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( 'panelbutton',
  7 {
  8 	requires : [ 'button' ],
  9 	beforeInit : function( editor )
 10 	{
 11 		editor.ui.addHandler( CKEDITOR.UI_PANELBUTTON, CKEDITOR.ui.panelButton.handler );
 12 	}
 13 });
 14
 15 /**
 16  * Button UI element.
 17  * @constant
 18  * @example
 19  */
 20 CKEDITOR.UI_PANELBUTTON = 4;
 21
 22 CKEDITOR.ui.panelButton = CKEDITOR.tools.createClass(
 23 {
 24 	$ : function( definition )
 25 	{
 26 		// Copy all definition properties to this object.
 27 		CKEDITOR.tools.extend( this, definition,
 28 			// Set defaults.
 29 			{
 30 				title : definition.label,
 31 				modes : { wysiwyg : 1 }
 32 			});
 33
 34 		// We don't want the panel definition in this object.
 35 		var panelDefinition = this.panel;
 36 		delete this.panel;
 37
 38 		this.document = ( panelDefinition
 39 							&& panelDefinition.parent
 40 							&& panelDefinition.parent.getDocument() )
 41 						|| CKEDITOR.document;
 42 		this._ =
 43 		{
 44 			panelDefinition : panelDefinition
 45 		};
 46 	},
 47
 48 	statics :
 49 	{
 50 		handler :
 51 		{
 52 			create : function( definition )
 53 			{
 54 				return new CKEDITOR.ui.panelButton( definition );
 55 			}
 56 		}
 57 	},
 58
 59 	proto :
 60 	{
 61 		render : function( editor, output )
 62 		{
 63 			var id = this._.id = 'cke_' + CKEDITOR.tools.getNextNumber();
 64
 65 			var instance =
 66 			{
 67 				id : id,
 68 				focus : function()
 69 				{
 70 					var element = CKEDITOR.document.getById( id );
 71 					element.focus();
 72 				},
 73 				execute : function()
 74 				{
 75 					this.button.click( editor );
 76 				}
 77 			};
 78
 79 			var clickFn = CKEDITOR.tools.addFunction( function( $element )
 80 				{
 81 					var _ = this._;
 82
 83 					if ( _.state == CKEDITOR.TRISTATE_DISABLED )
 84 						return;
 85
 86 					this.createPanel( editor );
 87
 88 					if ( _.on )
 89 					{
 90 						_.panel.hide();
 91 						return;
 92 					}
 93
 94 					_.panel.showBlock( this._.id, new CKEDITOR.dom.element( $element ), 4 );
 95 				},
 96 				this );
 97 			var keyDownFn = CKEDITOR.tools.addFunction( function( ev, element ){
 98
 99 				ev = new CKEDITOR.dom.event( ev );
100
101 				var keystroke = ev.getKeystroke();
102 				switch ( keystroke )
103 				{
104 					case 13 :	// ENTER
105 					case 32 :	// SPACE
106 					case 40 :	// ARROW-DOWN
107 						// Show panel
108 						CKEDITOR.tools.callFunction( clickFn, element );
109 						break;
110 					default :
111 						// Delegate the default behavior to toolbar button key handling.
112 						instance.onkey( instance,  keystroke );
113 				}
114
115 				// Avoid subsequent focus grab on editor document.
116 				ev.preventDefault();
117 			});
118
119 			var label = this.label || '';
120
121 			var classes = 'cke_off';
122
123 			if ( this.className )
124 				classes += ' ' + this.className;
125
126 			editor.on( 'mode', function()
127 				{
128 					this.setState( this.modes[ editor.mode ] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED );
129 				},
130 				this );
131
132 			output.push(
133 				'<span class="cke_button">',
134 				'<a id="', id, '"' +
135 					' class="', classes, '" href="javascript:void(\'', ( this.title || '' ).replace( "'", '' ), '\')"' +
136 					' title="', this.title, '"' +
137 					' tabindex="-1"' +
138 					' hidefocus="true"' );
139
140 			// Some browsers don't cancel key events in the keydown but in the
141 			// keypress.
142 			// TODO: Check if really needed for Gecko+Mac.
143 			if ( CKEDITOR.env.opera || ( CKEDITOR.env.gecko && CKEDITOR.env.mac ) )
144 			{
145 				output.push(
146 					' onkeypress="return false;"' );
147 			}
148
149 			// With Firefox, we need to force the button to redraw, otherwise it
150 			// will remain in the focus state.
151 			if ( CKEDITOR.env.gecko )
152 			{
153 				output.push(
154 					' onblur="this.style.cssText = this.style.cssText;"' );
155 			}
156
157 			output.push(
158 					' onkeydown="CKEDITOR.tools.callFunction( ', keyDownFn, ', event, this );"' +
159 					' onclick="CKEDITOR.tools.callFunction(', clickFn, ', this);">' +
160 						'<span class="cke_icon"></span>' +
161 						'<span class="cke_label">', this.label, '</span>' +
162 						'<span class="cke_buttonarrow"></span>' +
163 				'</a>' +
164 				'</span>' );
165
166 			return instance;
167 		},
168
169 		createPanel : function( editor )
170 		{
171 			var _ = this._;
172
173 			if ( _.panel )
174 				return;
175
176 			var panelDefinition = this._.panelDefinition || {},
177 				panelParentElement = panelDefinition.parent || CKEDITOR.document.getBody(),
178 				panel = this._.panel = new CKEDITOR.ui.floatPanel( editor, panelParentElement, panelDefinition ),
179 				me = this;
180
181 			panel.onShow = function()
182 				{
183 					if ( me.className )
184 						this.element.getFirst().addClass( me.className + '_panel' );
185
186 					me.setState( CKEDITOR.TRISTATE_ON );
187
188 					_.on = 1;
189
190 					if ( me.onOpen )
191 						me.onOpen();
192 				};
193
194 			panel.onHide = function()
195 				{
196 					if ( me.className )
197 						this.element.getFirst().removeClass( me.className + '_panel' );
198
199 					me.setState( CKEDITOR.TRISTATE_OFF );
200
201 					_.on = 0;
202
203 					if ( me.onClose )
204 						me.onClose();
205 				};
206
207 			panel.onEscape = function()
208 				{
209 					panel.hide();
210 					me.document.getById( _.id ).focus();
211 				};
212
213
214 			if ( this.onBlock )
215 				this.onBlock( panel, _.id );
216 		},
217
218 		setState : CKEDITOR.ui.button.prototype.setState
219 	}
220 });
221