2 Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
3 For licensing, see LICENSE.html or http://ckeditor.com/license
6 CKEDITOR.plugins.add( 'panel',
8 beforeInit : function( editor )
10 editor.ui.addHandler( CKEDITOR.UI_PANEL, CKEDITOR.ui.panel.handler );
19 CKEDITOR.UI_PANEL = 2;
21 CKEDITOR.ui.panel = function( document, definition )
23 // Copy all definition properties to this object.
25 CKEDITOR.tools.extend( this, definition );
28 CKEDITOR.tools.extend( this,
34 this.id = CKEDITOR.tools.getNextId();
35 this.document = document;
44 * Transforms a rich combo definition in a {@link CKEDITOR.ui.richCombo}
49 CKEDITOR.ui.panel.handler =
51 create : function( definition )
53 return new CKEDITOR.ui.panel( definition );
57 CKEDITOR.ui.panel.prototype =
59 renderHtml : function( editor )
62 this.render( editor, output );
63 return output.join( '' );
68 * @param {CKEDITOR.editor} editor The editor instance which this button is
70 * @param {Array} output The output array to which append the HTML relative
74 render : function( editor, output )
79 '<div class="', editor.skinClass ,'"' +
80 ' lang="', editor.langCode, '"' +
81 ' role="presentation"' +
82 // iframe loading need sometime, keep the panel hidden(#4186).
83 ' style="display:none;z-index:' + ( editor.config.baseFloatZIndex + 1 ) + '">' +
86 ' dir=', editor.lang.dir,
87 ' role="presentation"' +
88 ' class="cke_panel cke_', editor.lang.dir );
91 output.push( ' ', this.className );
96 if ( this.forceIFrame || this.css.length )
99 '<iframe id="', id, '_frame"' +
101 ' role="application" src="javascript:void(' );
104 // Support for custom document.domain in IE.
105 CKEDITOR.env.isCustomDomain() ?
108 'document.domain=\'' + document.domain + '\';' +
109 'document.close();' +
125 getHolderElement : function()
127 var holder = this._.holder;
131 if ( this.forceIFrame || this.css.length )
133 var iframe = this.document.getById( this.id + '_frame' ),
134 parentDiv = iframe.getParent(),
135 dir = parentDiv.getAttribute( 'dir' ),
136 className = parentDiv.getParent().getAttribute( 'class' ),
137 langCode = parentDiv.getParent().getAttribute( 'lang' ),
138 doc = iframe.getFrameDocument();
140 var onLoad = CKEDITOR.tools.addFunction( CKEDITOR.tools.bind( function( ev )
142 this.isLoaded = true;
149 '<html dir="' + dir + '" class="' + className + '_container" lang="' + langCode + '">' +
151 '<style>.' + className + '_container{visibility:hidden}</style>' +
153 '<body class="cke_' + dir + ' cke_panel_frame ' + CKEDITOR.env.cssClass + '" style="margin:0;padding:0"' +
154 ' onload="( window.CKEDITOR || window.parent.CKEDITOR ).tools.callFunction(' + onLoad + ');"></body>' +
155 // It looks strange, but for FF2, the styles must go
156 // after <body>, so it (body) becames immediatelly
157 // available. (#3031)
158 CKEDITOR.tools.buildStyleHtml( this.css ) +
163 var win = doc.getWindow();
165 // Register the CKEDITOR global.
166 win.$.CKEDITOR = CKEDITOR;
168 // Arrow keys for scrolling is only preventable with 'keypress' event in Opera (#4534).
169 doc.on( 'key' + ( CKEDITOR.env.opera? 'press':'down' ), function( evt )
171 var keystroke = evt.data.getKeystroke(),
172 dir = this.document.getById( this.id ).getAttribute( 'dir' );
174 // Delegate key processing to block.
175 if ( this._.onKeyDown && this._.onKeyDown( keystroke ) === false )
177 evt.data.preventDefault();
181 // ESC/ARROW-LEFT(ltr) OR ARROW-RIGHT(rtl)
182 if ( keystroke == 27 || keystroke == ( dir == 'rtl' ? 39 : 37 ) )
184 if ( this.onEscape && this.onEscape( keystroke ) === false )
185 evt.data.preventDefault();
190 holder = doc.getBody();
191 holder.unselectable();
192 CKEDITOR.env.air && CKEDITOR.tools.callFunction( onLoad );
195 holder = this.document.getById( this.id );
197 this._.holder = holder;
203 addBlock : function( name, block )
205 block = this._.blocks[ name ] = block instanceof CKEDITOR.ui.panel.block ? block
206 : new CKEDITOR.ui.panel.block( this.getHolderElement(), block );
208 if ( !this._.currentBlock )
209 this.showBlock( name );
214 getBlock : function( name )
216 return this._.blocks[ name ];
219 showBlock : function( name )
221 var blocks = this._.blocks,
222 block = blocks[ name ],
223 current = this._.currentBlock,
224 holder = this.forceIFrame ?
225 this.document.getById( this.id + '_frame' )
228 // Disable context menu for block panel.
229 holder.getParent().getParent().disableContextMenu();
233 // Clean up the current block's effects on holder.
234 holder.removeAttributes( current.attributes );
238 this._.currentBlock = block;
240 holder.setAttributes( block.attributes );
241 CKEDITOR.fire( 'ariaWidget', holder );
243 // Reset the focus index, so it will always go into the first one.
244 block._.focusIndex = -1;
246 this._.onKeyDown = block.onKeyDown && CKEDITOR.tools.bind( block.onKeyDown, block );
248 block.onMark = function( item )
250 holder.setAttribute( 'aria-activedescendant', item.getId() + '_option' );
253 block.onUnmark = function()
255 holder.removeAttribute( 'aria-activedescendant' );
265 this.element && this.element.remove();
269 CKEDITOR.ui.panel.block = CKEDITOR.tools.createClass(
271 $ : function( blockHolder, blockDefinition )
273 this.element = blockHolder.append(
274 blockHolder.getDocument().createElement( 'div',
279 'class' : 'cke_panel_block',
280 'role' : 'presentation'
288 // Copy all definition properties to this object.
289 if ( blockDefinition )
290 CKEDITOR.tools.extend( this, blockDefinition );
292 if ( !this.attributes.title )
293 this.attributes.title = this.attributes[ 'aria-label' ];
297 this._.focusIndex = -1;
299 // Disable context menu for panels.
300 this.element.disableContextMenu();
306 * Mark the item specified by the index as current activated.
308 markItem: function( index )
312 var links = this.element.getElementsByTag( 'a' );
313 var item = links.getItem( this._.focusIndex = index );
315 // Safari need focus on the iframe window first(#3389), but we need
316 // lock the blur to avoid hiding the panel.
317 if ( CKEDITOR.env.webkit || CKEDITOR.env.opera )
318 item.getDocument().getWindow().focus();
321 this.onMark && this.onMark( item );
329 this.element.setStyle( 'display', '' );
334 if ( !this.onHide || this.onHide.call( this ) !== true )
335 this.element.setStyle( 'display', 'none' );
338 onKeyDown : function( keystroke )
340 var keyAction = this.keys[ keystroke ];
345 var index = this._.focusIndex,
346 links = this.element.getElementsByTag( 'a' ),
349 while ( ( link = links.getItem( ++index ) ) )
351 // Move the focus only if the element is marked with
352 // the _cke_focus and it it's visible (check if it has
354 if ( link.getAttribute( '_cke_focus' ) && link.$.offsetWidth )
356 this._.focusIndex = index;
365 index = this._.focusIndex;
366 links = this.element.getElementsByTag( 'a' );
368 while ( index > 0 && ( link = links.getItem( --index ) ) )
370 // Move the focus only if the element is marked with
371 // the _cke_focus and it it's visible (check if it has
373 if ( link.getAttribute( '_cke_focus' ) && link.$.offsetWidth )
375 this._.focusIndex = index;
383 index = this._.focusIndex;
384 link = index >= 0 && this.element.getElementsByTag( 'a' ).getItem( index );
387 link.$.click ? link.$.click() : link.$.onclick();
398 * Fired when a panel is added to the document
399 * @name CKEDITOR#ariaWidget
401 * @param {Object} holder The element wrapping the panel