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