📄 webcore.js
字号:
/** * Removes the specified DOM node from the DOM tree in a recursive manner, i.e. all descendants * of the given node are removed individually. This alleviates slow performance when removing large * DOM trees. * * @param {Node} node the node which should be deleted */ _removeNodeRecursive: function(node) { var childNode = node.firstChild; while (childNode) { var nextChildNode = childNode.nextSibling; this._removeNodeRecursive(childNode); childNode = nextChildNode; } node.parentNode.removeChild(node); }, /** * Stops an event from propagating ("bubbling") to parent nodes in the DOM, * using the client's supported event model. * On clients which support the W3C DOM Level 2 event specification, * the stopPropagation() method of the event is invoked. * On clients which support only the Internet Explorer event model, * the 'cancelBubble' property of the event is set to true. * * @param {Event} e the event */ stopEventPropagation: function(e) { if (e.stopPropagation) { e.stopPropagation(); } else { e.cancelBubble = true; } }};/** * @class * Provides information about the web browser environment. * Non-instantiable class. */WebCore.Environment = { /** * Performs initial analysis of environment. * Automatically invoked when WebCore module is initialized. */ _init: function() { var ua = navigator.userAgent.toLowerCase(); this.BROWSER_OPERA = ua.indexOf("opera") != -1; this.BROWSER_SAFARI = ua.indexOf("safari") != -1; this.BROWSER_KONQUEROR = ua.indexOf("konqueror") != -1; this.BROWSER_FIREFOX = ua.indexOf("firefox") != -1; this.CSS_FLOAT = "cssFloat"; // Note deceptive user agent fields: // - Konqueror and Safari UA fields contain "like Gecko" // - Opera UA field typically contains "MSIE" this.DECEPTIVE_USER_AGENT = this.BROWSER_OPERA || this.BROWSER_SAFARI || this.BROWSER_KONQUEROR; this.BROWSER_MOZILLA = !this.DECEPTIVE_USER_AGENT && ua.indexOf("gecko") != -1; this.BROWSER_INTERNET_EXPLORER = !this.DECEPTIVE_USER_AGENT && ua.indexOf("msie") != -1; // Retrieve Version Info (as necessary). if (this.BROWSER_INTERNET_EXPLORER) { this._parseVersionInfo(ua, "msie "); } else if (this.BROWSER_FIREFOX) { this._parseVersionInfo(ua, "firefox/"); } else if (this.BROWSER_OPERA) { this._parseVersionInfo(ua, "opera/"); } else if (this.BROWSER_SAFARI) { this._parseVersionInfo(ua, "version/"); } else if (this.BROWSER_MOZILLA) { this._parseVersionInfo(ua, "rv:") } else if (this.BROWSER_KONQUEROR) { this._parseVersionInfo(ua, "konqueror/"); } //FIXME Quirk flags not refined yet, some quirk flags from Echo 2.0/1 will/may be deprecated/removed. // Set IE Quirk Flags if (this.BROWSER_INTERNET_EXPLORER) { //FIXME IE8 quirks have not been properly analyzed yet. // Internet Explorer Flags (all versions). this.PROPRIETARY_EVENT_MOUSE_ENTER_LEAVE_SUPPORTED = true; this.PROPRIETARY_EVENT_SELECT_START_SUPPORTED = true; this.QUIRK_IE_KEY_DOWN_EVENT_REPEAT = true; this.CSS_FLOAT = "styleFloat"; if (this.BROWSER_MAJOR_VERSION < 8) { // Internet Explorer 6 and 7 Flags. this.QUIRK_TABLE_CELL_WIDTH_EXCLUDES_PADDING = true; this.NOT_SUPPORTED_RELATIVE_COLUMN_WIDTHS = true; this.QUIRK_IE_REPAINT = true; this.QUIRK_TEXTAREA_CONTENT = true; this.QUIRK_IE_TEXTAREA_NEWLINE_OBLITERATION = true; this.QUIRK_IE_SELECT_LIST_DOM_UPDATE = true; this.QUIRK_CSS_BORDER_COLLAPSE_INSIDE = true; this.QUIRK_CSS_BORDER_COLLAPSE_FOR_0_PADDING = true; this.NOT_SUPPORTED_CSS_OPACITY = true; this.PROPRIETARY_IE_OPACITY_FILTER_REQUIRED = true; this.QUIRK_IE_TABLE_PERCENT_WIDTH_SCROLLBAR_ERROR = true; this.QUIRK_IE_SELECT_PERCENT_WIDTH = true; if (this.BROWSER_MAJOR_VERSION < 7) { // Internet Explorer 6 Flags. this.QUIRK_CSS_POSITIONING_ONE_SIDE_ONLY = true; this.PROPRIETARY_IE_PNG_ALPHA_FILTER_REQUIRED = true; this.QUIRK_CSS_BACKGROUND_ATTACHMENT_USE_FIXED = true; this.QUIRK_IE_SELECT_Z_INDEX = true; this.NOT_SUPPORTED_CSS_MAX_HEIGHT = true; this.QUIRK_DELAYED_FOCUS_REQUIRED = true; // Enable 'garbage collection' on large associative arrays to avoid memory leak. Core.Arrays.LargeMap.garbageCollectEnabled = true; } } } else if (this.BROWSER_MOZILLA) { if (this.BROWSER_FIREFOX) { if (this.BROWSER_MAJOR_VERSION < 2) { this.QUIRK_DELAYED_FOCUS_REQUIRED = true; } } else { this.QUIRK_PERFORMANCE_LARGE_DOM_REMOVE = true; this.QUIRK_DELAYED_FOCUS_REQUIRED = true; } } else if (this.BROWSER_OPERA) { this.NOT_SUPPORTED_RELATIVE_COLUMN_WIDTHS = true; } }, /** * Parses version information from user agent string. The text argument specifies * the string that prefixes the version info in the ua string (ie 'version/' for Safari for example). * <p> * The major version is retrieved by getting the int between text and the first dot. The minor version * is retrieved by getting the int between the first dot and the first non-numeric character that appears * after the dot, or the end of the ua string (whichever comes first). * If the ua string does not supply a minor version, the minor version is assumed to be 0. * * @private * @param ua the lower cased user agent string * @param searchString the text that prefixes the version info (version info must be the first appearance of * this text in the ua string) */ _parseVersionInfo: function(ua, searchString) { var ix1 = ua.indexOf(searchString); var ix2 = ua.indexOf(".", ix1); var ix3 = ua.length; if (ix2 == -1) { ix2 = ua.length; } else { // search for the first non-number character after the dot for (var i = ix2 + 1; i < ua.length; i++) { var c = ua.charAt(i); if (isNaN(c)) { ix3 = i; break; } } } this.BROWSER_MAJOR_VERSION = parseInt(ua.substring(ix1 + searchString.length, ix2)); if (ix2 == ua.length) { this.BROWSER_MINOR_VERSION = 0; } else { this.BROWSER_MINOR_VERSION = parseInt(ua.substring(ix2 + 1, ix3)); } }};/** * @class * EventProcessor namespace. Non-instantiable object. * The static methods in this object provide a standard framework for handling * DOM events across incompatible browser platforms. * <p> * <b>Capturing/Bubbling Listeners:</b> * This implementation additionally allows for the registration of capturing and bubbling event * listeners that work even on Internet Explorer platforms, where they are not natively supported. * This implementation relies on the fact that all event listeners will be registered * through it. */WebCore.EventProcessor = { /** * Provides utilities for restricting selection of DOM elements. These are necessary as double click and drag * events will cause/begin undesired selections. */ Selection: { /** * Adds a listener to an element that will prevent text selection / highlighting as a result of mouse clicks. * The disable() method should be invoked when the element is to be disposed. * The event is registered using the event processor, so invoking WebCore.EventProcessor.removeAll() on its * element will also dispose it. * * @param {Element} element the element on which to forbid text selection * @see WebCore.EventProcessor.Selection#enable */ disable: function(element) { WebCore.EventProcessor.add(element, "mousedown", WebCore.EventProcessor.Selection._disposeEvent, false); if (WebCore.Environment.PROPRIETARY_EVENT_SELECT_START_SUPPORTED) { WebCore.EventProcessor.add(element, "selectstart", WebCore.EventProcessor.Selection._disposeEvent, false); } }, /** * Selection denial listener implementation. * * @param e the selection/click event * @private */ _disposeEvent: function(e) { WebCore.DOM.preventEventDefault(e); }, /** * Removes a selection denial listener. * * @param element the element from which to remove the selection denial listener * @see WebCore.EventProcessor.Selection#enable */ enable: function(element) { WebCore.EventProcessor.remove(element, "mousedown", WebCore.EventProcessor.Selection._disposeEvent, false); if (WebCore.Environment.PROPRIETARY_EVENT_SELECT_START_SUPPORTED) { WebCore.EventProcessor.remove(element, "selectstart", WebCore.EventProcessor.Selection._disposeEvent, false); } } }, /** * Next available sequentially assigned element identifier. * Elements are assigned unique identifiers to enable mapping between * elements and lists of registered event listeners. * * @type Integer */ _nextId: 0, /** * Mapping between element ids and ListenerLists containing listeners to invoke during capturing phase. * @type Core.Arrays.LargeMap */ _capturingListenerMap: new Core.Arrays.LargeMap(), /** * 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 = ++WebCore.EventProcessor._nextId; } var listenerList; // Determine the Core.ListenerList to which the listener should be added. if (element.__eventProcessorId == WebCore.EventProcessor._lastId && capture == WebCore.EventProcessor._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 = WebCore.EventProcessor._lastListenerList; } else { // Obtain correct id->ListenerList mapping based on capture parameter. var listenerMap = capture ? WebCore.EventProcessor._capturingListenerMap : WebCore.EventProcessor._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. WebCore.EventProcessor._lastId = element.__eventProcessorId; WebCore.EventProcessor._lastCapture = capture; WebCore.EventProcessor._lastListenerList = listenerList; } // Register event listener on DOM element. if (!listenerList.hasListeners(eventType)) { WebCore.DOM.addEventListener(element, eventType, WebCore.EventProcessor._processEvent, false); } // 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) { 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; var propagate = true; // Fire event to capturing listeners. for (var i = elementAncestry.length - 1; i >= 0; --i) { listenerList = WebCore.EventProcessor._capturingListenerMap.map[elementAncestry[i].__eventProcessorId]; if (listenerList) { // Set registered target on event. e.registeredTarget = elementAncestry[i]; if (!listenerList.fireEvent(e)) { propagate = false; } } if (!propagate) { // Stop propagation if requested. break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -