Ext.define('Ext.event.Controller', {
isFiring: false,
listenerStack: null,
constructor: function(info) {
this.firingListeners = [];
this.firingArguments = [];
this.setInfo(info);
return this;
},
setInfo: function(info) {
this.info = info;
},
getInfo: function() {
return this.info;
},
setListenerStack: function(listenerStack) {
this.listenerStack = listenerStack;
},
fire: function(args, actions) {
var listenerStack = this.listenerStack,
firingListeners = this.firingListeners,
firingArguments = this.firingArguments,
push = firingListeners.push,
beforeActions = [],
afterActions = [],
listeners, beforeListeners, currentListeners, afterListeners,
i, ln, action, actionListener, fn;
if (listenerStack) {
listeners = listenerStack.listeners;
beforeListeners = listeners.before;
currentListeners = listeners.current;
afterListeners = listeners.after;
}
if (!args) {
args = [];
}
if (actions) {
for (i = 0,ln = actions.length; i < ln; i++) {
action = actions[i];
fn = action.fn;
actionListener = {
fn: fn,
scope: action.scope,
options: action.options || {},
isLateBinding: typeof fn == 'string'
};
if (action.order === 'before') {
beforeActions.push(actionListener);
}
else {
afterActions.push(actionListener);
}
}
}
firingListeners.length = 0;
if (beforeListeners && beforeListeners.length > 0) {
push.apply(firingListeners, listeners.before);
}
if (beforeActions.length > 0) {
push.apply(firingListeners, beforeActions);
}
if (currentListeners && currentListeners.length > 0) {
push.apply(firingListeners, listeners.current);
}
if (afterActions.length > 0) {
push.apply(firingListeners, afterActions);
}
if (afterListeners && afterListeners.length > 0) {
push.apply(firingListeners, listeners.after);
}
if (firingListeners.length < 1) {
return this;
}
firingArguments.length = 0;
firingArguments.push.apply(firingArguments, args);
// Backwards compatibility
firingArguments.push(null, this);
this.doFire();
return this;
},
doFire: function() {
var listenerStack = this.listenerStack,
firingListeners = this.firingListeners,
firingArguments = this.firingArguments,
optionsArgumentIndex = firingArguments.length - 2,
i, ln, listener, options, fn, firingFn,
boundFn, isLateBinding, scope, args, result;
this.isPausing = false;
this.isPaused = false;
this.isStopped = false;
this.isFiring = true;
for (i = 0, ln = firingListeners.length; i < ln; i++) {
listener = firingListeners[i];
options = listener.options;
fn = listener.fn;
firingFn = listener.firingFn;
boundFn = listener.boundFn;
isLateBinding = listener.isLateBinding;
scope = listener.scope;
// Re-bind the callback if it has changed since the last time it's bound (overridden)
if (isLateBinding && boundFn && boundFn !== scope[fn]) {
boundFn = false;
firingFn = false;
}
if (!boundFn) {
if (isLateBinding) {
boundFn = scope[fn];
if (!boundFn) {
continue;
}
}
else {
boundFn = fn;
}
listener.boundFn = boundFn;
}
if (!firingFn) {
firingFn = boundFn;
if (options.buffer) {
firingFn = Ext.Function.createBuffered(firingFn, options.buffer, scope);
}
if (options.delay) {
firingFn = Ext.Function.createDelayed(firingFn, options.delay, scope);
}
listener.firingFn = firingFn;
}
firingArguments[optionsArgumentIndex] = options;
args = firingArguments;
if (options.args) {
args = options.args.concat(args);
}
if (options.single === true && listenerStack) {
listenerStack.remove(fn, scope, listener.order);
}
result = firingFn.apply(scope, args);
if (result === false) {
this.stop();
}
if (this.isStopped) {
break;
}
else if (result && result instanceof Array) {
firingArguments = this.firingArguments = result.concat([null, this]);
}
if (this.isPausing) {
this.isPaused = true;
firingListeners.splice(0, i + 1);
return;
}
}
this.isFiring = false;
this.listenerStack = null;
firingListeners.length = 0;
firingArguments.length = 0;
this.connectingController = null;
},
connect: function(controller) {
this.connectingController = controller;
},
resume: function() {
var connectingController = this.connectingController;
this.isPausing = false;
if (this.isPaused && this.firingListeners.length > 0) {
this.isPaused = false;
this.doFire();
}
if (connectingController) {
connectingController.resume();
}
return this;
},
isInterrupted: function() {
return this.isStopped || this.isPaused;
},
stop: function() {
var connectingController = this.connectingController;
this.isStopped = true;
if (connectingController) {
this.connectingController = null;
connectingController.stop();
}
this.isFiring = false;
this.listenerStack = null;
return this;
},
pause: function() {
var connectingController = this.connectingController;
this.isPausing = true;
if (connectingController) {
connectingController.pause();
}
return this;
}
});