1/** 2 * Event Mixins 3 * (c) 2006 Seth Dillingham <[email protected]> 4 * 5 * This software is hereby released into the public domain. Do with it as 6 * you please, but with the understanding that it is provided "AS IS" and 7 * without any warranty of any kind. 8 * 9 * (But I'd love to be told about where and how this code is being used.) 10 **/ 11 12/** 13 * Description: 14 * add support (to any object or class) by mixing this class into your own 15 * 16 * Requires prototype.js 17 * 18 * Usage: 19 * To publish custom events: 20 * 1. mix this class with your own via 21 * Object.extend( [your class or prototype], Event.Publisher ) 22 * 2. post events by calling 23 * this.dispatchEvent( [event name], [data for event] ) 24 * 25 * To activate and deactivate the event-tracing feature, just call 26 * this.toggleEventsTrace() 27 **/ 28 29Event.Publisher = Class.create(); 30Object.extend( Event.Publisher, { 31 _ls_event_targets: null, 32 33 _event_source_id: null, 34 35 _fl_trace_events: false, 36 37 getEventSourceId: function() { 38 if ( typeof this._event_source_id == 'function' ) 39 return this._event_source_id(); 40 else 41 return this._event_source_id; 42 }, 43 44 getEventTarget: function( event_name ) { 45 if ( ! this._ls_event_targets ) 46 this._ls_event_targets = new Array(); 47 48 if ( ! this._ls_event_targets[ event_name ] ) 49 document.body.appendChild( 50 this._ls_event_targets[ event_name ] = document.createElement( 'A' ) 51 ); 52 53 return this._ls_event_targets[ event_name ]; 54 }, 55 56 addEventListener: function( event_name, callback_func, capturing ) { 57 var targ = this.getEventTarget( event_name ); 58 59 Event.observe( targ, 'click', callback_func, capturing ); 60 61 if ( this._fl_trace_events ) { 62 var data = { 63 publisher: this.getEventSourceId(), 64 event_name: event_name, 65 listener: callback_func, 66 capturing: capturing, 67 event_source_proxy: targ 68 }; 69 70 this.dispatchEvent( 'eventListenerAdded', data, true, true ); 71 } 72 }, 73 74 removeEventListener: function( event_name, callback_func, capturing ) { 75 var targ = this.getEventTarget( event_name ); 76 77 Event.stopObserving( targ, 'click', callback_func, capturing ); 78 79 if ( this._fl_trace_events ) { 80 var data = { 81 publisher: this.getEventSourceId(), 82 event_name: event_name, 83 listener: callback_func, 84 capturing: capturing, 85 event_source_proxy: targ 86 }; 87 88 this.dispatchEvent( 'eventListenerRemoved', data, true, true ); 89 } 90 }, 91 92 dispatchEvent: function( event_name, data, can_bubble, cancelable ) { 93 var targ = this.getEventTarget( event_name ); 94 var event_data = { 95 event_name: event_name, 96 event_target: this, 97 data: data ? data : null 98 }; 99 100 if ( ! can_bubble ) can_bubble = false; 101 if ( ! cancelable ) cancelable = false; 102 103 var event = Event.create( event_data, can_bubble, cancelable, true, targ ); 104 105 if ( this._fl_trace_events ) { 106 if ( event_name.match( /event(?:ListenerAdded|ListenerRemoved|Dispatched|Received)/ ) ) 107 return; 108 109 var data = { 110 publisher: this.getEventSourceId(), 111 event_name: event_name, 112 event_data: event_data, 113 can_bubble: can_bubble, 114 cancelable: cancelable, 115 event_source_proxy: targ, 116 result: event 117 }; 118 119 this.dispatchEvent( 'eventDispatched', data, true, true ); 120 } 121 }, 122 123 toggleEventsTrace: function() { 124 var trace = Event.Tracer.findTracer(); 125 126 if ( ! trace || ! this._fl_trace_events ) { 127 this._fl_trace_events = true; 128 129 trace = Event.Tracer.startTrace(); 130 131 trace.registerPublisher( this ); 132 } 133 else { 134 this._fl_trace_events = false; 135 136 if ( trace ) 137 trace.unregisterPublisher( this ); 138 } 139 140 return this._fl_trace_events; 141 }, 142 143 isEventsTraceActive: function() { 144 return this._fl_trace_events; 145 } 146} ); 147 148/** 149 * MIX IN: Event.Listener 150 * 151 * Description: 152 * easily add support for receiving totally custom events 153 * (to any object or class) by mixing this class into 154 * your own 155 * 156 * Usage: 157 * To receive custom events: 158 * 1. mix this class with your own via 159 * Object.extend( [your class or prototype], EventListener ) 160 * 2. listen for events by calling (from your object) 161 * this.listen() 162 * (see params for this.listen, below) 163 **/ 164Event.Listener = Class.create(); 165Object.extend( Event.Listener, 166{ 167 _listens: null, 168 169 getEventHandlerName: function( event_name ) { 170 var onEvent_name = event_name.split( /[ _]/ ).join( '-' ).camelize(); 171 172 return "on" + onEvent_name.charAt( 0 ).toUpperCase() + onEvent_name.substr( 1 ); 173 }, 174 175 /**
176 * Params: 177 * event_source [object]: 178 * the object which will generate the events, and which implements (or 179 * mixes in) the Event.Publisher interface (we need addEventListener) 180 * event_name [string]: 181 * the name of the event for which your object will listen 182 * use_capture [boolean]: 183 * standard DOM Event API param 184 * onEvent_name [string]: 185 * the name of the method in your object which will be called when the 186 * event is received if you omit this param, listen will look for a 187 * function named with the CapitalizedCamelCased name of the event with 188 * "on" at the front. So, if the event is named "message_received", 189 * we'll look for a function named "onMessageReceived" You can override 190 * this behavior by overriding getEventHandlerName in your object. 191 **/ 192 listenForEvent: function( event_source, event_name, use_capture, onEvent_name ) { 193 if ( ! onEvent_name ) 194 onEvent_name = this.getEventHandlerName( event_name ); 195 196 if ( ! this._listens ) this._listens = new Array(); 197 198 //added this in to allow for anonymous function handling of an event 199 var eventHandler = this[onEvent_name]; 200 201 if(typeof(onEvent_name) == 'function') { 202 eventHandler = onEvent_name; 203 } 204 205 var cb = eventHandler.bindAsEventListener( this ); 206 this._listens.push( [ event_source, event_name, use_capture, onEvent_name, cb ] ) 207 208 event_source.addEventListener( event_name, cb, use_capture ); 209 }, 210 211 stopListeningForEvent: function( event_source, event_name, use_capture, onEvent_name ) { 212 if ( ! this._listens ) return false; 213 214 if ( ! onEvent_name ) 215 onEvent_name = this.getEventHandlerName( event_name ); 216 217 var ix_item = -1; 218 var ls = this._listens.detect( function( val, ix ) { 219 if ( ( val[ 0 ] == event_source ) 220 && ( val[ 1 ] == event_name ) 221 && ( val[ 2 ] == use_capture ) 222 && ( val[ 3 ] == onEvent_name ) ) { 223 ix_item = ix; 224 return true; 225 } 226 } ); 227 228 if ( ix_item >= 0 ) { 229 this._listens.splice( ix_item, 1 ); 230 231 event_source.removeEventListener( event_name, ls[ 4 ], use_capture ); 232 233 return true; 234 } 235 236 return false; 237 } 238} ); 239 240/** 241 * Extensions to Prototype's Event object, 242 * for cleanly creating and dispatching custom events 243 * 244 * Called from Event.Publisher 245 **/ 246Object.extend( Event, 247{ 248 create: function( event_data, can_bubble, cancelable, fl_dispatch, target ) { 249 var event; 250 251 if ( document.createEvent ) { // gecko, safari 252 if ( ! can_bubble ) can_bubble = false; 253 if ( ! cancelable ) cancelable = false; 254 255 if ( /Konqueror|Safari|KHTML/.test( navigator.userAgent ) ) { 256 event = document.createEvent( 'HTMLEvents' ) 257 258 event.initEvent( 'click', can_bubble, cancelable ); 259 } 260 else { // gecko uses MouseEvents 261 event = document.createEvent( 'MouseEvents' ) 262 263 event.initMouseEvent( "click", can_bubble, cancelable, 264 window, 0, 0, 0, 0, 0, 265 false, false, false, false, 0, null ); 266 } 267 } 268 else { // msie 269 event = document.createEventObject(); 270 event.event_type = 'onclick'; 271 } 272 273 event.event_data = event_data; 274 275 if ( fl_dispatch ) 276 Event.dispatch( target, event ); 277 278 return event; 279 }, 280 281 dispatch: function( target, event ) { 282 if ( document.createEvent ) 283 return target.dispatchEvent( event ); 284 else 285 return target.fireEvent( ( typeof( event.event_type ) != "undefined" ) ? event.event_type : 'onclick', event ); 286 } 287} ); 288 289
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.