/*
change@independentProperty
event.
@function module:montage/core/core.Montage.addDependencyToProperty
@param {Object} obj The object containing the dependent and independent properties.
@param {String} independentProperty The name of the object's independent property.
@param {String} dependentProperty The name of the object's dependent property.
*/
Montage.defineProperty(Montage, "addDependencyToProperty", { value: function(obj, independentProperty, dependentProperty) {
// TODO optimize this so we don't keep checking over and over again
if (!obj._dependenciesForProperty) {
obj._dependenciesForProperty = {};
}
if (!obj._dependenciesForProperty[dependentProperty]) {
obj._dependenciesForProperty[dependentProperty] = [];
}
obj._dependenciesForProperty[dependentProperty].push(independentProperty);
}});
/**
Removes a dependent property from another property's collection of dependent properties.
When the value of a dependent property changes, it generates a change@independentProperty
event.
@function module:montage/core/core.Montage.removeDependencyFromProperty
@param {Object} obj The object containing the dependent and independent properties.
@param {String} independentProperty The name of the object's independent property.
@param {String} dependentProperty The name of the object's dependent property that you want to remove.
*/
Montage.defineProperty(Montage, "removeDependencyFromProperty", {value: function(obj, independentProperty, dependentProperty) {
if (!obj._dependenciesForProperty) {
return;
}
var dependencies = obj._dependenciesForProperty[dependentProperty];
if (dependencies) {
dependencies = dependencies.filter(function(element) {
return (element !== independentProperty);
});
}
}});
function getAttributeProperties(proto, attributeName) {
var attributePropertyName = UNDERSCORE + attributeName + ATTRIBUTE_PROPERTIES;
if (proto.hasOwnProperty(attributePropertyName)) {
return proto[attributePropertyName];
} else {
return Object.defineProperty(proto, attributePropertyName, {
enumerable: false, configurable: false, writable: false,
value: Object.create(getAttributeProperties(Object.getPrototypeOf(proto), attributeName))
})[attributePropertyName];
}
}
/**
Returns the names of serializable properties belonging to Montage object.
@function module:montage/core/core.Montage.getSerializablePropertyNames
@param {Object} anObject A Montage object.
@returns {Array} An array containing the names of the serializable properties belonging to anObject
.
*/
Montage.defineProperty(Montage, "getSerializablePropertyNames", {value: function(anObject) {
var propertyNames = [],
attributes = anObject._serializableAttributeProperties;
if (attributes) {
for (var name in attributes) {
if (attributes[name]) {
propertyNames.push(name);
}
}
}
return propertyNames;
}});
/**
Returns the attribute of a property belonging to an object.
@function module:montage/core/core.Montage.getPropertyAttribute
@param {Object} anObject A object.
@param {String} propertyName The name of a property belonging to anObject
.
@param {String} attributeName The name of a property's attribute.
@returns attributes array
*/
Montage.defineProperty(Montage, "getPropertyAttribute", {value: function(anObject, propertyName, attributeName) {
var attributePropertyName = UNDERSCORE + attributeName + ATTRIBUTE_PROPERTIES,
attributes = anObject[attributePropertyName];
if (attributes) {
return attributes[propertyName];
}
}});
/**
@function module:montage/core/core.Montage.getPropertyAttributes
@param {Object} anObject An object.
@param {String} attributeName The attribute name.
@returns {Object} TODO getPropertyAttributes returns description
*/
Montage.defineProperty(Montage, "getPropertyAttributes", {value: function(anObject, attributeName) {
var attributeValues = {},
attributePropertyName = UNDERSCORE + attributeName + ATTRIBUTE_PROPERTIES,
attributes = anObject[attributePropertyName];
if (!attributes) {
return;
}
for (var name in attributes) {
attributeValues[name] = attributes[name];
}
return attributeValues;
}});
var _instanceMetadataDescriptor = {
isInstance: {value: true}
};
var _functionInstanceMetadataDescriptor = {
objectName: {value: "Function"},
isInstance: {value: true}
};
/**
@function module:montage/core/core.Montage.getInfoForObject
@param {Object} object An object.
@returns {Object} object._montage_metadata
*/
Montage.defineProperty(Montage, "getInfoForObject", {
value: function(object) {
var metadata;
var instanceMetadataDescriptor;
if (hasOwnProperty.call(object, "_montage_metadata")) {
return object._montage_metadata;
} else {
metadata = object._montage_metadata || (object.constructor && object.constructor._montage_metadata) || null;
if (object.constructor === Function) {
instanceMetadataDescriptor = _functionInstanceMetadataDescriptor;
} else {
instanceMetadataDescriptor = _instanceMetadataDescriptor;
}
try {
return Object.defineProperty(object, "_montage_metadata", {
enumerable: false,
// this object needs to be overriden by the SerializationCompiler because this particular code might be executed on an exported object before the Compiler takes action, for instance, if this function is called within the module definition itself (happens with __core__).
writable: true,
value: Object.create(metadata, instanceMetadataDescriptor)
})._montage_metadata;
} catch(e) {
// NOTE Safari (as of Version 5.0.2 (6533.18.5, r78685)
// doesn't seem to allow redefining an existing property on a DOM Element
return (object._montage_metadata = Object.create(metadata, instanceMetadataDescriptor));
}
}
}
});
/**
@function module:montage/core/core.Montage.doNothing
@default function
*/
Object.defineProperty(Montage, "doNothing", {
value: function() {
}
});
/**
@function module:montage/core/core.Montage#self
@default function
@returns itself
*/
Object.defineProperty(Montage, "self", {
value: function() {
return this;
}
});
/**
@private
*/
Object.defineProperty(Montage, "__OBJECT_COUNT", {
value: 0,
writable: true
});
// TODO figure out why this code only works in this module. Attempts to move
// it to core/extras/object resulted in _uuid becoming enumerable and tests
// breaking.
var UUID = require("core/uuid");
var hasOwnProperty = Object.prototype.hasOwnProperty;
var uuidGetGenerator = function() {
var uuid = UUID.generate(),
info = Montage.getInfoForObject(this);
try {
if (info !== null && info.isInstance === false) {
this._uuid = uuid;
Object.defineProperty(this, "uuid", {
get: function() {
if (this.hasOwnProperty("uuid")) {
// we are calling uuid on the prototype
return this._uuid;
} else {
// we are calling uuid on instance of this prototype
return uuidGetGenerator.call(this);
}
}
});
} else {
//This is needed to workaround some bugs in Safari where re-defining uuid doesn't work for DOMWindow.
if (info.isInstance) {
Object.defineProperty(this, "uuid", {
configurable: true,
enumerable: false,
writable: false,
value: uuid
});
}
//This is really because re-defining the property on DOMWindow actually doesn't work, so the original property with the getter is still there and return this._uuid if there.
if (this instanceof Element || !info.isInstance || !(VALUE in Object.getOwnPropertyDescriptor(this, "uuid")) || !(PROTO in this /* lame way to detect IE */)) {
//This is needed to workaround some bugs in Safari where re-defining uuid doesn't work for DOMWindow.
this._uuid = uuid;
}
}
} catch(e) {
// NOTE Safari (as of Version 5.0.2 (6533.18.5, r78685)
// doesn't seem to allow redefining an existing property on a DOM Element
// Still want to redefine the property where possible for speed
this._uuid = uuid;
}
return uuid;
};
var defaultUuidGet = function defaultUuidGet() {
return (hasOwnProperty.call(this, "_uuid") ? this._uuid : uuidGetGenerator.call(this));
};
/**
@private
*/
Object.defineProperty(Object.prototype, "_uuid", {
enumerable: false,
value: null,
writable: true
});
/**
Contains an object's unique ID.
@member external:Object#uuid
@default null
*/
Object.defineProperty(Object.prototype, "uuid", {
configurable: true,
get: defaultUuidGet,
set: function() {
}
});
Montage.defineProperty(Montage, "identifier", {
value: null,
serializable: true
});
/**
Returns true if two objects are equal, otherwise returns false.
@function module:montage/core/core.Montage#equals
@param {Object} anObject The object to compare for equality.
@returns {Boolean} Returns true
if the calling object and anObject
are identical and their uuid
properties are also equal. Otherwise, returns false
.
*/
Object.defineProperty(Montage, "equals", {
value: function(anObject) {
return this === anObject || this.uuid === anObject.uuid;
}
});
/*
* If it exists this method calls the method named with the identifier prefix.
* Example: If the name parameter is "shouldDoSomething" and the caller's identifier is "bob", then
* this method will try and call "bobShouldDoSomething"
*/
/**
* @function module:montage/core/core.Montage#callDelegateMethod
* @param {string} name
*/
Object.defineProperty(Montage, "callDelegateMethod", {
value: function(name) {
var delegate = this.delegate, delegateFunctionName, delegateFunction;
if (typeof this.identifier === "string") {
delegateFunctionName = this.identifier + name.toCapitalized();
if (delegate && typeof (delegateFunction = delegate[delegateFunctionName]) === "function") {
// remove first argument
Array_prototype.shift.call(arguments);
return delegateFunction.apply(delegate, arguments);
}
}
if (delegate && typeof (delegateFunction = delegate[name]) === "function") {
// remove first argument
Array_prototype.shift.call(arguments);
return delegateFunction.apply(delegate, arguments);
}
}
});