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 --- .../autocomplete/autocomplete.reel/autocomplete.js | 126 ++-- .../autocomplete/result-item.reel/result-item.js | 33 + .../results-list.reel/results-list.html | 5 +- .../autocomplete/results-list.reel/results-list.js | 7 +- node_modules/montage/ui/button.reel/button.js | 6 + .../component-placeholder.js | 146 ---- node_modules/montage/ui/component.js | 163 +++-- node_modules/montage/ui/composer/key-composer.js | 385 +++++++++++ .../montage/ui/composer/translate-composer.js | 230 +++++-- .../montage/ui/condition.reel/condition.js | 79 +-- .../montage/ui/controller/array-controller.js | 53 +- node_modules/montage/ui/flow-bezier-spline.js | 163 +++-- node_modules/montage/ui/flow-path-cubic.js | 115 ---- node_modules/montage/ui/flow-path-lerp.js | 112 --- node_modules/montage/ui/flow-path-linear.js | 83 --- node_modules/montage/ui/flow-path-sigmoid.js | 148 ---- node_modules/montage/ui/flow-path.js | 215 ------ node_modules/montage/ui/flow.reel/flow.html | 10 +- node_modules/montage/ui/flow.reel/flow.js | 758 +++++++++++++-------- node_modules/montage/ui/list.reel/list.html | 2 +- node_modules/montage/ui/loader.reel/loader.js | 15 +- .../ui/nearest-neighbor-component-search.js | 122 ++-- .../montage/ui/repetition.reel/repetition.js | 711 +++++++++++++------ .../rich-text-editor.reel/rich-text-editor-base.js | 4 +- .../rich-text-editor.reel/rich-text-editor.js | 4 +- .../montage/ui/scroller.reel/scroller.html | 9 + node_modules/montage/ui/scroller.reel/scroller.js | 20 - .../ui/skeleton/range-input.reel/range-input.html | 18 +- .../ui/skeleton/range-input.reel/range-input.js | 159 +++-- node_modules/montage/ui/slot.reel/slot.js | 262 +------ .../montage/ui/substitution.reel/substitution.js | 14 - node_modules/montage/ui/tabs.reel/tabs.html | 3 +- node_modules/montage/ui/template.js | 9 +- .../token-field/token-field.reel/token-field.css | 40 ++ .../token-field/token-field.reel/token-field.html | 87 +++ .../ui/token-field/token-field.reel/token-field.js | 221 ++++++ .../montage/ui/token-field/token.reel/token.css | 54 ++ .../montage/ui/token-field/token.reel/token.html | 45 ++ .../montage/ui/token-field/token.reel/token.js | 91 +++ 39 files changed, 2651 insertions(+), 2076 deletions(-) create mode 100644 node_modules/montage/ui/autocomplete/result-item.reel/result-item.js delete mode 100755 node_modules/montage/ui/component-placeholder.reel/component-placeholder.js create mode 100644 node_modules/montage/ui/composer/key-composer.js delete mode 100644 node_modules/montage/ui/flow-path-cubic.js delete mode 100644 node_modules/montage/ui/flow-path-lerp.js delete mode 100644 node_modules/montage/ui/flow-path-linear.js delete mode 100644 node_modules/montage/ui/flow-path-sigmoid.js delete mode 100644 node_modules/montage/ui/flow-path.js create mode 100644 node_modules/montage/ui/token-field/token-field.reel/token-field.css create mode 100644 node_modules/montage/ui/token-field/token-field.reel/token-field.html create mode 100644 node_modules/montage/ui/token-field/token-field.reel/token-field.js create mode 100644 node_modules/montage/ui/token-field/token.reel/token.css create mode 100644 node_modules/montage/ui/token-field/token.reel/token.html create mode 100644 node_modules/montage/ui/token-field/token.reel/token.js (limited to 'node_modules/montage/ui') diff --git a/node_modules/montage/ui/autocomplete/autocomplete.reel/autocomplete.js b/node_modules/montage/ui/autocomplete/autocomplete.reel/autocomplete.js index 0ce1ab85..c9cbca74 100644 --- a/node_modules/montage/ui/autocomplete/autocomplete.reel/autocomplete.js +++ b/node_modules/montage/ui/autocomplete/autocomplete.reel/autocomplete.js @@ -54,6 +54,15 @@ var Autocomplete = exports.Autocomplete = Montage.create(TextInput, { value: null }, + /** + * If the delegate returns Objects, this property can be used to derive the + * display string for an object. If this property is not provided, the results + * provided by the delegate are assumed to be String. + */ + textPropertyPath: { + value: null + }, + separator: { value: ',', distinct: true @@ -112,42 +121,40 @@ var Autocomplete = exports.Autocomplete = Montage.create(TextInput, { // get the entered text after the separator var value = this._value; + if(value) { + var arr = value.split(this.separator).map(function(item) { + return item.trim(); + }); + this.activeTokenIndex = this._findActiveTokenIndex(this.tokens, arr); + this._tokens = value.split(this.separator).map(function(item) { + return item.trim(); + }); + } else { + this.activeTokenIndex = 0; + this._tokens = []; + } if(fromInput) { this._valueSyncedWithInputField = true; - if(value) { - var arr = value.split(this.separator).map(function(item) { - return item.trim(); - }); - this.activeTokenIndex = this._findActiveTokenIndex(this.tokens, arr); - this._tokens = value.split(this.separator).map(function(item) { - return item.trim(); - }); - if(this._tokens.length && this._tokens.length > 0) { - var searchTerm = this._tokens[this.activeTokenIndex]; - searchTerm = searchTerm ? searchTerm.trim() : ''; - if(searchTerm.length >= this.minLength) { - var self = this; - clearTimeout(this.delayTimer); - this.delayTimer = setTimeout(function() { - self.delayTimer = null; - if (logger.isDebug) { - logger.debug('SEARCH for ', searchTerm); - } - self.performSearch(searchTerm); - }, this.delay); - } else { - this.showPopup = false; - } - } else { - this.showPopup = false; + this.showPopup = false; + if(this._tokens.length && this._tokens.length > 0) { + var searchTerm = this._tokens[this.activeTokenIndex]; + searchTerm = searchTerm ? searchTerm.trim() : ''; + if(searchTerm.length >= this.minLength) { + var self = this; + clearTimeout(this.delayTimer); + this.delayTimer = setTimeout(function() { + self.delayTimer = null; + if (logger.isDebug) { + logger.debug('SEARCH for ', searchTerm); + } + self.performSearch(searchTerm); + }, this.delay); } } + } else { - this.activeTokenIndex = 0; - this._tokens = []; this.showPopup = false; - this._valueSyncedWithInputField = false; this.needsDraw = true; } @@ -239,11 +246,24 @@ var Autocomplete = exports.Autocomplete = Montage.create(TextInput, { get: function() { return this._suggestedValue; }, - set: function(value) { - if(value) { - this._suggestedValue = value; - var arr = this.tokens; - arr[this.activeTokenIndex] = this._suggestedValue; + set: function(aValue) { + this._suggestedValue = aValue; + if(aValue) { + + var arr = this.tokens || []; + var token; + + if(String.isString(aValue)) { + token = aValue; + } else { + if(this.textPropertyPath) { + token = aValue[this.textPropertyPath]; + } else { + token = ''; + } + } + + arr[this.activeTokenIndex] = token; this.tokens = arr; this.showPopup = false; } @@ -283,6 +303,7 @@ var Autocomplete = exports.Autocomplete = Montage.create(TextInput, { if (logger.isDebug) { logger.debug('got suggestions: ', value); } + this.loadingStatus = 'complete'; this._suggestions = value; this.showPopup = (value && value.length > 0); @@ -305,19 +326,12 @@ var Autocomplete = exports.Autocomplete = Montage.create(TextInput, { enumerable: false, value: function(searchTerm) { if(this.delegate) { + this.resultsController.selectedIndexes = []; // index on the popup this.activeItemIndex = 0; this.loadingStatus = 'loading'; - //this.showPopup = true; - // delegate must set the results on the AutoComplete - var fn = this.identifier + 'ShouldGetSuggestions'; - if(typeof this.delegate[fn] === 'function') { - this.delegate[fn](this, searchTerm); - } else if(typeof this.delegate.shouldGetSuggestions === 'function') { - this.delegate.shouldGetSuggestions(this, searchTerm); - } else { - // error - d - } + var delegateFn = this.callDelegateMethod('ShouldGetSuggestions', this, searchTerm); + } } }, @@ -403,6 +417,11 @@ var Autocomplete = exports.Autocomplete = Montage.create(TextInput, { boundObjectPropertyPath: "_activeIndexes", oneway: true }); + Object.defineBinding(this.resultsList, "textPropertyPath", { + boundObject: this, + boundObjectPropertyPath: "textPropertyPath", + oneway: true + }); var popup = this._getPopup(); } @@ -425,11 +444,18 @@ var Autocomplete = exports.Autocomplete = Montage.create(TextInput, { if (!this._valueSyncedWithInputField) { this.value = this.tokens.join(this.separator); + if(this.value && this.value.charAt(this.value.length-1) != this.separator) { + this.value += this.separator; + } this.element.value = this.value; this._valueSyncedWithInputField = true; } + var showPopup = this.showPopup; + if(this.value === '') { + showPopup = false; + } - if(this.showPopup) { + if(showPopup) { this.popup.show(); // reset active index this.activeItemIndex = 0; @@ -454,7 +480,7 @@ var Autocomplete = exports.Autocomplete = Montage.create(TextInput, { switch(code) { case KEY_DOWN: - if(popup.displayed == false) { + if(!popup.displayed) { popup.show(); this.activeItemIndex = 0; } else { @@ -470,7 +496,7 @@ var Autocomplete = exports.Autocomplete = Montage.create(TextInput, { break; case KEY_UP: - if(popup.displayed == true) { + if(popup.displayed === true) { if(this.activeItemIndex > 0) { this.activeItemIndex --; } else { @@ -481,10 +507,12 @@ var Autocomplete = exports.Autocomplete = Montage.create(TextInput, { break; case KEY_ENTER: - if(popup.displayed == true) { + if(popup.displayed === true) { this.resultsController.selectedIndexes = [this.activeItemIndex]; - //this.selectSuggestedValue(); + e.preventDefault(); // select the currently active item in the results list + } else { + this.suggestedValue = this.tokens[this.tokens.length-1]; } break; diff --git a/node_modules/montage/ui/autocomplete/result-item.reel/result-item.js b/node_modules/montage/ui/autocomplete/result-item.reel/result-item.js new file mode 100644 index 00000000..61b71afa --- /dev/null +++ b/node_modules/montage/ui/autocomplete/result-item.reel/result-item.js @@ -0,0 +1,33 @@ +/* + 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. +
*/ +var Montage = require("montage").Montage, + Component = require("ui/component").Component, + DynamicText = require("ui/dynamic-text.reel").DynamicText; + +exports.ResultItem = Montage.create(DynamicText, { + + textPropertyPath: {value: null}, + + _object: {value: null}, + object: { + get: function() { + return this._object; + }, + set: function(aValue) { + if(aValue) { + this._object = aValue; + } + if(this._object) { + if(this.textPropertyPath) { + this.value = this._object[this.textPropertyPath]; + } else { + this.value = this._object; + } + } + } + } + +}); diff --git a/node_modules/montage/ui/autocomplete/results-list.reel/results-list.html b/node_modules/montage/ui/autocomplete/results-list.reel/results-list.html index 73612736..2f904d62 100644 --- a/node_modules/montage/ui/autocomplete/results-list.reel/results-list.html +++ b/node_modules/montage/ui/autocomplete/results-list.reel/results-list.html @@ -32,12 +32,13 @@ }, "resultItem": { - "prototype": "montage/ui/dynamic-text.reel", + "prototype": "montage/ui/autocomplete/result-item.reel", "properties": { "element": {"#": "result-item"} }, "bindings": { - "value": {"<-": "@repetition1.objectAtCurrentIteration"} + "textPropertyPath": {"<-": "@owner.textPropertyPath"}, + "object": {"<-": "@repetition1.objectAtCurrentIteration"} } }, diff --git a/node_modules/montage/ui/autocomplete/results-list.reel/results-list.js b/node_modules/montage/ui/autocomplete/results-list.reel/results-list.js index 795e74e0..0950314d 100644 --- a/node_modules/montage/ui/autocomplete/results-list.reel/results-list.js +++ b/node_modules/montage/ui/autocomplete/results-list.reel/results-list.js @@ -7,10 +7,11 @@ var Montage = require("montage").Montage, Component = require("ui/component").Component; exports.ResultsList = Montage.create(Component, { - + + textPropertyPath: {value: null}, + // contentController -> this.repetition.contentController contentController: {value: null}, - - activeIndexes: {value: null} + activeIndexes: {value: null} }); diff --git a/node_modules/montage/ui/button.reel/button.js b/node_modules/montage/ui/button.reel/button.js index eead3124..9f1342f6 100644 --- a/node_modules/montage/ui/button.reel/button.js +++ b/node_modules/montage/ui/button.reel/button.js @@ -354,6 +354,12 @@ var Button = exports.Button = Montage.create(NativeControl, /** @lends module:"m this._element.classList.remove("disabled"); } + if (this._active) { + this._element.classList.add("active"); + } else { + this._element.classList.remove("active"); + } + this._drawLabel(this.label); } } diff --git a/node_modules/montage/ui/component-placeholder.reel/component-placeholder.js b/node_modules/montage/ui/component-placeholder.reel/component-placeholder.js deleted file mode 100755 index 784172e0..00000000 --- a/node_modules/montage/ui/component-placeholder.reel/component-placeholder.js +++ /dev/null @@ -1,146 +0,0 @@ -/* - 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. -
*/ -/** - @module "montage/ui/component-placeholder.reel" - @requires montage/core/core - @requires montage/ui/component - @requires core/logger -*/ -var Montage = require("montage").Montage; -var Component = require("ui/component").Component; -var logger = require("core/logger").logger("componentplaceholder"); -/** - @class module:"montage/ui/component-placeholder.reel".ComponentPlaceHolder - */ - -var ComponentPlaceHolder = exports.ComponentPlaceHolder = Montage.create(Component, /** @lends module:"montage/ui/component-placeholder.reel".ComponentPlaceHolder */ { - - hasTemplate: {value: false}, - - name: {value: null}, -/** - Description TODO - @private -*/ - _component: { - serializable: true, - enumerable: false, - value: null - }, -/** - Description TODO - @private -*/ - _prepareForDraw: {value: function() { - if (this.element) { - this._replaceElementWithTemplate(); - } - }}, -/** - Description TODO - @function - @returns this._component.draw.apply(this._component, arguments) - */ - draw: {value: function() { - return this._component.draw.apply(this._component, arguments); - }}, -/** - Description TODO - @type {Property} - @default {Boolean} true - */ - hasTemplate: { - value: true - }, - - // TODO: Remove when old serialization is gone - /** - Description TODO - @function - @param {Component} visitor The visitor component. - @param {Object} callback The callback object. - */ - traverseComponentTree: {value: function(visitor, callback) { - var self = this; - var innerComponent = this._component; - - if (this._isComponentExpanded) { - if (visitor) { - visitor(this); - } - this._component.traverseComponentTree.apply(this._component, arguments); - } else { - this.expandComponent(function() { - if (visitor) { - visitor(self); - } - self._component.traverseComponentTree(visitor, callback); - }); - } - }}, -/** - Description TODO - @private -*/ - _replaceElementWithTemplate: {value: function() { - var component = this._component, - element = this.element, - componentElement = component.element, - attributes = element.attributes, - attribute, attributeName, value; - - for (var i = 0; (attribute = attributes[i]); i++) { - attributeName = attribute.nodeName; - if (attributeName === "id") { - continue; - } - value = (componentElement.getAttribute(attributeName) || "") + " " + attribute.nodeValue; - componentElement.setAttribute(attributeName, value); - } - - element.parentNode.replaceChild(componentElement, element); - - this._element = null; - // check to see if the hosted component hasn't replaced its element yet, if not do it now. - if (component._templateElement) { - component._replaceElementWithTemplate(); - } - }}, - - // TODO: Add when old serialization is gone - //deserializedFromTemplate: {value: function() { - // this._component = this.parentComponent[this.name]; - //}}, - - // TODO: Remove when old serialization is gone -/** - Description TODO - @function - @param {Object} callback The callback object. - @returns self._component.loadComponentTree(callback) - */ - loadComponentTree: {value: function(callback) { - var self = this; - Component.loadComponentTree.call(this, function() { - self._component._cachedParentComponent = self._cachedParentComponent; - return self._component.loadComponentTree(callback); - }); - }}, - - // TODO: Remove when old serialization is gone - /** - Description TODO - @function - @param {Object} callback The callback object. - @returns this._component.expandComponent.apply(this._component, arguments) - */ - expandComponent: {value: function(callback) { - this._component = this.parentComponent[this.name]; - this._isComponentExpanded = true; - - return this._component.expandComponent.apply(this._component, arguments); - }} -}); diff --git a/node_modules/montage/ui/component.js b/node_modules/montage/ui/component.js index 9d963ada..8a8f5739 100755 --- a/node_modules/montage/ui/component.js +++ b/node_modules/montage/ui/component.js @@ -270,7 +270,7 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon aParentNode, eventManager = this.eventManager; if (anElement) { - while ((aParentNode = anElement.parentNode) !== null && eventManager.eventHandlerForElement(aParentNode) == null) { + while ((aParentNode = anElement.parentNode) != null && eventManager.eventHandlerForElement(aParentNode) == null) { anElement = aParentNode; } return aParentNode ? eventManager.eventHandlerForElement(aParentNode) : this._alternateParentComponent; @@ -539,6 +539,7 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon */ cleanupDeletedComponentTree: { value: function() { + Object.deleteBindings(this); this.needsDraw = false; this.traverseComponentTree(function(component) { Object.deleteBindings(component); @@ -551,12 +552,12 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon value: null }, - _newContent: { + _newDomContent: { enumerable: false, value: null }, - content: { + domContent: { get: function() { if (this._element) { return Array.prototype.slice.call(this._element.childNodes, 0); @@ -565,12 +566,16 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon } }, set: function(value) { - var components = [], - childNodes; + var components, + componentsToAdd = []; - this._newContent = value; + this._newDomContent = value; this.needsDraw = true; + if (this._newDomContent === null) { + this._shouldClearDomContentOnNextDraw = true; + } + if (typeof this.contentWillChange === "function") { this.contentWillChange(value); } @@ -584,7 +589,7 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon if (value instanceof Element) { findAndDetachComponents(value); - } else { + } else if (value) { for (var i = 0; i < value.length; i++) { findAndDetachComponents(value[i]); } @@ -596,7 +601,7 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon if (component) { component.detachFromParentComponent(); - components.push(component); + componentsToAdd.push(component); } else { var childNodes = node.childNodes; for (var i = 0, childNode; (childNode = childNodes[i]); i++) { @@ -606,12 +611,16 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon } // not sure if I can rely on _cachedParentComponent to detach the nodes instead of doing one loop for dettach and another to attach... - for (var i = 0, component; (component = components[i]); i++) { + for (var i = 0, component; (component = componentsToAdd[i]); i++) { this._addChildComponent(component); } } }, + _shouldClearDomContentOnNextDraw: { + value: false + }, + /** Description TODO @function @@ -988,7 +997,7 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon enumerable: false, value: function _drawIfNeeded(level) { var childComponent, - oldDrawList; + oldDrawList, i, childComponentListLength; this._treeLevel = level; if (this.needsDraw && !this._addedToDrawCycle) { rootComponent.addToDrawCycle(this); @@ -999,7 +1008,9 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon if (this._drawList !== null && this._drawList.length > 0) { oldDrawList = this._drawList; this._drawList = []; - while ((childComponent = oldDrawList.shift())) { + childComponentListLength = oldDrawList.length; + for (i = 0; i < childComponentListLength; i++) { + childComponent = oldDrawList[i]; if (drawLogger.isDebug) { drawLogger.debug("Parent Component " + (this.element != null ? this.element.id : "") + " drawList length: " + oldDrawList.length); } @@ -1014,6 +1025,44 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon } } }, + + _updateComponentDom: { + value: function() { + var component, composer, length, i; + if (this._firstDraw) { + + if (this.parentComponent && typeof this.parentComponent.childComponentWillPrepareForDraw === "function") { + this.parentComponent.childComponentWillPrepareForDraw(this); + } + + this._prepareForDraw(); + + if (this.prepareForDraw) { + this.prepareForDraw(); + } + + // Load any non lazyLoad composers that have been added + length = this.composerList.length; + for (i = 0; i < length; i++) { + composer = this.composerList[i]; + if (!composer.lazyLoad) { + composer._load(); + } + } + + // Will we expose a different property, firstDraw, for components to check + this._firstDraw = false; + } + + if (this._newDomContent !== null || this._shouldClearDomContentOnNextDraw) { + if (drawLogger.isDebug) { + logger.debug("Component content changed: component ", this._montage_metadata.objectName, this.identifier, " newDomContent", this._newDomContent); + } + this._performDomContentChanges(); + } + } + }, + /** Description TODO @private @@ -1042,7 +1091,11 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon template.setAttribute(attributeName, value); } - element.parentNode.replaceChild(template, element); + if (element.parentNode) { + element.parentNode.replaceChild(template, element); + } else { + console.warn("Warning: Trying to replace element ", element," which has no parentNode"); + } this.eventManager.unregisterEventHandlerForElement(element); this.eventManager.registerEventHandlerForElement(this, template); @@ -1108,31 +1161,30 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon Description TODO @private */ - _draw: { + _performDomContentChanges: { value: function() { - var contents = this._newContent, + var contents = this._newDomContent, + oldContent = this._element.childNodes[0], element; - this._canDrawTable = {}; - this._canDrawCount = 0; - - if (contents) { + if (contents || this._shouldClearDomContentOnNextDraw) { element = this._element; element.innerHTML = ""; if (contents instanceof Element) { element.appendChild(contents); - } else { + } else if(contents !== null) { for (var i = 0, content; (content = contents[i]); i++) { element.appendChild(content); } } - this._newContent = null; + this._newDomContent = null; if (typeof this.contentDidChange === "function") { - this.contentDidChange(); + this.contentDidChange(this._element.childNodes[0], oldContent); } + this._shouldClearDomContentOnNextDraw = false; } } }, @@ -1189,6 +1241,9 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon } else { parentComponent._addToDrawList(this); } + if (drawLogger.isDebug) { + drawLogger.debug("drawList -- childComponent",this._montage_metadata.objectName," added to ",parentComponent._montage_metadata.objectName); + } } } }, @@ -1390,10 +1445,12 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon */ clearAllComposers: { value: function() { - var composer; - while (composer = this.composerList.shift()) { - composer.unload(); + var i, length, composerList = this.composerList; + length = composerList.length; + for (i = 0; i < length; i++) { + composerList[i].unload(); } + composerList.splice(0, length); } } @@ -1515,13 +1572,16 @@ var rootComponent = Montage.create(Component, /** @lends module:montage/ui/compo */ _clearNeedsDrawList: { value: function() { - var component; - while ((component = this._needsDrawList.shift())) { + var component, i, length, needsDrawList = this._needsDrawList; + length = needsDrawList.length; + for (i = 0; i < length; i++) { + component = needsDrawList[i]; if (component.needsDraw) { component._addToParentsDrawList(); } } this._clearNeedsDrawTimeOut = null; + needsDrawList.splice(0, length); } }, /** @@ -1708,6 +1768,11 @@ var rootComponent = Montage.create(Component, /** @lends module:montage/ui/compo Description TODO @function */ + _previousDrawDate: { + enumerable: false, + value: 0 + }, + drawTree: { value: function drawTree() { if (this.requestedAnimationFrame === null) { // 0 is a valid requestedAnimationFrame value @@ -1757,8 +1822,16 @@ var rootComponent = Montage.create(Component, /** @lends module:montage/ui/compo if (requestAnimationFrame) { this.requestedAnimationFrame = requestAnimationFrame.call(window, _drawTree); } else { - //1000/17 = 60fps - this.requestedAnimationFrame = setTimeout(_drawTree, 16); + // Shim based in Erik Möller's code at + // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating + var currentDate = Date.now(), + miliseconds = 17 - currentDate + this._previousDrawDate; + + if (miliseconds < 0) { + miliseconds = 0; + } + this.requestedAnimationFrame = setTimeout(_drawTree, miliseconds); + this._previousDrawDate = currentDate + miliseconds; } this._scheduleComposerRequest = false; } @@ -1801,29 +1874,7 @@ var rootComponent = Montage.create(Component, /** @lends module:montage/ui/compo this._readyToDrawList.push(component); this._readyToDrawListIndex[component.uuid] = true; - if (component._firstDraw) { - - if (component.parentComponent && typeof component.parentComponent.childComponentWillPrepareForDraw === "function") { - component.parentComponent.childComponentWillPrepareForDraw(component); - } - - component._prepareForDraw(); - if (component.prepareForDraw) { - component.prepareForDraw(); - } - - // Load any non lazyLoad composers that have been added - length = component.composerList.length; - for (i = 0; i < length; i++) { - composer = component.composerList[i]; - if (!composer.lazyLoad) { - composer._load(); - } - } - - // Will we expose a different property, firstDraw, for components to check - component._firstDraw = false; - } + component._updateComponentDom(); } }, @@ -1835,18 +1886,21 @@ var rootComponent = Montage.create(Component, /** @lends module:montage/ui/compo drawIfNeeded:{ value: function drawIfNeeded() { var needsDrawList = this._readyToDrawList, component, i, j, start = 0, firstDrawEvent, - composerList = this.composerList, composer; + composerList = this.composerList, composer, composerListLength; needsDrawList.length = 0; + composerListLength = composerList.length; this._readyToDrawListIndex = {}; // Process the composers first so that any components that need to be newly drawn due to composer changes // get added in this cycle - if (composerList.length > 0) { + if (composerListLength > 0) { this.composerList = this.composerListSwap; // Swap between two arrays instead of creating a new array each draw cycle - while (composer = composerList.shift()) { + for (i = 0; i < composerListLength; i++) { + composer = composerList[i]; composer.needsFrame = false; composer.frame(this._frameTime); } + composerList.splice(0, composerListLength); this.composerListSwap = composerList; } @@ -1882,7 +1936,6 @@ var rootComponent = Montage.create(Component, /** @lends module:montage/ui/compo // TODO: add the possibility to display = "none" the body during development (IKXARIA-3631). for (i = j-1; i >= 0; i--) { component = needsDrawList[i]; - component._draw(); component.draw(this._frameTime); if (drawLogger.isDebug) { drawLogger.debug(component._montage_metadata.objectName, " draw treeLevel ",component._treeLevel); diff --git a/node_modules/montage/ui/composer/key-composer.js b/node_modules/montage/ui/composer/key-composer.js new file mode 100644 index 00000000..9d2c0f14 --- /dev/null +++ b/node_modules/montage/ui/composer/key-composer.js @@ -0,0 +1,385 @@ +/* + 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. +
*/ +/** + @module montage/ui/composer/key-composer + @requires montage + @requires montage/ui/composer/composer +*/ +var Montage = require("montage").Montage, + Composer = require("ui/composer/composer").Composer; + + +/** + @module montage/ui/composer/key-composer + */ + + +/* Event type dispatched by KeyComposer */ +var KEYPRESS_EVENT_TYPE = "keyPress", + LONGKEYPRESS_EVENT_TYPE = "longKeyPress", + KEYRELEASE_EVENT_TYPE = "keyRelease"; + + +/** + @class module:montage/ui/composer/key-composer.KeyComposer + @classdesc Create a virtual key composed of none or several key modifiers (shift, control, alt and meta) and one native key. + @extends module:montage/ui/composer/composer.Composer + */ +var KeyComposer = exports.KeyComposer = Montage.create(Composer, /** @lends module:montage/ui/composer/key-composer.KeyComposer# */ { + + /** + * @private + */ + _isLoaded: { + value: false + }, + + /** + * @private + */ + _shouldDispatchEvent: { + value: false + }, + + /** + * @private + */ + shouldDispatchLongPress: { + value: false + }, + + /** + @private + */ + _longPressTimeout: { + value: null + }, + + /** + * @private + */ + _keyRegistered: { + value: false + }, + + /** + * @private + */ + _keys:{ + value: null + }, + + /** + The sequence of keys to compose. + @type {string} + @default null + */ + keys: { + get: function() { + return this._keys; + }, + set: function(keys) { + if (this._keyRegistered) { + KeyManagerProxy.defaultKeyManager.unregisterKey(this); + this._keys = keys; + KeyManagerProxy.defaultKeyManager.registerKey(this); + } else { + this._keys = keys; + } + } + }, + + /** + * @private + */ + _identifier: { value: null }, + + /** + The keyComposer's identifier. + @type {string} + @default null + */ + identifier: { + get: function() { + return this._identifier; + }, + set: function(identifier) { + this._identifier = identifier; + } + }, + + /** + Create a ComposerKey. + The key will only dispatch events when the component's element is in the native key event target path. + If no identifier is provided, the keys and component's identifier will be used to generate an identifier. + Note: You do not have to call KeyComposer.create() before calling this method. + @function + @param {Object} component. The component to attach the keyComposer to. + @param {Object} keys. The key sequence. + @param {Object} identifier. The identifier. + @returns {Object} the newly created KeyComposer Object + */ + createKey: { + value: function(component, keys, identifier) { + var key = this; + + if (this === KeyComposer) { + // This function has been called without creating a new instance of KeyComposer first + key = KeyComposer.create(); + } + + if (!identifier) { + if (component.identifier) { + identifier = component.identifier + keys.toLowerCase().replace(/[ +]/g).toCapitalized(); + } else { + identifier = keys.toLowerCase().replace(/[ +]/g); + } + } + key.keys = keys; + key.identifier = identifier; + + // console.log("CREATING KEY:", component, key, key.identifier); + + component.addComposer(key); + + return key; + } + }, + + /** + Create a global composerKey. + A global key will dispatch events without requiring the component's element be in the native key event target path + If no identifier is provided, the keys and component's identifier will be used to generate an identifier. + Note: You do not have to call KeyComposer.create() before calling this method. + @function + @param {Object} component. The component to attach the keyComposer to. + @param {Object} keys. The key sequence. + @param {Object} identifier. The identifier. + @returns {Object} the newly created KeyComposer Object + */ + createGlobalKey: { + value: function(component, keys, identifier) { + var key = this; + + if (this === KeyComposer) { + // This function has been called without creating a new instance of KeyComposer first + key = KeyComposer.create(); + } + + key.keys = keys; + key.identifier = identifier; + // console.log("CREATING GLOBAL KEY:", component, key); + + component.addComposerForElement(key, window); + + return key; + } + }, + + /** + load method + @private + */ + load: { + value: function() { + // Only register the key if somebody is listening for, else let do it later + // console.log("--- load", this.identifier); + this._isLoaded = true; + if (this._shouldDispatchEvent && !this._keyRegistered) { + KeyManagerProxy.defaultKeyManager.registerKey(this); + this._keyRegistered = true; + } + } + }, + + /** + unload method + @private + */ + unload: { + value: function() { + this._isLoaded = false; + KeyManagerProxy.defaultKeyManager.unregisterKey(this); + this._keyRegistered = false; + } + }, + + /** + Add an event listener to the composerKey. + @function + @param {string} type. Any of the following types: keyPress, longKeyPress and keyRelease. + @param {Object|function} listener. The listener object or function to call when dispatching the event. + @param {boolean} useCapture. Specify if the listener want to be called during the capture phase of the event. + */ + addEventListener: { + value: function(type, listener, useCapture) { + // Optimisation so that we don't dispatch an event if we do not need to + // console.log("--- addEventListener", this.identifier); + var component = this.component; + + Composer.addEventListener.call(this, type, listener, useCapture); + + if (type == KEYPRESS_EVENT_TYPE || type == LONGKEYPRESS_EVENT_TYPE || type == KEYRELEASE_EVENT_TYPE) { + this._shouldDispatchEvent = true; + if (type == LONGKEYPRESS_EVENT_TYPE) { + this._shouldDispatchLongPress = true; + } + + if (this._isLoaded) { + if (!this._keyRegistered) { + KeyManagerProxy.defaultKeyManager.registerKey(this); + this._keyRegistered = true; + } + } else if (component && typeof component.addComposer !== "function") { + // this keyComposer is associated with an element, let's make it a global key + if (!this.element) { + this.element = window; + } + // this keyComposer is not attached to a UI Component, let's load it manually + this.load(); + } + } + } + }, + + /** + didCreate method + @private + */ + didCreate: { + value: function() { + // console.log("KEY CREATED") + } + }, + + /** + Called when a composer is part of a template serialization. It's responsible for calling addComposer on + the component or call load on the composer. + @private + */ + deserializedFromTemplate: { + value: function() { + var component = this.component; + + if (component) { + if (typeof component.addComposer == "function") { + component.addComposer(this); + } else if (!this._isLoaded) { + // this keyComposer is associated with an element, let's make it a global key + if (!this.element) { + this.element = window; + } + // this keyComposer is not attached to a UI Component, let's load it manually + this.load(); + } + } + } + } +}); + + +/** + @class KeyManagerProxy + @classdesc Provide a proxy for lazy load of module:montage/core/event/key-manager.KeyManager. + @extends module:montage + @private + */ +var _keyManagerProxy= null; + +var KeyManagerProxy = Montage.create(Montage, { + + /** + @private + */ + _defaultKeyManager: { + value: null + }, + + /** + @private + */ + _loadingDefaultKeyManager: { + value: false + }, + + /** + didCreate method + @private + */ + _keysToRegister : { + value: [] + }, + + /** + didCreate method + @private + */ + didCreate: { + value: function() { + // console.log("PROXY CREATED") + } + }, + + /** + Register a composerKey with the default KeyManager. + @function + @param {Object} keyComposer. A key composer object. + */ + registerKey: { + value: function(keyComposer) { + var thisRef = this; + + if (!this._defaultKeyManager) { + this._keysToRegister.push(keyComposer); + if (!this._loadingDefaultKeyManager) { + this._loadingDefaultKeyManager = true; + + require.async("core/event/key-manager", function(module) { + var keyManager = thisRef._defaultKeyManager = module.defaultKeyManager; + thisRef._keysToRegister.forEach(function(keyComposer) { + keyManager.registerKey(keyComposer); + }); + thisRef._keysToRegister.length = 0; + }); + } + } else { + // This will happend only if somebody uses a cached return value from KeyManagerProxy.defaultKeyManager + this._defaultKeyManager.registerKey(keyComposer); + } + } + }, + + /** + Unregister a composerKey with the default KeyManager. + @function + @param {Object} keyComposer. A key composer object. + */ + unregisterKey: { + value: function(keyComposer) { + if (this._defaultKeyManager) { + this._defaultKeyManager.unregisterKey(keyComposer); + } + } + }, + + /** + Return either the default KeyManager or its KeyManagerProxy. + @function + @returns {Object} KeyManager or KeyManagerProxy. + */ + defaultKeyManager: { + get: function() { + if (!_keyManagerProxy) { + _keyManagerProxy = KeyManagerProxy.create(); + } + if (this._defaultKeyManager) { + return this._defaultKeyManager; + } else { + return _keyManagerProxy; + } + } + } +}); diff --git a/node_modules/montage/ui/composer/translate-composer.js b/node_modules/montage/ui/composer/translate-composer.js index 86e6fb09..13e01207 100644 --- a/node_modules/montage/ui/composer/translate-composer.js +++ b/node_modules/montage/ui/composer/translate-composer.js @@ -34,6 +34,11 @@ var TranslateComposer = exports.TranslateComposer = Montage.create(Composer,/** ] }, + _WHEEL_POINTER: { + value: "wheel", + writable: false + }, + _externalUpdate: { enumerable: false, value: true @@ -388,6 +393,10 @@ var TranslateComposer = exports.TranslateComposer = Montage.create(Composer,/** value: 500 }, + startTranslateRadius: { + value: 8 + }, + _hasMomentum: { enumerable: false, value: true @@ -513,7 +522,7 @@ var TranslateComposer = exports.TranslateComposer = Montage.create(Composer,/** handleMousedown: { enumerable: false, value: function(event) { - if (event.button === 0 && !this.eventManager.componentClaimingPointer(this._observedPointer, this)) { + if (event.button === 0 && !this.eventManager.componentClaimingPointer(this._observedPointer)) { this.eventManager.claimPointer(this._observedPointer, this); this._start(event.clientX, event.clientY, event.target); } @@ -529,7 +538,13 @@ var TranslateComposer = exports.TranslateComposer = Montage.create(Composer,/** event.preventDefault(); this._move(event.clientX, event.clientY); } else { - this._analyzeMovement(event.velocity); + if (this.axis !== "both") { + this._analyzeMovement(event); + } else { + this._stealPointer(); + event.preventDefault(); + this._move(event.clientX, event.clientY); + } } } @@ -609,7 +624,7 @@ var TranslateComposer = exports.TranslateComposer = Montage.create(Composer,/** event.preventDefault(); this._move(event.changedTouches[i].clientX, event.changedTouches[i].clientY); } else { - this._analyzeMovement(event.changedTouches[i].velocity); + this._analyzeMovement(event.changedTouches[i]); } } @@ -630,7 +645,8 @@ var TranslateComposer = exports.TranslateComposer = Montage.create(Composer,/** }, _analyzeMovement: { - value: function(velocity) { + value: function(event) { + var velocity = event.velocity; if (!velocity) { return; @@ -642,7 +658,8 @@ var TranslateComposer = exports.TranslateComposer = Montage.create(Composer,/** upperRight = -0.7853981633974483, // 7pi/4 isUp, isDown, isRight, isLeft, angle, - speed; + speed, + dX, dY; speed = velocity.speed; @@ -674,6 +691,12 @@ var TranslateComposer = exports.TranslateComposer = Montage.create(Composer,/** } else if (speed >= this.startTranslateSpeed) { this._stealPointer(); + } else { + dX = this.pointerStartEventPosition.pageX - event.pageX; + dY = this.pointerStartEventPosition.pageY - event.pageY; + if (dX * dX + dY * dY > this.startTranslateRadius * this.startTranslateRadius) { + this._stealPointer(); + } } } @@ -690,25 +713,37 @@ var TranslateComposer = exports.TranslateComposer = Montage.create(Composer,/** value: null }, + captureMousewheel: { + value: function(event) { + if (!this.eventManager.componentClaimingPointer(this._WHEEL_POINTER)) { + this.eventManager.claimPointer(this._WHEEL_POINTER, this.component); + } + } + }, + handleMousewheel: { enumerable: false, value: function(event) { var self = this; - var oldTranslateY = this._translateY; - this._dispatchTranslateStart(); - this.translateY = this._translateY - ((event.wheelDeltaY * 20) / 120); - this._dispatchTranslate(); - window.clearTimeout(this._translateEndTimeout); - this._translateEndTimeout = window.setTimeout(function() { - self._dispatchTranslateEnd(); - }, 400); - - // If we're not at one of the extremes (i.e. the scroll actully - // changed the translate) then we want to preventDefault to stop - // the page scrolling. - if (oldTranslateY !== this._translateY) { - event.preventDefault(); + // If this composers' component is claiming the "wheel" pointer then handle the event + if (this.eventManager.isPointerClaimedByComponent(this._WHEEL_POINTER, this.component)) { + var oldTranslateY = this._translateY; + this._dispatchTranslateStart(); + this.translateY = this._translateY - ((event.wheelDeltaY * 20) / 120); + this._dispatchTranslate(); + window.clearTimeout(this._translateEndTimeout); + this._translateEndTimeout = window.setTimeout(function() { + self._dispatchTranslateEnd(); + }, 400); + + // If we're not at one of the extremes (i.e. the scroll actually + // changed the translate) then we want to preventDefault to stop + // the page scrolling. + if (oldTranslateY !== this._translateY && this._shouldPreventDefault(event)) { + event.preventDefault(); + } + this.eventManager.forfeitPointer(this._WHEEL_POINTER, this.component); } } }, @@ -743,11 +778,6 @@ var TranslateComposer = exports.TranslateComposer = Montage.create(Composer,/** } }, - _animationInterval: { - enumerable: false, - value: false - }, - _bezierTValue: { enumerable: false, value: function(x, p1x, p1y, p2x, p2y) { @@ -804,68 +834,117 @@ var TranslateComposer = exports.TranslateComposer = Montage.create(Composer,/** } }, + animateBouncingX: {value: false, enumerable: false}, + startTimeBounceX: {value: false, enumerable: false}, + animateBouncingY: {value: false, enumerable: false}, + startTimeBounceY: {value: false, enumerable: false}, + animateMomentum: {value: false, enumerable: false}, + startTime: {value: null, enumerable: false}, + startX: {value: null, enumerable: false}, + posX: {value: null, enumerable: false}, + endX: {value: null, enumerable: false}, + startY: {value: null, enumerable: false}, + posY: {value: null, enumerable: false}, + endY: {value: null, enumerable: false}, - _end: { - enumerable: false, - value: function(event) { + translateStrideX: { + value: null + }, - var animateMomentum=false, - momentumX, - momentumY, - startX = this._translateX, - startY = this._translateY, - posX = startX, - posY = startY, - endX = startX, - endY = startY, - self=this, - startTime=Date.now(); - - if ((this._hasMomentum) && (event.velocity.speed > 40)) { - if (this._axis != "vertical") { - momentumX = event.velocity.x * this._pointerSpeedMultiplier * (this._invertXAxis ? 1 : -1); + translateStrideY: { + value: null + }, + + translateStrideDuration: { + value: 330 + }, + + _animationInterval: { + value: function () { + var time = Date.now(), t, tmp, tmpX, tmpY, animateStride = false; + + if (this.animateMomentum) { + t=time-this.startTime; + if (t 0)) { + if (time - this.startStrideXTime < this.translateStrideDuration) { + t = this._bezierTValue((time - this.startStrideXTime) / this.translateStrideDuration, .275, 0, .275, 1); + this.posX = this.posX * (1 - t) + (tmp * this.translateStrideX) * t; + animateStride = true; } else { - momentumY = 0; + this.posX = tmp * this.translateStrideX; } - endX = startX - (momentumX * this.__momentumDuration / 2000); - endY = startY - (momentumY * this.__momentumDuration / 2000); - animateMomentum = true; - } - - this._animationInterval = function() { - var time = Date.now(), - t, tmpX, tmpY; - - if (animateMomentum) { - t = time - startTime; - if (t < self.__momentumDuration) { - posX = startX - ((momentumX + momentumX * (self.__momentumDuration - t) / self.__momentumDuration) * t / 1000) / 2; - posY = startY - ((momentumY + momentumY * (self.__momentumDuration - t) / self.__momentumDuration) * t / 1000) / 2; - } else { - animateMomentum = false; - } + } + tmp = Math.round(this.endY / this.translateStrideY); + if (this.startStrideYTime && (time - this.startStrideYTime > 0)) { + if (time - this.startStrideYTime < this.translateStrideDuration) { + t = this._bezierTValue((time - this.startStrideYTime) / this.translateStrideDuration, .275, 0, .275, 1); + this.posY = this.posY * (1 - t) + (tmp * this.translateStrideY) * t; + animateStride = true; + } else { + this.posY = tmp * this.translateStrideY; } + } + tmpX = this.posX; + tmpY = this.posY; + this._isSelfUpdate=true; + this.translateX=tmpX; + this.translateY=tmpY; + this._isSelfUpdate=false; + this.isAnimating = this.animateMomentum || animateStride; + if (this.isAnimating) { + this.needsFrame=true; + } else { + this._dispatchTranslateEnd(); + } + }, + enumerable: false + }, + + + _end: { + enumerable: false, + value: function (event) { + + this.startTime=Date.now(); - tmpX = posX; - tmpY = posY; + this.endX = this.posX = this.startX=this._translateX; + this.endY=this.posY=this.startY=this._translateY; - self._isSelfUpdate = true; - self.translateX = tmpX; - self.translateY = tmpY; - self._isSelfUpdate = false; - self.isAnimating = animateMomentum; - if (self.isAnimating) { - self.needsFrame = true; + if ((this._hasMomentum) && ((event.velocity.speed>40) || this.translateStrideX || this.translateStrideY)) { + if (this._axis != "vertical") { + this.momentumX = event.velocity.x * this._pointerSpeedMultiplier * (this._invertXAxis ? 1 : -1); } else { - this._dispatchTranslateEnd(); + this.momentumX = 0; } - }; - if (animateMomentum) { + if (this._axis != "horizontal") { + this.momentumY = event.velocity.y * this._pointerSpeedMultiplier * (this._invertYAxis ? 1 : -1); + } else { + this.momentumY=0; + } + this.endX = this.startX - (this.momentumX * this.__momentumDuration / 2000); + this.endY = this.startY - (this.momentumY * this.__momentumDuration / 2000); + this.startStrideXTime = null; + this.startStrideYTime = null; + this.animateMomentum = true; + } else { + this.animateMomentum = false; + } + + if (this.animateMomentum) { this._animationInterval(); } else if (!this._isFirstMove) { // Only dispatch a translateEnd if a translate start has occured @@ -896,6 +975,7 @@ var TranslateComposer = exports.TranslateComposer = Montage.create(Composer,/** this._element.addEventListener("mousedown", this, true); this._element.addEventListener("mousedown", this, false); this._element.addEventListener("mousewheel", this, false); + this._element.addEventListener("mousewheel", this, true); } this.eventManager.isStoringPointerEvents = true; diff --git a/node_modules/montage/ui/condition.reel/condition.js b/node_modules/montage/ui/condition.reel/condition.js index bcb0e957..7553c14f 100755 --- a/node_modules/montage/ui/condition.reel/condition.js +++ b/node_modules/montage/ui/condition.reel/condition.js @@ -12,7 +12,6 @@ */ var Montage = require("montage").Montage, Component = require("ui/component").Component, - Slot = require("ui/slot.reel").Slot, logger = require("core/logger").logger("condition"); /** @class module:"montage/ui/condition.reel".Condition @@ -53,11 +52,12 @@ exports.Condition = Montage.create(Component, /** @lends module:"montage/ui/cond this._condition = value; this.needsDraw = true; - if (this.removalStrategy === "remove") { + // If it is being deserialized originalContent has not been populated yet + if (this.removalStrategy === "remove" && !this.isDeserializing) { if (value) { - this._slot.content = this.content; + this.domContent = this.originalContent; } else { - this._slot.content = null; + this.domContent = null; } } }, @@ -65,42 +65,6 @@ exports.Condition = Montage.create(Component, /** @lends module:"montage/ui/cond return this._condition; } }, -/** - Description TODO - @private -*/ - _content: { - enumerable: false, - value: null - }, -/** - Description TODO - @type {Function} - @default null - */ - content: { - enumerable: false, - get: function() { - return this._content; - }, - set: function(value) { - if (this._content === value) { - return; - } - - this._content = value; - this.needsDraw = true; - - if (this.removalStrategy === "remove") { - if (this.condition) { - this._slot.content = va