From 13ae16997d4bbca14e255d5989d1c44a76eac72c Mon Sep 17 00:00:00 2001 From: Valerio Virgillito Date: Wed, 16 May 2012 15:23:48 -0700 Subject: montage v.0.10 integration Signed-off-by: Valerio Virgillito --- node_modules/montage/core/extras/array.js | 292 +++++++++++++++++++++++++++++ node_modules/montage/core/extras/object.js | 256 +++++++++++++++++++++++++ node_modules/montage/core/extras/string.js | 79 ++++++++ 3 files changed, 627 insertions(+) create mode 100755 node_modules/montage/core/extras/array.js create mode 100644 node_modules/montage/core/extras/object.js create mode 100755 node_modules/montage/core/extras/string.js (limited to 'node_modules/montage/core/extras') diff --git a/node_modules/montage/core/extras/array.js b/node_modules/montage/core/extras/array.js new file mode 100755 index 00000000..73e1bd87 --- /dev/null +++ b/node_modules/montage/core/extras/array.js @@ -0,0 +1,292 @@ +/* + This file contains proprietary software owned by Motorola Mobility, Inc.
+ No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+ (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ +/** + Defines extensions to native Array object. + @see [Array class]{@link external:Array} + @module montage/core/shim/array +*/ +/** + @external Array +*/ + +/** + @function external:Array#equals + @param {object} right The object to compare. + @returns {Boolean} true or false +*/ +if (!Array.prototype.equals) { + Object.defineProperty(Array.prototype, "equals", { + value: function (right) { + var i = 0, + length = this.length, + lhs, + rhs; + + if (this === right) { + return true; + } + + if (!right || !Array.isArray(right)) { + return false; + } + + if (length !== right.length) { + return false; + } else { + for (; i < length; ++i) { + if (i in this) { + lhs = this[i], + rhs = right[i]; + + if (lhs !== rhs && (lhs && rhs && !lhs.equals(rhs))) { + return false; + } + } else { + if (i in right) { + return false; + } + } + } + } + return true; + } + }); +} +Object.defineProperty(Array, "isCanvasPixelArray", { + value: function(obj) { + return Object.prototype.toString.call(obj) === "[object CanvasPixelArray]"; + } +}); + +/** +Description +@member external:Array#getProperty +@function +@param {Object} aPropertyPath +@param {Property} unique +@param {Property} preserve +@param {Function} visitedComponentCallback +@param {Array} currentIndex +*/ +var _index_array_regexp = /^[0-9]+$/; +Object.defineProperty(Array.prototype, "getProperty", { + value: function(aPropertyPath, unique, preserve, visitedComponentCallback, currentIndex) { + + if (aPropertyPath == null) { + return; + } + + currentIndex = currentIndex || 0; + + var result, + propertyIsNumber = _index_array_regexp.test(aPropertyPath),//!isNaN(aPropertyPath), + parenthesisStartIndex = propertyIsNumber ? -1 : aPropertyPath.indexOf("(", currentIndex), + parenthesisEndIndex = propertyIsNumber ? -1 : aPropertyPath.lastIndexOf(")"), + currentPathComponentEndIndex = propertyIsNumber ? -1 : aPropertyPath.indexOf(".", currentIndex), + nextDelimiterIndex = -1, + itemResult, + index, + currentPathComponent, + functionName, + functionArgPropertyPath, + tmpResult, + uniques; + + // PARSE: Determine the indices of the currentPathComponent we're concerned with + + if (currentPathComponentEndIndex > -1 && parenthesisStartIndex > -1) { + // We have both a dot and an open parenthesis somewhere in the path, figure out the next path component + if (currentPathComponentEndIndex > parenthesisStartIndex) { + // The next dot was actually inside the function call; use the entire function call: foo.bar(a.b.c) -> bar(a.b.c) + nextDelimiterIndex = parenthesisEndIndex + 1; + functionName = aPropertyPath.substring(currentIndex, parenthesisStartIndex); + } else { + // The next dot comes before the start of the function parenthesis; use the dot: foo.bar(a.b.c) -> foo + nextDelimiterIndex = currentPathComponentEndIndex; + } + } else { + // We have either a dot, parenthesis, or neither + if (parenthesisStartIndex > -1) { + // we had a starting parenthesis; use the END parenthesis to include the entire function call + nextDelimiterIndex = parenthesisEndIndex + 1; + functionName = aPropertyPath.substring(currentIndex, parenthesisStartIndex); + } else { + nextDelimiterIndex = currentPathComponentEndIndex; + } + } + + // Find the component of the propertyPath we want to deal with during this particular invocation of this function + currentPathComponent = propertyIsNumber ? aPropertyPath : aPropertyPath.substring(currentIndex, (nextDelimiterIndex === -1 ? aPropertyPath.length : nextDelimiterIndex)); + + // EVALUATE: Determine the value of the currentPathComponent + + if (functionName) { + // We have a function to execute as part of this propertyPath; execute it assuming that it will know + // how to handle the property path being passed along + + // TODO do we call this before or after finding the result (probably before to maintain the chain + // of one invocation's discovered value being the context of the next invocation + if (visitedComponentCallback) { + visitedComponentCallback(this, functionName + "()", null, null, null); + } + + functionArgPropertyPath = aPropertyPath.substring(parenthesisStartIndex + 1, parenthesisEndIndex); + result = this[functionName](functionArgPropertyPath, visitedComponentCallback); + + + } else { + + // TODO we don't provide any way to access properties that are actually accessible on the array itself + // we assume that by default, any property in a propertyPath after an array refers to a property + // you are interested in getting on each member of the array + + if (isNaN(currentPathComponent)) { + + if (visitedComponentCallback) { + //console.log("....", currentPathComponent, aPropertyPath , currentPathComponentEndIndex != -1 ? aPropertyPath.slice(currentPathComponentEndIndex + 1) : null); + //console.log(aPropertyPath.slice(currentIndex)); + visitedComponentCallback(this, null, undefined, null, aPropertyPath.slice(currentIndex)); + } + + result = []; + index = 0; + + // The currentPathComponent is some property not directly on this array, and not an index in the array + // so we'll be getting an array of resolving this currentPathComponent on each member in the array + if (preserve) { + + while((itemResult = this[index]) != null) { + result[index] = itemResult.getProperty(aPropertyPath, unique, preserve, visitedComponentCallback, currentIndex); + index++; + } + + } else { + + // TODO in either case, why do we stop if we encounter null|undefined? there could be useful + // values after that in the collection. I already had to fix an issue here where a zero + // would short-circuit the loop + while((itemResult = this[index]) != null) { + tmpResult = itemResult.getProperty(aPropertyPath, unique, preserve, visitedComponentCallback, currentIndex); + + if (Array.isArray(tmpResult)) { + result = result.concat(tmpResult); + } else { + result[index] = tmpResult; + } + index++; + } + + if (unique) { + var uniques = {}; // TODO reuse this object if possible + // TODO don't recreate this filter function each time + result = result.filter(function(element) { + return uniques[element] ? false : (uniques[element] = true); + }); + } + + } + + } else { + + // The currentPathComponent is an index into this array + result = this[currentPathComponent]; + + + if (visitedComponentCallback) { + visitedComponentCallback(this, currentPathComponent, result, null, currentPathComponentEndIndex != -1 ? aPropertyPath.slice(currentPathComponentEndIndex + 1) : null); + } + + if (currentPathComponentEndIndex > 0) { + result = result ? result.getProperty(aPropertyPath, unique, preserve, visitedComponentCallback, currentPathComponentEndIndex + 1) : undefined; + } else if (visitedComponentCallback && currentPathComponentEndIndex === -1 && result) { + // If we're at the end of the path, but have a result, visit it + //visitedComponentCallback(result, null, null, null, null); + } + } + } + + return result; + }, + enumerable: false +}); + +/** +@member external:Array#count +@function +@returns this.length +*/ +Object.defineProperty(Array.prototype, "count", { + value: function() { + return this.length; + } +}); + +/** +Description +@member external:Array#any +@function +@param {Object} propertyPath +@param {Function} visitedCallback +@returns result +*/ +Object.defineProperty(Array.prototype, "any", { + value: function(propertyPath, visitedCallback) { + var result; + if (propertyPath) { + result = this.some(function(value) { + return !!value.getProperty(propertyPath, null, null, visitedCallback); + }); + } else { + result = this.some(function(value) { + return !!value; + }); + } + return result; + } +}); + +/** +Description +@function external:Array#sum +@param {Object} propertyPath +@param {Function} visitedCallback +@returns sum +*/ +Object.defineProperty(Array.prototype, "sum", { + value: function(propertyPath, visitedCallBack) { + var sum = 0, result, resultSum; + if (propertyPath) { + this.map(function(value) { + result = value.getProperty(propertyPath, null, null, visitedCallBack); + if (Array.isArray(result)) { + resultSum = 0; + result.map(function(value) { + return (resultSum += Number(value)); + }); + result = resultSum; + } + return (sum += Number(result)); + }); + } + else { + this.map(function(value) { + return (sum += Number(value)); + }); + } + return sum; + } +}); + +/** + Removes all members of this array making the object suitable for reuse + @function module:montage/core/core.Array.wipe + */ +Object.defineProperty(Array.prototype, "wipe", { + value: function() { + this.length = 0; + return this; + } +}); diff --git a/node_modules/montage/core/extras/object.js b/node_modules/montage/core/extras/object.js new file mode 100644 index 00000000..0281240f --- /dev/null +++ b/node_modules/montage/core/extras/object.js @@ -0,0 +1,256 @@ + +var M = require("core/core"); // lazy bound because of dependency cycle + +var MODIFY = "modify"; + +/** +@function external:Object#getProperty +@param {Object} aPropertyPath +@param {Property} unique +@param {Property} preserve +@param {Function} visitedComponentCallback +@param {Array} currentIndex +@returns result +*/ +Object.defineProperty(Object.prototype, "getProperty", { + value: function(aPropertyPath, unique, preserve, visitedComponentCallback, currentIndex) { + var dotIndex, + result, + currentPathComponent, + nextDotIndex, + remainingPath = null; + + if (aPropertyPath == null) { + return; + } + + dotIndex = aPropertyPath.indexOf(".", currentIndex); + currentIndex = currentIndex || 0; + currentPathComponent = aPropertyPath.substring(currentIndex, (dotIndex === -1 ? aPropertyPath.length : dotIndex)); + + if (currentPathComponent in this) { + result = this[currentPathComponent]; + } else { + result = typeof this.undefinedGet === "function" ? this.undefinedGet(currentPathComponent) : undefined; + } + + if (visitedComponentCallback) { + nextDotIndex = aPropertyPath.indexOf(".", currentIndex); + if (nextDotIndex != -1) { + remainingPath = aPropertyPath.substr(nextDotIndex+1); + } + visitedComponentCallback(this, currentPathComponent, result, null, remainingPath); + } + + if (visitedComponentCallback && result && -1 === dotIndex) { + + // We resolved the last object on the propertyPath, be sure to give the visitor a chance to handle this one + //visitedComponentCallback(result, null, null, null, null); + + } else if (result && dotIndex !== -1) { + // We resolved that component of the path, but there's more path components; go to the next + + if (result.getProperty) { + result = result.getProperty(aPropertyPath, unique, preserve, visitedComponentCallback, dotIndex + 1); + } else { + // TODO track when this happens, right now it's only happening with CanvasPixelArray in WebKit + result = Object.prototype.getProperty.call(result, aPropertyPath, unique, preserve, visitedComponentCallback, dotIndex + 1); + } + } + // Otherwise, we reached the end of the propertyPath, or at least as far as we could; stop + return result; + }, + enumerable: false +}); + +/** + @private +*/ +Object.defineProperty(Object.prototype, "_propertySetterNamesByName", { + value: {} +}); + +/** + @private +*/ +Object.defineProperty(Object.prototype, "_propertySetterByName", { + value: {} +}); + +/** +Description +@member external:Object#setProperty +@function +@param {Object} aPropertyPath +@param {Object} value +@returns itself +*/ +Object.defineProperty(Object.prototype, "setProperty", { + value: function(aPropertyPath, value) { + var propertyIsNumber = !isNaN(aPropertyPath), + lastDotIndex = propertyIsNumber ? -1 : aPropertyPath.lastIndexOf("."), + setObject, + lastObjectAtPath, + propertyToSetOnArray; + + if (lastDotIndex !== -1) { + //The propertyPath describes a property that is deeper inside this object + setObject = this.getProperty(aPropertyPath.substring(0, lastDotIndex)); + + if (!setObject) { + this.undefinedSet(aPropertyPath); + return; + } + + aPropertyPath = aPropertyPath.substring(lastDotIndex + 1); + } else { + // The property path describes a property on this object + setObject = this; + } + + lastObjectAtPath = setObject.getProperty(aPropertyPath); + + // TODO clean up some of the duplicated code here + + if (lastObjectAtPath && Array.isArray(lastObjectAtPath)) { + if (lastObjectAtPath !== value) { + // if the value does not match the object described by this propertyPath; set it as the new value + + if (Array.isArray(setObject)) { + // If the setObject is an array itself; splice (typically called by set) to trigger bindings, do it here to save time + propertyToSetOnArray = parseInt(aPropertyPath, 10); + if (!isNaN(propertyToSetOnArray)) { + if (setObject.length < propertyToSetOnArray) { + // TODO while I could set the value here I'm setting null and letting the splice, + // which we need to do anyway to trigger bindings, do the actual setting + setObject[propertyToSetOnArray] = null; + } + + setObject.splice(propertyToSetOnArray, 1, value); + + } else { + setObject[aPropertyPath] = value; + } + + } else { + setObject[aPropertyPath] = value; + } + + } else { + // Otherwise, they are the same object, a mutation event probably happened + + // If the object at the property we're "setting" is itself an array, see if there was an event passed along + // as part of a change and whether we need to call the setObject's changeProperty method + var changeEvent = this.setProperty.changeEvent, modify; + + // For these mutation/addition/removal events, use the 'modify' attribute of this property's descriptor + if (changeEvent && (changeEvent.currentTarget.getProperty(changeEvent.currentPropertyPath) === lastObjectAtPath) && + (modify = M.Montage.getPropertyAttribute(setObject, aPropertyPath, MODIFY))) { + modify.call(setObject, changeEvent.type, changeEvent.newValue, changeEvent.prevValue); + } + } + } else if (Array.isArray(setObject)) { + // If the setObject is an array itself; splice (typically called by set) to trigger bindings, do it here to save time + propertyToSetOnArray = parseInt(aPropertyPath, 10); + if (!isNaN(propertyToSetOnArray)) { + if (setObject.length < propertyToSetOnArray) { + // TODO while I could set the value here I'm setting null and letting the splice, + // which we need to do anyway to trigger bindings, do the actual setting + setObject[propertyToSetOnArray] = null; + } + } + setObject.splice(propertyToSetOnArray, 1, value); + } else { + setObject[aPropertyPath] = value; + } + }, + enumerable: false +}); + +/** +@member external:Object#parentProperty +@default null +*/ +Object.defineProperty(Object.prototype, "parentProperty", { + enumerable: false, + value: null, + writable: true +}); + +/** + @function module:montage/core/core.Montage#undefinedGet + @param {Object} aPropertyName The object property name. + */ +Object.defineProperty(Object.prototype, "undefinedGet", { + value: function(aPropertyName) { + console.warn("get undefined property -" + aPropertyName + "-"); + }, + writable: true +}); + +/** + @function module:montage/core/core.Montage#undefinedSet + @param {Object} aPropertyName The object property name. + */ +Object.defineProperty(Object.prototype, "undefinedSet", { + value: function(aPropertyName) { + console.warn("set undefined property -" + aPropertyName + "-"); + }, + writable: true +}); + +/** + Returns the descriptor object for an object's property. + @function external:Object#getPropertyDescriptor + @param {Object} anObject The object containing the property. + @param {String} propertyName The name of the property. + @returns {Object} The object's property descriptor. + */ +Object.getPropertyDescriptor = function(anObject, propertyName) { + var current = anObject, + currentDescriptor; + + do { + currentDescriptor = Object.getOwnPropertyDescriptor(current, propertyName); + } while (!currentDescriptor && (current = current.__proto__ || Object.getPrototypeOf(current))); + + return currentDescriptor; +}; + +/** + Returns the prototype object and property descriptor for a property belonging to an object. + @function external:Object#getPrototypeAndDescriptorDefiningProperty + @param {Object} anObject The object to return the prototype for. + @param {String} propertyName The name of the property. + @returns {Object} An object containing two properties named prototype and propertyDescriptor that contain the object's prototype object and property descriptor, respectively. + */ +Object.getPrototypeAndDescriptorDefiningProperty = function(anObject, propertyName) { + var current = anObject, + currentDescriptor; + if (propertyName) { + + do { + currentDescriptor = Object.getOwnPropertyDescriptor(current, propertyName); + } while (!currentDescriptor && (current = current.__proto__ || Object.getPrototypeOf(current))); + + return { + prototype: current, + propertyDescriptor: currentDescriptor + }; + } +}; + +/** + Removes all properties owned by this object making the object suitable for reuse + @function module:montage/core/core.Object.wipe + */ +Object.defineProperty(Object.prototype, "wipe", { + value: function() { + var keys = Object.keys(this), + i = keys.length; + + while(i) delete this[keys[--i]]; + + return this; + } +}); diff --git a/node_modules/montage/core/extras/string.js b/node_modules/montage/core/extras/string.js new file mode 100755 index 00000000..10b69e88 --- /dev/null +++ b/node_modules/montage/core/extras/string.js @@ -0,0 +1,79 @@ +/* + This file contains proprietary software owned by Motorola Mobility, Inc.
+ No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+ (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ +/** + Defines extensions to native String object. + @see [String class]{@link external:String} + @module montage/core/shim/string +*/ + +/** + @external String + */ +Object.defineProperties(String.prototype, /** @lends external:String.prototype#*/{ + /** + @function external:String.addEventListener + @param {Listener} type The type of event listener. + @param {Listener} listener The event listener. + @param {Function} useCapture The capturing function. + */ + addEventListener: { + value: function(type, listener, useCapture) { + //NO OP, on purpose + } + + }, + /** + Capitalizes the first letter in the string. + @function external:String.toCapitalized + @returns {String} The original string with its first letter capitalized. + @example + var fname = "abe"; + var lname = "lincoln"; + var name = fname.toCapitalized() + " " + lname.toCapitalized(); + // name == "Abe Lincoln" + */ + toCapitalized: { + value: function() { + return this.charAt(0).toUpperCase() + this.slice(1); + } + }, + + /** + Returns true if the two strings are equal, otherwise returns false. + @function external:String.equals + @param {Object} anObject The object to compare to the string. + @returns {Boolean} Returns true if the string is equal to anObject. + */ + equals: { + value: function(anObject) { + if (this.toString() === anObject) { + return true; + } + + if (!anObject || !(anObject instanceof String)) { + return false; + } + + return (this == anObject); + } + } + +}); + +/** + Shim implementation of String.isString() for browsers that don't yet support it. + @function external:String.isString() + @param {object} obj The object to determine if its a String. + @returns {boolean} Object.prototype.toString.call(obj) === "[object String]" +*/ +if (!String.isString) { + Object.defineProperty(String, "isString", { + value: function(obj) { + return Object.prototype.toString.call(obj) === "[object String]"; + } + }); +} + -- cgit v1.2.3