JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.5
[ckeditor.git] / _source / plugins / toolbar / plugin.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 The "toolbar" plugin. Renders the default toolbar interface in\r
8  * the editor.\r
9  */\r
10 \r
11 (function()\r
12 {\r
13         var toolbox = function()\r
14         {\r
15                 this.toolbars = [];\r
16                 this.focusCommandExecuted = false;\r
17         };\r
18 \r
19         toolbox.prototype.focus = function()\r
20         {\r
21                 for ( var t = 0, toolbar ; toolbar = this.toolbars[ t++ ] ; )\r
22                 {\r
23                         for ( var i = 0, item ; item = toolbar.items[ i++ ] ; )\r
24                         {\r
25                                 if ( item.focus )\r
26                                 {\r
27                                         item.focus();\r
28                                         return;\r
29                                 }\r
30                         }\r
31                 }\r
32         };\r
33 \r
34         var commands =\r
35         {\r
36                 toolbarFocus :\r
37                 {\r
38                         modes : { wysiwyg : 1, source : 1 },\r
39 \r
40                         exec : function( editor )\r
41                         {\r
42                                 if ( editor.toolbox )\r
43                                 {\r
44                                         editor.toolbox.focusCommandExecuted = true;\r
45 \r
46                                         // Make the first button focus accessible for IE. (#3417)\r
47                                         // Adobe AIR instead need while of delay.\r
48                                         if ( CKEDITOR.env.ie || CKEDITOR.env.air )\r
49                                                 setTimeout( function(){ editor.toolbox.focus(); }, 100 );\r
50                                         else\r
51                                                 editor.toolbox.focus();\r
52                                 }\r
53                         }\r
54                 }\r
55         };\r
56 \r
57         CKEDITOR.plugins.add( 'toolbar',\r
58         {\r
59                 init : function( editor )\r
60                 {\r
61                         var itemKeystroke = function( item, keystroke )\r
62                         {\r
63                                 var next, nextToolGroup, groupItemsCount;\r
64                                 var rtl = editor.lang.dir == 'rtl';\r
65 \r
66                                 switch ( keystroke )\r
67                                 {\r
68                                         case rtl ? 37 : 39 :                                    // RIGHT-ARROW\r
69                                         case 9 :                                        // TAB\r
70                                                 do\r
71                                                 {\r
72                                                         // Look for the next item in the toolbar.\r
73                                                         next = item.next;\r
74 \r
75                                                         if ( !next )\r
76                                                         {\r
77                                                                 nextToolGroup = item.toolbar.next;\r
78                                                                 groupItemsCount = nextToolGroup && nextToolGroup.items.length;\r
79 \r
80                                                                 // Bypass the empty toolgroups.\r
81                                                                 while ( groupItemsCount === 0 )\r
82                                                                 {\r
83                                                                         nextToolGroup = nextToolGroup.next;\r
84                                                                         groupItemsCount = nextToolGroup && nextToolGroup.items.length;\r
85                                                                 }\r
86 \r
87                                                                 if ( nextToolGroup )\r
88                                                                         next = nextToolGroup.items[ 0 ];\r
89                                                         }\r
90 \r
91                                                         item = next;\r
92                                                 }\r
93                                                 while ( item && !item.focus )\r
94 \r
95                                                 // If available, just focus it, otherwise focus the\r
96                                                 // first one.\r
97                                                 if ( item )\r
98                                                         item.focus();\r
99                                                 else\r
100                                                         editor.toolbox.focus();\r
101 \r
102                                                 return false;\r
103 \r
104                                         case rtl ? 39 : 37 :                                    // LEFT-ARROW\r
105                                         case CKEDITOR.SHIFT + 9 :       // SHIFT + TAB\r
106                                                 do\r
107                                                 {\r
108                                                         // Look for the previous item in the toolbar.\r
109                                                         next = item.previous;\r
110 \r
111                                                         if ( !next )\r
112                                                         {\r
113                                                                 nextToolGroup = item.toolbar.previous;\r
114                                                                 groupItemsCount = nextToolGroup && nextToolGroup.items.length;\r
115 \r
116                                                                 // Bypass the empty toolgroups.\r
117                                                                 while ( groupItemsCount === 0 )\r
118                                                                 {\r
119                                                                         nextToolGroup = nextToolGroup.previous;\r
120                                                                         groupItemsCount = nextToolGroup && nextToolGroup.items.length;\r
121                                                                 }\r
122 \r
123                                                                 if ( nextToolGroup )\r
124                                                                         next = nextToolGroup.items[ groupItemsCount - 1 ];\r
125                                                         }\r
126 \r
127                                                         item = next;\r
128                                                 }\r
129                                                 while ( item && !item.focus )\r
130 \r
131                                                 // If available, just focus it, otherwise focus the\r
132                                                 // last one.\r
133                                                 if ( item )\r
134                                                         item.focus();\r
135                                                 else\r
136                                                 {\r
137                                                         var lastToolbarItems = editor.toolbox.toolbars[ editor.toolbox.toolbars.length - 1 ].items;\r
138                                                         lastToolbarItems[ lastToolbarItems.length - 1 ].focus();\r
139                                                 }\r
140 \r
141                                                 return false;\r
142 \r
143                                         case 27 :                                       // ESC\r
144                                                 editor.focus();\r
145                                                 return false;\r
146 \r
147                                         case 13 :                                       // ENTER\r
148                                         case 32 :                                       // SPACE\r
149                                                 item.execute();\r
150                                                 return false;\r
151                                 }\r
152                                 return true;\r
153                         };\r
154 \r
155                         editor.on( 'themeSpace', function( event )\r
156                                 {\r
157                                         if ( event.data.space == editor.config.toolbarLocation )\r
158                                         {\r
159                                                 editor.toolbox = new toolbox();\r
160 \r
161                                                 var labelId = CKEDITOR.tools.getNextId();\r
162 \r
163                                                 var output = [ '<div class="cke_toolbox" role="toolbar" aria-labelledby="', labelId, '" onmousedown="return false;"' ],\r
164                                                         expanded =  editor.config.toolbarStartupExpanded !== false,\r
165                                                         groupStarted;\r
166 \r
167                                                 output.push( expanded ? '>' : ' style="display:none">' );\r
168 \r
169                                                 // Sends the ARIA label.\r
170                                                 output.push( '<span id="', labelId, '" class="cke_voice_label">', editor.lang.toolbar, '</span>' );\r
171 \r
172                                                 var toolbars = editor.toolbox.toolbars,\r
173                                                         toolbar =\r
174                                                                         ( editor.config.toolbar instanceof Array ) ?\r
175                                                                                 editor.config.toolbar\r
176                                                                         :\r
177                                                                                 editor.config[ 'toolbar_' + editor.config.toolbar ];\r
178 \r
179                                                 for ( var r = 0 ; r < toolbar.length ; r++ )\r
180                                                 {\r
181                                                         var row = toolbar[ r ];\r
182 \r
183                                                         // It's better to check if the row object is really\r
184                                                         // available because it's a common mistake to leave\r
185                                                         // an extra comma in the toolbar definition\r
186                                                         // settings, which leads on the editor not loading\r
187                                                         // at all in IE. (#3983)\r
188                                                         if ( !row )\r
189                                                                 continue;\r
190 \r
191                                                         var toolbarId = CKEDITOR.tools.getNextId(),\r
192                                                                 toolbarObj = { id : toolbarId, items : [] };\r
193 \r
194                                                         if ( groupStarted )\r
195                                                         {\r
196                                                                 output.push( '</div>' );\r
197                                                                 groupStarted = 0;\r
198                                                         }\r
199 \r
200                                                         if ( row === '/' )\r
201                                                         {\r
202                                                                 output.push( '<div class="cke_break"></div>' );\r
203                                                                 continue;\r
204                                                         }\r
205 \r
206                                                         output.push( '<span id="', toolbarId, '" class="cke_toolbar" role="presentation"><span class="cke_toolbar_start"></span>' );\r
207 \r
208                                                         // Add the toolbar to the "editor.toolbox.toolbars"\r
209                                                         // array.\r
210                                                         var index = toolbars.push( toolbarObj ) - 1;\r
211 \r
212                                                         // Create the next/previous reference.\r
213                                                         if ( index > 0 )\r
214                                                         {\r
215                                                                 toolbarObj.previous = toolbars[ index - 1 ];\r
216                                                                 toolbarObj.previous.next = toolbarObj;\r
217                                                         }\r
218 \r
219                                                         // Create all items defined for this toolbar.\r
220                                                         for ( var i = 0 ; i < row.length ; i++ )\r
221                                                         {\r
222                                                                 var item,\r
223                                                                         itemName = row[ i ];\r
224 \r
225                                                                 if ( itemName == '-' )\r
226                                                                         item = CKEDITOR.ui.separator;\r
227                                                                 else\r
228                                                                         item = editor.ui.create( itemName );\r
229 \r
230                                                                 if ( item )\r
231                                                                 {\r
232                                                                         if ( item.canGroup )\r
233                                                                         {\r
234                                                                                 if ( !groupStarted )\r
235                                                                                 {\r
236                                                                                         output.push( '<span class="cke_toolgroup" role="presentation">' );\r
237                                                                                         groupStarted = 1;\r
238                                                                                 }\r
239                                                                         }\r
240                                                                         else if ( groupStarted )\r
241                                                                         {\r
242                                                                                 output.push( '</span>' );\r
243                                                                                 groupStarted = 0;\r
244                                                                         }\r
245 \r
246                                                                         var itemObj = item.render( editor, output );\r
247                                                                         index = toolbarObj.items.push( itemObj ) - 1;\r
248 \r
249                                                                         if ( index > 0 )\r
250                                                                         {\r
251                                                                                 itemObj.previous = toolbarObj.items[ index - 1 ];\r
252                                                                                 itemObj.previous.next = itemObj;\r
253                                                                         }\r
254 \r
255                                                                         itemObj.toolbar = toolbarObj;\r
256                                                                         itemObj.onkey = itemKeystroke;\r
257 \r
258                                                                         /*\r
259                                                                          * Fix for #3052:\r
260                                                                          * Prevent JAWS from focusing the toolbar after document load.\r
261                                                                          */\r
262                                                                         itemObj.onfocus = function()\r
263                                                                         {\r
264                                                                                 if ( !editor.toolbox.focusCommandExecuted )\r
265                                                                                         editor.focus();\r
266                                                                         };\r
267                                                                 }\r
268                                                         }\r
269 \r
270                                                         if ( groupStarted )\r
271                                                         {\r
272                                                                 output.push( '</span>' );\r
273                                                                 groupStarted = 0;\r
274                                                         }\r
275 \r
276                                                         output.push( '<span class="cke_toolbar_end"></span></span>' );\r
277                                                 }\r
278 \r
279                                                 output.push( '</div>' );\r
280 \r
281                                                 if ( editor.config.toolbarCanCollapse )\r
282                                                 {\r
283                                                         var collapserFn = CKEDITOR.tools.addFunction(\r
284                                                                 function()\r
285                                                                 {\r
286                                                                         editor.execCommand( 'toolbarCollapse' );\r
287                                                                 });\r
288 \r
289                                                         editor.on( 'destroy', function () {\r
290                                                                         CKEDITOR.tools.removeFunction( collapserFn );\r
291                                                                 });\r
292 \r
293                                                         var collapserId = CKEDITOR.tools.getNextId();\r
294 \r
295                                                         editor.addCommand( 'toolbarCollapse',\r
296                                                                 {\r
297                                                                         exec : function( editor )\r
298                                                                         {\r
299                                                                                 var collapser = CKEDITOR.document.getById( collapserId ),\r
300                                                                                         toolbox = collapser.getPrevious(),\r
301                                                                                         contents = editor.getThemeSpace( 'contents' ),\r
302                                                                                         toolboxContainer = toolbox.getParent(),\r
303                                                                                         contentHeight = parseInt( contents.$.style.height, 10 ),\r
304                                                                                         previousHeight = toolboxContainer.$.offsetHeight,\r
305                                                                                         collapsed = !toolbox.isVisible();\r
306 \r
307                                                                                 if ( !collapsed )\r
308                                                                                 {\r
309                                                                                         toolbox.hide();\r
310                                                                                         collapser.addClass( 'cke_toolbox_collapser_min' );\r
311                                                                                         collapser.setAttribute( 'title', editor.lang.toolbarExpand );\r
312                                                                                 }\r
313                                                                                 else\r
314                                                                                 {\r
315                                                                                         toolbox.show();\r
316                                                                                         collapser.removeClass( 'cke_toolbox_collapser_min' );\r
317                                                                                         collapser.setAttribute( 'title', editor.lang.toolbarCollapse );\r
318                                                                                 }\r
319 \r
320                                                                                 // Update collapser symbol.\r
321                                                                                 collapser.getFirst().setText( collapsed ?\r
322                                                                                         '\u25B2' :              // BLACK UP-POINTING TRIANGLE\r
323                                                                                         '\u25C0' );             // BLACK LEFT-POINTING TRIANGLE\r
324 \r
325                                                                                 var dy = toolboxContainer.$.offsetHeight - previousHeight;\r
326                                                                                 contents.setStyle( 'height', ( contentHeight - dy ) + 'px' );\r
327 \r
328                                                                                 editor.fire( 'resize' );\r
329                                                                         },\r
330 \r
331                                                                         modes : { wysiwyg : 1, source : 1 }\r
332                                                                 } );\r
333 \r
334                                                         output.push( '<a title="' + ( expanded ? editor.lang.toolbarCollapse : editor.lang.toolbarExpand )\r
335                                                                                                           + '" id="' + collapserId + '" tabIndex="-1" class="cke_toolbox_collapser' );\r
336 \r
337                                                         if ( !expanded )\r
338                                                                 output.push( ' cke_toolbox_collapser_min' );\r
339 \r
340                                                         output.push( '" onclick="CKEDITOR.tools.callFunction(' + collapserFn + ')">',\r
341                                                                                 '<span>&#9650;</span>',         // BLACK UP-POINTING TRIANGLE\r
342                                                                                 '</a>' );\r
343                                                 }\r
344 \r
345                                                 event.data.html += output.join( '' );\r
346                                         }\r
347                                 });\r
348 \r
349                         editor.addCommand( 'toolbarFocus', commands.toolbarFocus );\r
350                 }\r
351         });\r
352 })();\r
353 \r
354 /**\r
355  * The UI element that renders a toolbar separator.\r
356  * @type Object\r
357  * @example\r
358  */\r
359 CKEDITOR.ui.separator =\r
360 {\r
361         render : function( editor, output )\r
362         {\r
363                 output.push( '<span class="cke_separator" role="separator"></span>' );\r
364                 return {};\r
365         }\r
366 };\r
367 \r
368 /**\r
369  * The "theme space" to which rendering the toolbar. For the default theme,\r
370  * the recommended options are "top" and "bottom".\r
371  * @type String\r
372  * @default 'top'\r
373  * @see CKEDITOR.config.theme\r
374  * @example\r
375  * config.toolbarLocation = 'bottom';\r
376  */\r
377 CKEDITOR.config.toolbarLocation = 'top';\r
378 \r
379 /**\r
380  * The toolbar definition. It is an array of toolbars (strips),\r
381  * each one being also an array, containing a list of UI items.\r
382  * Note that this setting is composed by "toolbar_" added by the toolbar name,\r
383  * which in this case is called "Basic". This second part of the setting name\r
384  * can be anything. You must use this name in the\r
385  * {@link CKEDITOR.config.toolbar} setting, so you instruct the editor which\r
386  * toolbar_(name) setting to you.\r
387  * @type Array\r
388  * @example\r
389  * // Defines a toolbar with only one strip containing the "Source" button, a\r
390  * // separator and the "Bold" and "Italic" buttons.\r
391  * <b>config.toolbar_Basic =\r
392  * [\r
393  *     [ 'Source', '-', 'Bold', 'Italic' ]\r
394  * ]</b>;\r
395  * config.toolbar = 'Basic';\r
396  */\r
397 CKEDITOR.config.toolbar_Basic =\r
398 [\r
399         ['Bold', 'Italic', '-', 'NumberedList', 'BulletedList', '-', 'Link', 'Unlink','-','About']\r
400 ];\r
401 \r
402 /**\r
403  * This is the default toolbar definition used by the editor. It contains all\r
404  * editor features.\r
405  * @type Array\r
406  * @default (see example)\r
407  * @example\r
408  * // This is actually the default value.\r
409  * config.toolbar_Full =\r
410  * [\r
411  *     ['Source','-','Save','NewPage','Preview','-','Templates'],\r
412  *     ['Cut','Copy','Paste','PasteText','PasteFromWord','-','Print', 'SpellChecker', 'Scayt'],\r
413  *     ['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],\r
414  *     ['Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField'],\r
415  *     '/',\r
416  *     ['Bold','Italic','Underline','Strike','-','Subscript','Superscript'],\r
417  *     ['NumberedList','BulletedList','-','Outdent','Indent','Blockquote','CreateDiv'],\r
418  *     ['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'],\r
419  *     ['BidiLtr', 'BidiRtl' ],\r
420  *     ['Link','Unlink','Anchor'],\r
421  *     ['Image','Flash','Table','HorizontalRule','Smiley','SpecialChar','PageBreak','Iframe'],\r
422  *     '/',\r
423  *     ['Styles','Format','Font','FontSize'],\r
424  *     ['TextColor','BGColor'],\r
425  *     ['Maximize', 'ShowBlocks','-','About']\r
426  * ];\r
427  */\r
428 CKEDITOR.config.toolbar_Full =\r
429 [\r
430         ['Source','-','Save','NewPage','Preview','-','Templates'],\r
431         ['Cut','Copy','Paste','PasteText','PasteFromWord','-','Print', 'SpellChecker', 'Scayt'],\r
432         ['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],\r
433         ['Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField'],\r
434         '/',\r
435         ['Bold','Italic','Underline','Strike','-','Subscript','Superscript'],\r
436         ['NumberedList','BulletedList','-','Outdent','Indent','Blockquote','CreateDiv'],\r
437         ['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'],\r
438         ['BidiLtr', 'BidiRtl' ],\r
439         ['Link','Unlink','Anchor'],\r
440         ['Image','Flash','Table','HorizontalRule','Smiley','SpecialChar','PageBreak','Iframe'],\r
441         '/',\r
442         ['Styles','Format','Font','FontSize'],\r
443         ['TextColor','BGColor'],\r
444         ['Maximize', 'ShowBlocks','-','About']\r
445 ];\r
446 \r
447 /**\r
448  * The toolbox (alias toolbar) definition. It is a toolbar name or an array of\r
449  * toolbars (strips), each one being also an array, containing a list of UI items.\r
450  * @type Array|String\r
451  * @default 'Full'\r
452  * @example\r
453  * // Defines a toolbar with only one strip containing the "Source" button, a\r
454  * // separator and the "Bold" and "Italic" buttons.\r
455  * config.toolbar =\r
456  * [\r
457  *     [ 'Source', '-', 'Bold', 'Italic' ]\r
458  * ];\r
459  * @example\r
460  * // Load toolbar_Name where Name = Basic.\r
461  * config.toolbar = 'Basic';\r
462  */\r
463 CKEDITOR.config.toolbar = 'Full';\r
464 \r
465 /**\r
466  * Whether the toolbar can be collapsed by the user. If disabled, the collapser\r
467  * button will not be displayed.\r
468  * @type Boolean\r
469  * @default true\r
470  * @example\r
471  * config.toolbarCanCollapse = false;\r
472  */\r
473 CKEDITOR.config.toolbarCanCollapse = true;\r
474 \r
475 /**\r
476  * Whether the toolbar must start expanded when the editor is loaded.\r
477  * @name CKEDITOR.config.toolbarStartupExpanded\r
478  * @type Boolean\r
479  * @default true\r
480  * @example\r
481  * config.toolbarStartupExpanded = false;\r
482  */\r