-
Notifications
You must be signed in to change notification settings - Fork 0
/
stateful.js
119 lines (96 loc) · 3.49 KB
/
stateful.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
var stateful = function(obj) {
var dependencies = {},
dependentObjects = [],
stateComputers = {},
stateChangeCallbacks = {},
noticeInitial = {},
state = {},
computed = [];
return {
object: obj,
state: function() {
var key = arguments[0],
value = arguments[1];
if (_.isObject(key)) {
return this._configureState(key);
} else if (_.isString(key)) {
return !_.isUndefined(value) ? this._setState(key, value) : this._getState(key);
}
},
behavior: function(config) {
if (_.isObject(config)) {
_.each(config, function(callback, eventName) {
this.object.on(eventName, _.bind(function() {
callback.call(this);
}, this));
}, this);
}
return this;
},
inject: function(deps) {
_.each(deps, function(dep, key) {
dependencies[key] = dep;
dep.addDependentObject(this);
}, this);
return this;
},
takeOut: function(deps) {
// TBD
},
deps: function(dep) {
return _.isString(dep) ? dependencies[dep] : dependencies;
},
addDependentObject: function(dep) {
dependentObjects.push(dep);
},
// Private methods
_getState: function(key) {
return state[key];
},
_setState: function(key, value, isInitial) {
state[key] = value;
var omitCallback = isInitial && !noticeInitial[key];
this.callStateComputers(isInitial, key);
if (_.isFunction(stateChangeCallbacks[key]) && !omitCallback) {
stateChangeCallbacks[key].call(this, value);
}
_.each(dependentObjects, function(dep) {
dep.callStateComputers(isInitial);
});
return this;
},
_configureState: function(config) {
_.each(config, function(stateConfig, stateName) {
if (_.isFunction(stateConfig.compute)) {
stateComputers[stateName] = stateConfig.compute;
}
if (_.isFunction(stateConfig.change)) {
stateChangeCallbacks[stateName] = stateConfig.change;
}
noticeInitial[stateName] = stateConfig.noticeInitial ? true : false;
}, this);
_.each(config, function(stateConfig, stateName) {
if (
!_.isUndefined(stateConfig.initial) &&
this._getState(stateName) != stateConfig.initial
) {
this._setState(stateName, stateConfig.initial, true);
} else {
this.callStateComputers(true);
}
}, this);
return this;
},
callStateComputers: function(isInitial, omit) {
_.each(stateComputers, function(computer, stateName) {
if (stateName != omit && computed.indexOf(stateName) == -1) {
var computedState = computer.call(this);
if (this._getState(stateName) != computedState) {
this._setState(stateName, computer.call(this), isInitial);
}
}
}, this);
return this;
}
}
}