1
0
Fork 0
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

(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);