-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathtoolbox.extras.js
150 lines (136 loc) · 5.6 KB
/
toolbox.extras.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
(function () {
var Toolbox = window.Toolbox = (window.Toolbox || {});
// Declare a computed property.
// `watched` is a list of property names that this computed property depends on.
// A change to any property in `watches` will trigger a change event for the property.
// `getter` is a function that takes no arguments and returns the property value.
// `setter` is a function that takes a new property value and does whatever is
// appropriate to store the new value.
// `watched` is required, but can be an empty array
// `getter` is required
// `setter` is optional
Toolbox.prop = function (watches, getter, setter) {
return {
watches: watches,
getter: getter,
setter: setter,
isComputedProperty: true
};
}
// Provides support for property change notifications and computed properties.
// This module can be used by mixing it into an object or class prototype.
// `set()` will trigger a change event for the modified property, where the
// event name is: `*propertyName*Changed`.
// A computed property can be declared using `Toolbox.prop()`.
// Example:
// var MyClass = Base.extend({
// prop1: 'apple',
// prop2: Toolbox.prop(['prop1'], function () {
// return 'pine' + this.get('prop1');
// })
// });
// var obj = new MyClass();
// alert(obj.get('prop1')); // apple
// alert(obj.get('prop2')); // pineapple
Toolbox.SmartProperties = {
// Initialize properties to the defaults provided in `initProps` and process
// computed properties.
initSmartProperties: function (initProps) {
var that = this;
if (initProps) {
_.extend(this, initProps);
}
// Build a mapping from a property name to the list of property names
// that depend on it.
var watchers = this._watchers = {};
// NOTE: This loop should include both properties explicitly assigned
// to `this` and properties inherited from the prototype chain, so that
// we handle all computed properties.
for (var key in this) {
var value = this[key];
if (value && value.isComputedProperty) {
_.each(value.watches, function (watch) {
watchers[watch] = watchers[watch] || [];
watchers[watch].push(key);
});
}
}
},
// Return the value of the property with the given name.
// If the property is a computed property, the value is determined by the
// return value of the computed property's getter function.
get: function (name) {
var value = this[name];
if (value && value.isComputedProperty) {
return value.getter.call(this);
}
return this[name];
},
// Sets the value of the property with the given name.
// If the property is a computed property, the property's setter function
// will be called with the provided `value` as the first argument.
set: function (name, value) {
var currentValue = this[name];
var changed = false;
if (currentValue && currentValue.isComputedProperty) {
if (currentValue.setter) {
currentValue.setter.call(this, value);
changed = true;
}
} else {
this[name] = value;
changed = true;
}
if (changed) {
this._triggerChange(name);
}
},
// Trigger a change event for the given property name.
// Also triggers change events for all properties that are watching this property.
_triggerChange: function (name) {
var that = this;
this.trigger(name + 'Changed');
_.each(this._watchers[name], function (watcher) {
that._triggerChange(watcher);
});
}
};
// Mix events module into SmartProperties module.
_.extend(Toolbox.SmartProperties, Backbone.Events);
// Convenience class that extends Base and already integrates the SmartProperties
// mixin module.
Toolbox.LiveObject = Toolbox.Base.extend({
constructor: function (props) {
this.initSmartProperties(props);
}
});
_.extend(Toolbox.LiveObject.prototype, Toolbox.SmartProperties);
// Bind a property of `obj1` to a property of `obj2`.
// Initially, the property of `obj1` will take on the value of the `obj2` property.
// Subsequent changes to either property will be automatically propagated to the
// other property.
Toolbox.bindProperties = function (obj1, prop1, obj2, prop2) {
function createUpdateFunc(obj1, prop1, obj2, prop2) {
return function () {
var curValue = obj1.get(prop1);
var newValue = obj2.get(prop2);
if (curValue !== newValue) {
obj1.set(prop1, obj2.get(prop2));
}
};
}
var update1 = createUpdateFunc(obj1, prop1, obj2, prop2);
var update2 = createUpdateFunc(obj2, prop2, obj1, prop1);
obj1.bind(prop1 + 'Changed', update2);
obj2.bind(prop2 + 'Changed', update1);
update1();
}
})();
(function ($) {
$.fn.disable = function () {
this.attr('disabled', 'disabled');
};
$.fn.enable = function () {
this.removeAttr('disabled');
};
})(jQuery);