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