UNPKG

@attivio/suit

Version:

Attivio SUIT, the Search UI Toolkit, is a library for creating search clients for searching the Attivio platform.

498 lines (428 loc) 16.7 kB
'use strict'; exports.__esModule = true; exports.default = undefined; var _xregexp = require('xregexp'); var _xregexp2 = _interopRequireDefault(_xregexp); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** * Utility class that provides various string-manipulation functionality. */ var StringUtils = function () { function StringUtils() { _classCallCheck(this, StringUtils); } /** * Simply format a string/number combination based on the * value of the number. The format parameter is a string * containing multiple formatting templates separated by * a pipe character (|). If there are two parts, then the * first part is used if the value is 1 and the second part * is used if the value is not 1 (e.g., 0 or > 1). If there * are three parts, then the first is used if the value is * 0, the second if the value is 1 and the third if the * value is > 1. (If there is only one part, then it's used * in all cases.) * * In any case, if the part of the string being used contains * the characters '{}', that is substituted with the number * itself, as a string. * * @param {*} format the format string * @param {*} value the numeric value to switch on/replace with */ StringUtils.fmt = function fmt(format, value) { var pieceForValue = void 0; var pieces = format.split('|'); if (pieces.length === 1) { pieceForValue = pieces[0]; } else if (pieces.length === 2) { if (value === 1) { pieceForValue = pieces[0]; } else { pieceForValue = pieces[1]; } } else if (value === 0) { pieceForValue = pieces[0]; } else if (value === 1) { pieceForValue = pieces[1]; } else { pieceForValue = pieces[2]; } var valueString = value.toString(); return pieceForValue.replace('{}', valueString); }; /** * Find the match for a regular expression in a string closest * to the end of the string. * * @param s the string * @param regex the regular expression * @param startPos and optional position in the string at which to stsrt * @return the position of the last match or -1 if none was found */ StringUtils.regexLastIndexOf = function regexLastIndexOf(s, regex) { var startPos = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; var sp = startPos !== null ? startPos : s.length; var re = void 0; if (regex.global) { re = regex; } else { var flags = void 0; // (this rigamarole is required to make Flow happy) if (regex.ignoreCase && regex.multiline) { flags = 'gim'; } else if (regex.ignoreCase) { flags = 'gi'; } else if (regex.multiline) { flags = 'gm'; } else { flags = 'g'; } re = new RegExp(regex.source, flags); } var stringToWorkWith = s.substring(0, sp + 1); var lastIndexOf = -1; var nextStop = 0; var result = 1; while (result !== null) { result = re.exec(stringToWorkWith); if (result !== null) { lastIndexOf = result.index; nextStop += 1; re.lastIndex = nextStop; } } return lastIndexOf; }; /** * Remove simple HTML tags from the string. * * @param orig the string contsining HTML tags * @return the string with the HTML tags removed */ StringUtils.stripSimpleHtml = function stripSimpleHtml(orig) { var div = document.createElement('div'); div.innerHTML = orig; var text = div.textContent || div.innerText || ''; return text; }; /** * Truncate the passed-in string so it is no longer than the number of * characters specified by maxLen. The truncation will happen at a word * boundary, if possible. Unless otherwise specified, an ellipsis * is appended to the resulting string. * * @param orig the string to truncate * @param maxLen the maximum number of characters to allow * @param ellipsis if true, an ellipsis character will be appended to the * truncated string * @return the truncated string */ StringUtils.smartTruncate = function smartTruncate(orig, maxLen) { var ellipsis = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; if (orig.length < maxLen) { return orig; } // We check the first maxLen + 1 characters in case maxLen is the end of a word. var firstChunk = orig.substring(0, maxLen + 1); var lastWS = StringUtils.regexLastIndexOf(firstChunk, /\s/g); var result = void 0; if (lastWS >= 0) { // We found a whitespace character, so we'll break there. result = orig.substring(0, lastWS).trim(); } else { result = orig.substring(0, maxLen).trim(); } if (ellipsis) { result = result + '\u2026'; } return result; }; /** * Split the string onto multiple lines, separated with the * given character, if the given limit is reached. * * @param orig the string to wrap * @param newLine the line break string to use, optional—defaults to a newline * character but could be replaced with a string like <br /> for example * @param limit the maximum number of characters to allow on any given row * @return the wrapped string */ StringUtils.wrapLabel = function wrapLabel(orig) { var newLine = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '\n'; var limit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 50; var s = String(orig); if (s.length < limit) { return s; } var firstLine = void 0; var remainder = void 0; var firstChunk = s.substring(0, limit); if (s.length <= limit || s.charAt(limit).match(/\s/g)) { // If the first chunk is already at the end of the string, or the next // character is whitespace, we can leave it as is... well, just trim it firstLine = firstChunk.trim(); remainder = s.substring(limit).trim(); } else { var lastWS = StringUtils.regexLastIndexOf(firstChunk, /\s/g); if (lastWS >= 0) { // We found a whitespace character, so we'll break there. firstLine = s.substring(0, lastWS).trim(); remainder = s.substring(lastWS).trim(); } else { firstLine = firstChunk; remainder = s.substring(limit).trim(); } } if (remainder.length === 0) { // If the trimmed remainder is empty, then just return the part we found. return firstLine; } return '' + firstLine + newLine + StringUtils.wrapLabel(remainder, newLine, limit); }; /** * Returns true if the value is a string and it is has a length greater than 0. */ StringUtils.notEmpty = function notEmpty(value) { if (value && (typeof value === 'string' || value instanceof String) && value.length > 0) { return true; } return false; }; /** * Take a number and format it as a string accordning to the specified format. * The format string must consist of two main parts separated by a colon— * before the colon is the number of decimal points that should be used when formatting the * number. The remainder of the format string describes how to format the overall * string with instances of "{}" being replaced with the formatted value—it can * contanin separate to use if the number is 0, 1, or more than one, separated by * pipe characters. * For example: * "2:${}" with 3.215 will produce the string "$3.22" * "4:None|{}% More" with 0 will produce the string "None" * "4:None|{}% More" with 72.324214566 will produce the string "72.3242% More" * "0:No Queries|{} Query|{} Queries" with 0 will produce the string "No Queries" * "0:No Queries|{} Query|{} Queries" with 1 will produce the string "1 Query" * "0:No Queries|{} Query|{} Queries" with 72.1 will produce the string "72 Queries" */ StringUtils.formatNumber = function formatNumber(formatString, value) { var _formatString$split = formatString.split(':', 2), decimalPlaceString = _formatString$split[0], overallFormatString = _formatString$split[1]; var decimalPlaces = parseInt(decimalPlaceString, 10); if (isNaN(decimalPlaces)) { decimalPlaces = 0; } // Note: this is here because of a bug in toFixed where numbers ending in 5 weren't being // rounded up. E.g., for 3.125, at 2 decimal places, it would return 3.12 instead of 3.13 var decimalPlaceFactor = Math.pow(10, decimalPlaces); var roundedValue = Math.round(value * decimalPlaceFactor) / decimalPlaceFactor; var formattedValue = roundedValue.toFixed(decimalPlaces); var formatStringPieces = overallFormatString.split('|', 3); // If there's only format, use it for all values. // Otherwise, the first format is for values of 1 if there are 2 formats and for // values of 0 if there are three formats... var formatToUse = formatStringPieces[0]; if (formatStringPieces.length === 2 && value !== 1) { // If there are 2 formats, the first one is for values of 1, and the second is for all other values formatToUse = formatStringPieces[1]; } else if (formatStringPieces.length === 3 && value === 1) { // If there are three formats, the second is for values of one formatToUse = formatStringPieces[1]; } else if (formatStringPieces.length === 3 && value > 1) { // And the third is for values greater than 1 formatToUse = formatStringPieces[2]; } return formatToUse.replace('{}', formattedValue); }; /** * Normnalize a suggestion coming from autocomplete to make sure it doesn't have any special character. * This involves lowercasing the string and replacing punctuation with spaces, except: * detected email addresses are left intact * if a period isn't followed by whitespace, it's left intact * if one side of a hyphen is a number, it's left intact * * This will also ensure that unwanted characters aren't included in * simple query request (e.g. "?" will match exactly one character so if the suggestion is "who?" * then documents containing "who" will not be found (but those with "whom" would). * * @param original the string to modify * @return the normalized string suitable for using in a query */ StringUtils.normalizeAutocompleteSuggestion = function normalizeAutocompleteSuggestion(original) { var lc = original.toLocaleLowerCase(); var result = ''; var match = void 0; var pos = 0; var emailRegExp = RegExp('[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+', 'g'); while ((match = emailRegExp.exec(lc)) !== null) { // eslint-disable-line no-cond-assign var matchEnd = emailRegExp.lastIndex; var thisMatch = match[0]; var matchStart = matchEnd - thisMatch.length; var preceeding = original.substring(pos, matchStart); var cleanPreceeding = StringUtils.stripPunctuation(preceeding); result += cleanPreceeding; // If anyhthing came before this match, add it to the result result += match[0]; pos = matchEnd; } var remainder = original.substring(pos); var cleanRemainder = StringUtils.stripPunctuation(remainder); result += cleanRemainder; return StringUtils.coalesceWhitespace(result); }; /** * Check whether the given character is a digit. * * @param c the character to check * @return true if it's between 0 and 9 */ StringUtils.isDigit = function isDigit(c) { return (/^\d$/.test(c) ); }; /** * Check to see if the given character is a punctuation character. * This handles all punctuation, including various non-ASCII types * like curly quotes, CJK punctuation, etc. Note that this doesn't * check for whitespsce characters. * * @param c the character to check * @return true if it's a punctuation character. */ StringUtils.isPunctuation = function isPunctuation(c) { return (0, _xregexp2.default)('[\\p{P}]').test(c); }; /** * Check to see if the given character is a whitespace character * such as a space, tab, etc. * * @param c the character to check * @return true if it's a whitespace character. */ StringUtils.isWhitespace = function isWhitespace(c) { return (/\s/.test(c) ); }; /** * Given a string and a position in the string, check to see if * the adjacent characters preceeding the character at that * position are digits, up until either a whitespace character, * a punctuation character, or the beginning of the string. * * @param s the string to check * @param pos the position of the character before which to start looking * @return true if the preceeding characters are all digits */ StringUtils.isNumericOnlyBefore = function isNumericOnlyBefore(s, pos) { if (pos === 0) { return false; } var isNumeric = false; var i = void 0; for (i = pos - 1; i >= 0; i -= 1) { var c = s.charAt(i); if (StringUtils.isDigit(c)) { isNumeric = true; } if (StringUtils.isPunctuation(c) || StringUtils.isWhitespace(c)) { break; } } return isNumeric; }; /** * Given a string and a position in the string, check to see if * the adjacent characters following the character at that * position are digits, up until either a whitespace character, * a punctuation character, or the end of the string. * * @param s the string to check * @param pos the position of the character after which to start looking * @return true if the following characters are all digits */ StringUtils.isNumericOnlyAfter = function isNumericOnlyAfter(s, pos) { if (pos === s.length - 1) { return false; } var isNumeric = false; var i = void 0; for (i = pos + 1; i < s.length; i += 1) { var c = s.charAt(i); if (StringUtils.isDigit(c)) { isNumeric = true; } if (StringUtils.isPunctuation(c) || StringUtils.isWhitespace(c)) { break; } } return isNumeric; }; /** * Find any punctuation characters in the given string and replace them * with a space character. Ignores periods that aren't followed by whitespace * or other punctuation and ignores hyphens if the "word" immediately before * or after them is comprised solely of digits. * * @param orig the string to strip * @return the modified string */ StringUtils.stripPunctuation = function stripPunctuation(orig) { var result = ''; var i = void 0; for (i = 0; i < orig.length; i += 1) { var c = orig.charAt(i); // Check to see if there's a period followed by // non=whitespace/punctuation... if so, leave it in. // For example, we want to keep 123.4567 if (c === '.') { if (i < orig.length - 1) { var nextC = orig.charAt(i + 1); if (!StringUtils.isPunctuation(nextC) && !StringUtils.isWhitespace(nextC)) { result += c; continue; // eslint-disable-line no-continue } } } // If it's a hyphen, see if the part before or after it // is just digits... in which case, leave it in. // We want to keep the hyphen in part-numbery things like // AB-4-12-COR but not in compounds like white-house if (c === '-') { if (StringUtils.isNumericOnlyBefore(orig, i) || StringUtils.isNumericOnlyAfter(orig, i)) { result += c; continue; // eslint-disable-line no-continue } } if (StringUtils.isPunctuation(c)) { result += ' '; } else { result += c; } } return result; }; /** * Collapse any occurrences of whitespace in the given string to just * one single ASCII space character. * * @param orig the string to modify * @return the string with the single spaces */ StringUtils.coalesceWhitespace = function coalesceWhitespace(orig) { return orig.replace(/\s+/g, ' ').trim(); }; /** * Given a string, remove any question marks and replace them with * space characters. * @param orig the string to modify * @return the question-mark-less string */ StringUtils.stripQuestionMarks = function stripQuestionMarks(orig) { return orig.replace(/\?/g, ' '); }; return StringUtils; }(); exports.default = StringUtils; module.exports = exports['default'];