      1 ﻿/*
      2 Copyright (c) 2003-2009, 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 = 1;
     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 CKEDITOR.ui.button.prototype =
     59 {
     60 	canGroup : true,
     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
     74 		var id = this._.id = 'cke_' + CKEDITOR.tools.getNextNumber();
     75 		this._.editor = editor;
     76
     77 		var instance =
     78 		{
     79 			id : id,
     80 			button : this,
     81 			editor : editor,
     82 			focus : function()
     83 			{
     84 				var element = CKEDITOR.document.getById( id );
     85 				element.focus();
     86 			},
     87 			execute : function()
     88 			{
     89 				this.button.click( editor );
     90 			}
     91 		};
     92
     93 		var clickFn = CKEDITOR.tools.addFunction( instance.execute, instance );
     94
     95 		var index = CKEDITOR.ui.button._.instances.push( instance ) - 1;
     96
     97 		var classes = '';
     98
     99 		// Get the command name.
    100 		var command = this.command;
    101
    102 		if ( command )
    103 		{
    104 			// Get the command instance.
    105 			command = editor.getCommand( command );
    106
    107 			if ( command )
    108 			{
    109 				command.on( 'state', function()
    110 					{
    111 						this.setState( command.state );
    112 					}, this);
    113
    114 				classes += 'cke_' + (
    115 					command.state == CKEDITOR.TRISTATE_ON ? 'on' :
    116 					command.state == CKEDITOR.TRISTATE_DISABLED ? 'disabled' :
    117 					'off' );
    118 			}
    119 		}
    120
    121 		if ( !command )
    122 			classes	+= 'cke_off';
    123
    124 		if ( this.className )
    125 			classes += ' ' + this.className;
    126
    127 		output.push(
    128 			'<span class="cke_button">',
    129 			'<a id="', id, '"' +
    130 				' class="', classes, '" href="javascript:void(\'', ( this.title || '' ).replace( "'", '' ), '\')"' +
    131 				' title="', this.title, '"' +
    132 				' tabindex="-1"' +
    133 				' role="button"' +
    134 				' hidefocus="true"' );
    135
    136 		// Some browsers don't cancel key events in the keydown but in the
    137 		// keypress.
    138 		// TODO: Check if really needed for Gecko+Mac.
    139 		if ( env.opera || ( env.gecko && env.mac ) )
    140 		{
    141 			output.push(
    142 				' onkeypress="return false;"' );
    143 		}
    144
    145 		// With Firefox, we need to force the button to redraw, otherwise it
    146 		// will remain in the focus state.
    147 		if ( env.gecko )
    148 		{
    149 			output.push(
    150 				' onblur="this.style.cssText = this.style.cssText;"' );
    151 		}
    152
    153 		output.push(
    154 				' onkeydown="return CKEDITOR.ui.button._.keydown(', index, ', event);"' +
    155 				' onfocus="return CKEDITOR.ui.button._.focus(', index, ', event);"' +
    156 				' onclick="CKEDITOR.tools.callFunction(', clickFn, ', this); return false;">' +
    157 					'<span class="cke_icon"' );
    158
    159 		if ( this.icon )
    160 		{
    161 			var offset = ( this.iconOffset || 0 ) * -16;
    162 			output.push( ' style="background-image:url(', CKEDITOR.getUrl( this.icon ), ');background-position:0 ' + offset + 'px;"' );
    163 		}
    164
    165 		output.push(
    166 					'></span>' +
    167 					'<span class="cke_label">', this.label, '</span>' );
    168
    169 		if ( this.hasArrow )
    170 		{
    171 			output.push(
    172 					'<span class="cke_buttonarrow"></span>' );
    173 		}
    174
    175 		output.push(
    176 			'</a>',
    177 			'</span>' );
    178
    179 		if ( this.onRender )
    180 			this.onRender();
    181
    182 		return instance;
    183 	},
    184
    185 	setState : function( state )
    186 	{
    187 		if ( this._.state == state )
    188 			return;
    189
    190 		var element = CKEDITOR.document.getById( this._.id );
    191
    192 		if ( element )
    193 		{
    194 			element.setState( state );
    195
    196 			var htmlTitle = this.title,
    197 				unavailable = this._.editor.lang.common.unavailable,
    198 				labelElement = element.getChild( 1 );
    199
    200 			if ( state == CKEDITOR.TRISTATE_DISABLED )
    201 				htmlTitle = unavailable.replace( '%1', this.title );
    202
    203 			labelElement.setHtml( htmlTitle );
    204 		}
    205
    206 		this._.state = state;
    207 	}
    208 };
    209
    210 /**
    211  * Handles a button click.
    212  * @private
    213  */
    214 CKEDITOR.ui.button._ =
    215 {
    216 	instances : [],
    217
    218 	keydown : function( index, ev )
    219 	{
    220 		var instance = CKEDITOR.ui.button._.instances[ index ];
    221
    222 		if ( instance.onkey )
    223 		{
    224 			ev = new CKEDITOR.dom.event( ev );
    225 			return ( instance.onkey( instance, ev.getKeystroke() ) !== false );
    226 		}
    227 	},
    228
    229 	focus : function( index, ev )
    230 	{
    231 		var instance = CKEDITOR.ui.button._.instances[ index ],
    232 			retVal;
    233
    234 		if ( instance.onfocus )
    235 			retVal = ( instance.onfocus( instance, new CKEDITOR.dom.event( ev ) ) !== false );
    236
    237 		// FF2: prevent focus event been bubbled up to editor container, which caused unexpected editor focus.
    238 		if ( CKEDITOR.env.gecko && CKEDITOR.env.version < 10900 )
    239 			ev.preventBubble();
    240 		return retVal;
    241 	}
    242 };
    243
    244 /**
    245  * Adds a button definition to the UI elements list.
    246  * @param {String} The button name.
    247  * @param {Object} The button definition.
    248  * @example
    249  * editorInstance.ui.addButton( 'MyBold',
    250  *     {
    251  *         label : 'My Bold',
    252  *         command : 'bold'
    253  *     });
    254  */
    255 CKEDITOR.ui.prototype.addButton = function( name, definition )
    256 {
    257 	this.add( name, CKEDITOR.UI_BUTTON, definition );
    258 };
    259