Ext.define('Ext.event.Dispatcher', {
requires: [
'Ext.event.ListenerStack',
'Ext.event.Controller'
],
statics: {
getInstance: function() {
if (!this.instance) {
this.instance = new this();
}
return this.instance;
},
setInstance: function(instance) {
this.instance = instance;
return this;
}
},
config: {
publishers: {}
},
wildcard: '*',
constructor: function(config) {
this.listenerStacks = {};
this.activePublishers = {};
this.publishersCache = {};
this.noActivePublishers = [];
this.controller = null;
this.initConfig(config);
return this;
},
getListenerStack: function(targetType, target, eventName, createIfNotExist) {
var listenerStacks = this.listenerStacks,
map = listenerStacks[targetType],
listenerStack;
if (!map) {
if (createIfNotExist) {
map = listenerStacks[targetType] = {};
}
else {
return null;
}
}
map = map[target];
if (!map) {
if (createIfNotExist) {
map = listenerStacks[targetType][target] = {};
}
else {
return null;
}
}
listenerStack = map[eventName];
if (!listenerStack) {
if (createIfNotExist) {
listenerStack = map[eventName] = new Ext.event.ListenerStack();
}
else {
return null;
}
}
return listenerStack;
},
getController: function(targetType, target, eventName, connectedController) {
var controller = this.controller,
info = {
targetType: targetType,
target: target,
eventName: eventName
};
if (!controller) {
controller = this.controller = new Ext.event.Controller();
}
if (controller.isFiring) {
controller = new Ext.event.Controller();
}
controller.setInfo(info);
if (connectedController && controller !== connectedController) {
controller.connect(connectedController);
}
return controller;
},
applyPublishers: function(publishers) {
var i, publisher;
this.publishersCache = {};
for (i in publishers) {
if (publishers.hasOwnProperty(i)) {
publisher = publishers[i];
this.registerPublisher(publisher);
}
}
return publishers;
},
registerPublisher: function(publisher) {
var targetType = publisher.getTargetType(),
publishers = this.activePublishers[targetType];
if (!publishers) {
publishers = this.activePublishers[targetType] = [];
}
publishers.push(publisher);
publisher.setDispatcher(this);
return this;
},
getCachedActivePublishers: function(targetType, eventName) {
var cache = this.publishersCache,
publishers;
if ((publishers = cache[targetType]) && (publishers = publishers[eventName])) {
return publishers;
}
return null;
},
cacheActivePublishers: function(targetType, eventName, publishers) {
var cache = this.publishersCache;
if (!cache[targetType]) {
cache[targetType] = {};
}
cache[targetType][eventName] = publishers;
return publishers;
},
getActivePublishers: function(targetType, eventName) {
var publishers, activePublishers,
i, ln, publisher;
if ((publishers = this.getCachedActivePublishers(targetType, eventName))) {
return publishers;
}
activePublishers = this.activePublishers[targetType];
if (activePublishers) {
publishers = [];
for (i = 0,ln = activePublishers.length; i < ln; i++) {
publisher = activePublishers[i];
if (publisher.handles(eventName)) {
publishers.push(publisher);
}
}
}
else {
publishers = this.noActivePublishers;
}
return this.cacheActivePublishers(targetType, eventName, publishers);
},
hasListener: function(targetType, target, eventName) {
var listenerStack = this.getListenerStack(targetType, target, eventName);
if (listenerStack) {
return listenerStack.count() > 0;
}
return false;
},
addListener: function(targetType, target, eventName) {
var publishers = this.getActivePublishers(targetType, eventName),
ln = publishers.length,
i;
if (ln > 0) {
for (i = 0; i < ln; i++) {
publishers[i].subscribe(target, eventName);
}
}
return this.doAddListener.apply(this, arguments);
},
doAddListener: function(targetType, target, eventName, fn, scope, options, order) {
var listenerStack = this.getListenerStack(targetType, target, eventName, true);
return listenerStack.add(fn, scope, options, order);
},
removeListener: function(targetType, target, eventName) {
var publishers = this.getActivePublishers(targetType, eventName),
ln = publishers.length,
i;
if (ln > 0) {
for (i = 0; i < ln; i++) {
publishers[i].unsubscribe(target, eventName);
}
}
return this.doRemoveListener.apply(this, arguments);
},
doRemoveListener: function(targetType, target, eventName, fn, scope, order) {
var listenerStack = this.getListenerStack(targetType, target, eventName);
if (listenerStack === null) {
return false;
}
return listenerStack.remove(fn, scope, order);
},
clearListeners: function(targetType, target, eventName) {
var listenerStacks = this.listenerStacks,
ln = arguments.length;
if (ln === 3) {
if (listenerStacks[targetType] && listenerStacks[targetType][target]) {
delete listenerStacks[targetType][target][eventName];
}
}
else if (ln === 2) {
if (listenerStacks[targetType]) {
delete listenerStacks[targetType][target];
}
}
else if (ln === 1) {
delete listenerStacks[targetType];
}
else {
delete this.listenerStacks;
this.listenerStacks = {};
}
return this;
},
dispatchEvent: function(targetType, target, eventName) {
var publishers = this.getActivePublishers(targetType, eventName),
ln = publishers.length,
i;
if (ln > 0) {
for (i = 0; i < ln; i++) {
publishers[i].notify(target, eventName);
}
}
return this.doDispatchEvent.apply(this, arguments);
},
doDispatchEvent: function(targetType, target, eventName, args, actions, connectedController) {
var listenerStack = this.getListenerStack(targetType, target, eventName),
wildcardStacks = this.getWildcardListenerStacks(targetType, target, eventName),
controller;
if (wildcardStacks.length > 0) {
if (!actions) {
actions = [];
}
actions.push({
fn: this.fireListenerStacks,
scope: this,
options: {
args: [wildcardStacks, 0, targetType, target, eventName]
},
order: 'after'
});
}
if ((!listenerStack || listenerStack.length == 0) && (!actions || actions.length == 0)) {
return;
}
controller = this.getController(targetType, target, eventName, connectedController);
controller.setListenerStack(listenerStack);
controller.fire(args, actions);
return !controller.isInterrupted();
},
getWildcardListenerStacks: function(targetType, target, eventName) {
var stacks = [],
wildcard = this.wildcard,
isEventNameNotWildcard = eventName !== wildcard,
isTargetNotWildcard = target !== wildcard,
stack;
if (isEventNameNotWildcard && (stack = this.getListenerStack(targetType, target, wildcard))) {
stacks.push(stack);
}
if (isTargetNotWildcard && (stack = this.getListenerStack(targetType, wildcard, eventName))) {
stacks.push(stack);
}
return stacks;
},
fireListenerStacks: function(listenerStacks, index, targetType, target, eventName) {
var listenerStack = listenerStacks[index],
ln = listenerStacks.length,
controller = this.getController(targetType, target, eventName),
args = Array.prototype.slice.call(arguments, 5, -2),
actions;
if (++index <= ln - 1) {
actions = [{
fn: this.fireListenerStacks,
scope: this,
options: {
args: [listenerStacks, index, targetType, target, eventName]
},
order: 'after'
}];
}
controller.setListenerStack(listenerStack);
controller.fire(args, actions);
}
});