From a16704fbf03e6d629ca21f4f26e27c400f726f18 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Sun, 18 Dec 2016 10:17:42 -0500 Subject: [PATCH 1/7] use helpers for DOM operations --- src/generators/dom/index.js | 77 +++++++++++++------ src/generators/dom/visitors/Element.js | 19 ++++- src/generators/dom/visitors/MustacheTag.js | 3 +- src/generators/dom/visitors/RawMustacheTag.js | 6 +- src/generators/dom/visitors/Text.js | 4 +- src/shared/index.js | 29 +++++++ 6 files changed, 105 insertions(+), 33 deletions(-) create mode 100644 src/shared/index.js diff --git a/src/generators/dom/index.js b/src/generators/dom/index.js index 8088fbc91220..000ec6d75ffe 100644 --- a/src/generators/dom/index.js +++ b/src/generators/dom/index.js @@ -5,11 +5,13 @@ import namespaces from '../../utils/namespaces.js'; import processCss from '../shared/css/process.js'; import visitors from './visitors/index.js'; import Generator from '../Generator.js'; +import * as shared from '../../shared/index.js'; class DomGenerator extends Generator { constructor ( parsed, source, names, visitors ) { super( parsed, source, names, visitors ); this.renderers = []; + this.uses = {}; } addElement ( name, renderStatement, needsIdentifier = false ) { @@ -21,15 +23,13 @@ class DomGenerator extends Generator { this.createMountStatement( name ); } else { - this.current.builders.init.addLine( - `${this.current.target}.appendChild( ${renderStatement} );` - ); + this.uses.appendNode = true; + this.current.builders.init.addLine( `appendNode( ${renderStatement}, ${this.current.target} );` ); } if ( isToplevel ) { - this.current.builders.detach.addLine( - `${name}.parentNode.removeChild( ${name} );` - ); + this.uses.detachNode = true; + this.current.builders.detach.addLine( `detachNode( ${name} );` ); } } @@ -54,19 +54,38 @@ class DomGenerator extends Generator { if ( fragment.key ) properties.addBlock( `key: key,` ); - properties.addBlock( deindent` - mount: function ( target, anchor ) { - ${fragment.builders.mount} - }, + if ( fragment.builders.mount.isEmpty() ) { + this.uses.noop = true; + properties.addBlock( `mount: noop,` ); + } else { + properties.addBlock( deindent` + mount: function ( target, anchor ) { + ${fragment.builders.mount} + }, + ` ); + } - update: function ( changed, ${fragment.params} ) { - ${fragment.builders.update} - }, + if ( fragment.builders.update.isEmpty() ) { + this.uses.noop = true; + properties.addBlock( `update: noop,` ); + } else { + properties.addBlock( deindent` + update: function ( changed, ${fragment.params} ) { + ${fragment.builders.update} + }, + ` ); + } - teardown: function ( detach ) { - ${fragment.builders.teardown} - } - ` ); + if ( fragment.builders.teardown.isEmpty() ) { + this.uses.noop = true; + properties.addBlock( `teardown: noop,` ); + } else { + properties.addBlock( deindent` + teardown: function ( detach ) { + ${fragment.builders.teardown} + }, + ` ); + } this.renderers.push( deindent` function ${fragment.name} ( ${fragment.params}, component${fragment.key ? `, key` : ''} ) { @@ -80,18 +99,18 @@ class DomGenerator extends Generator { } createAnchor ( name, description = '' ) { - const renderStatement = `document.createComment( ${JSON.stringify( description )} )`; + this.uses.createComment = true; + const renderStatement = `createComment( ${JSON.stringify( description )} )`; this.addElement( name, renderStatement, true ); } createMountStatement ( name ) { if ( this.current.target === 'target' ) { - this.current.builders.mount.addLine( - `target.insertBefore( ${name}, anchor );` - ); + this.uses.insertNode = true; + this.current.builders.mount.addLine( `insertNode( ${name}, target, anchor );` ); } else { - this.current.builders.init.addLine( - `${this.current.target}.appendChild( ${name} );` ); + this.uses.appendNode = true; + this.current.builders.init.addLine( `appendNode( ${name}, ${this.current.target} );` ); } } @@ -192,12 +211,15 @@ export default function dom ( parsed, source, options, names ) { } if ( parsed.css && options.css !== false ) { + generator.uses.appendNode = true; + generator.uses.createElement = true; + builders.main.addBlock( deindent` let addedCss = false; function addCss () { - var style = document.createElement( 'style' ); + var style = createElement( 'style' ); style.textContent = ${JSON.stringify( processCss( parsed ) )}; - document.head.appendChild( style ); + appendNode( style, document.head ); addedCss = true; } @@ -364,5 +386,10 @@ export default function dom ( parsed, source, options, names ) { builders.main.addBlock( `${name}.prototype = template.methods;` ); } + Object.keys( generator.uses ).forEach( key => { + const fn = shared[ key ]; // eslint-disable-line import/namespace + builders.main.addBlock( fn.toString() ); + }); + return generator.generate( builders.main.toString(), options, { name, format } ); } diff --git a/src/generators/dom/visitors/Element.js b/src/generators/dom/visitors/Element.js index 9409ff97107e..92bfec050017 100644 --- a/src/generators/dom/visitors/Element.js +++ b/src/generators/dom/visitors/Element.js @@ -57,9 +57,19 @@ export default { local.update.addBlock( updates ); } - let render = local.namespace ? - `var ${name} = document.createElementNS( '${local.namespace}', '${node.name}' );` : - `var ${name} = document.createElement( '${node.name}' );`; + let render; + + if ( local.namespace ) { + if ( local.namespace === 'http://www.w3.org/2000/svg' ) { + generator.uses.createSvgElement = true; + render = `var ${name} = createSvgElement( '${node.name}' )`; + } else { + render = `var ${name} = document.createElementNS( '${local.namespace}', '${node.name}' );`; + } + } else { + generator.uses.createElement = true; + render = `var ${name} = createElement( '${node.name}' );`; + } if ( generator.cssId && !generator.elementDepth ) { render += `\n${name}.setAttribute( '${generator.cssId}', '' );`; @@ -67,7 +77,8 @@ export default { local.init.addLineAtStart( render ); if ( isToplevel ) { - generator.current.builders.detach.addLine( `${name}.parentNode.removeChild( ${name} );` ); + generator.uses.detachNode = true; + generator.current.builders.detach.addLine( `detachNode( ${name} );` ); } // special case – bound