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