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