mobservable
Advanced tools
Comparing version 0.1.2 to 0.1.3
@@ -1,2 +0,1 @@ | ||
/// <reference path="./typings/node-0.10.d.ts" /> | ||
var __extends = this.__extends || function (d, b) { | ||
@@ -11,2 +10,4 @@ for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; | ||
var prop = null; | ||
if (Array.isArray && Array.isArray(value)) | ||
warn("mobservable.value() was invoked with an array. Probably you want to create an mobservable.array() instead of observing a reference to an array?"); | ||
if (typeof value === "function") | ||
@@ -24,3 +25,5 @@ prop = new ComputedObservable(value, scope); | ||
propFunc.prop = prop; | ||
propFunc.toString = function () { return prop.toString(); }; | ||
propFunc.toString = function () { | ||
return prop.toString(); | ||
}; | ||
return propFunc; | ||
@@ -157,3 +160,3 @@ } | ||
var currentLength = this._values.length; | ||
if (this._supressLengthNotification === true || newLength != currentLength) | ||
if (newLength === currentLength) | ||
return; | ||
@@ -163,4 +166,3 @@ if (newLength > currentLength) | ||
else if (newLength < currentLength) | ||
this.splice(newLength - 1, currentLength - newLength); | ||
this.notifyObserved(); | ||
this.splice(newLength, currentLength - newLength); | ||
} | ||
@@ -292,4 +294,8 @@ }); | ||
}; | ||
ObservableArray.prototype.toString = function () { return this.wrapReadFunction("toString", arguments); }; | ||
ObservableArray.prototype.toLocaleString = function () { return this.wrapReadFunction("toLocaleString", arguments); }; | ||
ObservableArray.prototype.toString = function () { | ||
return this.wrapReadFunction("toString", arguments); | ||
}; | ||
ObservableArray.prototype.toLocaleString = function () { | ||
return this.wrapReadFunction("toLocaleString", arguments); | ||
}; | ||
ObservableArray.prototype.concat = function () { | ||
@@ -302,15 +308,41 @@ var items = []; | ||
}; | ||
ObservableArray.prototype.join = function (separator) { return this.wrapReadFunction("join", arguments); }; | ||
ObservableArray.prototype.reverse = function () { return this.wrapReadFunction("reverse", arguments); }; | ||
ObservableArray.prototype.slice = function (start, end) { return this.wrapReadFunction("slice", arguments); }; | ||
ObservableArray.prototype.sort = function (compareFn) { return this.wrapReadFunction("sort", arguments); }; | ||
ObservableArray.prototype.indexOf = function (searchElement, fromIndex) { return this.wrapReadFunction("indexOf", arguments); }; | ||
ObservableArray.prototype.lastIndexOf = function (searchElement, fromIndex) { return this.wrapReadFunction("lastIndexOf", arguments); }; | ||
ObservableArray.prototype.every = function (callbackfn, thisArg) { return this.wrapReadFunction("every", arguments); }; | ||
ObservableArray.prototype.some = function (callbackfn, thisArg) { return this.wrapReadFunction("some", arguments); }; | ||
ObservableArray.prototype.forEach = function (callbackfn, thisArg) { return this.wrapReadFunction("forEach", arguments); }; | ||
ObservableArray.prototype.map = function (callbackfn, thisArg) { return this.wrapReadFunction("map", arguments); }; | ||
ObservableArray.prototype.filter = function (callbackfn, thisArg) { return this.wrapReadFunction("filter", arguments); }; | ||
ObservableArray.prototype.reduce = function (callbackfn, initialValue) { return this.wrapReadFunction("reduce", arguments); }; | ||
ObservableArray.prototype.reduceRight = function (callbackfn, initialValue) { return this.wrapReadFunction("reduceRight", arguments); }; | ||
ObservableArray.prototype.join = function (separator) { | ||
return this.wrapReadFunction("join", arguments); | ||
}; | ||
ObservableArray.prototype.reverse = function () { | ||
return this.wrapReadFunction("reverse", arguments); | ||
}; | ||
ObservableArray.prototype.slice = function (start, end) { | ||
return this.wrapReadFunction("slice", arguments); | ||
}; | ||
ObservableArray.prototype.sort = function (compareFn) { | ||
return this.wrapReadFunction("sort", arguments); | ||
}; | ||
ObservableArray.prototype.indexOf = function (searchElement, fromIndex) { | ||
return this.wrapReadFunction("indexOf", arguments); | ||
}; | ||
ObservableArray.prototype.lastIndexOf = function (searchElement, fromIndex) { | ||
return this.wrapReadFunction("lastIndexOf", arguments); | ||
}; | ||
ObservableArray.prototype.every = function (callbackfn, thisArg) { | ||
return this.wrapReadFunction("every", arguments); | ||
}; | ||
ObservableArray.prototype.some = function (callbackfn, thisArg) { | ||
return this.wrapReadFunction("some", arguments); | ||
}; | ||
ObservableArray.prototype.forEach = function (callbackfn, thisArg) { | ||
return this.wrapReadFunction("forEach", arguments); | ||
}; | ||
ObservableArray.prototype.map = function (callbackfn, thisArg) { | ||
return this.wrapReadFunction("map", arguments); | ||
}; | ||
ObservableArray.prototype.filter = function (callbackfn, thisArg) { | ||
return this.wrapReadFunction("filter", arguments); | ||
}; | ||
ObservableArray.prototype.reduce = function (callbackfn, initialValue) { | ||
return this.wrapReadFunction("reduce", arguments); | ||
}; | ||
ObservableArray.prototype.reduceRight = function (callbackfn, initialValue) { | ||
return this.wrapReadFunction("reduceRight", arguments); | ||
}; | ||
ObservableArray.prototype.wrapReadFunction = function (funcName, args) { | ||
@@ -335,7 +367,8 @@ var baseFunc = Array.prototype[funcName]; | ||
function DNode() { | ||
this.state = DNodeState.READY; | ||
this.state = 2 /* READY */; | ||
this.observing = []; | ||
this.prevObserving = []; | ||
this.prevObserving = null; | ||
this.observers = []; | ||
this.dependencyChangeCount = 0; | ||
this.isDisposed = false; | ||
} | ||
@@ -363,13 +396,13 @@ DNode.prototype.getObserversCount = function () { | ||
DNode.prototype.markStale = function () { | ||
if (this.state === DNodeState.PENDING) | ||
if (this.state === 1 /* PENDING */) | ||
return; | ||
if (this.state === DNodeState.STALE) | ||
if (this.state === 0 /* STALE */) | ||
return; | ||
this.state = DNodeState.STALE; | ||
this.state = 0 /* STALE */; | ||
this.notifyObservers(); | ||
}; | ||
DNode.prototype.markReady = function (didTheValueActuallyChange) { | ||
if (this.state === DNodeState.READY) | ||
if (this.state === 2 /* READY */) | ||
return; | ||
this.state = DNodeState.READY; | ||
this.state = 2 /* READY */; | ||
this.notifyObservers(didTheValueActuallyChange); | ||
@@ -387,3 +420,3 @@ Scheduler.scheduleReady(); | ||
for (var i = 0; i < l; i++) | ||
if (obs[i].state !== DNodeState.READY) | ||
if (obs[i].state !== 2 /* READY */) | ||
return false; | ||
@@ -395,20 +428,20 @@ return true; | ||
switch (this.state) { | ||
case DNodeState.STALE: | ||
if (observable.state === DNodeState.READY && didTheValueActuallyChange) | ||
case 0 /* STALE */: | ||
if (observable.state === 2 /* READY */ && didTheValueActuallyChange) | ||
this.dependencyChangeCount += 1; | ||
if (observable.state === DNodeState.READY && this.areAllDependenciesAreStable()) { | ||
if (this.dependencyChangeCount > 0) { | ||
this.state = DNodeState.PENDING; | ||
Scheduler.schedule(function () { return _this.computeNextValue(); }); | ||
} | ||
else { | ||
this.markReady(false); | ||
} | ||
this.dependencyChangeCount = 0; | ||
if (observable.state === 2 /* READY */ && this.areAllDependenciesAreStable()) { | ||
this.state = 1 /* PENDING */; | ||
Scheduler.schedule(function () { | ||
if (_this.dependencyChangeCount > 0) | ||
_this.computeNextValue(); | ||
else | ||
_this.markReady(false); | ||
_this.dependencyChangeCount = 0; | ||
}); | ||
} | ||
break; | ||
case DNodeState.PENDING: | ||
case 1 /* PENDING */: | ||
break; | ||
case DNodeState.READY: | ||
if (observable.state === DNodeState.STALE) | ||
case 2 /* READY */: | ||
if (observable.state === 0 /* STALE */) | ||
this.markStale(); | ||
@@ -433,2 +466,4 @@ break; | ||
this.observing = DNode.trackingStack.pop(); | ||
if (this.observing.length === 0 && !this.isDisposed) | ||
warn("You have created a function that doesn't observe any values, did you forget to make its dependencies observable?"); | ||
var changes = quickDiff(this.observing, this.prevObserving); | ||
@@ -443,5 +478,6 @@ var added = changes[0]; | ||
} | ||
this.prevObserving = null; | ||
}; | ||
DNode.prototype.notifyObserved = function () { | ||
if (this.state === DNodeState.PENDING) | ||
if (this.state === 1 /* PENDING */) | ||
throw new Error("Cycle detected"); | ||
@@ -467,2 +503,4 @@ var ts = DNode.trackingStack, l = ts.length; | ||
this.observing = []; | ||
this.observers = []; | ||
this.isDisposed = true; | ||
}; | ||
@@ -476,4 +514,5 @@ DNode.trackingStack = []; | ||
Scheduler.schedule = function (func) { | ||
if (Scheduler.inBatch < 1) | ||
if (Scheduler.inBatch < 1) { | ||
func(); | ||
} | ||
else | ||
@@ -483,11 +522,14 @@ Scheduler.tasks[Scheduler.tasks.length] = func; | ||
Scheduler.runPostBatch = function () { | ||
while (Scheduler.tasks.length) { | ||
try { | ||
Scheduler.tasks.shift()(); | ||
} | ||
catch (e) { | ||
console && console.error("Failed to run scheduled action: " + e); | ||
throw e; | ||
} | ||
var i = 0; | ||
try { | ||
for (i = 0; i < Scheduler.tasks.length; i++) | ||
Scheduler.tasks[i](); | ||
Scheduler.tasks = []; | ||
} | ||
catch (e) { | ||
console && console.error("Failed to run scheduled action, the action has been dropped from the queue: " + e, e); | ||
Scheduler.tasks.splice(0, i + 1); | ||
setTimeout(function () { return Scheduler.runPostBatch(); }, 1); | ||
throw e; | ||
} | ||
}; | ||
@@ -576,3 +618,7 @@ Scheduler.batch = function (action) { | ||
mobservableStatic.quickDiff = quickDiff; | ||
function warn(message) { | ||
if (console) | ||
console.warn("[WARNING:mobservable] " + message); | ||
} | ||
module.exports = mobservableStatic; | ||
//# sourceMappingURL=mobservable.js.map |
@@ -36,2 +36,5 @@ /// <reference path="./typings/node-0.10.d.ts" /> | ||
if (Array.isArray && Array.isArray(value)) | ||
warn("mobservable.value() was invoked with an array. Probably you want to create an mobservable.array() instead of observing a reference to an array?"); | ||
if (typeof value === "function") | ||
@@ -168,2 +171,3 @@ prop = new ComputedObservable(<()=>T>value, scope); | ||
this.dependencyState.computeNextValue(); | ||
// TODO: go back to initialized/ sleep when all observers have left, remove from dependency tree | ||
} | ||
@@ -205,3 +209,2 @@ | ||
private _supressLengthNotification: boolean; | ||
private _values: T[]; | ||
@@ -219,5 +222,5 @@ private dependencyState:DNode; | ||
}, | ||
set: function(newLength) { | ||
set: function(newLength:number) { | ||
var currentLength = this._values.length; | ||
if (this._supressLengthNotification === true || newLength != currentLength) // distinguish between internal and external updates | ||
if (newLength === currentLength) | ||
return; | ||
@@ -231,5 +234,3 @@ | ||
else if (newLength < currentLength) | ||
this.splice(newLength -1, currentLength - newLength); | ||
this.notifyObserved(); | ||
this.splice(newLength, currentLength - newLength); | ||
} | ||
@@ -431,5 +432,6 @@ }); | ||
private observing: DNode[] = []; | ||
private prevObserving: DNode[] = []; | ||
private prevObserving: DNode[] = null; | ||
private observers: DNode[] = []; | ||
private dependencyChangeCount = 0; | ||
private isDisposed: boolean = false; | ||
@@ -516,11 +518,11 @@ getObserversCount() { | ||
// did any of the observables really change? | ||
if (this.dependencyChangeCount > 0) { | ||
this.state = DNodeState.PENDING; | ||
Scheduler.schedule(() => this.computeNextValue()); | ||
} | ||
else { | ||
// we're done, but didn't change, lets make sure verybody knows.. | ||
this.markReady(false); | ||
} | ||
this.dependencyChangeCount = 0; | ||
this.state = DNodeState.PENDING; | ||
Scheduler.schedule(() => { | ||
if (this.dependencyChangeCount > 0) | ||
this.computeNextValue(); | ||
else | ||
// we're done, but didn't change, lets make sure verybody knows.. | ||
this.markReady(false); | ||
this.dependencyChangeCount = 0; | ||
}); | ||
} | ||
@@ -570,2 +572,5 @@ break; | ||
if (this.observing.length === 0 && !this.isDisposed) | ||
warn("You have created a function that doesn't observe any values, did you forget to make its dependencies observable?"); | ||
var changes = quickDiff(this.observing, this.prevObserving); | ||
@@ -582,2 +587,4 @@ var added = changes[0]; | ||
} | ||
this.prevObserving = null; | ||
} | ||
@@ -612,2 +619,4 @@ | ||
this.observing = []; | ||
this.observers = []; | ||
this.isDisposed = true; | ||
// Do something with the observers, notify some state like KILLED? TODO: => set 'undefined' | ||
@@ -623,4 +632,5 @@ } | ||
public static schedule(func:Lambda) { | ||
if (Scheduler.inBatch < 1) | ||
func(); | ||
if (Scheduler.inBatch < 1) { | ||
func(); // func is allowed to throw, it will not affect any internal state | ||
} | ||
else | ||
@@ -631,11 +641,16 @@ Scheduler.tasks[Scheduler.tasks.length] = func; | ||
private static runPostBatch() { | ||
while(Scheduler.tasks.length) { | ||
try { // optimization: move try out of while, re-enter after exception (tasks array is preserved after all) | ||
Scheduler.tasks.shift()(); | ||
} | ||
catch (e) { | ||
console && console.error("Failed to run scheduled action: " + e); | ||
throw e; | ||
} | ||
var i = 0; | ||
try { // try is expensive, move it out of the while | ||
for(i = 0; i < Scheduler.tasks.length; i++) | ||
Scheduler.tasks[i](); | ||
Scheduler.tasks = []; | ||
} | ||
catch (e) { | ||
console && console.error("Failed to run scheduled action, the action has been dropped from the queue: " + e, e); | ||
// drop already executed tasks, including the failing one, and retry in the future | ||
Scheduler.tasks.splice(0, i + 1); | ||
setTimeout(() => Scheduler.runPostBatch(), 1); | ||
// rethrow | ||
throw e; | ||
} | ||
} | ||
@@ -752,2 +767,7 @@ | ||
function warn(message) { | ||
if (console) | ||
console.warn("[WARNING:mobservable] " + message); | ||
} | ||
export = mobservableStatic; |
{ | ||
"name": "mobservable", | ||
"version": "0.1.2", | ||
"version": "0.1.3", | ||
"description": "Changes are coming! Small library for creating observable properties en functions", | ||
@@ -24,2 +24,3 @@ "main": "dist/mobservable.js", | ||
"grunt-ts": "^4.0.1", | ||
"memwatch": "^0.2.2", | ||
"nscript": "^0.1.5", | ||
@@ -26,0 +27,0 @@ "typescript": "^1.4.1" |
@@ -7,2 +7,4 @@ # MOBservable | ||
[Typescript typings](https://github.com/mweststrate/MOBservable/blob/master/mobservable.d.ts) | ||
# Observable values | ||
@@ -13,9 +15,10 @@ | ||
```typescript | ||
/// <reference path='./node_modules/mobservable/mobservable.d.ts'/> | ||
import mobservable = require('mobservable'); | ||
var vat = mobservable(0.20); | ||
var vat = mobservable.value(0.20); | ||
var order = {}; | ||
order.price = mobservable(10), | ||
order.priceWithVat = mobservable(() => order.price() * (1 + vat())); | ||
order.priceWithVat = mobservable.value(() => order.price() * (1 + vat())); | ||
@@ -48,2 +51,5 @@ order.priceWithVat.observe((price) => console.log("New price: " + price)); | ||
**Note: `mobservable.value` versus `mobservable.array`** | ||
Do *not* confuse `mobservable.value([])` (or `mobservable([])`) with `mobservable.array([])`, the first creates an observable reference to an array, but does not observe its contents. The later observes the contents from the array you pass into it. | ||
## mobservable.array(initialValues?):ObservableArray | ||
@@ -70,2 +76,15 @@ | ||
**Note: do not reassign a array variables!** | ||
In general you should never (need to) reassign variables that hold an observable array, instead, use the `replace` method on the array. If you reassign a variable that holds an observable array, the reassignment won't be visible to any of it observers; they will still be observing the original array: | ||
```javascript | ||
var numbers = mobservable.array([1,2]); | ||
// .. stuff that depends on numbers | ||
// bad: | ||
var numbers = mobservable.array([1,2,3]); | ||
// good: | ||
numbers.replace([1,2,3]); | ||
``` | ||
## mobservable.defineProperty(object, name, value) | ||
@@ -98,3 +117,3 @@ | ||
class Order { | ||
_price = new mobservable.property(20, this); | ||
_price = new mobservable.value(20, this); | ||
get price() { | ||
@@ -167,2 +186,13 @@ return this._price(); | ||
Returns all the values of this ObservableArray as native, non-observable, javascript array. The returned array is a shallow copy. | ||
Returns all the values of this ObservableArray as native, non-observable, javascript array. The returned array is a shallow copy. | ||
# Using mobservable with Typescript | ||
Use the following import statement to have strongly typed mobservables in typescript: | ||
```typescript | ||
/// <reference path='./node_modules/mobservable/mobservable.d.ts'/> | ||
import mobservable = require('mobservable'); | ||
``` | ||
Note that the `mobservable(value)` shorthand is not available in typescript, due to limitations in the combination of require statements and .d.ts references. use `mobservable.value(value)` instead. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
118050
2569
192
6