@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
JavaScript
;
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'];