1 /* 2 Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. 3 For licensing, see LICENSE.html or http://ckeditor.com/license 4 */ 5 6 CKEDITOR.plugins.add( 'button', 7 { 8 beforeInit : function( editor ) 9 { 10 editor.ui.addHandler( CKEDITOR.UI_BUTTON, CKEDITOR.ui.button.handler ); 11 } 12 }); 13 14 /** 15 * Button UI element. 16 * @constant 17 * @example 18 */ 19 CKEDITOR.UI_BUTTON = 'button'; 20 21 /** 22 * Represents a button UI element. This class should not be called directly. To 23 * create new buttons use {@link CKEDITOR.ui.prototype.addButton} instead. 24 * @constructor 25 * @param {Object} definition The button definition. 26 * @example 27 */ 28 CKEDITOR.ui.button = function( definition ) 29 { 30 // Copy all definition properties to this object. 31 CKEDITOR.tools.extend( this, definition, 32 // Set defaults. 33 { 34 title : definition.label, 35 className : definition.className || ( definition.command && 'cke_button_' + definition.command ) || '', 36 click : definition.click || function( editor ) 37 { 38 editor.execCommand( definition.command ); 39 } 40 }); 41 42 this._ = {}; 43 }; 44 45 /** 46 * Transforms a button definition in a {@link CKEDITOR.ui.button} instance. 47 * @type Object 48 * @example 49 */ 50 CKEDITOR.ui.button.handler = 51 { 52 create : function( definition ) 53 { 54 return new CKEDITOR.ui.button( definition ); 55 } 56 }; 57 58 ( function() 59 { 60 CKEDITOR.ui.button.prototype = 61 { 62 /** 63 * Renders the button. 64 * @param {CKEDITOR.editor} editor The editor instance which this button is 65 * to be used by. 66 * @param {Array} output The output array to which append the HTML relative 67 * to this button. 68 * @example 69 */ 70 render : function( editor, output ) 71 { 72 var env = CKEDITOR.env, 73 id = this._.id = CKEDITOR.tools.getNextId(), 74 classes = '', 75 command = this.command, // Get the command name. 76 clickFn; 77 78 this._.editor = editor; 79 80 var instance = 81 { 82 id : id, 83 button : this, 84 editor : editor, 85 focus : function() 86 { 87 var element = CKEDITOR.document.getById( id ); 88 element.focus(); 89 }, 90 execute : function() 91 { 92 // IE 6 needs some time before execution (#7922) 93 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 7 ) 94 CKEDITOR.tools.setTimeout( function(){ this.button.click( editor ); }, 0, this ); 95 else 96 this.button.click( editor ); 97 } 98 }; 99 100 var keydownFn = CKEDITOR.tools.addFunction( function( ev ) 101 { 102 if ( instance.onkey ) 103 { 104 ev = new CKEDITOR.dom.event( ev ); 105 return ( instance.onkey( instance, ev.getKeystroke() ) !== false ); 106 } 107 }); 108 109 var focusFn = CKEDITOR.tools.addFunction( function( ev ) 110 { 111 var retVal; 112 113 if ( instance.onfocus ) 114 retVal = ( instance.onfocus( instance, new CKEDITOR.dom.event( ev ) ) !== false ); 115 116 // FF2: prevent focus event been bubbled up to editor container, which caused unexpected editor focus. 117 if ( CKEDITOR.env.gecko && CKEDITOR.env.version < 10900 ) 118 ev.preventBubble(); 119 return retVal; 120 }); 121 122 instance.clickFn = clickFn = CKEDITOR.tools.addFunction( instance.execute, instance ); 123 124 125 // Indicate a mode sensitive button. 126 if ( this.modes ) 127 { 128 var modeStates = {}; 129 130 function updateState() 131 { 132 // "this" is a CKEDITOR.ui.button instance. 133 134 var mode = editor.mode; 135 136 if ( mode ) 137 { 138 // Restore saved button state. 139 var state = this.modes[ mode ] ? modeStates[ mode ] != undefined ? modeStates[ mode ] : 140 CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED; 141 142 this.setState( editor.readOnly && !this.readOnly ? CKEDITOR.TRISTATE_DISABLED : state ); 143 } 144 } 145 146 editor.on( 'beforeModeUnload', function() 147 { 148 if ( editor.mode && this._.state != CKEDITOR.TRISTATE_DISABLED ) 149 modeStates[ editor.mode ] = this._.state; 150 }, this ); 151 152 editor.on( 'mode', updateState, this); 153 154 // If this button is sensitive to readOnly state, update it accordingly. 155 !this.readOnly && editor.on( 'readOnly', updateState, this); 156 } 157 else if ( command ) 158 { 159 // Get the command instance. 160 command = editor.getCommand( command ); 161 162 if ( command ) 163 { 164 command.on( 'state', function() 165 { 166 this.setState( command.state ); 167 }, this); 168 169 classes += 'cke_' + ( 170 command.state == CKEDITOR.TRISTATE_ON ? 'on' : 171 command.state == CKEDITOR.TRISTATE_DISABLED ? 'disabled' : 172 'off' ); 173 } 174 } 175 176 if ( !command ) 177 classes += 'cke_off'; 178 179 if ( this.className ) 180 classes += ' ' + this.className; 181 182 output.push( 183 '<span class="cke_button' + ( this.icon && this.icon.indexOf( '.png' ) == -1 ? ' cke_noalphafix' : '' ) + '">', 184 '<a id="', id, '"' + 185 ' class="', classes, '"', 186 env.gecko && env.version >= 10900 && !env.hc ? '' : '" href="javascript:void(\''+ ( this.title || '' ).replace( "'", '' )+ '\')"', 187 ' title="', this.title, '"' + 188 ' tabindex="-1"' + 189 ' hidefocus="true"' + 190 ' role="button"' + 191 ' aria-labelledby="' + id + '_label"' + 192 ( this.hasArrow ? ' aria-haspopup="true"' : '' ) ); 193 194 // Some browsers don't cancel key events in the keydown but in the 195 // keypress. 196 // TODO: Check if really needed for Gecko+Mac. 197 if ( env.opera || ( env.gecko && env.mac ) ) 198 { 199 output.push( 200 ' onkeypress="return false;"' ); 201 } 202 203 // With Firefox, we need to force the button to redraw, otherwise it 204 // will remain in the focus state. 205 if ( env.gecko ) 206 { 207 output.push( 208 ' onblur="this.style.cssText = this.style.cssText;"' ); 209 } 210 211 output.push( 212 ' onkeydown="return CKEDITOR.tools.callFunction(', keydownFn, ', event);"' + 213 ' onfocus="return CKEDITOR.tools.callFunction(', focusFn,', event);" ' + 214 ( CKEDITOR.env.ie ? 'onclick="return false;" onmouseup' : 'onclick' ) + // #188 215 '="CKEDITOR.tools.callFunction(', clickFn, ', this); return false;">' + 216 '<span class="cke_icon"' ); 217 218 if ( this.icon ) 219 { 220 var offset = ( this.iconOffset || 0 ) * -16; 221 output.push( ' style="background-image:url(', CKEDITOR.getUrl( this.icon ), ');background-position:0 ' + offset + 'px;"' ); 222 } 223 224 output.push( 225 '> </span>' + 226 '<span id="', id, '_label" class="cke_label">', this.label, '</span>' ); 227 228 if ( this.hasArrow ) 229 { 230 output.push( 231 '<span class="cke_buttonarrow">' 232 // BLACK DOWN-POINTING TRIANGLE 233 + ( CKEDITOR.env.hc ? '▼' : ' ' ) 234 + '</span>' ); 235 } 236 237 output.push( 238 '</a>', 239 '</span>' ); 240 241 if ( this.onRender ) 242 this.onRender(); 243 244 return instance; 245 }, 246 247 setState : function( state ) 248 { 249 if ( this._.state == state ) 250 return false; 251 252 this._.state = state; 253 254 var element = CKEDITOR.document.getById( this._.id ); 255 256 if ( element ) 257 { 258 element.setState( state ); 259 state == CKEDITOR.TRISTATE_DISABLED ? 260 element.setAttribute( 'aria-disabled', true ) : 261 element.removeAttribute( 'aria-disabled' ); 262 263 state == CKEDITOR.TRISTATE_ON ? 264 element.setAttribute( 'aria-pressed', true ) : 265 element.removeAttribute( 'aria-pressed' ); 266 267 return true; 268 } 269 else 270 return false; 271 } 272 }; 273 274 })(); 275 276 /** 277 * Adds a button definition to the UI elements list. 278 * @param {String} name The button name. 279 * @param {Object} definition The button definition. 280 * @example 281 * editorInstance.ui.addButton( 'MyBold', 282 * { 283 * label : 'My Bold', 284 * command : 'bold' 285 * }); 286 */ 287 CKEDITOR.ui.prototype.addButton = function( name, definition ) 288 { 289 this.add( name, CKEDITOR.UI_BUTTON, definition ); 290 }; 291