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( 'panel',
  7 {
  8 	beforeInit : function( editor )
  9 	{
 10 		editor.ui.addHandler( CKEDITOR.UI_PANEL, CKEDITOR.ui.panel.handler );
 11 	}
 12 });
 13
 14 /**
 15  * Panel UI element.
 16  * @constant
 17  * @example
 18  */
 19 CKEDITOR.UI_PANEL = 2;
 20
 21 CKEDITOR.ui.panel = function( document, definition )
 22 {
 23 	// Copy all definition properties to this object.
 24 	if ( definition )
 25 		CKEDITOR.tools.extend( this, definition );
 26
 27 	// Set defaults.
 28 	CKEDITOR.tools.extend( this,
 29 		{
 30 			className : '',
 31 			css : []
 32 		});
 33
 34 	this.id = CKEDITOR.tools.getNextNumber();
 35 	this.document = document;
 36
 37 	this._ =
 38 	{
 39 		blocks : {}
 40 	};
 41 };
 42
 43 /**
 44  * Transforms a rich combo definition in a {@link CKEDITOR.ui.richCombo}
 45  * instance.
 46  * @type Object
 47  * @example
 48  */
 49 CKEDITOR.ui.panel.handler =
 50 {
 51 	create : function( definition )
 52 	{
 53 		return new CKEDITOR.ui.panel( definition );
 54 	}
 55 };
 56
 57 CKEDITOR.ui.panel.prototype =
 58 {
 59 	renderHtml : function( editor )
 60 	{
 61 		var output = [];
 62 		this.render( editor, output );
 63 		return output.join( '' );
 64 	},
 65
 66 	/**
 67 	 * Renders the combo.
 68 	 * @param {CKEDITOR.editor} editor The editor instance which this button is
 69 	 *		to be used by.
 70 	 * @param {Array} output The output array to which append the HTML relative
 71 	 *		to this button.
 72 	 * @example
 73 	 */
 74 	render : function( editor, output )
 75 	{
 76 		var id = 'cke_' + this.id;
 77
 78 		output.push(
 79 			'<div class="', editor.skinClass ,'">' +
 80 				'<div id=', id, ' class="cke_panel' );
 81
 82 		if ( this.className )
 83 			output.push( ' ', this.className );
 84
 85 		output.push(
 86 				'">' );
 87
 88 		if ( this.forceIFrame || this.css.length )
 89 		{
 90 			output.push(
 91 						'<iframe id="', id, '_frame"' +
 92 							' frameborder="0"' +
 93 							' src="javascript:void(0)"' +
 94 						'></iframe>' );
 95 		}
 96
 97 		output.push(
 98 				'</div>' +
 99 			'</div>' );
100
101 		return id;
102 	},
103
104 	getHolderElement : function()
105 	{
106 		var holder = this._.holder;
107
108 		if ( !holder )
109 		{
110 			if ( this.forceIFrame || this.css.length )
111 			{
112 				var iframe = this.document.getById( 'cke_' + this.id + '_frame' );
113 				var doc = new CKEDITOR.dom.document( iframe.$.contentWindow.document );
114
115 				var className = iframe.getParent().getParent().getAttribute( 'class' );
116
117 				// Initialize the IFRAME document body.
118 				doc.$.open();
119 				doc.$.write(
120 					'<!DOCTYPE html>' +
121 					'<html>' +
122 						'<head>' +
123 							'<link type="text/css" rel=stylesheet href="' + this.css.join( '"><link type="text/css" rel="stylesheet" href="' ) + '">' +
124 							'<style>.' + className + '_container{visibility:hidden}</style>' +
125 						'</head>' +
126 						'<body class="' + className + '_container cke_panel_frame" style="margin:0;padding:0">' +
127 						'</body>' +
128 					'<\/html>' );
129 				doc.$.close();
130
131 				var win = doc.getWindow();
132
133 				// Register the CKEDITOR global.
134 				win.$.CKEDITOR = CKEDITOR;
135
136 				win.on( 'load', function( ev )
137 					{
138 						this.isLoaded = true;
139 						if ( this.onLoad )
140 							this.onLoad();
141 					},
142 					this);
143
144 				doc.on( 'keydown', function( evt )
145 					{
146 						var keystroke = evt.data.getKeystroke();
147
148 						// Delegate key processing to block.
149 						if ( this._.onKeyDown && this._.onKeyDown( keystroke ) === false )
150 						{
151 							evt.data.preventDefault();
152 							return;
153 						}
154
155 						if ( keystroke == 27 )		// ESC
156 							this.onEscape && this.onEscape();
157 					},
158 					this );
159
160 				holder = doc.getBody();
161 			}
162 			else
163 				holder = this.document.getById( 'cke_' + this.id );
164
165 			this._.holder = holder;
166 		}
167
168 		return holder;
169 	},
170
171 	addBlock : function( name, block )
172 	{
173 		block = this._.blocks[ name ] = block || new CKEDITOR.ui.panel.block( this.getHolderElement() );
174
175 		if ( !this._.currentBlock )
176 			this.showBlock( name );
177
178 		return block;
179 	},
180
181 	getBlock : function( name )
182 	{
183 		return this._.blocks[ name ];
184 	},
185
186 	showBlock : function( name )
187 	{
188 		var blocks = this._.blocks,
189 			block = blocks[ name ],
190 			current = this._.currentBlock;
191
192 		if ( current )
193 			current.hide();
194
195 		this._.currentBlock = block;
196
197 		// Reset the focus index, so it will always go into the first one.
198 		block._.focusIndex = -1;
199
200 		this._.onKeyDown = block.onKeyDown && CKEDITOR.tools.bind( block.onKeyDown, block );
201
202 		block.show();
203
204 		return block;
205 	}
206 };
207
208 CKEDITOR.ui.panel.block = CKEDITOR.tools.createClass(
209 {
210 	$ : function( blockHolder )
211 	{
212 		this.element = blockHolder.append(
213 			blockHolder.getDocument().createElement( 'div',
214 				{
215 					attributes :
216 					{
217 						'class' : 'cke_panel_block'
218 					},
219 					styles :
220 					{
221 						display : 'none'
222 					}
223 				}) );
224
225 		this.keys = {};
226
227 		this._.focusIndex = -1;
228 	},
229
230 	_ : {},
231
232 	proto :
233 	{
234 		show : function()
235 		{
236 			this.element.setStyle( 'display', '' );
237 		},
238
239 		hide : function()
240 		{
241 			this.element.setStyle( 'display', 'none' );
242 		},
243
244 		onKeyDown : function( keystroke )
245 		{
246 			var keyAction = this.keys[ keystroke ];
247 			switch ( keyAction )
248 			{
249 				// Move forward.
250 				case 'next' :
251 					var index = this._.focusIndex,
252 						links = this.element.getElementsByTag( 'a' ),
253 						link;
254
255 					while ( ( link = links.getItem( ++index ) ) )
256 					{
257 						// Move the focus only if the element is marked with
258 						// the _cke_focus and it it's visible (check if it has
259 						// width).
260 						if ( link.getAttribute( '_cke_focus' ) && link.$.offsetWidth )
261 						{
262 							this._.focusIndex = index;
263 							link.focus();
264 							break;
265 						}
266 					}
267 					return false;
268
269 				// Move backward.
270 				case 'prev' :
271 					var index = this._.focusIndex,
272 						links = this.element.getElementsByTag( 'a' ),
273 						link;
274
275 					while ( index > 0 && ( link = links.getItem( --index ) ) )
276 					{
277 						// Move the focus only if the element is marked with
278 						// the _cke_focus and it it's visible (check if it has
279 						// width).
280 						if ( link.getAttribute( '_cke_focus' ) && link.$.offsetWidth )
281 						{
282 							this._.focusIndex = index;
283 							link.focus();
284 							break;
285 						}
286 					}
287 					return false;
288
289 				case 'click' :
290 					var index = this._.focusIndex,
291 						link = index >= 0 && this.element.getElementsByTag( 'a' ).getItem( index );
292
293 					if ( link )
294 						link.$.click();
295
296 					return false;
297 			}
298 		}
299 	}
300 });
301