2 Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
\r
3 For licensing, see LICENSE.html or http://ckeditor.com/license
\r
6 CKEDITOR.plugins.add( 'panel',
\r
8 beforeInit : function( editor )
\r
10 editor.ui.addHandler( CKEDITOR.UI_PANEL, CKEDITOR.ui.panel.handler );
\r
19 CKEDITOR.UI_PANEL = 2;
\r
21 CKEDITOR.ui.panel = function( document, definition )
\r
23 // Copy all definition properties to this object.
\r
25 CKEDITOR.tools.extend( this, definition );
\r
28 CKEDITOR.tools.extend( this,
\r
34 this.id = CKEDITOR.tools.getNextNumber();
\r
35 this.document = document;
\r
44 * Transforms a rich combo definition in a {@link CKEDITOR.ui.richCombo}
\r
49 CKEDITOR.ui.panel.handler =
\r
51 create : function( definition )
\r
53 return new CKEDITOR.ui.panel( definition );
\r
57 CKEDITOR.ui.panel.prototype =
\r
59 renderHtml : function( editor )
\r
62 this.render( editor, output );
\r
63 return output.join( '' );
\r
67 * Renders the combo.
\r
68 * @param {CKEDITOR.editor} editor The editor instance which this button is
\r
70 * @param {Array} output The output array to which append the HTML relative
\r
74 render : function( editor, output )
\r
76 var id = 'cke_' + this.id;
\r
79 '<div class="', editor.skinClass ,'"' +
\r
80 ' lang="', editor.langCode, '"' +
\r
81 ' role="presentation"' +
\r
82 // iframe loading need sometime, keep the panel hidden(#4186).
\r
83 ' style="display:none;z-index:' + ( editor.config.baseFloatZIndex + 1 ) + '">' +
\r
86 ' dir=', editor.lang.dir,
\r
87 ' role="presentation"' +
\r
88 ' class="cke_panel cke_', editor.lang.dir );
\r
90 if ( this.className )
\r
91 output.push( ' ', this.className );
\r
96 if ( this.forceIFrame || this.css.length )
\r
99 '<iframe id="', id, '_frame"' +
\r
100 ' frameborder="0"' +
\r
101 ' role="application" src="javascript:void(' );
\r
104 // Support for custom document.domain in IE.
\r
105 CKEDITOR.env.isCustomDomain() ?
\r
107 'document.open();' +
\r
108 'document.domain=\'' + document.domain + '\';' +
\r
109 'document.close();' +
\r
125 getHolderElement : function()
\r
127 var holder = this._.holder;
\r
131 if ( this.forceIFrame || this.css.length )
\r
133 var iframe = this.document.getById( 'cke_' + this.id + '_frame' ),
\r
134 parentDiv = iframe.getParent(),
\r
135 dir = parentDiv.getAttribute( 'dir' ),
\r
136 className = parentDiv.getParent().getAttribute( 'class' ),
\r
137 langCode = parentDiv.getParent().getAttribute( 'lang' ),
\r
138 doc = iframe.getFrameDocument();
\r
139 // Initialize the IFRAME document body.
\r
142 // Support for custom document.domain in IE.
\r
143 if ( CKEDITOR.env.isCustomDomain() )
\r
144 doc.$.domain = document.domain;
\r
146 var onLoad = CKEDITOR.tools.addFunction( CKEDITOR.tools.bind( function( ev )
\r
148 this.isLoaded = true;
\r
154 '<!DOCTYPE html>' +
\r
155 '<html dir="' + dir + '" class="' + className + '_container" lang="' + langCode + '">' +
\r
157 '<style>.' + className + '_container{visibility:hidden}</style>' +
\r
159 '<body class="cke_' + dir + ' cke_panel_frame ' + CKEDITOR.env.cssClass + '" style="margin:0;padding:0"' +
\r
160 ' onload="( window.CKEDITOR || window.parent.CKEDITOR ).tools.callFunction(' + onLoad + ');"></body>' +
\r
161 // It looks strange, but for FF2, the styles must go
\r
162 // after <body>, so it (body) becames immediatelly
\r
163 // available. (#3031)
\r
164 CKEDITOR.tools.buildStyleHtml( this.css ) +
\r
168 var win = doc.getWindow();
\r
170 // Register the CKEDITOR global.
\r
171 win.$.CKEDITOR = CKEDITOR;
\r
173 doc.on( 'keydown', function( evt )
\r
175 var keystroke = evt.data.getKeystroke(),
\r
176 dir = this.document.getById( 'cke_' + this.id ).getAttribute( 'dir' );
\r
178 // Delegate key processing to block.
\r
179 if ( this._.onKeyDown && this._.onKeyDown( keystroke ) === false )
\r
181 evt.data.preventDefault();
\r
185 // ESC/ARROW-LEFT(ltr) OR ARROW-RIGHT(rtl)
\r
186 if ( keystroke == 27 || keystroke == ( dir == 'rtl' ? 39 : 37 ) )
\r
188 if ( this.onEscape && this.onEscape( keystroke ) === false )
\r
189 evt.data.preventDefault( );
\r
194 holder = doc.getBody();
\r
195 holder.unselectable();
\r
198 holder = this.document.getById( 'cke_' + this.id );
\r
200 this._.holder = holder;
\r
206 addBlock : function( name, block )
\r
208 block = this._.blocks[ name ] = block instanceof CKEDITOR.ui.panel.block ? block
\r
209 : new CKEDITOR.ui.panel.block( this.getHolderElement(), block );
\r
211 if ( !this._.currentBlock )
\r
212 this.showBlock( name );
\r
217 getBlock : function( name )
\r
219 return this._.blocks[ name ];
\r
222 showBlock : function( name )
\r
224 var blocks = this._.blocks,
\r
225 block = blocks[ name ],
\r
226 current = this._.currentBlock,
\r
227 holder = this.forceIFrame ?
\r
228 this.document.getById( 'cke_' + this.id + '_frame' )
\r
231 // Disable context menu for block panel.
\r
232 holder.getParent().getParent().disableContextMenu();
\r
236 // Clean up the current block's effects on holder.
\r
237 holder.removeAttributes( current.attributes );
\r
241 this._.currentBlock = block;
\r
243 holder.setAttributes( block.attributes );
\r
244 CKEDITOR.fire( 'ariaWidget', holder );
\r
246 // Reset the focus index, so it will always go into the first one.
\r
247 block._.focusIndex = -1;
\r
249 this._.onKeyDown = block.onKeyDown && CKEDITOR.tools.bind( block.onKeyDown, block );
\r
251 block.onMark = function( item )
\r
253 holder.setAttribute( 'aria-activedescendant', item.getId() + '_option' );
\r
256 block.onUnmark = function()
\r
258 holder.removeAttribute( 'aria-activedescendant' );
\r
266 destroy : function()
\r
268 this.element && this.element.remove();
\r
272 CKEDITOR.ui.panel.block = CKEDITOR.tools.createClass(
\r
274 $ : function( blockHolder, blockDefinition )
\r
276 this.element = blockHolder.append(
\r
277 blockHolder.getDocument().createElement( 'div',
\r
282 'class' : 'cke_panel_block',
\r
283 'role' : 'presentation'
\r
291 // Copy all definition properties to this object.
\r
292 if ( blockDefinition )
\r
293 CKEDITOR.tools.extend( this, blockDefinition );
\r
295 if ( !this.attributes.title )
\r
296 this.attributes.title = this.attributes[ 'aria-label' ];
\r
300 this._.focusIndex = -1;
\r
302 // Disable context menu for panels.
\r
303 this.element.disableContextMenu();
\r
309 * Mark the item specified by the index as current activated.
\r
311 markItem: function( index )
\r
315 var links = this.element.getElementsByTag( 'a' );
\r
316 var item = links.getItem( this._.focusIndex = index );
\r
318 // Safari need focus on the iframe window first(#3389), but we need
\r
319 // lock the blur to avoid hiding the panel.
\r
320 if ( CKEDITOR.env.webkit )
\r
321 item.getDocument().getWindow().focus();
\r
324 this.onMark && this.onMark( item );
\r
332 this.element.setStyle( 'display', '' );
\r
337 if ( !this.onHide || this.onHide.call( this ) !== true )
\r
338 this.element.setStyle( 'display', 'none' );
\r
341 onKeyDown : function( keystroke )
\r
343 var keyAction = this.keys[ keystroke ];
\r
344 switch ( keyAction )
\r
348 var index = this._.focusIndex,
\r
349 links = this.element.getElementsByTag( 'a' ),
\r
352 while ( ( link = links.getItem( ++index ) ) )
\r
354 // Move the focus only if the element is marked with
\r
355 // the _cke_focus and it it's visible (check if it has
\r
357 if ( link.getAttribute( '_cke_focus' ) && link.$.offsetWidth )
\r
359 this._.focusIndex = index;
\r
368 index = this._.focusIndex;
\r
369 links = this.element.getElementsByTag( 'a' );
\r
371 while ( index > 0 && ( link = links.getItem( --index ) ) )
\r
373 // Move the focus only if the element is marked with
\r
374 // the _cke_focus and it it's visible (check if it has
\r
376 if ( link.getAttribute( '_cke_focus' ) && link.$.offsetWidth )
\r
378 this._.focusIndex = index;
\r
386 index = this._.focusIndex;
\r
387 link = index >= 0 && this.element.getElementsByTag( 'a' ).getItem( index );
\r
390 link.$.click ? link.$.click() : link.$.onclick();
\r