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