UNPKG

ractive

Version:

Next-generation DOM manipulation

96 lines (71 loc) 2.6 kB
import circular from 'circular'; import isArray from 'utils/isArray'; import isEqual from 'utils/isEqual'; var runloop; circular.push( () => runloop = circular.runloop ); var Binding = function ( ractive, keypath, otherInstance, otherKeypath, priority ) { this.root = ractive; this.keypath = keypath; this.priority = priority; this.otherInstance = otherInstance; this.otherKeypath = otherKeypath; this.bind(); this.value = this.root.viewmodel.get( this.keypath ); }; Binding.prototype = { setValue: function ( value ) { // Only *you* can prevent infinite loops if ( this.updating || this.counterpart && this.counterpart.updating ) { this.value = value; return; } // Is this a smart array update? If so, it'll update on its // own, we shouldn't do anything if ( isArray( value ) && value._ractive && value._ractive.setting ) { return; } if ( !isEqual( value, this.value ) ) { this.updating = true; // TODO maybe the case that `value === this.value` - should that result // in an update rather than a set? runloop.addViewmodel( this.otherInstance.viewmodel ); this.otherInstance.viewmodel.set( this.otherKeypath, value ); this.value = value; // TODO will the counterpart update after this line, during // the runloop end cycle? may be a problem... runloop.scheduleTask( () => this.updating = false ); } }, bind: function () { this.root.viewmodel.register( this.keypath, this ); }, rebind: function ( newKeypath ) { this.unbind(); this.keypath = newKeypath; this.counterpart.otherKeypath = newKeypath; this.bind(); }, unbind: function () { this.root.viewmodel.unregister( this.keypath, this ); } }; export default function createComponentBinding ( component, parentInstance, parentKeypath, childKeypath ) { var hash, childInstance, bindings, priority, parentToChildBinding, childToParentBinding; hash = parentKeypath + '=' + childKeypath; bindings = component.bindings; if ( bindings[ hash ] ) { // TODO does this ever happen? return; } bindings[ hash ] = true; childInstance = component.instance; priority = component.parentFragment.priority; parentToChildBinding = new Binding( parentInstance, parentKeypath, childInstance, childKeypath, priority ); bindings.push( parentToChildBinding ); if ( childInstance.twoway ) { childToParentBinding = new Binding( childInstance, childKeypath, parentInstance, parentKeypath, 1 ); bindings.push( childToParentBinding ); parentToChildBinding.counterpart = childToParentBinding; childToParentBinding.counterpart = parentToChildBinding; } }