update: function ( keypath ) { var values; if ( wildcard.test( keypath ) ) { values = getPattern( this.root, keypath ); for ( keypath in values ) { if ( values.hasOwnProperty( keypath ) ) { this.update( keypath ); } } return; } // special case - array mutation should not trigger `array.*` // pattern observer with `array.length` if ( this.root.viewmodel.implicitChanges[ keypath ] ) { return; } if ( this.defer && this.ready ) { runloop.scheduleTask( () => this.getProxy( keypath ).update() ); return; } this.reallyUpdate( keypath ); },
handleChange: function () { runloop.start( this.root ); this.attribute.locked = true; this.root.viewmodel.set( this.keypath, this.getValue() ); runloop.scheduleTask( () => this.attribute.locked = false ); runloop.end(); },
forceUpdate: function () { var value = this.getValue(); if ( value !== undefined ) { this.attribute.locked = true; runloop.addViewmodel( this.root.viewmodel ); runloop.scheduleTask( () => this.attribute.locked = false ); this.root.viewmodel.set( this.keypath, value ); } },
setValue: function ( value ) { if ( !isEqual( value, this.value ) ) { this.value = value; if ( this.defer && this.ready ) { runloop.scheduleTask( () => this.update() ); } else { this.update(); } } },
export default function Element$unrender ( shouldDestroy ) { var binding, bindings; // Detach as soon as we can if ( this.name === 'option' ) { // <option> elements detach immediately, so that // their parent <select> element syncs correctly, and // since option elements can't have transitions anyway this.detach(); } else if ( shouldDestroy ) { runloop.detachWhenReady( this ); } // Children first. that way, any transitions on child elements will be // handled by the current transitionManager if ( this.fragment ) { this.fragment.unrender( false ); } if ( binding = this.binding ) { this.binding.unrender(); this.node._ractive.binding = null; bindings = this.root._twowayBindings[ binding.keypath ]; bindings.splice( bindings.indexOf( binding ), 1 ); } // Remove event handlers if ( this.eventHandlers ) { this.eventHandlers.forEach( h => h.unrender() ); } if ( this.decorator ) { this.decorator.teardown(); } // trigger outro transition if necessary if ( this.root.transitionsEnabled && this.outro ) { let transition = new Transition ( this, this.outro, false ); runloop.registerTransition( transition ); runloop.scheduleTask( () => transition.start() ); } // Remove this node from any live queries if ( this.liveQueries ) { removeFromLiveQueries( this ); } // Remove from nodes if ( this.node.id ) { delete this.root.nodes[ this.node.id ]; } }
export default function Element$render () { var root = this.root, namespace, node; namespace = getNamespace( this ); node = this.node = createElement( this.name, namespace ); // Is this a top-level node of a component? If so, we may need to add // a data-rvcguid attribute, for CSS encapsulation // NOTE: css no longer copied to instance, so we check constructor.css - // we can enhance to handle instance, but this is more "correct" with current // functionality if ( root.constructor.css && this.parentFragment.getNode() === root.el ) { this.node.setAttribute( 'data-rvcguid', root.constructor._guid /*|| root._guid*/ ); } // Add _ractive property to the node - we use this object to store stuff // related to proxy events, two-way bindings etc defineProperty( this.node, '_ractive', { value: { proxy: this, keypath: getInnerContext( this.parentFragment ), index: this.parentFragment.indexRefs, events: create( null ), root: root } }); // Render attributes this.attributes.forEach( a => a.render( node ) ); this.conditionalAttributes.forEach( a => a.render( node ) ); // Render children if ( this.fragment ) { // Special case - <script> element if ( this.name === 'script' ) { this.bubble = updateScript; this.node.text = this.fragment.toString( false ); // bypass warning initially this.fragment.unrender = noop; // TODO this is a kludge } // Special case - <style> element else if ( this.name === 'style' ) { this.bubble = updateCss; this.bubble(); this.fragment.unrender = noop; } // Special case - contenteditable else if ( this.binding && this.getAttribute( 'contenteditable' ) ) { this.fragment.unrender = noop; } else { this.node.appendChild( this.fragment.render() ); } } // Add proxy event handlers if ( this.eventHandlers ) { this.eventHandlers.forEach( h => h.render() ); } // deal with two-way bindings if ( this.binding ) { this.binding.render(); this.node._ractive.binding = this.binding; } // Special case: if this is an <img>, and we're in a crap browser, we may // need to prevent it from overriding width and height when it loads the src if ( this.name === 'img' ) { renderImage( this ); } // apply decorator(s) if ( this.decorator && this.decorator.fn ) { runloop.scheduleTask( () => this.decorator.init(), true ); } // trigger intro transition if ( root.transitionsEnabled && this.intro ) { let transition = new Transition ( this, this.intro, true ); runloop.registerTransition( transition ); runloop.scheduleTask( () => transition.start(), true ); this.transition = transition; } if ( this.name === 'option' ) { processOption( this ); } if ( this.node.autofocus ) { // Special case. Some browsers (*cough* Firefix *cough*) have a problem // with dynamically-generated elements having autofocus, and they won't // allow you to programmatically focus the element until it's in the DOM runloop.scheduleTask( () => this.node.focus(), true ); } updateLiveQueries( this ); return this.node; }