+
+tinymce.util.Dispatcher = function(scope) {
+ this.scope = scope || this;
+ this.listeners = [];
+
+ this.add = function(callback, scope) {
+ this.listeners.push({cb : callback, scope : scope || this.scope});
+
+ return callback;
+ };
+
+ this.addToTop = function(callback, scope) {
+ var self = this, listener = {cb : callback, scope : scope || self.scope};
+
+ // Create new listeners if addToTop is executed in a dispatch loop
+ if (self.inDispatch) {
+ self.listeners = [listener].concat(self.listeners);
+ } else {
+ self.listeners.unshift(listener);
+ }
+
+ return callback;
+ };
+
+ this.remove = function(callback) {
+ var listeners = this.listeners, output = null;
+
+ tinymce.each(listeners, function(listener, i) {
+ if (callback == listener.cb) {
+ output = listener;
+ listeners.splice(i, 1);
+ return false;
+ }
+ });
+
+ return output;
+ };
+
+ this.dispatch = function() {
+ var self = this, returnValue, args = arguments, i, listeners = self.listeners, listener;
+
+ self.inDispatch = true;
+
+ // Needs to be a real loop since the listener count might change while looping
+ // And this is also more efficient
+ for (i = 0; i < listeners.length; i++) {
+ listener = listeners[i];
+ returnValue = listener.cb.apply(listener.scope, args.length > 0 ? args : [listener.scope]);
+
+ if (returnValue === false) {
+ break;
+ }
+ }
+
+ self.inDispatch = false;
+
+ return returnValue;
+ };
+};