542 lines
19 KiB
HTML
542 lines
19 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
<title>The source code</title>
|
|
<link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
|
|
<script type="text/javascript" src="../resources/prettify/prettify.js"></script>
|
|
<style type="text/css">
|
|
.highlight { display: block; background-color: #ddd; }
|
|
</style>
|
|
<script type="text/javascript">
|
|
function highlight() {
|
|
document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
|
|
}
|
|
</script>
|
|
</head>
|
|
<body onload="prettyPrint(); highlight();">
|
|
<pre class="prettyprint lang-js">(function(){
|
|
|
|
var EXTUTIL = Ext.util,
|
|
EACH = Ext.each,
|
|
TRUE = true,
|
|
FALSE = false;
|
|
<span id='Ext-util-Observable'>/**
|
|
</span> * @class Ext.util.Observable
|
|
* Base class that provides a common interface for publishing events. Subclasses are expected to
|
|
* to have a property "events" with all the events defined, and, optionally, a property "listeners"
|
|
* with configured listeners defined.<br>
|
|
* For example:
|
|
* <pre><code>
|
|
Employee = Ext.extend(Ext.util.Observable, {
|
|
constructor: function(config){
|
|
this.name = config.name;
|
|
this.addEvents({
|
|
"fired" : true,
|
|
"quit" : true
|
|
});
|
|
|
|
// Copy configured listeners into *this* object so that the base class&#39;s
|
|
// constructor will add them.
|
|
this.listeners = config.listeners;
|
|
|
|
// Call our superclass constructor to complete construction process.
|
|
Employee.superclass.constructor.call(this, config)
|
|
}
|
|
});
|
|
</code></pre>
|
|
* This could then be used like this:<pre><code>
|
|
var newEmployee = new Employee({
|
|
name: employeeName,
|
|
listeners: {
|
|
quit: function() {
|
|
// By default, "this" will be the object that fired the event.
|
|
alert(this.name + " has quit!");
|
|
}
|
|
}
|
|
});
|
|
</code></pre>
|
|
*/
|
|
EXTUTIL.Observable = function(){
|
|
<span id='Ext-util-Observable-cfg-listeners'> /**
|
|
</span> * @cfg {Object} listeners (optional) <p>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.</p>
|
|
* <br><p><b><u>DOM events from ExtJs {@link Ext.Component Components}</u></b></p>
|
|
* <br><p>While <i>some</i> ExtJs Component classes export selected DOM events (e.g. "click", "mouseover" etc), this
|
|
* is usually only done when extra value can be added. For example the {@link Ext.DataView DataView}'s
|
|
* <b><code>{@link Ext.DataView#click click}</code></b> event passing the node clicked on. To access DOM
|
|
* events directly from a Component's HTMLElement, listeners must be added to the <i>{@link Ext.Component#getEl Element}</i> after the Component
|
|
* has been rendered. A plugin can simplify this step:<pre><code>
|
|
// Plugin is configured with a listeners config object.
|
|
// The Component is appended to the argument list of all handler functions.
|
|
Ext.DomObserver = Ext.extend(Object, {
|
|
constructor: function(config) {
|
|
this.listeners = config.listeners ? config.listeners : config;
|
|
},
|
|
|
|
// Component passes itself into plugin&#39;s init method
|
|
init: function(c) {
|
|
var p, l = this.listeners;
|
|
for (p in l) {
|
|
if (Ext.isFunction(l[p])) {
|
|
l[p] = this.createHandler(l[p], c);
|
|
} else {
|
|
l[p].fn = this.createHandler(l[p].fn, c);
|
|
}
|
|
}
|
|
|
|
// Add the listeners to the Element immediately following the render call
|
|
c.render = c.render.{@link Function#createSequence createSequence}(function() {
|
|
var e = c.getEl();
|
|
if (e) {
|
|
e.on(l);
|
|
}
|
|
});
|
|
},
|
|
|
|
createHandler: function(fn, c) {
|
|
return function(e) {
|
|
fn.call(this, e, c);
|
|
};
|
|
}
|
|
});
|
|
|
|
var combo = new Ext.form.ComboBox({
|
|
|
|
// Collapse combo when its element is clicked on
|
|
plugins: [ new Ext.DomObserver({
|
|
click: function(evt, comp) {
|
|
comp.collapse();
|
|
}
|
|
})],
|
|
store: myStore,
|
|
typeAhead: true,
|
|
mode: 'local',
|
|
triggerAction: 'all'
|
|
});
|
|
* </code></pre></p>
|
|
*/
|
|
var me = this, e = me.events;
|
|
if(me.listeners){
|
|
me.on(me.listeners);
|
|
delete me.listeners;
|
|
}
|
|
me.events = e || {};
|
|
};
|
|
|
|
EXTUTIL.Observable.prototype = {
|
|
// private
|
|
filterOptRe : /^(?:scope|delay|buffer|single)$/,
|
|
|
|
<span id='Ext-util-Observable-method-fireEvent'> /**
|
|
</span> * <p>Fires the specified event with the passed parameters (minus the event name).</p>
|
|
* <p>An event may be set to bubble up an Observable parent hierarchy (See {@link Ext.Component#getBubbleTarget})
|
|
* by calling {@link #enableBubble}.</p>
|
|
* @param {String} eventName The name of the event to fire.
|
|
* @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 a = Array.prototype.slice.call(arguments, 0),
|
|
ename = a[0].toLowerCase(),
|
|
me = this,
|
|
ret = TRUE,
|
|
ce = me.events[ename],
|
|
cc,
|
|
q,
|
|
c;
|
|
if (me.eventsSuspended === TRUE) {
|
|
if (q = me.eventQueue) {
|
|
q.push(a);
|
|
}
|
|
}
|
|
else if(typeof ce == 'object') {
|
|
if (ce.bubble){
|
|
if(ce.fire.apply(ce, a.slice(1)) === FALSE) {
|
|
return FALSE;
|
|
}
|
|
c = me.getBubbleTarget && me.getBubbleTarget();
|
|
if(c && c.enableBubble) {
|
|
cc = c.events[ename];
|
|
if(!cc || typeof cc != 'object' || !cc.bubble) {
|
|
c.enableBubble(ename);
|
|
}
|
|
return c.fireEvent.apply(c, a);
|
|
}
|
|
}
|
|
else {
|
|
a.shift();
|
|
ret = ce.fire.apply(ce, a);
|
|
}
|
|
}
|
|
return ret;
|
|
},
|
|
|
|
<span id='Ext-util-Observable-method-addListener'> /**
|
|
</span> * Appends an event handler to this object.
|
|
* @param {String} eventName The name of the event to listen for.
|
|
* @param {Function} handler The method the event invokes.
|
|
* @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
|
|
* <b>If omitted, defaults to the object which fired the event.</b>
|
|
* @param {Object} options (optional) An object containing handler configuration.
|
|
* properties. This may contain any of the following properties:<ul>
|
|
* <li><b>scope</b> : Object<div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the handler function is executed.
|
|
* <b>If omitted, defaults to the object which fired the event.</b></div></li>
|
|
* <li><b>delay</b> : Number<div class="sub-desc">The number of milliseconds to delay the invocation of the handler after the event fires.</div></li>
|
|
* <li><b>single</b> : Boolean<div class="sub-desc">True to add a handler to handle just the next firing of the event, and then remove itself.</div></li>
|
|
* <li><b>buffer</b> : Number<div class="sub-desc">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.</div></li>
|
|
* <li><b>target</b> : Observable<div class="sub-desc">Only call the handler if the event was fired on the target Observable, <i>not</i>
|
|
* if the event was bubbled up from a child Observable.</div></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 delayed, one-time listener.
|
|
* <pre><code>
|
|
myDataView.on('click', this.onClick, this, {
|
|
single: true,
|
|
delay: 100
|
|
});</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>
|
|
myGridPanel.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>
|
|
myGridPanel.on({
|
|
'click' : this.onClick,
|
|
'mouseover' : this.onMouseOver,
|
|
'mouseout' : this.onMouseOut,
|
|
scope: this
|
|
});</code></pre>
|
|
*/
|
|
addListener : function(eventName, fn, scope, o){
|
|
var me = this,
|
|
e,
|
|
oe,
|
|
ce;
|
|
|
|
if (typeof eventName == 'object') {
|
|
o = eventName;
|
|
for (e in o) {
|
|
oe = o[e];
|
|
if (!me.filterOptRe.test(e)) {
|
|
me.addListener(e, oe.fn || oe, oe.scope || o.scope, oe.fn ? oe : o);
|
|
}
|
|
}
|
|
} else {
|
|
eventName = eventName.toLowerCase();
|
|
ce = me.events[eventName] || TRUE;
|
|
if (typeof ce == 'boolean') {
|
|
me.events[eventName] = ce = new EXTUTIL.Event(me, eventName);
|
|
}
|
|
ce.addListener(fn, scope, typeof o == 'object' ? o : {});
|
|
}
|
|
},
|
|
|
|
<span id='Ext-util-Observable-method-removeListener'> /**
|
|
</span> * Removes an event handler.
|
|
* @param {String} eventName The type of event the handler was associated with.
|
|
* @param {Function} handler The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
|
|
* @param {Object} scope (optional) The scope originally specified for the handler.
|
|
*/
|
|
removeListener : function(eventName, fn, scope){
|
|
var ce = this.events[eventName.toLowerCase()];
|
|
if (typeof ce == 'object') {
|
|
ce.removeListener(fn, scope);
|
|
}
|
|
},
|
|
|
|
<span id='Ext-util-Observable-method-purgeListeners'> /**
|
|
</span> * Removes all listeners for this object
|
|
*/
|
|
purgeListeners : function(){
|
|
var events = this.events,
|
|
evt,
|
|
key;
|
|
for(key in events){
|
|
evt = events[key];
|
|
if(typeof evt == 'object'){
|
|
evt.clearListeners();
|
|
}
|
|
}
|
|
},
|
|
|
|
<span id='Ext-util-Observable-method-addEvents'> /**
|
|
</span> * Adds the specified events to the list of events which this Observable may fire.
|
|
* @param {Object|String} o Either an object with event names as properties with a value of <code>true</code>
|
|
* or the first event name string if multiple event names are being passed as separate parameters.
|
|
* @param {string} Optional. Event name if multiple event names are being passed as separate parameters.
|
|
* Usage:<pre><code>
|
|
this.addEvents('storeloaded', 'storecleared');
|
|
</code></pre>
|
|
*/
|
|
addEvents : function(o){
|
|
var me = this;
|
|
me.events = me.events || {};
|
|
if (typeof o == 'string') {
|
|
var a = arguments,
|
|
i = a.length;
|
|
while(i--) {
|
|
me.events[a[i]] = me.events[a[i]] || TRUE;
|
|
}
|
|
} else {
|
|
Ext.applyIf(me.events, o);
|
|
}
|
|
},
|
|
|
|
<span id='Ext-util-Observable-method-hasListener'> /**
|
|
</span> * 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.toLowerCase()];
|
|
return typeof e == 'object' && e.listeners.length > 0;
|
|
},
|
|
|
|
<span id='Ext-util-Observable-method-suspendEvents'> /**
|
|
</span> * Suspend the firing of all events. (see {@link #resumeEvents})
|
|
* @param {Boolean} queueSuspended Pass as true to queue up suspended events to be fired
|
|
* after the {@link #resumeEvents} call instead of discarding all suspended events;
|
|
*/
|
|
suspendEvents : function(queueSuspended){
|
|
this.eventsSuspended = TRUE;
|
|
if(queueSuspended && !this.eventQueue){
|
|
this.eventQueue = [];
|
|
}
|
|
},
|
|
|
|
<span id='Ext-util-Observable-method-resumeEvents'> /**
|
|
</span> * Resume firing events. (see {@link #suspendEvents})
|
|
* If events were suspended using the <tt><b>queueSuspended</b></tt> parameter, then all
|
|
* events fired during event suspension will be sent to any listeners now.
|
|
*/
|
|
resumeEvents : function(){
|
|
var me = this,
|
|
queued = me.eventQueue || [];
|
|
me.eventsSuspended = FALSE;
|
|
delete me.eventQueue;
|
|
EACH(queued, function(e) {
|
|
me.fireEvent.apply(me, e);
|
|
});
|
|
}
|
|
};
|
|
|
|
var OBSERVABLE = EXTUTIL.Observable.prototype;
|
|
<span id='Ext-util-Observable-method-on'>/**
|
|
</span> * Appends an event handler to this object (shorthand for {@link #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 (<code><b>this</b></code> reference) in which the handler function is executed.
|
|
* <b>If omitted, defaults to the object which fired the event.</b>
|
|
* @param {Object} options (optional) An object containing handler configuration.
|
|
* @method
|
|
*/
|
|
OBSERVABLE.on = OBSERVABLE.addListener;
|
|
<span id='Ext-util-Observable-method-un'>/**
|
|
</span> * Removes an event handler (shorthand for {@link #removeListener}.)
|
|
* @param {String} eventName The type of event the handler was associated with.
|
|
* @param {Function} handler The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
|
|
* @param {Object} scope (optional) The scope originally specified for the handler.
|
|
* @method
|
|
*/
|
|
OBSERVABLE.un = OBSERVABLE.removeListener;
|
|
|
|
<span id='Ext-util-Observable-static-method-releaseCapture'>/**
|
|
</span> * Removes <b>all</b> added captures from the Observable.
|
|
* @param {Observable} o The Observable to release
|
|
* @static
|
|
*/
|
|
EXTUTIL.Observable.releaseCapture = function(o){
|
|
o.fireEvent = OBSERVABLE.fireEvent;
|
|
};
|
|
|
|
function createTargeted(h, o, scope){
|
|
return function(){
|
|
if(o.target == arguments[0]){
|
|
h.apply(scope, Array.prototype.slice.call(arguments, 0));
|
|
}
|
|
};
|
|
};
|
|
|
|
function createBuffered(h, o, l, scope){
|
|
l.task = new EXTUTIL.DelayedTask();
|
|
return function(){
|
|
l.task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
|
|
};
|
|
};
|
|
|
|
function createSingle(h, e, fn, scope){
|
|
return function(){
|
|
e.removeListener(fn, scope);
|
|
return h.apply(scope, arguments);
|
|
};
|
|
};
|
|
|
|
function createDelayed(h, o, l, scope){
|
|
return function(){
|
|
var task = new EXTUTIL.DelayedTask(),
|
|
args = Array.prototype.slice.call(arguments, 0);
|
|
if(!l.tasks) {
|
|
l.tasks = [];
|
|
}
|
|
l.tasks.push(task);
|
|
task.delay(o.delay || 10, function(){
|
|
l.tasks.remove(task);
|
|
h.apply(scope, args);
|
|
}, scope);
|
|
};
|
|
};
|
|
|
|
EXTUTIL.Event = function(obj, name){
|
|
this.name = name;
|
|
this.obj = obj;
|
|
this.listeners = [];
|
|
};
|
|
|
|
EXTUTIL.Event.prototype = {
|
|
addListener : function(fn, scope, options){
|
|
var me = this,
|
|
l;
|
|
scope = scope || me.obj;
|
|
if(!me.isListening(fn, scope)){
|
|
l = me.createListener(fn, scope, options);
|
|
if(me.firing){ // if we are currently firing this event, don't disturb the listener loop
|
|
me.listeners = me.listeners.slice(0);
|
|
}
|
|
me.listeners.push(l);
|
|
}
|
|
},
|
|
|
|
createListener: function(fn, scope, o){
|
|
o = o || {};
|
|
scope = scope || this.obj;
|
|
var l = {
|
|
fn: fn,
|
|
scope: scope,
|
|
options: o
|
|
}, h = fn;
|
|
if(o.target){
|
|
h = createTargeted(h, o, scope);
|
|
}
|
|
if(o.delay){
|
|
h = createDelayed(h, o, l, scope);
|
|
}
|
|
if(o.single){
|
|
h = createSingle(h, this, fn, scope);
|
|
}
|
|
if(o.buffer){
|
|
h = createBuffered(h, o, l, scope);
|
|
}
|
|
l.fireFn = h;
|
|
return l;
|
|
},
|
|
|
|
findListener : function(fn, scope){
|
|
var list = this.listeners,
|
|
i = list.length,
|
|
l;
|
|
|
|
scope = scope || this.obj;
|
|
while(i--){
|
|
l = list[i];
|
|
if(l){
|
|
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,
|
|
l,
|
|
k,
|
|
me = this,
|
|
ret = FALSE;
|
|
if((index = me.findListener(fn, scope)) != -1){
|
|
if (me.firing) {
|
|
me.listeners = me.listeners.slice(0);
|
|
}
|
|
l = me.listeners[index];
|
|
if(l.task) {
|
|
l.task.cancel();
|
|
delete l.task;
|
|
}
|
|
k = l.tasks && l.tasks.length;
|
|
if(k) {
|
|
while(k--) {
|
|
l.tasks[k].cancel();
|
|
}
|
|
delete l.tasks;
|
|
}
|
|
me.listeners.splice(index, 1);
|
|
ret = TRUE;
|
|
}
|
|
return ret;
|
|
},
|
|
|
|
// Iterate to stop any buffered/delayed events
|
|
clearListeners : function(){
|
|
var me = this,
|
|
l = me.listeners,
|
|
i = l.length;
|
|
while(i--) {
|
|
me.removeListener(l[i].fn, l[i].scope);
|
|
}
|
|
},
|
|
|
|
fire : function(){
|
|
var me = this,
|
|
listeners = me.listeners,
|
|
len = listeners.length,
|
|
i = 0,
|
|
l;
|
|
|
|
if(len > 0){
|
|
me.firing = TRUE;
|
|
var args = Array.prototype.slice.call(arguments, 0);
|
|
for (; i < len; i++) {
|
|
l = listeners[i];
|
|
if(l && l.fireFn.apply(l.scope || me.obj || window, args) === FALSE) {
|
|
return (me.firing = FALSE);
|
|
}
|
|
}
|
|
}
|
|
me.firing = FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
};
|
|
})();
|
|
</pre>
|
|
</body>
|
|
</html>
|