From 1bf35eae63973b1c3b34b8bf2164ef026a0eaa10 Mon Sep 17 00:00:00 2001 From: Quan Nguyen Date: Sat, 14 Feb 2015 08:49:53 -0800 Subject: [PATCH] ES6 rewrite --- CHANGELOG.md | 5 +- README.md | 3 +- build/cortex.js | 711 ++++++++++++++++++++++---------------- build/cortex.min.js | 2 +- gulpfile.js | 3 +- package.json | 8 +- src/cortex.js | 299 ++++++++-------- src/data_wrapper.js | 166 ++++----- src/pubsub.js | 73 ++-- test/data_wrapper_test.js | 6 +- 10 files changed, 684 insertions(+), 592 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c4c9e5..80b6e69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ -# 0.6.3 (February 9, 2014) +# 0.7.0 (February 14, 2015) +- ES6 rewrite + +# 0.6.3 (February 9, 2015) - Batch rewrap # 0.6.2 (August 13, 2014) diff --git a/README.md b/README.md index b384997..27de0f2 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,9 @@ Cortex is a Javascript library for centrally managing data with React. **Key features:** - supports deeply nested data with a simple API - performs old and new data comparison out of the box so you don't have to implement shouldComponentUpdate -- performs batch updates and efficiently rewraps only the affected subtree. +- performs efficient batch updates and rewrapping - has built-in methods for working with arrays and hashes +- written in ES6 **Demos** diff --git a/build/cortex.js b/build/cortex.js index ca9aed1..5a0d004 100644 --- a/build/cortex.js +++ b/build/cortex.js @@ -1,357 +1,464 @@ (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 1) { + var subValue = this.__subValue(path.slice(0, path.length - 1)); + subValue[path[path.length - 1]] = newValue; + } else if (path.length === 1) { + this.__value[path[0]] = newValue; + } else { + this.__value = newValue; + } + }, + writable: true, + configurable: true + }, + __subValue: { + value: function __subValue(path) { + var subValue = this.__value; + for (var i = 0, ii = path.length; i < ii; i++) { + subValue = subValue[path[i]]; + } + return subValue; + }, + writable: true, + configurable: true + }, + __shouldUpdate: { + + // Check whether newValue is different, if not then return false to bypass rewrap and running callback. + // Note that we cannot compare stringified values of old and new data because order of keys cannot be guaranteed. + value: function __shouldUpdate(newValue, path) { + var oldValue = this.__value; + for (var i = 0, ii = path.length; i < ii; i++) { + oldValue = oldValue[path[i]]; + } + return this.__isDifferent(oldValue, newValue); + }, + writable: true, + configurable: true + }, + __isDifferent: { + + // Recursively performs comparison b/w old and new data + value: function __isDifferent(oldValue, newValue) { + if (oldValue && oldValue.constructor === Object) { + if (!newValue || newValue.constructor !== Object || this.__isDifferent(Object.keys(oldValue).sort(), Object.keys(newValue).sort())) { + return true; + } + for (var key in oldValue) { + if (this.__isDifferent(oldValue[key], newValue[key])) { + return true; + } + } + } else if (oldValue && oldValue.constructor === Array) { + if (!newValue || newValue.constructor !== Array || oldValue.length !== newValue.length) { + return true; + } + for (var i = 0, ii = oldValue.length; i < ii; i++) { + if (this.__isDifferent(oldValue[i], newValue[i])) { + return true; + } + } + } else { + return oldValue !== newValue; + } + }, + writable: true, + configurable: true } - this.update(subValue, subPath, true); - return removed; - } else { - delete this.__wrappers; - delete this.__value; - } - }; + }); - Cortex.prototype.__setValue = function (newValue, path) { - /* - When saving an object to a variable it's pass by reference, but when doing so for a primitive value - it's pass by value. We avoid this pass by value problem by only setting subValue when path length is greater - than 2 (meaning it can't never be a primitive). When path length is 0 or 1 we set the value directly. - */ - if (path.length > 1) { - var subValue = this.__subValue(path.slice(0, path.length - 1)); - subValue[path[path.length - 1]] = newValue; - } else if (path.length === 1) { - this.__value[path[0]] = newValue; - } else { - this.__value = newValue; - } - }; + return Cortex; + })(DataWrapper); - Cortex.prototype.__subValue = function (path) { - var subValue = this.__value; - for (var i = 0, ii = path.length; i < ii; i++) { - subValue = subValue[path[i]]; - } - return subValue; - }; - - // Check whether newValue is different, if not then return false to bypass rewrap and running callback. - // Note that we cannot compare stringified values of old and new data because order of keys cannot be guaranteed. - Cortex.prototype.__shouldUpdate = function (newValue, path) { - var oldValue = this.__value; - for (var i = 0, ii = path.length; i < ii; i++) { - oldValue = oldValue[path[i]]; - } - return this.__isDifferent(oldValue, newValue); - }; - - // Recursively performs comparison b/w old and new data - Cortex.prototype.__isDifferent = function (oldValue, newValue) { - if (oldValue && oldValue.constructor === Object) { - if (!newValue || newValue.constructor !== Object || this.__isDifferent(Object.keys(oldValue).sort(), Object.keys(newValue).sort())) { - return true; - } - for (var key in oldValue) { - if (this.__isDifferent(oldValue[key], newValue[key])) { - return true; - } - } - } else if (oldValue && oldValue.constructor === Array) { - if (!newValue || newValue.constructor !== Array || oldValue.length !== newValue.length) { - return true; - } - for (var i = 0, ii = oldValue.length; i < ii; i++) { - if (this.__isDifferent(oldValue[i], newValue[i])) { - return true; - } - } - } else { - return oldValue !== newValue; - } - }; + if (typeof window !== "undefined" && window !== null) { + window.Cortex = Cortex; + } return Cortex; -})(DataWrapper, cortexPubSub); - -if (typeof window !== "undefined" && window !== null) { - window.Cortex = Cortex; -} - -module.exports = Cortex; +})(); -},{"./data_wrapper":2,"./pubsub":3,"./wrappers/array":4,"./wrappers/hash":5}],2:[function(require,module,exports){ +},{"./data_wrapper":2,"./pubsub":3}],2:[function(require,module,exports){ "use strict"; -var __include = function (klass, mixins) { - for (var i = 0, ii = mixins.length; i < ii; i++) { - for (var methodName in mixins[i]) { - klass.prototype[methodName] = mixins[i][methodName]; - } - } -}; - -module.exports = function (_mixins, _cortexPubSub) { - function DataWrapper(value, path, eventId) { - this.__eventId = eventId; - this.__value = value; - this.__path = path || []; - this.__wrap(); - } - - DataWrapper.prototype.set = function (value, forceUpdate) { - _cortexPubSub.publish("update" + this.__eventId, { value: value, path: this.__path, forceUpdate: forceUpdate }); - }; - - DataWrapper.prototype.getValue = function () { - return this.__value; - }; +var _prototypeProperties = function (child, staticProps, instanceProps) { if (staticProps) Object.defineProperties(child, staticProps); if (instanceProps) Object.defineProperties(child.prototype, instanceProps); }; - // Short alias for getValue - DataWrapper.prototype.val = DataWrapper.prototype.getValue; +var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; - DataWrapper.prototype.getPath = function () { - return this.__path; - }; +module.exports = function (_cortexPubSub) { + var DataWrapper = (function () { + function DataWrapper(value, path, eventId) { + _classCallCheck(this, DataWrapper); - DataWrapper.prototype.getKey = function () { - return this.__path[this.__path.length - 1]; - }; + this.__eventId = eventId; + this.__value = value; + this.__path = path || []; + this.__wrap(); - DataWrapper.prototype.forEach = function (callback) { - if (this.__isObject()) { - for (var key in this.__wrappers) { - callback(key, this.__wrappers[key], this.__wrappers); - } - } else if (this.__isArray()) { - this.__wrappers.forEach(callback); + this.val = this.getValue; } - }; - - DataWrapper.prototype.remove = function () { - _cortexPubSub.publish("remove" + this.__eventId, { path: this.__path }); - }; - // Recursively wrap data if @value is a hash or an array. - // Otherwise there's no need to further wrap primitive or other class instances - DataWrapper.prototype.__wrap = function () { - var path; - this.__cleanup(); - - if (this.__isObject()) { - this.__wrappers = {}; - for (var key in this.__value) { - path = this.__path.slice(); - path.push(key); - this.__wrappers[key] = new DataWrapper(this.__value[key], path, this.__eventId); - this[key] = this.__wrappers[key]; - } - } else if (this.__isArray()) { - this.__wrappers = []; - for (var index = 0, ii = this.__value.length; index < ii; index++) { - path = this.__path.slice(); - path.push(index); - this.__wrappers[index] = new DataWrapper(this.__value[index], path, this.__eventId); - this[index] = this.__wrappers[index]; + _prototypeProperties(DataWrapper, null, { + set: { + value: function set(value, forceUpdate) { + _cortexPubSub.publish("update" + this.__eventId, { value: value, path: this.__path, forceUpdate: forceUpdate }); + }, + writable: true, + configurable: true + }, + getValue: { + value: function getValue() { + return this.__value; + }, + writable: true, + configurable: true + }, + getPath: { + value: function getPath() { + return this.__path; + }, + writable: true, + configurable: true + }, + getKey: { + value: function getKey() { + return this.__path[this.__path.length - 1]; + }, + writable: true, + configurable: true + }, + forEach: { + value: function forEach(callback) { + if (this.__isObject()) { + for (var key in this.__wrappers) { + callback(key, this.__wrappers[key], this.__wrappers); + } + } else if (this.__isArray()) { + this.__wrappers.forEach(callback); + } + }, + writable: true, + configurable: true + }, + remove: { + value: function remove() { + _cortexPubSub.publish("remove" + this.__eventId, { path: this.__path }); + }, + writable: true, + configurable: true + }, + __wrap: { + + // Recursively wrap data if @value is a hash or an array. + // Otherwise there's no need to further wrap primitive or other class instances + value: function __wrap() { + var path; + this.__cleanup(); + + if (this.__isObject()) { + this.__wrappers = {}; + for (var key in this.__value) { + path = this.__path.slice(); + path.push(key); + this.__wrappers[key] = new DataWrapper(this.__value[key], path, this.__eventId); + this[key] = this.__wrappers[key]; + } + } else if (this.__isArray()) { + this.__wrappers = []; + for (var index = 0, ii = this.__value.length; index < ii; index++) { + path = this.__path.slice(); + path.push(index); + this.__wrappers[index] = new DataWrapper(this.__value[index], path, this.__eventId); + this[index] = this.__wrappers[index]; + } + } + }, + writable: true, + configurable: true + }, + __cleanup: { + value: function __cleanup() { + if (this.__wrappers) { + if (this.__isObject()) { + for (var key in this.__wrappers) { + delete this[key]; + } + } else if (this.__isArray()) { + for (var i = 0, ii = this.__wrappers.length; i < ii; i++) { + delete this[i]; + } + } + delete this.__wrappers; + } + }, + writable: true, + configurable: true + }, + __forceUpdate: { + value: function __forceUpdate() { + this.set(this.__value, true); + }, + writable: true, + configurable: true + }, + __isObject: { + value: function __isObject() { + return this.__value && this.__value.constructor === Object; + }, + writable: true, + configurable: true + }, + __isArray: { + value: function __isArray() { + return this.__value && this.__value.constructor === Array; + }, + writable: true, + configurable: true } - } - }; - - DataWrapper.prototype.__cleanup = function () { - if (this.__wrappers) { - if (this.__isObject()) { - for (var key in this.__wrappers) { - delete this[key]; - } - } else if (this.__isArray()) { - for (var i = 0, ii = this.__wrappers.length; i < ii; i++) { - delete this[i]; - } + }); + + return DataWrapper; + })(); + + // Mixin Array and Hash behaviors + var ArrayWrapper = require("./wrappers/array"), + HashWrapper = require("./wrappers/hash"); + var __include = function (klass, mixins) { + for (var _iterator = mixins[Symbol.iterator](), _step; !(_step = _iterator.next()).done;) { + var mixin = _step.value; + for (var methodName in mixin) { + klass.prototype[methodName] = mixin[methodName]; } - delete this.__wrappers; } }; - DataWrapper.prototype.__forceUpdate = function () { - this.set(this.__value, true); - }; - - DataWrapper.prototype.__isObject = function () { - return this.__value && this.__value.constructor === Object; - }; - - DataWrapper.prototype.__isArray = function () { - return this.__value && this.__value.constructor === Array; - }; - - __include(DataWrapper, _mixins); + __include(DataWrapper, [ArrayWrapper, HashWrapper]); return DataWrapper; }; -},{}],3:[function(require,module,exports){ +},{"./wrappers/array":4,"./wrappers/hash":5}],3:[function(require,module,exports){ "use strict"; -var PubSub = (function () { - function PubSub() { - this.uid = -1; - this.topics = {}; - } +var _prototypeProperties = function (child, staticProps, instanceProps) { if (staticProps) Object.defineProperties(child, staticProps); if (instanceProps) Object.defineProperties(child.prototype, instanceProps); }; - PubSub.prototype.subscribe = function (topic, callback) { - if (!this.topics.hasOwnProperty(topic)) { - this.topics[topic] = []; - } - this.topics[topic].push({ callback: callback }); - }; +var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; +module.exports = (function () { + var PubSub = (function () { + function PubSub() { + _classCallCheck(this, PubSub); - PubSub.prototype.publish = function (topic, data) { - if (!this.topics.hasOwnProperty(topic)) { - return false; + this.uid = -1; + this.topics = {}; } - var subscribers = this.topics[topic]; - var notify = function () { - for (var i = 0, ii = subscribers.length; i < ii; i++) { - subscribers[i].callback(topic, data); - } - }; + _prototypeProperties(PubSub, null, { + subscribe: { + value: function subscribe(topic, callback) { + if (!this.topics.hasOwnProperty(topic)) { + this.topics[topic] = []; + } + this.topics[topic].push({ callback: callback }); + }, + writable: true, + configurable: true + }, + publish: { + value: function publish(topic, data) { + if (!this.topics.hasOwnProperty(topic)) { + return false; + } - notify(); + var subscribers = this.topics[topic]; + var notify = function () { + for (var i = 0, ii = subscribers.length; i < ii; i++) { + subscribers[i].callback(topic, data); + } + }; - return true; - }; + notify(); - // Add both update and remove subscriptions with 1 call. - // Return the unique id so each cortex can handle its own event id. - PubSub.prototype.subscribeToCortex = function (updateCallback, removeCallback) { - this.uid += 1; - this.subscribe("update" + this.uid, updateCallback); - this.subscribe("remove" + this.uid, removeCallback); - return this.uid; - }; + return true; + }, + writable: true, + configurable: true + }, + subscribeToCortex: { + value: function subscribeToCortex(updateCallback, removeCallback) { + this.uid += 1; + this.subscribe("update" + this.uid, updateCallback); + this.subscribe("remove" + this.uid, removeCallback); + return this.uid; + }, + writable: true, + configurable: true + }, + unsubscribeFromCortex: { + value: function unsubscribeFromCortex(topicId) { + delete this.topics["update" + topicId]; + delete this.topics["remove" + topicId]; + }, + writable: true, + configurable: true + } + }); - PubSub.prototype.unsubscribeFromCortex = function (topicId) { - delete this.topics["update" + topicId]; - delete this.topics["remove" + topicId]; - }; + return PubSub; + })(); - return PubSub; + return new PubSub(); })(); -module.exports = new PubSub(); - },{}],4:[function(require,module,exports){ "use strict"; diff --git a/build/cortex.min.js b/build/cortex.min.js index 957d81b..1350589 100644 --- a/build/cortex.min.js +++ b/build/cortex.min.js @@ -1 +1 @@ -!function t(e,r,i){function s(n,o){if(!r[n]){if(!e[n]){var u="function"==typeof require&&require;if(!o&&u)return u(n,!0);if(_)return _(n,!0);var a=new Error("Cannot find module '"+n+"'");throw a.code="MODULE_NOT_FOUND",a}var p=r[n]={exports:{}};e[n][0].call(p.exports,function(t){var r=e[n][1][t];return s(r?r:t)},p,p.exports,t,e,r,i)}return r[n].exports}for(var _="function"==typeof require&&require,n=0;nr;r++)if(e===this.__callbacks[r]){this.__callbacks.splice(r,1);break}}else this.__callbacks=[]},r.prototype.update=function(t,e,r){return r||this.__shouldUpdate(t,e)?(this.__updates.push({newValue:t,path:e}),this.__loopProcessing||(this.__loopProcessing=!0,setTimeout(this.__batchAll.bind(this),0)),!0):!1},r.prototype.__batchAll=function(){this.__batchSetValue(),this.__wrap(),this.__loopProcessing=!1,this.__runCallbacks()},r.prototype.__batchSetValue=function(){for(var t=0,e=this.__updates.length;e>t;t++){var r=this.__updates[t];this.__setValue(r.newValue,r.path)}this.__updates=[]},r.prototype.__runCallbacks=function(){for(var t=0,e=this.__callbacks.length;e>t;t++)this.__callbacks[t]&&this.__callbacks[t](this)},r.prototype.__subscribe=function(){this.__eventId=e.subscribeToCortex(function(t,e){this.update(e.value,e.path,e.forceUpdate)}.bind(this),function(t,e){this.__remove(e.path)}.bind(this))},r.prototype.__remove=function(t){if(t.length){var e=t.slice(0,t.length-1),r=this.__subValue(e),i=t[t.length-1],s=r[i];return r.constructor===Object?delete r[i]:r.constructor===Array&&r.splice(i,1),this.update(r,e,!0),s}delete this.__wrappers,delete this.__value},r.prototype.__setValue=function(t,e){if(e.length>1){var r=this.__subValue(e.slice(0,e.length-1));r[e[e.length-1]]=t}else 1===e.length?this.__value[e[0]]=t:this.__value=t},r.prototype.__subValue=function(t){for(var e=this.__value,r=0,i=t.length;i>r;r++)e=e[t[r]];return e},r.prototype.__shouldUpdate=function(t,e){for(var r=this.__value,i=0,s=e.length;s>i;i++)r=r[e[i]];return this.__isDifferent(r,t)},r.prototype.__isDifferent=function(t,e){if(t&&t.constructor===Object){if(!e||e.constructor!==Object||this.__isDifferent(Object.keys(t).sort(),Object.keys(e).sort()))return!0;for(var r in t)if(this.__isDifferent(t[r],e[r]))return!0}else{if(!t||t.constructor!==Array)return t!==e;if(!e||e.constructor!==Array||t.length!==e.length)return!0;for(var i=0,s=t.length;s>i;i++)if(this.__isDifferent(t[i],e[i]))return!0}},r}(_,r);"undefined"!=typeof window&&null!==window&&(window.Cortex=u),e.exports=u},{"./data_wrapper":2,"./pubsub":3,"./wrappers/array":4,"./wrappers/hash":5}],2:[function(t,e){"use strict";var r=function(t,e){for(var r=0,i=e.length;i>r;r++)for(var s in e[r])t.prototype[s]=e[r][s]};e.exports=function(t,e){function i(t,e,r){this.__eventId=r,this.__value=t,this.__path=e||[],this.__wrap()}return i.prototype.set=function(t,r){e.publish("update"+this.__eventId,{value:t,path:this.__path,forceUpdate:r})},i.prototype.getValue=function(){return this.__value},i.prototype.val=i.prototype.getValue,i.prototype.getPath=function(){return this.__path},i.prototype.getKey=function(){return this.__path[this.__path.length-1]},i.prototype.forEach=function(t){if(this.__isObject())for(var e in this.__wrappers)t(e,this.__wrappers[e],this.__wrappers);else this.__isArray()&&this.__wrappers.forEach(t)},i.prototype.remove=function(){e.publish("remove"+this.__eventId,{path:this.__path})},i.prototype.__wrap=function(){var t;if(this.__cleanup(),this.__isObject()){this.__wrappers={};for(var e in this.__value)t=this.__path.slice(),t.push(e),this.__wrappers[e]=new i(this.__value[e],t,this.__eventId),this[e]=this.__wrappers[e]}else if(this.__isArray()){this.__wrappers=[];for(var r=0,s=this.__value.length;s>r;r++)t=this.__path.slice(),t.push(r),this.__wrappers[r]=new i(this.__value[r],t,this.__eventId),this[r]=this.__wrappers[r]}},i.prototype.__cleanup=function(){if(this.__wrappers){if(this.__isObject())for(var t in this.__wrappers)delete this[t];else if(this.__isArray())for(var e=0,r=this.__wrappers.length;r>e;e++)delete this[e];delete this.__wrappers}},i.prototype.__forceUpdate=function(){this.set(this.__value,!0)},i.prototype.__isObject=function(){return this.__value&&this.__value.constructor===Object},i.prototype.__isArray=function(){return this.__value&&this.__value.constructor===Array},r(i,t),i}},{}],3:[function(t,e){"use strict";var r=function(){function t(){this.uid=-1,this.topics={}}return t.prototype.subscribe=function(t,e){this.topics.hasOwnProperty(t)||(this.topics[t]=[]),this.topics[t].push({callback:e})},t.prototype.publish=function(t,e){if(!this.topics.hasOwnProperty(t))return!1;var r=this.topics[t],i=function(){for(var i=0,s=r.length;s>i;i++)r[i].callback(t,e)};return i(),!0},t.prototype.subscribeToCortex=function(t,e){return this.uid+=1,this.subscribe("update"+this.uid,t),this.subscribe("remove"+this.uid,e),this.uid},t.prototype.unsubscribeFromCortex=function(t){delete this.topics["update"+t],delete this.topics["remove"+t]},t}();e.exports=new r},{}],4:[function(t,e){"use strict";var r={count:function(){return this.__value.length},map:function(t){return this.__wrappers.map(t)},filter:function(t,e){return this.__wrappers.filter(t,e)},find:function(t){for(var e=0,r=this.__wrappers.length;r>e;e++)if(t(this.__wrappers[e],e,this.__wrappers))return this.__wrappers[e];return null},findIndex:function(t){for(var e=0,r=this.__wrappers.length;r>e;e++)if(t(this.__wrappers[e],e,this.__wrappers))return e;return-1},push:function(t){var e=this.__value.push(t);return this.__forceUpdate(),e},pop:function(){var t=this.__value.pop();return this.__forceUpdate(),t},unshift:function(t){var e=this.__value.unshift(t);return this.__forceUpdate(),e},shift:function(){var t=this.__value.shift();return this.__forceUpdate(),t},insertAt:function(t,e){var r=[t,0].concat(e);Array.prototype.splice.apply(this.__value,r),this.__forceUpdate()},removeAt:function(t,e){(isNaN(e)||0>=e)&&(e=1);var r=this.__value.splice(t,e);return this.__forceUpdate(),r}};e.exports=r},{}],5:[function(t,e){"use strict";var r={keys:function(){return Object.keys(this.__value)},values:function(){var t,e=[];for(t in this.__value)e.push(this.__value[t]);return e},hasKey:function(t){return null!=this.__value[t]},destroy:function(t){var e=this.__value[t];return delete this.__value[t],this.__forceUpdate(),e},"delete":function(t){return console.warn("Method deprecated! Please use .destroy(key) method"),this.remove(t)},add:function(t,e){return this.__value[t]=e,this.__forceUpdate(),e}};e.exports=r},{}]},{},[1]); \ No newline at end of file +!function t(e,r,i){function n(s,u){if(!r[s]){if(!e[s]){var o="function"==typeof require&&require;if(!u&&o)return o(s,!0);if(a)return a(s,!0);var _=new Error("Cannot find module '"+s+"'");throw _.code="MODULE_NOT_FOUND",_}var l=r[s]={exports:{}};e[s][0].call(l.exports,function(t){var r=e[s][1][t];return n(r?r:t)},l,l.exports,t,e,r,i)}return r[s].exports}for(var a="function"==typeof require&&require,s=0;sr;r++)if(e===this.__callbacks[r]){this.__callbacks.splice(r,1);break}}else this.__callbacks=[]},writable:!0,configurable:!0},update:{value:function(t,e,r){return r||this.__shouldUpdate(t,e)?(this.__updates.push({newValue:t,path:e}),this.__loopProcessing||(this.__loopProcessing=!0,setTimeout(this.__batchAll.bind(this),0)),!0):!1},writable:!0,configurable:!0},__batchAll:{value:function(){this.__batchSetValue(),this.__wrap(),this.__loopProcessing=!1,this.__runCallbacks()},writable:!0,configurable:!0},__batchSetValue:{value:function(){for(var t,e=this.__updates[Symbol.iterator]();!(t=e.next()).done;){var r=t.value;this.__setValue(r.newValue,r.path)}this.__updates=[]},writable:!0,configurable:!0},__runCallbacks:{value:function(){for(var t,e=this.__callbacks[Symbol.iterator]();!(t=e.next()).done;){var r=t.value;r&&r(this)}},writable:!0,configurable:!0},__subscribe:{value:function(){this.__eventId=e.subscribeToCortex(function(t,e){this.update(e.value,e.path,e.forceUpdate)}.bind(this),function(t,e){this.__remove(e.path)}.bind(this))},writable:!0,configurable:!0},__remove:{value:function(t){if(t.length){var e=t.slice(0,t.length-1),r=this.__subValue(e),i=t[t.length-1],n=r[i];return r.constructor===Object?delete r[i]:r.constructor===Array&&r.splice(i,1),this.update(r,e,!0),n}delete this.__wrappers,delete this.__value},writable:!0,configurable:!0},__setValue:{value:function(t,e){if(e.length>1){var r=this.__subValue(e.slice(0,e.length-1));r[e[e.length-1]]=t}else 1===e.length?this.__value[e[0]]=t:this.__value=t},writable:!0,configurable:!0},__subValue:{value:function(t){for(var e=this.__value,r=0,i=t.length;i>r;r++)e=e[t[r]];return e},writable:!0,configurable:!0},__shouldUpdate:{value:function(t,e){for(var r=this.__value,i=0,n=e.length;n>i;i++)r=r[e[i]];return this.__isDifferent(r,t)},writable:!0,configurable:!0},__isDifferent:{value:function(t,e){if(t&&t.constructor===Object){if(!e||e.constructor!==Object||this.__isDifferent(Object.keys(t).sort(),Object.keys(e).sort()))return!0;for(var r in t)if(this.__isDifferent(t[r],e[r]))return!0}else{if(!t||t.constructor!==Array)return t!==e;if(!e||e.constructor!==Array||t.length!==e.length)return!0;for(var i=0,n=t.length;n>i;i++)if(this.__isDifferent(t[i],e[i]))return!0}},writable:!0,configurable:!0}}),a}(a);return"undefined"!=typeof window&&null!==window&&(window.Cortex=s),s}()},{"./data_wrapper":2,"./pubsub":3}],2:[function(t,e){"use strict";var r=function(t,e,r){e&&Object.defineProperties(t,e),r&&Object.defineProperties(t.prototype,r)},i=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")};e.exports=function(e){var n=function(){function t(e,r,n){i(this,t),this.__eventId=n,this.__value=e,this.__path=r||[],this.__wrap(),this.val=this.getValue}return r(t,null,{set:{value:function(t,r){e.publish("update"+this.__eventId,{value:t,path:this.__path,forceUpdate:r})},writable:!0,configurable:!0},getValue:{value:function(){return this.__value},writable:!0,configurable:!0},getPath:{value:function(){return this.__path},writable:!0,configurable:!0},getKey:{value:function(){return this.__path[this.__path.length-1]},writable:!0,configurable:!0},forEach:{value:function(t){if(this.__isObject())for(var e in this.__wrappers)t(e,this.__wrappers[e],this.__wrappers);else this.__isArray()&&this.__wrappers.forEach(t)},writable:!0,configurable:!0},remove:{value:function(){e.publish("remove"+this.__eventId,{path:this.__path})},writable:!0,configurable:!0},__wrap:{value:function(){var e;if(this.__cleanup(),this.__isObject()){this.__wrappers={};for(var r in this.__value)e=this.__path.slice(),e.push(r),this.__wrappers[r]=new t(this.__value[r],e,this.__eventId),this[r]=this.__wrappers[r]}else if(this.__isArray()){this.__wrappers=[];for(var i=0,n=this.__value.length;n>i;i++)e=this.__path.slice(),e.push(i),this.__wrappers[i]=new t(this.__value[i],e,this.__eventId),this[i]=this.__wrappers[i]}},writable:!0,configurable:!0},__cleanup:{value:function(){if(this.__wrappers){if(this.__isObject())for(var t in this.__wrappers)delete this[t];else if(this.__isArray())for(var e=0,r=this.__wrappers.length;r>e;e++)delete this[e];delete this.__wrappers}},writable:!0,configurable:!0},__forceUpdate:{value:function(){this.set(this.__value,!0)},writable:!0,configurable:!0},__isObject:{value:function(){return this.__value&&this.__value.constructor===Object},writable:!0,configurable:!0},__isArray:{value:function(){return this.__value&&this.__value.constructor===Array},writable:!0,configurable:!0}}),t}(),a=t("./wrappers/array"),s=t("./wrappers/hash"),u=function(t,e){for(var r,i=e[Symbol.iterator]();!(r=i.next()).done;){var n=r.value;for(var a in n)t.prototype[a]=n[a]}};return u(n,[a,s]),n}},{"./wrappers/array":4,"./wrappers/hash":5}],3:[function(t,e){"use strict";var r=function(t,e,r){e&&Object.defineProperties(t,e),r&&Object.defineProperties(t.prototype,r)},i=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")};e.exports=function(){var t=function(){function t(){i(this,t),this.uid=-1,this.topics={}}return r(t,null,{subscribe:{value:function(t,e){this.topics.hasOwnProperty(t)||(this.topics[t]=[]),this.topics[t].push({callback:e})},writable:!0,configurable:!0},publish:{value:function(t,e){if(!this.topics.hasOwnProperty(t))return!1;var r=this.topics[t],i=function(){for(var i=0,n=r.length;n>i;i++)r[i].callback(t,e)};return i(),!0},writable:!0,configurable:!0},subscribeToCortex:{value:function(t,e){return this.uid+=1,this.subscribe("update"+this.uid,t),this.subscribe("remove"+this.uid,e),this.uid},writable:!0,configurable:!0},unsubscribeFromCortex:{value:function(t){delete this.topics["update"+t],delete this.topics["remove"+t]},writable:!0,configurable:!0}}),t}();return new t}()},{}],4:[function(t,e){"use strict";var r={count:function(){return this.__value.length},map:function(t){return this.__wrappers.map(t)},filter:function(t,e){return this.__wrappers.filter(t,e)},find:function(t){for(var e=0,r=this.__wrappers.length;r>e;e++)if(t(this.__wrappers[e],e,this.__wrappers))return this.__wrappers[e];return null},findIndex:function(t){for(var e=0,r=this.__wrappers.length;r>e;e++)if(t(this.__wrappers[e],e,this.__wrappers))return e;return-1},push:function(t){var e=this.__value.push(t);return this.__forceUpdate(),e},pop:function(){var t=this.__value.pop();return this.__forceUpdate(),t},unshift:function(t){var e=this.__value.unshift(t);return this.__forceUpdate(),e},shift:function(){var t=this.__value.shift();return this.__forceUpdate(),t},insertAt:function(t,e){var r=[t,0].concat(e);Array.prototype.splice.apply(this.__value,r),this.__forceUpdate()},removeAt:function(t,e){(isNaN(e)||0>=e)&&(e=1);var r=this.__value.splice(t,e);return this.__forceUpdate(),r}};e.exports=r},{}],5:[function(t,e){"use strict";var r={keys:function(){return Object.keys(this.__value)},values:function(){var t,e=[];for(t in this.__value)e.push(this.__value[t]);return e},hasKey:function(t){return null!=this.__value[t]},destroy:function(t){var e=this.__value[t];return delete this.__value[t],this.__forceUpdate(),e},"delete":function(t){return console.warn("Method deprecated! Please use .destroy(key) method"),this.remove(t)},add:function(t,e){return this.__value[t]=e,this.__forceUpdate(),e}};e.exports=r},{}]},{},[1]); \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 62a7a04..e0af1ca 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -31,11 +31,12 @@ gulp.task("test", function() { ]; for(var i=0,ii=tests.length;i 1) { - var subValue = this.__subValue(path.slice(0, path.length - 1)); - subValue[path[path.length-1]] = newValue; - } else if(path.length === 1) { - this.__value[path[0]] = newValue; - } else { - this.__value = newValue; - } - }; - Cortex.prototype.__subValue = function(path) { - var subValue = this.__value; - for(var i=0, ii = path.length;i 1) { + var subValue = this.__subValue(path.slice(0, path.length - 1)); + subValue[path[path.length-1]] = newValue; + } else if(path.length === 1) { + this.__value[path[0]] = newValue; + } else { + this.__value = newValue; + } } - return subValue; - }; - - // Check whether newValue is different, if not then return false to bypass rewrap and running callback. - // Note that we cannot compare stringified values of old and new data because order of keys cannot be guaranteed. - Cortex.prototype.__shouldUpdate = function(newValue, path) { - var oldValue = this.__value; - for(var i=0, ii=path.length;i