]>
git.immae.eu Git - perso/Immae/Projets/packagist/piedsjaloux-ckeditor-component.git/blob - sources/plugins/menu/plugin.js
2 * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
6 CKEDITOR
.plugins
.add( 'menu', {
7 requires: 'floatpanel',
9 beforeInit: function( editor
) {
10 var groups
= editor
.config
.menu_groups
.split( ',' ),
11 groupsOrder
= editor
._
.menuGroups
= {},
12 menuItems
= editor
._
.menuItems
= {};
14 for ( var i
= 0; i
< groups
.length
; i
++ )
15 groupsOrder
[ groups
[ i
] ] = i
+ 1;
18 * Registers an item group to the editor context menu in order to make it
19 * possible to associate it with menu items later.
21 * @param {String} name Specify a group name.
22 * @param {Number} [order=100] Define the display sequence of this group
23 * inside the menu. A smaller value gets displayed first.
24 * @member CKEDITOR.editor
26 editor
.addMenuGroup = function( name
, order
) {
27 groupsOrder
[ name
] = order
|| 100;
31 * Adds an item from the specified definition to the editor context menu.
34 * @param {String} name The menu item name.
35 * @param {Object} definition The menu item definition.
36 * @member CKEDITOR.editor
38 editor
.addMenuItem = function( name
, definition
) {
39 if ( groupsOrder
[ definition
.group
] )
40 menuItems
[ name
] = new CKEDITOR
.menuItem( this, name
, definition
);
44 * Adds one or more items from the specified definition array to the editor context menu.
47 * @param {Array} definitions List of definitions for each menu item as if {@link #addMenuItem} is called.
48 * @member CKEDITOR.editor
50 editor
.addMenuItems = function( definitions
) {
51 for ( var itemName
in definitions
) {
52 this.addMenuItem( itemName
, definitions
[ itemName
] );
57 * Retrieves a particular menu item definition from the editor context menu.
60 * @param {String} name The name of the desired menu item.
62 * @member CKEDITOR.editor
64 editor
.getMenuItem = function( name
) {
65 return menuItems
[ name
];
69 * Removes a particular menu item added before from the editor context menu.
73 * @param {String} name The name of the desired menu item.
74 * @member CKEDITOR.editor
76 editor
.removeMenuItem = function( name
) {
77 delete menuItems
[ name
];
83 var menuItemSource
= '<span class="cke_menuitem">' +
85 ' class="cke_menubutton cke_menubutton__{name} cke_menubutton_{state} {cls}" href="{href}"' +
91 ' aria-haspopup="{hasPopup}"' +
92 ' aria-disabled="{disabled}"' +
95 // Some browsers don't cancel key events in the keydown but in the
97 // TODO: Check if really needed.
98 if ( CKEDITOR
.env
.gecko
&& CKEDITOR
.env
.mac
)
99 menuItemSource
+= ' onkeypress="return false;"';
101 // With Firefox, we need to force the button to redraw, otherwise it
102 // will remain in the focus state.
103 if ( CKEDITOR
.env
.gecko
)
104 menuItemSource
+= ' onblur="this.style.cssText = this.style.cssText;"';
107 menuItemSource
+= ' onmouseover="CKEDITOR.tools.callFunction({hoverFn},{index});"' +
108 ' onmouseout="CKEDITOR.tools.callFunction({moveOutFn},{index});" ' +
109 ( CKEDITOR
.env
.ie
? 'onclick="return false;" onmouseup' : 'onclick' ) +
110 '="CKEDITOR.tools.callFunction({clickFn},{index}); return false;"' +
114 '<span class="cke_menubutton_inner">' +
115 '<span class="cke_menubutton_icon">' +
116 '<span class="cke_button_icon cke_button__{iconName}_icon" style="{iconStyle}"></span>' +
118 '<span class="cke_menubutton_label">' +
125 var menuArrowSource
= '<span class="cke_menuarrow">' +
126 '<span>{label}</span>' +
129 var menuItemTpl
= CKEDITOR
.addTemplate( 'menuItem', menuItemSource
),
130 menuArrowTpl
= CKEDITOR
.addTemplate( 'menuArrow', menuArrowSource
);
136 CKEDITOR
.menu
= CKEDITOR
.tools
.createClass( {
140 $: function( editor
, definition
) {
141 definition
= this._
.definition
= definition
|| {};
142 this.id
= CKEDITOR
.tools
.getNextId();
144 this.editor
= editor
;
146 this._
.listeners
= [];
148 this._
.level
= definition
.level
|| 1;
150 var panelDefinition
= CKEDITOR
.tools
.extend( {}, definition
.panel
, {
151 css: [ CKEDITOR
.skin
.getPath( 'editor' ) ],
152 level: this._
.level
- 1,
156 var attrs
= panelDefinition
.block
.attributes
= ( panelDefinition
.attributes
|| {} );
157 // Provide default role of 'menu'.
158 !attrs
.role
&& ( attrs
.role
= 'menu' );
159 this._
.panelDefinition
= panelDefinition
;
164 var selection
= this.editor
.getSelection(),
165 start
= selection
&& selection
.getStartElement(),
166 path
= this.editor
.elementPath(),
167 listeners
= this._
.listeners
;
170 // Call all listeners, filling the list of items to be displayed.
171 for ( var i
= 0; i
< listeners
.length
; i
++ ) {
172 var listenerItems
= listeners
[ i
]( start
, selection
, path
);
174 if ( listenerItems
) {
175 for ( var itemName
in listenerItems
) {
176 var item
= this.editor
.getMenuItem( itemName
);
178 if ( item
&& ( !item
.command
|| this.editor
.getCommand( item
.command
).state
) ) {
179 item
.state
= listenerItems
[ itemName
];
187 onClick: function( item
) {
192 else if ( item
.command
)
193 this.editor
.execCommand( item
.command
);
196 onEscape: function( keystroke
) {
197 var parent
= this.parent
;
198 // 1. If it's sub-menu, close it, with focus restored on this.
199 // 2. In case of a top-menu, close it, with focus returned to page.
201 parent
._
.panel
.hideChild( 1 );
202 else if ( keystroke
== 27 )
209 this.onHide
&& this.onHide();
212 showSubMenu: function( index
) {
213 var menu
= this._
.subMenu
,
214 item
= this.items
[ index
],
215 subItemDefs
= item
.getItems
&& item
.getItems();
217 // If this item has no subitems, we just hide the submenu, if
218 // available, and return back.
219 if ( !subItemDefs
) {
220 // Hide sub menu with focus returned.
221 this._
.panel
.hideChild( 1 );
225 // Create the submenu, if not available, or clean the existing
230 menu
= this._
.subMenu
= new CKEDITOR
.menu( this.editor
, CKEDITOR
.tools
.extend( {}, this._
.definition
, { level: this._
.level
+ 1 }, true ) );
232 menu
._
.onClick
= CKEDITOR
.tools
.bind( this._
.onClick
, this );
235 // Add all submenu items to the menu.
236 for ( var subItemName
in subItemDefs
) {
237 var subItem
= this.editor
.getMenuItem( subItemName
);
239 subItem
.state
= subItemDefs
[ subItemName
];
244 // Get the element representing the current item.
245 var element
= this._
.panel
.getBlock( this.id
).element
.getDocument().getById( this.id
+ String( index
) );
248 // This timeout is needed to give time for the sub-menu get
249 // focus when JAWS is running. (#9844)
250 setTimeout( function() {
251 menu
.show( element
, 2 );
262 add: function( item
) {
263 // Later we may sort the items, but Array#sort is not stable in
264 // some browsers, here we're forcing the original sequence with
265 // 'order' attribute if it hasn't been assigned. (#3868)
267 item
.order
= this.items
.length
;
269 this.items
.push( item
);
275 removeAll: function() {
280 * Shows the menu in given location.
282 * @param {CKEDITOR.dom.element} offsetParent
283 * @param {Number} [corner]
284 * @param {Number} [offsetX]
285 * @param {Number} [offsetY]
287 show: function( offsetParent
, corner
, offsetX
, offsetY
) {
289 if ( !this.parent
) {
291 // Don't menu with zero items.
292 if ( !this.items
.length
)
296 corner
= corner
|| ( this.editor
.lang
.dir
== 'rtl' ? 2 : 1 );
298 var items
= this.items
,
299 editor
= this.editor
,
300 panel
= this._
.panel
,
301 element
= this._
.element
;
303 // Create the floating panel for this menu.
305 panel
= this._
.panel
= new CKEDITOR
.ui
.floatPanel( this.editor
, CKEDITOR
.document
.getBody(), this._
.panelDefinition
, this._
.level
);
307 panel
.onEscape
= CKEDITOR
.tools
.bind( function( keystroke
) {
308 if ( this._
.onEscape( keystroke
) === false )
312 panel
.onShow = function() {
313 // Menu need CSS resets, compensate class name.
314 var holder
= panel
._
.panel
.getHolderElement();
315 holder
.getParent().addClass( 'cke' ).addClass( 'cke_reset_all' );
318 panel
.onHide
= CKEDITOR
.tools
.bind( function() {
319 this._
.onHide
&& this._
.onHide();
322 // Create an autosize block inside the panel.
323 var block
= panel
.addBlock( this.id
, this._
.panelDefinition
.block
);
324 block
.autoSize
= true;
326 var keys
= block
.keys
;
327 keys
[ 40 ] = 'next'; // ARROW-DOWN
328 keys
[ 9 ] = 'next'; // TAB
329 keys
[ 38 ] = 'prev'; // ARROW-UP
330 keys
[ CKEDITOR
.SHIFT
+ 9 ] = 'prev'; // SHIFT + TAB
331 keys
[ ( editor
.lang
.dir
== 'rtl' ? 37 : 39 ) ] = CKEDITOR
.env
.ie
? 'mouseup' : 'click'; // ARROW-RIGHT/ARROW-LEFT(rtl)
332 keys
[ 32 ] = CKEDITOR
.env
.ie
? 'mouseup' : 'click'; // SPACE
333 CKEDITOR
.env
.ie
&& ( keys
[ 13 ] = 'mouseup' ); // Manage ENTER, since onclick is blocked in IE (#8041).
335 element
= this._
.element
= block
.element
;
337 var elementDoc
= element
.getDocument();
338 elementDoc
.getBody().setStyle( 'overflow', 'hidden' );
339 elementDoc
.getElementsByTag( 'html' ).getItem( 0 ).setStyle( 'overflow', 'hidden' );
341 this._
.itemOverFn
= CKEDITOR
.tools
.addFunction( function( index
) {
342 clearTimeout( this._
.showSubTimeout
);
343 this._
.showSubTimeout
= CKEDITOR
.tools
.setTimeout( this._
.showSubMenu
, editor
.config
.menu_subMenuDelay
|| 400, this, [ index
] );
346 this._
.itemOutFn
= CKEDITOR
.tools
.addFunction( function() {
347 clearTimeout( this._
.showSubTimeout
);
350 this._
.itemClickFn
= CKEDITOR
.tools
.addFunction( function( index
) {
351 var item
= this.items
[ index
];
353 if ( item
.state
== CKEDITOR
.TRISTATE_DISABLED
) {
359 this._
.showSubMenu( index
);
361 this._
.onClick( item
);
365 // Put the items in the right order.
368 // Apply the editor mixed direction status to menu.
369 var path
= editor
.elementPath(),
370 mixedDirCls
= ( path
&& path
.direction() != editor
.lang
.dir
) ? ' cke_mixed_dir_content' : '';
372 // Build the HTML that composes the menu and its items.
373 var output
= [ '<div class="cke_menu' + mixedDirCls
+ '" role="presentation">' ];
375 var length
= items
.length
,
376 lastGroup
= length
&& items
[ 0 ].group
;
378 for ( var i
= 0; i
< length
; i
++ ) {
379 var item
= items
[ i
];
380 if ( lastGroup
!= item
.group
) {
381 output
.push( '<div class="cke_menuseparator" role="separator"></div>' );
382 lastGroup
= item
.group
;
385 item
.render( this, i
, output
);
388 output
.push( '</div>' );
390 // Inject the HTML inside the panel.
391 element
.setHtml( output
.join( '' ) );
393 CKEDITOR
.ui
.fire( 'ready', this );
397 this.parent
._
.panel
.showAsChild( panel
, this.id
, offsetParent
, corner
, offsetX
, offsetY
);
399 panel
.showBlock( this.id
, offsetParent
, corner
, offsetX
, offsetY
);
401 editor
.fire( 'menuShow', [ panel
] );
405 * Adds a callback executed on opening the menu. Items
406 * returned by that callback are added to the menu.
408 * @param {Function} listenerFn
409 * @param {CKEDITOR.dom.element} listenerFn.startElement The selection start anchor element.
410 * @param {CKEDITOR.dom.selection} listenerFn.selection The current selection.
411 * @param {CKEDITOR.dom.elementPath} listenerFn.path The current elements path.
412 * @param listenerFn.return Object (`commandName` => `state`) of items that should be added to the menu.
414 addListener: function( listenerFn
) {
415 this._
.listeners
.push( listenerFn
);
421 * @param {Boolean} [returnFocus]
423 hide: function( returnFocus
) {
424 this._
.onHide
&& this._
.onHide();
425 this._
.panel
&& this._
.panel
.hide( returnFocus
);
430 function sortItems( items
) {
431 items
.sort( function( itemA
, itemB
) {
432 if ( itemA
.group
< itemB
.group
)
434 else if ( itemA
.group
> itemB
.group
)
437 return itemA
.order
< itemB
.order
? -1 : itemA
.order
> itemB
.order
? 1 : 0;
445 CKEDITOR
.menuItem
= CKEDITOR
.tools
.createClass( {
446 $: function( editor
, name
, definition
) {
447 CKEDITOR
.tools
.extend( this, definition
,
451 className: 'cke_menubutton__' + name
454 // Transform the group name into its order number.
455 this.group
= editor
._
.menuGroups
[ this.group
];
457 this.editor
= editor
;
462 render: function( menu
, index
, output
) {
463 var id
= menu
.id
+ String( index
),
464 state
= ( typeof this.state
== 'undefined' ) ? CKEDITOR
.TRISTATE_OFF : this.state
,
467 var stateName
= state
== CKEDITOR
.TRISTATE_ON
? 'on' : state
== CKEDITOR
.TRISTATE_DISABLED
? 'disabled' : 'off';
469 if ( this.role
in { menuitemcheckbox: 1, menuitemradio: 1 } )
470 ariaChecked
= ' aria-checked="' + ( state
== CKEDITOR
.TRISTATE_ON
? 'true' : 'false' ) + '"';
472 var hasSubMenu
= this.getItems
;
473 // ltr: BLACK LEFT-POINTING POINTER
474 // rtl: BLACK RIGHT-POINTING POINTER
475 var arrowLabel
= '&#' + ( this.editor
.lang
.dir
== 'rtl' ? '9668' : '9658' ) + ';';
477 var iconName
= this.name
;
478 if ( this.icon
&& !( /\./ ).test( this.icon
) )
479 iconName
= this.icon
;
486 cls: this.className
|| '',
488 hasPopup: hasSubMenu
? 'true' : 'false',
489 disabled: state
== CKEDITOR
.TRISTATE_DISABLED
,
491 href: 'javascript:void(\'' + ( this.label
|| '' ).replace( "'" + '' ) + '\')', // jshint ignore:line
492 hoverFn: menu
._
.itemOverFn
,
493 moveOutFn: menu
._
.itemOutFn
,
494 clickFn: menu
._
.itemClickFn
,
496 iconStyle: CKEDITOR
.skin
.getIconStyle( iconName
, ( this.editor
.lang
.dir
== 'rtl' ), iconName
== this.icon
? null : this.icon
, this.iconOffset
),
497 arrowHtml: hasSubMenu
? menuArrowTpl
.output( { label: arrowLabel
} ) : '',
498 role: this.role
? this.role : 'menuitem',
499 ariaChecked: ariaChecked
502 menuItemTpl
.output( params
, output
);
511 * The amount of time, in milliseconds, the editor waits before displaying submenu
512 * options when moving the mouse over options that contain submenus, like the
513 * "Cell Properties" entry for tables.
515 * // Remove the submenu delay.
516 * config.menu_subMenuDelay = 0;
518 * @cfg {Number} [menu_subMenuDelay=400]
519 * @member CKEDITOR.config
523 * Fired when a menu is shown.
526 * @member CKEDITOR.editor
527 * @param {CKEDITOR.editor} editor This editor instance.
528 * @param {CKEDITOR.ui.panel[]} data
532 * A comma separated list of items group names to be displayed in the context
533 * menu. The order of items will reflect the order specified in this list if
534 * no priority was defined in the groups.
536 * config.menu_groups = 'clipboard,table,anchor,link,image';
538 * @cfg {String} [menu_groups=see source]
539 * @member CKEDITOR.config
541 CKEDITOR
.config
.menu_groups
= 'clipboard,' +
543 'tablecell,tablecellproperties,tablerow,tablecolumn,table,' +
544 'anchor,link,image,flash,' +
545 'checkbox,radio,textfield,hiddenfield,imagebutton,button,select,textarea,div';