diff options
author | Ismaël Bouya <ismael.bouya@normalesup.org> | 2016-02-19 23:38:52 +0100 |
---|---|---|
committer | Ismaël Bouya <ismael.bouya@normalesup.org> | 2016-02-19 23:38:52 +0100 |
commit | 3332bebe4da6dfa0fe3e4b2abddc84b1cc62f8f5 (patch) | |
tree | a4f77655fe55b79606e7d3416504686a1ab8b058 /sources/core/event.js | |
download | piedsjaloux-ckeditor-component-3332bebe4da6dfa0fe3e4b2abddc84b1cc62f8f5.tar.gz piedsjaloux-ckeditor-component-3332bebe4da6dfa0fe3e4b2abddc84b1cc62f8f5.tar.zst piedsjaloux-ckeditor-component-3332bebe4da6dfa0fe3e4b2abddc84b1cc62f8f5.zip |
Initial commit4.5.7
Diffstat (limited to 'sources/core/event.js')
-rw-r--r-- | sources/core/event.js | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/sources/core/event.js b/sources/core/event.js new file mode 100644 index 0000000..0dd1f41 --- /dev/null +++ b/sources/core/event.js | |||
@@ -0,0 +1,389 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | |||
6 | /** | ||
7 | * @fileOverview Defines the {@link CKEDITOR.event} class, which serves as the | ||
8 | * base for classes and objects that require event handling features. | ||
9 | */ | ||
10 | |||
11 | if ( !CKEDITOR.event ) { | ||
12 | /** | ||
13 | * Creates an event class instance. This constructor is rarely used, being | ||
14 | * the {@link #implementOn} function used in class prototypes directly | ||
15 | * instead. | ||
16 | * | ||
17 | * This is a base class for classes and objects that require event | ||
18 | * handling features. | ||
19 | * | ||
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. | ||
23 | * | ||
24 | * @class | ||
25 | * @constructor Creates an event class instance. | ||
26 | */ | ||
27 | CKEDITOR.event = function() {}; | ||
28 | |||
29 | /** | ||
30 | * Implements the {@link CKEDITOR.event} features in an object. | ||
31 | * | ||
32 | * var myObject = { message: 'Example' }; | ||
33 | * CKEDITOR.event.implementOn( myObject ); | ||
34 | * | ||
35 | * myObject.on( 'testEvent', function() { | ||
36 | * alert( this.message ); | ||
37 | * } ); | ||
38 | * myObject.fire( 'testEvent' ); // 'Example' | ||
39 | * | ||
40 | * @static | ||
41 | * @param {Object} targetObject The object into which implement the features. | ||
42 | */ | ||
43 | CKEDITOR.event.implementOn = function( targetObject ) { | ||
44 | var eventProto = CKEDITOR.event.prototype; | ||
45 | |||
46 | for ( var prop in eventProto ) { | ||
47 | if ( targetObject[ prop ] == null ) | ||
48 | targetObject[ prop ] = eventProto[ prop ]; | ||
49 | } | ||
50 | }; | ||
51 | |||
52 | CKEDITOR.event.prototype = ( function() { | ||
53 | // Returns the private events object for a given object. | ||
54 | var getPrivate = function( obj ) { | ||
55 | var _ = ( obj.getPrivate && obj.getPrivate() ) || obj._ || ( obj._ = {} ); | ||
56 | return _.events || ( _.events = {} ); | ||
57 | }; | ||
58 | |||
59 | var eventEntry = function( eventName ) { | ||
60 | this.name = eventName; | ||
61 | this.listeners = []; | ||
62 | }; | ||
63 | |||
64 | eventEntry.prototype = { | ||
65 | // Get the listener index for a specified function. | ||
66 | // Returns -1 if not found. | ||
67 | getListenerIndex: function( listenerFunction ) { | ||
68 | for ( var i = 0, listeners = this.listeners; i < listeners.length; i++ ) { | ||
69 | if ( listeners[ i ].fn == listenerFunction ) | ||
70 | return i; | ||
71 | } | ||
72 | return -1; | ||
73 | } | ||
74 | }; | ||
75 | |||
76 | // Retrieve the event entry on the event host (create it if needed). | ||
77 | function getEntry( name ) { | ||
78 | // Get the event entry (create it if needed). | ||
79 | var events = getPrivate( this ); | ||
80 | return events[ name ] || ( events[ name ] = new eventEntry( name ) ); | ||
81 | } | ||
82 | |||
83 | return { | ||
84 | /** | ||
85 | * Predefine some intrinsic properties on a specific event name. | ||
86 | * | ||
87 | * @param {String} name The event name | ||
88 | * @param meta | ||
89 | * @param [meta.errorProof=false] Whether the event firing should catch error thrown from a per listener call. | ||
90 | */ | ||
91 | define: function( name, meta ) { | ||
92 | var entry = getEntry.call( this, name ); | ||
93 | CKEDITOR.tools.extend( entry, meta, true ); | ||
94 | }, | ||
95 | |||
96 | /** | ||
97 | * Registers a listener to a specific event in the current object. | ||
98 | * | ||
99 | * someObject.on( 'someEvent', function() { | ||
100 | * alert( this == someObject ); // true | ||
101 | * } ); | ||
102 | * | ||
103 | * someObject.on( 'someEvent', function() { | ||
104 | * alert( this == anotherObject ); // true | ||
105 | * }, anotherObject ); | ||
106 | * | ||
107 | * someObject.on( 'someEvent', function( event ) { | ||
108 | * alert( event.listenerData ); // 'Example' | ||
109 | * }, null, 'Example' ); | ||
110 | * | ||
111 | * someObject.on( 'someEvent', function() { ... } ); // 2nd called | ||
112 | * someObject.on( 'someEvent', function() { ... }, null, null, 100 ); // 3rd called | ||
113 | * someObject.on( 'someEvent', function() { ... }, null, null, 1 ); // 1st called | ||
114 | * | ||
115 | * @param {String} eventName The event name to which listen. | ||
116 | * @param {Function} listenerFunction The function listening to the | ||
117 | * event. A single {@link CKEDITOR.eventInfo} object instanced | ||
118 | * is passed to this function containing all the event data. | ||
119 | * @param {Object} [scopeObj] The object used to scope the listener | ||
120 | * call (the `this` object). If omitted, the current object is used. | ||
121 | * @param {Object} [listenerData] Data to be sent as the | ||
122 | * {@link CKEDITOR.eventInfo#listenerData} when calling the | ||
123 | * listener. | ||
124 | * @param {Number} [priority=10] The listener priority. Lower priority | ||
125 | * listeners are called first. Listeners with the same priority | ||
126 | * value are called in registration order. | ||
127 | * @returns {Object} An object containing the `removeListener` | ||
128 | * function, which can be used to remove the listener at any time. | ||
129 | */ | ||
130 | on: function( eventName, listenerFunction, scopeObj, listenerData, priority ) { | ||
131 | // Create the function to be fired for this listener. | ||
132 | function listenerFirer( editor, publisherData, stopFn, cancelFn ) { | ||
133 | var ev = { | ||
134 | name: eventName, | ||
135 | sender: this, | ||
136 | editor: editor, | ||
137 | data: publisherData, | ||
138 | listenerData: listenerData, | ||
139 | stop: stopFn, | ||
140 | cancel: cancelFn, | ||
141 | removeListener: removeListener | ||
142 | }; | ||
143 | |||
144 | var ret = listenerFunction.call( scopeObj, ev ); | ||
145 | |||
146 | return ret === false ? false : ev.data; | ||
147 | } | ||
148 | |||
149 | function removeListener() { | ||
150 | me.removeListener( eventName, listenerFunction ); | ||
151 | } | ||
152 | |||
153 | var event = getEntry.call( this, eventName ); | ||
154 | |||
155 | if ( event.getListenerIndex( listenerFunction ) < 0 ) { | ||
156 | // Get the listeners. | ||
157 | var listeners = event.listeners; | ||
158 | |||
159 | // Fill the scope. | ||
160 | if ( !scopeObj ) | ||
161 | scopeObj = this; | ||
162 | |||
163 | // Default the priority, if needed. | ||
164 | if ( isNaN( priority ) ) | ||
165 | priority = 10; | ||
166 | |||
167 | var me = this; | ||
168 | |||
169 | listenerFirer.fn = listenerFunction; | ||
170 | listenerFirer.priority = priority; | ||
171 | |||
172 | // Search for the right position for this new listener, based on its | ||
173 | // priority. | ||
174 | for ( var i = listeners.length - 1; i >= 0; i-- ) { | ||
175 | // Find the item which should be before the new one. | ||
176 | if ( listeners[ i ].priority <= priority ) { | ||
177 | // Insert the listener in the array. | ||
178 | listeners.splice( i + 1, 0, listenerFirer ); | ||
179 | return { removeListener: removeListener }; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | // If no position has been found (or zero length), put it in | ||
184 | // the front of list. | ||
185 | listeners.unshift( listenerFirer ); | ||
186 | } | ||
187 | |||
188 | return { removeListener: removeListener }; | ||
189 | }, | ||
190 | |||
191 | /** | ||
192 | * Similiar with {@link #on} but the listener will be called only once upon the next event firing. | ||
193 | * | ||
194 | * @see CKEDITOR.event#on | ||
195 | */ | ||
196 | once: function() { | ||
197 | var args = Array.prototype.slice.call( arguments ), | ||
198 | fn = args[ 1 ]; | ||
199 | |||
200 | args[ 1 ] = function( evt ) { | ||
201 | evt.removeListener(); | ||
202 | return fn.apply( this, arguments ); | ||
203 | }; | ||
204 | |||
205 | return this.on.apply( this, args ); | ||
206 | }, | ||
207 | |||
208 | /** | ||
209 | * @static | ||
210 | * @property {Boolean} useCapture | ||
211 | * @todo | ||
212 | */ | ||
213 | |||
214 | /** | ||
215 | * Register event handler under the capturing stage on supported target. | ||
216 | */ | ||
217 | capture: function() { | ||
218 | CKEDITOR.event.useCapture = 1; | ||
219 | var retval = this.on.apply( this, arguments ); | ||
220 | CKEDITOR.event.useCapture = 0; | ||
221 | return retval; | ||
222 | }, | ||
223 | |||
224 | /** | ||
225 | * Fires an specific event in the object. All registered listeners are | ||
226 | * called at this point. | ||
227 | * | ||
228 | * someObject.on( 'someEvent', function() { ... } ); | ||
229 | * someObject.on( 'someEvent', function() { ... } ); | ||
230 | * someObject.fire( 'someEvent' ); // Both listeners are called. | ||
231 | * | ||
232 | * someObject.on( 'someEvent', function( event ) { | ||
233 | * alert( event.data ); // 'Example' | ||
234 | * } ); | ||
235 | * someObject.fire( 'someEvent', 'Example' ); | ||
236 | * | ||
237 | * @method | ||
238 | * @param {String} eventName The event name to fire. | ||
239 | * @param {Object} [data] Data to be sent as the | ||
240 | * {@link CKEDITOR.eventInfo#data} when calling the listeners. | ||
241 | * @param {CKEDITOR.editor} [editor] The editor instance to send as the | ||
242 | * {@link CKEDITOR.eventInfo#editor} when calling the listener. | ||
243 | * @returns {Boolean/Object} A boolean indicating that the event is to be | ||
244 | * canceled, or data returned by one of the listeners. | ||
245 | */ | ||
246 | fire: ( function() { | ||
247 | // Create the function that marks the event as stopped. | ||
248 | var stopped = 0; | ||
249 | var stopEvent = function() { | ||
250 | stopped = 1; | ||
251 | }; | ||
252 | |||
253 | // Create the function that marks the event as canceled. | ||
254 | var canceled = 0; | ||
255 | var cancelEvent = function() { | ||
256 | canceled = 1; | ||
257 | }; | ||
258 | |||
259 | return function( eventName, data, editor ) { | ||
260 | // Get the event entry. | ||
261 | var event = getPrivate( this )[ eventName ]; | ||
262 | |||
263 | // Save the previous stopped and cancelled states. We may | ||
264 | // be nesting fire() calls. | ||
265 | var previousStopped = stopped, | ||
266 | previousCancelled = canceled; | ||
267 | |||
268 | // Reset the stopped and canceled flags. | ||
269 | stopped = canceled = 0; | ||
270 | |||
271 | if ( event ) { | ||
272 | var listeners = event.listeners; | ||
273 | |||
274 | if ( listeners.length ) { | ||
275 | // As some listeners may remove themselves from the | ||
276 | // event, the original array length is dinamic. So, | ||
277 | // let's make a copy of all listeners, so we are | ||
278 | // sure we'll call all of them. | ||
279 | listeners = listeners.slice( 0 ); | ||
280 | |||
281 | var retData; | ||
282 | // Loop through all listeners. | ||
283 | for ( var i = 0; i < listeners.length; i++ ) { | ||
284 | // Call the listener, passing the event data. | ||
285 | if ( event.errorProof ) { | ||
286 | try { | ||
287 | retData = listeners[ i ].call( this, editor, data, stopEvent, cancelEvent ); | ||
288 | } catch ( er ) {} | ||
289 | } else { | ||
290 | retData = listeners[ i ].call( this, editor, data, stopEvent, cancelEvent ); | ||
291 | } | ||
292 | |||
293 | if ( retData === false ) | ||
294 | canceled = 1; | ||
295 | else if ( typeof retData != 'undefined' ) | ||
296 | data = retData; | ||
297 | |||
298 | // No further calls is stopped or canceled. | ||
299 | if ( stopped || canceled ) | ||
300 | break; | ||
301 | } | ||
302 | } | ||
303 | } | ||
304 | |||
305 | var ret = canceled ? false : ( typeof data == 'undefined' ? true : data ); | ||
306 | |||
307 | // Restore the previous stopped and canceled states. | ||
308 | stopped = previousStopped; | ||
309 | canceled = previousCancelled; | ||
310 | |||
311 | return ret; | ||
312 | }; | ||
313 | } )(), | ||
314 | |||
315 | /** | ||
316 | * Fires an specific event in the object, releasing all listeners | ||
317 | * registered to that event. The same listeners are not called again on | ||
318 | * successive calls of it or of {@link #fire}. | ||
319 | * | ||
320 | * someObject.on( 'someEvent', function() { ... } ); | ||
321 | * someObject.fire( 'someEvent' ); // Above listener called. | ||
322 | * someObject.fireOnce( 'someEvent' ); // Above listener called. | ||
323 | * someObject.fire( 'someEvent' ); // No listeners called. | ||
324 | * | ||
325 | * @param {String} eventName The event name to fire. | ||
326 | * @param {Object} [data] Data to be sent as the | ||
327 | * {@link CKEDITOR.eventInfo#data} when calling the listeners. | ||
328 | * @param {CKEDITOR.editor} [editor] The editor instance to send as the | ||
329 | * {@link CKEDITOR.eventInfo#editor} when calling the listener. | ||
330 | * @returns {Boolean/Object} A booloan indicating that the event is to be | ||
331 | * canceled, or data returned by one of the listeners. | ||
332 | */ | ||
333 | fireOnce: function( eventName, data, editor ) { | ||
334 | var ret = this.fire( eventName, data, editor ); | ||
335 | delete getPrivate( this )[ eventName ]; | ||
336 | return ret; | ||
337 | }, | ||
338 | |||
339 | /** | ||
340 | * Unregisters a listener function from being called at the specified | ||
341 | * event. No errors are thrown if the listener has not been registered previously. | ||
342 | * | ||
343 | * var myListener = function() { ... }; | ||
344 | * someObject.on( 'someEvent', myListener ); | ||
345 | * someObject.fire( 'someEvent' ); // myListener called. | ||
346 | * someObject.removeListener( 'someEvent', myListener ); | ||
347 | * someObject.fire( 'someEvent' ); // myListener not called. | ||
348 | * | ||
349 | * @param {String} eventName The event name. | ||
350 | * @param {Function} listenerFunction The listener function to unregister. | ||
351 | */ | ||
352 | removeListener: function( eventName, listenerFunction ) { | ||
353 | // Get the event entry. | ||
354 | var event = getPrivate( this )[ eventName ]; | ||
355 | |||
356 | if ( event ) { | ||
357 | var index = event.getListenerIndex( listenerFunction ); | ||
358 | if ( index >= 0 ) | ||
359 | event.listeners.splice( index, 1 ); | ||
360 | } | ||
361 | }, | ||
362 | |||
363 | /** | ||
364 | * Remove all existing listeners on this object, for cleanup purpose. | ||
365 | */ | ||
366 | removeAllListeners: function() { | ||
367 | var events = getPrivate( this ); | ||
368 | for ( var i in events ) | ||
369 | delete events[ i ]; | ||
370 | }, | ||
371 | |||
372 | /** | ||
373 | * Checks if there is any listener registered to a given event. | ||
374 | * | ||
375 | * var myListener = function() { ... }; | ||
376 | * someObject.on( 'someEvent', myListener ); | ||
377 | * alert( someObject.hasListeners( 'someEvent' ) ); // true | ||
378 | * alert( someObject.hasListeners( 'noEvent' ) ); // false | ||
379 | * | ||
380 | * @param {String} eventName The event name. | ||
381 | * @returns {Boolean} | ||
382 | */ | ||
383 | hasListeners: function( eventName ) { | ||
384 | var event = getPrivate( this )[ eventName ]; | ||
385 | return ( event && event.listeners.length > 0 ); | ||
386 | } | ||
387 | }; | ||
388 | } )(); | ||
389 | } | ||