Ça devrait le faire. Maintenant, on va passer au tests / ajustements.
[ckeditor.git] / skins / ckeditor / _source / adapters / jquery.js
1 /*
2 Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
3 For licensing, see LICENSE.html or http://ckeditor.com/license
4 */
5
6 /**
7 * @fileOverview jQuery adapter provides easy use of basic CKEditor functions
8 * and access to internal API. It also integrates some aspects of CKEditor with
9 * jQuery framework.
10 *
11 * Every TEXTAREA, DIV and P elements can be converted to working editor.
12 *
13 * Plugin exposes some of editor's event to jQuery event system. All of those are namespaces inside
14 * ".ckeditor" namespace and can be binded/listened on supported textarea, div and p nodes.
15 *
16 * Available jQuery events:
17 * - instanceReady.ckeditor( editor, rootNode )
18 * Triggered when new instance is ready.
19 * - destroy.ckeditor( editor )
20 * Triggered when instance is destroyed.
21 * - getData.ckeditor( editor, eventData )
22 * Triggered when getData event is fired inside editor. It can change returned data using eventData reference.
23 * - setData.ckeditor( editor )
24 * Triggered when getData event is fired inside editor.
25 *
26 * @example
27 * <script src="jquery.js"></script>
28 * <script src="ckeditor.js"></script>
29 * <script src="adapters/jquery/adapter.js"></script>
30 */
31
32 (function()
33 {
34 /**
35 * Allows CKEditor to override jQuery.fn.val(), making it possible to use the val()
36 * function on textareas, as usual, having it synchronized with CKEditor.<br>
37 * <br>
38 * This configuration option is global and executed during the jQuery Adapter loading.
39 * It can't be customized across editor instances.
40 * @type Boolean
41 * @example
42 * &lt;script&gt;
43 * CKEDITOR.config.jqueryOverrideVal = true;
44 * &lt;/script&gt;
45 * &lt;!-- Important: The JQuery adapter is loaded *after* setting jqueryOverrideVal --&gt;
46 * &lt;script src="/ckeditor/adapters/jquery.js"&gt;&lt;/script&gt;
47 * @example
48 * // ... then later in the code ...
49 *
50 * $( 'textarea' ).ckeditor();
51 * // ...
52 * $( 'textarea' ).val( 'New content' );
53 */
54 CKEDITOR.config.jqueryOverrideVal = typeof CKEDITOR.config.jqueryOverrideVal == 'undefined'
55 ? true : CKEDITOR.config.jqueryOverrideVal;
56
57 var jQuery = window.jQuery;
58
59 if ( typeof jQuery == 'undefined' )
60 return;
61
62 // jQuery object methods.
63 jQuery.extend( jQuery.fn,
64 /** @lends jQuery.fn */
65 {
66 /**
67 * Return existing CKEditor instance for first matched element.
68 * Allows to easily use internal API. Doesn't return jQuery object.
69 *
70 * Raised exception if editor doesn't exist or isn't ready yet.
71 *
72 * @name jQuery.ckeditorGet
73 * @return CKEDITOR.editor
74 * @see CKEDITOR.editor
75 */
76 ckeditorGet: function()
77 {
78 var instance = this.eq( 0 ).data( 'ckeditorInstance' );
79 if ( !instance )
80 throw "CKEditor not yet initialized, use ckeditor() with callback.";
81 return instance;
82 },
83 /**
84 * Triggers creation of CKEditor in all matched elements (reduced to DIV, P and TEXTAREAs).
85 * Binds callback to instanceReady event of all instances. If editor is already created, than
86 * callback is fired right away.
87 *
88 * Mixed parameter order allowed.
89 *
90 * @param callback Function to be run on editor instance. Passed parameters: [ textarea ].
91 * Callback is fiered in "this" scope being ckeditor instance and having source textarea as first param.
92 *
93 * @param config Configuration options for new instance(s) if not already created.
94 * See URL
95 *
96 * @example
97 * $( 'textarea' ).ckeditor( function( textarea ) {
98 * $( textarea ).val( this.getData() )
99 * } );
100 *
101 * @name jQuery.fn.ckeditor
102 * @return jQuery.fn
103 */
104 ckeditor: function( callback, config )
105 {
106 if ( !CKEDITOR.env.isCompatible )
107 return this;
108
109 if ( !jQuery.isFunction( callback ))
110 {
111 var tmp = config;
112 config = callback;
113 callback = tmp;
114 }
115 config = config || {};
116
117 this.filter( 'textarea, div, p' ).each( function()
118 {
119 var $element = jQuery( this ),
120 editor = $element.data( 'ckeditorInstance' ),
121 instanceLock = $element.data( '_ckeditorInstanceLock' ),
122 element = this;
123
124 if ( editor && !instanceLock )
125 {
126 if ( callback )
127 callback.apply( editor, [ this ] );
128 }
129 else if ( !instanceLock )
130 {
131 // CREATE NEW INSTANCE
132
133 // Handle config.autoUpdateElement inside this plugin if desired.
134 if ( config.autoUpdateElement
135 || ( typeof config.autoUpdateElement == 'undefined' && CKEDITOR.config.autoUpdateElement ) )
136 {
137 config.autoUpdateElementJquery = true;
138 }
139
140 // Always disable config.autoUpdateElement.
141 config.autoUpdateElement = false;
142 $element.data( '_ckeditorInstanceLock', true );
143
144 // Set instance reference in element's data.
145 editor = CKEDITOR.replace( element, config );
146 $element.data( 'ckeditorInstance', editor );
147
148 // Register callback.
149 editor.on( 'instanceReady', function( event )
150 {
151 var editor = event.editor;
152 setTimeout( function()
153 {
154 // Delay bit more if editor is still not ready.
155 if ( !editor.element )
156 {
157 setTimeout( arguments.callee, 100 );
158 return;
159 }
160
161 // Remove this listener.
162 event.removeListener( 'instanceReady', this.callee );
163
164 // Forward setData on dataReady.
165 editor.on( 'dataReady', function()
166 {
167 $element.trigger( 'setData' + '.ckeditor', [ editor ] );
168 });
169
170 // Forward getData.
171 editor.on( 'getData', function( event ) {
172 $element.trigger( 'getData' + '.ckeditor', [ editor, event.data ] );
173 }, 999 );
174
175 // Forward destroy event.
176 editor.on( 'destroy', function()
177 {
178 $element.trigger( 'destroy.ckeditor', [ editor ] );
179 });
180
181 // Integrate with form submit.
182 if ( editor.config.autoUpdateElementJquery && $element.is( 'textarea' ) && $element.parents( 'form' ).length )
183 {
184 var onSubmit = function()
185 {
186 $element.ckeditor( function()
187 {
188 editor.updateElement();
189 });
190 };
191
192 // Bind to submit event.
193 $element.parents( 'form' ).submit( onSubmit );
194
195 // Bind to form-pre-serialize from jQuery Forms plugin.
196 $element.parents( 'form' ).bind( 'form-pre-serialize', onSubmit );
197
198 // Unbind when editor destroyed.
199 $element.bind( 'destroy.ckeditor', function()
200 {
201 $element.parents( 'form' ).unbind( 'submit', onSubmit );
202 $element.parents( 'form' ).unbind( 'form-pre-serialize', onSubmit );
203 });
204 }
205
206 // Garbage collect on destroy.
207 editor.on( 'destroy', function()
208 {
209 $element.data( 'ckeditorInstance', null );
210 });
211
212 // Remove lock.
213 $element.data( '_ckeditorInstanceLock', null );
214
215 // Fire instanceReady event.
216 $element.trigger( 'instanceReady.ckeditor', [ editor ] );
217
218 // Run given (first) code.
219 if ( callback )
220 callback.apply( editor, [ element ] );
221 }, 0 );
222 }, null, null, 9999);
223 }
224 else
225 {
226 // Editor is already during creation process, bind our code to the event.
227 CKEDITOR.on( 'instanceReady', function( event )
228 {
229 var editor = event.editor;
230 setTimeout( function()
231 {
232 // Delay bit more if editor is still not ready.
233 if ( !editor.element )
234 {
235 setTimeout( arguments.callee, 100 );
236 return;
237 }
238
239 if ( editor.element.$ == element )
240 {
241 // Run given code.
242 if ( callback )
243 callback.apply( editor, [ element ] );
244 }
245 }, 0 );
246 }, null, null, 9999);
247 }
248 });
249 return this;
250 }
251 });
252
253 // New val() method for objects.
254 if ( CKEDITOR.config.jqueryOverrideVal )
255 {
256 jQuery.fn.val = CKEDITOR.tools.override( jQuery.fn.val, function( oldValMethod )
257 {
258 /**
259 * CKEditor-aware val() method.
260 *
261 * Acts same as original jQuery val(), but for textareas which have CKEditor instances binded to them, method
262 * returns editor's content. It also works for settings values.
263 *
264 * @param oldValMethod
265 * @name jQuery.fn.val
266 */
267 return function( newValue, forceNative )
268 {
269 var isSetter = typeof newValue != 'undefined',
270 result;
271
272 this.each( function()
273 {
274 var $this = jQuery( this ),
275 editor = $this.data( 'ckeditorInstance' );
276
277 if ( !forceNative && $this.is( 'textarea' ) && editor )
278 {
279 if ( isSetter )
280 editor.setData( newValue );
281 else
282 {
283 result = editor.getData();
284 // break;
285 return null;
286 }
287 }
288 else
289 {
290 if ( isSetter )
291 oldValMethod.call( $this, newValue );
292 else
293 {
294 result = oldValMethod.call( $this );
295 // break;
296 return null;
297 }
298 }
299
300 return true;
301 });
302 return isSetter ? this : result;
303 };
304 });
305 }
306 })();