1/** 2 * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved. 3 * CKEditor 4 LTS ("Long Term Support") is available under the terms of the Extended Support Model. 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 {@glink guide/dev_jquery jQuery Adapter section} 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 {@glink guide/dev_jquery documentation}. 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 ( typeof callback !== 'function' ) { 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 waitForEditor() { 161 // Delay bit more if editor is still not ready. 162 if ( !editor.element ) { 163 setTimeout( waitForEditor, 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 ).trigger('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 ).on( 'submit', onSubmit ); 231 232 // Bind to form-pre-serialize from jQuery Forms plugin. 233 $( element.form ).on( 'form-pre-serialize', onSubmit ); 234 235 // Unbind when editor destroyed. 236 $element.on( 'destroy.ckeditor', function() { 237 $( element.form ).off( 'submit', onSubmit ); 238 $( element.form ).off( '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 waitForEditor() { 269 // Delay bit more if editor is still not ready. 270 if ( !editor.element ) { 271 setTimeout( waitForEditor, 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 );
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.