]> git.immae.eu Git - perso/Immae/Projets/packagist/ludivine-ckeditor-component.git/blame - sources/plugins/richcombo/plugin.js
Update to 4.7.3
[perso/Immae/Projets/packagist/ludivine-ckeditor-component.git] / sources / plugins / richcombo / plugin.js
CommitLineData
c63493c8
IB
1/**\r
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.\r
3 * For licensing, see LICENSE.md or http://ckeditor.com/license\r
4 */\r
5\r
6CKEDITOR.plugins.add( 'richcombo', {\r
7 requires: 'floatpanel,listblock,button',\r
8\r
9 beforeInit: function( editor ) {\r
10 editor.ui.addHandler( CKEDITOR.UI_RICHCOMBO, CKEDITOR.ui.richCombo.handler );\r
11 }\r
12} );\r
13\r
14( function() {\r
15 var template = '<span id="{id}"' +\r
16 ' class="cke_combo cke_combo__{name} {cls}"' +\r
17 ' role="presentation">' +\r
18 '<span id="{id}_label" class="cke_combo_label">{label}</span>' +\r
19 '<a class="cke_combo_button" title="{title}" tabindex="-1"' +\r
20 ( CKEDITOR.env.gecko && !CKEDITOR.env.hc ? '' : ' href="javascript:void(\'{titleJs}\')"' ) +\r
21 ' hidefocus="true"' +\r
22 ' role="button"' +\r
23 ' aria-labelledby="{id}_label"' +\r
24 ' aria-haspopup="true"';\r
25\r
26 // Some browsers don't cancel key events in the keydown but in the\r
27 // keypress.\r
28 // TODO: Check if really needed.\r
29 if ( CKEDITOR.env.gecko && CKEDITOR.env.mac )\r
30 template += ' onkeypress="return false;"';\r
31\r
32 // With Firefox, we need to force the button to redraw, otherwise it\r
33 // will remain in the focus state.\r
34 if ( CKEDITOR.env.gecko )\r
35 template += ' onblur="this.style.cssText = this.style.cssText;"';\r
36\r
37 template +=\r
38 ' onkeydown="return CKEDITOR.tools.callFunction({keydownFn},event,this);"' +\r
39 ' onfocus="return CKEDITOR.tools.callFunction({focusFn},event);" ' +\r
1794320d 40 ( CKEDITOR.env.ie ? 'onclick="return false;" onmouseup' : 'onclick' ) + // http://dev.ckeditor.com/ticket/188\r
c63493c8
IB
41 '="CKEDITOR.tools.callFunction({clickFn},this);return false;">' +\r
42 '<span id="{id}_text" class="cke_combo_text cke_combo_inlinelabel">{label}</span>' +\r
43 '<span class="cke_combo_open">' +\r
44 '<span class="cke_combo_arrow">' +\r
45 // BLACK DOWN-POINTING TRIANGLE\r
46 ( CKEDITOR.env.hc ? '&#9660;' : CKEDITOR.env.air ? '&nbsp;' : '' ) +\r
47 '</span>' +\r
48 '</span>' +\r
49 '</a>' +\r
50 '</span>';\r
51\r
52 var rcomboTpl = CKEDITOR.addTemplate( 'combo', template );\r
53\r
54 /**\r
55 * Button UI element.\r
56 *\r
57 * @readonly\r
58 * @property {String} [='richcombo']\r
59 * @member CKEDITOR\r
60 */\r
61 CKEDITOR.UI_RICHCOMBO = 'richcombo';\r
62\r
63 /**\r
64 * @class\r
65 * @todo\r
66 */\r
67 CKEDITOR.ui.richCombo = CKEDITOR.tools.createClass( {\r
68 $: function( definition ) {\r
69 // Copy all definition properties to this object.\r
70 CKEDITOR.tools.extend( this, definition,\r
71 // Set defaults.\r
72 {\r
73 // The combo won't participate in toolbar grouping.\r
74 canGroup: false,\r
75 title: definition.label,\r
76 modes: { wysiwyg: 1 },\r
77 editorFocus: 1\r
78 } );\r
79\r
80 // We don't want the panel definition in this object.\r
81 var panelDefinition = this.panel || {};\r
82 delete this.panel;\r
83\r
84 this.id = CKEDITOR.tools.getNextNumber();\r
85\r
86 this.document = ( panelDefinition.parent && panelDefinition.parent.getDocument() ) || CKEDITOR.document;\r
87\r
88 panelDefinition.className = 'cke_combopanel';\r
89 panelDefinition.block = {\r
90 multiSelect: panelDefinition.multiSelect,\r
91 attributes: panelDefinition.attributes\r
92 };\r
93 panelDefinition.toolbarRelated = true;\r
94\r
95 this._ = {\r
96 panelDefinition: panelDefinition,\r
97 items: {}\r
98 };\r
99 },\r
100\r
101 proto: {\r
102 renderHtml: function( editor ) {\r
103 var output = [];\r
104 this.render( editor, output );\r
105 return output.join( '' );\r
106 },\r
107\r
108 /**\r
109 * Renders the combo.\r
110 *\r
111 * @param {CKEDITOR.editor} editor The editor instance which this button is\r
112 * to be used by.\r
113 * @param {Array} output The output array to which append the HTML relative\r
114 * to this button.\r
115 */\r
116 render: function( editor, output ) {\r
117 var env = CKEDITOR.env;\r
118\r
119 var id = 'cke_' + this.id;\r
120 var clickFn = CKEDITOR.tools.addFunction( function( el ) {\r
121 // Restore locked selection in Opera.\r
122 if ( selLocked ) {\r
123 editor.unlockSelection( 1 );\r
124 selLocked = 0;\r
125 }\r
126 instance.execute( el );\r
127 }, this );\r
128\r
129 var combo = this;\r
130 var instance = {\r
131 id: id,\r
132 combo: this,\r
133 focus: function() {\r
134 var element = CKEDITOR.document.getById( id ).getChild( 1 );\r
135 element.focus();\r
136 },\r
137 execute: function( el ) {\r
138 var _ = combo._;\r
139\r
140 if ( _.state == CKEDITOR.TRISTATE_DISABLED )\r
141 return;\r
142\r
143 combo.createPanel( editor );\r
144\r
145 if ( _.on ) {\r
146 _.panel.hide();\r
147 return;\r
148 }\r
149\r
150 combo.commit();\r
151 var value = combo.getValue();\r
152 if ( value )\r
153 _.list.mark( value );\r
154 else\r
155 _.list.unmarkAll();\r
156\r
157 _.panel.showBlock( combo.id, new CKEDITOR.dom.element( el ), 4 );\r
158 },\r
159 clickFn: clickFn\r
160 };\r
161\r
162 function updateState() {\r
1794320d 163 // Don't change state while richcombo is active (http://dev.ckeditor.com/ticket/11793).\r
c63493c8
IB
164 if ( this.getState() == CKEDITOR.TRISTATE_ON )\r
165 return;\r
166\r
167 var state = this.modes[ editor.mode ] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED;\r
168\r
169 if ( editor.readOnly && !this.readOnly )\r
170 state = CKEDITOR.TRISTATE_DISABLED;\r
171\r
172 this.setState( state );\r
173 this.setValue( '' );\r
174\r
175 // Let plugin to disable button.\r
176 if ( state != CKEDITOR.TRISTATE_DISABLED && this.refresh )\r
177 this.refresh();\r
178 }\r
179\r
180 // Update status when activeFilter, mode, selection or readOnly changes.\r
181 editor.on( 'activeFilterChange', updateState, this );\r
182 editor.on( 'mode', updateState, this );\r
183 editor.on( 'selectionChange', updateState, this );\r
184 // If this combo is sensitive to readOnly state, update it accordingly.\r
185 !this.readOnly && editor.on( 'readOnly', updateState, this );\r
186\r
187 var keyDownFn = CKEDITOR.tools.addFunction( function( ev, element ) {\r
188 ev = new CKEDITOR.dom.event( ev );\r
189\r
190 var keystroke = ev.getKeystroke();\r
191\r
c63493c8
IB
192 switch ( keystroke ) {\r
193 case 13: // ENTER\r
194 case 32: // SPACE\r
195 case 40: // ARROW-DOWN\r
196 // Show panel\r
197 CKEDITOR.tools.callFunction( clickFn, element );\r
198 break;\r
199 default:\r
200 // Delegate the default behavior to toolbar button key handling.\r
201 instance.onkey( instance, keystroke );\r
202 }\r
203\r
204 // Avoid subsequent focus grab on editor document.\r
205 ev.preventDefault();\r
206 } );\r
207\r
208 var focusFn = CKEDITOR.tools.addFunction( function() {\r
209 instance.onfocus && instance.onfocus();\r
210 } );\r
211\r
212 var selLocked = 0;\r
213\r
214 // For clean up\r
215 instance.keyDownFn = keyDownFn;\r
216\r
217 var params = {\r
218 id: id,\r
219 name: this.name || this.command,\r
220 label: this.label,\r
221 title: this.title,\r
222 cls: this.className || '',\r
223 titleJs: env.gecko && !env.hc ? '' : ( this.title || '' ).replace( "'", '' ),\r
224 keydownFn: keyDownFn,\r
225 focusFn: focusFn,\r
226 clickFn: clickFn\r
227 };\r
228\r
229 rcomboTpl.output( params, output );\r
230\r
231 if ( this.onRender )\r
232 this.onRender();\r
233\r
234 return instance;\r
235 },\r
236\r
237 createPanel: function( editor ) {\r
238 if ( this._.panel )\r
239 return;\r
240\r
241 var panelDefinition = this._.panelDefinition,\r
242 panelBlockDefinition = this._.panelDefinition.block,\r
243 panelParentElement = panelDefinition.parent || CKEDITOR.document.getBody(),\r
244 namedPanelCls = 'cke_combopanel__' + this.name,\r
245 panel = new CKEDITOR.ui.floatPanel( editor, panelParentElement, panelDefinition ),\r
246 list = panel.addListBlock( this.id, panelBlockDefinition ),\r
247 me = this;\r
248\r
249 panel.onShow = function() {\r
250 this.element.addClass( namedPanelCls );\r
251\r
252 me.setState( CKEDITOR.TRISTATE_ON );\r
253\r
254 me._.on = 1;\r
255\r
256 me.editorFocus && !editor.focusManager.hasFocus && editor.focus();\r
257\r
258 if ( me.onOpen )\r
259 me.onOpen();\r
c63493c8
IB
260 };\r
261\r
262 panel.onHide = function( preventOnClose ) {\r
263 this.element.removeClass( namedPanelCls );\r
264\r
265 me.setState( me.modes && me.modes[ editor.mode ] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED );\r
266\r
267 me._.on = 0;\r
268\r
269 if ( !preventOnClose && me.onClose )\r
270 me.onClose();\r
271 };\r
272\r
273 panel.onEscape = function() {\r
274 // Hide drop-down with focus returned.\r
275 panel.hide( 1 );\r
276 };\r
277\r
278 list.onClick = function( value, marked ) {\r
279\r
280 if ( me.onClick )\r
281 me.onClick.call( me, value, marked );\r
282\r
283 panel.hide();\r
284 };\r
285\r
286 this._.panel = panel;\r
287 this._.list = list;\r
288\r
289 panel.getBlock( this.id ).onHide = function() {\r
290 me._.on = 0;\r
291 me.setState( CKEDITOR.TRISTATE_OFF );\r
292 };\r
293\r
294 if ( this.init )\r
295 this.init();\r
296 },\r
297\r
298 setValue: function( value, text ) {\r
299 this._.value = value;\r
300\r
301 var textElement = this.document.getById( 'cke_' + this.id + '_text' );\r
302 if ( textElement ) {\r
303 if ( !( value || text ) ) {\r
304 text = this.label;\r
305 textElement.addClass( 'cke_combo_inlinelabel' );\r
306 } else {\r
307 textElement.removeClass( 'cke_combo_inlinelabel' );\r
308 }\r
309\r
310 textElement.setText( typeof text != 'undefined' ? text : value );\r
311 }\r
312 },\r
313\r
314 getValue: function() {\r
315 return this._.value || '';\r
316 },\r
317\r
318 unmarkAll: function() {\r
319 this._.list.unmarkAll();\r
320 },\r
321\r
322 mark: function( value ) {\r
323 this._.list.mark( value );\r
324 },\r
325\r
326 hideItem: function( value ) {\r
327 this._.list.hideItem( value );\r
328 },\r
329\r
330 hideGroup: function( groupTitle ) {\r
331 this._.list.hideGroup( groupTitle );\r
332 },\r
333\r
334 showAll: function() {\r
335 this._.list.showAll();\r
336 },\r
337\r
338 add: function( value, html, text ) {\r
339 this._.items[ value ] = text || value;\r
340 this._.list.add( value, html, text );\r
341 },\r
342\r
343 startGroup: function( title ) {\r
344 this._.list.startGroup( title );\r
345 },\r
346\r
347 commit: function() {\r
348 if ( !this._.committed ) {\r
349 this._.list.commit();\r
350 this._.committed = 1;\r
351 CKEDITOR.ui.fire( 'ready', this );\r
352 }\r
353 this._.committed = 1;\r
354 },\r
355\r
356 setState: function( state ) {\r
357 if ( this._.state == state )\r
358 return;\r
359\r
360 var el = this.document.getById( 'cke_' + this.id );\r
361 el.setState( state, 'cke_combo' );\r
362\r
363 state == CKEDITOR.TRISTATE_DISABLED ?\r
364 el.setAttribute( 'aria-disabled', true ) :\r
365 el.removeAttribute( 'aria-disabled' );\r
366\r
367 this._.state = state;\r
368 },\r
369\r
370 getState: function() {\r
371 return this._.state;\r
372 },\r
373\r
374 enable: function() {\r
375 if ( this._.state == CKEDITOR.TRISTATE_DISABLED )\r
376 this.setState( this._.lastState );\r
377 },\r
378\r
379 disable: function() {\r
380 if ( this._.state != CKEDITOR.TRISTATE_DISABLED ) {\r
381 this._.lastState = this._.state;\r
382 this.setState( CKEDITOR.TRISTATE_DISABLED );\r
383 }\r
384 }\r
385 },\r
386\r
387 /**\r
388 * Represents richCombo handler object.\r
389 *\r
390 * @class CKEDITOR.ui.richCombo.handler\r
391 * @singleton\r
392 * @extends CKEDITOR.ui.handlerDefinition\r
393 */\r
394 statics: {\r
395 handler: {\r
396 /**\r
397 * Transforms a richCombo definition in a {@link CKEDITOR.ui.richCombo} instance.\r
398 *\r
399 * @param {Object} definition\r
400 * @returns {CKEDITOR.ui.richCombo}\r
401 */\r
402 create: function( definition ) {\r
403 return new CKEDITOR.ui.richCombo( definition );\r
404 }\r
405 }\r
406 }\r
407 } );\r
408\r
409 /**\r
410 * @param {String} name\r
411 * @param {Object} definition\r
412 * @member CKEDITOR.ui\r
413 * @todo\r
414 */\r
415 CKEDITOR.ui.prototype.addRichCombo = function( name, definition ) {\r
416 this.add( name, CKEDITOR.UI_RICHCOMBO, definition );\r
417 };\r
418\r
419} )();\r