📄 core.web.js
字号:
/** * Mapping between element ids and ListenerLists containing listeners to invoke during bubbling phase. * @type Core.Arrays.LargeMap */ _bubblingListenerMap: new Core.Arrays.LargeMap(), /** * Registers an event handler. * * @param {Element} element the DOM element on which to add the event handler * @param {String} eventType the DOM event type * @param {Function} eventTarget the event handler to invoke when the event is fired * @param {Boolean} capture true to fire the event during the capturing phase, false to fire the event during * the bubbling phase */ add: function(element, eventType, eventTarget, capture) { // Assign event processor element id to element if not present. if (!element.__eventProcessorId) { element.__eventProcessorId = ++Core.Web.Event._nextId; } var listenerList; // Determine the Core.ListenerList to which the listener should be added. if (element.__eventProcessorId == Core.Web.Event._lastId && capture == Core.Web.Event._lastCapture) { // If the 'element' and 'capture' properties are identical to those specified on the prior invocation // of this method, the correct listener list is stored in the '_lastListenerList' property. listenerList = Core.Web.Event._lastListenerList; } else { // Obtain correct id->ListenerList mapping based on capture parameter. var listenerMap = capture ? Core.Web.Event._capturingListenerMap : Core.Web.Event._bubblingListenerMap; // Obtain ListenerList based on element id. listenerList = listenerMap.map[element.__eventProcessorId]; if (!listenerList) { // Create new ListenerList if none exists. listenerList = new Core.ListenerList(); listenerMap.map[element.__eventProcessorId] = listenerList; } // Cache element's event processor id, capture parameter value, and listener list. // If the same element/capture properties are provided in the next call (which commonly occurs), // the lookup operation will be unnecessary. Core.Web.Event._lastId = element.__eventProcessorId; Core.Web.Event._lastCapture = capture; Core.Web.Event._lastListenerList = listenerList; } // Register event listener on DOM element. if (!listenerList.hasListeners(eventType)) { Core.Web.DOM.addEventListener(element, eventType, Core.Web.Event._processEvent, false); ++Core.Web.Event._listenerCount; } // Add event handler to the ListenerList. listenerList.addListener(eventType, eventTarget); }, /** * Listener method which is invoked when ANY event registered with the event processor occurs. * * @param {Event} e */ _processEvent: function(e) { if (Core.Web.Event.debugListenerCount) { Core.Debug.consoleWrite("Core.Web.Event listener count: " + Core.Web.Event._listenerCount); } e = e ? e : window.event; if (!e.target && e.srcElement) { // The Internet Explorer event model stores the target element in the 'srcElement' property of an event. // Modify the event such the target is retrievable using the W3C DOM Level 2 specified property 'target'. e.target = e.srcElement; } // Establish array containing elements ancestry, with index 0 containing // the element and the last index containing its most distant ancestor. // Only record elements that have ids. var elementAncestry = []; var targetElement = e.target; while (targetElement) { if (targetElement.__eventProcessorId) { // Element Node with identifier. elementAncestry.push(targetElement); } targetElement = targetElement.parentNode; } var listenerList, i, propagate = true; // Fire event to capturing listeners. for (i = elementAncestry.length - 1; i >= 0; --i) { listenerList = Core.Web.Event._capturingListenerMap.map[elementAncestry[i].__eventProcessorId]; if (listenerList) { // Set registered target on event. e.registeredTarget = elementAncestry[i]; if (!listenerList.fireEvent(e)) { // Stop propagation if requested. propagate = false; break; } } } if (propagate) { // Fire event to bubbling listeners. for (i = 0; i < elementAncestry.length; ++i) { listenerList = Core.Web.Event._bubblingListenerMap.map[elementAncestry[i].__eventProcessorId]; if (listenerList) { // Set registered target on event. e.registeredTarget = elementAncestry[i]; if (!listenerList.fireEvent(e)) { // Stop propagation if requested. break; } } } } // Inform DOM to stop propagation of event, in all cases. // Event will otherwise be re-processed by higher-level elements registered with the event processor. Core.Web.DOM.stopEventPropagation(e); }, /** * Unregisters an event handler. * * @param {Element} element the DOM element on which to add the event handler * @param {String} eventType the DOM event type * @param {Function} eventTarget the function to invoke when the event is fired * @param {Boolean} capture true to fire the event during the capturing phase, false to fire the event during * the bubbling phase */ remove: function(element, eventType, eventTarget, capture) { Core.Web.Event._lastId = null; if (!element.__eventProcessorId) { return; } // Obtain correct id->ListenerList mapping based on capture parameter. var listenerMap = capture ? Core.Web.Event._capturingListenerMap : Core.Web.Event._bubblingListenerMap; // Obtain ListenerList based on element id. var listenerList = listenerMap.map[element.__eventProcessorId]; if (listenerList) { // Remove event handler from the ListenerList. listenerList.removeListener(eventType, eventTarget); if (listenerList.isEmpty()) { listenerMap.remove(element.__eventProcessorId); } // Unregister event listener on DOM element if all listeners have been removed. if (!listenerList.hasListeners(eventType)) { Core.Web.DOM.removeEventListener(element, eventType, Core.Web.Event._processEvent, false); --Core.Web.Event._listenerCount; } } }, /** * Unregister all event handlers from a specific element. * Use of this operation is recommended when disposing of components, it is * more efficient than removing listeners individually and guarantees proper clean-up. * * @param {Element} element the element */ removeAll: function(element) { Core.Web.Event._lastId = null; if (!element.__eventProcessorId) { return; } Core.Web.Event._removeAllImpl(element, Core.Web.Event._capturingListenerMap); Core.Web.Event._removeAllImpl(element, Core.Web.Event._bubblingListenerMap); }, /** * Implementation method for removeAll(). * Removes all capturing or bubbling listeners from a specific element * * @param {Element} element the element * @param {Core.Arrays.LargeMap} listenerMap the map from which the listeners should be removed, either * Core.Web.Event._capturingListenerMap or Core.Web.Event._bubblingListenerMap */ _removeAllImpl: function(element, listenerMap) { var listenerList = listenerMap.map[element.__eventProcessorId]; if (!listenerList) { return; } var types = listenerList.getListenerTypes(); for (var i = 0; i < types.length; ++i) { Core.Web.DOM.removeEventListener(element, types[i], Core.Web.Event._processEvent, false); --Core.Web.Event._listenerCount; } listenerMap.remove(element.__eventProcessorId); }, /** * toString() implementation for debugging purposes. * Displays contents of capturing and bubbling listener maps. * * @return string representation of listener maps * @type String */ toString: function() { return "Capturing: " + Core.Web.Event._capturingListenerMap + "\n" + "Bubbling: " + Core.Web.Event._bubblingListenerMap; }};/** * An HTTP connection to the hosting server. This method provides a cross * platform wrapper for XMLHttpRequest and additionally allows method * reference-based listener registration. */Core.Web.HttpConnection = Core.extend({ /** The URL. */ _url: null, /** The request content type. */ _contentType: null, /** The request method. */ _method: null, /** The message content object. */ _messageObject: null, /** Listener storage facility. */ _listenerList: null, /** Disposed state. */ _disposed: false, /** Browser XMLHttpRequest object. */ _xmlHttpRequest: null, /** Request header value map. */ _requestHeaders: null, /** * Creates a new <code>HttpConnection</code>. * This method simply configures the connection, the connection * will not be opened until <code>connect()</code> is invoked. * * @param {String} url the target URL * @param {String} method the connection method, i.e., GET or POST * @param messageObject the message to send (may be a String or XML DOM) * @param {String} contentType the request content-type * @constructor */ $construct: function(url, method, messageObject, contentType) { this._url = url; this._contentType = contentType; this._method = method; if (Core.Web.Env.QUIRK_SAFARI_DOM_TEXT_ESCAPE && messageObject instanceof Document) { this._preprocessSafariDOM(messageObject.documentElement); } this._messageObject = messageObject; this._listenerList = new Core.ListenerList(); }, /** * Preprocesses outgoing requests to Safari (invoked when appropriate quirk is detected). * All less than, greater than, and ampersands are replaced with escaped values, as this browser * is broken in this regard and will otherwise fail. Recursively invoked on nodes, starting with * document element. * * @param {Node} node the node to process */ _preprocessSafariDOM: function(node) { if (node.nodeType == 3) { var value = node.data; value = value.replace(/&/g, "&"); value = value.replace(/</g, "<"); value = value.replace(/>/g, ">"); node.data = value; } else { var child = node.firstChild; while (child) { this._preprocessSafariDOM(child); child = child.nextSibling; } } }, /** * Adds a response listener to be notified when a response is received from the connection. * * @param {Function} l the listener to add */ addResponseListener: function(l) { this._listenerList.addListener("response", l); }, /** * Executes the HTTP connection. * This method will return before the HTTP connection has received a response. */ connect: function() { var usingActiveXObject = false; if (window.XMLHttpRequest) { this._xmlHttpRequest = new XMLHttpRequest(); } else if (window.ActiveXObject) { usingActiveXObject = true; this._xmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP"); } else { throw "Connect failed: Cannot create XMLHttpRequest."; } var instance = this; // Create closure around instance. this._xmlHttpRequest.onreadystatechange = function() { if (!instance) { return; } try { instance._processReadyStateChange(); } finally { if (instance._disposed) { // Release instance reference to allow garbage collection. instance = null; } } }; this._xmlHttpRequest.open(this._method, this._url, true); // Set headers. if (this._requestHeaders && (usingActiveXObject || this._xmlHttpRequest.setRequestHeader)) { for(var h in this._requestHeaders) { try { this._xmlHttpRequest.setRequestHeader(h, this._requestHeaders[h]); } catch (e) { throw new Error("Failed to set header \"" + h + "\""); } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -