Skip to content

Commit 6226757

Browse files
committed
generalize svgTextUtils.plainText
- so that it can selective allow some pseudo-html tags to go through - add truncate logic where allowed pseudo-html tags don't count toward the output "length"
1 parent cc45972 commit 6226757

File tree

2 files changed

+97
-6
lines changed

2 files changed

+97
-6
lines changed

src/lib/svg_text_utils.js

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,6 @@ var ZERO_WIDTH_SPACE = '\u200b';
264264
*/
265265
var PROTOCOLS = ['http:', 'https:', 'mailto:', '', undefined, ':'];
266266

267-
var STRIP_TAGS = new RegExp('</?(' + Object.keys(TAG_STYLES).join('|') + ')( [^>]*)?/?>', 'g');
268-
269267
var NEWLINES = /(\r\n?|\n)/g;
270268

271269
var SPLIT_TAGS = /(<[^<>]*>)/;
@@ -315,10 +313,66 @@ function getQuotedMatch(_str, re) {
315313

316314
var COLORMATCH = /(^|;)\s*color:/;
317315

318-
exports.plainText = function(_str) {
319-
// strip out our pseudo-html so we have a readable
320-
// version to put into text fields
321-
return (_str || '').replace(STRIP_TAGS, ' ');
316+
/**
317+
* Strip string of tags
318+
*
319+
* @param {string} _str : input string
320+
* @param {object} opts :
321+
* - maxLen {number} max length of output string
322+
* - allowedTags {array} list of pseudo-html tags to NOT strip
323+
* @return {string}
324+
*/
325+
exports.plainText = function(_str, opts) {
326+
opts = opts || {};
327+
328+
var len = (opts.len !== undefined && opts.len !== -1) ? opts.len : Infinity;
329+
var allowedTags = opts.allowedTags !== undefined ? opts.allowedTags : ['br'];
330+
331+
var ellipsis = '...';
332+
var eLen = ellipsis.length;
333+
334+
var oldParts = _str.split(SPLIT_TAGS);
335+
var newParts = [];
336+
var prevTag = '';
337+
var l = 0;
338+
339+
for(var i = 0; i < oldParts.length; i++) {
340+
var p = oldParts[i];
341+
var match = p.match(ONE_TAG);
342+
var tagType = match && match[2].toLowerCase();
343+
344+
if(tagType) {
345+
// N.B. tags do not count towards string length
346+
if(allowedTags.indexOf(tagType) !== -1) {
347+
newParts.push(p);
348+
prevTag = tagType;
349+
}
350+
} else {
351+
var pLen = p.length;
352+
353+
if((l + pLen) < len) {
354+
newParts.push(p);
355+
l += pLen;
356+
} else if(l < len) {
357+
var pLen2 = len - l;
358+
359+
if(prevTag && (prevTag !== 'br' || pLen2 <= eLen || pLen <= eLen)) {
360+
newParts.pop();
361+
}
362+
363+
if(len > eLen) {
364+
newParts.push(p.substr(0, pLen2 - eLen) + ellipsis);
365+
} else {
366+
newParts.push(p.substr(0, pLen2));
367+
}
368+
break;
369+
}
370+
371+
prevTag = '';
372+
}
373+
}
374+
375+
return newParts.join('');
322376
};
323377

324378
/*

test/jasmine/tests/svg_text_utils_test.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,4 +468,41 @@ describe('svg+text utils', function() {
468468
expect(node.text()).toEqual('test\u200b5\u200bmore');
469469
});
470470
});
471+
472+
describe('plainText:', function() {
473+
var fn = util.plainText;
474+
475+
it('should strip tags except <br> by default', function() {
476+
expect(fn('a<b>b</b><br><sup>tm</sup>a')).toBe('ab<br>tma');
477+
});
478+
479+
it('should work in various cases w/o <br>', function() {
480+
var sIn = 'ThisIsDATA<sup>300</sup>';
481+
482+
expect(fn(sIn)).toBe('ThisIsDATA300');
483+
expect(fn(sIn, {len: 3})).toBe('Thi');
484+
expect(fn(sIn, {len: 4})).toBe('T...');
485+
expect(fn(sIn, {len: 13})).toBe('ThisIsDATA...');
486+
expect(fn(sIn, {len: 16})).toBe('ThisIsDATA300');
487+
expect(fn(sIn, {allowedTags: ['sup']})).toBe('ThisIsDATA<sup>300</sup>');
488+
expect(fn(sIn, {len: 13, allowedTags: ['sup']})).toBe('ThisIsDATA...');
489+
expect(fn(sIn, {len: 16, allowedTags: ['sup']})).toBe('ThisIsDATA<sup>300</sup>');
490+
});
491+
492+
it('should work in various cases w/ <br>', function() {
493+
var sIn = 'ThisIs<br>DATA<sup>300</sup>';
494+
495+
expect(fn(sIn)).toBe('ThisIs<br>DATA300');
496+
expect(fn(sIn, {len: 3})).toBe('Thi');
497+
expect(fn(sIn, {len: 4})).toBe('T...');
498+
expect(fn(sIn, {len: 7})).toBe('ThisIs...');
499+
expect(fn(sIn, {len: 8})).toBe('ThisIs...');
500+
expect(fn(sIn, {len: 9})).toBe('ThisIs...');
501+
expect(fn(sIn, {len: 10})).toBe('ThisIs<br>D...');
502+
expect(fn(sIn, {len: 13})).toBe('ThisIs<br>DATA...');
503+
expect(fn(sIn, {len: 16})).toBe('ThisIs<br>DATA300');
504+
expect(fn(sIn, {allowedTags: ['sup']})).toBe('ThisIsDATA<sup>300</sup>');
505+
expect(fn(sIn, {allowedTags: ['br', 'sup']})).toBe('ThisIs<br>DATA<sup>300</sup>');
506+
});
507+
});
471508
});

0 commit comments

Comments
 (0)