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 	/**
 31 	 * The button label.
 32 	 * @name CKEDITOR.ui.button.prototype.label
 33 	 * @type String
 34 	 * @example
 35 	 */
 36 	this.label = definition.label;
 37
 38 	/**
 39 	 * The button advisory title. It is usually displayed as the button tooltip.
 40 	 * If not defined, the label is used.
 41 	 * @name CKEDITOR.ui.button.prototype.title
 42 	 * @type String
 43 	 * @example
 44 	 */
 45 	this.title = definition.title || definition.label;
 46
 47 	/**
 48 	 * The command name associated to the button. If no command is defined, the
 49 	 * "click" event is used.
 50 	 * @name CKEDITOR.ui.button.prototype.command
 51 	 * @type String
 52 	 * @example
 53 	 */
 54 	this.command = definition.command;
 55
 56 	this.className = definition.className || ( definition.command && 'cke_button_' + definition.command ) || '';
 57
 58 	this.icon = definition.icon;
 59 	this.iconOffset = definition.iconOffset;
 60
 61 	/**
 62 	 * The function to be called when the user clicks the button. If not
 63 	 * defined, the "command" property is required, and the command gets
 64 	 * executed on click.
 65 	 * @function
 66 	 * @name CKEDITOR.ui.button.prototype.click
 67 	 * @example
 68 	 */
 69 	this.click = definition.click || function( editor )
 70 		{
 71 			editor.execCommand( definition.command );
 72 		};
 73
 74 	this._ = {};
 75 };
 76
 77 /**
 78  * Transforms a button definition in a {@link CKEDITOR.ui.button} instance.
 79  * @type Object
 80  * @example
 81  */
 82 CKEDITOR.ui.button.handler =
 83 {
 84 	create : function( definition )
 85 	{
 86 		return new CKEDITOR.ui.button( definition );
 87 	}
 88 };
 89
 90 CKEDITOR.ui.button.prototype =
 91 {
 92 	/**
 93 	 * Renders the button.
 94 	 * @param {CKEDITOR.editor} editor The editor instance which this button is
 95 	 *		to be used by.
 96 	 * @param {Array} output The output array to which append the HTML relative
 97 	 *		to this button.
 98 	 * @example
 99 	 */
100 	render : function( editor, output )
101 	{
102 		var env = CKEDITOR.env;
103
104 		var id = this._.id = 'cke_' + CKEDITOR.tools.getNextNumber();
105
106 		var instance =
107 		{
108 			id : id,
109 			button : this,
110 			editor : editor,
111 			focus : function()
112 			{
113 				var element = CKEDITOR.document.getById( id );
114 				element.focus();
115 			},
116 			execute : function()
117 			{
118 				this.button.click( editor );
119 			}
120 		};
121
122 		var index = CKEDITOR.ui.button._.instances.push( instance ) - 1;
123
124 		var classes = '';
125
126 		// Get the command name.
127 		var command = this.command;
128
129 		if ( command )
130 		{
131 			// Get the command instance.
132 			command = editor.getCommand( command );
133
134 			if ( command )
135 			{
136 				command.on( 'state', function()
137 					{
138 						this.setState( command.state );
139 					}, this);
140
141 				classes += ' cke_' + (
142 					command.state == CKEDITOR.TRISTATE_ON ? 'on' :
143 					command.state == CKEDITOR.TRISTATE_DISABLED ? 'disabled' :
144 					'off' );
145 			}
146 		}
147
148 		if ( this.className )
149 			classes += ' ' + this.className;
150
151 		output.push(
152 			'<span class="cke_button">',
153 			'<a id="', id, '"' +
154 				' class="', classes, '" href="javascript:void(\'', ( this.title || '' ).replace( "'", '' ), '\')"' +
155 				' title="', this.title, '"' +
156 				' tabindex="-1"' +
157 				' hidefocus="true"' );
158
159 		// Some browsers don't cancel key events in the keydown but in the
160 		// keypress.
161 		// TODO: Check if really needed for Gecko+Mac.
162 		if ( env.opera || ( env.gecko && env.mac ) )
163 		{
164 			output.push(
165 				' onkeypress="return false;"' );
166 		}
167
168 		// With Firefox, we need to force the button to redraw, otherwise it
169 		// will remain in the focus state.
170 		if ( env.gecko )
171 		{
172 			output.push(
173 				' onblur="this.style.cssText = this.style.cssText;"' );
174 		}
175
176 		output.push(
177 				' onkeydown="return CKEDITOR.ui.button._.keydown(', index, ', event);"' +
178 				' onfocus="return CKEDITOR.ui.button._.focus(', index, ', event);"' +
179 				' onclick="return CKEDITOR.ui.button._.click(', index, ', event);">' +
180 					'<span class="cke_icon"' );
181
182 		if ( this.icon )
183 		{
184 			var offset = ( this.iconOffset || 0 ) * -16;
185 			output.push( ' style="background-image:url(', CKEDITOR.getUrl( this.icon ), ');background-position:0 ' + offset + 'px;"' );
186 		}
187
188 		output.push(
189 					'></span>' +
190 					'<span class="cke_label">', this.label, '</span>' +
191 			'</a>',
192 			'</span>' );
193
194 		return instance;
195 	},
196
197 	setState : function( state )
198 	{
199 		if ( this._.state == state )
200 			return;
201
202 		CKEDITOR.document.getById( this._.id ).setState( state );
203
204 		this._.state = state;
205 	}
206 };
207
208 /**
209  * Handles a button click.
210  * @private
211  */
212 CKEDITOR.ui.button._ =
213 {
214 	instances : [],
215
216 	click : function( index )
217 	{
218 		CKEDITOR.ui.button._.instances[ index ].execute();
219 		return false;
220 	},
221
222 	keydown : function( index, ev )
223 	{
224 		var instance = CKEDITOR.ui.button._.instances[ index ];
225
226 		if ( instance.onkey )
227 		{
228 			ev = new CKEDITOR.dom.event( ev );
229 			return ( instance.onkey( instance, ev.getKeystroke() ) !== false );
230 		}
231 	},
232
233 	focus : function( index, ev )
234 	{
235 		var instance = CKEDITOR.ui.button._.instances[ index ];
236
237 		if ( instance.onfocus )
238 			return ( instance.onfocus( instance, new CKEDITOR.dom.event( ev ) ) !== false );
239 	}
240 };
241
242 /**
243  * Adds a button definition to the UI elements list.
244  * @param {String} The button name.
245  * @param {Object} The button definition.
246  * @example
247  * editorInstance.ui.addButton( 'MyBold',
248  *     {
249  *         label : 'My Bold',
250  *         command : 'bold'
251  *     });
252  */
253 CKEDITOR.ui.prototype.addButton = function( name, definition )
254 {
255 	this.add( name, CKEDITOR.UI_BUTTON, definition );
256 };
257