2 Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
3 For licensing, see LICENSE.html or http://ckeditor.com/license
7 * @fileOverview Defines the {@link CKEDITOR.event} class, which serves as the
8 * base for classes and objects that require event handling features.
11 if ( !CKEDITOR
.event
)
14 * Creates an event class instance. This constructor is rearely used, being
15 * the {@link #.implementOn} function used in class prototypes directly
17 * @class This is a base class for classes and objects that require event
18 * handling features.<br />
20 * Do not confuse this class with {@link CKEDITOR.dom.event} which is
21 * instead used for DOM events. The CKEDITOR.event class implements the
22 * internal event system used by the CKEditor to fire API related events.
25 CKEDITOR
.event = function()
29 * Implements the {@link CKEDITOR.event} features in an object.
30 * @param {Object} targetObject The object into which implement the features.
32 * var myObject = { message : 'Example' };
33 * <b>CKEDITOR.event.implementOn( myObject }</b>;
34 * myObject.on( 'testEvent', function()
36 * alert( this.message ); // "Example"
38 * myObject.fire( 'testEvent' );
40 CKEDITOR
.event
.implementOn = function( targetObject
)
42 var eventProto
= CKEDITOR
.event
.prototype;
44 for ( var prop
in eventProto
)
46 if ( targetObject
[ prop
] == undefined )
47 targetObject
[ prop
] = eventProto
[ prop
];
51 CKEDITOR
.event
.prototype = (function()
53 // Returns the private events object for a given object.
54 var getPrivate = function( obj
)
56 var _
= ( obj
.getPrivate
&& obj
.getPrivate() ) || obj
._
|| ( obj
._
= {} );
57 return _
.events
|| ( _
.events
= {} );
60 var eventEntry = function( eventName
)
62 this.name
= eventName
;
66 eventEntry
.prototype =
68 // Get the listener index for a specified function.
69 // Returns -1 if not found.
70 getListenerIndex : function( listenerFunction
)
72 for ( var i
= 0, listeners
= this.listeners
; i
< listeners
.length
; i
++ )
74 if ( listeners
[i
].fn
== listenerFunction
)
81 return /** @lends CKEDITOR.event.prototype */ {
83 * Registers a listener to a specific event in the current object.
84 * @param {String} eventName The event name to which listen.
85 * @param {Function} listenerFunction The function listening to the
86 * event. A single {@link CKEDITOR.eventInfo} object instanced
87 * is passed to this function containing all the event data.
88 * @param {Object} [scopeObj] The object used to scope the listener
89 * call (the this object. If omitted, the current object is used.
90 * @param {Object} [listenerData] Data to be sent as the
91 * {@link CKEDITOR.eventInfo#listenerData} when calling the
93 * @param {Number} [priority] The listener priority. Lower priority
94 * listeners are called first. Listeners with the same priority
95 * value are called in registration order. Defaults to 10.
97 * someObject.on( 'someEvent', function()
99 * alert( this == someObject ); // "true"
102 * someObject.on( 'someEvent', function()
104 * alert( this == anotherObject ); // "true"
108 * someObject.on( 'someEvent', function( event )
110 * alert( event.listenerData ); // "Example"
112 * , null, 'Example' );
114 * someObject.on( 'someEvent', function() { ... } ); // 2nd called
115 * someObject.on( 'someEvent', function() { ... }, null, null, 100 ); // 3rd called
116 * someObject.on( 'someEvent', function() { ... }, null, null, 1 ); // 1st called
118 on : function( eventName
, listenerFunction
, scopeObj
, listenerData
, priority
)
120 // Get the event entry (create it if needed).
121 var events
= getPrivate( this ),
122 event
= events
[ eventName
] || ( events
[ eventName
] = new eventEntry( eventName
) );
124 if ( event
.getListenerIndex( listenerFunction
) < 0 )
126 // Get the listeners.
127 var listeners
= event
.listeners
;
133 // Default the priority, if needed.
134 if ( isNaN( priority
) )
139 // Create the function to be fired for this listener.
140 var listenerFirer = function( editor
, publisherData
, stopFn
, cancelFn
)
147 data
: publisherData
,
148 listenerData
: listenerData
,
151 removeListener : function()
153 me
.removeListener( eventName
, listenerFunction
);
157 listenerFunction
.call( scopeObj
, ev
);
161 listenerFirer
.fn
= listenerFunction
;
162 listenerFirer
.priority
= priority
;
164 // Search for the right position for this new listener, based on its
166 for ( var i
= listeners
.length
- 1 ; i
>= 0 ; i
-- )
168 // Find the item which should be before the new one.
169 if ( listeners
[ i
].priority
<= priority
)
171 // Insert the listener in the array.
172 listeners
.splice( i
+ 1, 0, listenerFirer
);
177 // If no position has been found (or zero length), put it in
178 // the front of list.
179 listeners
.unshift( listenerFirer
);
184 * Fires an specific event in the object. All registered listeners are
185 * called at this point.
187 * @param {String} eventName The event name to fire.
188 * @param {Object} [data] Data to be sent as the
189 * {@link CKEDITOR.eventInfo#data} when calling the
191 * @param {CKEDITOR.editor} [editor] The editor instance to send as the
192 * {@link CKEDITOR.eventInfo#editor} when calling the
194 * @returns {Boolean|Object} A booloan indicating that the event is to be
195 * canceled, or data returned by one of the listeners.
197 * someObject.on( 'someEvent', function() { ... } );
198 * someObject.on( 'someEvent', function() { ... } );
199 * <b>someObject.fire( 'someEvent' )</b>; // both listeners are called
201 * someObject.on( 'someEvent', function( event )
203 * alert( event.data ); // "Example"
205 * <b>someObject.fire( 'someEvent', 'Example' )</b>;
209 // Create the function that marks the event as stopped.
211 var stopEvent = function()
216 // Create the function that marks the event as canceled.
217 var canceled
= false;
218 var cancelEvent = function()
223 return function( eventName
, data
, editor
)
225 // Get the event entry.
226 var event
= getPrivate( this )[ eventName
];
228 // Save the previous stopped and cancelled states. We may
229 // be nesting fire() calls.
230 var previousStopped
= stopped
,
231 previousCancelled
= canceled
;
233 // Reset the stopped and canceled flags.
234 stopped
= canceled
= false;
238 var listeners
= event
.listeners
;
240 if ( listeners
.length
)
242 // As some listeners may remove themselves from the
243 // event, the original array length is dinamic. So,
244 // let's make a copy of all listeners, so we are
245 // sure we'll call all of them.
246 listeners
= listeners
.slice( 0 );
248 // Loop through all listeners.
249 for ( var i
= 0 ; i
< listeners
.length
; i
++ )
251 // Call the listener, passing the event data.
252 var retData
= listeners
[i
].call( this, editor
, data
, stopEvent
, cancelEvent
);
254 if ( typeof retData
!= 'undefined' )
257 // No further calls is stopped or canceled.
258 if ( stopped
|| canceled
)
264 var ret
= canceled
|| ( typeof data
== 'undefined' ? false : data
);
266 // Restore the previous stopped and canceled states.
267 stopped
= previousStopped
;
268 canceled
= previousCancelled
;
275 * Fires an specific event in the object, releasing all listeners
276 * registered to that event. The same listeners are not called again on
277 * successive calls of it or of {@link #fire}.
278 * @param {String} eventName The event name to fire.
279 * @param {Object} [data] Data to be sent as the
280 * {@link CKEDITOR.eventInfo#data} when calling the
282 * @param {CKEDITOR.editor} [editor] The editor instance to send as the
283 * {@link CKEDITOR.eventInfo#editor} when calling the
285 * @returns {Boolean|Object} A booloan indicating that the event is to be
286 * canceled, or data returned by one of the listeners.
288 * someObject.on( 'someEvent', function() { ... } );
289 * someObject.fire( 'someEvent' ); // above listener called
290 * <b>someObject.fireOnce( 'someEvent' )</b>; // above listener called
291 * someObject.fire( 'someEvent' ); // no listeners called
293 fireOnce : function( eventName
, data
, editor
)
295 var ret
= this.fire( eventName
, data
, editor
);
296 delete getPrivate( this )[ eventName
];
301 * Unregisters a listener function from being called at the specified
302 * event. No errors are thrown if the listener has not been
303 * registered previously.
304 * @param {String} eventName The event name.
305 * @param {Function} listenerFunction The listener function to unregister.
307 * var myListener = function() { ... };
308 * someObject.on( 'someEvent', myListener );
309 * someObject.fire( 'someEvent' ); // myListener called
310 * <b>someObject.removeListener( 'someEvent', myListener )</b>;
311 * someObject.fire( 'someEvent' ); // myListener not called
313 removeListener : function( eventName
, listenerFunction
)
315 // Get the event entry.
316 var event
= getPrivate( this )[ eventName
];
320 var index
= event
.getListenerIndex( listenerFunction
);
322 event
.listeners
.splice( index
, 1 );
327 * Checks if there is any listener registered to a given event.
328 * @param {String} eventName The event name.
330 * var myListener = function() { ... };
331 * someObject.on( 'someEvent', myListener );
332 * alert( someObject.<b>hasListeners( 'someEvent' )</b> ); // "true"
333 * alert( someObject.<b>hasListeners( 'noEvent' )</b> ); // "false"
335 hasListeners : function( eventName
)
337 var event
= getPrivate( this )[ eventName
];
338 return ( event
&& event
.listeners
.length
> 0 ) ;