From 9d37ae4f4b0a53a834062b1e9c93638b0727ab24 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Sun, 18 Dec 2016 12:23:32 -0500 Subject: [PATCH] move methods out of constructor --- src/generators/dom/index.js | 135 +++++++++++------------------------- src/shared/dom.js | 27 ++++++++ src/shared/index.js | 40 +++++------ src/shared/methods.js | 43 ++++++++++++ 4 files changed, 130 insertions(+), 115 deletions(-) create mode 100644 src/shared/dom.js create mode 100644 src/shared/methods.js diff --git a/src/generators/dom/index.js b/src/generators/dom/index.js index 000ec6d75f..ecfcbab600 100644 --- a/src/generators/dom/index.js +++ b/src/generators/dom/index.js @@ -177,8 +177,8 @@ export default function dom ( parsed, source, options, names ) { set: new CodeBuilder() }; - builders.set.addLine( 'var oldState = state;' ); - builders.set.addLine( 'state = Object.assign( {}, oldState, newState );' ); + builders.set.addLine( 'var oldState = this._state;' ); + builders.set.addLine( 'this._state = Object.assign( {}, oldState, newState );' ); if ( computations.length ) { const builder = new CodeBuilder(); @@ -197,13 +197,14 @@ export default function dom ( parsed, source, options, names ) { } ` ); - builders.set.addLine( `applyComputations( state, newState, oldState )` ); + builders.set.addLine( `applyComputations( this._state, newState, oldState )` ); } + // TODO is the `if` necessary? builders.set.addBlock( deindent` - dispatchObservers( observers.immediate, newState, oldState ); - if ( mainFragment ) mainFragment.update( newState, state ); - dispatchObservers( observers.deferred, newState, oldState ); + dispatchObservers( this, this._observers.pre, newState, oldState ); + if ( this._fragment ) this._fragment.update( newState, this._state ); + dispatchObservers( this, this._observers.post, newState, oldState ); ` ); if ( parsed.js ) { @@ -240,7 +241,7 @@ export default function dom ( parsed, source, options, names ) { if ( generator.hasComplexBindings ) { builders.init.addBlock( deindent` this.__bindings = []; - var mainFragment = renderMainFragment( state, this ); + this._fragment = renderMainFragment( this._state, this ); if ( options.target ) this._mount( options.target ); while ( this.__bindings.length ) this.__bindings.pop()(); ` ); @@ -248,7 +249,7 @@ export default function dom ( parsed, source, options, names ) { builders.set.addLine( `while ( this.__bindings.length ) this.__bindings.pop()();` ); } else { builders.init.addBlock( deindent` - var mainFragment = renderMainFragment( state, this ); + this._fragment = renderMainFragment( this._state, this ); if ( options.target ) this._mount( options.target ); ` ); } @@ -280,105 +281,44 @@ export default function dom ( parsed, source, options, names ) { builders.main.addBlock( deindent` function ${name} ( options ) { options = options || {}; + ${generator.usesRefs ? `\nthis.refs = {}` : ``} + this._state = ${initialState};${templateProperties.computed ? `\napplyComputations( this._state, this._state, {} );` : ``} - var component = this;${generator.usesRefs ? `\nthis.refs = {}` : ``} - var state = ${initialState};${templateProperties.computed ? `\napplyComputations( state, state, {} );` : ``} - - var observers = { - immediate: Object.create( null ), - deferred: Object.create( null ) - }; - - var callbacks = Object.create( null ); - - function dispatchObservers ( group, newState, oldState ) { - for ( var key in group ) { - if ( !( key in newState ) ) continue; - - var newValue = newState[ key ]; - var oldValue = oldState[ key ]; - - if ( newValue === oldValue && typeof newValue !== 'object' ) continue; - - var callbacks = group[ key ]; - if ( !callbacks ) continue; - - for ( var i = 0; i < callbacks.length; i += 1 ) { - var callback = callbacks[i]; - if ( callback.__calling ) continue; - - callback.__calling = true; - callback.call( component, newValue, oldValue ); - callback.__calling = false; - } - } - } - - this.fire = function fire ( eventName, data ) { - var handlers = eventName in callbacks && callbacks[ eventName ].slice(); - if ( !handlers ) return; - - for ( var i = 0; i < handlers.length; i += 1 ) { - handlers[i].call( this, data ); - } + this._observers = { + pre: Object.create( null ), + post: Object.create( null ) }; - this.get = function get ( key ) { - return key ? state[ key ] : state; - }; + this._handlers = Object.create( null ); - this.set = function set ( newState ) { - ${builders.set} - }; + this.get = get; + this.fire = fire; + this.observe = observe; + this.on = on; + this.set = set; + this.teardown = teardown; this._mount = function mount ( target, anchor ) { - mainFragment.mount( target, anchor ); + this._fragment.mount( target, anchor ); } - this.observe = function ( key, callback, options ) { - var group = ( options && options.defer ) ? observers.deferred : observers.immediate; - - ( group[ key ] || ( group[ key ] = [] ) ).push( callback ); - - if ( !options || options.init !== false ) { - callback.__calling = true; - callback.call( component, state[ key ] ); - callback.__calling = false; - } - - return { - cancel: function () { - var index = group[ key ].indexOf( callback ); - if ( ~index ) group[ key ].splice( index, 1 ); - } - }; - }; - - this.on = function on ( eventName, handler ) { - var handlers = callbacks[ eventName ] || ( callbacks[ eventName ] = [] ); - handlers.push( handler ); - - return { - cancel: function () { - var index = handlers.indexOf( handler ); - if ( ~index ) handlers.splice( index, 1 ); - } - }; - }; + this.root = options.root; + this.yield = options.yield; - this.teardown = function teardown ( detach ) { - this.fire( 'teardown' );${templateProperties.onteardown ? `\ntemplate.onteardown.call( this );` : ``} + ${builders.init} + } - mainFragment.teardown( detach !== false ); - mainFragment = null; + function set ( newState ) { + ${builders.set} + } - state = {}; - }; + function teardown ( detach ) { + this.fire( 'teardown' );${templateProperties.onteardown ? `\ntemplate.onteardown.call( this );` : ``} - this.root = options.root; - this.yield = options.yield; + this._fragment.teardown( detach !== false ); + this._fragment = null; - ${builders.init} + this._state = {}; } ` ); @@ -386,6 +326,13 @@ export default function dom ( parsed, source, options, names ) { builders.main.addBlock( `${name}.prototype = template.methods;` ); } + builders.main.addBlock( shared.fire.toString() ); + builders.main.addBlock( shared.get.toString() ); + builders.main.addBlock( shared.observe.toString() ); + builders.main.addBlock( shared.on.toString() ); + + builders.main.addBlock( shared.dispatchObservers.toString() ); + Object.keys( generator.uses ).forEach( key => { const fn = shared[ key ]; // eslint-disable-line import/namespace builders.main.addBlock( fn.toString() ); diff --git a/src/shared/dom.js b/src/shared/dom.js new file mode 100644 index 0000000000..9db9b03386 --- /dev/null +++ b/src/shared/dom.js @@ -0,0 +1,27 @@ +export function appendNode ( node, target ) { + target.appendChild( node ); +} + +export function insertNode ( node, target, anchor ) { + target.insertBefore( node, anchor ); +} + +export function detachNode ( node ) { + node.parentNode.removeChild( node ); +} + +export function createElement ( name ) { + return document.createElement( name ); +} + +export function createSvgElement ( name ) { + return document.createElementNS( 'http://www.w3.org/2000/svg', name ); +} + +export function createText ( data ) { + return document.createTextNode( data ); +} + +export function createComment ( data ) { + return document.createComment( data ); +} diff --git a/src/shared/index.js b/src/shared/index.js index 55bc1c0433..7f76df1b45 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -1,29 +1,27 @@ -export function noop () {} +export * from './dom.js'; +export * from './methods.js'; -export function appendNode ( node, target ) { - target.appendChild( node ); -} +export function noop () {} -export function insertNode ( node, target, anchor ) { - target.insertBefore( node, anchor ); -} +export function dispatchObservers ( component, group, newState, oldState ) { + for ( var key in group ) { + if ( !( key in newState ) ) continue; -export function detachNode ( node ) { - node.parentNode.removeChild( node ); -} + var newValue = newState[ key ]; + var oldValue = oldState[ key ]; -export function createElement ( name ) { - return document.createElement( name ); -} + if ( newValue === oldValue && typeof newValue !== 'object' ) continue; -export function createSvgElement ( name ) { - return document.createElementNS( 'http://www.w3.org/2000/svg', name ); -} + var callbacks = group[ key ]; + if ( !callbacks ) continue; -export function createText ( data ) { - return document.createTextNode( data ); -} + for ( var i = 0; i < callbacks.length; i += 1 ) { + var callback = callbacks[i]; + if ( callback.__calling ) continue; -export function createComment ( data ) { - return document.createComment( data ); + callback.__calling = true; + callback.call( component, newValue, oldValue ); + callback.__calling = false; + } + } } diff --git a/src/shared/methods.js b/src/shared/methods.js new file mode 100644 index 0000000000..4595a13523 --- /dev/null +++ b/src/shared/methods.js @@ -0,0 +1,43 @@ +export function get ( key ) { + return key ? this._state[ key ] : this._state; +} + +export function fire ( eventName, data ) { + var handlers = eventName in this._handlers && this._handlers[ eventName ].slice(); + if ( !handlers ) return; + + for ( var i = 0; i < handlers.length; i += 1 ) { + handlers[i].call( this, data ); + } +} + +export function observe ( key, callback, options ) { + var group = ( options && options.defer ) ? this._observers.pre : this._observers.post; + + ( group[ key ] || ( group[ key ] = [] ) ).push( callback ); + + if ( !options || options.init !== false ) { + callback.__calling = true; + callback.call( this, this._state[ key ] ); + callback.__calling = false; + } + + return { + cancel: function () { + var index = group[ key ].indexOf( callback ); + if ( ~index ) group[ key ].splice( index, 1 ); + } + }; +} + +export function on ( eventName, handler ) { + var handlers = this._handlers[ eventName ] || ( this._handlers[ eventName ] = [] ); + handlers.push( handler ); + + return { + cancel: function () { + var index = handlers.indexOf( handler ); + if ( ~index ) handlers.splice( index, 1 ); + } + }; +}