event.js
来自「国外很不错的一个开源OA系统Group-Office」· JavaScript 代码 · 共 1,739 行 · 第 1/4 页
JS
1,739 行
*/ var onAvailStack = []; /** * Lookup table for legacy events * @property legacyMap * @static * @private */ var legacyMap = []; /** * Counter for auto id generation * @property counter * @static * @private */ var counter = 0; return { // PREPROCESS /** * The number of times we should look for elements that are not * in the DOM at the time the event is requested after the document * has been loaded. The default is 200@amp;50 ms, so it will poll * for 10 seconds or until all outstanding handlers are bound * (whichever comes first). * @property POLL_RETRYS * @type int * @static * @final */ POLL_RETRYS: 200, /** * The poll interval in milliseconds * @property POLL_INTERVAL * @type int * @static * @final */ POLL_INTERVAL: 20, /** * Element to bind, int constant * @property EL * @type int * @static * @final */ EL: 0, /** * Type of event, int constant * @property TYPE * @type int * @static * @final */ TYPE: 1, /** * Function to execute, int constant * @property FN * @type int * @static * @final */ FN: 2, /** * Function wrapped for scope correction and cleanup, int constant * @property WFN * @type int * @static * @final */ WFN: 3, /** * Object passed in by the user that will be returned as a * parameter to the callback, int constant * @property OBJ * @type int * @static * @final */ OBJ: 3, /** * Adjusted scope, either the element we are registering the event * on or the custom object passed in by the listener, int constant * @property ADJ_SCOPE * @type int * @static * @final */ ADJ_SCOPE: 4, /** * Safari detection is necessary to work around the preventDefault * bug that makes it so you can't cancel a href click from the * handler. There is not a capabilities check we can use here. * @property isSafari * @private * @static */ isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent), /** * IE detection needed to properly calculate pageX and pageY. * capabilities checking didn't seem to work because another * browser that does not provide the properties have the values * calculated in a different manner than IE. * @property isIE * @private * @static */ isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) && navigator.userAgent.match(/msie/gi)), /** * poll handle * @property _interval * @private */ _interval: null, /** * @method startInterval * @static * @private */ startInterval: function() { if (!this._interval) { var self = this; var callback = function() { self._tryPreloadAttach(); }; this._interval = setInterval(callback, this.POLL_INTERVAL); // this.timeout = setTimeout(callback, i); } }, /** * Executes the supplied callback when the item with the supplied * id is found. This is meant to be used to execute behavior as * soon as possible as the page loads. If you use this after the * initial page load it will poll for a fixed time for the element. * The number of times it will poll and the frequency are * configurable. By default it will poll for 10 seconds. * * @method onAvailable * * @param {string} p_id the id of the element to look for. * @param {function} p_fn what to execute when the element is found. * @param {object} p_obj an optional object to be passed back as * a parameter to p_fn. * @param {boolean} p_override If set to true, p_fn will execute * in the scope of p_obj * * @static */ onAvailable: function(p_id, p_fn, p_obj, p_override) { onAvailStack.push( { id: p_id, fn: p_fn, obj: p_obj, override: p_override, checkReady: false } ); retryCount = this.POLL_RETRYS; this.startInterval(); }, /** * Works the same way as onAvailable, but additionally checks the * state of sibling elements to determine if the content of the * available element is safe to modify. * * @method onContentReady * * @param {string} p_id the id of the element to look for. * @param {function} p_fn what to execute when the element is ready. * @param {object} p_obj an optional object to be passed back as * a parameter to p_fn. * @param {boolean} p_override If set to true, p_fn will execute * in the scope of p_obj * * @static */ onContentReady: function(p_id, p_fn, p_obj, p_override) { onAvailStack.push( { id: p_id, fn: p_fn, obj: p_obj, override: p_override, checkReady: true } ); retryCount = this.POLL_RETRYS; this.startInterval(); }, /** * Appends an event handler * * @method addListener * * @param {Object} el The html element to assign the * event to * @param {String} sType The type of event to append * @param {Function} fn The method the event invokes * @param {Object} obj An arbitrary object that will be * passed as a parameter to the handler * @param {boolean} override If true, the obj passed in becomes * the execution scope of the listener * @return {boolean} True if the action was successful or defered, * false if one or more of the elements * could not have the event bound to it. * @static */ addListener: function(el, sType, fn, obj, override) { if (!fn || !fn.call) { return false; } // The el argument can be an array of elements or element ids. if ( this._isValidCollection(el)) { var ok = true; for (var i=0,len=el.length; i<len; ++i) { ok = this.on(el[i], sType, fn, obj, override) && ok; } return ok; } else if (typeof el == "string") { var oEl = this.getEl(el); // If the el argument is a string, we assume it is // actually the id of the element. If the page is loaded // we convert el to the actual element, otherwise we // defer attaching the event until onload event fires // check to see if we need to delay hooking up the event // until after the page loads. if (oEl) { el = oEl; } else { // defer adding the event until the element is available this.onAvailable(el, function() { YAHOO.util.Event.on(el, sType, fn, obj, override); }); return true; } } // Element should be an html element or an array if we get // here. if (!el) { return false; } // we need to make sure we fire registered unload events // prior to automatically unhooking them. So we hang on to // these instead of attaching them to the window and fire the // handles explicitly during our one unload event. if ("unload" == sType && obj !== this) { unloadListeners[unloadListeners.length] = [el, sType, fn, obj, override]; return true; } // if the user chooses to override the scope, we use the custom // object passed in, otherwise the executing scope will be the // HTML element that the event is registered on var scope = el; if (override) { if (override === true) { scope = obj; } else { scope = override; } } // wrap the function so we can return the obj object when // the event fires; var wrappedFn = function(e) { return fn.call(scope, YAHOO.util.Event.getEvent(e), obj); }; var li = [el, sType, fn, wrappedFn, scope]; var index = listeners.length; // cache the listener so we can try to automatically unload listeners[index] = li; if (this.useLegacyEvent(el, sType)) { var legacyIndex = this.getLegacyIndex(el, sType); // Add a new dom0 wrapper if one is not detected for this // element if ( legacyIndex == -1 || el != legacyEvents[legacyIndex][0] ) { legacyIndex = legacyEvents.length; legacyMap[el.id + sType] = legacyIndex; // cache the signature for the DOM0 event, and // include the existing handler for the event, if any legacyEvents[legacyIndex] = [el, sType, el["on" + sType]]; legacyHandlers[legacyIndex] = []; el["on" + sType] = function(e) { YAHOO.util.Event.fireLegacyEvent( YAHOO.util.Event.getEvent(e), legacyIndex); }; } // add a reference to the wrapped listener to our custom // stack of events //legacyHandlers[legacyIndex].push(index); legacyHandlers[legacyIndex].push(li); } else { this._simpleAdd(el, sType, wrappedFn, false); } return true; }, /** * When using legacy events, the handler is routed to this object * so we can fire our custom listener stack. * @method fireLegacyEvent * @static * @private */ fireLegacyEvent: function(e, legacyIndex) { var ok = true; var le = legacyHandlers[legacyIndex]; for (var i=0,len=le.length; i<len; ++i) { var li = le[i]; if ( li && li[this.WFN] ) { var scope = li[this.ADJ_SCOPE]; var ret = li[this.WFN].call(scope, e); ok = (ok && ret); } } return ok; }, /** * Returns the legacy event index that matches the supplied * signature * @method getLegacyIndex * @static * @private */ getLegacyIndex: function(el, sType) { var key = this.generateId(el) + sType; if (typeof legacyMap[key] == "undefined") { return -1; } else { return legacyMap[key]; } }, /** * Logic that determines when we should automatically use legacy * events instead of DOM2 events. * @method useLegacyEvent * @static * @private */ useLegacyEvent: function(el, sType) { if (!el.addEventListener && !el.attachEvent) { return true; } else if (this.isSafari) { if ("click" == sType || "dblclick" == sType) { return true; } } return false; }, /** * Removes an event handler * * @method removeListener * * @param {Object} el the html element or the id of the element to * assign the event to. * @param {String} sType the type of event to remove. * @param {Function} fn the method the event invokes. If fn is * undefined, then all event handlers for the type of event are * removed. * @return {boolean} true if the unbind was successful, false * otherwise. * @static */ removeListener: function(el, sType, fn) { var i, len; // The el argument can be a string if (typeof el == "string") { el = this.getEl(el); // The el argument can be an array of elements or element ids. } else if ( this._isValidCollection(el)) { var ok = true; for (i=0,len=el.length; i<len; ++i) { ok = ( this.removeListener(el[i], sType, fn) && ok ); } return ok; } if (!fn || !fn.call) { //return false; return this.purgeElement(el, false, sType); } if ("unload" == sType) { for (i=0, len=unloadListeners.length; i<len; i++) { var li = unloadListeners[i]; if (li && li[0] == el && li[1] == sType && li[2] == fn) { unloadListeners.splice(i, 1); return true;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?