Ext.ns("Terrasoft.utils.string"); /** * @singleton */ /** * Empty string literal. * @type {String} */ Terrasoft.utils.string.emptyString = ""; /** * Alias for {@link Terrasoft.utils.string#emptyString} * @member Terrasoft * @inheritdoc Terrasoft.utils.string#emptyString */ Terrasoft.emptyString = Terrasoft.utils.string.emptyString; /** * Decodes special characters of HTML-markup. * @param {String} value String to decode. * @return {String} Decoded value. */ Terrasoft.utils.string.decodeHtml = function (value) { return Ext.util.Format.htmlDecode(value); }; /** * Alias for {@link Terrasoft.utils.string#decodeHtml} * @member Terrasoft * @method decodeHtml * @inheritdoc Terrasoft.utils.string#decodeHtml */ Terrasoft.decodeHtml = Terrasoft.utils.string.decodeHtml; /** * Encodes special characters of HTML-markup. * @param {String} value String to encode. * @return {String} Encoded value. */ Terrasoft.utils.string.encodeHtml = function (value) { return Ext.util.Format.htmlEncode(value); }; /** * Alias for {@link Terrasoft.utils.string#encodeHtml} * @member Terrasoft * @method encodeHtml * @inheritdoc Terrasoft.utils.string#encodeHtml */ Terrasoft.encodeHtml = Terrasoft.utils.string.encodeHtml; /** * Replaces mnemonic symbols of HTML-markup. * @param {String} value String to replace. * @return {String} Encoded value. */ Terrasoft.utils.string.decodeHtmlEntities = function (value) { if (!Ext.isString(value) || value === "") { return value; } var element = document.createElement("textarea"); element.innerHTML = value.replace(/</g, "<").replace(/>/g, ">"); var result = element.value; element = null; return result; }; /** * Alias for {@link Terrasoft.utils.string#decodeHtmlEntities} * @member Terrasoft * @method decodeHtmlEntities * @inheritdoc Terrasoft.utils.string#decodeHtmlEntities */ Terrasoft.decodeHtmlEntities = Terrasoft.utils.string.decodeHtmlEntities; /** * Strips all HTML tags from text. * @param {Object} value The text with tags. * @return {String} The text without tags. */ Terrasoft.utils.string.stripTags = function (value) { return Ext.util.Format.stripTags(value); }; /** * Alias for {@link Terrasoft.utils.string#stripTags} * @member Terrasoft * @method stripTags * @inheritdoc Terrasoft.utils.string#stripTags */ Terrasoft.stripTags = Terrasoft.utils.string.stripTags; /** * Replaces html spec symbols for normal symbols. * @param {String} value The text with html spec symbols. * @return {String} The text with replaced symbols. */ Terrasoft.utils.string.unescape = function (value) { return _.unescape(value); }; /** * Alias for {@link Terrasoft.utils.string#unescape} * @member Terrasoft * @method unescape * @inheritdoc Terrasoft.utils.string#unescape */ Terrasoft.unescape = Terrasoft.utils.string.unescape; /** * Performs parametrized replace in string. * Example: * getFormattedString('some {0} text {1}', 'good', 'allowed') * Result: * 'some good text allowed' * @param {String} string String to format. * @return {String} Formatted string. */ Terrasoft.getFormattedString = function (string) { var args = Array.prototype.slice.call(arguments, 1); var searchRegExp = /\{(\d*)\}/ig; if (string === undefined) { throw new Error("parameter string is not defined"); } return string.replace(searchRegExp, function (value, index) { var positionIndex = parseInt(index, Terrasoft.NumeralSystem.DECIMAL); return args[positionIndex] || value; }); }; /** * Returns string representation of value. * @throws {Terrasoft.exceptions.ItemNotFoundException} * Throws exception {@link Terrasoft.exceptions#ItemNotFoundException} if type is unsupported. * @param {Number/String/Object/Boolean/Date} value Value to transform. * @param {Terrasoft.DataValueType} type Value datatype. * @param {Object} [config] String format config. * @return {String} Value string representation. */ Terrasoft.utils.string.getTypedStringValue = function (value, type, config) { if (!Ext.isNumber(type)) { return; } switch (type) { case Terrasoft.DataValueType.DATE: return Ext.isDate(value) ? Ext.Date.format(value, Terrasoft.Resources.CultureSettings.dateFormat) : ""; case Terrasoft.DataValueType.TIME: return Ext.isDate(value) ? Ext.Date.format(value, Terrasoft.Resources.CultureSettings.timeFormat) : ""; case Terrasoft.DataValueType.DATE_TIME: return Ext.isDate(value) ? Ext.Date.format(value, Terrasoft.Resources.CultureSettings.dateFormat + " " + Terrasoft.Resources.CultureSettings.timeFormat) : ""; case Terrasoft.DataValueType.LOOKUP: case Terrasoft.DataValueType.MAPPING: return value ? value.displayValue : ""; case Terrasoft.DataValueType.MONEY: return Terrasoft.getFormattedNumberValue(value, { type: Terrasoft.DataValueType.MONEY }); case Terrasoft.DataValueType.FLOAT: var decimalPrecision = config ? config.decimalPrecision : null; return Terrasoft.getFormattedNumberValue(value, { decimalPrecision: decimalPrecision }); case Terrasoft.DataValueType.INTEGER: return Terrasoft.getFormattedNumberValue(value, { type: Terrasoft.DataValueType.INTEGER }); case Terrasoft.DataValueType.TEXT: case Terrasoft.DataValueType.SHORT_TEXT: case Terrasoft.DataValueType.MEDIUM_TEXT: case Terrasoft.DataValueType.LONG_TEXT: case Terrasoft.DataValueType.MAXSIZE_TEXT: case Terrasoft.DataValueType.GUID: return value; case Terrasoft.DataValueType.BOOLEAN: var result = null; result = value ? Terrasoft.Resources.CommonUtils.TrueStringValue : Terrasoft.Resources.CommonUtils.FalseStringValue; return result; default: throw new Terrasoft.exceptions.UnsupportedTypeException({ message: type + " is unsupported type" }); } }; /** * Alias for {@link Terrasoft.utils.string#getTypedStringValue} */ Terrasoft.getTypedStringValue = Terrasoft.utils.string.getTypedStringValue; /** * Creates string of given length consisting of given character. * Example: * var str = Terrasoft.utils.string.getUniformString(5, 'a') // str = 'aaaaa' * @param {Number} length String length. * @param {String} symbol Character to fill string. * @return {String} String of given length and given character. */ Terrasoft.utils.string.getUniformString = function (length, symbol) { if (length <= 0) { return ""; } var zerosArr = new Array(length + 1); return zerosArr.join(symbol); }; /** * Alias for {@link Terrasoft.utils.string#getUniformString} * @member Terrasoft * @method getUniformString * @inheritdoc Terrasoft.utils.string#getUniformString */ Terrasoft.getUniformString = Terrasoft.utils.string.getUniformString; /** * Checks whether string is valid URL. * @param {String} value String representation of URL. * @return {Boolean} Returns true if string is valid URL. */ Terrasoft.utils.string.isUrl = function (value) { var obsoleteMessage = Ext.String.format(Terrasoft.Resources.ObsoleteMessages.ObsoleteMethodMessage, "Terrasoft.utils.isUrl", "Terrasoft.utils.uri.isUrl"); console.log(obsoleteMessage); return Terrasoft.utils.uri.isUrl(value); }; /** * Adds missing number of characters in the beginning of the string. * @param {String} value Source string. * @param {Number} length Required length of result string. * @param {String} symbol (optional) Symbol to add to string (optional). * @return {String} String of required length. */ Terrasoft.utils.string.pad = function (value, length, symbol) { symbol = symbol || "0"; value = String(value); return value.length >= length ? value : new Array(length - value.length + 1).join(symbol) + value; }; /** * Alias for {@link Terrasoft.utils.string#pad} * @member Terrasoft * @method pad * @inheritdoc Terrasoft.utils.string#pad */ Terrasoft.pad = Terrasoft.utils.string.pad; /** * Performs reverse of string. * * Example: * var str = Terrasoft.utils.string.reverseStr('1234') // str = '4321' * * @param {String} str Source string. * @return {String} Reversed string. */ Terrasoft.utils.string.reverseStr = function (str) { var arr = str.split(""); var reverseArr = arr.reverse(); return reverseArr.join(""); }; /** * Alias for {@link Terrasoft.utils.string#reverseStr} * @member Terrasoft * @method reverseStr * @inheritdoc Terrasoft.utils.string#reverseStr */ Terrasoft.reverseStr = Terrasoft.utils.string.reverseStr; /** * Returns copy of string transformed to lowerCamelCase. * @param {String} value Source string. * @return {String} String transformed to lowerCamelCase. */ Terrasoft.utils.string.toLowerCamelCase = function (value) { return value.length > 0 ? value.substr(0, 1).toLowerCase() + value.substr(1) : ""; }; /** * Alias for {@link Terrasoft.utils.string#toLowerCamelCase} * @member Terrasoft * @method toLowerCamelCase * @inheritdoc Terrasoft.utils.string#toLowerCamelCase */ Terrasoft.toLowerCamelCase = Terrasoft.utils.string.toLowerCamelCase; /** * Returns string with converted eol char to unix style. * @param {String} value Source string. * @return {String} String converted eol char to unix style. */ Terrasoft.utils.string.convertEolToUnix = function (value) { var winEol = String.fromCharCode(13, 10); var unixEol = String.fromCharCode(10); return (value || "").replace(new RegExp(winEol, "g"), unixEol); }; /** * Alias for {@link Terrasoft.utils.string#convertEolToUnix} * @member Terrasoft * @method convertEolToUnix * @inheritdoc Terrasoft.utils.string#convertEolToUnix */ Terrasoft.convertEolToUnix = Terrasoft.utils.string.convertEolToUnix; /** * Checks whether string is serialized JSON object. * @param {String} value Value to check. * @param {Boolean} [checksPropertyNamesOnQuotes] Flag that indicates whether to check property names on quotes. * Default true. * @return {Boolean} */ Terrasoft.isJsonObject = function (value, checksPropertyNamesOnQuotes) { if (value == null) { return false; } var jsonParseFn = checksPropertyNamesOnQuotes === false ? Ext.global.JSON5.parse : Ext.JSON.decode; try { var jsonObject = jsonParseFn(value); return Ext.isArray(jsonObject) || Ext.isObject(jsonObject); } catch (e) { return false; } }; /** * Alias for {@link Terrasoft#isJsonObject} * @member Terrasoft.utils.string * @method isJsonObject * @inheritdoc Terrasoft#isJsonObject */ Terrasoft.utils.string.isJsonObject = Terrasoft.isJsonObject; /** * Removes html tags from string. * @param {String} value Source string. * @return {String} String without html tags. */ Terrasoft.utils.string.removeHtmlTags = function (value) { if (Ext.isString(value)) { value = Terrasoft.decodeHtml(value); value = value.replace(/<head>[\s\S]*<\/head>/, ""); value = value.replace(/<style>[\s\S]*<\/style>/, ""); value = value.replace(/<script>[\s\S]*<\/script>/, ""); value = value.replace(/<noscript>[\s\S]*<\/noscript>/, ""); value = value.replace(/<svg[\s\S]*<\/svg>/, ""); value = value.replace(/<form[\s\S]*<\/form>/, ""); /* jshint ignore:start */ var regExp = /(<([\s/]*(a|o:p|xml|abbr|acronym|address|applet|area|article|aside|audio|b|base|basefont|bdi|bdo|bgsound|blockquote|big|body|blink|br|button|canvas|caption|center|cite|code|col|colgroup|command|comment|datalist|dd|del|details|dfn|dir|div|dl|dt|em|embed|fieldset|figcaption|figure|font|form|footer|frame|frameset|h1|h2|h3|h4|h5|h6|head|header|hgroup|hr|html|i|iframe|img|input|ins|isindex|kbd|keygen|label|legend|li|link|main|map|marquee|mark|menu|meta|meter|nav|nobr|noembed|noframes|noscript|object|ol|optgroup|option|output|p|param|plaintext|pre|progress|q|rp|rt|ruby|s|samp|script|section|select|small|span|source|strike|strong|style|sub|summary|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|u|ul|var|video|wbr|xmp)(\b|\/)[^@>]*)>)/ig; value = value.replace(regExp, ""); value = value.replace(/ /g, " "); value = value.replace(/<![\s\S]*?>/g, ""); value = value.replace(/<!DOCTYPE[\s\S]*?>/g, ""); /* jshint ignore:end */ } return value; }; /** * Alias for {@link Terrasoft.utils.string#removeHtmlTags} * @member Terrasoft * @method removeHtmlTags * @inheritdoc Terrasoft.utils.string#removeHtmlTags */ Terrasoft.removeHtmlTags = Terrasoft.utils.string.removeHtmlTags; /** * Determines whether one string may be found within another string, returning true or false as appropriate. * @param {String} sourceString String to search inside. * @param {String} searchString String to search for. * @return {Boolean} True if the given string is found anywhere within the search string, otherwise, false if not. */ Terrasoft.utils.string.includes = function (sourceString, searchString) { return sourceString.indexOf(searchString) !== -1; }; /** * Alias for {@link Terrasoft.utils.string#includes} * @member Terrasoft * @method includes * @inheritdoc Terrasoft.utils.string#includes */ Terrasoft.includes = Terrasoft.utils.string.includes; /** * Checks the string contains RTL characters. * @param {String} sourceString Source string. * @return {Boolean} True if string contains RTL characters. */ Terrasoft.utils.string.containsRtlChars = function (sourceString) { var rtlCharsPattern = /[\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC]/; return rtlCharsPattern.test(sourceString); }; /** * Alias for {@link Terrasoft.utils.string#containsRtlChars} * @member Terrasoft * @method containsRtlChars * @inheritdoc Terrasoft.utils.string#containsRtlChars */ Terrasoft.containsRtlChars = Terrasoft.utils.string.containsRtlChars; /** * Gets direction of the source text. * @param {String} text Source text. * @return {String|null} Direction of the source text. */ Terrasoft.utils.string.getTextDirection = function (text) { if (!Terrasoft.getIsRtlMode() || Ext.isEmpty(text)) { return null; } return Terrasoft.containsRtlChars(text) ? "rtl" : "ltr"; }; /** * Alias for {@link Terrasoft.utils.string#getTextDirection} * @member Terrasoft * @method getTextDirection * @inheritdoc Terrasoft.utils.string#getTextDirection */ Terrasoft.getTextDirection = Terrasoft.utils.string.getTextDirection; /** * Gets random string. * @return {String} Random string. */ Terrasoft.utils.string.randomString = function () { var randomFloat = Math.random(); var randomString = randomFloat.toString(36); return randomString.substring(2); }; /** * Alias for {@link Terrasoft.utils.string#randomString} * @member Terrasoft * @method randomString * @inheritdoc Terrasoft.utils.string#randomString */ Terrasoft.randomString = Terrasoft.utils.string.randomString; /** * Generate new html with safe content only, using for protect against XSS * @param {String} html Html to sanitize. * @method sanitizeHTML * @return {String} XSS-safe html. */ Terrasoft.utils.string.sanitizeHTML = function (html) { if (!html) { return ""; } /* Adds a value before every matched tag * Use prefix = "<!--\"'-->", so that unterminated quotes aren't preventing the browser from * splitting a tag. Test case: * '<input style="foo;b:url(0);><input onclick="<input type=button onclick="too() href=;>">' */ var prefix = ""; /* Attributes should not be prefixed by these characters. This list is not complete, but will be sufficient * for this function. * (see http://www.w3.org/TR/REC-xml/#NT-NameChar) */ var att = "[^-a-z0-9:._]"; var tag = "<[a-z]"; var any = "(?:[^<>\"']*(?:\"[^\"]*\"|'[^']*'))*?[^<>]*"; var etag = "(?:>|(?=<))"; var entityEnd = "(?:;|(?!\\d))"; var ents = { " ": Ext.String.format("(?:\\s|�?|�*32{0}|�*20{1})", entityEnd, entityEnd), "(": Ext.String.format("(?:\\(|�*40{0}|�*28{1})", entityEnd, entityEnd), ")": Ext.String.format("(?:\\)|�*41{0}|�*29{1})", entityEnd, entityEnd), ".": Ext.String.format("(?:\\.|�*46{0}|�*2e{1})", entityEnd, entityEnd) }; /* Placeholder to avoid tricky filter-circumventing methods */ var charMap = {}; var s = Ext.String.format("{0}*", ents[" "]); /* Short-hand space */ /* Important: Must be pre- and postfixed by < and >. RE matches a whole tag! */ /** * @name ae * @description Converts a given string in a sequence of the original input and the HTML entity * @param {String} string String to convert */ function ae(string) { var allCharsLowercase = string.toLowerCase(); if (ents[string]) { return ents[string]; } var allCharsUppercase = string.toUpperCase(); var reRes = ""; for (var i = 0; i < string.length; i++) { var charLowercase = allCharsLowercase.charAt(i); if (charMap[charLowercase]) { reRes += charMap[charLowercase]; continue; } var charUppercase = allCharsUppercase.charAt(i); var reSub = [charLowercase]; reSub.push(Ext.String.format("�*{0}{1}", charLowercase.charCodeAt(0), entityEnd)); reSub.push(Ext.String.format("�*{0}{1}", charLowercase.charCodeAt(0).toString(16), entityEnd)); if (charLowercase !== charUppercase) { reSub.push(Ext.String.format("�*{0}{1}", charUppercase.charCodeAt(0), entityEnd)); reSub.push(Ext.String.format("�*{0}{1}", charUppercase.charCodeAt(0).toString(16), entityEnd)); } reSub = Ext.String.format("(?:{0})", reSub.join("|")); reRes += charMap[charLowercase] = reSub; } return ents[string] = reRes; } /** * @name by * @description second argument for the replace function. */ function by(match, group1, group2) { /* Adds a data-prefix before every external pointer */ return Ext.String.format("{0}data-{1}", group1, group2); } /** * @name cr * @description Selects a HTML element and performs a search-and-replace on attributes * @param {String} selector HTML substring to match * @param {String} attribute RegExp-escaped; HTML element attribute to match * @param {String} marker Optional RegExp-escaped; marks the prefix * @param {String} delimiter Optional RegExp escaped; non-quote delimiters * @param {String} end Optional RegExp-escaped; forces the match to end before an occurence of <end> when * quotes are missing */ function cr(selector, attribute, marker, delimiter, end) { if (typeof selector === "string") { selector = new RegExp(selector, "gi"); } marker = typeof marker === "string" ? marker : "\\s*="; delimiter = typeof delimiter === "string" ? delimiter : ""; end = typeof end === "string" ? end : ""; var isEnd = end && "?"; var re1 = new RegExp(Ext.String.format("({0})({1}{2}(?:\\s*\"[^\"{3}]*\"|\\s*'[^'{3}]*'|[^\\s{3}]+{4}){5})", att, attribute, marker, delimiter, isEnd, end), "gi"); html = html.replace(selector, function (match) { return Ext.String.format("{0}{1}", prefix, match.replace(re1, by)); }); } /** * @name cri * @description Selects an attribute of a HTML element, and performs a search-and-replace on certain values * @param {String} selector HTML element to match * @param {String} attribute RegExp-escaped; HTML element attribute to match * @param {String} front RegExp-escaped; attribute value, prefix to match * @param {String} flags Optional RegExp flags, default "gi" * @param {String} delimiter Optional RegExp-escaped; non-quote delimiters * @param {String} end Optional RegExp-escaped; forces the match to end before an occurence of <end> when quotes * are missing */ function cri(selector, attribute, front, flags, delimiter, end) { if (typeof selector === "string") { selector = new RegExp(selector, "gi"); } flags = typeof flags === "string" ? flags : "gi"; var re1 = new RegExp("(" + att + attribute + "\\s*=)((?:\\s*\"[^\"]*\"|\\s*'[^']*'|[^\\s>]+))", "gi"); end = typeof end === "string" ? end + ")" : ")"; var at1 = new RegExp("(\")(" + front + "[^\"]+\")", flags); var at2 = new RegExp("(')(" + front + "[^']+')", flags); var at3 = new RegExp("()(" + front + "(?:\"[^\"]+\"|'[^']+'|(?:(?!" + delimiter + ").)+)" + end, flags); var handleAttr = function (match, g1, g2) { if (g2.charAt(0) === "\"") { return g1 + g2.replace(at1, by); } if (g2.charAt(0) === "'") { return g1 + g2.replace(at2, by); } return g1 + g2.replace(at3, by); }; html = html.replace(selector, function (match) { return prefix + match.replace(re1, handleAttr); }); } /* <meta http-equiv=refresh content=" ; url= " > */ html = html.replace(new RegExp("<meta" + any + att + "http-equiv\\s*=\\s*(?:\"" + ae("refresh") + "\"" + any + etag + "|'" + ae("refresh") + "'" + any + etag + "|" + ae("refresh") + "(?:" + ae(" ") + any + etag + "|" + etag + "))", "gi"), "<!-- meta http-equiv=refresh stripped-->"); /* Stripping all scripts */ html = html.replace(new RegExp("<script" + any + ">\\s*//\\s*<\\[CDATA\\[[\\S\\s]*?]]>\\s*</script[^>]*>", "gi"), "<!--CDATA script-->"); html = html.replace(/<script[\S\s]+?<\/script\s*>/gi, "<!--Non-CDATA script-->"); cr(tag + any + att + "on[-a-z0-9:_.]+=" + any + etag, "on[-a-z0-9:_.]+"); /* Event listeners */ //cr(tag+any+att+"href\\s*="+any+etag, "href"); /* Linked elements - disabled*/ //cr(tag + any + att + "src\\s*=" + any + etag, "src"); /* Embedded elements - disabled*/ cr("<object" + any + att + "data\\s*=" + any + etag, "data"); /* <object data= > */ cr("<applet" + any + att + "codebase\\s*=" + any + etag, "codebase"); /* <applet codebase= > */ /* <param name=movie value= >*/ cr("<param" + any + att + "name\\s*=\\s*(?:\"" + ae("movie") + "\"" + any + etag + "|'" + ae("movie") + "'" + any + etag + "|" + ae("movie") + "(?:" + ae(" ") + any + etag + "|" + etag + "))", "value"); /* <style> and < style= > url()*/ cr(/<style[^>]*>(?:[^"']*(?:"[^"]*"|'[^']*'))*?[^'"]*(?:<\/style|$)/gi, "url", "\\s*\\(\\s*", "", "\\s*\\)"); cri(tag + any + att + "style\\s*=" + any + etag, "style", ae("url") + s + ae("(") + s, 0, s + ae(")"), ae(")")); /* IE7- CSS expression() */ cr(/<style[^>]*>(?:[^"']*(?:"[^"]*"|'[^']*'))*?[^'"]*(?:<\/style|$)/gi, "expression", "\\s*\\(\\s*", "", "\\s*\\)"); cri(tag + any + att + "style\\s*=" + any + etag, "style", ae("expression") + s + ae("(") + s, 0, s + ae(")"), ae(")")); return html.replace(new RegExp("(?:" + prefix + ")+", "g"), prefix); }; /** * Alias for {@link Terrasoft.utils.string#sanitizeHTML} * @member Terrasoft * @method sanitizeHTML * @inheritdoc Terrasoft.utils.string#sanitizeHTML */ Terrasoft.sanitizeHTML = Terrasoft.utils.string.sanitizeHTML;