/* --- name: Events.Pseudos description: Adds the functionality to add pseudo events license: MIT-style license authors: - Arian Stolwijk requires: [Core/Class.Extras, Core/Slick.Parser, MooTools.More] provides: [Events.Pseudos] ... */ (function(){ Events.Pseudos = function(pseudos, addEvent, removeEvent){ var storeKey = '_monitorEvents:'; var storageOf = function(object){ return { store: object.store ? function(key, value){ object.store(storeKey + key, value); } : function(key, value){ (object._monitorEvents || (object._monitorEvents = {}))[key] = value; }, retrieve: object.retrieve ? function(key, dflt){ return object.retrieve(storeKey + key, dflt); } : function(key, dflt){ if (!object._monitorEvents) return dflt; return object._monitorEvents[key] || dflt; } }; }; var splitType = function(type){ if (type.indexOf(':') == -1 || !pseudos) return null; var parsed = Slick.parse(type).expressions[0][0], parsedPseudos = parsed.pseudos, l = parsedPseudos.length, splits = []; while (l--){ var pseudo = parsedPseudos[l].key, listener = pseudos[pseudo]; if (listener != null) splits.push({ event: parsed.tag, value: parsedPseudos[l].value, pseudo: pseudo, original: type, listener: listener }); } return splits.length ? splits : null; }; return { addEvent: function(type, fn, internal){ var split = splitType(type); if (!split) return addEvent.call(this, type, fn, internal); var storage = storageOf(this), events = storage.retrieve(type, []), eventType = split[0].event, args = Array.slice(arguments, 2), stack = fn, self = this; split.each(function(item){ var listener = item.listener, stackFn = stack; if (listener == false) eventType += ':' + item.pseudo + '(' + item.value + ')'; else stack = function(){ listener.call(self, item, stackFn, arguments, stack); }; }); events.include({type: eventType, event: fn, monitor: stack}); storage.store(type, events); if (type != eventType) addEvent.apply(this, [type, fn].concat(args)); return addEvent.apply(this, [eventType, stack].concat(args)); }, removeEvent: function(type, fn){ var split = splitType(type); if (!split) return removeEvent.call(this, type, fn); var storage = storageOf(this), events = storage.retrieve(type); if (!events) return this; var args = Array.slice(arguments, 2); removeEvent.apply(this, [type, fn].concat(args)); events.each(function(monitor, i){ if (!fn || monitor.event == fn) removeEvent.apply(this, [monitor.type, monitor.monitor].concat(args)); delete events[i]; }, this); storage.store(type, events); return this; } }; }; var pseudos = { once: function(split, fn, args, monitor){ fn.apply(this, args); this.removeEvent(split.event, monitor) .removeEvent(split.original, fn); }, throttle: function(split, fn, args){ if (!fn._throttled){ fn.apply(this, args); fn._throttled = setTimeout(function(){ fn._throttled = false; }, split.value || 250); } }, pause: function(split, fn, args){ clearTimeout(fn._pause); fn._pause = fn.delay(split.value || 250, this, args); } }; Events.definePseudo = function(key, listener){ pseudos[key] = listener; return this; }; Events.lookupPseudo = function(key){ return pseudos[key]; }; var proto = Events.prototype; Events.implement(Events.Pseudos(pseudos, proto.addEvent, proto.removeEvent)); ['Request', 'Fx'].each(function(klass){ if (this[klass]) this[klass].implement(Events.prototype); }); })();