Comparing version 0.1.0 to 0.2.0
{ | ||
"name": "brink", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "main": "./src/brink/brink.js", |
@@ -334,3 +334,2 @@ $b( | ||
if (this.__meta) { | ||
this.__meta.changedProps = []; | ||
this.__meta.contentChanges = {}; | ||
@@ -337,0 +336,0 @@ } |
$b( | ||
[ | ||
'../config', | ||
'./CoreObject', | ||
'./Dictionary', | ||
'./InstanceWatcher', | ||
'../config', | ||
'../utils/get', | ||
'../utils/merge', | ||
@@ -12,3 +12,3 @@ '../utils/flatten' | ||
function (CoreObject, Dictionary, InstanceWatcher, config, merge, flatten) { | ||
function (config, CoreObject, InstanceWatcher, get, merge, flatten) { | ||
@@ -20,9 +20,19 @@ 'use strict'; | ||
if (typeof window !== 'undefined') { | ||
window.count = 0; | ||
} | ||
InstanceManager = CoreObject.extend({ | ||
instances : null, | ||
changedProps : null, | ||
changedInstances : null, | ||
init : function () { | ||
this.instances = Dictionary.create(); | ||
this.watcher = InstanceWatcher.create(this.instances); | ||
this.instances = {}; | ||
this.changedProps = []; | ||
this.changedInstances = []; | ||
this.watcher = InstanceWatcher.create(this); | ||
}, | ||
@@ -35,4 +45,2 @@ | ||
meta.changedProps = meta.changedProps || []; | ||
return meta; | ||
@@ -42,50 +50,100 @@ }, | ||
add : function (instance, meta) { | ||
meta = this.buildMeta(meta); | ||
this.instances.add(instance, meta); | ||
this.instances[meta.iid] = instance; | ||
return meta; | ||
}, | ||
remove : function () { | ||
this.instances.remove.apply(this.instances, arguments); | ||
remove : function (instance) { | ||
this.instances[instance.__meta.iid] = null; | ||
}, | ||
forEach : function (fn) { | ||
return this.instances.forEach(fn); | ||
getChangedProps : function (obj) { | ||
var idx, | ||
meta; | ||
meta = obj.__meta; | ||
idx = this.changedInstances.indexOf(meta.iid); | ||
if (!~idx) { | ||
return []; | ||
} | ||
else { | ||
return this.changedProps[idx]; | ||
} | ||
}, | ||
propertyDidChange : function (obj, props) { | ||
propertyDidChange : function (obj, p) { | ||
var d, | ||
i, | ||
p, | ||
p2, | ||
meta; | ||
var i, | ||
idx, | ||
meta, | ||
changed, | ||
chProps, | ||
chInstances; | ||
props = [].concat(props); | ||
meta = obj.__meta; | ||
for (i = 0; i < props.length; i ++) { | ||
chInstances = this.changedInstances; | ||
chProps = this.changedProps; | ||
p = props[i]; | ||
idx = chInstances.indexOf(meta.iid); | ||
if (idx === -1) { | ||
chInstances.push(meta.iid); | ||
changed = []; | ||
chProps.push(changed); | ||
} | ||
if (config.DIRTY_CHECK) { | ||
meta.values[p] = this[p]; | ||
} | ||
else { | ||
changed = chProps[idx]; | ||
} | ||
for (p2 in meta.properties) { | ||
i = changed.length; | ||
if (changed.indexOf(p) === -1) { | ||
changed[i] = p; | ||
} | ||
d = meta.properties[p2]; | ||
this.watcher.start(); | ||
return changed; | ||
}, | ||
if (~(Array.isArray(d.watch) ? d.watch : []).indexOf(p)) { | ||
this.propertyDidChange(obj, p2); | ||
} | ||
propertiesDidChange : function (obj, props) { | ||
var i, | ||
j, | ||
p, | ||
idx, | ||
meta, | ||
changed, | ||
chProps, | ||
chInstances; | ||
meta = obj.__meta; | ||
chInstances = this.changedInstances; | ||
chProps = this.changedProps; | ||
idx = chInstances.indexOf(meta.iid); | ||
if (idx === -1) { | ||
chInstances.push(meta.iid); | ||
changed = []; | ||
chProps.push(changed); | ||
} | ||
else { | ||
changed = chProps[idx]; | ||
} | ||
i = props.length; | ||
j = changed.length; | ||
while (i--) { | ||
p = props[i]; | ||
if (changed.indexOf(p) === -1) { | ||
changed[j++] = p; | ||
} | ||
} | ||
merge(meta.changedProps, props); | ||
this.watcher.start(); | ||
return changed; | ||
}, | ||
@@ -102,3 +160,3 @@ | ||
if (!~idx) { | ||
if (idx === -1) { | ||
meta.watchers.fns.push(fn); | ||
@@ -105,0 +163,0 @@ idx = meta.watchers.fns.length - 1; |
@@ -16,84 +16,190 @@ $b( | ||
init : function (instances) { | ||
instanceManager : null, | ||
this.instances = instances; | ||
init : function (instanceManager) { | ||
this.runLoop = RunLoop.create(); | ||
this.runLoop.loop(this.run.bind(this)); | ||
var self; | ||
this.watchLoop = RunLoop.create(); | ||
this.watchLoop.name = 'watchLoop'; | ||
self = this; | ||
if (config.DIRTY_CHECK) { | ||
this.start(); | ||
} | ||
this.instanceManager = instanceManager; | ||
this.runLoop = RunLoop.create(); | ||
this.runLoop.loop(function () { | ||
self.run(); | ||
}); | ||
return this; | ||
}, | ||
dirtyCheck : function (meta, instance) { | ||
processBindings : function (obj, props, meta, prefix, recursionLimit) { | ||
var i, | ||
p; | ||
j, | ||
l, | ||
p, | ||
p2, | ||
arr, | ||
key, | ||
tmp, | ||
changed, | ||
bindings, | ||
memoized, | ||
prefixReset, | ||
memoizedBindings; | ||
for (i = 0; i < meta.watchedProps.length; i ++) { | ||
bindings = meta.bindings; | ||
memoizedBindings = meta.memoizedBindings = meta.memoizedBindings || {}; | ||
p = meta.watchedProps[i]; | ||
prefix = prefix ? prefix.concat('.') : ''; | ||
changed = []; | ||
recursionLimit = recursionLimit || 20; | ||
if (meta.values[p] !== instance[p]) { | ||
instance.set(p, instance[p], false, true); | ||
for (i = 0, l = prefixReset = props.length; i < l; i ++) { | ||
if (i < prefixReset) { | ||
p = prefix.concat(props[i]); | ||
props[i] = p; | ||
} | ||
else { | ||
p = props[i]; | ||
} | ||
memoized = memoizedBindings[p]; | ||
if (memoized == null) { | ||
memoized = []; | ||
if (bindings[p]) { | ||
memoized = bindings[p].concat(); | ||
} | ||
tmp = p.split('.'); | ||
if (tmp.length > 1) { | ||
key = '.'.concat(tmp.pop()); | ||
p2 = tmp.join('.'); | ||
arr = bindings[p2]; | ||
if (arr && (j = arr.length)) { | ||
while (j--) { | ||
memoized.push(arr[j].concat(key)); | ||
} | ||
} | ||
} | ||
memoizedBindings[p] = memoized; | ||
} | ||
if (recursionLimit) { | ||
j = memoized.length; | ||
while (j--) { | ||
tmp = memoized[j]; | ||
if (props.indexOf(tmp) === -1) { | ||
props[l++] = tmp; | ||
} | ||
} | ||
recursionLimit--; | ||
} | ||
} | ||
return props; | ||
}, | ||
notifyWatchers : function (meta, instance) { | ||
run : function () { | ||
var i, | ||
k, | ||
fn, | ||
props, | ||
willNotify, | ||
intersected; | ||
iid, | ||
key, | ||
meta, | ||
meta2, | ||
looped, | ||
watched, | ||
changed, | ||
chProps, | ||
manager, | ||
instance, | ||
instances, | ||
reference, | ||
references, | ||
chInstances, | ||
intersected, | ||
referenceKeys; | ||
for (i = 0; i < meta.watchers.fns.length; i ++) { | ||
manager = this.instanceManager; | ||
instances = manager.instances; | ||
chProps = manager.changedProps; | ||
chInstances = manager.changedInstances; | ||
looped = []; | ||
fn = meta.watchers.fns[i]; | ||
props = meta.watchers.props[i]; | ||
intersected = props.length ? intersect(props, meta.changedProps) : meta.changedProps.concat(); | ||
k = 0; | ||
if (!intersected.length) { | ||
while (chInstances.length) { | ||
iid = chInstances[k]; | ||
instance = instances[iid]; | ||
if (!instance) { | ||
chProps.splice(k, 1); | ||
chInstances.splice(k, 1); | ||
continue; | ||
} | ||
willNotify = true; | ||
this.watchLoop.once(fn, intersected); | ||
} | ||
looped.push(instance); | ||
if (willNotify) { | ||
instance.willNotifyWatchers.call(instance); | ||
} | ||
meta = instance.__meta; | ||
references = meta.references; | ||
referenceKeys = meta.referenceKeys; | ||
while (this.watchLoop.run()) { | ||
changed = chProps[k]; | ||
this.processBindings(instance, changed, meta); | ||
} | ||
// Loop through all references and notify them too... | ||
if (changed.length && references.length) { | ||
instance.didNotifyWatchers.call(instance); | ||
}, | ||
i = meta.references.length; | ||
run : function () { | ||
while (i --) { | ||
this.instances.forEach(function (meta, instance) { | ||
reference = references[i]; | ||
if (config.DIRTY_CHECK) { | ||
this.dirtyCheck(meta, instance); | ||
if (~looped.indexOf(reference)) { | ||
continue; | ||
} | ||
looped.push(reference); | ||
key = referenceKeys[i]; | ||
meta2 = reference.__meta; | ||
/* TODO : Move this.... | ||
if (reference.isDestroyed) { | ||
instance.__removeReference(reference); | ||
continue; | ||
}*/ | ||
watched = this.processBindings(reference, changed.concat(), meta2, key); | ||
manager.propertiesDidChange(reference, watched); | ||
} | ||
} | ||
if (meta.changedProps.length) { | ||
this.notifyWatchers(meta, instance); | ||
i = meta.watchers.fns.length; | ||
instance.willNotifyWatchers.call(instance); | ||
while (i--) { | ||
fn = meta.watchers.fns[i]; | ||
watched = meta.watchers.props[i]; | ||
intersected = watched.length ? intersect(watched, changed) : changed.concat(); | ||
if (!intersected.length) { | ||
continue; | ||
} | ||
fn.call(null, intersected); | ||
} | ||
instance.didNotifyWatchers.call(instance); | ||
chProps.splice(k, 1); | ||
chInstances.splice(k, 1); | ||
} | ||
}, this); | ||
manager.changedProps = []; | ||
manager.changedInstances = []; | ||
if (!config.DIRTY_CHECK) { | ||
this.stop(); | ||
} | ||
this.stop(); | ||
}, | ||
@@ -100,0 +206,0 @@ |
@@ -68,2 +68,5 @@ $b( | ||
meta.references = []; | ||
meta.referenceKeys = []; | ||
if (o && typeof o === 'object' && !Array.isArray(o)) { | ||
@@ -181,24 +184,13 @@ | ||
if (!config.DIRTY_CHECK) { | ||
d = clone(d); | ||
d = clone(d); | ||
// Modern browsers, IE9 + | ||
if (Object.defineProperty) { | ||
Object.defineProperty(this, p, d); | ||
} | ||
// Modern browsers, IE9 + | ||
if (Object.defineProperty) { | ||
Object.defineProperty(this, p, d); | ||
} | ||
// Old FF | ||
else if (this.__defineGetter__) { | ||
this.__defineGetter__(p, d.get); | ||
this.__defineSetter__(p, d.set); | ||
} | ||
else { | ||
this.__meta.pojoStyle = true; | ||
} | ||
if (typeof d.defaultValue !== 'undefined') { | ||
this.set(p, d.defaultValue, true, true); | ||
} | ||
// Old FF | ||
else if (this.__defineGetter__) { | ||
this.__defineGetter__(p, d.get); | ||
this.__defineSetter__(p, d.set); | ||
} | ||
@@ -208,4 +200,7 @@ | ||
this.__meta.pojoStyle = true; | ||
this[p] = d.defaultValue; | ||
} | ||
if (typeof d.defaultValue !== 'undefined') { | ||
this.set(p, d.defaultValue, true, true); | ||
} | ||
}, | ||
@@ -222,3 +217,3 @@ | ||
meta = this.__meta; | ||
bindings = meta.externalBindings || {}; | ||
bindings = meta.externalBindings; | ||
@@ -278,100 +273,23 @@ // Cleanup external bindings | ||
__hasReference : function (obj) { | ||
this.__meta.references = this.__meta.references || $b.Dictionary.create(); | ||
return this.__meta.references.has(obj); | ||
var meta = this.__meta; | ||
return !!~meta.references.indexOf(obj); | ||
}, | ||
__addReference : function (obj, key) { | ||
this.__meta.references = this.__meta.references || $b.Dictionary.create(); | ||
this.__meta.references.add(obj, key); | ||
var meta = this.__meta; | ||
meta.references.push(obj); | ||
meta.referenceKeys.push(key); | ||
}, | ||
__removeReference : function (obj) { | ||
this.__meta.references = this.__meta.references || $b.Dictionary.create(); | ||
this.__meta.references.remove(obj); | ||
}, | ||
__propertiesDidChange : function (props, skipReference) { | ||
var idx, | ||
meta; | ||
var i, | ||
j, | ||
p, | ||
tmp, | ||
meta, | ||
bindings, | ||
changedProps; | ||
meta = this.__meta; | ||
idx = meta.references.indexOf(obj); | ||
if ($b.instanceManager && props.length) { | ||
meta = this.__meta; | ||
changedProps = meta.changedProps || []; | ||
bindings = meta.bindings; | ||
if (props.length) { | ||
for (i = 0; i < props.length; i ++) { | ||
p = props[i]; | ||
if (changedProps.indexOf(p) > -1) { | ||
props.splice(i, 1); | ||
i --; | ||
} | ||
else if (bindings[p] && bindings[p].length) { | ||
props = props.concat(bindings[p]); | ||
} | ||
else if (changedProps.length) { | ||
for (j = 0; j < changedProps.length; j ++) { | ||
if (new RegExp(changedProps[j] + '\.').test(p)) { | ||
props.splice(i, 1); | ||
i --; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
if (props.length) { | ||
for (i = 0; i < props.length; i ++) { | ||
p = props[i].split('.'); | ||
tmp = p[p.length - 1]; | ||
if (p.length > 2) { | ||
p = p.splice(0, p.length - 1).join('.'); | ||
if (bindings[p] && bindings[p].length) { | ||
for (j = 0; j < bindings[p].length; j ++) { | ||
props.push(bindings[p][j] + '.' + tmp); | ||
} | ||
} | ||
} | ||
} | ||
$b.instanceManager.propertyDidChange(this, props); | ||
if (meta.references) { | ||
meta.references.forEach(function (key, instance) { | ||
var subProps = []; | ||
if (instance.isDestroyed) { | ||
this.__removeReference(instance); | ||
return; | ||
} | ||
for (i = 0; i < props.length; i ++) { | ||
p = (key ? key + '.' : '') + props[i]; | ||
if (skipReference !== instance && get(instance, p) !== this) { | ||
subProps.push(p); | ||
} | ||
} | ||
instance.__propertiesDidChange(subProps, this); | ||
}, this); | ||
} | ||
} | ||
if (~idx) { | ||
meta.references.splice(idx, 1); | ||
meta.referenceKeys.splice(idx, 1); | ||
} | ||
@@ -384,10 +302,12 @@ }, | ||
There is almost no need to ever call this manually, as Brink will call it for you | ||
when setting a property. | ||
This will also trigger any watchers of this property in the next Run Loop. | ||
@method propertyDidChange | ||
@param {Array|String} props A single property or an array of properties. | ||
@param {String} prop The property that changed. | ||
************************************************************************/ | ||
propertyDidChange : function (props) { | ||
props = flatten([].slice.call(arguments, 0, arguments.length)); | ||
return this.__propertiesDidChange(props); | ||
propertyDidChange : function (prop) { | ||
$b.instanceManager.propertyDidChange(this, prop); | ||
}, | ||
@@ -412,3 +332,3 @@ | ||
if (props.length) { | ||
if (arguments.length) { | ||
@@ -436,3 +356,3 @@ for (i = 0; i < props.length; i ++) { | ||
getChangedProperties : function () { | ||
return this.getProperties.apply(this, this.__meta.changedProps); | ||
return this.getProperties($b.instanceManager.getChangedProps(this)); | ||
}, | ||
@@ -452,4 +372,7 @@ | ||
i, | ||
p, | ||
obj, | ||
meta; | ||
tmp, | ||
meta, | ||
watched; | ||
@@ -461,4 +384,6 @@ obj = getObjKeyPair(this, key); | ||
meta = obj.__meta; | ||
meta.bindings = meta.bindings || {}; | ||
meta.externalBindings = meta.externalBindings || {}; | ||
meta.memoizedBindings = meta.memoizedBindings || {}; | ||
@@ -483,16 +408,36 @@ if (typeof meta.properties[key] !== 'undefined') { | ||
if (val.watch && val.watch.length) { | ||
for (i = 0; i < val.watch.length; i ++) { | ||
a = meta.bindings[val.watch[i]] = meta.bindings[val.watch[i]] || []; | ||
a.push(key); | ||
watched = val.watch; | ||
if (watched && (i = watched.length)) { | ||
tmp = []; | ||
while (i--) { | ||
a = watched[i].split('.'); | ||
p = null; | ||
while (a.length) { | ||
p = (p ? p.concat('.') : '').concat(a.splice(0, 1)[0]); | ||
tmp.push(p); | ||
} | ||
} | ||
i = tmp.length; | ||
if (i) { | ||
meta.memoizedBindings = {}; | ||
} | ||
while (i--) { | ||
a = meta.bindings[tmp[i]] = meta.bindings[tmp[i]] || []; | ||
if (!~a.indexOf(key)) { | ||
a.push(key); | ||
} | ||
} | ||
} | ||
val.bindTo = bindFunction(function (o, p) { | ||
val.bindTo = function (o, p) { | ||
this.prop(p, bindTo(o, p)); | ||
}, obj); | ||
}.bind(obj); | ||
val.didChange = bindFunction(function () { | ||
val.didChange = function () { | ||
obj.propertyDidChange(key); | ||
}, obj); | ||
}.bind(obj); | ||
@@ -686,5 +631,3 @@ if (val.boundTo) { | ||
didNotifyWatchers : function () { | ||
if (this.__meta) { | ||
this.__meta.changedProps = []; | ||
} | ||
}, | ||
@@ -691,0 +634,0 @@ |
@@ -13,3 +13,3 @@ $b( | ||
__interval : 25, | ||
__interval : 'raf', | ||
__timerID : null, | ||
@@ -16,0 +16,0 @@ __started : false, |
@@ -93,5 +93,3 @@ $b( | ||
this.watch(props.concat('isLocked'), this.contextUpdated); | ||
setTimeout(function () { | ||
this.propertyDidChange(props); | ||
}.bind(this), 0); | ||
this.contextUpdated(); | ||
} | ||
@@ -98,0 +96,0 @@ }, |
@@ -146,3 +146,3 @@ $b( | ||
moveItem : function (item, newIndex) { | ||
moveItem : function (item/*,newIndex*/) { | ||
@@ -149,0 +149,0 @@ var lDict; |
@@ -175,3 +175,3 @@ $b( | ||
$b('templates/' + name, Template.create(tmpl)); | ||
$b('templates/' + name, Template.create(tmpl.innerHTML)); | ||
} | ||
@@ -178,0 +178,0 @@ }); |
$b( | ||
[ | ||
'./flatten', | ||
'./isFunction', | ||
'./expandProps' | ||
'./isFunction' | ||
], | ||
@@ -12,3 +10,3 @@ | ||
************************************************************************/ | ||
function (flatten, isFunction, expandProps) { | ||
function (isFunction) { | ||
@@ -88,3 +86,3 @@ 'use strict'; | ||
o = { | ||
watch : flatten([].slice.call(arguments, 1)), | ||
watch : arguments[1], | ||
get : o | ||
@@ -98,3 +96,3 @@ }; | ||
o.watch = expandProps(o.watch ? [].concat(o.watch) : []); | ||
o.watch = o.watch ? [].concat(o.watch) : []; | ||
o.__isComputed = true; | ||
@@ -101,0 +99,0 @@ |
$b( | ||
[ | ||
'./flatten' | ||
], | ||
@@ -10,3 +9,3 @@ | ||
************************************************************************/ | ||
function (flatten) { | ||
function () { | ||
@@ -27,10 +26,16 @@ 'use strict'; | ||
var i, | ||
c; | ||
c, | ||
d; | ||
b = flatten([].slice.call(arguments, 1)); | ||
c = []; | ||
i = b.length; | ||
for (i = 0; i < b.length; i ++) { | ||
if (~a.indexOf(b[i])) { | ||
c.push(b[i]); | ||
if (!a.length || !i) { | ||
return c; | ||
} | ||
while (i--) { | ||
d = b[i]; | ||
if (~a.indexOf(d)) { | ||
c.push(d); | ||
} | ||
@@ -37,0 +42,0 @@ } |
@@ -57,5 +57,8 @@ $b( | ||
obj = getObjKeyPair(obj, key, true); | ||
key = obj[1]; | ||
obj = obj[0]; | ||
if (key.indexOf('.') > -1) { | ||
obj = getObjKeyPair(obj, key, true); | ||
key = obj[1]; | ||
obj = obj[0]; | ||
} | ||
old = get(obj, key); | ||
@@ -62,0 +65,0 @@ |
764574
15326