// Based on event:Selectors by Justin Palmer // http://encytemedia.com/event-selectors/ // // Usage: // // Event.addBehavior({ // "selector:event" : function(event) { /* event handler. this refers to the element. */ }, // "selector" : function() { /* runs function on dom ready. this refers to the element. */ } // ... // }); // // Multiple calls will add to exisiting rules. Event.addBehavior.reassignAfterAjax and // Event.addBehavior.autoTrigger can be adjusted to needs. Event.addBehavior = function(rules) { var ab = this.addBehavior; Object.extend(ab.rules, rules); if (!ab.responderApplied) { Ajax.Responders.register({ onComplete : function() { if (Event.addBehavior.reassignAfterAjax) setTimeout(function() { ab.reload() }, 10); } }); ab.responderApplied = true; } if (ab.autoTrigger) { this.onReady(ab.load.bind(ab, rules)); } }; Event.delegate = function(rules) { return function(e) { var element = $(e.element()); for (var selector in rules) if (element.match(selector)) return rules[selector].apply(this, $A(arguments)); } } Object.extend(Event.addBehavior, { rules : {}, cache : [], reassignAfterAjax : false, autoTrigger : true, load : function(rules) { for (var selector in rules) { var observer = rules[selector]; var sels = selector.split(','); sels.each(function(sel) { var parts = sel.split(/:(?=[a-z]+$)/), css = parts[0], event = parts[1]; $$(css).each(function(element) { if (event) { observer = Event.addBehavior._wrapObserver(observer); $(element).observe(event, observer); Event.addBehavior.cache.push([element, event, observer]); } else { if (!element.$$assigned || !element.$$assigned.include(observer)) { if (observer.attach) observer.attach(element); else observer.call($(element)); element.$$assigned = element.$$assigned || []; element.$$assigned.push(observer); } } }); }); } }, unload : function() { this.cache.each(function(c) { Event.stopObserving.apply(Event, c); }); this.cache = []; }, reload: function() { var ab = Event.addBehavior; ab.unload(); ab.load(ab.rules); }, _wrapObserver: function(observer) { return function(event) { if (observer.call(this, event) === false) event.stop(); } } }); Event.observe(window, 'unload', Event.addBehavior.unload.bind(Event.addBehavior)); // A silly Prototype style shortcut for the reckless $$$ = Event.addBehavior.bind(Event); // Behaviors can be bound to elements to provide an object orientated way of controlling elements // and their behavior. Use Behavior.create() to make a new behavior class then use attach() to // glue it to an element. Each element then gets it's own instance of the behavior and any // methods called onxxx are bound to the relevent event. // // Usage: // // var MyBehavior = Behavior.create({ // onmouseover : function() { this.element.addClassName('bong') } // }); // // Event.addBehavior({ 'a.rollover' : MyBehavior }); // // If you need to pass additional values to initialize use: // // Event.addBehavior({ 'a.rollover' : MyBehavior(10, { thing : 15 }) }) // // You can also use the attach() method. If you specify extra arguments to attach they get passed to initialize. // // MyBehavior.attach(el, values, to, init); // // Finally, the rawest method is using the new constructor normally: // var draggable = new Draggable(element, init, vals); // // Each behaviour has a collection of all its instances in Behavior.instances // var Behavior = { create: function() { var parent = null, properties = $A(arguments); if (Object.isFunction(properties[0])) parent = properties.shift(); var behavior = function() { var behavior = arguments.callee; if (!this.initialize) { var args = $A(arguments); return function() { var initArgs = [this].concat(args); behavior.attach.apply(behavior, initArgs); }; } else { var args = (arguments.length == 2 && arguments[1] instanceof Array) ? arguments[1] : Array.prototype.slice.call(arguments, 1); this.element = $(arguments[0]); this.initialize.apply(this, args); behavior._bindEvents(this); behavior.instances.push(this); } }; Object.extend(behavior, Class.Methods); Object.extend(behavior, Behavior.Methods); behavior.superclass = parent; behavior.subclasses = []; behavior.instances = []; if (parent) { var subclass = function() { }; subclass.prototype = parent.prototype; behavior.prototype = new subclass; parent.subclasses.push(behavior); } for (var i = 0; i < properties.length; i++) behavior.addMethods(properties[i]); if (!behavior.prototype.initialize) behavior.prototype.initialize = Prototype.emptyFunction; behavior.prototype.constructor = behavior; return behavior; }, Methods : { attach : function(element) { return new this(element, Array.prototype.slice.call(arguments, 1)); }, _bindEvents : function(bound) { for (var member in bound) if (member.match(/^on(.+)/) && typeof bound[member] == 'function') bound.element.observe(RegExp.$1, Event.addBehavior._wrapObserver(bound[member].bindAsEventListener(bound))); } } };