diff --git a/compute/compute.js b/compute/compute.js index be99806d285..d4fa361b05b 100644 --- a/compute/compute.js +++ b/compute/compute.js @@ -126,29 +126,38 @@ steal('can/util', 'can/util/bind', 'can/util/batch', function (can, bind) { obEv, name; // Go through what needs to be observed. - for( name in newObserveSet ) { - - if( oldObserved[name] ) { - // After binding is set up, values - // in `oldObserved` will be unbound. So if a name - // has already be observed, remove from `oldObserved` - // to prevent this. - delete oldObserved[name]; - } else { - // If current name has not been observed, listen to it. - obEv = newObserveSet[name]; - obEv.obj.bind(obEv.event, onchanged); - } + bindNewSet(oldObserved, newObserveSet, onchanged); + unbindOldSet(oldObserved, onchanged); + + return info; + }; + // This will not be optimized. + var bindNewSet = function(oldObserved, newObserveSet, onchanged){ + for(var name in newObserveSet ) { + bindOrPreventUnbinding(oldObserved, newObserveSet, name, onchanged); } - - // Iterate through oldObserved, looking for observe/attributes - // that are no longer being bound and unbind them. - for ( name in oldObserved) { + }; + // This will be optimized. + var bindOrPreventUnbinding = function(oldObserved, newObserveSet, name, onchanged){ + if( oldObserved[name] ) { + // After binding is set up, values + // in `oldObserved` will be unbound. So if a name + // has already be observed, remove from `oldObserved` + // to prevent this. + delete oldObserved[name]; + } else { + // If current name has not been observed, listen to it. + obEv = newObserveSet[name]; + obEv.obj.bind(obEv.event, onchanged); + } + }; + // Iterate through oldObserved, looking for observe/attributes + // that are no longer being bound and unbind them. + var unbindOldSet = function(oldObserved, onchanged){ + for (var name in oldObserved) { obEv = oldObserved[name]; obEv.obj.unbind(obEv.event, onchanged); } - - return info; }; // ### updateOnChange @@ -257,7 +266,7 @@ steal('can/util', 'can/util/bind', 'can/util/batch', function (can, bind) { }, setCached = set, // Save arguments for cloning - args = can.makeArray(arguments), + args = [], // updater for when value is changed updater = function (newValue, oldValue, batchNum) { setCached(newValue); @@ -265,6 +274,13 @@ steal('can/util', 'can/util/bind', 'can/util/batch', function (can, bind) { }, // the form of the arguments form; + + + // convert arguments to args to make V8 Happy + for(var i = 0, arglen = arguments.length; i< arglen; i++){ + args[i] = arguments[i]; + } + computed = function (newVal) { // If the computed function is called with arguments, // a value should be set diff --git a/map/bubble.js b/map/bubble.js index f9892665f71..bedb9f58ad2 100644 --- a/map/bubble.js +++ b/map/bubble.js @@ -53,6 +53,9 @@ steal('can/util', function(can){ can.stopListening.call(parent, child, eventName); } }, + isBubbling: function(parent, eventName){ + return parent._bubbleBindings && parent._bubbleBindings[eventName]; + }, bind: function(parent, eventName) { if (!parent._init ) { var bubbleEvent = bubble.event(parent, eventName); diff --git a/map/map.js b/map/map.js index eb2b64f07f8..2183c44480d 100644 --- a/map/map.js +++ b/map/map.js @@ -300,17 +300,24 @@ steal('can/util', 'can/util/bind','./bubble.js', 'can/construct', 'can/util/batc target: ev.target }, [newVal, oldVal]); + + }, + // Trigger a change event. + _triggerChange: function (attr, how, newVal, oldVal) { + // so this change can bubble ... a bubbling change triggers the + // _changes trigger + if(bubble.isBubbling(this, "change")) { + can.batch.trigger(this, "change", [attr, how, newVal, oldVal]); + } else { + can.batch.trigger(this, attr, [newVal, oldVal]); + } + if(how === "remove" || how === "add") { can.batch.trigger(this, { - type: "__keys", - batchNum: ev.batchNum + type: "__keys" }); } }, - // Trigger a change event. - _triggerChange: function (attr, how, newVal, oldVal) { - can.batch.trigger(this, "change", arguments); - }, // Iterator that does not trigger live binding. _each: function (callback) { var data = this.__get(); @@ -384,8 +391,10 @@ steal('can/util', 'can/util/bind','./bubble.js', 'can/construct', 'can/util/batc // Reads a property from the `object`. _get: function (attr) { var value; + // Handles the case of a key having a `.` in its name - if (typeof attr === 'string' && !! ~attr.indexOf('.')) { + // Otherwise we have to dig deeper into the Map to get the value. + if( typeof attr === 'string' && !! ~attr.indexOf('.') ) { // Attempt to get the value value = this.__get(attr); // For keys with a `.` in them, value will be defined @@ -393,12 +402,13 @@ steal('can/util', 'can/util/bind','./bubble.js', 'can/construct', 'can/util/batc return value; } } - - // Otherwise we have to dig deeper into the Map to get the value. + // First, break up the attr (`"foo.bar"`) into parts like `["foo","bar"]`. var parts = can.Map.helpers.attrParts(attr), // Then get the value of the first attr name (`"foo"`). current = this.__get(parts.shift()); + + // If there are other attributes to read... return parts.length ? // and current has a value... @@ -475,7 +485,7 @@ steal('can/util', 'can/util/bind','./bubble.js', 'can/construct', 'can/util/batc if (value !== current) { // Check if we are adding this for the first time -- // if we are, we need to create an `add` event. - var changeType = this.__get() + var changeType = current !== undefined || this.__get() .hasOwnProperty(prop) ? "set" : "add"; // Set the value on `_data` and hook it up to send event. @@ -500,7 +510,7 @@ steal('can/util', 'can/util/bind','./bubble.js', 'can/construct', 'can/util/batc } // Add property directly for easy writing. // Check if its on the `prototype` so we don't overwrite methods like `attrs`. - if (!can.isFunction(this.constructor.prototype[prop]) && !this._computedBindings[prop] ) { + if (! typeof this.constructor.prototype[prop] === 'function' && !this._computedBindings[prop] ) { this[prop] = val; } }, diff --git a/map/test.html b/map/test.html index 01775986460..16ff9b68e4c 100644 --- a/map/test.html +++ b/map/test.html @@ -22,10 +22,13 @@

} QUnit.config.autostart = false; - steal("can/map/map_test.js", function() { - can.dev.logLevel = 3; - QUnit.start(); - }); + setTimeout(function(){ + steal("can/map/map_test.js", function() { + can.dev.logLevel = 3; + QUnit.start(); + }); + },300); + diff --git a/util/batch/batch.js b/util/batch/batch.js index 3d3ecb2a519..75ae5d57f79 100644 --- a/util/batch/batch.js +++ b/util/batch/batch.js @@ -200,6 +200,7 @@ steal('can/util/can.js', function (can) { * immediately. */ trigger: function (item, event, args) { + //console.log(event, item, args); // Don't send events if initalizing. if (!item._init) { if (transactions === 0) { diff --git a/util/can.js b/util/can.js index 335dc7da10b..cb7c7ff1f57 100644 --- a/util/can.js +++ b/util/can.js @@ -11,7 +11,7 @@ steal(function () { can.isDeferred = function (obj) { var isFunction = this.isFunction; // Returns `true` if something looks like a deferred. - return obj && isFunction(obj.then) && isFunction(obj.pipe); + return obj && typeof obj.then === "function" && typeof obj.pipe === "function"; }; var cid = 0; diff --git a/view/stache/visual_benchmark.html b/view/stache/visual_benchmark.html index 6dd7b21e07c..264625c3ffd 100644 --- a/view/stache/visual_benchmark.html +++ b/view/stache/visual_benchmark.html @@ -54,7 +54,7 @@ var template = stache( "{{#each boxes}}"+ "
"+ - "
"+ + "
"+ "{{content}}"+ "
"+ "
"+ @@ -63,21 +63,30 @@ var boxes = new can.List(), Box = can.Map.extend({ - count: 0, - content: 0, - tick: function(){ - var count = this.attr('count') + 1; + top: 0, + left: 0, + content: 0, + count: 0, + + tick: function() { + var count = this.attr('count') + 1; + this.attr('count', count); this.attr('top', Math.sin(count / 10) * 10); this.attr('left', Math.cos(count / 10) * 10); this.attr('color', count % 255); this.attr('content', count % 100); - } + this.attr('style', this.computeStyle()); + + }, + + computeStyle: function() { + return 'top: ' + this.attr('top') + 'px; left: ' + this.attr('left') +'px; background: rgb(0,0,' + this.attr('color') + ');'; + } }); for(var i =0; i < 100; i++) { var box = new Box({ number: i }); - box.tick(); boxes.push( box ); } @@ -103,6 +112,7 @@ benchmarkLoop(run); }); + window.timeout = null; window.totalTime = null; @@ -116,7 +126,7 @@ if (loopCount % 20 === 0) { $('#timing').text('Performed ' + loopCount + ' iterations in ' + totalTime + ' ms (average ' + (totalTime / loopCount).toFixed(2) + ' ms per loop).'); } - if(loopCount < 10) { + if(loopCount < 1000) { timeout = setTimeout(function(){ benchmarkLoop(fn); },1);