diff --git a/src/generators/dom/index.ts b/src/generators/dom/index.ts index 6306645fa7..2252126861 100644 --- a/src/generators/dom/index.ts +++ b/src/generators/dom/index.ts @@ -233,8 +233,7 @@ export default function dom( this._fragment = ${generator.alias( 'create_main_fragment' - )}( this._state, this ); - if ( options.target ) this._fragment.mount( options.target, null ); + )}( options.target, 0, this._state, this ); ${generator.hasComplexBindings && `while ( this._bindings.length ) this._bindings.pop()();`} ${(generator.hasComponents || generator.hasIntroTransitions) && diff --git a/src/generators/dom/preprocess.ts b/src/generators/dom/preprocess.ts index 93cbbf7e4b..786988c8fd 100644 --- a/src/generators/dom/preprocess.ts +++ b/src/generators/dom/preprocess.ts @@ -355,7 +355,7 @@ export default function preprocess( indexes: new Map(), contextDependencies: new Map(), - params: ['state'], + params: ['target', 'h', 'state'], indexNames: new Map(), listNames: new Map(), diff --git a/src/generators/dom/visitors/Element/Element.ts b/src/generators/dom/visitors/Element/Element.ts index a35177c073..2f701dff6b 100644 --- a/src/generators/dom/visitors/Element/Element.ts +++ b/src/generators/dom/visitors/Element/Element.ts @@ -178,18 +178,34 @@ export default function visitElement( } } +// function getRenderStatement( +// generator: DomGenerator, +// namespace: string, +// name: string +// ) { +// if (namespace === 'http://www.w3.org/2000/svg') { +// return `${generator.helper('createSvgElement')}( '${name}' )`; +// } + +// if (namespace) { +// return `document.createElementNS( '${namespace}', '${name}' )`; +// } + +// return `${generator.helper('createElement')}( '${name}' )`; +// } + function getRenderStatement( generator: DomGenerator, namespace: string, name: string ) { - if (namespace === 'http://www.w3.org/2000/svg') { - return `${generator.helper('createSvgElement')}( '${name}' )`; - } + // if (namespace === 'http://www.w3.org/2000/svg') { + // return `${generator.helper('createSvgElement')}( '${name}' )`; + // } - if (namespace) { - return `document.createElementNS( '${namespace}', '${name}' )`; - } + // if (namespace) { + // return `document.createElementNS( '${namespace}', '${name}' )`; + // } - return `${generator.helper('createElement')}( '${name}' )`; + return `${generator.helper('hydrateElement')}( target, h, '${name.toUpperCase()}' )`; } diff --git a/src/generators/dom/visitors/Text.ts b/src/generators/dom/visitors/Text.ts index b8a3850142..9d316a8ae0 100644 --- a/src/generators/dom/visitors/Text.ts +++ b/src/generators/dom/visitors/Text.ts @@ -10,10 +10,32 @@ export default function visitText( node: Node ) { if (!node._state.shouldCreate) return; - block.addElement( - node._state.name, - `${generator.helper('createText')}( ${JSON.stringify(node.data)} )`, - state.parentNode, - node.usedAsAnchor + + const isTopLevel = !state.parentNode; + let h; + if (!isTopLevel) { + h = block.getUniqueName(`${state.parentNode}_i`) + block.addVariable(h, 0); + } else { + h = block.alias('h'); + } + + const prefix = state.parentNode && !node.usedAsAnchor ? '' : `var ${node._state.name} = `; + + block.builders.create.addLine( + `${prefix}${generator.helper('hydrateText')}( ${state.parentNode || 'target'}, ${h}++, ${JSON.stringify(node.data)} )` ); + + if (!state.parentNode) { + this.builders.unmount.addLine( + `${this.generator.helper('detachNode')}( ${name} );` + ); + } + + // block.addElement( + // node._state.name, + // `${generator.helper('hydrateText')}( ${state.parentNode}, 0, ${JSON.stringify(node.data)} )`, + // state.parentNode, + // node.usedAsAnchor + // ); } diff --git a/src/shared/dom.js b/src/shared/dom.js index fba7af93d4..685923f73d 100644 --- a/src/shared/dom.js +++ b/src/shared/dom.js @@ -66,3 +66,31 @@ export function getBindingGroupValue(group) { export function toNumber(value) { return value === '' ? undefined : +value; } + +export function hydrateElement(target, i, type) { // TODO attrs + var child; + while (child = target.childNodes[i]) { + if (child.nodeName === type) { + return child; + } + target.removeChild(child); + } + + child = createElement(type); + target.appendChild(child); + return child; +} + +export function hydrateText(target, i, data) { + var child; + while (child = target.childNodes[i]) { + if (child.nodeType === 3) { + return (child.data = data, child); + } + target.removeChild(child); + } + + child = createText(data); + target.appendChild(child); + return child; +} \ No newline at end of file diff --git a/test/hydration/samples/dynamic-text-changed/_after.html b/test/hydration/samples/dynamic-text-changed/_after.html new file mode 100644 index 0000000000..c675400a49 --- /dev/null +++ b/test/hydration/samples/dynamic-text-changed/_after.html @@ -0,0 +1 @@ +

Hello everybody!

\ No newline at end of file diff --git a/test/hydration/samples/dynamic-text-changed/_before.html b/test/hydration/samples/dynamic-text-changed/_before.html new file mode 100644 index 0000000000..efe5048cbc --- /dev/null +++ b/test/hydration/samples/dynamic-text-changed/_before.html @@ -0,0 +1 @@ +

Hello world!

\ No newline at end of file diff --git a/test/hydration/samples/dynamic-text-changed/_config.js b/test/hydration/samples/dynamic-text-changed/_config.js new file mode 100644 index 0000000000..e836ebf4b2 --- /dev/null +++ b/test/hydration/samples/dynamic-text-changed/_config.js @@ -0,0 +1,21 @@ +export default { + data: { + name: 'everybody' + }, + + snapshot(target) { + const h1 = target.querySelector('h1'); + + return { + h1, + text: h1.childNodes[0] + }; + }, + + test(assert, target, snapshot) { + const h1 = target.querySelector('h1'); + + assert.equal(h1, snapshot.h1); + assert.equal(h1.childNodes[0], snapshot.text); + } +}; \ No newline at end of file diff --git a/test/hydration/samples/dynamic-text-changed/main.html b/test/hydration/samples/dynamic-text-changed/main.html new file mode 100644 index 0000000000..c8dd28836a --- /dev/null +++ b/test/hydration/samples/dynamic-text-changed/main.html @@ -0,0 +1 @@ +

Hello {{name}}!

\ No newline at end of file diff --git a/test/hydration/samples/dynamic-text/_after.html b/test/hydration/samples/dynamic-text/_after.html new file mode 100644 index 0000000000..efe5048cbc --- /dev/null +++ b/test/hydration/samples/dynamic-text/_after.html @@ -0,0 +1 @@ +

Hello world!

\ No newline at end of file diff --git a/test/hydration/samples/dynamic-text/_before.html b/test/hydration/samples/dynamic-text/_before.html new file mode 100644 index 0000000000..efe5048cbc --- /dev/null +++ b/test/hydration/samples/dynamic-text/_before.html @@ -0,0 +1 @@ +

Hello world!

\ No newline at end of file diff --git a/test/hydration/samples/dynamic-text/_config.js b/test/hydration/samples/dynamic-text/_config.js new file mode 100644 index 0000000000..3ca70ee5d2 --- /dev/null +++ b/test/hydration/samples/dynamic-text/_config.js @@ -0,0 +1,21 @@ +export default { + data: { + name: 'world' + }, + + snapshot(target) { + const h1 = target.querySelector('h1'); + + return { + h1, + text: h1.childNodes[0] + }; + }, + + test(assert, target, snapshot) { + const h1 = target.querySelector('h1'); + + assert.equal(h1, snapshot.h1); + assert.equal(h1.childNodes[0], snapshot.text); + } +}; \ No newline at end of file diff --git a/test/hydration/samples/dynamic-text/main.html b/test/hydration/samples/dynamic-text/main.html new file mode 100644 index 0000000000..c8dd28836a --- /dev/null +++ b/test/hydration/samples/dynamic-text/main.html @@ -0,0 +1 @@ +

Hello {{name}}!

\ No newline at end of file