📄 render.js
字号:
/** * @fileoverview * 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> *//** * @class Application rendering namespace. Non-instantiable object. */EchoRender = { /** * Mapping between component type names and instantiable peer classes. * * @type Object * @private */ _peers: {}, /** * Map containing removed components. Maps component ids to removed components. * Created and destroyed during each render. * * @type Object * @private */ _disposedComponents: null, //FIXME. Scrollbar position tracking code in SplitPane appears to suggest that // disposed states are not in good shape....SplitPane is being disposed when // parent contentPane is redrawn. /** * An array sorting implemention to organize an array by component depth. * @private */ _componentDepthArraySort: function(a, b) { return EchoRender._getComponentDepth(a.parent) - EchoRender._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 the root component of the sub-hierarchy on which renderDisplay() should be invoked * @param includeSelf flag indicating whether renderDisplay() should be invoked on the * specified component (if false, it will only be invoked on child components) * @private */ _doRenderDisplay: function(component, includeSelf) { if (includeSelf) { EchoRender._doRenderDisplayImpl(component); } else { for (var i = 0; i < component.children.length; ++i) { EchoRender._doRenderDisplayImpl(component.children[i]); } } }, /** * Recursive work method for _doRenderDisplay(). * * @param component the component on which to invoke renderDisplay() * @private */ _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) { EchoRender._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 component the component whose depth is to be calculated * @return the depth of the component * @private */ _getComponentDepth: function(component) { var depth = -1; while (component != null) { component = component.parent; ++depth; } return depth; }, getPeerClass: function(component) { return EchoRender._peers[component.componentType]; }, /** * 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 {EchoClient} client the relevant Client * @param {EchoApp.Component} component the component * @private */ _loadPeer: function(client, component) { if (component.peer) { return; // FIXME. which behavior is correct for this scenario: ignore or fail? // throw new Error("Peer already installed: " + component); } var peerClass = EchoRender._peers[component.componentType]; if (!peerClass) { throw new Error("Peer not found for: " + component.componentType); } component.peer = new peerClass(); 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 {EchoApp.Component} parent the component whose size changed */ notifyResize: function(parent) { EchoRender._doRenderDisplay(parent, false); }, /** * Invokes renderDispose() on all removed children and descendants found in the specified update. * * @param {EchoApp.Update.ComponentUpdate} update the update * @private */ _processDispose: function(update) { var components = update.getRemovedDescendants(); if (components) { for (var i = 0; i < components.length; ++i) { EchoRender._renderComponentDisposeImpl(update, components[i]); } } components = update.getRemovedChildren(); if (components) { for (var i = 0; i < components.length; ++i) { EchoRender._renderComponentDisposeImpl(update, components[i]); } } }, /** * Processes all pending updates in the client's application's update manager. * * @param {EchoClient} 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). EchoRender._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(EchoRender._componentDepthArraySort); // Load peers for any root components being updated. for (var i = 0; i < updates.length; ++i) { updates[i].renderContext = {}; var peers = updates[i].parent.peer; if (peer == null && updates[i].parent.componentType == "Root") { EchoRender._loadPeer(client, updates[i].parent); } } // Remove Phase: Invoke renderDispose on all updates. for (var i = updates.length - 1; i >= 0; --i) { if (updates[i] == null) { // Skip removed updates. continue; } var peer = updates[i].parent.peer; EchoRender._processDispose(updates[i]); } // Profiling: Mark completion of remove phase. if (EchoClient.profilingTimer) { EchoClient.profilingTimer.mark("rem"); } // Update Phase: Invoke renderUpdate on all updates. for (var i = 0; i < updates.length; ++i) { if (updates[i] == null) { // The update has been removed, skip it. continue; } // Obtain component synchronization peer. var 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 descandant components. if (fullRender) { for (var j = i + 1; j < updates.length; ++j) { if (updates[j] != null && updates[i].parent.isAncestorOf(updates[j].parent)) { updates[j] = null; } } } //FIXME ....moved after loop, ensure this is okay (evaluate use of dispose). // Set disposed set of peer to false. EchoRender._setPeerDisposedState(updates[i].parent, false); } // Profiling: Mark completion of update phase. if (EchoClient.profilingTimer) { EchoClient.profilingTimer.mark("up"); } // Display Phase: Invoke renderDisplay on all updates. for (var i = 0; i < updates.length; ++i) { if (updates[i] == null) { // Skip removed updates. continue; } //FIXME. this does needless work....resizing twice is quite possible. // if property updates are present. if (updates[i].renderContext.displayRequired) { for (var j = 0; j < updates[i].renderContext.displayRequired.length; ++j) { Core.Debug.consoleWrite("PartialRenderUpdate:" + updates[i].renderContext.displayRequired[j]); EchoRender._doRenderDisplay(updates[i].renderContext.displayRequired[j], true); } } else { EchoRender._doRenderDisplay(updates[i].parent, true); } } // Profiling: Mark completion of display phase. if (EchoClient.profilingTimer) { EchoClient.profilingTimer.mark("disp"); } // Unload peers for truly removed components, destroy mapping. for (var componentId in EchoRender._disposedComponents) { var component = EchoRender._disposedComponents[componentId]; EchoRender._unloadPeer(component); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -