📄 event.js
字号:
*/
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
*/
POLL_RETRYS: 200,
/**
* The poll interval in milliseconds
* @property POLL_INTERVAL
* @type int
*/
POLL_INTERVAL: 50,
/**
* Element to bind, int constant
* @property EL
* @type int
*/
EL: 0,
/**
* Type of event, int constant
* @property TYPE
* @type int
*/
TYPE: 1,
/**
* Function to execute, int constant
* @property FN
* @type int
*/
FN: 2,
/**
* Function wrapped for scope correction and cleanup, int constant
* @property WFN
* @type int
*/
WFN: 3,
/**
* Object passed in by the user that will be returned as a
* parameter to the callback, int constant
* @property SCOPE
* @type int
*/
SCOPE: 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
*/
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
*/
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
*/
isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) &&
navigator.userAgent.match(/msie/gi)),
/**
* @method addDelayedListener
* @private
*/
addDelayedListener: function(el, sType, fn, oScope, bOverride) {
delayedListeners[delayedListeners.length] =
[el, sType, fn, oScope, bOverride];
// If this happens after the inital page load, we need to
// reset the poll counter so that we continue to search for
// the element for a fixed period of time.
if (loadComplete) {
retryCount = this.POLL_RETRYS;
this.startTimeout(0);
// this._tryPreloadAttach();
}
},
/**
* @method startTimeout
* @private
*/
startTimeout: function(interval) {
var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
var self = this;
var callback = function() { self._tryPreloadAttach(); };
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
*
*/
onAvailable: function(p_id, p_fn, p_obj, p_override) {
onAvailStack.push( { id: p_id,
fn: p_fn,
obj: p_obj,
override: p_override } );
retryCount = this.POLL_RETRYS;
this.startTimeout(0);
// this._tryPreloadAttach();
},
/**
* 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} oScope An arbitrary object that will be
* passed as a parameter to the handler
* @param {boolean} bOverride 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.
*/
addListener: function(el, sType, fn, oScope, bOverride) {
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,
oScope,
bOverride) && 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 (loadComplete && oEl) {
el = oEl;
} else {
// defer adding the event until onload fires
this.addDelayedListener(el,
sType,
fn,
oScope,
bOverride);
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 && oScope !== this) {
unloadListeners[unloadListeners.length] =
[el, sType, fn, oScope, bOverride];
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 = (bOverride) ? oScope : el;
// wrap the function so we can return the oScope object when
// the event fires;
var wrappedFn = function(e) {
return fn.call(scope, YAHOO.util.Event.getEvent(e),
oScope);
};
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);
// DOM2 Event model
} else if (el.addEventListener) {
el.addEventListener(sType, wrappedFn, false);
// IE
} else if (el.attachEvent) {
el.attachEvent("on" + sType, wrappedFn);
}
return true;
},
/**
* When using legacy events, the handler is routed to this object
* so we can fire our custom listener stack.
* @method fireLegacyEvent
* @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
* @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
* @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;
},
/**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -