Skip to content
This repository was archived by the owner on Apr 4, 2019. It is now read-only.

Commit a09bed6

Browse files
author
Godhuda
committed
Support adjacent text nodes
1 parent db6462f commit a09bed6

File tree

3 files changed

+68
-7
lines changed

3 files changed

+68
-7
lines changed

packages/dom-helper/lib/main.js

+26
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,32 @@ prototype.parseHTML = function(html, contextualElement) {
550550
return fragment;
551551
};
552552

553+
const SHOW_TEXT = 4;
554+
555+
prototype.preserveAdjacentTextNodes = function(root) {
556+
let iterator = this.document.createNodeIterator(root, SHOW_TEXT, function(node) {
557+
return node.previousSibling && node.previousSibling.nodeType === 3;
558+
});
559+
560+
let node;
561+
562+
/*jshint boss:true*/
563+
while (node = iterator.nextNode()) {
564+
let element = this.createElement('script');
565+
this.setAttribute(element, 'data-hbs-split', '');
566+
node.parentNode.insertBefore(element, node);
567+
}
568+
};
569+
570+
prototype.restoreAdjacentTextNodes = function(root) {
571+
let elements = root.querySelectorAll('script[data-hbs-split]');
572+
573+
for (let i=0, l=elements.length; i<l; i++) {
574+
let element = elements[i];
575+
element.parentNode.removeChild(element);
576+
}
577+
};
578+
553579
var parsingNode;
554580

555581
// Used to determine whether a URL needs to be sanitized.

packages/htmlbars-compiler/tests/dirtying-test.js

+32-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import defaultHooks from "../htmlbars-runtime/hooks";
77
import { merge } from "../htmlbars-util/object-utils";
88
import DOMHelper from "../dom-helper";
99
import { equalTokens } from "../htmlbars-test-helpers";
10-
import { rehydrateNode, serializeNode } from "../htmlbars-runtime/render";
10+
import { rehydrateNode, prepareAndSerializeNode } from "../htmlbars-runtime/render";
1111

1212
var hooks, helpers, partials, env;
1313

@@ -678,7 +678,7 @@ test("it is possible to serialize a render node tree", function() {
678678
let original = result.fragment.firstChild;
679679
let newRoot = env.dom.createMorph(null, original, original);
680680
newRoot.ownerNode = newRoot;
681-
let node = rehydrateNode(serializeNode(env, result.root), newRoot);
681+
let node = rehydrateNode(prepareAndSerializeNode(env, result.root), newRoot);
682682

683683
let scope = env.hooks.createFreshScope();
684684

@@ -703,7 +703,7 @@ test("it is possible to serialize a render node tree with recursive templates",
703703

704704
let newRoot = env.dom.createMorph(null, original, original);
705705
newRoot.ownerNode = newRoot;
706-
let node = rehydrateNode(serializeNode(env, result.root), newRoot);
706+
let node = rehydrateNode(prepareAndSerializeNode(env, result.root), newRoot);
707707

708708
let scope = env.hooks.createFreshScope();
709709

@@ -718,3 +718,32 @@ test("it is possible to serialize a render node tree with recursive templates",
718718

719719
equalTokens(newNode, '<p title="chancancode"><span>Godfrey</span></p>');
720720
});
721+
722+
test("it is possible to serialize a template with adjacent text nodes", function() {
723+
let template = compile("<p>{{salutation}} {{name}}</p>");
724+
let obj = { salutation: 'Mr.', name: 'Godfrey Chan' };
725+
let result = template.render(obj, env);
726+
727+
equalTokens(result.fragment, '<p>Mr. Godfrey Chan</p>');
728+
729+
let serializedChildNodes = prepareAndSerializeNode(env, result.root);
730+
let serialized = result.fragment.cloneNode(true).firstChild;
731+
732+
// TODO: actually serialize and parse this, so it works with SimpleDOM and is more accurate
733+
// at the moment, this is a sanity check that we didn't leave any adjacent text nodes
734+
// around.
735+
serialized.normalize();
736+
737+
let newRoot = env.dom.createMorph(null, serialized, serialized);
738+
739+
let newNode = rehydrateNode(serializedChildNodes, newRoot);
740+
741+
let scope = env.hooks.createFreshScope();
742+
743+
obj.name = "Yehuda Katz";
744+
result = RenderResult.rehydrate(env, scope, template.raw, { renderNode: newNode, self: obj });
745+
newRoot.ownerNode = newRoot;
746+
result.render();
747+
748+
equalTokens(result.root.firstNode, '<p>Mr. Yehuda Katz</p>');
749+
});

packages/htmlbars-runtime/lib/render.js

+10-4
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ export function getCachedFragment(template, env) {
331331
export function rehydrateNode(serializedNodes, renderNode) {
332332
let dom = renderNode.domHelper;
333333
let context = renderNode.firstNode.parentNode;
334+
dom.restoreAdjacentTextNodes(context);
334335
let cache = Object.create(null);
335336

336337
renderNode.childNodes = serializedNodes.map(childNode => _rehydrateNode(renderNode, childNode, dom, context, cache));
@@ -368,10 +369,12 @@ function elementFromId(dom, context, id, cache) {
368369
return element;
369370
}
370371

371-
export function serializeNode(env, renderNode) {
372+
export function prepareAndSerializeNode(env, renderNode) {
372373
let serializationContext = { id: 0 };
373374

374-
return renderNode.childNodes.map(childNode => _serializeNode(env, childNode, serializationContext));
375+
let serialized = renderNode.childNodes.map(childNode => _serializeNode(env, childNode, serializationContext));
376+
env.dom.preserveAdjacentTextNodes(renderNode.firstNode.parentNode);
377+
return serialized;
375378

376379
//return [{
377380
//type: 'attr',
@@ -413,18 +416,21 @@ function parentOffsets(dom, parent, renderNode) {
413416
let firstNeedle = renderNode.firstNode;
414417
let lastNeedle = renderNode.lastNode;
415418
let firstNode, lastNode;
419+
let offset = 0;
416420

417421
while (current !== firstNeedle) {
422+
offset++;
418423
current = current.nextSibling;
419424
}
420425

421-
firstNode = current;
426+
firstNode = offset;
422427

423428
while (current !== lastNeedle) {
429+
offset++;
424430
current = current.nextSibling;
425431
}
426432

427-
lastNode = current;
433+
lastNode = offset;
428434

429435
return { firstNode, lastNode };
430436
}

0 commit comments

Comments
 (0)