348 lines
No EOL
12 KiB
JavaScript
348 lines
No EOL
12 KiB
JavaScript
/*
|
|
* Ext JS Library 1.0.1
|
|
* Copyright(c) 2006-2007, Ext JS, LLC.
|
|
* licensing@extjs.com
|
|
*
|
|
* http://www.extjs.com/license
|
|
*/
|
|
|
|
|
|
/**
|
|
* @class Ext.util.Observable
|
|
* Abstract base class that provides a common interface for publishing events. Subclasses are expected to
|
|
* to have a property "events" with all the events defined.<br>
|
|
* For example:
|
|
* <pre><code>
|
|
Employee = function(name){
|
|
this.name = name;
|
|
this.events = {
|
|
"fired" : true,
|
|
"quit" : true
|
|
}
|
|
}
|
|
Ext.extend(Employee, Ext.util.Observable);
|
|
</code></pre>
|
|
*/
|
|
Ext.util.Observable = function(){
|
|
if(this.listeners){
|
|
this.on(this.listeners);
|
|
delete this.listeners;
|
|
}
|
|
};
|
|
Ext.util.Observable.prototype = {
|
|
/**
|
|
* Fires the specified event with the passed parameters (minus the event name).
|
|
* @param {String} eventName
|
|
* @param {Object...} args Variable number of parameters are passed to handlers
|
|
* @return {Boolean} returns false if any of the handlers return false otherwise it returns true
|
|
*/
|
|
fireEvent : function(){
|
|
var ce = this.events[arguments[0].toLowerCase()];
|
|
if(typeof ce == "object"){
|
|
return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
|
|
}else{
|
|
return true;
|
|
}
|
|
},
|
|
|
|
// private
|
|
filterOptRe : /^(?:scope|delay|buffer|single)$/,
|
|
|
|
/**
|
|
* Appends an event handler to this component
|
|
* @param {String} eventName The type of event to listen for
|
|
* @param {Function} handler The method the event invokes
|
|
* @param {Object} scope (optional) The scope in which to execute the handler
|
|
* function. The handler function's "this" context.
|
|
* @param {Object} options (optional) An object containing handler configuration
|
|
* properties. This may contain any of the following properties:<ul>
|
|
* <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
|
|
* <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
|
|
* <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
|
|
* <li>preventDefault {Boolean} True to prevent the default action</li>
|
|
* <li>stopPropagation {Boolean} True to prevent event propagation</li>
|
|
* <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Ext.EventObject</li>
|
|
* <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
|
|
* <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
|
|
* <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
|
|
* by the specified number of milliseconds. If the event fires again within that time, the original
|
|
* handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
|
|
* </ul>
|
|
* <p>
|
|
* <b>Combining Options</b><br>
|
|
* Using the options argument, it is possible to combine different types of listeners:<br>
|
|
* <br>
|
|
* A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
|
|
* Code:
|
|
* <pre><code>el.on('click', this.onClick, this, {
|
|
* single: true,
|
|
* delay: 100,
|
|
* stopEvent : true,
|
|
* forumId: 4
|
|
* });</pre>
|
|
* <p>
|
|
* The method also allows for a single argument to be passed which is a config object containing properties
|
|
* which specify multiple handlers.
|
|
* <p>
|
|
* <b>Attaching multiple handlers in 1 call</b><br>
|
|
* Code:
|
|
* <pre><code>el.on({
|
|
* 'click' : {
|
|
* fn: this.onClick
|
|
* scope: this,
|
|
* delay: 100
|
|
* },
|
|
* 'mouseover' : {
|
|
* fn: this.onMouseOver
|
|
* scope: this
|
|
* },
|
|
* 'mouseout' : {
|
|
* fn: this.onMouseOut
|
|
* scope: this
|
|
* }
|
|
* });</pre>
|
|
* <p>
|
|
* Or a shorthand syntax:<br>
|
|
* Code:
|
|
* <pre><code>el.on({
|
|
* 'click' : this.onClick,
|
|
* 'mouseover' : this.onMouseOver,
|
|
* 'mouseout' : this.onMouseOut
|
|
* scope: this
|
|
* });</pre>
|
|
*/
|
|
addListener : function(eventName, fn, scope, o){
|
|
if(typeof eventName == "object"){
|
|
o = eventName;
|
|
for(var e in o){
|
|
if(this.filterOptRe.test(e)){
|
|
continue;
|
|
}
|
|
if(typeof o[e] == "function"){
|
|
// shared options
|
|
this.addListener(e, o[e], o.scope, o);
|
|
}else{
|
|
// individual options
|
|
this.addListener(e, o[e].fn, o[e].scope, o[e]);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
o = (!o || typeof o == "boolean") ? {} : o;
|
|
eventName = eventName.toLowerCase();
|
|
var ce = this.events[eventName] || true;
|
|
if(typeof ce == "boolean"){
|
|
ce = new Ext.util.Event(this, eventName);
|
|
this.events[eventName] = ce;
|
|
}
|
|
ce.addListener(fn, scope, o);
|
|
},
|
|
|
|
/**
|
|
* Removes a listener
|
|
* @param {String} eventName The type of event to listen for
|
|
* @param {Function} handler The handler to remove
|
|
* @param {Object} scope (optional) The scope (this object) for the handler
|
|
*/
|
|
removeListener : function(eventName, fn, scope){
|
|
var ce = this.events[eventName.toLowerCase()];
|
|
if(typeof ce == "object"){
|
|
ce.removeListener(fn, scope);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Removes all listeners for this object
|
|
*/
|
|
purgeListeners : function(){
|
|
for(var evt in this.events){
|
|
if(typeof this.events[evt] == "object"){
|
|
this.events[evt].clearListeners();
|
|
}
|
|
}
|
|
},
|
|
|
|
relayEvents : function(o, events){
|
|
var createHandler = function(ename){
|
|
return function(){
|
|
return this.fireEvent.apply(this, Ext.combine(ename, Array.prototype.slice.call(arguments, 0)));
|
|
};
|
|
};
|
|
for(var i = 0, len = events.length; i < len; i++){
|
|
var ename = events[i];
|
|
if(!this.events[ename]){ this.events[ename] = true; };
|
|
o.on(ename, createHandler(ename), this);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Copies any events from the passed object onto this object if they do not already exist. The passed object
|
|
* must also inherit from Observable for this method to have any effect.
|
|
* @param {Object} object The object from which to copy events
|
|
*/
|
|
addEvents : function(o){
|
|
if(!this.events){
|
|
this.events = {};
|
|
}
|
|
Ext.applyIf(this.events, o);
|
|
},
|
|
|
|
/**
|
|
* Checks to see if this object is currently listening for a specified event
|
|
* @param {String} eventName The name of the event to check for
|
|
* @return {Boolean} True if the event is being listened for, else false
|
|
*/
|
|
hasListener : function(eventName){
|
|
var e = this.events[eventName];
|
|
return typeof e == "object" && e.listeners.length > 0;
|
|
}
|
|
};
|
|
/**
|
|
* Appends an event handler to this element (shorthand for addListener)
|
|
* @param {String} eventName The type of event to listen for
|
|
* @param {Function} handler The method the event invokes
|
|
* @param {Object} options (optional)
|
|
* @method
|
|
*/
|
|
Ext.util.Observable.prototype.on = Ext.util.Observable.prototype.addListener;
|
|
/**
|
|
* Removes a listener (shorthand for removeListener)
|
|
* @param {String} eventName The type of event to listen for
|
|
* @param {Function} handler The handler to remove
|
|
* @param {Object} scope (optional) The scope (this object) for the handler
|
|
* @method
|
|
*/
|
|
Ext.util.Observable.prototype.un = Ext.util.Observable.prototype.removeListener;
|
|
|
|
/**
|
|
* Starts capture on the specified Observable. All events will be passed
|
|
* to the supplied function with the event name + standard signature of the event
|
|
* <b>before</b> the event is fired. If the supplied function returns false,
|
|
* the event will not fire.
|
|
* @param {Observable} o The Observable to capture
|
|
* @param {Function} fn The function to call
|
|
* @param {Object} scope (optional) The scope (this object) for the fn
|
|
* @static
|
|
*/
|
|
Ext.util.Observable.capture = function(o, fn, scope){
|
|
o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
|
|
};
|
|
|
|
/**
|
|
* Removes <b>all</b> added captures from the Observable.
|
|
* @param {Observable} o The Observable to release
|
|
* @static
|
|
*/
|
|
Ext.util.Observable.releaseCapture = function(o){
|
|
o.fireEvent = Ext.util.Observable.prototype.fireEvent;
|
|
};
|
|
|
|
(function(){
|
|
|
|
var createBuffered = function(h, o, scope){
|
|
var task = new Ext.util.DelayedTask();
|
|
return function(){
|
|
task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
|
|
};
|
|
};
|
|
|
|
var createSingle = function(h, e, fn, scope){
|
|
return function(){
|
|
e.removeListener(fn, scope);
|
|
return h.apply(scope, arguments);
|
|
};
|
|
};
|
|
|
|
var createDelayed = function(h, o, scope){
|
|
return function(){
|
|
var args = Array.prototype.slice.call(arguments, 0);
|
|
setTimeout(function(){
|
|
h.apply(scope, args);
|
|
}, o.delay || 10);
|
|
};
|
|
};
|
|
|
|
Ext.util.Event = function(obj, name){
|
|
this.name = name;
|
|
this.obj = obj;
|
|
this.listeners = [];
|
|
};
|
|
|
|
Ext.util.Event.prototype = {
|
|
addListener : function(fn, scope, options){
|
|
var o = options || {};
|
|
scope = scope || this.obj;
|
|
if(!this.isListening(fn, scope)){
|
|
var l = {fn: fn, scope: scope, options: o};
|
|
var h = fn;
|
|
if(o.delay){
|
|
h = createDelayed(h, o, scope);
|
|
}
|
|
if(o.single){
|
|
h = createSingle(h, this, fn, scope);
|
|
}
|
|
if(o.buffer){
|
|
h = createBuffered(h, o, scope);
|
|
}
|
|
l.fireFn = h;
|
|
if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
|
|
this.listeners.push(l);
|
|
}else{
|
|
this.listeners = this.listeners.slice(0);
|
|
this.listeners.push(l);
|
|
}
|
|
}
|
|
},
|
|
|
|
findListener : function(fn, scope){
|
|
scope = scope || this.obj;
|
|
var ls = this.listeners;
|
|
for(var i = 0, len = ls.length; i < len; i++){
|
|
var l = ls[i];
|
|
if(l.fn == fn && l.scope == scope){
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
},
|
|
|
|
isListening : function(fn, scope){
|
|
return this.findListener(fn, scope) != -1;
|
|
},
|
|
|
|
removeListener : function(fn, scope){
|
|
var index;
|
|
if((index = this.findListener(fn, scope)) != -1){
|
|
if(!this.firing){
|
|
this.listeners.splice(index, 1);
|
|
}else{
|
|
this.listeners = this.listeners.slice(0);
|
|
this.listeners.splice(index, 1);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
clearListeners : function(){
|
|
this.listeners = [];
|
|
},
|
|
|
|
fire : function(){
|
|
var ls = this.listeners, scope, len = ls.length;
|
|
if(len > 0){
|
|
this.firing = true;
|
|
var args = Array.prototype.slice.call(arguments, 0);
|
|
for(var i = 0; i < len; i++){
|
|
var l = ls[i];
|
|
if(l.fireFn.apply(l.scope, arguments) === false){
|
|
this.firing = false;
|
|
return false;
|
|
}
|
|
}
|
|
this.firing = false;
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
})(); |