UNPKG

ractive

Version:

Next-generation DOM manipulation

167 lines (108 loc) 3.02 kB
import wrap from 'utils/wrapMethod'; var dataConfig = { name: 'data', extend: extend, init: init, reset: reset }; export default dataConfig; function combine( Parent, target, options ) { var value = options.data || {}, parentValue = getAddedKeys( Parent.prototype.data ); return dispatch( parentValue, value ); } function extend( Parent, proto, options ) { proto.data = combine( Parent, proto, options ); } function init ( Parent, ractive, options ) { var value = options.data, result = combine( Parent, ractive, options ); if ( typeof result === 'function' ) { result = result.call( ractive, value ) || value; } return ractive.data = result || {}; } function reset ( ractive ) { var result = this.init( ractive.constructor, ractive, ractive ); if ( result ) { ractive.data = result; return true; } } function getAddedKeys( parent ) { // only for functions that had keys added if ( typeof parent !== 'function' || !Object.keys( parent ).length ) { return parent; } // copy the added keys to temp 'object', otherwise // parent would be interpreted as 'function' by dispatch let temp = {}; copy( parent, temp ); // roll in added keys return dispatch( parent, temp ); } function dispatch ( parent, child ) { if ( typeof child === 'function' ) { return extendFn( child, parent ); } else if ( typeof parent === 'function' ){ return fromFn( child, parent ); } else { return fromProperties( child, parent ); } } function copy ( from, to, fillOnly ) { for ( let key in from ) { if ( fillOnly && key in to ) { continue; } to[ key ] = from[ key ]; } } function fromProperties ( child, parent ) { child = child || {}; if ( !parent ) { return child; } copy( parent, child, true ); return child; } function fromFn ( child, parentFn ) { return function( data ){ var keys; if ( child ) { // Track the keys that our on the child, // but not on the data. We'll need to apply these // after the parent function returns. keys = []; for ( let key in child ) { if ( !data || !( key in data ) ) { keys.push( key ); } } } // call the parent fn, use data if no return value data = parentFn.call( this, data ) || data; // Copy child keys back onto data. The child keys // should take precedence over whatever the // parent did with the data. if ( keys && keys.length ) { data = data || {}; keys.forEach( key => { data[ key ] = child[ key ]; }); } return data; }; } function extendFn ( childFn, parent ) { var parentFn; if( typeof parent !== 'function' ) { // copy props to data parentFn = function ( data ) { fromProperties ( data, parent ); }; } else { parentFn = function ( data ) { // give parent function it's own this._super context, // otherwise this._super is from child and // causes infinite loop parent = wrap( parent, () => {}, true ); return parent.call( this, data ) || data; }; } return wrap( childFn, parentFn ); }