Skip to content

Commit 151e4fd

Browse files
committed
Merge pull request #9 from 'markcarver/patch-2'
2 parents 749734e + d2b6a94 commit 151e4fd

File tree

2 files changed

+89
-7
lines changed

2 files changed

+89
-7
lines changed

lib/parse.js

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,21 @@ var parseTag = require('./parse-tag');
44
// re-used obj for quick lookups of components
55
var empty = Object.create ? Object.create(null) : {};
66
// common logic for pushing a child node onto a list
7-
function pushTextNode(list, html, start) {
7+
function pushTextNode(list, html, level, start, ignoreWhitespace) {
88
// calculate correct end of the content slice in case there's
99
// no tag after the text node.
1010
var end = html.indexOf('<', start);
1111
var content = html.slice(start, end === -1 ? undefined : end);
12-
// if a node is nothing but whitespace, no need to add it.
13-
if (!/^\s*$/.test(content)) {
12+
// if a node is nothing but whitespace, collapse it as the spec states:
13+
// https://www.w3.org/TR/html4/struct/text.html#h-9.1
14+
if (/^\s*$/.test(content)) {
15+
content = ' ';
16+
}
17+
// don't add whitespace-only text nodes if they would be trailing text nodes
18+
// or if they would be leading whitespace-only text nodes:
19+
// * end > -1 indicates this is not a trailing text node
20+
// * leading node is when level is -1 and list has length 0
21+
if ((!ignoreWhitespace && end > -1 && level + list.length >= 0) || content !== ' ') {
1422
list.push({
1523
type: 'text',
1624
content: content
@@ -53,7 +61,7 @@ module.exports = function parse(html, options) {
5361
}
5462

5563
if (!current.voidElement && !inComponent && nextChar && nextChar !== '<') {
56-
pushTextNode(current.children, html, start);
64+
pushTextNode(current.children, html, level, start, options.ignoreWhitespace);
5765
}
5866

5967
byTag[current.tagName] = current;
@@ -81,10 +89,15 @@ module.exports = function parse(html, options) {
8189
// if we're at the root, push a base text node. otherwise add as
8290
// a child to the current node.
8391
parent = level === -1 ? result : arr[level].children;
84-
pushTextNode(parent, html, start);
92+
pushTextNode(parent, html, level, start, options.ignoreWhitespace);
8593
}
8694
}
8795
});
8896

97+
// If the "html" passed isn't actually html, add it as a text node.
98+
if (!result.length && html.length) {
99+
pushTextNode(result, html, 0, 0, options.ignoreWhitespace);
100+
}
101+
89102
return result;
90103
};

test/parse.js

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,10 @@ test('parse', function (t) {
338338
{ type: 'text', content: 'something' }
339339
]
340340
},{
341+
type: 'text',
342+
content: ' '
343+
},
344+
{
341345
type: 'tag',
342346
name: 'a',
343347
attrs: {},
@@ -347,8 +351,66 @@ test('parse', function (t) {
347351
type: 'text', content: 'else '
348352
}], 'should handle text nodes in the middle of tags at the top-level');
349353

350-
html = '<div>Hi</div>\n\n <span>There</span> \t <iframe>\n\t</iframe>';
354+
html = '\n<div> <span>Hi!</span> </div>\n';
355+
parsed = HTML.parse(html);
356+
t.deepEqual(parsed, [{
357+
type: 'tag',
358+
name: 'div',
359+
attrs: {},
360+
voidElement: false,
361+
children: [
362+
{ type: 'text', content: ' '},
363+
{
364+
type: 'tag',
365+
name: 'span',
366+
attrs: {},
367+
voidElement: false,
368+
children: [
369+
{ type: 'text', content: 'Hi!' }
370+
]
371+
},
372+
{ type: 'text', content: ' '}
373+
]
374+
}], 'should trim whitespace from the beginning and end of the parsed nodes');
375+
376+
html = '<div>Hi</div>\n\n <span>There</span> \t <div>\n\t</div>';
351377
parsed = HTML.parse(html);
378+
t.deepEqual(parsed, [{
379+
type: 'tag',
380+
name: 'div',
381+
attrs: {},
382+
voidElement: false,
383+
children: [
384+
{ type: 'text', content: 'Hi' }
385+
]
386+
},{
387+
type: 'text',
388+
content: ' '
389+
},
390+
{
391+
type: 'tag',
392+
name: 'span',
393+
attrs: {},
394+
voidElement: false,
395+
children: [
396+
{ type: 'text', content: 'There' }
397+
]
398+
},{
399+
type: 'text',
400+
content: ' '
401+
},{
402+
type: 'tag',
403+
name: 'div',
404+
attrs: {},
405+
voidElement: false,
406+
children: [
407+
{ type: 'text', content: ' ' }
408+
]
409+
}], 'should collapse whitespace');
410+
// See https://www.w3.org/TR/html4/struct/text.html#h-9.1
411+
412+
html = '<div>Hi</div>\n\n <span>There</span> \t <iframe>\n\t</iframe>';
413+
parsed = HTML.parse(html, { ignoreWhitespace: true });
352414
t.deepEqual(parsed, [{
353415
type: 'tag',
354416
name: 'div',
@@ -371,7 +433,7 @@ test('parse', function (t) {
371433
attrs: {},
372434
voidElement: false,
373435
children: []
374-
}], 'should remove text nodes that are nothing but whitespace');
436+
}], 'should remove text nodes that are nothing but whitespace if the ignoreWhitespace option is passed');
375437

376438
html = '<!--\n\t<style type="text/css">\n\t\t.header {\n\t\t\tfont-size: 14px;\n\t\t}\n\t</style>\n\n-->\n<div>Hi</div>';
377439
parsed = HTML.parse(html);
@@ -410,6 +472,13 @@ test('parse', function (t) {
410472
voidElement: false,
411473
children: []
412474
}], 'should ignore nested HTML comments');
475+
476+
html = 'Hello, world!';
477+
parsed = HTML.parse(html);
478+
t.deepEqual(parsed, [{
479+
type: 'text',
480+
content: 'Hello, world!'
481+
}], 'should handle just text');
413482
t.end();
414483
});
415484

0 commit comments

Comments
 (0)