]>
Commit | Line | Data |
---|---|---|
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 | |
6 | ( function() {\r | |
7 | var template = '<a id="{id}"' +\r | |
8 | ' class="cke_button cke_button__{name} cke_button_{state} {cls}"' +\r | |
9 | ( CKEDITOR.env.gecko && !CKEDITOR.env.hc ? '' : ' href="javascript:void(\'{titleJs}\')"' ) +\r | |
10 | ' title="{title}"' +\r | |
11 | ' tabindex="-1"' +\r | |
12 | ' hidefocus="true"' +\r | |
13 | ' role="button"' +\r | |
14 | ' aria-labelledby="{id}_label"' +\r | |
15 | ' aria-describedby="{id}_description"' +\r | |
16 | ' aria-haspopup="{hasArrow}"' +\r | |
17 | ' aria-disabled="{ariaDisabled}"';\r | |
18 | \r | |
19 | // Some browsers don't cancel key events in the keydown but in the\r | |
20 | // keypress.\r | |
21 | // TODO: Check if really needed.\r | |
22 | if ( CKEDITOR.env.gecko && CKEDITOR.env.mac )\r | |
23 | template += ' onkeypress="return false;"';\r | |
24 | \r | |
25 | // With Firefox, we need to force the button to redraw, otherwise it\r | |
26 | // will remain in the focus state.\r | |
27 | if ( CKEDITOR.env.gecko )\r | |
28 | template += ' onblur="this.style.cssText = this.style.cssText;"';\r | |
29 | \r | |
30 | template += ' onkeydown="return CKEDITOR.tools.callFunction({keydownFn},event);"' +\r | |
31 | ' onfocus="return CKEDITOR.tools.callFunction({focusFn},event);" ' +\r | |
32 | ( CKEDITOR.env.ie ? 'onclick="return false;" onmouseup' : 'onclick' ) + // #188\r | |
33 | '="CKEDITOR.tools.callFunction({clickFn},this);return false;">' +\r | |
34 | '<span class="cke_button_icon cke_button__{iconName}_icon" style="{style}"';\r | |
35 | \r | |
36 | \r | |
37 | template += '> </span>' +\r | |
38 | '<span id="{id}_label" class="cke_button_label cke_button__{name}_label" aria-hidden="false">{label}</span>' +\r | |
39 | '<span id="{id}_description" class="cke_button_label" aria-hidden="false">{ariaShortcut}</span>' +\r | |
40 | '{arrowHtml}' +\r | |
41 | '</a>';\r | |
42 | \r | |
43 | var templateArrow = '<span class="cke_button_arrow">' +\r | |
44 | // BLACK DOWN-POINTING TRIANGLE\r | |
45 | ( CKEDITOR.env.hc ? '▼' : '' ) +\r | |
46 | '</span>';\r | |
47 | \r | |
48 | var btnArrowTpl = CKEDITOR.addTemplate( 'buttonArrow', templateArrow ),\r | |
49 | btnTpl = CKEDITOR.addTemplate( 'button', template );\r | |
50 | \r | |
51 | CKEDITOR.plugins.add( 'button', {\r | |
52 | lang: 'af,ar,az,bg,ca,cs,da,de,de-ch,el,en,en-gb,eo,es,eu,fa,fi,fr,gl,he,hu,id,it,ja,km,ko,ku,lt,nb,nl,no,oc,pl,pt,pt-br,ro,ru,sk,sl,sq,sv,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%\r | |
53 | beforeInit: function( editor ) {\r | |
54 | editor.ui.addHandler( CKEDITOR.UI_BUTTON, CKEDITOR.ui.button.handler );\r | |
55 | }\r | |
56 | } );\r | |
57 | \r | |
58 | /**\r | |
59 | * Button UI element.\r | |
60 | *\r | |
61 | * @readonly\r | |
62 | * @property {String} [='button']\r | |
63 | * @member CKEDITOR\r | |
64 | */\r | |
65 | CKEDITOR.UI_BUTTON = 'button';\r | |
66 | \r | |
67 | /**\r | |
68 | * Represents a button UI element. This class should not be called directly. To\r | |
69 | * create new buttons use {@link CKEDITOR.ui#addButton} instead.\r | |
70 | *\r | |
71 | * @class\r | |
72 | * @constructor Creates a button class instance.\r | |
73 | * @param {Object} definition The button definition.\r | |
74 | */\r | |
75 | CKEDITOR.ui.button = function( definition ) {\r | |
76 | CKEDITOR.tools.extend( this, definition,\r | |
77 | // Set defaults.\r | |
78 | {\r | |
79 | title: definition.label,\r | |
80 | click: definition.click ||\r | |
81 | function( editor ) {\r | |
82 | editor.execCommand( definition.command );\r | |
83 | }\r | |
84 | } );\r | |
85 | \r | |
86 | this._ = {};\r | |
87 | };\r | |
88 | \r | |
89 | /**\r | |
90 | * Represents the button handler object.\r | |
91 | *\r | |
92 | * @class\r | |
93 | * @singleton\r | |
94 | * @extends CKEDITOR.ui.handlerDefinition\r | |
95 | */\r | |
96 | CKEDITOR.ui.button.handler = {\r | |
97 | /**\r | |
98 | * Transforms a button definition in a {@link CKEDITOR.ui.button} instance.\r | |
99 | *\r | |
100 | * @member CKEDITOR.ui.button.handler\r | |
101 | * @param {Object} definition\r | |
102 | * @returns {CKEDITOR.ui.button}\r | |
103 | */\r | |
104 | create: function( definition ) {\r | |
105 | return new CKEDITOR.ui.button( definition );\r | |
106 | }\r | |
107 | };\r | |
108 | \r | |
109 | /** @class CKEDITOR.ui.button */\r | |
110 | CKEDITOR.ui.button.prototype = {\r | |
111 | /**\r | |
112 | * Renders the button.\r | |
113 | *\r | |
114 | * @param {CKEDITOR.editor} editor The editor instance which this button is\r | |
115 | * to be used by.\r | |
116 | * @param {Array} output The output array to which the HTML code related to\r | |
117 | * this button should be appended.\r | |
118 | */\r | |
119 | render: function( editor, output ) {\r | |
120 | function updateState() {\r | |
121 | // "this" is a CKEDITOR.ui.button instance.\r | |
122 | var mode = editor.mode;\r | |
123 | \r | |
124 | if ( mode ) {\r | |
125 | // Restore saved button state.\r | |
126 | var state = this.modes[ mode ] ? modeStates[ mode ] !== undefined ? modeStates[ mode ] : CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED;\r | |
127 | \r | |
128 | state = editor.readOnly && !this.readOnly ? CKEDITOR.TRISTATE_DISABLED : state;\r | |
129 | \r | |
130 | this.setState( state );\r | |
131 | \r | |
132 | // Let plugin to disable button.\r | |
133 | if ( this.refresh )\r | |
134 | this.refresh();\r | |
135 | }\r | |
136 | }\r | |
137 | \r | |
138 | var env = CKEDITOR.env,\r | |
139 | id = this._.id = CKEDITOR.tools.getNextId(),\r | |
140 | stateName = '',\r | |
141 | command = this.command,\r | |
142 | // Get the command name.\r | |
143 | clickFn,\r | |
144 | keystroke,\r | |
145 | shortcut;\r | |
146 | \r | |
147 | this._.editor = editor;\r | |
148 | \r | |
149 | var instance = {\r | |
150 | id: id,\r | |
151 | button: this,\r | |
152 | editor: editor,\r | |
153 | focus: function() {\r | |
154 | var element = CKEDITOR.document.getById( id );\r | |
155 | element.focus();\r | |
156 | },\r | |
157 | execute: function() {\r | |
158 | this.button.click( editor );\r | |
159 | },\r | |
160 | attach: function( editor ) {\r | |
161 | this.button.attach( editor );\r | |
162 | }\r | |
163 | };\r | |
164 | \r | |
165 | var keydownFn = CKEDITOR.tools.addFunction( function( ev ) {\r | |
166 | if ( instance.onkey ) {\r | |
167 | ev = new CKEDITOR.dom.event( ev );\r | |
168 | return ( instance.onkey( instance, ev.getKeystroke() ) !== false );\r | |
169 | }\r | |
170 | } );\r | |
171 | \r | |
172 | var focusFn = CKEDITOR.tools.addFunction( function( ev ) {\r | |
173 | var retVal;\r | |
174 | \r | |
175 | if ( instance.onfocus )\r | |
176 | retVal = ( instance.onfocus( instance, new CKEDITOR.dom.event( ev ) ) !== false );\r | |
177 | \r | |
178 | return retVal;\r | |
179 | } );\r | |
180 | \r | |
181 | var selLocked = 0;\r | |
182 | \r | |
183 | instance.clickFn = clickFn = CKEDITOR.tools.addFunction( function() {\r | |
184 | \r | |
185 | // Restore locked selection in Opera.\r | |
186 | if ( selLocked ) {\r | |
187 | editor.unlockSelection( 1 );\r | |
188 | selLocked = 0;\r | |
189 | }\r | |
190 | instance.execute();\r | |
191 | \r | |
192 | // Fixed iOS focus issue when your press disabled button (#12381).\r | |
193 | if ( env.iOS ) {\r | |
194 | editor.focus();\r | |
195 | }\r | |
196 | } );\r | |
197 | \r | |
198 | \r | |
199 | // Indicate a mode sensitive button.\r | |
200 | if ( this.modes ) {\r | |
201 | var modeStates = {};\r | |
202 | \r | |
203 | editor.on( 'beforeModeUnload', function() {\r | |
204 | if ( editor.mode && this._.state != CKEDITOR.TRISTATE_DISABLED )\r | |
205 | modeStates[ editor.mode ] = this._.state;\r | |
206 | }, this );\r | |
207 | \r | |
208 | // Update status when activeFilter, mode or readOnly changes.\r | |
209 | editor.on( 'activeFilterChange', updateState, this );\r | |
210 | editor.on( 'mode', updateState, this );\r | |
211 | // If this button is sensitive to readOnly state, update it accordingly.\r | |
212 | !this.readOnly && editor.on( 'readOnly', updateState, this );\r | |
213 | \r | |
214 | } else if ( command ) {\r | |
215 | // Get the command instance.\r | |
216 | command = editor.getCommand( command );\r | |
217 | \r | |
218 | if ( command ) {\r | |
219 | command.on( 'state', function() {\r | |
220 | this.setState( command.state );\r | |
221 | }, this );\r | |
222 | \r | |
223 | stateName += ( command.state == CKEDITOR.TRISTATE_ON ? 'on' : command.state == CKEDITOR.TRISTATE_DISABLED ? 'disabled' : 'off' );\r | |
224 | }\r | |
225 | }\r | |
226 | \r | |
227 | // For button that has text-direction awareness on selection path.\r | |
228 | if ( this.directional ) {\r | |
229 | editor.on( 'contentDirChanged', function( evt ) {\r | |
230 | var el = CKEDITOR.document.getById( this._.id ),\r | |
231 | icon = el.getFirst();\r | |
232 | \r | |
233 | var pathDir = evt.data;\r | |
234 | \r | |
235 | // Make a minor direction change to become style-able for the skin icon.\r | |
236 | if ( pathDir != editor.lang.dir )\r | |
237 | el.addClass( 'cke_' + pathDir );\r | |
238 | else\r | |
239 | el.removeClass( 'cke_ltr' ).removeClass( 'cke_rtl' );\r | |
240 | \r | |
241 | // Inline style update for the plugin icon.\r | |
242 | icon.setAttribute( 'style', CKEDITOR.skin.getIconStyle( iconName, pathDir == 'rtl', this.icon, this.iconOffset ) );\r | |
243 | }, this );\r | |
244 | }\r | |
245 | \r | |
246 | if ( !command ) {\r | |
247 | stateName += 'off';\r | |
248 | } else {\r | |
249 | keystroke = editor.getCommandKeystroke( command );\r | |
250 | \r | |
251 | if ( keystroke ) {\r | |
252 | shortcut = CKEDITOR.tools.keystrokeToString( editor.lang.common.keyboard, keystroke );\r | |
253 | }\r | |
254 | }\r | |
255 | \r | |
256 | var name = this.name || this.command,\r | |
257 | iconName = name;\r | |
258 | \r | |
259 | // Check if we're pointing to an icon defined by another command. (#9555)\r | |
260 | if ( this.icon && !( /\./ ).test( this.icon ) ) {\r | |
261 | iconName = this.icon;\r | |
262 | this.icon = null;\r | |
263 | }\r | |
264 | \r | |
265 | var params = {\r | |
266 | id: id,\r | |
267 | name: name,\r | |
268 | iconName: iconName,\r | |
269 | label: this.label,\r | |
270 | cls: this.className || '',\r | |
271 | state: stateName,\r | |
272 | ariaDisabled: stateName == 'disabled' ? 'true' : 'false',\r | |
273 | title: this.title + ( shortcut ? ' (' + shortcut.display + ')' : '' ),\r | |
274 | ariaShortcut: shortcut ? editor.lang.common.keyboardShortcut + ' ' + shortcut.aria : '',\r | |
275 | titleJs: env.gecko && !env.hc ? '' : ( this.title || '' ).replace( "'", '' ),\r | |
276 | hasArrow: this.hasArrow ? 'true' : 'false',\r | |
277 | keydownFn: keydownFn,\r | |
278 | focusFn: focusFn,\r | |
279 | clickFn: clickFn,\r | |
280 | style: CKEDITOR.skin.getIconStyle( iconName, ( editor.lang.dir == 'rtl' ), this.icon, this.iconOffset ),\r | |
281 | arrowHtml: this.hasArrow ? btnArrowTpl.output() : ''\r | |
282 | };\r | |
283 | \r | |
284 | btnTpl.output( params, output );\r | |
285 | \r | |
286 | if ( this.onRender )\r | |
287 | this.onRender();\r | |
288 | \r | |
289 | return instance;\r | |
290 | },\r | |
291 | \r | |
292 | /**\r | |
293 | * Sets the button state.\r | |
294 | *\r | |
295 | * @param {Number} state Indicates the button state. One of {@link CKEDITOR#TRISTATE_ON},\r | |
296 | * {@link CKEDITOR#TRISTATE_OFF}, or {@link CKEDITOR#TRISTATE_DISABLED}.\r | |
297 | */\r | |
298 | setState: function( state ) {\r | |
299 | if ( this._.state == state )\r | |
300 | return false;\r | |
301 | \r | |
302 | this._.state = state;\r | |
303 | \r | |
304 | var element = CKEDITOR.document.getById( this._.id );\r | |
305 | \r | |
306 | if ( element ) {\r | |
307 | element.setState( state, 'cke_button' );\r | |
308 | \r | |
309 | state == CKEDITOR.TRISTATE_DISABLED ?\r | |
310 | element.setAttribute( 'aria-disabled', true ) :\r | |
311 | element.removeAttribute( 'aria-disabled' );\r | |
312 | \r | |
313 | if ( !this.hasArrow ) {\r | |
314 | // Note: aria-pressed attribute should not be added to menuButton instances. (#11331)\r | |
315 | state == CKEDITOR.TRISTATE_ON ?\r | |
316 | element.setAttribute( 'aria-pressed', true ) :\r | |
317 | element.removeAttribute( 'aria-pressed' );\r | |
318 | } else {\r | |
319 | var newLabel = state == CKEDITOR.TRISTATE_ON ?\r | |
320 | this._.editor.lang.button.selectedLabel.replace( /%1/g, this.label ) : this.label;\r | |
321 | CKEDITOR.document.getById( this._.id + '_label' ).setText( newLabel );\r | |
322 | }\r | |
323 | \r | |
324 | return true;\r | |
325 | } else {\r | |
326 | return false;\r | |
327 | }\r | |
328 | },\r | |
329 | \r | |
330 | /**\r | |
331 | * Gets the button state.\r | |
332 | *\r | |
333 | * @returns {Number} The button state. One of {@link CKEDITOR#TRISTATE_ON},\r | |
334 | * {@link CKEDITOR#TRISTATE_OFF}, or {@link CKEDITOR#TRISTATE_DISABLED}.\r | |
335 | */\r | |
336 | getState: function() {\r | |
337 | return this._.state;\r | |
338 | },\r | |
339 | \r | |
340 | /**\r | |
341 | * Returns this button's {@link CKEDITOR.feature} instance.\r | |
342 | *\r | |
343 | * It may be this button instance if it has at least one of\r | |
344 | * `allowedContent` and `requiredContent` properties. Otherwise,\r | |
345 | * if a command is bound to this button by the `command` property, then\r | |
346 | * that command will be returned.\r | |
347 | *\r | |
348 | * This method implements the {@link CKEDITOR.feature#toFeature} interface method.\r | |
349 | *\r | |
350 | * @since 4.1\r | |
351 | * @param {CKEDITOR.editor} Editor instance.\r | |
352 | * @returns {CKEDITOR.feature} The feature.\r | |
353 | */\r | |
354 | toFeature: function( editor ) {\r | |
355 | if ( this._.feature )\r | |
356 | return this._.feature;\r | |
357 | \r | |
358 | var feature = this;\r | |
359 | \r | |
360 | // If button isn't a feature, return command if is bound.\r | |
361 | if ( !this.allowedContent && !this.requiredContent && this.command )\r | |
362 | feature = editor.getCommand( this.command ) || feature;\r | |
363 | \r | |
364 | return this._.feature = feature;\r | |
365 | }\r | |
366 | };\r | |
367 | \r | |
368 | /**\r | |
369 | * Adds a button definition to the UI elements list.\r | |
370 | *\r | |
371 | * editorInstance.ui.addButton( 'MyBold', {\r | |
372 | * label: 'My Bold',\r | |
373 | * command: 'bold',\r | |
374 | * toolbar: 'basicstyles,1'\r | |
375 | * } );\r | |
376 | *\r | |
377 | * @member CKEDITOR.ui\r | |
378 | * @param {String} name The button name.\r | |
379 | * @param {Object} definition The button definition.\r | |
380 | * @param {String} definition.label The textual part of the button (if visible) and its tooltip.\r | |
381 | * @param {String} definition.command The command to be executed once the button is activated.\r | |
382 | * @param {String} definition.toolbar The {@link CKEDITOR.config#toolbarGroups toolbar group} into which\r | |
383 | * the button will be added. An optional index value (separated by a comma) determines the button position within the group.\r | |
384 | */\r | |
385 | CKEDITOR.ui.prototype.addButton = function( name, definition ) {\r | |
386 | this.add( name, CKEDITOR.UI_BUTTON, definition );\r | |
387 | };\r | |
388 | \r | |
389 | } )();\r |