mobservable
Advanced tools
Comparing version 0.6.1 to 0.6.2
@@ -18,5 +18,5 @@ /** | ||
sideEffect(func: Mobservable.Lambda,scope?): Mobservable.Lambda; | ||
sideEffect(func: Mobservable.Lambda, options?: Mobservable.IMakeReactiveOptions): Mobservable.Lambda; | ||
observeUntilInvalid<T>(func: ()=>T, onInvalidate: Mobservable.Lambda): [T,Mobservable.Lambda]; | ||
observeUntilInvalid<T>(func: ()=>T, onInvalidate: Mobservable.Lambda, context?: Mobservable.IContextInfo): [T,Mobservable.Lambda]; | ||
@@ -33,2 +33,10 @@ transaction<T>(action: ()=>T): T; | ||
debugLevel: number; | ||
extras: { | ||
getDependencyTree(thing:any, property?:string): Mobservable.IDependencyTree; | ||
getObserverTree(thing:any, property?:string): Mobservable.IObserverTree; | ||
trackTransitions(extensive?:boolean, onReport?:(lines:Mobservable.ITransitionEvent) => void) : Mobservable.Lambda; | ||
} | ||
} | ||
@@ -50,8 +58,18 @@ | ||
scope?: Object, | ||
context?: Object, | ||
recurse?: boolean; | ||
name?: string; | ||
// protected: boolean TODO: see #9 | ||
} | ||
export interface IContextInfoStruct { | ||
object: Object; | ||
name: string; | ||
} | ||
export type IContextInfo = IContextInfoStruct | string; | ||
interface Lambda { | ||
(): void; | ||
name?: string; | ||
} | ||
@@ -94,2 +112,26 @@ | ||
} | ||
interface IDependencyTree { | ||
id: number; | ||
name: string; | ||
context: any; | ||
dependencies?: IDependencyTree[]; | ||
} | ||
interface IObserverTree { | ||
id: number; | ||
name: string; | ||
context: any; | ||
observers?: IObserverTree[]; | ||
listeners?: number; // amount of functions manually attached using an .observe method | ||
} | ||
interface ITransitionEvent { | ||
id: number; | ||
name: string; | ||
context: Object; | ||
state: string; | ||
changed: boolean; | ||
newValue: string; | ||
} | ||
} | ||
@@ -96,0 +138,0 @@ |
@@ -6,71 +6,3 @@ /** | ||
*/ | ||
var mobservable; | ||
(function (mobservable) { | ||
var _; | ||
(function (_) { | ||
var ObservableValue = (function () { | ||
function ObservableValue(value, recurse) { | ||
this.value = value; | ||
this.recurse = recurse; | ||
this.changeEvent = new _.SimpleEventEmitter(); | ||
this.dependencyState = new _.DNode(this); | ||
this._value = this.makeReferenceValueReactive(value); | ||
} | ||
ObservableValue.prototype.makeReferenceValueReactive = function (value) { | ||
if (this.recurse && (Array.isArray(value) || _.isPlainObject(value))) | ||
return mobservable.makeReactive(value); | ||
return value; | ||
}; | ||
ObservableValue.prototype.set = function (value) { | ||
if (value !== this._value) { | ||
var oldValue = this._value; | ||
this.dependencyState.markStale(); | ||
this._value = this.makeReferenceValueReactive(value); | ||
this.dependencyState.markReady(true); | ||
this.changeEvent.emit(this._value, oldValue); | ||
} | ||
}; | ||
ObservableValue.prototype.get = function () { | ||
this.dependencyState.notifyObserved(); | ||
return this._value; | ||
}; | ||
ObservableValue.prototype.observe = function (listener, fireImmediately) { | ||
var _this = this; | ||
if (fireImmediately === void 0) { fireImmediately = false; } | ||
this.dependencyState.setRefCount(+1); | ||
if (fireImmediately) | ||
listener(this.get(), undefined); | ||
var disposer = this.changeEvent.on(listener); | ||
return _.once(function () { | ||
_this.dependencyState.setRefCount(-1); | ||
disposer(); | ||
}); | ||
}; | ||
ObservableValue.prototype.createGetterSetter = function () { | ||
var self = this; | ||
var f = function (value) { | ||
if (arguments.length > 0) | ||
self.set(value); | ||
else | ||
return self.get(); | ||
}; | ||
f.impl = this; | ||
f.observe = function (listener, fire) { | ||
return self.observe(listener, fire); | ||
}; | ||
f.toString = function () { | ||
return "" + self.value; | ||
}; | ||
_.markReactive(f); | ||
return f; | ||
}; | ||
ObservableValue.prototype.toString = function () { | ||
return "Observable[" + this._value + "]"; | ||
}; | ||
return ObservableValue; | ||
})(); | ||
_.ObservableValue = ObservableValue; | ||
})(_ = mobservable._ || (mobservable._ = {})); | ||
})(mobservable || (mobservable = {})); | ||
/// <reference path="./observablevalue" /> | ||
/// <reference path="./api.ts" /> | ||
var __extends = (this && this.__extends) || function (d, b) { | ||
@@ -85,84 +17,4 @@ for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; | ||
var _; | ||
(function (_1) { | ||
var ComputedObservable = (function (_super) { | ||
__extends(ComputedObservable, _super); | ||
function ComputedObservable(func, scope) { | ||
_super.call(this, undefined, false); | ||
this.func = func; | ||
this.scope = scope; | ||
this.isComputing = false; | ||
this.hasError = false; | ||
if (typeof func !== "function") | ||
throw new Error("ComputedObservable requires a function"); | ||
} | ||
ComputedObservable.prototype.get = function () { | ||
if (this.isComputing) | ||
throw new Error("Cycle detected"); | ||
var state = this.dependencyState; | ||
if (state.isSleeping) { | ||
if (_1.DNode.trackingStack.length > 0) { | ||
state.wakeUp(); | ||
state.notifyObserved(); | ||
} | ||
else { | ||
this.compute(); | ||
} | ||
} | ||
else { | ||
state.notifyObserved(); | ||
} | ||
if (state.hasCycle) | ||
throw new Error("Cycle detected"); | ||
if (this.hasError) { | ||
if (mobservable.debugLevel) { | ||
console.trace(); | ||
_1.warn(this + ": rethrowing caught exception to observer: " + this._value + (this._value.cause || '')); | ||
} | ||
throw this._value; | ||
} | ||
return this._value; | ||
}; | ||
ComputedObservable.prototype.set = function (_) { | ||
throw new Error(this.toString() + ": A computed observable does not accept new values!"); | ||
}; | ||
ComputedObservable.prototype.compute = function () { | ||
var newValue; | ||
try { | ||
if (this.isComputing) | ||
throw new Error("Cycle detected"); | ||
this.isComputing = true; | ||
newValue = this.func.call(this.scope); | ||
this.hasError = false; | ||
} | ||
catch (e) { | ||
this.hasError = true; | ||
console.error(this + "Caught error during computation: ", e); | ||
if (e instanceof Error) | ||
newValue = e; | ||
else { | ||
newValue = new Error("MobservableComputationError"); | ||
newValue.cause = e; | ||
} | ||
} | ||
this.isComputing = false; | ||
if (newValue !== this._value) { | ||
var oldValue = this._value; | ||
this._value = newValue; | ||
this.changeEvent.emit(newValue, oldValue); | ||
return true; | ||
} | ||
return false; | ||
}; | ||
ComputedObservable.prototype.toString = function () { | ||
return "ComputedObservable[" + this.func.toString() + "]"; | ||
}; | ||
return ComputedObservable; | ||
})(_1.ObservableValue); | ||
_1.ComputedObservable = ComputedObservable; | ||
})(_ = mobservable._ || (mobservable._ = {})); | ||
})(mobservable || (mobservable = {})); | ||
var mobservable; | ||
(function (mobservable) { | ||
var _; | ||
(function (_) { | ||
var mobservableId = 0; | ||
(function (DNodeState) { | ||
@@ -175,49 +27,41 @@ DNodeState[DNodeState["STALE"] = 0] = "STALE"; | ||
; | ||
var DNode = (function () { | ||
function DNode(owner) { | ||
this.owner = owner; | ||
var RootDNode = (function () { | ||
function RootDNode(context) { | ||
this.context = context; | ||
this.id = ++mobservableId; | ||
this.state = DNodeState.READY; | ||
this.isSleeping = true; | ||
this.hasCycle = false; | ||
this.observing = []; | ||
this.prevObserving = null; | ||
this.observers = []; | ||
this.dependencyChangeCount = 0; | ||
this.dependencyStaleCount = 0; | ||
this.isDisposed = false; | ||
this.externalRefenceCount = 0; | ||
this.isComputed = owner.compute !== undefined; | ||
if (!context.name) | ||
context.name = "[m#" + this.id + "]"; | ||
} | ||
; | ||
DNode.prototype.setRefCount = function (delta) { | ||
var rc = this.externalRefenceCount += delta; | ||
if (rc === 0) | ||
this.tryToSleep(); | ||
else if (rc === delta) | ||
this.wakeUp(); | ||
RootDNode.prototype.setRefCount = function (delta) { | ||
this.externalRefenceCount += delta; | ||
}; | ||
DNode.prototype.addObserver = function (node) { | ||
RootDNode.prototype.addObserver = function (node) { | ||
this.observers[this.observers.length] = node; | ||
}; | ||
DNode.prototype.removeObserver = function (node) { | ||
RootDNode.prototype.removeObserver = function (node) { | ||
var obs = this.observers, idx = obs.indexOf(node); | ||
if (idx !== -1) { | ||
if (idx !== -1) | ||
obs.splice(idx, 1); | ||
if (obs.length === 0) | ||
this.tryToSleep(); | ||
} | ||
}; | ||
DNode.prototype.markStale = function () { | ||
RootDNode.prototype.markStale = function () { | ||
if (this.state !== DNodeState.READY) | ||
return; | ||
this.state = DNodeState.STALE; | ||
if (_.transitionTracker) | ||
_.reportTransition(this, "STALE"); | ||
this.notifyObservers(); | ||
}; | ||
DNode.prototype.markReady = function (stateDidActuallyChange) { | ||
RootDNode.prototype.markReady = function (stateDidActuallyChange) { | ||
if (this.state === DNodeState.READY) | ||
return; | ||
this.state = DNodeState.READY; | ||
if (_.transitionTracker) | ||
_.reportTransition(this, "READY", true, this["_value"]); | ||
this.notifyObservers(stateDidActuallyChange); | ||
}; | ||
DNode.prototype.notifyObservers = function (stateDidActuallyChange) { | ||
RootDNode.prototype.notifyObservers = function (stateDidActuallyChange) { | ||
if (stateDidActuallyChange === void 0) { stateDidActuallyChange = false; } | ||
@@ -228,4 +72,46 @@ var os = this.observers.slice(); | ||
}; | ||
DNode.prototype.tryToSleep = function () { | ||
if (!this.isSleeping && this.isComputed && this.observers.length === 0 && this.externalRefenceCount === 0) { | ||
RootDNode.prototype.notifyObserved = function () { | ||
var ts = RootDNode.trackingStack, l = ts.length; | ||
if (l > 0) { | ||
var cs = ts[l - 1], csl = cs.length; | ||
if (cs[csl - 1] !== this && cs[csl - 2] !== this) | ||
cs[csl] = this; | ||
} | ||
}; | ||
RootDNode.prototype.dispose = function () { | ||
if (this.observers.length) | ||
throw new Error("Cannot dispose DNode; it is still being observed"); | ||
this.isDisposed = true; | ||
}; | ||
RootDNode.prototype.toString = function () { | ||
return "DNode[" + this.context.name + ", state: " + this.state + ", observers: " + this.observers.length + "]"; | ||
}; | ||
RootDNode.trackingStack = []; | ||
return RootDNode; | ||
})(); | ||
_.RootDNode = RootDNode; | ||
var ObservingDNode = (function (_super) { | ||
__extends(ObservingDNode, _super); | ||
function ObservingDNode() { | ||
_super.apply(this, arguments); | ||
this.isSleeping = true; | ||
this.hasCycle = false; | ||
this.observing = []; | ||
this.prevObserving = null; | ||
this.dependencyChangeCount = 0; | ||
this.dependencyStaleCount = 0; | ||
} | ||
ObservingDNode.prototype.setRefCount = function (delta) { | ||
var rc = this.externalRefenceCount += delta; | ||
if (rc === 0) | ||
this.tryToSleep(); | ||
else if (rc === delta) | ||
this.wakeUp(); | ||
}; | ||
ObservingDNode.prototype.removeObserver = function (node) { | ||
_super.prototype.removeObserver.call(this, node); | ||
this.tryToSleep(); | ||
}; | ||
ObservingDNode.prototype.tryToSleep = function () { | ||
if (!this.isSleeping && this.observers.length === 0 && this.externalRefenceCount === 0) { | ||
for (var i = 0, l = this.observing.length; i < l; i++) | ||
@@ -237,4 +123,4 @@ this.observing[i].removeObserver(this); | ||
}; | ||
DNode.prototype.wakeUp = function () { | ||
if (this.isSleeping && this.isComputed) { | ||
ObservingDNode.prototype.wakeUp = function () { | ||
if (this.isSleeping) { | ||
this.isSleeping = false; | ||
@@ -245,3 +131,3 @@ this.state = DNodeState.PENDING; | ||
}; | ||
DNode.prototype.notifyStateChange = function (observable, stateDidActuallyChange) { | ||
ObservingDNode.prototype.notifyStateChange = function (observable, stateDidActuallyChange) { | ||
var _this = this; | ||
@@ -267,15 +153,20 @@ if (observable.state === DNodeState.STALE) { | ||
}; | ||
DNode.prototype.computeNextState = function () { | ||
ObservingDNode.prototype.computeNextState = function () { | ||
this.trackDependencies(); | ||
var stateDidChange = this.owner.compute(); | ||
if (_.transitionTracker) | ||
_.reportTransition(this, "PENDING"); | ||
var stateDidChange = this.compute(); | ||
this.bindDependencies(); | ||
this.markReady(stateDidChange); | ||
}; | ||
DNode.prototype.trackDependencies = function () { | ||
ObservingDNode.prototype.compute = function () { | ||
throw "Abstract!"; | ||
}; | ||
ObservingDNode.prototype.trackDependencies = function () { | ||
this.prevObserving = this.observing; | ||
DNode.trackingStack[DNode.trackingStack.length] = []; | ||
RootDNode.trackingStack[RootDNode.trackingStack.length] = []; | ||
}; | ||
DNode.prototype.bindDependencies = function () { | ||
this.observing = DNode.trackingStack.pop(); | ||
if (this.isComputed && this.observing.length === 0 && mobservable.debugLevel > 1 && !this.isDisposed) { | ||
ObservingDNode.prototype.bindDependencies = function () { | ||
this.observing = RootDNode.trackingStack.pop(); | ||
if (this.observing.length === 0 && mobservable.debugLevel > 1 && !this.isDisposed) { | ||
console.trace(); | ||
@@ -290,6 +181,7 @@ _.warn("You have created a function that doesn't observe any values, did you forget to make its dependencies observable?"); | ||
for (var i = 0, l = added.length; i < l; i++) { | ||
if (this.isComputed && added[i].findCycle(this)) { | ||
var dependency = added[i]; | ||
if (dependency instanceof ObservingDNode && dependency.findCycle(this)) { | ||
this.hasCycle = true; | ||
this.observing.splice(this.observing.indexOf(added[i]), 1); | ||
added[i].hasCycle = true; | ||
dependency.hasCycle = true; | ||
} | ||
@@ -301,11 +193,3 @@ else { | ||
}; | ||
DNode.prototype.notifyObserved = function () { | ||
var ts = DNode.trackingStack, l = ts.length; | ||
if (l > 0) { | ||
var cs = ts[l - 1], csl = cs.length; | ||
if (cs[csl - 1] !== this && cs[csl - 2] !== this) | ||
cs[csl] = this; | ||
} | ||
}; | ||
DNode.prototype.findCycle = function (node) { | ||
ObservingDNode.prototype.findCycle = function (node) { | ||
var obs = this.observing; | ||
@@ -315,9 +199,7 @@ if (obs.indexOf(node) !== -1) | ||
for (var l = obs.length, i = 0; i < l; i++) | ||
if (obs[i].findCycle(node)) | ||
if (obs[i] instanceof ObservingDNode && obs[i].findCycle(node)) | ||
return true; | ||
return false; | ||
}; | ||
DNode.prototype.dispose = function () { | ||
if (this.observers.length) | ||
throw new Error("Cannot dispose DNode; it is still being observed"); | ||
ObservingDNode.prototype.dispose = function () { | ||
if (this.observing) | ||
@@ -327,10 +209,9 @@ for (var l = this.observing.length, i = 0; i < l; i++) | ||
this.observing = null; | ||
this.isDisposed = true; | ||
_super.prototype.dispose.call(this); | ||
}; | ||
DNode.trackingStack = []; | ||
return DNode; | ||
})(); | ||
_.DNode = DNode; | ||
return ObservingDNode; | ||
})(RootDNode); | ||
_.ObservingDNode = ObservingDNode; | ||
function stackDepth() { | ||
return DNode.trackingStack.length; | ||
return RootDNode.trackingStack.length; | ||
} | ||
@@ -347,11 +228,2 @@ _.stackDepth = stackDepth; | ||
(function (mobservable) { | ||
var ValueType; | ||
(function (ValueType) { | ||
ValueType[ValueType["Reference"] = 0] = "Reference"; | ||
ValueType[ValueType["PlainObject"] = 1] = "PlainObject"; | ||
ValueType[ValueType["ComplexObject"] = 2] = "ComplexObject"; | ||
ValueType[ValueType["Array"] = 3] = "Array"; | ||
ValueType[ValueType["ViewFunction"] = 4] = "ViewFunction"; | ||
ValueType[ValueType["ComplexFunction"] = 5] = "ComplexFunction"; | ||
})(ValueType || (ValueType = {})); | ||
function makeReactive(value, opts) { | ||
@@ -366,15 +238,21 @@ if (isReactive(value)) | ||
var recurse = opts.recurse !== false; | ||
var sourceType = opts.as === "reference" ? ValueType.Reference : getTypeOfValue(value); | ||
var sourceType = opts.as === "reference" ? _.ValueType.Reference : _.getTypeOfValue(value); | ||
var context = { | ||
name: opts.name, | ||
object: opts.context || opts.scope | ||
}; | ||
switch (sourceType) { | ||
case ValueType.Reference: | ||
case ValueType.ComplexObject: | ||
return _.makeReactiveReference(value, false); | ||
case ValueType.ComplexFunction: | ||
case _.ValueType.Reference: | ||
case _.ValueType.ComplexObject: | ||
return _.toGetterSetterFunction(new _.ObservableValue(value, false, context)); | ||
case _.ValueType.ComplexFunction: | ||
throw new Error("[mobservable:error] Creating reactive functions from functions with multiple arguments is currently not supported, see https://github.com/mweststrate/mobservable/issues/12"); | ||
case ValueType.ViewFunction: | ||
return new _.ComputedObservable(value, opts.scope).createGetterSetter(); | ||
case ValueType.Array: | ||
return new _.ObservableArray(value, recurse); | ||
case ValueType.PlainObject: | ||
return _.extendReactive({}, value, recurse); | ||
case _.ValueType.ViewFunction: | ||
if (!context.name) | ||
context.name = value.name; | ||
return _.toGetterSetterFunction(new _.ObservableView(value, opts.scope || opts.context, context)); | ||
case _.ValueType.Array: | ||
return new _.ObservableArray(value, recurse, context); | ||
case _.ValueType.PlainObject: | ||
return _.extendReactive({}, value, recurse, context); | ||
} | ||
@@ -384,13 +262,2 @@ throw "Illegal State"; | ||
mobservable.makeReactive = makeReactive; | ||
function getTypeOfValue(value) { | ||
if (value === null || value === undefined) | ||
return ValueType.Reference; | ||
if (typeof value === "function") | ||
return value.length ? ValueType.ComplexFunction : ValueType.ViewFunction; | ||
if (Array.isArray(value) || value instanceof _.ObservableArray) | ||
return ValueType.Array; | ||
if (typeof value == 'object') | ||
return _.isPlainObject(value) ? ValueType.PlainObject : ValueType.ComplexObject; | ||
return ValueType.Reference; | ||
} | ||
function asReference(value) { | ||
@@ -403,21 +270,20 @@ return new _.AsReference(value); | ||
return false; | ||
switch (typeof value) { | ||
case "array": | ||
case "object": | ||
case "function": | ||
return value.__isReactive === true; | ||
} | ||
return false; | ||
return !!value.$mobservable; | ||
} | ||
mobservable.isReactive = isReactive; | ||
function sideEffect(func, scope) { | ||
var observable = new _.ComputedObservable(func, scope); | ||
function sideEffect(func, opts) { | ||
opts = opts || {}; | ||
var observable = new _.ObservableView(func, opts.scope || opts.context, { | ||
object: opts.context || opts.scope, | ||
name: opts.name || func.name | ||
}); | ||
var disposer = observable.observe(_.noop); | ||
if (observable.dependencyState.observing.length === 0) | ||
if (observable.observing.length === 0) | ||
_.warn("mobservable.sideEffect: not a single observable was used inside the side-effect function. Side-effect would be a no-op."); | ||
disposer.$mobservable = observable; | ||
return disposer; | ||
} | ||
mobservable.sideEffect = sideEffect; | ||
function extendReactive(target, properties) { | ||
_.extendReactive(target, properties, true); | ||
function extendReactive(target, properties, context) { | ||
_.extendReactive(target, properties, true, context); | ||
} | ||
@@ -427,27 +293,16 @@ mobservable.extendReactive = extendReactive; | ||
var baseValue = descriptor ? descriptor.value : null; | ||
if (typeof baseValue === "function") { | ||
delete descriptor.value; | ||
delete descriptor.writable; | ||
descriptor.configurable = true; | ||
descriptor.get = function () { | ||
var observable = this.key = new _.ComputedObservable(baseValue, this).createGetterSetter(); | ||
return observable; | ||
}; | ||
descriptor.set = function () { | ||
console.trace(); | ||
throw new Error("It is not allowed to reassign observable functions"); | ||
}; | ||
} | ||
else { | ||
Object.defineProperty(target, key, { | ||
configurable: true, enumberable: true, | ||
get: function () { | ||
_.defineReactiveProperty(this, key, undefined, true); | ||
return this[key]; | ||
}, | ||
set: function (value) { | ||
_.defineReactiveProperty(this, key, value, true); | ||
} | ||
}); | ||
} | ||
if (typeof baseValue === "function") | ||
throw new Error("@observable functions are deprecated. Use @observable (getter) properties instead"); | ||
if (descriptor && descriptor.set) | ||
throw new Error("@observable properties cannot have a setter."); | ||
Object.defineProperty(target, key, { | ||
configurable: true, enumberable: true, | ||
get: function () { | ||
_.ObservableObject.asReactive(this, null).set(key, undefined, true); | ||
return this[key]; | ||
}, | ||
set: function (value) { | ||
_.ObservableObject.asReactive(this, null).set(key, value, true); | ||
} | ||
}); | ||
} | ||
@@ -474,5 +329,5 @@ mobservable.observable = observable; | ||
mobservable.transaction = transaction; | ||
function observeUntilInvalid(func, onInvalidate) { | ||
var watch = new _.WatchedExpression(func, onInvalidate); | ||
return [watch.value, function () { return watch.dispose(); }]; | ||
function observeUntilInvalid(func, onInvalidate, context) { | ||
var watch = new _.WatchedExpression(func, onInvalidate, context || func.name); | ||
return [watch.value, function () { return watch.dispose(); }, watch]; | ||
} | ||
@@ -483,77 +338,48 @@ mobservable.observeUntilInvalid = observeUntilInvalid; | ||
(function (_) { | ||
function extendReactive(target, properties, recurse) { | ||
markReactive(target); | ||
(function (ValueType) { | ||
ValueType[ValueType["Reference"] = 0] = "Reference"; | ||
ValueType[ValueType["PlainObject"] = 1] = "PlainObject"; | ||
ValueType[ValueType["ComplexObject"] = 2] = "ComplexObject"; | ||
ValueType[ValueType["Array"] = 3] = "Array"; | ||
ValueType[ValueType["ViewFunction"] = 4] = "ViewFunction"; | ||
ValueType[ValueType["ComplexFunction"] = 5] = "ComplexFunction"; | ||
})(_.ValueType || (_.ValueType = {})); | ||
var ValueType = _.ValueType; | ||
function getTypeOfValue(value) { | ||
if (value === null || value === undefined) | ||
return ValueType.Reference; | ||
if (typeof value === "function") | ||
return value.length ? ValueType.ComplexFunction : ValueType.ViewFunction; | ||
if (Array.isArray(value) || value instanceof _.ObservableArray) | ||
return ValueType.Array; | ||
if (typeof value == 'object') | ||
return _.isPlainObject(value) ? ValueType.PlainObject : ValueType.ComplexObject; | ||
return ValueType.Reference; | ||
} | ||
_.getTypeOfValue = getTypeOfValue; | ||
function extendReactive(target, properties, recurse, context) { | ||
var meta = _.ObservableObject.asReactive(target, context); | ||
for (var key in properties) | ||
defineReactiveProperty(target, key, properties[key], recurse); | ||
if (properties.hasOwnProperty(key)) | ||
meta.set(key, properties[key], recurse); | ||
return target; | ||
} | ||
_.extendReactive = extendReactive; | ||
function defineReactiveProperty(target, name, value, recurse) { | ||
var type; | ||
if (value instanceof AsReference) { | ||
value = value.value; | ||
type = ValueType.Reference; | ||
recurse = false; | ||
} | ||
else { | ||
type = getTypeOfValue(value); | ||
} | ||
var observable; | ||
switch (type) { | ||
case ValueType.Reference: | ||
case ValueType.ComplexObject: | ||
observable = makeReactiveReference(value, false); | ||
break; | ||
case ValueType.ViewFunction: | ||
observable = new _.ComputedObservable(value, target).createGetterSetter(); | ||
break; | ||
case ValueType.ComplexFunction: | ||
_.warn("Storing reactive functions in objects is not supported yet, please use flag 'recurse:false' or wrap the function in 'asReference'"); | ||
observable = makeReactiveReference(value, false); | ||
case ValueType.Array: | ||
case ValueType.PlainObject: | ||
observable = makeReactiveReference(value, recurse); | ||
default: "Illegal state"; | ||
} | ||
Object.defineProperty(target, name, { | ||
get: observable, | ||
set: observable, | ||
enumerable: true, | ||
configurable: false | ||
}); | ||
return target; | ||
function toGetterSetterFunction(observable) { | ||
var f = function (value) { | ||
if (arguments.length > 0) | ||
observable.set(value); | ||
else | ||
return observable.get(); | ||
}; | ||
f.$mobservable = observable; | ||
f.observe = function (listener, fire) { | ||
return observable.observe(listener, fire); | ||
}; | ||
f.toString = function () { | ||
return observable.toString(); | ||
}; | ||
return f; | ||
} | ||
_.defineReactiveProperty = defineReactiveProperty; | ||
function makeReactiveArrayItem(value) { | ||
if (isReactive(value)) | ||
return value; | ||
if (value instanceof AsReference) | ||
return value = value.value; | ||
switch (getTypeOfValue(value)) { | ||
case ValueType.Reference: | ||
case ValueType.ComplexObject: | ||
return value; | ||
case ValueType.ViewFunction: | ||
case ValueType.ComplexFunction: | ||
_.warn("Storing reactive functions in arrays is not supported, please use flag 'recurse:false' or wrap the function in 'asReference'"); | ||
return value; | ||
case ValueType.Array: | ||
return new _.ObservableArray(value, true); | ||
case ValueType.PlainObject: | ||
return _.extendReactive({}, value, true); | ||
} | ||
throw "Illegal State"; | ||
} | ||
_.makeReactiveArrayItem = makeReactiveArrayItem; | ||
function makeReactiveReference(value, recurse) { | ||
return new _.ObservableValue(value, recurse).createGetterSetter(); | ||
} | ||
_.makeReactiveReference = makeReactiveReference; | ||
function markReactive(value) { | ||
Object.defineProperty(value, "__isReactive", { | ||
enumerable: false, | ||
value: true | ||
}); | ||
} | ||
_.markReactive = markReactive; | ||
_.toGetterSetterFunction = toGetterSetterFunction; | ||
var AsReference = (function () { | ||
@@ -572,2 +398,84 @@ function AsReference(value) { | ||
(function (_) { | ||
function warn(message) { | ||
if (console) | ||
console.warn("[mobservable:warning] " + message); | ||
} | ||
_.warn = warn; | ||
function once(func) { | ||
var invoked = false; | ||
return function () { | ||
if (invoked) | ||
return; | ||
invoked = true; | ||
return func.apply(this, arguments); | ||
}; | ||
} | ||
_.once = once; | ||
function noop() { | ||
} | ||
_.noop = noop; | ||
function unique(list) { | ||
var res = []; | ||
list.forEach(function (item) { | ||
if (res.indexOf(item) === -1) | ||
res.push(item); | ||
}); | ||
return res; | ||
} | ||
_.unique = unique; | ||
function isPlainObject(value) { | ||
return value !== null && typeof value == 'object' && Object.getPrototypeOf(value) === Object.prototype; | ||
} | ||
_.isPlainObject = isPlainObject; | ||
function quickDiff(current, base) { | ||
if (!base || !base.length) | ||
return [current, []]; | ||
if (!current || !current.length) | ||
return [[], base]; | ||
var added = []; | ||
var removed = []; | ||
var currentIndex = 0, currentSearch = 0, currentLength = current.length, currentExhausted = false, baseIndex = 0, baseSearch = 0, baseLength = base.length, isSearching = false, baseExhausted = false; | ||
while (!baseExhausted && !currentExhausted) { | ||
if (!isSearching) { | ||
if (currentIndex < currentLength && baseIndex < baseLength && current[currentIndex] === base[baseIndex]) { | ||
currentIndex++; | ||
baseIndex++; | ||
if (currentIndex === currentLength && baseIndex === baseLength) | ||
return [added, removed]; | ||
continue; | ||
} | ||
currentSearch = currentIndex; | ||
baseSearch = baseIndex; | ||
isSearching = true; | ||
} | ||
baseSearch += 1; | ||
currentSearch += 1; | ||
if (baseSearch >= baseLength) | ||
baseExhausted = true; | ||
if (currentSearch >= currentLength) | ||
currentExhausted = true; | ||
if (!currentExhausted && current[currentSearch] === base[baseIndex]) { | ||
added.push.apply(added, current.slice(currentIndex, currentSearch)); | ||
currentIndex = currentSearch + 1; | ||
baseIndex++; | ||
isSearching = false; | ||
} | ||
else if (!baseExhausted && base[baseSearch] === current[currentIndex]) { | ||
removed.push.apply(removed, base.slice(baseIndex, baseSearch)); | ||
baseIndex = baseSearch + 1; | ||
currentIndex++; | ||
isSearching = false; | ||
} | ||
} | ||
added.push.apply(added, current.slice(currentIndex)); | ||
removed.push.apply(removed, base.slice(baseIndex)); | ||
return [added, removed]; | ||
} | ||
_.quickDiff = quickDiff; | ||
})(_ = mobservable._ || (mobservable._ = {})); | ||
})(mobservable || (mobservable = {})); | ||
var mobservable; | ||
(function (mobservable) { | ||
var _; | ||
(function (_) { | ||
var StubArray = (function () { | ||
@@ -579,26 +487,32 @@ function StubArray() { | ||
StubArray.prototype = []; | ||
var ObservableArrayAdministration = (function (_super) { | ||
__extends(ObservableArrayAdministration, _super); | ||
function ObservableArrayAdministration(array, recurse, context) { | ||
_super.call(this, context); | ||
this.array = array; | ||
this.recurse = recurse; | ||
this.values = []; | ||
this.changeEvent = new _.SimpleEventEmitter(); | ||
if (!context.object) | ||
context.object = array; | ||
} | ||
return ObservableArrayAdministration; | ||
})(_.RootDNode); | ||
_.ObservableArrayAdministration = ObservableArrayAdministration; | ||
var ObservableArray = (function (_super) { | ||
__extends(ObservableArray, _super); | ||
function ObservableArray(initialValues, recurse) { | ||
function ObservableArray(initialValues, recurse, context) { | ||
_super.call(this); | ||
_.markReactive(this); | ||
Object.defineProperties(this, { | ||
"recurse": { enumerable: false, value: recurse }, | ||
"dependencyState": { enumerable: false, value: new _.DNode(this) }, | ||
"_values": { | ||
enumerable: false, | ||
value: initialValues | ||
? (recurse | ||
? initialValues.map(_.makeReactiveArrayItem) | ||
: initialValues.slice()) | ||
: [] }, | ||
"changeEvent": { enumerable: false, value: new _.SimpleEventEmitter() } | ||
Object.defineProperty(this, "$mobservable", { | ||
enumerable: false, | ||
configurable: false, | ||
value: new ObservableArrayAdministration(this, recurse, context) | ||
}); | ||
if (initialValues && initialValues.length) | ||
this.updateLength(0, initialValues.length); | ||
this.replace(initialValues); | ||
} | ||
Object.defineProperty(ObservableArray.prototype, "length", { | ||
get: function () { | ||
this.dependencyState.notifyObserved(); | ||
return this._values.length; | ||
this.$mobservable.notifyObserved(); | ||
return this.$mobservable.values.length; | ||
}, | ||
@@ -608,3 +522,3 @@ set: function (newLength) { | ||
throw new Error("Out of range: " + newLength); | ||
var currentLength = this._values.length; | ||
var currentLength = this.$mobservable.values.length; | ||
if (newLength === currentLength) | ||
@@ -632,3 +546,4 @@ return; | ||
ObservableArray.prototype.spliceWithArray = function (index, deleteCount, newItems) { | ||
var length = this._values.length; | ||
var _this = this; | ||
var length = this.$mobservable.values.length; | ||
if ((newItems === undefined || newItems.length === 0) && (deleteCount === 0 || length === 0)) | ||
@@ -650,6 +565,6 @@ return []; | ||
newItems = []; | ||
else if (this.recurse) | ||
newItems = newItems.map(_.makeReactiveArrayItem); | ||
else if (this.$mobservable.recurse) | ||
newItems = newItems.map(function (value) { return _this.makeReactiveArrayItem(value); }); | ||
var lengthDelta = newItems.length - deleteCount; | ||
var res = (_a = this._values).splice.apply(_a, [index, deleteCount].concat(newItems)); | ||
var res = (_a = this.$mobservable.values).splice.apply(_a, [index, deleteCount].concat(newItems)); | ||
this.updateLength(length, lengthDelta); | ||
@@ -660,5 +575,20 @@ this.notifySplice(index, res, newItems); | ||
}; | ||
ObservableArray.prototype.makeReactiveArrayItem = function (value) { | ||
if (mobservable.isReactive(value)) | ||
return value; | ||
if (value instanceof _.AsReference) | ||
return value = value.value; | ||
var context = { | ||
object: this.$mobservable.context.object, | ||
name: this.$mobservable.context.name + "[x]" | ||
}; | ||
if (Array.isArray(value)) | ||
return new _.ObservableArray(value, true, context); | ||
if (_.isPlainObject(value)) | ||
return _.extendReactive({}, value, true, context); | ||
return value; | ||
}; | ||
ObservableArray.prototype.notifyChildUpdate = function (index, oldValue) { | ||
this.notifyChanged(); | ||
this.changeEvent.emit({ object: this, type: 'update', index: index, oldValue: oldValue }); | ||
this.$mobservable.changeEvent.emit({ object: this, type: 'update', index: index, oldValue: oldValue }); | ||
}; | ||
@@ -669,7 +599,7 @@ ObservableArray.prototype.notifySplice = function (index, deleted, added) { | ||
this.notifyChanged(); | ||
this.changeEvent.emit({ object: this, type: 'splice', index: index, addedCount: added.length, removed: deleted }); | ||
this.$mobservable.changeEvent.emit({ object: this, type: 'splice', index: index, addedCount: added.length, removed: deleted }); | ||
}; | ||
ObservableArray.prototype.notifyChanged = function () { | ||
this.dependencyState.markStale(); | ||
this.dependencyState.markReady(true); | ||
this.$mobservable.markStale(); | ||
this.$mobservable.markReady(true); | ||
}; | ||
@@ -679,4 +609,4 @@ ObservableArray.prototype.observe = function (listener, fireImmediately) { | ||
if (fireImmediately) | ||
listener({ object: this, type: 'splice', index: 0, addedCount: this._values.length, removed: [] }); | ||
return this.changeEvent.on(listener); | ||
listener({ object: this, type: 'splice', index: 0, addedCount: this.$mobservable.values.length, removed: [] }); | ||
return this.$mobservable.changeEvent.on(listener); | ||
}; | ||
@@ -687,20 +617,23 @@ ObservableArray.prototype.clear = function () { | ||
ObservableArray.prototype.replace = function (newItems) { | ||
return this.spliceWithArray(0, this._values.length, newItems); | ||
return this.spliceWithArray(0, this.$mobservable.values.length, newItems); | ||
}; | ||
ObservableArray.prototype.values = function () { | ||
this.dependencyState.notifyObserved(); | ||
return this._values.slice(); | ||
this.$mobservable.notifyObserved(); | ||
return this.$mobservable.values.slice(); | ||
}; | ||
ObservableArray.prototype.toJSON = function () { | ||
this.dependencyState.notifyObserved(); | ||
return this._values.slice(); | ||
this.$mobservable.notifyObserved(); | ||
return this.$mobservable.values.slice(); | ||
}; | ||
ObservableArray.prototype.clone = function () { | ||
this.dependencyState.notifyObserved(); | ||
return new ObservableArray(this._values, this.recurse); | ||
this.$mobservable.notifyObserved(); | ||
return new ObservableArray(this.$mobservable.values, this.$mobservable.recurse, { | ||
object: null, | ||
name: this.$mobservable.context.name + "[clone]" | ||
}); | ||
}; | ||
ObservableArray.prototype.find = function (predicate, thisArg, fromIndex) { | ||
if (fromIndex === void 0) { fromIndex = 0; } | ||
this.dependencyState.notifyObserved(); | ||
var items = this._values, l = items.length; | ||
this.$mobservable.notifyObserved(); | ||
var items = this.$mobservable.values, l = items.length; | ||
for (var i = fromIndex; i < l; i++) | ||
@@ -733,8 +666,8 @@ if (predicate.call(thisArg, items[i], i, this)) | ||
this.sideEffectWarning("push"); | ||
this.spliceWithArray(this._values.length, 0, items); | ||
return this._values.length; | ||
this.spliceWithArray(this.$mobservable.values.length, 0, items); | ||
return this.$mobservable.values.length; | ||
}; | ||
ObservableArray.prototype.pop = function () { | ||
this.sideEffectWarning("pop"); | ||
return this.splice(Math.max(this._values.length - 1, 0), 1)[0]; | ||
return this.splice(Math.max(this.$mobservable.values.length - 1, 0), 1)[0]; | ||
}; | ||
@@ -752,15 +685,15 @@ ObservableArray.prototype.shift = function () { | ||
this.spliceWithArray(0, 0, items); | ||
return this._values.length; | ||
return this.$mobservable.values.length; | ||
}; | ||
ObservableArray.prototype.reverse = function () { | ||
this.sideEffectWarning("reverse"); | ||
return this.replace(this._values.reverse()); | ||
return this.replace(this.$mobservable.values.reverse()); | ||
}; | ||
ObservableArray.prototype.sort = function (compareFn) { | ||
this.sideEffectWarning("sort"); | ||
return this.replace(this._values.sort.apply(this._values, arguments)); | ||
return this.replace(this.$mobservable.values.sort.apply(this.$mobservable.values, arguments)); | ||
}; | ||
ObservableArray.prototype.remove = function (value) { | ||
this.sideEffectWarning("remove"); | ||
var idx = this._values.indexOf(value); | ||
var idx = this.$mobservable.values.indexOf(value); | ||
if (idx > -1) { | ||
@@ -789,8 +722,8 @@ this.splice(idx, 1); | ||
return (ObservableArray.prototype[funcName] = function () { | ||
this.dependencyState.notifyObserved(); | ||
return baseFunc.apply(this._values, arguments); | ||
this.$mobservable.notifyObserved(); | ||
return baseFunc.apply(this.$mobservable.values, arguments); | ||
}).apply(this, initialArgs); | ||
}; | ||
ObservableArray.prototype.sideEffectWarning = function (funcName) { | ||
if (mobservable.debugLevel > 0 && _.DNode.trackingStack.length > 0) | ||
if (mobservable.debugLevel > 0 && _.RootDNode.trackingStack.length > 0) | ||
_.warn("[Mobservable.Array] The method array." + funcName + " should probably not be used inside observable functions since it has side-effects"); | ||
@@ -808,10 +741,10 @@ }; | ||
set: function (value) { | ||
if (index < this._values.length) { | ||
var oldValue = this._values[index]; | ||
if (index < this.$mobservable.values.length) { | ||
var oldValue = this.$mobservable.values[index]; | ||
if (oldValue !== value) { | ||
this._values[index] = value; | ||
this.$mobservable.values[index] = value; | ||
this.notifyChildUpdate(index, oldValue); | ||
} | ||
} | ||
else if (index === this._values.length) | ||
else if (index === this.$mobservable.values.length) | ||
this.push(value); | ||
@@ -822,5 +755,5 @@ else | ||
get: function () { | ||
if (index < this._values.length) { | ||
this.dependencyState.notifyObserved(); | ||
return this._values[index]; | ||
if (index < this.$mobservable.values.length) { | ||
this.$mobservable.notifyObserved(); | ||
return this.$mobservable.values[index]; | ||
} | ||
@@ -843,6 +776,348 @@ return undefined; | ||
})(mobservable || (mobservable = {})); | ||
/// <reference path="./index.ts" /> | ||
/// <reference path="./utils.ts" /> | ||
/// <reference path="./dnode.ts" /> | ||
/// <reference path="./observablearray.ts" /> | ||
/// <reference path="./api.ts" /> | ||
var mobservable; | ||
(function (mobservable) { | ||
var _; | ||
(function (_) { | ||
function getDNode(thing, property) { | ||
if (!mobservable.isReactive(thing)) | ||
throw new Error("[mobservable.getDNode] " + thing + " doesn't seem to be reactive"); | ||
if (property !== undefined) { | ||
_.RootDNode.trackingStack.push([]); | ||
thing[property]; | ||
var dnode = _.RootDNode.trackingStack.pop()[0]; | ||
if (!dnode) | ||
throw new Error("[mobservable.getDNode] property '" + property + "' of '" + thing + "' doesn't seem to be a reactive property"); | ||
return dnode; | ||
} | ||
if (thing.$mobservable) { | ||
if (thing.$mobservable instanceof _.ObservableObject) | ||
throw new Error("[mobservable.getDNode] missing properties parameter. Please specify a property of '" + thing + "'."); | ||
return thing.$mobservable; | ||
} | ||
throw new Error("[mobservable.getDNode] " + thing + " doesn't seem to be reactive"); | ||
} | ||
_.getDNode = getDNode; | ||
function reportTransition(node, state, changed, newValue) { | ||
if (changed === void 0) { changed = false; } | ||
if (newValue === void 0) { newValue = null; } | ||
_.transitionTracker.emit({ | ||
id: node.id, | ||
name: node.context.name, | ||
context: node.context.object, | ||
state: state, | ||
changed: changed, | ||
newValue: newValue | ||
}); | ||
} | ||
_.reportTransition = reportTransition; | ||
_.transitionTracker = null; | ||
})(_ = mobservable._ || (mobservable._ = {})); | ||
var extras; | ||
(function (extras) { | ||
function getDependencyTree(thing, property) { | ||
return nodeToDependencyTree(_.getDNode(thing, property)); | ||
} | ||
extras.getDependencyTree = getDependencyTree; | ||
function nodeToDependencyTree(node) { | ||
var result = { | ||
id: node.id, | ||
name: node.context.name, | ||
context: node.context.object || null | ||
}; | ||
if (node instanceof _.ObservingDNode && node.observing.length) | ||
result.dependencies = _.unique(node.observing).map(nodeToDependencyTree); | ||
return result; | ||
} | ||
function getObserverTree(thing, property) { | ||
return nodeToObserverTree(_.getDNode(thing, property)); | ||
} | ||
extras.getObserverTree = getObserverTree; | ||
function nodeToObserverTree(node) { | ||
var result = { | ||
id: node.id, | ||
name: node.context.name, | ||
context: node.context.object || null | ||
}; | ||
if (node.observers.length) | ||
result.observers = _.unique(node.observers).map(nodeToObserverTree); | ||
if (node.externalRefenceCount > 0) | ||
result.listeners = node.externalRefenceCount; | ||
return result; | ||
} | ||
function createConsoleReporter(extensive) { | ||
var lines = []; | ||
var scheduled = false; | ||
return function (line) { | ||
if (extensive || line.changed) | ||
lines.push(line); | ||
if (!scheduled) { | ||
scheduled = true; | ||
setTimeout(function () { | ||
console[console["table"] ? "table" : "dir"](lines); | ||
lines = []; | ||
scheduled = false; | ||
}, 1); | ||
} | ||
}; | ||
} | ||
function trackTransitions(extensive, onReport) { | ||
if (extensive === void 0) { extensive = false; } | ||
if (!_.transitionTracker) | ||
_.transitionTracker = new _.SimpleEventEmitter(); | ||
var reporter = onReport | ||
? function (line) { | ||
if (extensive || line.changed) | ||
onReport(line); | ||
} | ||
: createConsoleReporter(extensive); | ||
var disposer = _.transitionTracker.on(reporter); | ||
return _.once(function () { | ||
disposer(); | ||
if (_.transitionTracker.listeners.length === 0) | ||
_.transitionTracker = null; | ||
}); | ||
} | ||
extras.trackTransitions = trackTransitions; | ||
})(extras = mobservable.extras || (mobservable.extras = {})); | ||
})(mobservable || (mobservable = {})); | ||
/// <reference path="./dnode.ts" /> | ||
var mobservable; | ||
(function (mobservable) { | ||
var _; | ||
(function (_) { | ||
var ObservableValue = (function (_super) { | ||
__extends(ObservableValue, _super); | ||
function ObservableValue(value, recurse, context) { | ||
_super.call(this, context); | ||
this.value = value; | ||
this.recurse = recurse; | ||
this.changeEvent = new _.SimpleEventEmitter(); | ||
this._value = this.makeReferenceValueReactive(value); | ||
} | ||
ObservableValue.prototype.makeReferenceValueReactive = function (value) { | ||
if (this.recurse && (Array.isArray(value) || _.isPlainObject(value))) | ||
return mobservable.makeReactive(value, { | ||
context: this.context.object, | ||
name: this.context.name | ||
}); | ||
return value; | ||
}; | ||
ObservableValue.prototype.set = function (value) { | ||
if (value !== this._value) { | ||
var oldValue = this._value; | ||
this.markStale(); | ||
this._value = this.makeReferenceValueReactive(value); | ||
this.markReady(true); | ||
this.changeEvent.emit(this._value, oldValue); | ||
} | ||
}; | ||
ObservableValue.prototype.get = function () { | ||
this.notifyObserved(); | ||
return this._value; | ||
}; | ||
ObservableValue.prototype.observe = function (listener, fireImmediately) { | ||
if (fireImmediately === void 0) { fireImmediately = false; } | ||
if (fireImmediately) | ||
listener(this.get(), undefined); | ||
return this.changeEvent.on(listener); | ||
}; | ||
ObservableValue.prototype.asPropertyDescriptor = function () { | ||
var _this = this; | ||
return { | ||
configurable: false, | ||
enumerable: true, | ||
get: function () { return _this.get(); }, | ||
set: function (value) { return _this.set(value); } | ||
}; | ||
}; | ||
ObservableValue.prototype.toString = function () { | ||
return "Observable[" + this.context.name + ":" + this._value + "]"; | ||
}; | ||
return ObservableValue; | ||
})(_.RootDNode); | ||
_.ObservableValue = ObservableValue; | ||
})(_ = mobservable._ || (mobservable._ = {})); | ||
})(mobservable || (mobservable = {})); | ||
/// <reference path="./observablevalue" /> | ||
var mobservable; | ||
(function (mobservable) { | ||
var _; | ||
(function (_) { | ||
var ObservableView = (function (_super) { | ||
__extends(ObservableView, _super); | ||
function ObservableView(func, scope, context) { | ||
_super.call(this, context); | ||
this.func = func; | ||
this.scope = scope; | ||
this.isComputing = false; | ||
this.hasError = false; | ||
this.changeEvent = new _.SimpleEventEmitter(); | ||
} | ||
ObservableView.prototype.get = function () { | ||
if (this.isComputing) | ||
throw new Error("Cycle detected"); | ||
if (this.isSleeping) { | ||
if (_.RootDNode.trackingStack.length > 0) { | ||
this.wakeUp(); | ||
this.notifyObserved(); | ||
} | ||
else { | ||
this.compute(); | ||
} | ||
} | ||
else { | ||
this.notifyObserved(); | ||
} | ||
if (this.hasCycle) | ||
throw new Error("Cycle detected"); | ||
if (this.hasError) { | ||
if (mobservable.debugLevel) { | ||
console.trace(); | ||
_.warn(this + ": rethrowing caught exception to observer: " + this._value + (this._value.cause || '')); | ||
} | ||
throw this._value; | ||
} | ||
return this._value; | ||
}; | ||
ObservableView.prototype.set = function () { | ||
throwingSetter(); | ||
}; | ||
ObservableView.prototype.compute = function () { | ||
var newValue; | ||
try { | ||
if (this.isComputing) | ||
throw new Error("Cycle detected"); | ||
this.isComputing = true; | ||
newValue = this.func.call(this.scope); | ||
this.hasError = false; | ||
} | ||
catch (e) { | ||
this.hasError = true; | ||
console.error(this + "Caught error during computation: ", e); | ||
if (e instanceof Error) | ||
newValue = e; | ||
else { | ||
newValue = new Error("MobservableComputationError"); | ||
newValue.cause = e; | ||
} | ||
} | ||
this.isComputing = false; | ||
if (newValue !== this._value) { | ||
var oldValue = this._value; | ||
this._value = newValue; | ||
this.changeEvent.emit(newValue, oldValue); | ||
return true; | ||
} | ||
return false; | ||
}; | ||
ObservableView.prototype.observe = function (listener, fireImmediately) { | ||
var _this = this; | ||
if (fireImmediately === void 0) { fireImmediately = false; } | ||
this.setRefCount(+1); | ||
if (fireImmediately) | ||
listener(this.get(), undefined); | ||
var disposer = this.changeEvent.on(listener); | ||
return _.once(function () { | ||
_this.setRefCount(-1); | ||
disposer(); | ||
}); | ||
}; | ||
ObservableView.prototype.asPropertyDescriptor = function () { | ||
var _this = this; | ||
return { | ||
configurable: false, | ||
enumerable: false, | ||
get: function () { return _this.get(); }, | ||
set: throwingSetter | ||
}; | ||
}; | ||
ObservableView.prototype.toString = function () { | ||
return "ComputedObservable[" + this.context.name + ":" + this._value + "]"; | ||
}; | ||
return ObservableView; | ||
})(_.ObservingDNode); | ||
_.ObservableView = ObservableView; | ||
function throwingSetter() { | ||
throw new Error("View functions do not accept new values"); | ||
} | ||
})(_ = mobservable._ || (mobservable._ = {})); | ||
})(mobservable || (mobservable = {})); | ||
/// <reference path="./observablearray.ts" /> | ||
/// <reference path="./observableview.ts" /> | ||
/// <reference path="./index.ts" /> | ||
/// <reference path="./api.ts" /> | ||
/// <reference path="./utils.ts" /> | ||
var mobservable; | ||
(function (mobservable) { | ||
var _; | ||
(function (_) { | ||
var ObservableObject = (function () { | ||
function ObservableObject(target, context) { | ||
this.target = target; | ||
this.context = context; | ||
if (target.$mobservable) | ||
throw new Error("Illegal state: already an reactive object"); | ||
if (!context) { | ||
this.context = { | ||
object: target, | ||
name: "" | ||
}; | ||
} | ||
else if (!context.object) { | ||
context.object = target; | ||
} | ||
this.keys = new _.ObservableArray([], false, { | ||
object: target, | ||
name: this.context.name + "[keys]" | ||
}); | ||
Object.defineProperty(target, "$mobservable", { | ||
enumerable: false, | ||
configurable: false, | ||
value: this | ||
}); | ||
} | ||
ObservableObject.asReactive = function (target, context) { | ||
if (target.$mobservable) | ||
return target.$mobservable; | ||
return new ObservableObject(target, context); | ||
}; | ||
ObservableObject.prototype.set = function (propName, value, recurse) { | ||
if (this.keys.indexOf(propName) === -1) | ||
this.defineReactiveProperty(propName, value, recurse); | ||
else | ||
this.target[propName] = value; | ||
}; | ||
ObservableObject.prototype.defineReactiveProperty = function (propName, value, recurse) { | ||
if (value instanceof _.AsReference) { | ||
value = value.value; | ||
recurse = false; | ||
} | ||
var context = { | ||
object: this.context.object, | ||
name: (this.context.name || "") + "." + propName | ||
}; | ||
var descriptor; | ||
if (typeof value === "function" && value.length === 0 && recurse) | ||
descriptor = new _.ObservableView(value, this.target, context).asPropertyDescriptor(); | ||
else | ||
descriptor = new _.ObservableValue(value, recurse, context).asPropertyDescriptor(); | ||
Object.defineProperty(this.target, propName, descriptor); | ||
}; | ||
return ObservableObject; | ||
})(); | ||
_.ObservableObject = ObservableObject; | ||
})(_ = mobservable._ || (mobservable._ = {})); | ||
})(mobservable || (mobservable = {})); | ||
/// <reference path="./index.ts" /> | ||
var mobservable; | ||
(function (mobservable) { | ||
var reactComponentId = 1; | ||
mobservable.reactiveMixin = { | ||
componentWillMount: function () { | ||
var name = (this.displayName || this.constructor.name || "ReactiveComponent") + reactComponentId++; | ||
var baseRender = this.render; | ||
@@ -855,3 +1130,7 @@ this.render = function () { | ||
_this.forceUpdate(); | ||
}), rendering = _a[0], disposer = _a[1]; | ||
}, { | ||
object: this, | ||
name: name | ||
}), rendering = _a[0], disposer = _a[1], watch = _a[2]; | ||
this.$mobservable = watch; | ||
this._watchDisposer = disposer; | ||
@@ -864,2 +1143,3 @@ return rendering; | ||
this._watchDisposer(); | ||
delete this._mobservableDNode; | ||
}, | ||
@@ -880,14 +1160,15 @@ shouldComponentUpdate: function (nextProps, nextState) { | ||
function reactiveComponent(componentClass) { | ||
var baseMount = componentClass.prototype.componentWillMount; | ||
var baseUnmount = componentClass.prototype.componentWillUnmount; | ||
componentClass.prototype.componentWillMount = function () { | ||
var target = componentClass.prototype || componentClass; | ||
var baseMount = target.componentWillMount; | ||
var baseUnmount = target.componentWillUnmount; | ||
target.componentWillMount = function () { | ||
mobservable.reactiveMixin.componentWillMount.apply(this, arguments); | ||
baseMount && baseMount.apply(this, arguments); | ||
}; | ||
componentClass.prototype.componentWillUnmount = function () { | ||
target.componentWillUnmount = function () { | ||
mobservable.reactiveMixin.componentWillUnmount.apply(this, arguments); | ||
baseUnmount && baseUnmount.apply(this, arguments); | ||
}; | ||
if (!componentClass.prototype.shouldComponentUpdate) | ||
componentClass.prototype.shouldComponentUpdate = mobservable.reactiveMixin.shouldComponentUpdate; | ||
if (!target.shouldComponentUpdate) | ||
target.shouldComponentUpdate = mobservable.reactiveMixin.shouldComponentUpdate; | ||
return componentClass; | ||
@@ -992,75 +1273,2 @@ } | ||
})(mobservable || (mobservable = {})); | ||
var mobservable; | ||
(function (mobservable) { | ||
var _; | ||
(function (_) { | ||
function warn(message) { | ||
if (console) | ||
console.warn("[mobservable:warning] " + message); | ||
} | ||
_.warn = warn; | ||
function once(func) { | ||
var invoked = false; | ||
return function () { | ||
if (invoked) | ||
return; | ||
invoked = true; | ||
return func.apply(this, arguments); | ||
}; | ||
} | ||
_.once = once; | ||
function noop() { | ||
} | ||
_.noop = noop; | ||
function isPlainObject(value) { | ||
return value !== null && typeof value == 'object' && Object.getPrototypeOf(value) === Object.prototype; | ||
} | ||
_.isPlainObject = isPlainObject; | ||
function quickDiff(current, base) { | ||
if (!base || !base.length) | ||
return [current, []]; | ||
if (!current || !current.length) | ||
return [[], base]; | ||
var added = []; | ||
var removed = []; | ||
var currentIndex = 0, currentSearch = 0, currentLength = current.length, currentExhausted = false, baseIndex = 0, baseSearch = 0, baseLength = base.length, isSearching = false, baseExhausted = false; | ||
while (!baseExhausted && !currentExhausted) { | ||
if (!isSearching) { | ||
if (currentIndex < currentLength && baseIndex < baseLength && current[currentIndex] === base[baseIndex]) { | ||
currentIndex++; | ||
baseIndex++; | ||
if (currentIndex === currentLength && baseIndex === baseLength) | ||
return [added, removed]; | ||
continue; | ||
} | ||
currentSearch = currentIndex; | ||
baseSearch = baseIndex; | ||
isSearching = true; | ||
} | ||
baseSearch += 1; | ||
currentSearch += 1; | ||
if (baseSearch >= baseLength) | ||
baseExhausted = true; | ||
if (currentSearch >= currentLength) | ||
currentExhausted = true; | ||
if (!currentExhausted && current[currentSearch] === base[baseIndex]) { | ||
added.push.apply(added, current.slice(currentIndex, currentSearch)); | ||
currentIndex = currentSearch + 1; | ||
baseIndex++; | ||
isSearching = false; | ||
} | ||
else if (!baseExhausted && base[baseSearch] === current[currentIndex]) { | ||
removed.push.apply(removed, base.slice(baseIndex, baseSearch)); | ||
baseIndex = baseSearch + 1; | ||
currentIndex++; | ||
isSearching = false; | ||
} | ||
} | ||
added.push.apply(added, current.slice(currentIndex)); | ||
removed.push.apply(removed, base.slice(baseIndex)); | ||
return [added, removed]; | ||
} | ||
_.quickDiff = quickDiff; | ||
})(_ = mobservable._ || (mobservable._ = {})); | ||
})(mobservable || (mobservable = {})); | ||
/// <reference path="./observablevalue" /> | ||
@@ -1071,9 +1279,10 @@ var mobservable; | ||
(function (_) { | ||
var WatchedExpression = (function () { | ||
function WatchedExpression(expr, onInvalidate) { | ||
var WatchedExpression = (function (_super) { | ||
__extends(WatchedExpression, _super); | ||
function WatchedExpression(expr, onInvalidate, context) { | ||
_super.call(this, context); | ||
this.expr = expr; | ||
this.onInvalidate = onInvalidate; | ||
this.dependencyState = new _.DNode(this); | ||
this.didEvaluate = false; | ||
this.dependencyState.computeNextState(); | ||
this.computeNextState(); | ||
} | ||
@@ -1091,7 +1300,4 @@ WatchedExpression.prototype.compute = function () { | ||
}; | ||
WatchedExpression.prototype.dispose = function () { | ||
this.dependencyState.dispose(); | ||
}; | ||
return WatchedExpression; | ||
})(); | ||
})(_.ObservingDNode); | ||
_.WatchedExpression = WatchedExpression; | ||
@@ -1124,5 +1330,7 @@ })(_ = mobservable._ || (mobservable._ = {})); | ||
var m = mobservable.makeReactive; | ||
m['default'] = mobservable.makeReactive; | ||
for (var key in mobservable) | ||
m[key] = mobservable[key]; | ||
if (mobservable.hasOwnProperty(key)) | ||
m[key] = mobservable[key]; | ||
return m; | ||
})); |
@@ -1,1 +0,1 @@ | ||
var mobservable;!function(a){var b;!function(b){var c=function(){function c(a,c){this.value=a,this.recurse=c,this.changeEvent=new b.SimpleEventEmitter,this.dependencyState=new b.DNode(this),this._value=this.makeReferenceValueReactive(a)}return c.prototype.makeReferenceValueReactive=function(c){return this.recurse&&(Array.isArray(c)||b.isPlainObject(c))?a.makeReactive(c):c},c.prototype.set=function(a){if(a!==this._value){var b=this._value;this.dependencyState.markStale(),this._value=this.makeReferenceValueReactive(a),this.dependencyState.markReady(!0),this.changeEvent.emit(this._value,b)}},c.prototype.get=function(){return this.dependencyState.notifyObserved(),this._value},c.prototype.observe=function(a,c){var d=this;void 0===c&&(c=!1),this.dependencyState.setRefCount(1),c&&a(this.get(),void 0);var e=this.changeEvent.on(a);return b.once(function(){d.dependencyState.setRefCount(-1),e()})},c.prototype.createGetterSetter=function(){var a=this,c=function(b){return arguments.length>0?void a.set(b):a.get()};return c.impl=this,c.observe=function(b,c){return a.observe(b,c)},c.toString=function(){return""+a.value},b.markReactive(c),c},c.prototype.toString=function(){return"Observable["+this._value+"]"},c}();b.ObservableValue=c}(b=a._||(a._={}))}(mobservable||(mobservable={}));var __extends=this&&this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},mobservable;!function(a){var b;!function(b){var c=function(c){function d(a,b){if(c.call(this,void 0,!1),this.func=a,this.scope=b,this.isComputing=!1,this.hasError=!1,"function"!=typeof a)throw new Error("ComputedObservable requires a function")}return __extends(d,c),d.prototype.get=function(){if(this.isComputing)throw new Error("Cycle detected");var c=this.dependencyState;if(c.isSleeping?b.DNode.trackingStack.length>0?(c.wakeUp(),c.notifyObserved()):this.compute():c.notifyObserved(),c.hasCycle)throw new Error("Cycle detected");if(this.hasError)throw a.debugLevel&&(console.trace(),b.warn(this+": rethrowing caught exception to observer: "+this._value+(this._value.cause||""))),this._value;return this._value},d.prototype.set=function(a){throw new Error(this.toString()+": A computed observable does not accept new values!")},d.prototype.compute=function(){var a;try{if(this.isComputing)throw new Error("Cycle detected");this.isComputing=!0,a=this.func.call(this.scope),this.hasError=!1}catch(b){this.hasError=!0,console.error(this+"Caught error during computation: ",b),b instanceof Error?a=b:(a=new Error("MobservableComputationError"),a.cause=b)}if(this.isComputing=!1,a!==this._value){var c=this._value;return this._value=a,this.changeEvent.emit(a,c),!0}return!1},d.prototype.toString=function(){return"ComputedObservable["+this.func.toString()+"]"},d}(b.ObservableValue);b.ComputedObservable=c}(b=a._||(a._={}))}(mobservable||(mobservable={}));var mobservable;!function(a){var b;!function(b){function c(){return e.trackingStack.length}!function(a){a[a.STALE=0]="STALE",a[a.PENDING=1]="PENDING",a[a.READY=2]="READY"}(b.DNodeState||(b.DNodeState={}));var d=b.DNodeState,e=function(){function c(a){this.owner=a,this.state=d.READY,this.isSleeping=!0,this.hasCycle=!1,this.observing=[],this.prevObserving=null,this.observers=[],this.dependencyChangeCount=0,this.dependencyStaleCount=0,this.isDisposed=!1,this.externalRefenceCount=0,this.isComputed=void 0!==a.compute}return c.prototype.setRefCount=function(a){var b=this.externalRefenceCount+=a;0===b?this.tryToSleep():b===a&&this.wakeUp()},c.prototype.addObserver=function(a){this.observers[this.observers.length]=a},c.prototype.removeObserver=function(a){var b=this.observers,c=b.indexOf(a);-1!==c&&(b.splice(c,1),0===b.length&&this.tryToSleep())},c.prototype.markStale=function(){this.state===d.READY&&(this.state=d.STALE,this.notifyObservers())},c.prototype.markReady=function(a){this.state!==d.READY&&(this.state=d.READY,this.notifyObservers(a))},c.prototype.notifyObservers=function(a){void 0===a&&(a=!1);for(var b=this.observers.slice(),c=b.length,d=0;c>d;d++)b[d].notifyStateChange(this,a)},c.prototype.tryToSleep=function(){if(!this.isSleeping&&this.isComputed&&0===this.observers.length&&0===this.externalRefenceCount){for(var a=0,b=this.observing.length;b>a;a++)this.observing[a].removeObserver(this);this.observing=[],this.isSleeping=!0}},c.prototype.wakeUp=function(){this.isSleeping&&this.isComputed&&(this.isSleeping=!1,this.state=d.PENDING,this.computeNextState())},c.prototype.notifyStateChange=function(a,c){var e=this;a.state===d.STALE?1===++this.dependencyStaleCount&&this.markStale():(c&&(this.dependencyChangeCount+=1),0===--this.dependencyStaleCount&&(this.state=d.PENDING,b.Scheduler.schedule(function(){e.dependencyChangeCount>0?e.computeNextState():e.markReady(!1),e.dependencyChangeCount=0})))},c.prototype.computeNextState=function(){this.trackDependencies();var a=this.owner.compute();this.bindDependencies(),this.markReady(a)},c.prototype.trackDependencies=function(){this.prevObserving=this.observing,c.trackingStack[c.trackingStack.length]=[]},c.prototype.bindDependencies=function(){this.observing=c.trackingStack.pop(),this.isComputed&&0===this.observing.length&&a.debugLevel>1&&!this.isDisposed&&(console.trace(),b.warn("You have created a function that doesn't observe any values, did you forget to make its dependencies observable?"));var d=b.quickDiff(this.observing,this.prevObserving),e=d[0],f=d[1];this.prevObserving=null;for(var g=0,h=f.length;h>g;g++)f[g].removeObserver(this);this.hasCycle=!1;for(var g=0,h=e.length;h>g;g++)this.isComputed&&e[g].findCycle(this)?(this.hasCycle=!0,this.observing.splice(this.observing.indexOf(e[g]),1),e[g].hasCycle=!0):e[g].addObserver(this)},c.prototype.notifyObserved=function(){var a=c.trackingStack,b=a.length;if(b>0){var d=a[b-1],e=d.length;d[e-1]!==this&&d[e-2]!==this&&(d[e]=this)}},c.prototype.findCycle=function(a){var b=this.observing;if(-1!==b.indexOf(a))return!0;for(var c=b.length,d=0;c>d;d++)if(b[d].findCycle(a))return!0;return!1},c.prototype.dispose=function(){if(this.observers.length)throw new Error("Cannot dispose DNode; it is still being observed");if(this.observing)for(var a=this.observing.length,b=0;a>b;b++)this.observing[b].removeObserver(this);this.observing=null,this.isDisposed=!0},c.trackingStack=[],c}();b.DNode=e,b.stackDepth=c}(b=a._||(a._={}))}(mobservable||(mobservable={}));var mobservable;!function(a){function b(a,b){if(e(a))return a;b=b||{},a instanceof m.AsReference&&(a=a.value,b.as="reference");var d=b.recurse!==!1,f="reference"===b.as?l.Reference:c(a);switch(f){case l.Reference:case l.ComplexObject:return m.makeReactiveReference(a,!1);case l.ComplexFunction:throw new Error("[mobservable:error] Creating reactive functions from functions with multiple arguments is currently not supported, see https://github.com/mweststrate/mobservable/issues/12");case l.ViewFunction:return new m.ComputedObservable(a,b.scope).createGetterSetter();case l.Array:return new m.ObservableArray(a,d);case l.PlainObject:return m.extendReactive({},a,d)}throw"Illegal State"}function c(a){return null===a||void 0===a?l.Reference:"function"==typeof a?a.length?l.ComplexFunction:l.ViewFunction:Array.isArray(a)||a instanceof m.ObservableArray?l.Array:"object"==typeof a?m.isPlainObject(a)?l.PlainObject:l.ComplexObject:l.Reference}function d(a){return new m.AsReference(a)}function e(a){if(null===a||void 0===a)return!1;switch(typeof a){case"array":case"object":case"function":return a.__isReactive===!0}return!1}function f(a,b){var c=new m.ComputedObservable(a,b),d=c.observe(m.noop);return 0===c.dependencyState.observing.length&&m.warn("mobservable.sideEffect: not a single observable was used inside the side-effect function. Side-effect would be a no-op."),d}function g(a,b){m.extendReactive(a,b,!0)}function h(a,b,c){var d=c?c.value:null;"function"==typeof d?(delete c.value,delete c.writable,c.configurable=!0,c.get=function(){var a=this.key=new m.ComputedObservable(d,this).createGetterSetter();return a},c.set=function(){throw console.trace(),new Error("It is not allowed to reassign observable functions")}):Object.defineProperty(a,b,{configurable:!0,enumberable:!0,get:function(){return m.defineReactiveProperty(this,b,void 0,!0),this[b]},set:function(a){m.defineReactiveProperty(this,b,a,!0)}})}function i(a){if(!a)return a;if(Array.isArray(a)||a instanceof m.ObservableArray)return a.map(i);if("object"==typeof a){var b={};for(var c in a)a.hasOwnProperty(c)&&(b[c]=i(a[c]));return b}return a}function j(a){return m.Scheduler.batch(a)}function k(a,b){var c=new m.WatchedExpression(a,b);return[c.value,function(){return c.dispose()}]}var l;!function(a){a[a.Reference=0]="Reference",a[a.PlainObject=1]="PlainObject",a[a.ComplexObject=2]="ComplexObject",a[a.Array=3]="Array",a[a.ViewFunction=4]="ViewFunction",a[a.ComplexFunction=5]="ComplexFunction"}(l||(l={})),a.makeReactive=b,a.asReference=d,a.isReactive=e,a.sideEffect=f,a.extendReactive=g,a.observable=h,a.toJson=i,a.transaction=j,a.observeUntilInvalid=k,a.debugLevel=0;var m;!function(a){function b(a,b,c){h(a);for(var e in b)d(a,e,b[e],c);return a}function d(b,d,e,f){var h;e instanceof i?(e=e.value,h=l.Reference,f=!1):h=c(e);var j;switch(h){case l.Reference:case l.ComplexObject:j=g(e,!1);break;case l.ViewFunction:j=new a.ComputedObservable(e,b).createGetterSetter();break;case l.ComplexFunction:a.warn("Storing reactive functions in objects is not supported yet, please use flag 'recurse:false' or wrap the function in 'asReference'"),j=g(e,!1);case l.Array:case l.PlainObject:j=g(e,f)}return Object.defineProperty(b,d,{get:j,set:j,enumerable:!0,configurable:!1}),b}function f(b){if(e(b))return b;if(b instanceof i)return b=b.value;switch(c(b)){case l.Reference:case l.ComplexObject:return b;case l.ViewFunction:case l.ComplexFunction:return a.warn("Storing reactive functions in arrays is not supported, please use flag 'recurse:false' or wrap the function in 'asReference'"),b;case l.Array:return new a.ObservableArray(b,!0);case l.PlainObject:return a.extendReactive({},b,!0)}throw"Illegal State"}function g(b,c){return new a.ObservableValue(b,c).createGetterSetter()}function h(a){Object.defineProperty(a,"__isReactive",{enumerable:!1,value:!0})}a.extendReactive=b,a.defineReactiveProperty=d,a.makeReactiveArrayItem=f,a.makeReactiveReference=g,a.markReactive=h;var i=function(){function a(a){this.value=a}return a}();a.AsReference=i}(m=a._||(a._={}))}(mobservable||(mobservable={}));var mobservable;!function(a){var b;!function(b){function c(a){var b={enumerable:!1,configurable:!1,set:function(b){if(a<this._values.length){var c=this._values[a];c!==b&&(this._values[a]=b,this.notifyChildUpdate(a,c))}else{if(a!==this._values.length)throw new Error("ObservableArray: Index out of bounds, "+a+" is larger than "+this.values.length);this.push(b)}},get:function(){return a<this._values.length?(this.dependencyState.notifyObserved(),this._values[a]):void 0}};Object.defineProperty(f.prototype,""+a,b),b.enumerable=!0,b.configurable=!0,h[a]=b}function d(a){for(var b=g;a>b;b++)c(b);g=a}var e=function(){function a(){}return a}();e.prototype=[];var f=function(c){function e(a,d){c.call(this),b.markReactive(this),Object.defineProperties(this,{recurse:{enumerable:!1,value:d},dependencyState:{enumerable:!1,value:new b.DNode(this)},_values:{enumerable:!1,value:a?d?a.map(b.makeReactiveArrayItem):a.slice():[]},changeEvent:{enumerable:!1,value:new b.SimpleEventEmitter}}),a&&a.length&&this.updateLength(0,a.length)}return __extends(e,c),Object.defineProperty(e.prototype,"length",{get:function(){return this.dependencyState.notifyObserved(),this._values.length},set:function(a){if("number"!=typeof a||0>a)throw new Error("Out of range: "+a);var b=this._values.length;a!==b&&(a>b?this.spliceWithArray(b,0,new Array(a-b)):this.spliceWithArray(a,b-a))},enumerable:!0,configurable:!0}),e.prototype.updateLength=function(a,b){if(0>b)for(var c=a+b;a>c;c++)delete this[c];else if(b>0){a+b>g&&d(a+b);for(var c=a,e=a+b;e>c;c++)Object.defineProperty(this,""+c,h[c])}},e.prototype.spliceWithArray=function(a,c,d){var e=this._values.length;if(!(void 0!==d&&0!==d.length||0!==c&&0!==e))return[];void 0===a?a=0:a>e?a=e:0>a&&(a=Math.max(0,e+a)),c=1===arguments.length?e-a:void 0===c||null===c?0:Math.max(0,Math.min(c,e-a)),void 0===d?d=[]:this.recurse&&(d=d.map(b.makeReactiveArrayItem));var f=d.length-c,g=(h=this._values).splice.apply(h,[a,c].concat(d));return this.updateLength(e,f),this.notifySplice(a,g,d),g;var h},e.prototype.notifyChildUpdate=function(a,b){this.notifyChanged(),this.changeEvent.emit({object:this,type:"update",index:a,oldValue:b})},e.prototype.notifySplice=function(a,b,c){(0!==b.length||0!==c.length)&&(this.notifyChanged(),this.changeEvent.emit({object:this,type:"splice",index:a,addedCount:c.length,removed:b}))},e.prototype.notifyChanged=function(){this.dependencyState.markStale(),this.dependencyState.markReady(!0)},e.prototype.observe=function(a,b){return void 0===b&&(b=!1),b&&a({object:this,type:"splice",index:0,addedCount:this._values.length,removed:[]}),this.changeEvent.on(a)},e.prototype.clear=function(){return this.splice(0)},e.prototype.replace=function(a){return this.spliceWithArray(0,this._values.length,a)},e.prototype.values=function(){return this.dependencyState.notifyObserved(),this._values.slice()},e.prototype.toJSON=function(){return this.dependencyState.notifyObserved(),this._values.slice()},e.prototype.clone=function(){return this.dependencyState.notifyObserved(),new e(this._values,this.recurse)},e.prototype.find=function(a,b,c){void 0===c&&(c=0),this.dependencyState.notifyObserved();for(var d=this._values,e=d.length,f=c;e>f;f++)if(a.call(b,d[f],f,this))return d[f];return null},e.prototype.splice=function(a,b){for(var c=[],d=2;d<arguments.length;d++)c[d-2]=arguments[d];switch(this.sideEffectWarning("splice"),arguments.length){case 0:return[];case 1:return this.spliceWithArray(a);case 2:return this.spliceWithArray(a,b)}return this.spliceWithArray(a,b,c)},e.prototype.push=function(){for(var a=[],b=0;b<arguments.length;b++)a[b-0]=arguments[b];return this.sideEffectWarning("push"),this.spliceWithArray(this._values.length,0,a),this._values.length},e.prototype.pop=function(){return this.sideEffectWarning("pop"),this.splice(Math.max(this._values.length-1,0),1)[0]},e.prototype.shift=function(){return this.sideEffectWarning("shift"),this.splice(0,1)[0]},e.prototype.unshift=function(){for(var a=[],b=0;b<arguments.length;b++)a[b-0]=arguments[b];return this.sideEffectWarning("unshift"),this.spliceWithArray(0,0,a),this._values.length},e.prototype.reverse=function(){return this.sideEffectWarning("reverse"),this.replace(this._values.reverse())},e.prototype.sort=function(a){return this.sideEffectWarning("sort"),this.replace(this._values.sort.apply(this._values,arguments))},e.prototype.remove=function(a){this.sideEffectWarning("remove");var b=this._values.indexOf(a);return b>-1?(this.splice(b,1),!0):!1},e.prototype.toString=function(){return this.wrapReadFunction("toString",arguments)},e.prototype.toLocaleString=function(){return this.wrapReadFunction("toLocaleString",arguments)},e.prototype.concat=function(){return this.wrapReadFunction("concat",arguments)},e.prototype.join=function(a){return this.wrapReadFunction("join",arguments)},e.prototype.slice=function(a,b){return this.wrapReadFunction("slice",arguments)},e.prototype.indexOf=function(a,b){return this.wrapReadFunction("indexOf",arguments)},e.prototype.lastIndexOf=function(a,b){return this.wrapReadFunction("lastIndexOf",arguments)},e.prototype.every=function(a,b){return this.wrapReadFunction("every",arguments)},e.prototype.some=function(a,b){return this.wrapReadFunction("some",arguments)},e.prototype.forEach=function(a,b){return this.wrapReadFunction("forEach",arguments)},e.prototype.map=function(a,b){return this.wrapReadFunction("map",arguments)},e.prototype.filter=function(a,b){return this.wrapReadFunction("filter",arguments)},e.prototype.reduce=function(a,b){return this.wrapReadFunction("reduce",arguments)},e.prototype.reduceRight=function(a,b){return this.wrapReadFunction("reduceRight",arguments)},e.prototype.wrapReadFunction=function(a,b){var c=Array.prototype[a];return(e.prototype[a]=function(){return this.dependencyState.notifyObserved(),c.apply(this._values,arguments)}).apply(this,b)},e.prototype.sideEffectWarning=function(c){a.debugLevel>0&&b.DNode.trackingStack.length>0&&b.warn("[Mobservable.Array] The method array."+c+" should probably not be used inside observable functions since it has side-effects")},e}(e);b.ObservableArray=f;var g=0,h=[];d(1e3)}(b=a._||(a._={}))}(mobservable||(mobservable={}));var mobservable;!function(a){function b(b){var c=b.prototype.componentWillMount,d=b.prototype.componentWillUnmount;return b.prototype.componentWillMount=function(){a.reactiveMixin.componentWillMount.apply(this,arguments),c&&c.apply(this,arguments)},b.prototype.componentWillUnmount=function(){a.reactiveMixin.componentWillUnmount.apply(this,arguments),d&&d.apply(this,arguments)},b.prototype.shouldComponentUpdate||(b.prototype.shouldComponentUpdate=a.reactiveMixin.shouldComponentUpdate),b}a.reactiveMixin={componentWillMount:function(){var b=this.render;this.render=function(){var c=this;this._watchDisposer&&this._watchDisposer();var d=a.observeUntilInvalid(function(){return b.call(c)},function(){c.forceUpdate()}),e=d[0],f=d[1];return this._watchDisposer=f,e}},componentWillUnmount:function(){this._watchDisposer&&this._watchDisposer()},shouldComponentUpdate:function(a,b){if(this.state!==b)return!0;var c,d=Object.keys(this.props);if(d.length!==Object.keys(a).length)return!0;for(var e=d.length-1;c=d[e];e--)if(a[c]!==this.props[c])return!0;return!1}},a.reactiveComponent=b}(mobservable||(mobservable={}));var mobservable;!function(a){var b;!function(a){var b=function(){function a(){}return a.schedule=function(b){a.inBatch<1?b():a.tasks[a.tasks.length]=b},a.runPostBatchActions=function(){for(var b=0;a.tasks.length;)try{for(;b<a.tasks.length;b++)a.tasks[b]();a.tasks=[]}catch(c){console.error("Failed to run scheduled action, the action has been dropped from the queue: "+c,c),a.tasks.splice(0,b+1)}},a.batch=function(b){a.inBatch+=1;try{return b()}finally{0===--a.inBatch&&(a.inBatch+=1,a.runPostBatchActions(),a.inBatch-=1)}},a.inBatch=0,a.tasks=[],a}();a.Scheduler=b}(b=a._||(a._={}))}(mobservable||(mobservable={}));var mobservable;!function(a){var b;!function(a){var b=function(){function b(){this.listeners=[]}return b.prototype.emit=function(){var a=this.listeners.slice(),b=a.length;switch(arguments.length){case 0:for(var c=0;b>c;c++)a[c]();break;case 1:for(var d=arguments[0],c=0;b>c;c++)a[c](d);break;default:for(var c=0;b>c;c++)a[c].apply(null,arguments)}},b.prototype.on=function(b){var c=this;return this.listeners.push(b),a.once(function(){var a=c.listeners.indexOf(b);-1!==a&&c.listeners.splice(a,1)})},b.prototype.once=function(a){var b=this.on(function(){b(),a.apply(this,arguments)});return b},b}();a.SimpleEventEmitter=b}(b=a._||(a._={}))}(mobservable||(mobservable={}));var mobservable;!function(a){var b;!function(a){function b(a){console&&console.warn("[mobservable:warning] "+a)}function c(a){var b=!1;return function(){return b?void 0:(b=!0,a.apply(this,arguments))}}function d(){}function e(a){return null!==a&&"object"==typeof a&&Object.getPrototypeOf(a)===Object.prototype}function f(a,b){if(!b||!b.length)return[a,[]];if(!a||!a.length)return[[],b];for(var c=[],d=[],e=0,f=0,g=a.length,h=!1,i=0,j=0,k=b.length,l=!1,m=!1;!m&&!h;){if(!l){if(g>e&&k>i&&a[e]===b[i]){if(e++,i++,e===g&&i===k)return[c,d];continue}f=e,j=i,l=!0}j+=1,f+=1,j>=k&&(m=!0),f>=g&&(h=!0),h||a[f]!==b[i]?m||b[j]!==a[e]||(d.push.apply(d,b.slice(i,j)),i=j+1,e++,l=!1):(c.push.apply(c,a.slice(e,f)),e=f+1,i++,l=!1)}return c.push.apply(c,a.slice(e)),d.push.apply(d,b.slice(i)),[c,d]}a.warn=b,a.once=c,a.noop=d,a.isPlainObject=e,a.quickDiff=f}(b=a._||(a._={}))}(mobservable||(mobservable={}));var mobservable;!function(a){var b;!function(a){var b=function(){function b(b,c){this.expr=b,this.onInvalidate=c,this.dependencyState=new a.DNode(this),this.didEvaluate=!1,this.dependencyState.computeNextState()}return b.prototype.compute=function(){return this.didEvaluate?(this.dispose(),this.onInvalidate()):(this.didEvaluate=!0,this.value=this.expr()),!1},b.prototype.dispose=function(){this.dependencyState.dispose()},b}();a.WatchedExpression=b}(b=a._||(a._={}))}(mobservable||(mobservable={}));var forCompilerVerificationOnly=mobservable;!function(a,b){"function"==typeof define&&define.amd?define("mobservable",[],function(){return b()}):"object"==typeof exports?module.exports=b():a.mobservable=b()}(this,function(){var a=mobservable.makeReactive;for(var b in mobservable)a[b]=mobservable[b];return a}); | ||
var __extends=this&&this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},mobservable;!function(a){var b;!function(b){function c(){return f.trackingStack.length}var d=0;!function(a){a[a.STALE=0]="STALE",a[a.PENDING=1]="PENDING",a[a.READY=2]="READY"}(b.DNodeState||(b.DNodeState={}));var e=b.DNodeState,f=function(){function a(a){this.context=a,this.id=++d,this.state=e.READY,this.observers=[],this.isDisposed=!1,this.externalRefenceCount=0,a.name||(a.name="[m#"+this.id+"]")}return a.prototype.setRefCount=function(a){this.externalRefenceCount+=a},a.prototype.addObserver=function(a){this.observers[this.observers.length]=a},a.prototype.removeObserver=function(a){var b=this.observers,c=b.indexOf(a);-1!==c&&b.splice(c,1)},a.prototype.markStale=function(){this.state===e.READY&&(this.state=e.STALE,b.transitionTracker&&b.reportTransition(this,"STALE"),this.notifyObservers())},a.prototype.markReady=function(a){this.state!==e.READY&&(this.state=e.READY,b.transitionTracker&&b.reportTransition(this,"READY",!0,this._value),this.notifyObservers(a))},a.prototype.notifyObservers=function(a){void 0===a&&(a=!1);for(var b=this.observers.slice(),c=b.length,d=0;c>d;d++)b[d].notifyStateChange(this,a)},a.prototype.notifyObserved=function(){var b=a.trackingStack,c=b.length;if(c>0){var d=b[c-1],e=d.length;d[e-1]!==this&&d[e-2]!==this&&(d[e]=this)}},a.prototype.dispose=function(){if(this.observers.length)throw new Error("Cannot dispose DNode; it is still being observed");this.isDisposed=!0},a.prototype.toString=function(){return"DNode["+this.context.name+", state: "+this.state+", observers: "+this.observers.length+"]"},a.trackingStack=[],a}();b.RootDNode=f;var g=function(c){function d(){c.apply(this,arguments),this.isSleeping=!0,this.hasCycle=!1,this.observing=[],this.prevObserving=null,this.dependencyChangeCount=0,this.dependencyStaleCount=0}return __extends(d,c),d.prototype.setRefCount=function(a){var b=this.externalRefenceCount+=a;0===b?this.tryToSleep():b===a&&this.wakeUp()},d.prototype.removeObserver=function(a){c.prototype.removeObserver.call(this,a),this.tryToSleep()},d.prototype.tryToSleep=function(){if(!this.isSleeping&&0===this.observers.length&&0===this.externalRefenceCount){for(var a=0,b=this.observing.length;b>a;a++)this.observing[a].removeObserver(this);this.observing=[],this.isSleeping=!0}},d.prototype.wakeUp=function(){this.isSleeping&&(this.isSleeping=!1,this.state=e.PENDING,this.computeNextState())},d.prototype.notifyStateChange=function(a,c){var d=this;a.state===e.STALE?1===++this.dependencyStaleCount&&this.markStale():(c&&(this.dependencyChangeCount+=1),0===--this.dependencyStaleCount&&(this.state=e.PENDING,b.Scheduler.schedule(function(){d.dependencyChangeCount>0?d.computeNextState():d.markReady(!1),d.dependencyChangeCount=0})))},d.prototype.computeNextState=function(){this.trackDependencies(),b.transitionTracker&&b.reportTransition(this,"PENDING");var a=this.compute();this.bindDependencies(),this.markReady(a)},d.prototype.compute=function(){throw"Abstract!"},d.prototype.trackDependencies=function(){this.prevObserving=this.observing,f.trackingStack[f.trackingStack.length]=[]},d.prototype.bindDependencies=function(){this.observing=f.trackingStack.pop(),0===this.observing.length&&a.debugLevel>1&&!this.isDisposed&&(console.trace(),b.warn("You have created a function that doesn't observe any values, did you forget to make its dependencies observable?"));var c=b.quickDiff(this.observing,this.prevObserving),e=c[0],g=c[1];this.prevObserving=null;for(var h=0,i=g.length;i>h;h++)g[h].removeObserver(this);this.hasCycle=!1;for(var h=0,i=e.length;i>h;h++){var j=e[h];j instanceof d&&j.findCycle(this)?(this.hasCycle=!0,this.observing.splice(this.observing.indexOf(e[h]),1),j.hasCycle=!0):e[h].addObserver(this)}},d.prototype.findCycle=function(a){var b=this.observing;if(-1!==b.indexOf(a))return!0;for(var c=b.length,e=0;c>e;e++)if(b[e]instanceof d&&b[e].findCycle(a))return!0;return!1},d.prototype.dispose=function(){if(this.observing)for(var a=this.observing.length,b=0;a>b;b++)this.observing[b].removeObserver(this);this.observing=null,c.prototype.dispose.call(this)},d}(f);b.ObservingDNode=g,b.stackDepth=c}(b=a._||(a._={}))}(mobservable||(mobservable={}));var mobservable;!function(a){function b(a,b){if(d(a))return a;b=b||{},a instanceof k.AsReference&&(a=a.value,b.as="reference");var c=b.recurse!==!1,e="reference"===b.as?k.ValueType.Reference:k.getTypeOfValue(a),f={name:b.name,object:b.context||b.scope};switch(e){case k.ValueType.Reference:case k.ValueType.ComplexObject:return k.toGetterSetterFunction(new k.ObservableValue(a,!1,f));case k.ValueType.ComplexFunction:throw new Error("[mobservable:error] Creating reactive functions from functions with multiple arguments is currently not supported, see https://github.com/mweststrate/mobservable/issues/12");case k.ValueType.ViewFunction:return f.name||(f.name=a.name),k.toGetterSetterFunction(new k.ObservableView(a,b.scope||b.context,f));case k.ValueType.Array:return new k.ObservableArray(a,c,f);case k.ValueType.PlainObject:return k.extendReactive({},a,c,f)}throw"Illegal State"}function c(a){return new k.AsReference(a)}function d(a){return null===a||void 0===a?!1:!!a.$mobservable}function e(a,b){b=b||{};var c=new k.ObservableView(a,b.scope||b.context,{object:b.context||b.scope,name:b.name||a.name}),d=c.observe(k.noop);return 0===c.observing.length&&k.warn("mobservable.sideEffect: not a single observable was used inside the side-effect function. Side-effect would be a no-op."),d.$mobservable=c,d}function f(a,b,c){k.extendReactive(a,b,!0,c)}function g(a,b,c){var d=c?c.value:null;if("function"==typeof d)throw new Error("@observable functions are deprecated. Use @observable (getter) properties instead");if(c&&c.set)throw new Error("@observable properties cannot have a setter.");Object.defineProperty(a,b,{configurable:!0,enumberable:!0,get:function(){return k.ObservableObject.asReactive(this,null).set(b,void 0,!0),this[b]},set:function(a){k.ObservableObject.asReactive(this,null).set(b,a,!0)}})}function h(a){if(!a)return a;if(Array.isArray(a)||a instanceof k.ObservableArray)return a.map(h);if("object"==typeof a){var b={};for(var c in a)a.hasOwnProperty(c)&&(b[c]=h(a[c]));return b}return a}function i(a){return k.Scheduler.batch(a)}function j(a,b,c){var d=new k.WatchedExpression(a,b,c||a.name);return[d.value,function(){return d.dispose()},d]}a.makeReactive=b,a.asReference=c,a.isReactive=d,a.sideEffect=e,a.extendReactive=f,a.observable=g,a.toJson=h,a.transaction=i,a.observeUntilInvalid=j,a.debugLevel=0;var k;!function(a){function b(b){return null===b||void 0===b?e.Reference:"function"==typeof b?b.length?e.ComplexFunction:e.ViewFunction:Array.isArray(b)||b instanceof a.ObservableArray?e.Array:"object"==typeof b?a.isPlainObject(b)?e.PlainObject:e.ComplexObject:e.Reference}function c(b,c,d,e){var f=a.ObservableObject.asReactive(b,e);for(var g in c)c.hasOwnProperty(g)&&f.set(g,c[g],d);return b}function d(a){var b=function(b){return arguments.length>0?void a.set(b):a.get()};return b.$mobservable=a,b.observe=function(b,c){return a.observe(b,c)},b.toString=function(){return a.toString()},b}!function(a){a[a.Reference=0]="Reference",a[a.PlainObject=1]="PlainObject",a[a.ComplexObject=2]="ComplexObject",a[a.Array=3]="Array",a[a.ViewFunction=4]="ViewFunction",a[a.ComplexFunction=5]="ComplexFunction"}(a.ValueType||(a.ValueType={}));var e=a.ValueType;a.getTypeOfValue=b,a.extendReactive=c,a.toGetterSetterFunction=d;var f=function(){function a(a){this.value=a}return a}();a.AsReference=f}(k=a._||(a._={}))}(mobservable||(mobservable={}));var mobservable;!function(a){var b;!function(a){function b(a){console&&console.warn("[mobservable:warning] "+a)}function c(a){var b=!1;return function(){return b?void 0:(b=!0,a.apply(this,arguments))}}function d(){}function e(a){var b=[];return a.forEach(function(a){-1===b.indexOf(a)&&b.push(a)}),b}function f(a){return null!==a&&"object"==typeof a&&Object.getPrototypeOf(a)===Object.prototype}function g(a,b){if(!b||!b.length)return[a,[]];if(!a||!a.length)return[[],b];for(var c=[],d=[],e=0,f=0,g=a.length,h=!1,i=0,j=0,k=b.length,l=!1,m=!1;!m&&!h;){if(!l){if(g>e&&k>i&&a[e]===b[i]){if(e++,i++,e===g&&i===k)return[c,d];continue}f=e,j=i,l=!0}j+=1,f+=1,j>=k&&(m=!0),f>=g&&(h=!0),h||a[f]!==b[i]?m||b[j]!==a[e]||(d.push.apply(d,b.slice(i,j)),i=j+1,e++,l=!1):(c.push.apply(c,a.slice(e,f)),e=f+1,i++,l=!1)}return c.push.apply(c,a.slice(e)),d.push.apply(d,b.slice(i)),[c,d]}a.warn=b,a.once=c,a.noop=d,a.unique=e,a.isPlainObject=f,a.quickDiff=g}(b=a._||(a._={}))}(mobservable||(mobservable={}));var mobservable;!function(a){var b;!function(b){function c(a){var b={enumerable:!1,configurable:!1,set:function(b){if(a<this.$mobservable.values.length){var c=this.$mobservable.values[a];c!==b&&(this.$mobservable.values[a]=b,this.notifyChildUpdate(a,c))}else{if(a!==this.$mobservable.values.length)throw new Error("ObservableArray: Index out of bounds, "+a+" is larger than "+this.values.length);this.push(b)}},get:function(){return a<this.$mobservable.values.length?(this.$mobservable.notifyObserved(),this.$mobservable.values[a]):void 0}};Object.defineProperty(g.prototype,""+a,b),b.enumerable=!0,b.configurable=!0,i[a]=b}function d(a){for(var b=h;a>b;b++)c(b);h=a}var e=function(){function a(){}return a}();e.prototype=[];var f=function(a){function c(c,d,e){a.call(this,e),this.array=c,this.recurse=d,this.values=[],this.changeEvent=new b.SimpleEventEmitter,e.object||(e.object=c)}return __extends(c,a),c}(b.RootDNode);b.ObservableArrayAdministration=f;var g=function(c){function e(a,b,d){c.call(this),Object.defineProperty(this,"$mobservable",{enumerable:!1,configurable:!1,value:new f(this,b,d)}),a&&a.length&&this.replace(a)}return __extends(e,c),Object.defineProperty(e.prototype,"length",{get:function(){return this.$mobservable.notifyObserved(),this.$mobservable.values.length},set:function(a){if("number"!=typeof a||0>a)throw new Error("Out of range: "+a);var b=this.$mobservable.values.length;a!==b&&(a>b?this.spliceWithArray(b,0,new Array(a-b)):this.spliceWithArray(a,b-a))},enumerable:!0,configurable:!0}),e.prototype.updateLength=function(a,b){if(0>b)for(var c=a+b;a>c;c++)delete this[c];else if(b>0){a+b>h&&d(a+b);for(var c=a,e=a+b;e>c;c++)Object.defineProperty(this,""+c,i[c])}},e.prototype.spliceWithArray=function(a,b,c){var d=this,e=this.$mobservable.values.length;if(!(void 0!==c&&0!==c.length||0!==b&&0!==e))return[];void 0===a?a=0:a>e?a=e:0>a&&(a=Math.max(0,e+a)),b=1===arguments.length?e-a:void 0===b||null===b?0:Math.max(0,Math.min(b,e-a)),void 0===c?c=[]:this.$mobservable.recurse&&(c=c.map(function(a){return d.makeReactiveArrayItem(a)}));var f=c.length-b,g=(h=this.$mobservable.values).splice.apply(h,[a,b].concat(c));return this.updateLength(e,f),this.notifySplice(a,g,c),g;var h},e.prototype.makeReactiveArrayItem=function(c){if(a.isReactive(c))return c;if(c instanceof b.AsReference)return c=c.value;var d={object:this.$mobservable.context.object,name:this.$mobservable.context.name+"[x]"};return Array.isArray(c)?new b.ObservableArray(c,!0,d):b.isPlainObject(c)?b.extendReactive({},c,!0,d):c},e.prototype.notifyChildUpdate=function(a,b){this.notifyChanged(),this.$mobservable.changeEvent.emit({object:this,type:"update",index:a,oldValue:b})},e.prototype.notifySplice=function(a,b,c){(0!==b.length||0!==c.length)&&(this.notifyChanged(),this.$mobservable.changeEvent.emit({object:this,type:"splice",index:a,addedCount:c.length,removed:b}))},e.prototype.notifyChanged=function(){this.$mobservable.markStale(),this.$mobservable.markReady(!0)},e.prototype.observe=function(a,b){return void 0===b&&(b=!1),b&&a({object:this,type:"splice",index:0,addedCount:this.$mobservable.values.length,removed:[]}),this.$mobservable.changeEvent.on(a)},e.prototype.clear=function(){return this.splice(0)},e.prototype.replace=function(a){return this.spliceWithArray(0,this.$mobservable.values.length,a)},e.prototype.values=function(){return this.$mobservable.notifyObserved(),this.$mobservable.values.slice()},e.prototype.toJSON=function(){return this.$mobservable.notifyObserved(),this.$mobservable.values.slice()},e.prototype.clone=function(){return this.$mobservable.notifyObserved(),new e(this.$mobservable.values,this.$mobservable.recurse,{object:null,name:this.$mobservable.context.name+"[clone]"})},e.prototype.find=function(a,b,c){void 0===c&&(c=0),this.$mobservable.notifyObserved();for(var d=this.$mobservable.values,e=d.length,f=c;e>f;f++)if(a.call(b,d[f],f,this))return d[f];return null},e.prototype.splice=function(a,b){for(var c=[],d=2;d<arguments.length;d++)c[d-2]=arguments[d];switch(this.sideEffectWarning("splice"),arguments.length){case 0:return[];case 1:return this.spliceWithArray(a);case 2:return this.spliceWithArray(a,b)}return this.spliceWithArray(a,b,c)},e.prototype.push=function(){for(var a=[],b=0;b<arguments.length;b++)a[b-0]=arguments[b];return this.sideEffectWarning("push"),this.spliceWithArray(this.$mobservable.values.length,0,a),this.$mobservable.values.length},e.prototype.pop=function(){return this.sideEffectWarning("pop"),this.splice(Math.max(this.$mobservable.values.length-1,0),1)[0]},e.prototype.shift=function(){return this.sideEffectWarning("shift"),this.splice(0,1)[0]},e.prototype.unshift=function(){for(var a=[],b=0;b<arguments.length;b++)a[b-0]=arguments[b];return this.sideEffectWarning("unshift"),this.spliceWithArray(0,0,a),this.$mobservable.values.length},e.prototype.reverse=function(){return this.sideEffectWarning("reverse"),this.replace(this.$mobservable.values.reverse())},e.prototype.sort=function(a){return this.sideEffectWarning("sort"),this.replace(this.$mobservable.values.sort.apply(this.$mobservable.values,arguments))},e.prototype.remove=function(a){this.sideEffectWarning("remove");var b=this.$mobservable.values.indexOf(a);return b>-1?(this.splice(b,1),!0):!1},e.prototype.toString=function(){return this.wrapReadFunction("toString",arguments)},e.prototype.toLocaleString=function(){return this.wrapReadFunction("toLocaleString",arguments)},e.prototype.concat=function(){return this.wrapReadFunction("concat",arguments)},e.prototype.join=function(a){return this.wrapReadFunction("join",arguments)},e.prototype.slice=function(a,b){return this.wrapReadFunction("slice",arguments)},e.prototype.indexOf=function(a,b){return this.wrapReadFunction("indexOf",arguments)},e.prototype.lastIndexOf=function(a,b){return this.wrapReadFunction("lastIndexOf",arguments)},e.prototype.every=function(a,b){return this.wrapReadFunction("every",arguments)},e.prototype.some=function(a,b){return this.wrapReadFunction("some",arguments)},e.prototype.forEach=function(a,b){return this.wrapReadFunction("forEach",arguments)},e.prototype.map=function(a,b){return this.wrapReadFunction("map",arguments)},e.prototype.filter=function(a,b){return this.wrapReadFunction("filter",arguments)},e.prototype.reduce=function(a,b){return this.wrapReadFunction("reduce",arguments)},e.prototype.reduceRight=function(a,b){return this.wrapReadFunction("reduceRight",arguments)},e.prototype.wrapReadFunction=function(a,b){var c=Array.prototype[a];return(e.prototype[a]=function(){return this.$mobservable.notifyObserved(),c.apply(this.$mobservable.values,arguments)}).apply(this,b)},e.prototype.sideEffectWarning=function(c){a.debugLevel>0&&b.RootDNode.trackingStack.length>0&&b.warn("[Mobservable.Array] The method array."+c+" should probably not be used inside observable functions since it has side-effects")},e}(e);b.ObservableArray=g;var h=0,i=[];d(1e3)}(b=a._||(a._={}))}(mobservable||(mobservable={}));var mobservable;!function(a){var b;!function(b){function c(c,d){if(!a.isReactive(c))throw new Error("[mobservable.getDNode] "+c+" doesn't seem to be reactive");if(void 0!==d){b.RootDNode.trackingStack.push([]),c[d];var e=b.RootDNode.trackingStack.pop()[0];if(!e)throw new Error("[mobservable.getDNode] property '"+d+"' of '"+c+"' doesn't seem to be a reactive property");return e}if(c.$mobservable){if(c.$mobservable instanceof b.ObservableObject)throw new Error("[mobservable.getDNode] missing properties parameter. Please specify a property of '"+c+"'.");return c.$mobservable}throw new Error("[mobservable.getDNode] "+c+" doesn't seem to be reactive")}function d(a,c,d,e){void 0===d&&(d=!1),void 0===e&&(e=null),b.transitionTracker.emit({id:a.id,name:a.context.name,context:a.context.object,state:c,changed:d,newValue:e})}b.getDNode=c,b.reportTransition=d,b.transitionTracker=null}(b=a._||(a._={}));var c;!function(a){function c(a,c){return d(b.getDNode(a,c))}function d(a){var c={id:a.id,name:a.context.name,context:a.context.object||null};return a instanceof b.ObservingDNode&&a.observing.length&&(c.dependencies=b.unique(a.observing).map(d)),c}function e(a,c){return f(b.getDNode(a,c))}function f(a){var c={id:a.id,name:a.context.name,context:a.context.object||null};return a.observers.length&&(c.observers=b.unique(a.observers).map(f)),a.externalRefenceCount>0&&(c.listeners=a.externalRefenceCount),c}function g(a){var b=[],c=!1;return function(d){(a||d.changed)&&b.push(d),c||(c=!0,setTimeout(function(){console[console.table?"table":"dir"](b),b=[],c=!1},1))}}function h(a,c){void 0===a&&(a=!1),b.transitionTracker||(b.transitionTracker=new b.SimpleEventEmitter);var d=c?function(b){(a||b.changed)&&c(b)}:g(a),e=b.transitionTracker.on(d);return b.once(function(){e(),0===b.transitionTracker.listeners.length&&(b.transitionTracker=null)})}a.getDependencyTree=c,a.getObserverTree=e,a.trackTransitions=h}(c=a.extras||(a.extras={}))}(mobservable||(mobservable={}));var mobservable;!function(a){var b;!function(b){var c=function(c){function d(a,d,e){c.call(this,e),this.value=a,this.recurse=d,this.changeEvent=new b.SimpleEventEmitter,this._value=this.makeReferenceValueReactive(a)}return __extends(d,c),d.prototype.makeReferenceValueReactive=function(c){return this.recurse&&(Array.isArray(c)||b.isPlainObject(c))?a.makeReactive(c,{context:this.context.object,name:this.context.name}):c},d.prototype.set=function(a){if(a!==this._value){var b=this._value;this.markStale(),this._value=this.makeReferenceValueReactive(a),this.markReady(!0),this.changeEvent.emit(this._value,b)}},d.prototype.get=function(){return this.notifyObserved(),this._value},d.prototype.observe=function(a,b){return void 0===b&&(b=!1),b&&a(this.get(),void 0),this.changeEvent.on(a)},d.prototype.asPropertyDescriptor=function(){var a=this;return{configurable:!1,enumerable:!0,get:function(){return a.get()},set:function(b){return a.set(b)}}},d.prototype.toString=function(){return"Observable["+this.context.name+":"+this._value+"]"},d}(b.RootDNode);b.ObservableValue=c}(b=a._||(a._={}))}(mobservable||(mobservable={}));var mobservable;!function(a){var b;!function(b){function c(){throw new Error("View functions do not accept new values")}var d=function(d){function e(a,c,e){d.call(this,e),this.func=a,this.scope=c,this.isComputing=!1,this.hasError=!1,this.changeEvent=new b.SimpleEventEmitter}return __extends(e,d),e.prototype.get=function(){if(this.isComputing)throw new Error("Cycle detected");if(this.isSleeping?b.RootDNode.trackingStack.length>0?(this.wakeUp(),this.notifyObserved()):this.compute():this.notifyObserved(),this.hasCycle)throw new Error("Cycle detected");if(this.hasError)throw a.debugLevel&&(console.trace(),b.warn(this+": rethrowing caught exception to observer: "+this._value+(this._value.cause||""))),this._value;return this._value},e.prototype.set=function(){c()},e.prototype.compute=function(){var a;try{if(this.isComputing)throw new Error("Cycle detected");this.isComputing=!0,a=this.func.call(this.scope),this.hasError=!1}catch(b){this.hasError=!0,console.error(this+"Caught error during computation: ",b),b instanceof Error?a=b:(a=new Error("MobservableComputationError"),a.cause=b)}if(this.isComputing=!1,a!==this._value){var c=this._value;return this._value=a,this.changeEvent.emit(a,c),!0}return!1},e.prototype.observe=function(a,c){var d=this;void 0===c&&(c=!1),this.setRefCount(1),c&&a(this.get(),void 0);var e=this.changeEvent.on(a);return b.once(function(){d.setRefCount(-1),e()})},e.prototype.asPropertyDescriptor=function(){var a=this;return{configurable:!1,enumerable:!1,get:function(){return a.get()},set:c}},e.prototype.toString=function(){return"ComputedObservable["+this.context.name+":"+this._value+"]"},e}(b.ObservingDNode);b.ObservableView=d}(b=a._||(a._={}))}(mobservable||(mobservable={}));var mobservable;!function(a){var b;!function(a){var b=function(){function b(b,c){if(this.target=b,this.context=c,b.$mobservable)throw new Error("Illegal state: already an reactive object");c?c.object||(c.object=b):this.context={object:b,name:""},this.keys=new a.ObservableArray([],!1,{object:b,name:this.context.name+"[keys]"}),Object.defineProperty(b,"$mobservable",{enumerable:!1,configurable:!1,value:this})}return b.asReactive=function(a,c){return a.$mobservable?a.$mobservable:new b(a,c)},b.prototype.set=function(a,b,c){-1===this.keys.indexOf(a)?this.defineReactiveProperty(a,b,c):this.target[a]=b},b.prototype.defineReactiveProperty=function(b,c,d){c instanceof a.AsReference&&(c=c.value,d=!1);var e,f={object:this.context.object,name:(this.context.name||"")+"."+b};e="function"==typeof c&&0===c.length&&d?new a.ObservableView(c,this.target,f).asPropertyDescriptor():new a.ObservableValue(c,d,f).asPropertyDescriptor(),Object.defineProperty(this.target,b,e)},b}();a.ObservableObject=b}(b=a._||(a._={}))}(mobservable||(mobservable={}));var mobservable;!function(a){function b(b){var c=b.prototype||b,d=c.componentWillMount,e=c.componentWillUnmount;return c.componentWillMount=function(){a.reactiveMixin.componentWillMount.apply(this,arguments),d&&d.apply(this,arguments)},c.componentWillUnmount=function(){a.reactiveMixin.componentWillUnmount.apply(this,arguments),e&&e.apply(this,arguments)},c.shouldComponentUpdate||(c.shouldComponentUpdate=a.reactiveMixin.shouldComponentUpdate),b}var c=1;a.reactiveMixin={componentWillMount:function(){var b=(this.displayName||this.constructor.name||"ReactiveComponent")+c++,d=this.render;this.render=function(){var c=this;this._watchDisposer&&this._watchDisposer();var e=a.observeUntilInvalid(function(){return d.call(c)},function(){c.forceUpdate()},{object:this,name:b}),f=e[0],g=e[1],h=e[2];return this.$mobservable=h,this._watchDisposer=g,f}},componentWillUnmount:function(){this._watchDisposer&&this._watchDisposer(),delete this._mobservableDNode},shouldComponentUpdate:function(a,b){if(this.state!==b)return!0;var c,d=Object.keys(this.props);if(d.length!==Object.keys(a).length)return!0;for(var e=d.length-1;c=d[e];e--)if(a[c]!==this.props[c])return!0;return!1}},a.reactiveComponent=b}(mobservable||(mobservable={}));var mobservable;!function(a){var b;!function(a){var b=function(){function a(){}return a.schedule=function(b){a.inBatch<1?b():a.tasks[a.tasks.length]=b},a.runPostBatchActions=function(){for(var b=0;a.tasks.length;)try{for(;b<a.tasks.length;b++)a.tasks[b]();a.tasks=[]}catch(c){console.error("Failed to run scheduled action, the action has been dropped from the queue: "+c,c),a.tasks.splice(0,b+1)}},a.batch=function(b){a.inBatch+=1;try{return b()}finally{0===--a.inBatch&&(a.inBatch+=1,a.runPostBatchActions(),a.inBatch-=1)}},a.inBatch=0,a.tasks=[],a}();a.Scheduler=b}(b=a._||(a._={}))}(mobservable||(mobservable={}));var mobservable;!function(a){var b;!function(a){var b=function(){function b(){this.listeners=[]}return b.prototype.emit=function(){var a=this.listeners.slice(),b=a.length;switch(arguments.length){case 0:for(var c=0;b>c;c++)a[c]();break;case 1:for(var d=arguments[0],c=0;b>c;c++)a[c](d);break;default:for(var c=0;b>c;c++)a[c].apply(null,arguments)}},b.prototype.on=function(b){var c=this;return this.listeners.push(b),a.once(function(){var a=c.listeners.indexOf(b);-1!==a&&c.listeners.splice(a,1)})},b.prototype.once=function(a){var b=this.on(function(){b(),a.apply(this,arguments)});return b},b}();a.SimpleEventEmitter=b}(b=a._||(a._={}))}(mobservable||(mobservable={}));var mobservable;!function(a){var b;!function(a){var b=function(a){function b(b,c,d){a.call(this,d),this.expr=b,this.onInvalidate=c,this.didEvaluate=!1,this.computeNextState()}return __extends(b,a),b.prototype.compute=function(){return this.didEvaluate?(this.dispose(),this.onInvalidate()):(this.didEvaluate=!0,this.value=this.expr()),!1},b}(a.ObservingDNode);a.WatchedExpression=b}(b=a._||(a._={}))}(mobservable||(mobservable={}));var forCompilerVerificationOnly=mobservable;!function(a,b){"function"==typeof define&&define.amd?define("mobservable",[],function(){return b()}):"object"==typeof exports?module.exports=b():a.mobservable=b()}(this,function(){var a=mobservable.makeReactive;a["default"]=mobservable.makeReactive;for(var b in mobservable)mobservable.hasOwnProperty(b)&&(a[b]=mobservable[b]);return a}); |
@@ -151,2 +151,4 @@ # API Documentation | ||
* `recurse` defaults `true`. If `false`, `makeActive` will not recurse into any child values. | ||
* `name`: can be set to assign a name to this observable, used by the developers tools in the `extras` namespaces. | ||
* `context` can be set to specify a certain context which is reported by the developers tools defined in the `extras`namespaces. Defaults to the object which caused this value to become reactive. | ||
@@ -186,3 +188,2 @@ More flags will be made available in the feature. | ||
Decorator (or annotation) that can be used on ES6 or TypeScript properties to make them reactive. | ||
It can be used on functions as well if they should be reactive, but for type consistency it is recommended to use a getter function in such cases. | ||
@@ -309,2 +310,4 @@ Note that in ES6 the annotation can only be used on getter functions, as ES6 doesn't support property initializers in class declarations. | ||
Since in practice you will see that most reactive components become stateless, they can easily be hot-reloaded. | ||
_Note: when `reactiveComponent` needs to be combined with other decorators or higher-order-components, make sure that `reactiveComponent` is the most inner (first applied) decorator; | ||
@@ -383,1 +386,55 @@ otherwise it might do nothing at all._ | ||
``` | ||
### extras.getDependencyTree(thing, property?) | ||
Accepts something reactive and prints its current dependency tree; other reactive values it depends on. For sideEffects, this method can be invoked on its disposer. | ||
Works for React components as well, but only if they are actually mounted (otherwise they won't be observing any data). | ||
For object properties, pass in the property name as second argument. `id` is unique and generated by mobservable. | ||
`name` and `context` are determined automatically, unless they were overriden in the options passed to `makeReactive`. | ||
The returned dependency tree is a recursive structure with the following signature: | ||
```javascript | ||
interface IDependencyTree { | ||
id: number; | ||
name: string; | ||
context: any; | ||
dependencies?: IDependencyTree[]; | ||
} | ||
``` | ||
### extras.getObserverTree(thing, property?) | ||
Similar to `getDependencyTree`, but observer tree returns a tree of all objects that are depending on `thing`. It returns a tree structure with the following structure: | ||
```javascript | ||
interface IObserverTree { | ||
id: number; | ||
name: string; | ||
context: any; | ||
observers?: IObserverTree[]; | ||
listeners?: number; | ||
} | ||
``` | ||
`listeners` defines the amount of external observers, attached by using `.observe` of some reactive value. Side-effects will always report 1 listener. | ||
### extras.trackTransitions(extensive, onReport) | ||
Debugging tool that reports each change in a reactive value. | ||
The optional `extensive` boolean indicates whether all control events should be reported, or only the events that changes a value. Defaults to `false`. | ||
The `onReport` function is a callback that will be invoked for each transition. If omitted, the reports will be printed to the console. | ||
`trackTransitions` returns a function that can be used to stop the tracker. | ||
Each transition is reported as an object with the following signature. The `state` value is either `STALE`, `PENDING` or `READY`. | ||
```javascript | ||
interface ITransitionEvent { | ||
id: number; | ||
name: string; | ||
context: Object; | ||
state: string; | ||
changed: boolean; | ||
newValue: string; | ||
} | ||
``` |
Coming soon. | ||
Developer tools | ||
Async stuff | ||
State recording and hydration | ||
Developer tools | ||
Dependency tree printing | ||
Faq: how does it keep my memory sane? why are there so few subscription cleanups | ||
performance |
{ | ||
"name": "mobservable", | ||
"version": "0.6.1", | ||
"version": "0.6.2", | ||
"description": "Keeps views automatically in sync with state. Unobtrusively.", | ||
@@ -5,0 +5,0 @@ "main": "dist/mobservable.js", |
@@ -5,3 +5,2 @@ # mobservable | ||
##### _Keeps views automatically in sync with state. Unobtrusively._ | ||
@@ -13,8 +12,5 @@ | ||
<br/> | ||
### New to Mobservable? Take the [five minute, interactive introduction](https://mweststrate.github.io/mobservable/getting-started.html) | ||
##### <center>A [Five minute, interactive introduction](https://mweststrate.github.io/mobservable/getting-started.html) to Mobservable and React</center> | ||
[API documentation](https://github.com/mweststrate/mobservable/blob/master/docs/api.md) - [Tips & Tricks](https://github.com/mweststrate/mobservable/blob/master/docs/syntax.md) - [ES5, ES6, TypeScript syntax examples](https://github.com/mweststrate/mobservable/blob/master/docs/api.md) - [TypeScript Typings](https://github.com/mweststrate/mobservable/blob/master/dist/mobservable.d.ts) | ||
## Introduction | ||
@@ -29,2 +25,16 @@ | ||
## What others are saying... | ||
> _Elegant! I love it!_ | ||
> ‐ Johan den Haan, CTO of Mendix | ||
> _We ported the book Notes and Kanban examples to Mobservable. Check out [the source](https://github.com/survivejs/mobservable-demo) to see how this worked out. Compared to the original I was definitely positively surprised. Mobservable seems like a good fit for these problems._ | ||
> ‐ Juho Vepsäläinen, author of "SurviveJS - Webpack and React" and jster.net curator | ||
> _Great job with Mobservable! Really gives current conventions and libraries a run for their money._ | ||
> ‐ Daniel Dunderfelt | ||
> _I was reluctant to abandon immutable data and the PureRenderMixin, but I no longer have any reservations. I can't think of any reason not to do things the simple, elegant way you have demonstrated._ | ||
>‐David Schalk | ||
## The essentials | ||
@@ -91,16 +101,20 @@ | ||
<div align="center"> | ||
<img src="https://mweststrate.github.io/mobservable/images/overview.png" height="300"/> | ||
</div> | ||
## Getting started | ||
Either: | ||
* `npm install mobservable --save` | ||
* [Edit](https://mweststrate.github.io/mobservable/getting-started.html#demo) a simple ToDo application online. | ||
* `npm install mobservable --save` | ||
* Clone the boilerplate repository containing the above example from: https://github.com/mweststrate/react-mobservable-boilerplate. | ||
* Or fork this [JSFiddle](https://jsfiddle.net/mweststrate/wgbe4guu/). | ||
## Examples | ||
## Resources | ||
* [Five minute interactive introducton to Mobservable and React](https://mweststrate.github.io/mobservable/getting-started.html) | ||
* [API documentation](https://github.com/mweststrate/mobservable/blob/master/docs/api.md) | ||
* [Tips & Tricks](https://github.com/mweststrate/mobservable/blob/master/docs/syntax.md) | ||
* [ES5, ES6, TypeScript syntax examples](https://github.com/mweststrate/mobservable/blob/master/docs/api.md) | ||
* [TypeScript Typings](https://github.com/mweststrate/mobservable/blob/master/dist/mobservable.d.ts) | ||
## More examples | ||
* The [ports of the _Notes_ and _Kanban_ examples](https://github.com/survivejs/mobservable-demo) from the book "SurviveJS - Webpack and React" to mobservable. | ||
@@ -111,19 +125,10 @@ * A simple webshop using [React + mobservable](https://jsfiddle.net/mweststrate/46vL0phw) or [JQuery + mobservable](http://jsfiddle.net/mweststrate/vxn7qgdw). | ||
## Read more | ||
## Philosophy | ||
* [Five minute interactive introducton](https://mweststrate.github.io/mobservable/getting-started.html) to Mobservable and React | ||
* [Making React reactive: the pursuit of high performing, easily maintainable React apps](https://www.mendix.com/tech-blog/making-react-reactive-pursuit-high-performing-easily-maintainable-react-apps/) | ||
* [SurviveJS interview on Mobservable, React and Flux](http://survivejs.com/blog/mobservable-interview/) | ||
* [Pure rendering in the light of time and state](https://medium.com/@mweststrate/pure-rendering-in-the-light-of-time-and-state-4b537d8d40b1) | ||
* [Official homepage](http://mweststrate.github.io/mobservable/) | ||
* Advanced [tips & tricks](https://github.com/mweststrate/mobservable/blob/master/docs/tips.md) | ||
## Runtime behavior | ||
* Reactive views always update synchronously (unless `transaction is used`) | ||
* Reactive views always update atomically, intermediate values will never be visible. | ||
* Reactive functions evaluate lazily and are not processed if they aren't observed. | ||
* Dependency detection is based on actual values to real-time minify the amount of dependencies. | ||
* Cycles are detected automatically. | ||
* Exceptions during computations are propagated to consumers. | ||
## Top level api | ||
@@ -147,4 +152,17 @@ | ||
## Runtime behavior | ||
* Reactive views always update synchronously (unless `transaction is used`) | ||
* Reactive views always update atomically, intermediate values will never be visible. | ||
* Reactive functions evaluate lazily and are not processed if they aren't observed. | ||
* Dependency detection is based on actual values to real-time minify the amount of dependencies. | ||
* Cycles are detected automatically. | ||
* Exceptions during computations are propagated to consumers. | ||
## FAQ | ||
##### Which browsers are supported? | ||
Mobservable runs on any ES5 environment. That means that all browsers except IE8, Node.js and Rhine are supported. See [caniuse.com](http://caniuse.com/#feat=es5) | ||
##### Is mobservable a framework? | ||
@@ -168,2 +186,6 @@ | ||
##### Why should I use Mobservable instead of reactive library X? | ||
See: https://github.com/mweststrate/mobservable/issues/18 | ||
##### Can I record states and re-hydrate them? | ||
@@ -175,2 +197,2 @@ | ||
Sure, join the reactiflux channel our checkout [dnode.ts](dnode.ts). Or, submit an issue to motivate me to make some nice drawings :). | ||
Sure, join the reactiflux channel our checkout [dnode.ts](lib/dnode.ts). Or, submit an issue to motivate me to make some nice drawings :). |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
123278
11
1403
191
1