plugin.js 24 KB

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