} */
var seen = {'&': '&', '<': '<', '>': '>', '"': '"'};
var div;
if (opt_document) {
div = opt_document.createElement('div');
} else {
div = goog.global.document.createElement('div');
}
// Match as many valid entity characters as possible. If the actual entity
// happens to be shorter, it will still work as innerHTML will return the
// trailing characters unchanged. Since the entity characters do not include
// open angle bracket, there is no chance of XSS from the innerHTML use.
// Since no whitespace is passed to innerHTML, whitespace is preserved.
return str.replace(goog.string.HTML_ENTITY_PATTERN_, function(s, entity) {
// Check for cached entity.
var value = seen[s];
if (value) {
return value;
}
// Check for numeric entity.
if (entity.charAt(0) == '#') {
// Prefix with 0 so that hex entities (e.g. ) parse as hex numbers.
var n = Number('0' + entity.substr(1));
if (!isNaN(n)) {
value = String.fromCharCode(n);
}
}
// Fall back to innerHTML otherwise.
if (!value) {
// Append a non-entity character to avoid a bug in Webkit that parses
// an invalid entity at the end of innerHTML text as the empty string.
div.innerHTML = s + ' ';
// Then remove the trailing character from the result.
value = div.firstChild.nodeValue.slice(0, -1);
}
// Cache and return.
return seen[s] = value;
});
};
/**
* Unescapes XML entities.
* @private
* @param {string} str The string to unescape.
* @return {string} An unescaped copy of {@code str}.
*/
goog.string.unescapePureXmlEntities_ = function(str) {
return str.replace(/&([^;]+);/g, function(s, entity) {
switch (entity) {
case 'amp':
return '&';
case 'lt':
return '<';
case 'gt':
return '>';
case 'quot':
return '"';
default:
if (entity.charAt(0) == '#') {
// Prefix with 0 so that hex entities (e.g. ) parse as hex.
var n = Number('0' + entity.substr(1));
if (!isNaN(n)) {
return String.fromCharCode(n);
}
}
// For invalid entities we just return the entity
return s;
}
});
};
/**
* Regular expression that matches an HTML entity.
* See also HTML5: Tokenization / Tokenizing character references.
* @private
* @type {!RegExp}
*/
goog.string.HTML_ENTITY_PATTERN_ = /&([^;\s<&]+);?/g;
/**
* Do escaping of whitespace to preserve spatial formatting. We use character
* entity #160 to make it safer for xml.
* @param {string} str The string in which to escape whitespace.
* @param {boolean=} opt_xml Whether to use XML compatible tags.
* @return {string} An escaped copy of {@code str}.
*/
goog.string.whitespaceEscape = function(str, opt_xml) {
// This doesn't use goog.string.preserveSpaces for backwards compatibility.
return goog.string.newLineToBr(str.replace(/ /g, ' '), opt_xml);
};
/**
* Preserve spaces that would be otherwise collapsed in HTML by replacing them
* with non-breaking space Unicode characters.
* @param {string} str The string in which to preserve whitespace.
* @return {string} A copy of {@code str} with preserved whitespace.
*/
goog.string.preserveSpaces = function(str) {
return str.replace(/(^|[\n ]) /g, '$1' + goog.string.Unicode.NBSP);
};
/**
* Strip quote characters around a string. The second argument is a string of
* characters to treat as quotes. This can be a single character or a string of
* multiple character and in that case each of those are treated as possible
* quote characters. For example:
*
*
* goog.string.stripQuotes('"abc"', '"`') --> 'abc'
* goog.string.stripQuotes('`abc`', '"`') --> 'abc'
*
*
* @param {string} str The string to strip.
* @param {string} quoteChars The quote characters to strip.
* @return {string} A copy of {@code str} without the quotes.
*/
goog.string.stripQuotes = function(str, quoteChars) {
var length = quoteChars.length;
for (var i = 0; i < length; i++) {
var quoteChar = length == 1 ? quoteChars : quoteChars.charAt(i);
if (str.charAt(0) == quoteChar && str.charAt(str.length - 1) == quoteChar) {
return str.substring(1, str.length - 1);
}
}
return str;
};
/**
* Truncates a string to a certain length and adds '...' if necessary. The
* length also accounts for the ellipsis, so a maximum length of 10 and a string
* 'Hello World!' produces 'Hello W...'.
* @param {string} str The string to truncate.
* @param {number} chars Max number of characters.
* @param {boolean=} opt_protectEscapedCharacters Whether to protect escaped
* characters from being cut off in the middle.
* @return {string} The truncated {@code str} string.
*/
goog.string.truncate = function(str, chars, opt_protectEscapedCharacters) {
if (opt_protectEscapedCharacters) {
str = goog.string.unescapeEntities(str);
}
if (str.length > chars) {
str = str.substring(0, chars - 3) + '...';
}
if (opt_protectEscapedCharacters) {
str = goog.string.htmlEscape(str);
}
return str;
};
/**
* Truncate a string in the middle, adding "..." if necessary,
* and favoring the beginning of the string.
* @param {string} str The string to truncate the middle of.
* @param {number} chars Max number of characters.
* @param {boolean=} opt_protectEscapedCharacters Whether to protect escaped
* characters from being cutoff in the middle.
* @param {number=} opt_trailingChars Optional number of trailing characters to
* leave at the end of the string, instead of truncating as close to the
* middle as possible.
* @return {string} A truncated copy of {@code str}.
*/
goog.string.truncateMiddle = function(
str, chars, opt_protectEscapedCharacters, opt_trailingChars) {
if (opt_protectEscapedCharacters) {
str = goog.string.unescapeEntities(str);
}
if (opt_trailingChars && str.length > chars) {
if (opt_trailingChars > chars) {
opt_trailingChars = chars;
}
var endPoint = str.length - opt_trailingChars;
var startPoint = chars - opt_trailingChars;
str = str.substring(0, startPoint) + '...' + str.substring(endPoint);
} else if (str.length > chars) {
// Favor the beginning of the string:
var half = Math.floor(chars / 2);
var endPos = str.length - half;
half += chars % 2;
str = str.substring(0, half) + '...' + str.substring(endPos);
}
if (opt_protectEscapedCharacters) {
str = goog.string.htmlEscape(str);
}
return str;
};
/**
* Special chars that need to be escaped for goog.string.quote.
* @private {!Object}
*/
goog.string.specialEscapeChars_ = {
'\0': '\\0',
'\b': '\\b',
'\f': '\\f',
'\n': '\\n',
'\r': '\\r',
'\t': '\\t',
'\x0B': '\\x0B', // '\v' is not supported in JScript
'"': '\\"',
'\\': '\\\\',
// To support the use case of embedding quoted strings inside of script
// tags, we have to make sure HTML comments and opening/closing script tags do
// not appear in the resulting string. The specific strings that must be
// escaped are documented at:
// http://www.w3.org/TR/html51/semantics.html#restrictions-for-contents-of-script-elements
'<': '\x3c'
};
/**
* Character mappings used internally for goog.string.escapeChar.
* @private {!Object}
*/
goog.string.jsEscapeCache_ = {
'\'': '\\\''
};
/**
* Encloses a string in double quotes and escapes characters so that the
* string is a valid JS string. The resulting string is safe to embed in
* `