render.js
来自「echo3 很炫的ajax框架技术 js 演示demo ajax j2ee 里」· JavaScript 代码 · 共 713 行 · 第 1/2 页
JS
713 行
/** * @namespace * Module for rendering state of application to DOM. * <ul> * <li>Provides capability to process updates in Application UpdateManager, * rendering state changes to the DOM.</li> * <li>Provides component synchronization peer base class.</li> * <li>Provides root component synchronization peer implementation.</li> * <li>Provides rendering utilities for the core properties.</li> * </ul> * * <h3>renderContext</h3> * * <p>This object will add a <code>renderContext</code> property to all <code>Echo.Update.ComponentUpdate</code> * objects which are processed by it. *//** * Application rendering namespace. * @namespace */Echo.Render = { /** * Count of loaded/unloaded peers. Used for testing purposes to ensure peers are not being leaked. * @type Number */ _loadedPeerCount: 0, /** * Next sequentially assigned unique peer identifier. * @type Number */ _nextPeerId: 0, /** * Mapping between component type names and instantiable peer classes. */ _peers: {}, /** * Map containing removed components. Maps component ids to removed components. * Created and destroyed during each render. */ _disposedComponents: null, /** * An array sorting implementation to organize an array by component depth. * @see Array#sort */ _componentDepthArraySort: function(a, b) { return Echo.Render._getComponentDepth(a.parent) - Echo.Render._getComponentDepth(b.parent); }, /** * Recursively invokes renderDisplay() method on a sub-hierarchy of the * component hierarchy. If a peer does not provide a renderDisplay() implementation, * it is skipped (although its descendants will NOT be skipped). * * @param {Echo.Component} the root component of the sub-hierarchy on which renderDisplay() should be invoked * @param {Boolean} includeSelf flag indicating whether renderDisplay() should be invoked on the * specified component (if false, it will only be invoked on child components) */ _doRenderDisplay: function(component, includeSelf) { if (includeSelf) { Echo.Render._doRenderDisplayImpl(component); } else { for (var i = 0; i < component.children.length; ++i) { Echo.Render._doRenderDisplayImpl(component.children[i]); } } }, /** * Recursive work method for _doRenderDisplay(). * * @param {Echo.Component} component the component on which to invoke renderDisplay() */ _doRenderDisplayImpl: function(component) { if (component.peer) { // components that are present on the client, but are not rendered (lazy rendered as in tree), // have no peer installed. if (component.peer.renderDisplay) { component.peer.renderDisplay(); } for (var i = 0; i < component.children.length; ++i) { Echo.Render._doRenderDisplayImpl(component.children[i]); } } }, /** * Returns the depth of a specific component in the hierarchy. * The root component is at depth 0, its immediate children are * at depth 1, their children are at depth 2, and so on. * * @param {Echo.Component} component the component whose depth is to be calculated * @return the depth of the component * @type Number */ _getComponentDepth: function(component) { var depth = -1; while (component != null) { component = component.parent; ++depth; } return depth; }, /** * Creates a component synchronization peer for a component. * The peer will be stored in the "peer" property of the component. * The client will be stored in the "client" property of the component. * * @param {Echo.Client} client the relevant Client * @param {Echo.Component} component the component */ _loadPeer: function(client, component) { if (component.peer) { // If peer already loaded, do nothing. return; } var peerClass = Echo.Render._peers[component.componentType]; if (!peerClass) { throw new Error("Peer not found for: " + component.componentType); } ++this._loadedPeerCount; component.peer = new peerClass(); component.peer._peerId = this._nextPeerId++; component.peer.component = component; component.peer.client = client; }, /** * Notifies child components that the parent component has been drawn * or resized. At this point the parent component is on the screen * (the parent element is part of the DOM hierarchy). * Child components (and their descendants) will be notified by having * their renderDisplay() implementations invoked. * Note that the parent WILL NOT have its renderDisplay() method * invoked. * <p> * If your component requires virtual positioning (for IE6) you should invoke * this method after informing the virtual positioning system to recalculate * the size of your component. * * @param {Echo.Component} parent the component whose size changed */ notifyResize: function(parent) { Echo.Render._doRenderDisplay(parent, false); }, /** * Invokes renderDispose() on all removed children and descendants found in the specified update. * * @param {Echo.Update.ComponentUpdate} update the update */ _processDispose: function(update) { var i, components = update.getRemovedDescendants(); if (components) { for (i = 0; i < components.length; ++i) { Echo.Render._renderComponentDisposeImpl(update, components[i]); } } components = update.getRemovedChildren(); if (components) { for (i = 0; i < components.length; ++i) { Echo.Render._renderComponentDisposeImpl(update, components[i]); } } }, /** * Processes all pending updates in the client's application's update manager. * * @param {Echo.Client} client the client */ processUpdates: function(client) { var updateManager = client.application.updateManager; // Do nothing if no updates exist. if (!updateManager.hasUpdates()) { return; } // Create map to contain removed components (for peer unloading). Echo.Render._disposedComponents = {}; // Retrieve updates, sorting by depth in hierarchy. This will ensure that higher // level updates have a chance to execute first, in case they null out lower-level // updates if they require re-rendering their descendants. var updates = updateManager.getUpdates(); updates.sort(Echo.Render._componentDepthArraySort); var peer, i, j; // Load peers for any new root components being updated. for (i = 0; i < updates.length; ++i) { updates[i].renderContext = {}; peer = updates[i].parent.peer; if (peer == null && updates[i].parent.componentType == "Root") { Echo.Render._loadPeer(client, updates[i].parent); } } // Remove Phase: Invoke renderDispose on all updates. for (i = updates.length - 1; i >= 0; --i) { if (updates[i] == null) { // Skip removed updates. continue; } peer = updates[i].parent.peer; Echo.Render._processDispose(updates[i]); } // Profiling: Mark completion of remove phase. if (Echo.Client.profilingTimer) { Echo.Client.profilingTimer.mark("rem"); } // Update Phase: Invoke renderUpdate on all updates. for (i = 0; i < updates.length; ++i) { if (updates[i] == null) { // The update has been removed, skip it. continue; } // Obtain component synchronization peer. peer = updates[i].parent.peer; // Perform update by invoking peer's renderUpdate() method. var fullRender = peer.renderUpdate(updates[i]); // If the update required re-rendering descendants of the updated component, // null-out any pending updates to descendant components. if (fullRender) { for (j = i + 1; j < updates.length; ++j) { if (updates[j] != null && updates[i].parent.isAncestorOf(updates[j].parent)) { updates[j] = null; } } } // Invoke _setPeerDisposedState() to ensure that peer is marked as non-disposed. // (A full-re-render may have invoked renderComponentDispose()). Echo.Render._setPeerDisposedState(updates[i].parent, false); } // Profiling: Mark completion of update phase. if (Echo.Client.profilingTimer) { Echo.Client.profilingTimer.mark("up"); } // Display Phase: Invoke renderDisplay on all updates. // The "displayed" array holds component who have already had renderDisplay() invoked on themselves (and their descendants). // This is done to avoid invoking renderDisplay() multiple times on a single component during a single rendering. var displayed = []; for (i = 0; i < updates.length; ++i) { if (updates[i] == null) { // Skip removed updates. continue; } // Determine if component hierarchy has already had renderDisplay() invoked, skipping to next update if necessary. var cancelDisplay = false; for (j = 0; j < displayed.length; ++j) { if (displayed[j].isAncestorOf(updates[i].parent)) { cancelDisplay = true; break; } } if (cancelDisplay) { continue; } if (updates[i].renderContext.displayRequired) { // The renderContext has specified only certain child components should have their // renderDisplay() methods invoked. for (j = 0; j < updates[i].renderContext.displayRequired.length; ++j) { displayed.push(updates[i].renderContext.displayRequired[j]); Echo.Render._doRenderDisplay(updates[i].renderContext.displayRequired[j], true); } } else { displayed.push(updates[i].parent); Echo.Render._doRenderDisplay(updates[i].parent, true); } } // Profiling: Mark completion of display phase. if (Echo.Client.profilingTimer) { Echo.Client.profilingTimer.mark("disp"); } // Unload peers for truly removed components, destroy mapping. for (var peerId in Echo.Render._disposedComponents) { var component = Echo.Render._disposedComponents[peerId]; Echo.Render._unloadPeer(component); } // Clear disposed component list. Echo.Render._disposedComponents = null; // Inform UpdateManager that all updates have been completed. updateManager.purge(); // Perform focus update. Echo.Render.updateFocus(client); }, /** * Registers a component type name with an instantiable peer class. * Components of the specified type name will be assigned new instances of the peer class * when rendered for the first time. * * @param {String} componentName the component type name * @param {Function} peerObject the peer class object */ registerPeer: function(componentName, peerObject) { if (this._peers[componentName]) { throw new Error("Peer already registered: " + componentName); } this._peers[componentName] = peerObject; }, /** * Renders a new component inside of a DOM element. * This method should be called by container components in order to render their children. * * @param {Echo.Update.ComponentUpdate} update the relevant ComponentUpdate * @param {Echo.Component} component the component to add * @param {Element} parentElement the DOM element to which the rendered component should be added */ renderComponentAdd: function(update, component, parentElement) { if (!component.parent || !component.parent.peer || !component.parent.peer.client) { throw new Error("Cannot find reference to the Client with which this component should be associated: " + "cannot load peer. This is due to the component's parent's peer not being associated with a Client. " + "Component = " + component); } Echo.Render._loadPeer(component.parent.peer.client, component); Echo.Render._setPeerDisposedState(component, false); component.peer.renderAdd(update, parentElement); }, /** * Manually invokes renderDisplay on a component (and its descendants) that was added to the * hierarchy outside of processUpdates(). This method is only used in special cases, * e.g., by in the case of Application Rendered Components that need to render children. * * @param {Echo.Component} parent the parent component of the sub-hierarchy on which renderDisplay() should * be invoked (note that renderDisplay WILL be invoked on the parent as well * as its descendants)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?