From a3024011a91d3941f81481dd4d600e9684eb0fd4 Mon Sep 17 00:00:00 2001 From: Valerio Virgillito Date: Thu, 2 Feb 2012 00:11:51 -0800 Subject: upgrading to Montage v0.6 Signed-off-by: Valerio Virgillito --- node_modules/montage/ui/component.js | 292 +++++++++++++++++++++++++++++++++-- 1 file changed, 278 insertions(+), 14 deletions(-) (limited to 'node_modules/montage/ui/component.js') diff --git a/node_modules/montage/ui/component.js b/node_modules/montage/ui/component.js index 30d59c22..90612f83 100755 --- a/node_modules/montage/ui/component.js +++ b/node_modules/montage/ui/component.js @@ -395,9 +395,12 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon @function @param {Component} childComponent The childComponent */ - addChildComponent: { + _addChildComponent: { value: function(childComponent) { - this.childComponents.push(childComponent); + if (this.childComponents.indexOf(childComponent) == -1) { + this.childComponents.push(childComponent); + childComponent._cachedParentComponent = this; + } } }, /** @@ -405,10 +408,23 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon @function */ attachToParentComponent: { + value: function() { + this._cachedParentComponent = null; + + var parentComponent = this.parentComponent; + + if (parentComponent) { + parentComponent._addChildComponent(this); + } + } + }, + + detachFromParentComponent: { value: function() { var parentComponent = this.parentComponent; + if (parentComponent) { - parentComponent.addChildComponent(this); + parentComponent.removeChildComponent(this); } } }, @@ -425,6 +441,7 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon if (ix > -1) { childComponents.splice(ix, 1); + childComponent._cachedParentComponent = null; } if (element && element.parentNode) { @@ -479,6 +496,85 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon enumerable: false, value: null }, + + /** + * Remove all bindings and starts buffering the needsDraw. + * @function + */ + cleanupDeletedComponentTree: { + value: function() { + this.needsDraw = false; + this.traverseComponentTree(function(component) { + Object.deleteBindings(component); + component.canDrawGate.setField("componentTreeLoaded", false); + component.blockDrawGate.setField("element", false); + component.blockDrawGate.setField("drawRequested", false); + component.needsDraw = false; + }); + } + }, + + originalContent: { + value: null + }, + + _newContent: { + enumerable: false, + value: null + }, + + content: { + get: function() { + return Array.prototype.slice.call(this._element.childNodes, 0); + }, + set: function(value) { + var components = [], + childNodes; + + this._newContent = value; + this.needsDraw = true; + + if (typeof this.contentWillChange === "function") { + this.contentWillChange(value); + } + + // cleanup current content + components = this.childComponents; + for (var i = 0, component; (component = components[i]); i++) { + component.detachFromParentComponent(); + component.cleanupDeletedComponentTree(); + } + + if (value instanceof Element) { + findAndDetachComponents(value); + } else { + for (var i = 0; i < value.length; i++) { + findAndDetachComponents(value[i]); + } + } + + // find the component fringe and detach them from the component tree + function findAndDetachComponents(node) { + var component = node.controller; + + if (component) { + component.detachFromParentComponent(); + components.push(component); + } else { + var childNodes = node.childNodes; + for (var i = 0, childNode; (childNode = childNodes[i]); i++) { + findAndDetachComponents(childNode); + } + } + } + + // 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++) { + this._addChildComponent(component); + } + } + }, + /** Description TODO @function @@ -486,6 +582,9 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon deserializedFromSerialization: { value: function() { this.attachToParentComponent(); + if (this._element) { + this.originalContent = Array.prototype.slice.call(this._element.childNodes, 0); + } } }, @@ -892,11 +991,13 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon // TODO: get a spec for this, what attributes should we merge? for (i = 0; (attribute = attributes[i]); i++) { attributeName = attribute.nodeName; - if (attributeName === "id") { + if (attributeName === "id" || attributeName === "data-montage-id") { continue; + } else { + value = (template.getAttribute(attributeName) || "") + " " + + attribute.nodeValue; } - value = (template.getAttribute(attributeName) || "") + " " + - attribute.nodeValue; + template.setAttribute(attributeName, value); } @@ -921,7 +1022,10 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon if (this._templateElement) { this._replaceElementWithTemplate(); } - this._element.removeAttribute("id"); + // TODO: removeAttribute only here for backwards compatibility + if (!this._element.getAttribute("data-montage-id")) { + this._element.removeAttribute("id"); + } // This will schedule a second draw for any component that has children var childComponents = this.childComponents; @@ -949,8 +1053,30 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon */ _draw: { value: function() { + var contents = this._newContent, + element; + this._canDrawTable = {}; this._canDrawCount = 0; + + if (contents) { + element = this._element; + + element.innerHTML = ""; + + if (contents instanceof Element) { + element.appendChild(contents); + } else { + for (var i = 0, content; (content = contents[i]); i++) { + element.appendChild(content); + } + } + + this._newContent = null; + if (typeof this.contentDidChange === "function") { + this.contentDidChange(); + } + } } }, /** @@ -1134,10 +1260,101 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon value: function(pointer, demandingComponent) { return true; } + }, + + // Composers + /* + Variable to track this component's associated composers + @private + */ + composerList: { + value: [], + distinct: true + }, + + /** + Adds the passed in composer to the component's composer list. + @function + @param {Composer} composer Composer object + */ + addComposer: { // What if the same composer instance is added to more than one component? + value: function(composer) { + this.addComposerForElement(composer, composer.element); + } + }, + + /** + Adds the passed in composer to the component's composer list and + sets the element of the composer to the passed in element. + @function + @param {Composer} composer Composer object + @param {Element} element Element + */ + addComposerForElement: { + value: function(composer, element) { + composer.component = this; + composer.element = element; + this.composerList.push(composer); + + if (!this._firstDraw) { // prepareForDraw has already happened so do the loading here + composer._load(); + } + } + }, + + /** + Adds the passed in composer to the list of composers which will have their + frame method called during the next draw cycle. It causes a draw cycle to be scheduled + iff one has not already been scheduled. + @function + @param {Composer} composer Composer object + */ + scheduleComposer: { + value: function(composer) { + this.rootComponent.addToComposerList(composer); + } + }, + + /** + Removes the passed in composer from this component's composer list. It takes care + of calling the composers unload method before removing it from the list. + @function + @param {Composer} composer Composer object + */ + removeComposer: { + value: function(composer) { + var i, length; + length = this.composerList.length; + for (i = 0; i < length; i++) { + if (this.composerList[i].uuid === composer.uuid) { + this.composerList[i].unload(); + this.composerList.splice(i, 1); + break; + } + } + } + }, + + /** + A convenience method for removing all composers from a component. This method + is responsible for calling unload on each composer before removing it. + @function + */ + clearAllComposers: { + value: function() { + var length, i; + length = this.composerList.length; + for (i = 0; i < length; i++) { + this.composerList[i].unload(); + } + this.composerList = []; + } } }); + + /* @extends montage/ui/component.Component */ /** * @class module:montage/ui/component.RootComponent @@ -1315,6 +1532,36 @@ var rootComponent = Montage.create(Component, /** @lends module:montage/ui/compo enumerable: false }, + /** + * Adds the passed in composer to the list of composers to be executed + * in the next draw cycle and requests a draw cycle iff one has not been + * requested yet. + * @private + * @function + * @param {Composer} composer Composer object + */ + addToComposerList: { + value: function(composer) { + this.composerList.push(composer); + if (drawLogger.isDebug) { + drawLogger.debug(this, composer, "Added to composer list"); + } + // If a draw is already in progress this.drawTree() will not schedule another one, so track + // that a composer requested a draw in case a new draw does need to be scheduled when the + // current loop is done + this._scheduleComposerRequest = true; + this.drawTree(); + } + }, + + /* + Flag to track if a composer is requesting a draw + @private + */ + _scheduleComposerRequest: { + value: false + }, + /** The value returned by requestAnimationFrame.
If a request has been scheduled but not run yet, else null. @@ -1377,6 +1624,9 @@ var rootComponent = Montage.create(Component, /** @lends module:montage/ui/compo console.groupEnd(); } self._frameTime = null; + if (self._scheduleComposerRequest) { + self.drawTree(); + } }; if (requestAnimationFrame) { this.requestedAnimationFrame = requestAnimationFrame.call(window, _drawTree); @@ -1384,6 +1634,7 @@ var rootComponent = Montage.create(Component, /** @lends module:montage/ui/compo //1000/17 = 60fps this.requestedAnimationFrame = setTimeout(_drawTree, 16); } + this._scheduleComposerRequest = false; } }, enumerable: false @@ -1420,7 +1671,7 @@ var rootComponent = Montage.create(Component, /** @lends module:montage/ui/compo */ addToDrawCycle: { value: function(component) { - var needsDrawListIndex = this._readyToDrawListIndex; + var needsDrawListIndex = this._readyToDrawListIndex, length; if (needsDrawListIndex.hasOwnProperty(component.uuid)) { // Requesting a draw of a component that has already been drawn in the current cycle @@ -1442,6 +1693,13 @@ var rootComponent = Montage.create(Component, /** @lends module:montage/ui/compo if (component.prepareForDraw) { component.prepareForDraw(); } + + // Load any composers that have been added + length = component.composerList.length; + for (i = 0; i < length; i++) { + component.composerList[i]._load(); + } + // Will we expose a different property, firstDraw, for components to check component._firstDraw = false; } @@ -1450,19 +1708,25 @@ var rootComponent = Montage.create(Component, /** @lends module:montage/ui/compo /** - We set display:none on the body so that we cannot inadvertently cause a repaint.
@function @returns !!needsDrawList.length */ - /* TODO: Simplify this method if we are going to stick with needsDraw being called within a draw cycle always scheduling another draw.
- Instead it should probably be changed to draw newly requested components in the same cycle, but schedule a new cycle for any components that have already been drawn once in the cycle and are requesting to be drawn again. */ drawIfNeeded:{ value: function drawIfNeeded() { - var body = this.element.body, - needsDrawList = this._readyToDrawList, component; - var j, i, start = 0, firstDrawEvent; + var needsDrawList = this._readyToDrawList, component, j, i, start = 0, firstDrawEvent, + composerList = this.composerList, composer, length; needsDrawList.length = 0; this._readyToDrawListIndex = {}; + this.composerList = []; + + // Process the composers first so that any components that need to be newly drawn due to composer changes + // get added in this cycle + length = composerList.length; + for (i = 0; i < length; i++) { + composer = composerList[i]; + composer.needsFrame = false; + composer.frame(this._frameTime); + } this._drawIfNeeded(); j = needsDrawList.length; -- cgit v1.2.3