123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552 |
- /*
- * Ext JS Library 2.0 Copyright(c) 2006-2007, Ext JS, LLC. licensing@extjs.com
- *
- * http://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.addEvents({
- * "fired" : true,
- * "quit" : true
- * });
- * }
- * Ext.extend(Employee, Ext.util.Observable);
- * </code></pre>
- */
- Ext.util.Observable = function() {
- /**
- * @cfg {Object} listeners A config object containing one or more event
- * handlers to be added to this object during initialization. This
- * should be a valid listeners config object as specified in the
- * {@link #addListener} example for attaching multiple handlers at
- * once.
- */
- 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() {
- if (this.eventsSuspended !== true) {
- var ce = this.events[arguments[0].toLowerCase()];
- if (typeof ce == "object") {
- return ce.fire.apply(ce, Array.prototype.slice.call(arguments,
- 1));
- }
- }
- 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><b>scope</b> : Object
- * <p class="sub-desc">
- * The scope in which to execute the handler function. The
- * handler function's "this" context.
- * </p>
- * </li>
- * <li><b>delay</b> : Number
- * <p class="sub-desc">
- * The number of milliseconds to delay the invocation of the
- * handler after the event fires.
- * </p>
- * </li>
- * <li><b>single</b> : Boolean
- * <p class="sub-desc">
- * True to add a handler to handle just the next firing of the
- * event, and then remove itself.
- * </p>
- * </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>
- * <br>
- * <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)
- *
- * <pre><code>
- * el.on('click', this.onClick, this, {
- * single : true,
- * delay : 100,
- * forumId : 4
- * });
- * </code></pre>
- *
- * <p>
- * <b>Attaching multiple handlers in 1 call</b><br>
- * The method also allows for a single argument to be passed
- * which is a config object containing properties which specify
- * multiple handlers.
- * <p>
- *
- * <pre><code>
- * foo.on({
- * 'click' : {
- * fn : this.onClick,
- * scope : this,
- * delay : 100
- * },
- * 'mouseover' : {
- * fn : this.onMouseOver,
- * scope : this
- * },
- * 'mouseout' : {
- * fn : this.onMouseOut,
- * scope : this
- * }
- * });
- * </code></pre>
- *
- * <p>
- * Or a shorthand syntax:<br>
- *
- * <pre><code>
- * foo.on({
- * 'click' : this.onClick,
- * 'mouseover' : this.onMouseOver,
- * 'mouseout' : this.onMouseOut,
- * scope : this
- * });
- * </code></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);
- }
- },
- /**
- * Used to define events on this Observable
- *
- * @param {Object}
- * object The object with the events defined
- */
- addEvents : function(o) {
- if (!this.events) {
- this.events = {};
- }
- if (typeof o == 'string') {
- for (var i = 0, a = arguments, v; v = a[i]; i++) {
- if (!this.events[a[i]]) {
- o[a[i]] = true;
- }
- }
- } else {
- Ext.applyIf(this.events, o);
- }
- },
- /**
- * Checks to see if this object has any listeners 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;
- },
- /**
- * Suspend the firing of all events. (see {@link #resumeEvents})
- */
- suspendEvents : function() {
- this.eventsSuspended = true;
- },
- /**
- * Resume firing events. (see {@link #suspendEvents})
- */
- resumeEvents : function() {
- this.eventsSuspended = false;
- },
- // these are considered experimental
- // allows for easier interceptor and sequences, including cancelling and
- // overwriting the return value of the call
- // private
- getMethodEvent : function(method) {
- if (!this.methodEvents) {
- this.methodEvents = {};
- }
- var e = this.methodEvents[method];
- if (!e) {
- e = {};
- this.methodEvents[method] = e;
- e.originalFn = this[method];
- e.methodName = method;
- e.before = [];
- e.after = [];
- var returnValue, v, cancel;
- var obj = this;
- var makeCall = function(fn, scope, args) {
- if ((v = fn.apply(scope || obj, args)) !== undefined) {
- if (typeof v === 'object') {
- if (v.returnValue !== undefined) {
- returnValue = v.returnValue;
- } else {
- returnValue = v;
- }
- if (v.cancel === true) {
- cancel = true;
- }
- } else if (v === false) {
- cancel = true;
- } else {
- returnValue = v;
- }
- }
- }
- this[method] = function() {
- returnValue = v = undefined;
- cancel = false;
- var args = Array.prototype.slice.call(arguments, 0);
- for (var i = 0, len = e.before.length; i < len; i++) {
- makeCall(e.before[i].fn, e.before[i].scope, args);
- if (cancel) {
- return returnValue;
- }
- }
- if ((v = e.originalFn.apply(obj, args)) !== undefined) {
- returnValue = v;
- }
- for (var i = 0, len = e.after.length; i < len; i++) {
- makeCall(e.after[i].fn, e.after[i].scope, args);
- if (cancel) {
- return returnValue;
- }
- }
- return returnValue;
- };
- }
- return e;
- },
- // adds an "interceptor" called before the original method
- beforeMethod : function(method, fn, scope) {
- var e = this.getMethodEvent(method);
- e.before.push({
- fn : fn,
- scope : scope
- });
- },
- // adds a "sequence" called after the original method
- afterMethod : function(method, fn, scope) {
- var e = this.getMethodEvent(method);
- e.after.push({
- fn : fn,
- scope : scope
- });
- },
- removeMethodListener : function(method, fn, scope) {
- var e = this.getMethodEvent(method);
- for (var i = 0, len = e.before.length; i < len; i++) {
- if (e.before[i].fn == fn && e.before[i].scope == scope) {
- e.before.splice(i, 1);
- return;
- }
- }
- for (var i = 0, len = e.after.length; i < len; i++) {
- if (e.after[i].fn == fn && e.after[i].scope == scope) {
- e.after.splice(i, 1);
- return;
- }
- }
- }
- };
- /**
- * 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}
- * scope (optional) The scope in which to execute the handler
- * function. The handler function's "this" context.
- * @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) {
- scope = scope || this.obj;
- if (!this.isListening(fn, scope)) {
- var l = this.createListener(fn, scope, options);
- if (!this.firing) {
- this.listeners.push(l);
- } else { // if we are currently firing this event, don't
- // disturb the listener loop
- this.listeners = this.listeners.slice(0);
- this.listeners.push(l);
- }
- }
- },
- createListener : function(fn, scope, o) {
- o = o || {};
- scope = scope || this.obj;
- 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;
- return 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 || this.obj || window, arguments) === false) {
- this.firing = false;
- return false;
- }
- }
- this.firing = false;
- }
- return true;
- }
- };
- })();
|