diff --git a/bind.js b/bind.js index 18f4bf7..22d7624 100644 --- a/bind.js +++ b/bind.js @@ -62,16 +62,16 @@ function bind(target, targetPath, descriptor) { var convert = descriptor.convert; var revert = descriptor.revert; - var sourceSyntax = descriptor.sourceSyntax = parse(sourcePath); - var targetSyntax = descriptor.targetSyntax = parse(targetPath); + var sourceSyntax = descriptor.sourceSyntax = bind.parse(sourcePath); + var targetSyntax = descriptor.targetSyntax = bind.parse(targetPath); - var solution = solve(targetSyntax, sourceSyntax); + var solution = bind.solve(targetSyntax, sourceSyntax); targetSyntax = solution[0]; sourceSyntax = solution[1]; if (twoWay) { if (targetSyntax.type === "rangeContent") { - return bindRangeContent( + return bind.bindRangeContent( targetScope, targetSyntax.args[0], sourceScope, @@ -87,9 +87,14 @@ function bind(target, targetPath, descriptor) { } } + var cancel = function cancel() { + cancel.cancelSourceToTarget(); + cancel.cancelTargetToSource(); + }; + // <- source to target trace && console.log("DEFINE BINDING", targetPath, ONE_WAY, sourcePath, target); - var cancelSourceToTarget = bindOneWay( + cancel.cancelSourceToTarget = bind.bindOneWay( targetScope, targetSyntax, sourceScope, @@ -100,7 +105,7 @@ function bind(target, targetPath, descriptor) { ); // flip the arrow - var solution = solve(sourceSyntax, targetSyntax); + var solution = bind.solve(sourceSyntax, targetSyntax); sourceSyntax = solution[0]; targetSyntax = solution[1]; @@ -108,7 +113,7 @@ function bind(target, targetPath, descriptor) { var cancelTargetToSource = Function.noop; if (twoWay) { trace && console.log("DEFINE BINDING", targetPath, ONE_WAY_RIGHT, sourcePath, source); - cancelTargetToSource = bindOneWay( + cancelTargetToSource = bind.bindOneWay( sourceScope, sourceSyntax, targetScope, @@ -118,14 +123,16 @@ function bind(target, targetPath, descriptor) { trace ); } + cancel.cancelTargetToSource = cancelTargetToSource; - return function cancel() { - cancelSourceToTarget(); - cancelTargetToSource(); - }; - + return cancel; } +bind.parse = parse; +bind.solve = solve; +bind.bindOneWay = bindOneWay; +bind.bindRangeContent = bindRangeContent; + function bindOneWay( targetScope, targetSyntax, @@ -136,7 +143,7 @@ function bindOneWay( trace ) { - var observeSource = compileObserver(sourceSyntax); + var observeSource = bindOneWay.compileObserver(sourceSyntax); if (convert) { observeSource = Observers.makeConverterObserver( observeSource, @@ -145,7 +152,7 @@ function bindOneWay( ); } - var bindTarget = compileBinder(targetSyntax); + var bindTarget = bindOneWay.compileBinder(targetSyntax); return bindTarget( observeSource, sourceScope, @@ -158,6 +165,8 @@ function bindOneWay( ); } +bindOneWay.compileObserver = compileObserver; +bindOneWay.compileBinder = compileBinder; function bindRangeContent( targetScope, @@ -170,10 +179,10 @@ function bindRangeContent( trace ) { - var observeSource = compileObserver(sourceSyntax); - var observeTarget = compileObserver(targetSyntax); - var assignSource = compileAssigner(sourceSyntax); - var assignTarget = compileAssigner(targetSyntax); + var observeSource = bindRangeContent.compileObserver(sourceSyntax); + var observeTarget = bindRangeContent.compileObserver(targetSyntax); + var assignSource = bindRangeContent.compileAssigner(sourceSyntax); + var assignTarget = bindRangeContent.compileAssigner(targetSyntax); var cancel = Function.noop; @@ -193,7 +202,7 @@ function bindRangeContent( // prevent the target from overwriting an existing source. isActive = true; - var cancelTargetObserver = observeTarget(function replaceRangeContentTarget(_target) { + cancelRangeContentBinding.cancelTargetObserver = observeTarget(function replaceRangeContentTarget(_target) { cancel(); cancel = Function.noop; trace && console.log("RANGE CONTENT TARGET", trace.targetPath, "SET TO", _target); @@ -213,7 +222,7 @@ function bindRangeContent( }, targetScope); isActive = false; - var cancelSourceObserver = observeSource(function replaceRangeContentSource(_source) { + cancelRangeContentBinding.cancelSourceObserver = observeSource(function replaceRangeContentSource(_source) { cancel(); cancel = Function.noop; trace && console.log("RANGE CONTENT SOURCE", trace.sourcePath, "SET TO", _source); @@ -261,19 +270,27 @@ function bindRangeContent( } trace && console.log("RANGE CONTENT BOUND", trace.targetPath, TWO_WAY, trace.sourcePath); isActive = true; - var cancelSourceRangeChangeObserver = observeRangeChange(source, sourceRangeChange, sourceScope); - var cancelTargetRangeChangeObserver = observeRangeChange(target, targetRangeChange, targetScope); + cancelRangeContentBinding.cancelSourceRangeChangeObserver = observeRangeChange(source, sourceRangeChange, sourceScope); + cancelRangeContentBinding.cancelTargetRangeChangeObserver = observeRangeChange(target, targetRangeChange, targetScope); isActive = false; - return function cancelRangeContentBinding() { + + function cancelRangeContentBinding() { trace && console.log("RANGE CONTENT UNBOUND", trace.targetPath, TWO_WAY, trace.sourcePath); - cancelSourceRangeChangeObserver(); - cancelTargetRangeChangeObserver(); + cancelRangeContentBinding.cancelSourceRangeChangeObserver(); + cancelRangeContentBinding.cancelTargetRangeChangeObserver(); }; + + return cancelRangeContentBinding; } - return function cancelRangeContentBinding() { + function cancelRangeContentBinding() { cancel(); - cancelTargetObserver(); - cancelSourceObserver(); + cancelRangeContentBinding.cancelTargetObserver(); + cancelRangeContentBinding.cancelSourceObserver(); }; + + return cancelRangeContentBinding; } +bindRangeContent.compileObserver = compileObserver; +bindRangeContent.compileAssigner = compileAssigner; + diff --git a/bindings.js b/bindings.js index 0cfe48f..89318f5 100644 --- a/bindings.js +++ b/bindings.js @@ -38,7 +38,8 @@ function defineBinding(object, name, descriptor, commonDescriptor) { if (bindingsForName.has(name)) { throw new Error("Can't bind to already bound target, " + JSON.stringify(name)); } - else if (ONE_WAY in descriptor || TWO_WAY in descriptor || COMPUTE in descriptor) { + //Replaced (ONE_WAY in descriptor[ONE_WAY] || TWO_WAY in descriptor || COMPUTE in descriptor) + else if (descriptor[ONE_WAY] || descriptor[TWO_WAY] || descriptor[COMPUTE]) { bindingsForName.set(name,descriptor); descriptor.target = object; if((parameters = descriptor.parameters || commonDescriptor.parameters)) @@ -46,8 +47,8 @@ function defineBinding(object, name, descriptor, commonDescriptor) { if((document = descriptor.document || commonDescriptor.document)) descriptor.document = document; descriptor.components = descriptor.components || commonDescriptor.components; - - descriptor.cancel = (COMPUTE in descriptor) + //Replaced (COMPUTE in descriptor) + descriptor.cancel = (descriptor[COMPUTE]) ? defineBinding.compute(object, name, descriptor) : defineBinding.bind(object, name, descriptor); @@ -74,14 +75,15 @@ defineBinding.bind = bind; exports.getBindings = getBindings; function getBindings(object) { var value; - return bindingsForObject.get(object) || (bindingsForObject.set(object, ( value = new Map)) && value); + return getBindings.bindingsForObject.get(object) || (getBindings.bindingsForObject.set(object, ( value = new Map)) && value); } +getBindings.bindingsForObject = bindingsForObject; exports.getBinding = getBinding; function getBinding(object, name) { - var bindingsForName = getBindings(object); - return bindingsForName.get(name); + return getBinding.getBindings(object).get(name); } +getBinding.getBindings = getBindings; exports.cancelBindings = cancelBindings; function cancelBindings(object) { @@ -89,18 +91,20 @@ function cancelBindings(object) { mapIter = bindings.keys(); while (name = mapIter.next().value) { - cancelBinding(object, name, bindings); + cancelBindings.cancelBinding(object, name, bindings); } // for (var name in bindings) { // cancelBinding(object, name); // } } +cancelBindings.getBindings = getBindings; +cancelBindings.cancelBinding = cancelBinding; exports.cancelBinding = cancelBinding; function cancelBinding(object, name, bindings/*private argument to call from cancelBindings*/) { if(!bindings) { - bindings = getBindings(object); + bindings = cancelBinding.getBindings(object); if (!bindings.has(name)) { throw new Error("Can't cancel non-existent binding to " + JSON.stringify(name)); } @@ -112,7 +116,9 @@ function cancelBinding(object, name, bindings/*private argument to call from can exports.count--; if (bindings.size < 1) { - bindingsForObject.delete(object); + cancelBinding.bindingsForObject.delete(object); } } } +cancelBinding.getBindings = getBindings; +cancelBinding.bindingsForObject = bindingsForObject; diff --git a/compile-evaluator.js b/compile-evaluator.js index 742dc6d..43d62be 100644 --- a/compile-evaluator.js +++ b/compile-evaluator.js @@ -299,44 +299,55 @@ var semantics = compile.semantics = { } else { if (!operators.hasOwnProperty(syntax.type)) { operators[syntax.type] = function (object) { - var args = Array.prototype.slice.call(arguments, 1); if (!object[syntax.type]) throw new TypeError("Can't call " + JSON.stringify(syntax.type) + " of " + object); - if(args.length === 1) { - return object[syntax.type].call(object, args[0]); + if(arguments.length === 2) { + return object[syntax.type].call(object, arguments[1]); } - else if(args.length === 2) { - return object[syntax.type].call(object, args[0], args[1]); + else if(arguments.length === 3) { + return object[syntax.type].call(object, arguments[1], arguments[2]); } else { + var args = Array.prototype.slice.call(arguments, 1); return object[syntax.type].apply(object, args); } }; } - var operator = operators[syntax.type]; - var argEvaluators = syntax.args.map(this.compile, this); - return function (scope) { - var args = argEvaluators.map(function (evaluateArg) { - return evaluateArg(scope); - }); - if (!args.every(Operators.defined)) - return; + var compiledSyntax = function compiledSyntax(scope) { + var args = [], i, iArg, + argEvaluators = compiledSyntax.argEvaluators, + argEvaluator = compiledSyntax.argEvaluator, + evaluatedArg; + + for(i=0;(iArg = argEvaluators[i]);i++) { + evaluatedArg = iArg(scope); + if(Operators.defined(evaluatedArg)) { + args[i] = (iArg(scope)); + } + else { + return; + } + } if(args.length === 1) { - return operator.call(null, args[0]); + return compiledSyntax.operator.call(null, args[0]); } else if(args.length === 2) { - return operator.call(null, args[0], args[1]); + return compiledSyntax.operator.call(null, args[0], args[1]); } else { - return operator.apply(null, args); + return compiledSyntax.operator.apply(null, args); } }; + compiledSyntax.operator = operators[syntax.type]; + compiledSyntax.argEvaluators = syntax.args.map(this.compile, this); + compiledSyntax.argEvaluator = this.argEvaluator; + + return compiledSyntax; } } - }; diff --git a/compile-observer.js b/compile-observer.js index 509012b..41f15f0 100644 --- a/compile-observer.js +++ b/compile-observer.js @@ -73,9 +73,8 @@ var semantics = compile.semantics = { }, compile: function compile(syntax) { - var compilers = this.compilers, - syntaxType = syntax.type; - if (syntax.type === LITERAL) { + var syntaxType = syntax.type; + if (syntaxType === LITERAL) { return Observers.makeLiteralObserver(syntax.value); } else if (syntaxType === VALUE) { return Observers.observeValue; @@ -94,20 +93,28 @@ var semantics = compile.semantics = { } return Observers.makeObjectObserver(observers); } else { - if (!compilers.hasOwnProperty(syntaxType)) { - compilers[syntaxType] = Observers.makeMethodObserverMaker(syntaxType); + if (!this.compilers.hasOwnProperty(syntaxType)) { + this.compilers[syntaxType] = Observers.makeMethodObserverMaker(syntaxType); } - var argObservers = []; - for(var i=0, args = syntax.args, countI = args.length;i