📄 application.js
字号:
/** * @fileoverview * Application framework main module. * Requires Core. *//** * @class Namespace for application framework. */EchoApp = { /** * Next unique identifier. */ _nextUid: 1, /** * Generates a unique identifier. Identifiers are unique for the duration of the existence of this namespace. */ generateUid: function() { return this._nextUid++; }};/** * @class * Representation of a single application instance. * Derived objects must invoke construtor with root component id. */EchoApp.Application = Core.extend({ $abstract: true, /** * Mapping between component ids and component instances. * @private * @type Core.Arrays.LargeMap */ _idToComponentMap: null, /** * ListenerList instance for application-level events. * @private * @type Core.ListenerList */ _listenerList: null, /** * Array of modal components. * This value is read-only. * @type Array */ _modalComponents: null, /** * Displayed style sheet. * * @private * @type EchoApp.StyleSheet */ _styleSheet: null, /** * Currently focused component. * @private * @type EchoApp.Component */ _focusedComponent: null, /** * Root component instance. * This value is read-only. * @type EchoApp.Component */ rootComponent: null, /** * UpdateManager instance monitoring changes to the application for redraws. * @type EchoApp.Update.Manager */ updateManager: null, /** * FocusManager instance handling application focus behavior. * @type EchoApp.FocusManager */ focusManager: null, /** * Creates a new application instance. * @constructor */ $construct: function() { this._idToComponentMap = new Core.Arrays.LargeMap(); this._listenerList = new Core.ListenerList(); this.rootComponent = new EchoApp.Component(); this.rootComponent.componentType = "Root"; this.rootComponent.register(this); this._modalComponents = []; this.updateManager = new EchoApp.Update.Manager(this); this.focusManager = new EchoApp.FocusManager(this); }, /** * Adds a ComponentUpdateListener. * * @param {Function} l the listener to add */ addComponentUpdateListener: function(l) { this._listenerList.addListener("componentUpdate", l); }, /** * Adds a FocusListener. Focus listeners will be invoked when the focused * component in the application changes. * * @param {Function} l the listener to add */ addFocusListener: function(l) { this._listenerList.addListener("focus", l); }, /** * Disposes of the application. * Once invoked, the application will no longer function and cannot be used again. * This method will free any resources allocated by the application. */ dispose: function() { this.updateManager.dispose(); }, /** * Recurisvely determines the current root component of the modal context. * * @param {EchoApp.Component} searchComponent (optional) the component from which to search * (this paramater is provided when recursively searching, if omitted the sear * will begin at the root component of the application). * @return the current modal context root component */ _findModalContextRoot: function(searchComponent) { searchComponent = searchComponent ? searchComponent : this.rootComponent; for (var i = searchComponent.children.length - 1; i >= 0; --i) { var foundComponent = this._findModalContextRoot(searchComponent.children[i]); if (foundComponent) { return foundComponent; } } if (searchComponent.modalSupport && searchComponent.get("modal")) { return searchComponent; } return null; }, /** * Focuses the previous/next component based on the currently focused component. * * @param {Boolean} reverse false to focus the next component, true to focus the * previous component */ focusNext: function(reverse) { focusedComponent = this.focusManager.find(null, reverse); if (focusedComponent != null) { this.setFocusedComponent(focusedComponent); } }, /** * Retrieves the registered component with the specified render id. * * @param {String} renderId the render id * @return the component * @type EchoApp.Component */ getComponentByRenderId: function(renderId) { return this._idToComponentMap.map[renderId]; }, /** * Returns the focused component. * * @return the focused component * @type EchoApp.Component */ getFocusedComponent: function() { return this._focusedComponent; }, /** * Returns the default layout direction of the application. * * @return the default layout direction * @type EchoApp.LayoutDirection */ getLayoutDirection: function() { // FIXME ensure layout direction gets set upon application instantiation return this._layoutDirection ? this._layoutDirection : EchoApp.LayoutDirection.LTR; }, /** * Returns the root component of the modal context. * * @return the root component of the modal context */ getModalContextRoot: function() { if (this._modalComponents.length == 0) { return null; } else if (this._modalComponents.length == 1) { return this._modalComponents[0]; } return this._findModalContextRoot(); }, /** * Returns the application style sheet. * * @return the application style sheet * @type EchoApp.StyleSheet */ getStyleSheet: function() { return this._styleSheet; }, /** * Returns the active state of the application. * * @return the active state of the application, a value of * true indicating the application is ready for user * input, a value of false indicating otherwise * @type Boolean */ isActive: function() { return true; }, /** * Notifies the application of an update to a component. * * @param {EchoApp.Component} parent the parent component * @param {String} propertyName the updated property * @param oldValue the previous property value * @param newValue the new property value */ notifyComponentUpdate: function(parent, propertyName, oldValue, newValue) { if (parent.modalSupport && propertyName == "modal") { this._setModal(parent, newValue); } if (this._listenerList.hasListeners("componentUpdate")) { this._listenerList.fireEvent({type: "componentUpdate", parent: parent, propertyName: propertyName, oldValue: oldValue, newValue: newValue}); } this.updateManager._processComponentUpdate(parent, propertyName, oldValue, newValue); }, /** * Registers a component with the application. * Invoked when a component is added to a hierarchy of * components that is registered with the application. * * @param {EchoApp.Component} component the component to register * @private */ _registerComponent: function(component) { if (this._idToComponentMap.map[component.renderId]) { throw new Error("Component already exists with id: " + component.renderId); } this._idToComponentMap.map[component.renderId] = component; if (component.modalSupport && component.get("modal")) { this._setModal(component, true); } }, /** * Removes a ComponentUpdateListener. * * @param {Function} l the listener to remove */ removeComponentUpdateListener: function(l) { this._listenerList.removeListener("componentUpdate", l); }, /** * Removes a FocusListener. Focus listeners will be invoked when the focused * component in the application changes. * * @param {Function} l the listener to remove */ removeFocusListener: function(l) { this._listenerList.removeListener("focus", l); }, /** * Sets the focused component * * @param {EchoApp.Component} newValue the new focused component */ setFocusedComponent: function(newValue) { // If required, find focusable parent containing 'newValue'. while (newValue != null && !newValue.focusable) { newValue = newValue.parent; } // Verify new focused component is within modal context. if (this._modalComponents.length > 0) { var modalContextRoot = this.getModalContextRoot(); if (!modalContextRoot.isAncestorOf(newValue)) { // Reject request to focus component outside of modal context. Core.Debug.consoleWrite("not in modal:" + newValue); return; } } this._focusedComponent = newValue; this._listenerList.fireEvent({type: "focus", source: this}); }, /** * Sets the application default layout direction. * * @param {EchoApp.LayoutDirection} newValue the new layout direction */ setLayoutDirection: function(newValue) { this._layoutDirection = newValue; }, /** * Informs the application of the modal state of a specific component. * When modal components are unregistered, this method must be executed * in order to avoid a memory leak. */ _setModal: function(component, modal) { Core.Arrays.remove(this._modalComponents, component); if (modal) { this._modalComponents.push(component); } // Auto-focus first component in modal context if component is currently focused component is not within modal context. if (this._modalComponents.length > 0 && this._focusedComponent) { var modalContextRoot = this.getModalContextRoot(); if (!modalContextRoot.isAncestorOf(this._focusedComponent)) { if (modalContextRoot.focusable) { this.setFocusedComponent(modalContextRoot); } else { this.setFocusedComponent(this.focusManager.findInParent(modalContextRoot, false)); } } } }, /** * Sets the application style sheet. * * @param {EchoApp.StyleSheet} newValue the new style sheet */ setStyleSheet: function(newValue) { var oldValue = this._styleSheet; this._styleSheet = newValue; // FIXME updatemanager can't handle this yet. // this.notifyComponentUpdate(null, "styleSheet", oldValue, newValue); }, /** * Unregisters a component from the application. * This method is invoked when a component is removed from a hierarchy of * components registered with the application. * * @param {EchoApp.Component} component the component to remove * @private */ _unregisterComponent: function(component) { this._idToComponentMap.remove(component.renderId); if (component.modalSupport) { this._setModal(component, false); } }});/** * @class * Factory to create new instances of arbitrary components. This object is * used to instantiate new components during XML deserialization. * This is a namespace object, do not instantiate. */EchoApp.ComponentFactory = { /** * Mapping between type names and object constructors. * * @type Object * @private */ _typeToConstructorMap: {}, /** * Creates a new instance of an arbitrary component. * * @constructor * @param {String} typeName the type name of the component * @param {String} renderId the component render id * @return a newly instantiated component * @type EchoApp.Component */ newInstance: function(typeName, renderId) { var typeConstructor = this._typeToConstructorMap[typeName]; if (!typeConstructor) { throw new Error("Type not registered: " + typeName); } var component = new typeConstructor(); component.renderId = renderId; return component; },
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -