Skip to content
This repository has been archived by the owner on Aug 1, 2024. It is now read-only.

Commit

Permalink
Add opt_preserveSpacesAndTabs param to linkifyPlainTextAsHtml.
Browse files Browse the repository at this point in the history
RELNOTES: Add opt_preserveSpacesAndTabs param to linkifyPlainTextAsHtml.

PiperOrigin-RevId: 407399841
Change-Id: I2777b48a05c5eb18a182e010703027e98590bde7
  • Loading branch information
Matt Hughes authored and copybara-github committed Nov 3, 2021
1 parent 0fd0574 commit e904648
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 17 deletions.
2 changes: 2 additions & 0 deletions closure/goog/string/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ closure_js_library(
name = "linkify",
srcs = ["linkify.js"],
deps = [
":const",
":string",
"//closure/goog/html:safehtml",
"//closure/goog/html:uncheckedconversions",
],
)

Expand Down
59 changes: 44 additions & 15 deletions closure/goog/string/linkify.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
goog.provide('goog.string.linkify');

goog.require('goog.html.SafeHtml');
goog.require('goog.html.uncheckedconversions');
goog.require('goog.string');
goog.require('goog.string.Const');


/**
Expand All @@ -26,21 +28,53 @@ goog.require('goog.string');
* target=''.
* @param {boolean=} opt_preserveNewlines Whether to preserve newlines with
* <br>.
* @param {boolean=} opt_preserveSpacesAndTabs Whether to preserve spaces with
* non-breaking spaces and tabs with <span style="white-space:pre">
* @return {!goog.html.SafeHtml} Linkified HTML. Any text that is not part of a
* link will be HTML-escaped.
*/
goog.string.linkify.linkifyPlainTextAsHtml = function(
text, opt_attributes, opt_preserveNewlines) {
text, opt_attributes, opt_preserveNewlines, opt_preserveSpacesAndTabs) {
'use strict';

/**
* @param {string} plainText
* @return {!goog.html.SafeHtml} html
*/
const htmlEscape = function(plainText) {
if (opt_preserveSpacesAndTabs) {
const html = goog.html.SafeHtml.htmlEscape(plainText);
let modifiedHtml =
goog.html.SafeHtml
.unwrap(html)
// Leading space is converted into a non-breaking space, and
// spaces following whitespace are converted into non-breaking
// spaces. This must happen first, to ensure we preserve spaces
// after newlines.
.replace(/(^|[\n\r\t\ ])\ /g, '$1&#160;')
// Preserve tabs by using style="white-space:pre"
.replace(/(\t+)/g, '<span style="white-space:pre">$1</span>');
if (opt_preserveNewlines) {
modifiedHtml = goog.string.newLineToBr(modifiedHtml);
}
return goog.html.uncheckedconversions
.safeHtmlFromStringKnownToSatisfyTypeContract(
goog.string.Const.from('Escaped plain text'), modifiedHtml,
html.getDirection());
} else if (opt_preserveNewlines) {
return goog.html.SafeHtml.htmlEscapePreservingNewlines(plainText);
} else {
return goog.html.SafeHtml.htmlEscape(plainText);
}
};

// This shortcut makes linkifyPlainText ~10x faster if text doesn't contain
// URLs or email addresses and adds insignificant performance penalty if it
// does.
if (text.indexOf('@') == -1 && text.indexOf('://') == -1 &&
text.indexOf('www.') == -1 && text.indexOf('Www.') == -1 &&
text.indexOf('WWW.') == -1) {
return opt_preserveNewlines ?
goog.html.SafeHtml.htmlEscapePreservingNewlines(text) :
goog.html.SafeHtml.htmlEscape(text);
return htmlEscape(text);
}

const attributesMap = {};
Expand All @@ -66,10 +100,7 @@ goog.string.linkify.linkifyPlainTextAsHtml = function(
goog.string.linkify.FIND_LINKS_RE_,
function(part, before, original, email, protocol) {
'use strict';
output.push(
opt_preserveNewlines ?
goog.html.SafeHtml.htmlEscapePreservingNewlines(before) :
before);
output.push(htmlEscape(before));
if (!original) {
return '';
}
Expand Down Expand Up @@ -123,10 +154,7 @@ goog.string.linkify.linkifyPlainTextAsHtml = function(
}
attributesMap['href'] = href + linkText;
output.push(goog.html.SafeHtml.create('a', attributesMap, linkText));
output.push(
opt_preserveNewlines ?
goog.html.SafeHtml.htmlEscapePreservingNewlines(afterLink) :
afterLink);
output.push(htmlEscape(afterLink));
return '';
});
return goog.html.SafeHtml.concat(output);
Expand Down Expand Up @@ -225,9 +253,10 @@ goog.string.linkify.WWW_START_ = 'www\\.';
* @const
* @private
*/
goog.string.linkify.URL_RE_STRING_ = '(?:' +
goog.string.linkify.PROTOCOL_START_ + '|' + goog.string.linkify.WWW_START_ +
')[' + goog.string.linkify.ACCEPTABLE_URL_CHARS_ + ']+';
goog.string.linkify.URL_RE_STRING_ =
'(?:' + goog.string.linkify.PROTOCOL_START_ + '|' +
goog.string.linkify.WWW_START_ + ')[' +
goog.string.linkify.ACCEPTABLE_URL_CHARS_ + ']+';


/**
Expand Down
56 changes: 54 additions & 2 deletions closure/goog/string/linkify_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,17 @@ const testingDom = goog.require('goog.testing.dom');
/** @type {!HTMLDivElement} */
const div = dom.createElement(TagName.DIV);

function assertLinkify(comment, input, expected, preserveNewlines = undefined) {
/**
* @private
*/
function assertLinkify(
comment, input, expected, preserveNewlines = undefined,
preserveSpacesAndTabs = undefined) {
assertEquals(
comment, expected,
SafeHtml.unwrap(linkify.linkifyPlainTextAsHtml(
input, {rel: '', target: ''}, preserveNewlines)));
input, {rel: '', target: ''}, preserveNewlines,
preserveSpacesAndTabs)));
}

testSuite({
Expand Down Expand Up @@ -557,4 +563,50 @@ testSuite({
'Line 1<br>Line 2',
/* preserveNewlines */ true);
},

testPreserveSpacesAndTabs() {
assertLinkify(
'Preserving spaces', ' Example:\n http://www.google.com/ ',
'&#160;Example:\n&#160;<a href="http://www.google.com/">http://www.google.com/<\/a>&#160;',
/* preserveNewlines */ false,
/* preserveSpacesAndTabs */ true);
assertLinkify(
'Preserving spaces with no links', ' Line 1\n Line 2 ',
'&#160;Line 1\n&#160; Line 2 ',
/* preserveNewlines */ false,
/* preserveSpacesAndTabs */ true);
assertLinkify(
'Preserving tabs', 'Example:\thttp://www.google.com/',
'Example:<span style="white-space:pre">\t</span><a href="http://www.google.com/">http://www.google.com/<\/a>',
/* preserveNewlines */ false,
/* preserveSpacesAndTabs */ true);
assertLinkify(
'Preserving tabs with no links', 'Column 1\t\tColumn 2',
'Column 1<span style="white-space:pre">\t\t</span>Column 2',
/* preserveNewlines */ false,
/* preserveSpacesAndTabs */ true);
},

testPreserveNewlinesSpacesAndTabs() {
assertLinkify(
'Preserving spaces', ' Example:\n http://www.google.com/ ',
'&#160;Example:<br>&#160;<a href="http://www.google.com/">http://www.google.com/<\/a>&#160;',
/* preserveNewlines */ true,
/* preserveSpacesAndTabs */ true);
assertLinkify(
'Preserving spaces with no links', ' Line 1\n Line 2 ',
'&#160;Line 1<br>&#160; Line 2 ',
/* preserveNewlines */ true,
/* preserveSpacesAndTabs */ true);
assertLinkify(
'Preserving tabs', 'Example:\n\thttp://www.google.com/',
'Example:<br><span style="white-space:pre">\t</span><a href="http://www.google.com/">http://www.google.com/<\/a>',
/* preserveNewlines */ true,
/* preserveSpacesAndTabs */ true);
assertLinkify(
'Preserving tabs with no links', 'Line 1\n\t\tLine 2',
'Line 1<br><span style="white-space:pre">\t\t</span>Line 2',
/* preserveNewlines */ true,
/* preserveSpacesAndTabs */ true);
},
});

0 comments on commit e904648

Please sign in to comment.