]> git.immae.eu Git - perso/Immae/Projets/packagist/piedsjaloux-ckeditor-component.git/blob - sources/adapters/jquery.js
Add oembed
[perso/Immae/Projets/packagist/piedsjaloux-ckeditor-component.git] / sources / adapters / jquery.js
1 /**
2 * @license Copyright (c) 2003-2017, 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_Adapters.jQuery jQuery Adapter}.
8 */
9
10 /**
11 * @class CKEDITOR_Adapters.jQuery
12 * @singleton
13 *
14 * The jQuery Adapter allows for easy use of basic CKEditor functions and access to the internal API.
15 * To find more information about the jQuery Adapter, go to the [jQuery Adapter section](#!/guide/dev_jquery)
16 * of the Developer's Guide or see the "Create Editors with jQuery" sample.
17 *
18 * @aside guide dev_jquery
19 */
20
21 ( function( $ ) {
22 if ( typeof $ == 'undefined' ) {
23 throw new Error( 'jQuery should be loaded before CKEditor jQuery adapter.' );
24 }
25
26 if ( typeof CKEDITOR == 'undefined' ) {
27 throw new Error( 'CKEditor should be loaded before CKEditor jQuery adapter.' );
28 }
29
30 /**
31 * Allows CKEditor to override `jQuery.fn.val()`. When set to `true`, the `val()` function
32 * used on textarea elements replaced with CKEditor uses the CKEditor API.
33 *
34 * This configuration option is global and is executed during the loading of the jQuery Adapter.
35 * It cannot be customized across editor instances.
36 *
37 * Read more in the [documentation](#!/guide/dev_jquery).
38 *
39 * <script>
40 * CKEDITOR.config.jqueryOverrideVal = true;
41 * </script>
42 *
43 * <!-- Important: The jQuery Adapter is loaded *after* setting jqueryOverrideVal. -->
44 * <script src="/ckeditor/adapters/jquery.js"></script>
45 *
46 * <script>
47 * $( 'textarea' ).ckeditor();
48 * // ...
49 * $( 'textarea' ).val( 'New content' );
50 * </script>
51 *
52 * @cfg {Boolean} [jqueryOverrideVal=true]
53 * @member CKEDITOR.config
54 */
55 CKEDITOR.config.jqueryOverrideVal =
56 typeof CKEDITOR.config.jqueryOverrideVal == 'undefined' ? true : CKEDITOR.config.jqueryOverrideVal;
57
58 // jQuery object methods.
59 $.extend( $.fn, {
60 /**
61 * Returns an existing CKEditor instance for the first matched element.
62 * Allows to easily use the internal API. Does not return a jQuery object.
63 *
64 * Raises an exception if the editor does not exist or is not ready yet.
65 *
66 * @returns CKEDITOR.editor
67 * @deprecated Use {@link #editor editor property} instead.
68 */
69 ckeditorGet: function() {
70 var instance = this.eq( 0 ).data( 'ckeditorInstance' );
71
72 if ( !instance )
73 throw 'CKEditor is not initialized yet, use ckeditor() with a callback.';
74
75 return instance;
76 },
77
78 /**
79 * A jQuery function which triggers the creation of CKEditor with `<textarea>` and
80 * {@link CKEDITOR.dtd#$editable editable} elements.
81 * Every `<textarea>` element will be converted to a classic (`iframe`-based) editor,
82 * while any other supported element will be converted to an inline editor.
83 * This method binds the callback to the `instanceReady` event of all instances.
84 * If the editor has already been created, the callback is fired straightaway.
85 * You can also create multiple editors at once by using `$( '.className' ).ckeditor();`.
86 *
87 * **Note**: jQuery chaining and mixed parameter order is allowed.
88 *
89 * @param {Function} callback
90 * Function to be run on the editor instance. Callback takes the source element as a parameter.
91 *
92 * $( 'textarea' ).ckeditor( function( textarea ) {
93 * // Callback function code.
94 * } );
95 *
96 * @param {Object} config
97 * Configuration options for new instance(s) if not already created.
98 *
99 * $( 'textarea' ).ckeditor( {
100 * uiColor: '#9AB8F3'
101 * } );
102 *
103 * @returns jQuery.fn
104 */
105 ckeditor: function( callback, config ) {
106 if ( !CKEDITOR.env.isCompatible )
107 throw new Error( 'The environment is incompatible.' );
108
109 // Reverse the order of arguments if the first one isn't a function.
110 if ( !$.isFunction( callback ) ) {
111 var tmp = config;
112 config = callback;
113 callback = tmp;
114 }
115
116 // An array of instanceReady callback promises.
117 var promises = [];
118
119 config = config || {};
120
121 // Iterate over the collection.
122 this.each( function() {
123 var $element = $( this ),
124 editor = $element.data( 'ckeditorInstance' ),
125 instanceLock = $element.data( '_ckeditorInstanceLock' ),
126 element = this,
127 dfd = new $.Deferred();
128
129 promises.push( dfd.promise() );
130
131 if ( editor && !instanceLock ) {
132 if ( callback )
133 callback.apply( editor, [ this ] );
134
135 dfd.resolve();
136 } else if ( !instanceLock ) {
137 // CREATE NEW INSTANCE
138
139 // Handle config.autoUpdateElement inside this plugin if desired.
140 if ( config.autoUpdateElement || ( typeof config.autoUpdateElement == 'undefined' && CKEDITOR.config.autoUpdateElement ) ) {
141 config.autoUpdateElementJquery = true;
142 }
143
144 // Always disable config.autoUpdateElement.
145 config.autoUpdateElement = false;
146 $element.data( '_ckeditorInstanceLock', true );
147
148 // Set instance reference in element's data.
149 if ( $( this ).is( 'textarea' ) )
150 editor = CKEDITOR.replace( element, config );
151 else
152 editor = CKEDITOR.inline( element, config );
153
154 $element.data( 'ckeditorInstance', editor );
155
156 // Register callback.
157 editor.on( 'instanceReady', function( evt ) {
158 var editor = evt.editor;
159
160 setTimeout( function() {
161 // Delay bit more if editor is still not ready.
162 if ( !editor.element ) {
163 setTimeout( arguments.callee, 100 );
164 return;
165 }
166
167 // Remove this listener. Triggered when new instance is ready.
168 evt.removeListener();
169
170 /**
171 * Forwards the CKEditor {@link CKEDITOR.editor#event-dataReady dataReady event} as a jQuery event.
172 *
173 * @event dataReady
174 * @param {CKEDITOR.editor} editor Editor instance.
175 */
176 editor.on( 'dataReady', function() {
177 $element.trigger( 'dataReady.ckeditor', [ editor ] );
178 } );
179
180 /**
181 * Forwards the CKEditor {@link CKEDITOR.editor#event-setData setData event} as a jQuery event.
182 *
183 * @event setData
184 * @param {CKEDITOR.editor} editor Editor instance.
185 * @param data
186 * @param {String} data.dataValue The data that will be used.
187 */
188 editor.on( 'setData', function( evt ) {
189 $element.trigger( 'setData.ckeditor', [ editor, evt.data ] );
190 } );
191
192 /**
193 * Forwards the CKEditor {@link CKEDITOR.editor#event-getData getData event} as a jQuery event.
194 *
195 * @event getData
196 * @param {CKEDITOR.editor} editor Editor instance.
197 * @param data
198 * @param {String} data.dataValue The data that will be returned.
199 */
200 editor.on( 'getData', function( evt ) {
201 $element.trigger( 'getData.ckeditor', [ editor, evt.data ] );
202 }, 999 );
203
204 /**
205 * Forwards the CKEditor {@link CKEDITOR.editor#event-destroy destroy event} as a jQuery event.
206 *
207 * @event destroy
208 * @param {CKEDITOR.editor} editor Editor instance.
209 */
210 editor.on( 'destroy', function() {
211 $element.trigger( 'destroy.ckeditor', [ editor ] );
212 } );
213
214 // Overwrite save button to call jQuery submit instead of javascript submit.
215 // Otherwise jQuery.forms does not work properly
216 editor.on( 'save', function() {
217 $( element.form ).submit();
218 return false;
219 }, null, null, 20 );
220
221 // Integrate with form submit.
222 if ( editor.config.autoUpdateElementJquery && $element.is( 'textarea' ) && $( element.form ).length ) {
223 var onSubmit = function() {
224 $element.ckeditor( function() {
225 editor.updateElement();
226 } );
227 };
228
229 // Bind to submit event.
230 $( element.form ).submit( onSubmit );
231
232 // Bind to form-pre-serialize from jQuery Forms plugin.
233 $( element.form ).bind( 'form-pre-serialize', onSubmit );
234
235 // Unbind when editor destroyed.
236 $element.bind( 'destroy.ckeditor', function() {
237 $( element.form ).unbind( 'submit', onSubmit );
238 $( element.form ).unbind( 'form-pre-serialize', onSubmit );
239 } );
240 }
241
242 // Garbage collect on destroy.
243 editor.on( 'destroy', function() {
244 $element.removeData( 'ckeditorInstance' );
245 } );
246
247 // Remove lock.
248 $element.removeData( '_ckeditorInstanceLock' );
249
250 /**
251 * Forwards the CKEditor {@link CKEDITOR.editor#event-instanceReady instanceReady event} as a jQuery event.
252 *
253 * @event instanceReady
254 * @param {CKEDITOR.editor} editor Editor instance.
255 */
256 $element.trigger( 'instanceReady.ckeditor', [ editor ] );
257
258 // Run given (first) code.
259 if ( callback )
260 callback.apply( editor, [ element ] );
261
262 dfd.resolve();
263 }, 0 );
264 }, null, null, 9999 );
265 } else {
266 // Editor is already during creation process, bind our code to the event.
267 editor.once( 'instanceReady', function() {
268 setTimeout( function() {
269 // Delay bit more if editor is still not ready.
270 if ( !editor.element ) {
271 setTimeout( arguments.callee, 100 );
272 return;
273 }
274
275 // Run given code.
276 if ( editor.element.$ == element && callback )
277 callback.apply( editor, [ element ] );
278
279 dfd.resolve();
280 }, 0 );
281 }, null, null, 9999 );
282 }
283 } );
284
285 /**
286 * The [jQuery Promise object]((http://api.jquery.com/promise/)) that handles the asynchronous constructor.
287 * This promise will be resolved after **all** of the constructors.
288 *
289 * @property {Function} promise
290 */
291 var dfd = new $.Deferred();
292
293 this.promise = dfd.promise();
294
295 $.when.apply( this, promises ).then( function() {
296 dfd.resolve();
297 } );
298
299 /**
300 * Existing CKEditor instance. Allows to easily use the internal API.
301 *
302 * **Note**: This is not a jQuery object.
303 *
304 * var editor = $( 'textarea' ).ckeditor().editor;
305 *
306 * @property {CKEDITOR.editor} editor
307 */
308 this.editor = this.eq( 0 ).data( 'ckeditorInstance' );
309
310 return this;
311 }
312 } );
313
314 /**
315 * Overwritten jQuery `val()` method for `<textarea>` elements that have bound CKEditor instances.
316 * This method gets or sets editor content by using the {@link CKEDITOR.editor#method-getData editor.getData()}
317 * or {@link CKEDITOR.editor#method-setData editor.setData()} methods. To handle
318 * the {@link CKEDITOR.editor#method-setData editor.setData()} callback (as `setData` is asynchronous),
319 * `val( 'some data' )` will return a [jQuery Promise object](http://api.jquery.com/promise/).
320 *
321 * @method val
322 * @returns String|Number|Array|jQuery.fn|function(jQuery Promise)
323 */
324 if ( CKEDITOR.config.jqueryOverrideVal ) {
325 $.fn.val = CKEDITOR.tools.override( $.fn.val, function( oldValMethod ) {
326 return function( value ) {
327 // Setter, i.e. .val( "some data" );
328 if ( arguments.length ) {
329 var _this = this,
330 promises = [], //use promise to handle setData callback
331
332 result = this.each( function() {
333 var $elem = $( this ),
334 editor = $elem.data( 'ckeditorInstance' );
335
336 // Handle .val for CKEditor.
337 if ( $elem.is( 'textarea' ) && editor ) {
338 var dfd = new $.Deferred();
339
340 editor.setData( value, function() {
341 dfd.resolve();
342 } );
343
344 promises.push( dfd.promise() );
345 return true;
346 // Call default .val function for rest of elements
347 } else {
348 return oldValMethod.call( $elem, value );
349 }
350 } );
351
352 // If there is no promise return default result (jQuery object of chaining).
353 if ( !promises.length )
354 return result;
355 // Create one promise which will be resolved when all of promises will be done.
356 else {
357 var dfd = new $.Deferred();
358
359 $.when.apply( this, promises ).done( function() {
360 dfd.resolveWith( _this );
361 } );
362
363 return dfd.promise();
364 }
365 }
366 // Getter .val();
367 else {
368 var $elem = $( this ).eq( 0 ),
369 editor = $elem.data( 'ckeditorInstance' );
370
371 if ( $elem.is( 'textarea' ) && editor )
372 return editor.getData();
373 else
374 return oldValMethod.call( $elem );
375 }
376 };
377 } );
378 }
379 } )( window.jQuery );