You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
151 lines
5.6 KiB
151 lines
5.6 KiB
(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);
|