test( 'can find _super in prototype chain', function ( t ) { expect(1); var grandparent = { talk: () => t.ok( true ) }, parent = create( grandparent ), instance = create( parent ); instance.talk = wrap( parent, 'talk', callSuper ); instance.talk(); });
function initialiseProperties ( ractive, options ) { // Generate a unique identifier, for places where you'd use a weak map if it // existed ractive._guid = 'r-' + uid++; // events ractive._subs = create( null ); // storage for item configuration from instantiation to reset, // like dynamic functions or original values ractive._config = {}; // two-way bindings ractive._twowayBindings = create( null ); // animations (so we can stop any in progress at teardown) ractive._animations = []; // nodes registry ractive.nodes = {}; // live queries ractive._liveQueries = []; ractive._liveComponentQueries = []; // bound data functions ractive._boundFunctions = []; // observers ractive._observers = []; // properties specific to inline components if ( options.component ) { ractive.parent = options.parent; ractive.container = options.container || null; ractive.root = ractive.parent.root; ractive.component = options.component; options.component.instance = ractive; // for hackability, this could be an open option // for any ractive instance, but for now, just // for components and just for ractive... ractive._inlinePartials = options.inlinePartials; } else { ractive.root = ractive; ractive.parent = ractive.container = null; } }
configure: function ( Parent, target, options ) { var name = this.name, option = options[ name ], registry; registry = create( Parent[name] ); for ( let key in option ) { registry[ key ] = option[ key ]; } target[ name ] = registry; },
test( 'only wraps when this._super used in method', function ( t ) { expect(1); var parent = { talk: () => t.ok( true ) }, instance = create( parent ), method = function () {}; t.equal( wrap( parent, 'talk', method), method ); });
test( 'can call _super on parent', function ( t ) { expect(1); var parent = { talk: () => t.ok( true ) }, instance = create( parent ); instance.talk = wrap( parent, 'talk', callSuper ); instance.talk(); });
test( 'parent _super can be added later', function ( t ) { expect(1); var parent = {}, instance = create( parent ); instance.talk = wrap( parent, 'talk', callSuper ); parent.talk = () => t.ok( true ); instance.talk(); });
test( 'safe to use _super with no parent', function ( t ) { expect(1); var parent = {}, instance = create( parent ); instance.talk = wrap( parent, 'talk', function () { this._super() t.ok( true ) } ); instance.talk(); });
test( 'if this._super is non-function, returns as value', function ( t ) { expect(1); var data = { foo: 'bar' }, parent = { talk: data }, instance = create( parent ), method = function () { return this._super(); }; instance.talk = wrap( parent, 'talk', method ); t.equal( instance.talk() , data ); });
test( 'parent instance can be changed', function ( t ) { expect(2); var parent = { talk: () => false }, newParent = { talk: () => t.ok( true ) }, instance = create( parent ); instance.talk = wrap( parent, 'talk', callSuper ); t.equal( instance.talk._parent, parent ); instance.talk._parent = newParent; instance.talk(); });
test( '"this" in methods refers to correct instance', function ( t ) { expect(2); // no fat arrows! that would bind "this" to test method or module! var parent = { talk: function () { t.equal( this, instance, '_super method has correct "this"' ); } }, instance = create( parent ); instance.talk = wrap( parent, 'talk', function () { t.equal( this, instance, 'instance method has correct "this"' ); this._super(); }); instance.talk(); });
export default function readTemplate ( parser ) { let fragment = []; let partials = create( null ); let hasPartials = false; let preserveWhitespace = parser.preserveWhitespace; while ( parser.pos < parser.str.length ) { let pos = parser.pos, item, partial; if ( partial = parser.read( PARTIAL_READERS ) ) { if ( partials[ partial.n ] ) { parser.pos = pos; parser.error( 'Duplicated partial definition' ); } cleanup( partial.f, parser.stripComments, preserveWhitespace, !preserveWhitespace, !preserveWhitespace ); partials[ partial.n ] = partial.f; hasPartials = true; } else if ( item = parser.read( READERS ) ) { fragment.push( item ); } else { parser.error( 'Unexpected template content' ); } } let result = { v: TEMPLATE_VERSION, t: fragment }; if ( hasPartials ) { result.p = partials; } return result; }
var Viewmodel = function ( options ) { var { adapt, data, ractive, computed, mappings } = options, key, mapping; // TODO is it possible to remove this reference? this.ractive = ractive; this.adaptors = adapt; this.onchange = options.onchange; this.cache = {}; // we need to be able to use hasOwnProperty, so can't inherit from null this.cacheMap = create( null ); this.deps = { computed: create( null ), 'default': create( null ) }; this.depsMap = { computed: create( null ), 'default': create( null ) }; this.patternObservers = []; this.specials = create( null ); this.wrapped = create( null ); this.computations = create( null ); this.captureGroups = []; this.unresolvedImplicitDependencies = []; this.changes = []; this.implicitChanges = {}; this.noCascade = {}; this.data = data; // set up explicit mappings this.mappings = create( null ); for ( key in mappings ) { this.map( getKeypath( key ), mappings[ key ] ); } if ( data ) { // if data exists locally, but is missing on the parent, // we transfer ownership to the parent for ( key in data ) { if ( ( mapping = this.mappings[ key ] ) && mapping.getValue() === undefined ) { mapping.setValue( data[ key ] ); } } } for ( key in computed ) { if ( mappings && key in mappings ) { fatal( 'Cannot map to a computed property (\'%s\')', key ); } this.compute( getKeypath( key ), computed[ key ] ); } this.ready = true; };
registryNames.forEach( name => { ractive[ name ] = extend( create( ractive.constructor[ name ] || null ), userOptions[ name ] ); });
function initialiseRactiveInstance ( ractive, userOptions = {}, options = {} ) { var el, viewmodel; if ( Ractive.DEBUG ) { welcome(); } initialiseProperties( ractive, options ); // TODO remove this, eventually defineProperty( ractive, 'data', { get: deprecateRactiveData }); // TODO don't allow `onconstruct` with `new Ractive()`, there's no need for it constructHook.fire( ractive, userOptions ); // Add registries registryNames.forEach( name => { ractive[ name ] = extend( create( ractive.constructor[ name ] || null ), userOptions[ name ] ); }); // Create a viewmodel viewmodel = new Viewmodel({ adapt: getAdaptors( ractive, ractive.adapt, userOptions ), data: dataConfigurator.init( ractive.constructor, ractive, userOptions ), computed: getComputationSignatures( ractive, extend( create( ractive.constructor.prototype.computed ), userOptions.computed ) ), mappings: options.mappings, ractive: ractive, onchange: () => runloop.addRactive( ractive ) }); ractive.viewmodel = viewmodel; // This can't happen earlier, because computed properties may call `ractive.get()`, etc viewmodel.init(); // init config from Parent and options config.init( ractive.constructor, ractive, userOptions ); configHook.fire( ractive ); initHook.begin( ractive ); // // If this is a component with a function `data` property, call the function // // with `ractive` as context (unless the child was also a function) // if ( typeof ractive.constructor.prototype.data === 'function' && typeof userOptions.data !== 'function' ) { // viewmodel.reset( ractive.constructor.prototype.data.call( ractive ) || fatal( '`data` functions must return a data object' ) ); // } // Render virtual DOM if ( ractive.template ) { let cssIds; if ( options.cssIds || ractive.cssId ) { cssIds = options.cssIds ? options.cssIds.slice() : []; if ( ractive.cssId ) { cssIds.push( ractive.cssId ); } } ractive.fragment = new Fragment({ template: ractive.template, root: ractive, owner: ractive, // saves doing `if ( this.parent ) { /*...*/ }` later on cssIds }); } initHook.end( ractive ); // render automatically ( if `el` is specified ) if ( el = getElement( ractive.el ) ) { let promise = ractive.render( el, ractive.append ); if ( Ractive.DEBUG_PROMISES ) { promise.catch( err => { warnOnceIfDebug( 'Promise debugging is enabled, to help solve errors that happen asynchronously. Some browsers will log unhandled promise rejections, in which case you can safely disable promise debugging:\n Ractive.DEBUG_PROMISES = false;' ); warnIfDebug( 'An error happened during rendering', { ractive }); err.stack && logIfDebug( err.stack ); throw err; }); } } }