diff options
Diffstat (limited to 'sources/plugins/toolbar/plugin.js')
-rw-r--r-- | sources/plugins/toolbar/plugin.js | 806 |
1 files changed, 806 insertions, 0 deletions
diff --git a/sources/plugins/toolbar/plugin.js b/sources/plugins/toolbar/plugin.js new file mode 100644 index 0000000..b267b51 --- /dev/null +++ b/sources/plugins/toolbar/plugin.js | |||
@@ -0,0 +1,806 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | |||
6 | /** | ||
7 | * @fileOverview The "toolbar" plugin. Renders the default toolbar interface in | ||
8 | * the editor. | ||
9 | */ | ||
10 | |||
11 | ( function() { | ||
12 | var toolbox = function() { | ||
13 | this.toolbars = []; | ||
14 | this.focusCommandExecuted = false; | ||
15 | }; | ||
16 | |||
17 | toolbox.prototype.focus = function() { | ||
18 | for ( var t = 0, toolbar; toolbar = this.toolbars[ t++ ]; ) { | ||
19 | for ( var i = 0, item; item = toolbar.items[ i++ ]; ) { | ||
20 | if ( item.focus ) { | ||
21 | item.focus(); | ||
22 | return; | ||
23 | } | ||
24 | } | ||
25 | } | ||
26 | }; | ||
27 | |||
28 | var commands = { | ||
29 | toolbarFocus: { | ||
30 | modes: { wysiwyg: 1, source: 1 }, | ||
31 | readOnly: 1, | ||
32 | |||
33 | exec: function( editor ) { | ||
34 | if ( editor.toolbox ) { | ||
35 | editor.toolbox.focusCommandExecuted = true; | ||
36 | |||
37 | // Make the first button focus accessible for IE. (#3417) | ||
38 | // Adobe AIR instead need while of delay. | ||
39 | if ( CKEDITOR.env.ie || CKEDITOR.env.air ) { | ||
40 | setTimeout( function() { | ||
41 | editor.toolbox.focus(); | ||
42 | }, 100 ); | ||
43 | } else { | ||
44 | editor.toolbox.focus(); | ||
45 | } | ||
46 | } | ||
47 | } | ||
48 | } | ||
49 | }; | ||
50 | |||
51 | CKEDITOR.plugins.add( 'toolbar', { | ||
52 | requires: 'button', | ||
53 | // jscs:disable maximumLineLength | ||
54 | lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE% | ||
55 | // jscs:enable maximumLineLength | ||
56 | |||
57 | init: function( editor ) { | ||
58 | var endFlag; | ||
59 | |||
60 | var itemKeystroke = function( item, keystroke ) { | ||
61 | var next, toolbar; | ||
62 | var rtl = editor.lang.dir == 'rtl', | ||
63 | toolbarGroupCycling = editor.config.toolbarGroupCycling, | ||
64 | // Picking right/left key codes. | ||
65 | rightKeyCode = rtl ? 37 : 39, | ||
66 | leftKeyCode = rtl ? 39 : 37; | ||
67 | |||
68 | toolbarGroupCycling = toolbarGroupCycling === undefined || toolbarGroupCycling; | ||
69 | |||
70 | switch ( keystroke ) { | ||
71 | case 9: // TAB | ||
72 | case CKEDITOR.SHIFT + 9: // SHIFT + TAB | ||
73 | // Cycle through the toolbars, starting from the one | ||
74 | // closest to the current item. | ||
75 | while ( !toolbar || !toolbar.items.length ) { | ||
76 | if ( keystroke == 9 ) { | ||
77 | toolbar = ( ( toolbar ? toolbar.next : item.toolbar.next ) || editor.toolbox.toolbars[ 0 ] ); | ||
78 | } else { | ||
79 | toolbar = ( ( toolbar ? toolbar.previous : item.toolbar.previous ) || editor.toolbox.toolbars[ editor.toolbox.toolbars.length - 1 ] ); | ||
80 | } | ||
81 | |||
82 | // Look for the first item that accepts focus. | ||
83 | if ( toolbar.items.length ) { | ||
84 | item = toolbar.items[ endFlag ? ( toolbar.items.length - 1 ) : 0 ]; | ||
85 | while ( item && !item.focus ) { | ||
86 | item = endFlag ? item.previous : item.next; | ||
87 | |||
88 | if ( !item ) | ||
89 | toolbar = 0; | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | |||
94 | if ( item ) | ||
95 | item.focus(); | ||
96 | |||
97 | return false; | ||
98 | |||
99 | case rightKeyCode: | ||
100 | next = item; | ||
101 | do { | ||
102 | // Look for the next item in the toolbar. | ||
103 | next = next.next; | ||
104 | |||
105 | // If it's the last item, cycle to the first one. | ||
106 | if ( !next && toolbarGroupCycling ) next = item.toolbar.items[ 0 ]; | ||
107 | } | ||
108 | while ( next && !next.focus ); | ||
109 | |||
110 | // If available, just focus it, otherwise focus the | ||
111 | // first one. | ||
112 | if ( next ) | ||
113 | next.focus(); | ||
114 | else | ||
115 | // Send a TAB. | ||
116 | itemKeystroke( item, 9 ); | ||
117 | |||
118 | return false; | ||
119 | case 40: // DOWN-ARROW | ||
120 | if ( item.button && item.button.hasArrow ) { | ||
121 | // Note: code is duplicated in plugins\richcombo\plugin.js in keyDownFn(). | ||
122 | editor.once( 'panelShow', function( evt ) { | ||
123 | evt.data._.panel._.currentBlock.onKeyDown( 40 ); | ||
124 | } ); | ||
125 | item.execute(); | ||
126 | } else { | ||
127 | // Send left arrow key. | ||
128 | itemKeystroke( item, keystroke == 40 ? rightKeyCode : leftKeyCode ); | ||
129 | } | ||
130 | return false; | ||
131 | case leftKeyCode: | ||
132 | case 38: // UP-ARROW | ||
133 | next = item; | ||
134 | do { | ||
135 | // Look for the previous item in the toolbar. | ||
136 | next = next.previous; | ||
137 | |||
138 | // If it's the first item, cycle to the last one. | ||
139 | if ( !next && toolbarGroupCycling ) next = item.toolbar.items[ item.toolbar.items.length - 1 ]; | ||
140 | } | ||
141 | while ( next && !next.focus ); | ||
142 | |||
143 | // If available, just focus it, otherwise focus the | ||
144 | // last one. | ||
145 | if ( next ) | ||
146 | next.focus(); | ||
147 | else { | ||
148 | endFlag = 1; | ||
149 | // Send a SHIFT + TAB. | ||
150 | itemKeystroke( item, CKEDITOR.SHIFT + 9 ); | ||
151 | endFlag = 0; | ||
152 | } | ||
153 | |||
154 | return false; | ||
155 | |||
156 | case 27: // ESC | ||
157 | editor.focus(); | ||
158 | return false; | ||
159 | |||
160 | case 13: // ENTER | ||
161 | case 32: // SPACE | ||
162 | item.execute(); | ||
163 | return false; | ||
164 | } | ||
165 | return true; | ||
166 | }; | ||
167 | |||
168 | editor.on( 'uiSpace', function( event ) { | ||
169 | if ( event.data.space != editor.config.toolbarLocation ) | ||
170 | return; | ||
171 | |||
172 | // Create toolbar only once. | ||
173 | event.removeListener(); | ||
174 | |||
175 | editor.toolbox = new toolbox(); | ||
176 | |||
177 | var labelId = CKEDITOR.tools.getNextId(); | ||
178 | |||
179 | var output = [ | ||
180 | '<span id="', labelId, '" class="cke_voice_label">', editor.lang.toolbar.toolbars, '</span>', | ||
181 | '<span id="' + editor.ui.spaceId( 'toolbox' ) + '" class="cke_toolbox" role="group" aria-labelledby="', labelId, '" onmousedown="return false;">' | ||
182 | ]; | ||
183 | |||
184 | var expanded = editor.config.toolbarStartupExpanded !== false, | ||
185 | groupStarted, pendingSeparator; | ||
186 | |||
187 | // If the toolbar collapser will be available, we'll have | ||
188 | // an additional container for all toolbars. | ||
189 | if ( editor.config.toolbarCanCollapse && editor.elementMode != CKEDITOR.ELEMENT_MODE_INLINE ) | ||
190 | output.push( '<span class="cke_toolbox_main"' + ( expanded ? '>' : ' style="display:none">' ) ); | ||
191 | |||
192 | var toolbars = editor.toolbox.toolbars, | ||
193 | toolbar = getToolbarConfig( editor ), | ||
194 | toolbarLength = toolbar.length; | ||
195 | |||
196 | for ( var r = 0; r < toolbarLength; r++ ) { | ||
197 | var toolbarId, | ||
198 | toolbarObj = 0, | ||
199 | toolbarName, | ||
200 | row = toolbar[ r ], | ||
201 | lastToolbarInRow = row !== '/' && ( toolbar[ r + 1 ] === '/' || r == toolbarLength - 1 ), | ||
202 | items; | ||
203 | |||
204 | // It's better to check if the row object is really | ||
205 | // available because it's a common mistake to leave | ||
206 | // an extra comma in the toolbar definition | ||
207 | // settings, which leads on the editor not loading | ||
208 | // at all in IE. (#3983) | ||
209 | if ( !row ) | ||
210 | continue; | ||
211 | |||
212 | if ( groupStarted ) { | ||
213 | output.push( '</span>' ); | ||
214 | groupStarted = 0; | ||
215 | pendingSeparator = 0; | ||
216 | } | ||
217 | |||
218 | if ( row === '/' ) { | ||
219 | output.push( '<span class="cke_toolbar_break"></span>' ); | ||
220 | continue; | ||
221 | } | ||
222 | |||
223 | items = row.items || row; | ||
224 | |||
225 | // Create all items defined for this toolbar. | ||
226 | for ( var i = 0; i < items.length; i++ ) { | ||
227 | var item = items[ i ], | ||
228 | canGroup; | ||
229 | |||
230 | if ( item ) { | ||
231 | if ( item.type == CKEDITOR.UI_SEPARATOR ) { | ||
232 | // Do not add the separator immediately. Just save | ||
233 | // it be included if we already have something in | ||
234 | // the toolbar and if a new item is to be added (later). | ||
235 | pendingSeparator = groupStarted && item; | ||
236 | continue; | ||
237 | } | ||
238 | |||
239 | canGroup = item.canGroup !== false; | ||
240 | |||
241 | // Initialize the toolbar first, if needed. | ||
242 | if ( !toolbarObj ) { | ||
243 | // Create the basic toolbar object. | ||
244 | toolbarId = CKEDITOR.tools.getNextId(); | ||
245 | toolbarObj = { id: toolbarId, items: [] }; | ||
246 | toolbarName = row.name && ( editor.lang.toolbar.toolbarGroups[ row.name ] || row.name ); | ||
247 | |||
248 | // Output the toolbar opener. | ||
249 | output.push( '<span id="', toolbarId, '" class="cke_toolbar' + ( lastToolbarInRow ? ' cke_toolbar_last"' : '"' ), | ||
250 | ( toolbarName ? ' aria-labelledby="' + toolbarId + '_label"' : '' ), ' role="toolbar">' ); | ||
251 | |||
252 | // If a toolbar name is available, send the voice label. | ||
253 | toolbarName && output.push( '<span id="', toolbarId, '_label" class="cke_voice_label">', toolbarName, '</span>' ); | ||
254 | |||
255 | output.push( '<span class="cke_toolbar_start"></span>' ); | ||
256 | |||
257 | // Add the toolbar to the "editor.toolbox.toolbars" | ||
258 | // array. | ||
259 | var index = toolbars.push( toolbarObj ) - 1; | ||
260 | |||
261 | // Create the next/previous reference. | ||
262 | if ( index > 0 ) { | ||
263 | toolbarObj.previous = toolbars[ index - 1 ]; | ||
264 | toolbarObj.previous.next = toolbarObj; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | if ( canGroup ) { | ||
269 | if ( !groupStarted ) { | ||
270 | output.push( '<span class="cke_toolgroup" role="presentation">' ); | ||
271 | groupStarted = 1; | ||
272 | } | ||
273 | } else if ( groupStarted ) { | ||
274 | output.push( '</span>' ); | ||
275 | groupStarted = 0; | ||
276 | } | ||
277 | |||
278 | function addItem( item ) { // jshint ignore:line | ||
279 | var itemObj = item.render( editor, output ); | ||
280 | index = toolbarObj.items.push( itemObj ) - 1; | ||
281 | |||
282 | if ( index > 0 ) { | ||
283 | itemObj.previous = toolbarObj.items[ index - 1 ]; | ||
284 | itemObj.previous.next = itemObj; | ||
285 | } | ||
286 | |||
287 | itemObj.toolbar = toolbarObj; | ||
288 | itemObj.onkey = itemKeystroke; | ||
289 | |||
290 | // Fix for #3052: | ||
291 | // Prevent JAWS from focusing the toolbar after document load. | ||
292 | itemObj.onfocus = function() { | ||
293 | if ( !editor.toolbox.focusCommandExecuted ) | ||
294 | editor.focus(); | ||
295 | }; | ||
296 | } | ||
297 | |||
298 | if ( pendingSeparator ) { | ||
299 | addItem( pendingSeparator ); | ||
300 | pendingSeparator = 0; | ||
301 | } | ||
302 | |||
303 | addItem( item ); | ||
304 | } | ||
305 | } | ||
306 | |||
307 | if ( groupStarted ) { | ||
308 | output.push( '</span>' ); | ||
309 | groupStarted = 0; | ||
310 | pendingSeparator = 0; | ||
311 | } | ||
312 | |||
313 | if ( toolbarObj ) | ||
314 | output.push( '<span class="cke_toolbar_end"></span></span>' ); | ||
315 | } | ||
316 | |||
317 | if ( editor.config.toolbarCanCollapse ) | ||
318 | output.push( '</span>' ); | ||
319 | |||
320 | // Not toolbar collapser for inline mode. | ||
321 | if ( editor.config.toolbarCanCollapse && editor.elementMode != CKEDITOR.ELEMENT_MODE_INLINE ) { | ||
322 | var collapserFn = CKEDITOR.tools.addFunction( function() { | ||
323 | editor.execCommand( 'toolbarCollapse' ); | ||
324 | } ); | ||
325 | |||
326 | editor.on( 'destroy', function() { | ||
327 | CKEDITOR.tools.removeFunction( collapserFn ); | ||
328 | } ); | ||
329 | |||
330 | editor.addCommand( 'toolbarCollapse', { | ||
331 | readOnly: 1, | ||
332 | exec: function( editor ) { | ||
333 | var collapser = editor.ui.space( 'toolbar_collapser' ), | ||
334 | toolbox = collapser.getPrevious(), | ||
335 | contents = editor.ui.space( 'contents' ), | ||
336 | toolboxContainer = toolbox.getParent(), | ||
337 | contentHeight = parseInt( contents.$.style.height, 10 ), | ||
338 | previousHeight = toolboxContainer.$.offsetHeight, | ||
339 | minClass = 'cke_toolbox_collapser_min', | ||
340 | collapsed = collapser.hasClass( minClass ); | ||
341 | |||
342 | if ( !collapsed ) { | ||
343 | toolbox.hide(); | ||
344 | collapser.addClass( minClass ); | ||
345 | collapser.setAttribute( 'title', editor.lang.toolbar.toolbarExpand ); | ||
346 | } else { | ||
347 | toolbox.show(); | ||
348 | collapser.removeClass( minClass ); | ||
349 | collapser.setAttribute( 'title', editor.lang.toolbar.toolbarCollapse ); | ||
350 | } | ||
351 | |||
352 | // Update collapser symbol. | ||
353 | collapser.getFirst().setText( collapsed ? '\u25B2' : // BLACK UP-POINTING TRIANGLE | ||
354 | '\u25C0' ); // BLACK LEFT-POINTING TRIANGLE | ||
355 | |||
356 | var dy = toolboxContainer.$.offsetHeight - previousHeight; | ||
357 | contents.setStyle( 'height', ( contentHeight - dy ) + 'px' ); | ||
358 | |||
359 | editor.fire( 'resize', { | ||
360 | outerHeight: editor.container.$.offsetHeight, | ||
361 | contentsHeight: contents.$.offsetHeight, | ||
362 | outerWidth: editor.container.$.offsetWidth | ||
363 | } ); | ||
364 | }, | ||
365 | |||
366 | modes: { wysiwyg: 1, source: 1 } | ||
367 | } ); | ||
368 | |||
369 | editor.setKeystroke( CKEDITOR.ALT + ( CKEDITOR.env.ie || CKEDITOR.env.webkit ? 189 : 109 ) /*-*/, 'toolbarCollapse' ); | ||
370 | |||
371 | output.push( '<a title="' + ( expanded ? editor.lang.toolbar.toolbarCollapse : editor.lang.toolbar.toolbarExpand ) + | ||
372 | '" id="' + editor.ui.spaceId( 'toolbar_collapser' ) + | ||
373 | '" tabIndex="-1" class="cke_toolbox_collapser' ); | ||
374 | |||
375 | if ( !expanded ) | ||
376 | output.push( ' cke_toolbox_collapser_min' ); | ||
377 | |||
378 | output.push( '" onclick="CKEDITOR.tools.callFunction(' + collapserFn + ')">', '<span class="cke_arrow">▲</span>', // BLACK UP-POINTING TRIANGLE | ||
379 | '</a>' ); | ||
380 | } | ||
381 | |||
382 | output.push( '</span>' ); | ||
383 | event.data.html += output.join( '' ); | ||
384 | } ); | ||
385 | |||
386 | editor.on( 'destroy', function() { | ||
387 | if ( this.toolbox ) { | ||
388 | var toolbars, | ||
389 | index = 0, | ||
390 | i, items, instance; | ||
391 | toolbars = this.toolbox.toolbars; | ||
392 | for ( ; index < toolbars.length; index++ ) { | ||
393 | items = toolbars[ index ].items; | ||
394 | for ( i = 0; i < items.length; i++ ) { | ||
395 | instance = items[ i ]; | ||
396 | if ( instance.clickFn ) | ||
397 | CKEDITOR.tools.removeFunction( instance.clickFn ); | ||
398 | if ( instance.keyDownFn ) | ||
399 | CKEDITOR.tools.removeFunction( instance.keyDownFn ); | ||
400 | } | ||
401 | } | ||
402 | } | ||
403 | } ); | ||
404 | |||
405 | // Manage editor focus when navigating the toolbar. | ||
406 | editor.on( 'uiReady', function() { | ||
407 | var toolbox = editor.ui.space( 'toolbox' ); | ||
408 | toolbox && editor.focusManager.add( toolbox, 1 ); | ||
409 | } ); | ||
410 | |||
411 | editor.addCommand( 'toolbarFocus', commands.toolbarFocus ); | ||
412 | editor.setKeystroke( CKEDITOR.ALT + 121 /*F10*/, 'toolbarFocus' ); | ||
413 | |||
414 | editor.ui.add( '-', CKEDITOR.UI_SEPARATOR, {} ); | ||
415 | editor.ui.addHandler( CKEDITOR.UI_SEPARATOR, { | ||
416 | create: function() { | ||
417 | return { | ||
418 | render: function( editor, output ) { | ||
419 | output.push( '<span class="cke_toolbar_separator" role="separator"></span>' ); | ||
420 | return {}; | ||
421 | } | ||
422 | }; | ||
423 | } | ||
424 | } ); | ||
425 | } | ||
426 | } ); | ||
427 | |||
428 | function getToolbarConfig( editor ) { | ||
429 | var removeButtons = editor.config.removeButtons; | ||
430 | |||
431 | removeButtons = removeButtons && removeButtons.split( ',' ); | ||
432 | |||
433 | function buildToolbarConfig() { | ||
434 | |||
435 | // Object containing all toolbar groups used by ui items. | ||
436 | var lookup = getItemDefinedGroups(); | ||
437 | |||
438 | // Take the base for the new toolbar, which is basically a toolbar | ||
439 | // definition without items. | ||
440 | var toolbar = CKEDITOR.tools.clone( editor.config.toolbarGroups ) || getPrivateToolbarGroups( editor ); | ||
441 | |||
442 | // Fill the toolbar groups with the available ui items. | ||
443 | for ( var i = 0; i < toolbar.length; i++ ) { | ||
444 | var toolbarGroup = toolbar[ i ]; | ||
445 | |||
446 | // Skip toolbar break. | ||
447 | if ( toolbarGroup == '/' ) | ||
448 | continue; | ||
449 | // Handle simply group name item. | ||
450 | else if ( typeof toolbarGroup == 'string' ) | ||
451 | toolbarGroup = toolbar[ i ] = { name: toolbarGroup }; | ||
452 | |||
453 | var items, subGroups = toolbarGroup.groups; | ||
454 | |||
455 | // Look for items that match sub groups. | ||
456 | if ( subGroups ) { | ||
457 | for ( var j = 0, sub; j < subGroups.length; j++ ) { | ||
458 | sub = subGroups[ j ]; | ||
459 | |||
460 | // If any ui item is registered for this subgroup. | ||
461 | items = lookup[ sub ]; | ||
462 | items && fillGroup( toolbarGroup, items ); | ||
463 | } | ||
464 | } | ||
465 | |||
466 | // Add the main group items as well. | ||
467 | items = lookup[ toolbarGroup.name ]; | ||
468 | items && fillGroup( toolbarGroup, items ); | ||
469 | } | ||
470 | |||
471 | return toolbar; | ||
472 | } | ||
473 | |||
474 | // Returns an object containing all toolbar groups used by ui items. | ||
475 | function getItemDefinedGroups() { | ||
476 | var groups = {}, | ||
477 | itemName, item, itemToolbar, group, order; | ||
478 | |||
479 | for ( itemName in editor.ui.items ) { | ||
480 | item = editor.ui.items[ itemName ]; | ||
481 | itemToolbar = item.toolbar || 'others'; | ||
482 | if ( itemToolbar ) { | ||
483 | // Break the toolbar property into its parts: "group_name[,order]". | ||
484 | itemToolbar = itemToolbar.split( ',' ); | ||
485 | group = itemToolbar[ 0 ]; | ||
486 | order = parseInt( itemToolbar[ 1 ] || -1, 10 ); | ||
487 | |||
488 | // Initialize the group, if necessary. | ||
489 | groups[ group ] || ( groups[ group ] = [] ); | ||
490 | |||
491 | // Push the data used to build the toolbar later. | ||
492 | groups[ group ].push( { name: itemName, order: order } ); | ||
493 | } | ||
494 | } | ||
495 | |||
496 | // Put the items in the right order. | ||
497 | for ( group in groups ) { | ||
498 | groups[ group ] = groups[ group ].sort( function( a, b ) { | ||
499 | return a.order == b.order ? 0 : | ||
500 | b.order < 0 ? -1 : | ||
501 | a.order < 0 ? 1 : | ||
502 | a.order < b.order ? -1 : | ||
503 | 1; | ||
504 | } ); | ||
505 | } | ||
506 | |||
507 | return groups; | ||
508 | } | ||
509 | |||
510 | function fillGroup( toolbarGroup, uiItems ) { | ||
511 | if ( uiItems.length ) { | ||
512 | if ( toolbarGroup.items ) | ||
513 | toolbarGroup.items.push( editor.ui.create( '-' ) ); | ||
514 | else | ||
515 | toolbarGroup.items = []; | ||
516 | |||
517 | var item, name; | ||
518 | while ( ( item = uiItems.shift() ) ) { | ||
519 | name = typeof item == 'string' ? item : item.name; | ||
520 | |||
521 | // Ignore items that are configured to be removed. | ||
522 | if ( !removeButtons || CKEDITOR.tools.indexOf( removeButtons, name ) == -1 ) { | ||
523 | item = editor.ui.create( name ); | ||
524 | |||
525 | if ( !item ) | ||
526 | continue; | ||
527 | |||
528 | if ( !editor.addFeature( item ) ) | ||
529 | continue; | ||
530 | |||
531 | toolbarGroup.items.push( item ); | ||
532 | } | ||
533 | } | ||
534 | } | ||
535 | } | ||
536 | |||
537 | function populateToolbarConfig( config ) { | ||
538 | var toolbar = [], | ||
539 | i, group, newGroup; | ||
540 | |||
541 | for ( i = 0; i < config.length; ++i ) { | ||
542 | group = config[ i ]; | ||
543 | newGroup = {}; | ||
544 | |||
545 | if ( group == '/' ) | ||
546 | toolbar.push( group ); | ||
547 | else if ( CKEDITOR.tools.isArray( group ) ) { | ||
548 | fillGroup( newGroup, CKEDITOR.tools.clone( group ) ); | ||
549 | toolbar.push( newGroup ); | ||
550 | } | ||
551 | else if ( group.items ) { | ||
552 | fillGroup( newGroup, CKEDITOR.tools.clone( group.items ) ); | ||
553 | newGroup.name = group.name; | ||
554 | toolbar.push( newGroup ); | ||
555 | } | ||
556 | } | ||
557 | |||
558 | return toolbar; | ||
559 | } | ||
560 | |||
561 | var toolbar = editor.config.toolbar; | ||
562 | |||
563 | // If it is a string, return the relative "toolbar_name" config. | ||
564 | if ( typeof toolbar == 'string' ) | ||
565 | toolbar = editor.config[ 'toolbar_' + toolbar ]; | ||
566 | |||
567 | return ( editor.toolbar = toolbar ? populateToolbarConfig( toolbar ) : buildToolbarConfig() ); | ||
568 | } | ||
569 | |||
570 | /** | ||
571 | * Adds a toolbar group. See {@link CKEDITOR.config#toolbarGroups} for more details. | ||
572 | * | ||
573 | * **Note:** This method will not modify toolbar groups set explicitly by | ||
574 | * {@link CKEDITOR.config#toolbarGroups}. It will only extend the default setting. | ||
575 | * | ||
576 | * @param {String} name Toolbar group name. | ||
577 | * @param {Number/String} previous The name of the toolbar group after which this one | ||
578 | * should be added or `0` if this group should be the first one. | ||
579 | * @param {String} [subgroupOf] The name of the parent group. | ||
580 | * @member CKEDITOR.ui | ||
581 | */ | ||
582 | CKEDITOR.ui.prototype.addToolbarGroup = function( name, previous, subgroupOf ) { | ||
583 | // The toolbarGroups from the privates is the one we gonna use for automatic toolbar creation. | ||
584 | var toolbarGroups = getPrivateToolbarGroups( this.editor ), | ||
585 | atStart = previous === 0, | ||
586 | newGroup = { name: name }; | ||
587 | |||
588 | if ( subgroupOf ) { | ||
589 | // Transform the subgroupOf name in the real subgroup object. | ||
590 | subgroupOf = CKEDITOR.tools.search( toolbarGroups, function( group ) { | ||
591 | return group.name == subgroupOf; | ||
592 | } ); | ||
593 | |||
594 | if ( subgroupOf ) { | ||
595 | !subgroupOf.groups && ( subgroupOf.groups = [] ) ; | ||
596 | |||
597 | if ( previous ) { | ||
598 | // Search the "previous" item and add the new one after it. | ||
599 | previous = CKEDITOR.tools.indexOf( subgroupOf.groups, previous ); | ||
600 | if ( previous >= 0 ) { | ||
601 | subgroupOf.groups.splice( previous + 1, 0, name ); | ||
602 | return; | ||
603 | } | ||
604 | } | ||
605 | |||
606 | // If no previous found. | ||
607 | |||
608 | if ( atStart ) | ||
609 | subgroupOf.groups.splice( 0, 0, name ); | ||
610 | else | ||
611 | subgroupOf.groups.push( name ); | ||
612 | return; | ||
613 | } else { | ||
614 | // Ignore "previous" if subgroupOf has not been found. | ||
615 | previous = null; | ||
616 | } | ||
617 | } | ||
618 | |||
619 | if ( previous ) { | ||
620 | // Transform the "previous" name into its index. | ||
621 | previous = CKEDITOR.tools.indexOf( toolbarGroups, function( group ) { | ||
622 | return group.name == previous; | ||
623 | } ); | ||
624 | } | ||
625 | |||
626 | if ( atStart ) | ||
627 | toolbarGroups.splice( 0, 0, name ); | ||
628 | else if ( typeof previous == 'number' ) | ||
629 | toolbarGroups.splice( previous + 1, 0, newGroup ); | ||
630 | else | ||
631 | toolbarGroups.push( name ); | ||
632 | }; | ||
633 | |||
634 | function getPrivateToolbarGroups( editor ) { | ||
635 | return editor._.toolbarGroups || ( editor._.toolbarGroups = [ | ||
636 | { name: 'document', groups: [ 'mode', 'document', 'doctools' ] }, | ||
637 | { name: 'clipboard', groups: [ 'clipboard', 'undo' ] }, | ||
638 | { name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ] }, | ||
639 | { name: 'forms' }, | ||
640 | '/', | ||
641 | { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] }, | ||
642 | { name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] }, | ||
643 | { name: 'links' }, | ||
644 | { name: 'insert' }, | ||
645 | '/', | ||
646 | { name: 'styles' }, | ||
647 | { name: 'colors' }, | ||
648 | { name: 'tools' }, | ||
649 | { name: 'others' }, | ||
650 | { name: 'about' } | ||
651 | ] ); | ||
652 | } | ||
653 | } )(); | ||
654 | |||
655 | /** | ||
656 | * Separator UI element. | ||
657 | * | ||
658 | * @readonly | ||
659 | * @property {String} [='separator'] | ||
660 | * @member CKEDITOR | ||
661 | */ | ||
662 | CKEDITOR.UI_SEPARATOR = 'separator'; | ||
663 | |||
664 | /** | ||
665 | * The part of the user interface where the toolbar will be rendered. For the default | ||
666 | * editor implementation, the recommended options are `'top'` and `'bottom'`. | ||
667 | * | ||
668 | * Please note that this option is only applicable to [classic](#!/guide/dev_framed) | ||
669 | * (`iframe`-based) editor. In case of [inline](#!/guide/dev_inline) editor the toolbar | ||
670 | * position is set dynamically depending on the position of the editable element on the screen. | ||
671 | * | ||
672 | * Read more in the [documentation](#!/guide/dev_toolbarlocation) | ||
673 | * and see the [SDK sample](http://sdk.ckeditor.com/samples/toolbarlocation.html). | ||
674 | * | ||
675 | * config.toolbarLocation = 'bottom'; | ||
676 | * | ||
677 | * @cfg | ||
678 | * @member CKEDITOR.config | ||
679 | */ | ||
680 | CKEDITOR.config.toolbarLocation = 'top'; | ||
681 | |||
682 | /** | ||
683 | * The toolbox (alias toolbar) definition. It is a toolbar name or an array of | ||
684 | * toolbars (strips), each one being also an array, containing a list of UI items. | ||
685 | * | ||
686 | * If set to `null`, the toolbar will be generated automatically using all available buttons | ||
687 | * and {@link #toolbarGroups} as a toolbar groups layout. | ||
688 | * | ||
689 | * In CKEditor 4.5+ you can generate your toolbar customization code by using the [visual | ||
690 | * toolbar configurator](http://docs.ckeditor.com/#!/guide/dev_toolbar). | ||
691 | * | ||
692 | * // Defines a toolbar with only one strip containing the "Source" button, a | ||
693 | * // separator, and the "Bold" and "Italic" buttons. | ||
694 | * config.toolbar = [ | ||
695 | * [ 'Source', '-', 'Bold', 'Italic' ] | ||
696 | * ]; | ||
697 | * | ||
698 | * // Similar to the example above, defines a "Basic" toolbar with only one strip containing three buttons. | ||
699 | * // Note that this setting is composed by "toolbar_" added to the toolbar name, which in this case is called "Basic". | ||
700 | * // This second part of the setting name can be anything. You must use this name in the CKEDITOR.config.toolbar setting | ||
701 | * // in order to instruct the editor which `toolbar_(name)` setting should be used. | ||
702 | * config.toolbar_Basic = [ | ||
703 | * [ 'Source', '-', 'Bold', 'Italic' ] | ||
704 | * ]; | ||
705 | * // Load toolbar_Name where Name = Basic. | ||
706 | * config.toolbar = 'Basic'; | ||
707 | * | ||
708 | * @cfg {Array/String} [toolbar=null] | ||
709 | * @member CKEDITOR.config | ||
710 | */ | ||
711 | |||
712 | /** | ||
713 | * The toolbar groups definition. | ||
714 | * | ||
715 | * If the toolbar layout is not explicitly defined by the {@link #toolbar} setting, then | ||
716 | * this setting is used to group all defined buttons (see {@link CKEDITOR.ui#addButton}). | ||
717 | * Buttons are associated with toolbar groups by the `toolbar` property in their definition objects. | ||
718 | * | ||
719 | * New groups may be dynamically added during the editor and plugin initialization by | ||
720 | * {@link CKEDITOR.ui#addToolbarGroup}. This is only possible if the default setting was used. | ||
721 | * | ||
722 | * // Default setting. | ||
723 | * config.toolbarGroups = [ | ||
724 | * { name: 'document', groups: [ 'mode', 'document', 'doctools' ] }, | ||
725 | * { name: 'clipboard', groups: [ 'clipboard', 'undo' ] }, | ||
726 | * { name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ] }, | ||
727 | * { name: 'forms' }, | ||
728 | * '/', | ||
729 | * { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] }, | ||
730 | * { name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] }, | ||
731 | * { name: 'links' }, | ||
732 | * { name: 'insert' }, | ||
733 | * '/', | ||
734 | * { name: 'styles' }, | ||
735 | * { name: 'colors' }, | ||
736 | * { name: 'tools' }, | ||
737 | * { name: 'others' }, | ||
738 | * { name: 'about' } | ||
739 | * ]; | ||
740 | * | ||
741 | * @cfg {Array} [toolbarGroups=see example] | ||
742 | * @member CKEDITOR.config | ||
743 | */ | ||
744 | |||
745 | /** | ||
746 | * Whether the toolbar can be collapsed by the user. If disabled, the Collapse Toolbar | ||
747 | * button will not be displayed. | ||
748 | * | ||
749 | * config.toolbarCanCollapse = true; | ||
750 | * | ||
751 | * @cfg {Boolean} [toolbarCanCollapse=false] | ||
752 | * @member CKEDITOR.config | ||
753 | */ | ||
754 | |||
755 | /** | ||
756 | * Whether the toolbar must start expanded when the editor is loaded. | ||
757 | * | ||
758 | * Setting this option to `false` will affect the toolbar only when | ||
759 | * {@link #toolbarCanCollapse} is set to `true`: | ||
760 | * | ||
761 | * config.toolbarCanCollapse = true; | ||
762 | * config.toolbarStartupExpanded = false; | ||
763 | * | ||
764 | * @cfg {Boolean} [toolbarStartupExpanded=true] | ||
765 | * @member CKEDITOR.config | ||
766 | */ | ||
767 | |||
768 | /** | ||
769 | * When enabled, causes the *Arrow* keys navigation to cycle within the current | ||
770 | * toolbar group. Otherwise the *Arrow* keys will move through all items available in | ||
771 | * the toolbar. The *Tab* key will still be used to quickly jump among the | ||
772 | * toolbar groups. | ||
773 | * | ||
774 | * config.toolbarGroupCycling = false; | ||
775 | * | ||
776 | * @since 3.6 | ||
777 | * @cfg {Boolean} [toolbarGroupCycling=true] | ||
778 | * @member CKEDITOR.config | ||
779 | */ | ||
780 | |||
781 | /** | ||
782 | * List of toolbar button names that must not be rendered. This will also work | ||
783 | * for non-button toolbar items, like the Font drop-down list. | ||
784 | * | ||
785 | * config.removeButtons = 'Underline,JustifyCenter'; | ||
786 | * | ||
787 | * This configuration option should not be overused. The recommended way is to use the | ||
788 | * {@link CKEDITOR.config#removePlugins} setting to remove features from the editor | ||
789 | * or even better, [create a custom editor build](http://ckeditor.com/builder) with | ||
790 | * just the features that you will use. | ||
791 | * In some cases though, a single plugin may define a set of toolbar buttons and | ||
792 | * `removeButtons` may be useful when just a few of them are to be removed. | ||
793 | * | ||
794 | * @cfg {String} [removeButtons] | ||
795 | * @member CKEDITOR.config | ||
796 | */ | ||
797 | |||
798 | /** | ||
799 | * The toolbar definition used by the editor. It is created from the | ||
800 | * {@link CKEDITOR.config#toolbar} option if it is set or automatically | ||
801 | * based on {@link CKEDITOR.config#toolbarGroups}. | ||
802 | * | ||
803 | * @readonly | ||
804 | * @property {Object} toolbar | ||
805 | * @member CKEDITOR.editor | ||
806 | */ | ||