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
= 'panel';
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
;
384 index
= this._
.focusIndex
;
385 link
= index
>= 0 && this.element
.getElementsByTag( 'a' ).getItem( index
);
388 link
.$[ keyAction
] ? link
.$[ keyAction
]() : link
.$[ 'on' + keyAction
]();
399 * Fired when a panel is added to the document
400 * @name CKEDITOR#ariaWidget
402 * @param {Object} holder The element wrapping the panel