JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
9489cc81d1ed8985db5e5e6d7c6de16f2403da95
[ckeditor.git] / _source / plugins / panel / plugin.js
1 /*\r
2 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.\r
3 For licensing, see LICENSE.html or http://ckeditor.com/license\r
4 */\r
5 \r
6 CKEDITOR.plugins.add( 'panel',\r
7 {\r
8         beforeInit : function( editor )\r
9         {\r
10                 editor.ui.addHandler( CKEDITOR.UI_PANEL, CKEDITOR.ui.panel.handler );\r
11         }\r
12 });\r
13 \r
14 /**\r
15  * Panel UI element.\r
16  * @constant\r
17  * @example\r
18  */\r
19 CKEDITOR.UI_PANEL = 2;\r
20 \r
21 CKEDITOR.ui.panel = function( document, definition )\r
22 {\r
23         // Copy all definition properties to this object.\r
24         if ( definition )\r
25                 CKEDITOR.tools.extend( this, definition );\r
26 \r
27         // Set defaults.\r
28         CKEDITOR.tools.extend( this,\r
29                 {\r
30                         className : '',\r
31                         css : []\r
32                 });\r
33 \r
34         this.id = CKEDITOR.tools.getNextNumber();\r
35         this.document = document;\r
36 \r
37         this._ =\r
38         {\r
39                 blocks : {}\r
40         };\r
41 };\r
42 \r
43 /**\r
44  * Transforms a rich combo definition in a {@link CKEDITOR.ui.richCombo}\r
45  * instance.\r
46  * @type Object\r
47  * @example\r
48  */\r
49 CKEDITOR.ui.panel.handler =\r
50 {\r
51         create : function( definition )\r
52         {\r
53                 return new CKEDITOR.ui.panel( definition );\r
54         }\r
55 };\r
56 \r
57 CKEDITOR.ui.panel.prototype =\r
58 {\r
59         renderHtml : function( editor )\r
60         {\r
61                 var output = [];\r
62                 this.render( editor, output );\r
63                 return output.join( '' );\r
64         },\r
65 \r
66         /**\r
67          * Renders the combo.\r
68          * @param {CKEDITOR.editor} editor The editor instance which this button is\r
69          *              to be used by.\r
70          * @param {Array} output The output array to which append the HTML relative\r
71          *              to this button.\r
72          * @example\r
73          */\r
74         render : function( editor, output )\r
75         {\r
76                 var id = 'cke_' + this.id;\r
77 \r
78                 output.push(\r
79                         '<div class="', editor.skinClass ,'"' +\r
80                                 ' lang="', editor.langCode, '"' +\r
81                                 // iframe loading need sometime, keep the panel hidden(#4186).\r
82                                 ' style="display:none;z-index:' + ( editor.config.baseFloatZIndex + 1 ) + '">' +\r
83                                 '<div' +\r
84                                         ' id=', id,\r
85                                         ' dir=', editor.lang.dir,\r
86                                         ' class="cke_panel cke_', editor.lang.dir );\r
87 \r
88                 if ( this.className )\r
89                         output.push( ' ', this.className );\r
90 \r
91                 output.push(\r
92                                 '">' );\r
93 \r
94                 if ( this.forceIFrame || this.css.length )\r
95                 {\r
96                         output.push(\r
97                                                 '<iframe id="', id, '_frame"' +\r
98                                                         ' frameborder="0"' +\r
99                                                         ' src="javascript:void(' );\r
100 \r
101                         output.push(\r
102                                                         // Support for custom document.domain in IE.\r
103                                                         CKEDITOR.env.isCustomDomain() ?\r
104                                                                 '(function(){' +\r
105                                                                         'document.open();' +\r
106                                                                         'document.domain=\'' + document.domain + '\';' +\r
107                                                                         'document.close();' +\r
108                                                                 '})()'\r
109                                                         :\r
110                                                                 '0' );\r
111 \r
112                         output.push(\r
113                                                 ')"></iframe>' );\r
114                 }\r
115 \r
116                 output.push(\r
117                                 '</div>' +\r
118                         '</div>' );\r
119 \r
120                 return id;\r
121         },\r
122 \r
123         getHolderElement : function()\r
124         {\r
125                 var holder = this._.holder;\r
126 \r
127                 if ( !holder )\r
128                 {\r
129                         if ( this.forceIFrame || this.css.length )\r
130                         {\r
131                                 var iframe = this.document.getById( 'cke_' + this.id + '_frame' ),\r
132                                         parentDiv = iframe.getParent(),\r
133                                         dir = parentDiv.getAttribute( 'dir' ),\r
134                                         className = parentDiv.getParent().getAttribute( 'class' ),\r
135                                         langCode = parentDiv.getParent().getAttribute( 'lang' ),\r
136                                         doc = iframe.getFrameDocument();\r
137                                 // Initialize the IFRAME document body.\r
138                                 doc.$.open();\r
139 \r
140                                 // Support for custom document.domain in IE.\r
141                                 if ( CKEDITOR.env.isCustomDomain() )\r
142                                         doc.$.domain = document.domain;\r
143 \r
144                                 var onLoad = CKEDITOR.tools.addFunction( CKEDITOR.tools.bind( function( ev )\r
145                                         {\r
146                                                 this.isLoaded = true;\r
147                                                 if ( this.onLoad )\r
148                                                         this.onLoad();\r
149                                         }, this ) );\r
150 \r
151                                 doc.$.write(\r
152                                         '<!DOCTYPE html>' +\r
153                                         '<html dir="' + dir + '" class="' + className + '_container" lang="' + langCode + '">' +\r
154                                                 '<head>' +\r
155                                                         '<style>.' + className + '_container{visibility:hidden}</style>' +\r
156                                                 '</head>' +\r
157                                                 '<body class="cke_' + dir + ' cke_panel_frame ' + CKEDITOR.env.cssClass + '" style="margin:0;padding:0"' +\r
158                                                 ' onload="( window.CKEDITOR || window.parent.CKEDITOR ).tools.callFunction(' + onLoad + ');">' +\r
159                                                 '</body>' +\r
160                                                 // It looks strange, but for FF2, the styles must go\r
161                                                 // after <body>, so it (body) becames immediatelly\r
162                                                 // available. (#3031)\r
163                                                 '<link type="text/css" rel=stylesheet href="' + this.css.join( '"><link type="text/css" rel="stylesheet" href="' ) + '">' +\r
164                                         '<\/html>' );\r
165                                 doc.$.close();\r
166 \r
167                                 var win = doc.getWindow();\r
168 \r
169                                 // Register the CKEDITOR global.\r
170                                 win.$.CKEDITOR = CKEDITOR;\r
171 \r
172                                 doc.on( 'keydown', function( evt )\r
173                                         {\r
174                                                 var keystroke = evt.data.getKeystroke();\r
175 \r
176                                                 // Delegate key processing to block.\r
177                                                 if ( this._.onKeyDown && this._.onKeyDown( keystroke ) === false )\r
178                                                 {\r
179                                                         evt.data.preventDefault();\r
180                                                         return;\r
181                                                 }\r
182 \r
183                                                 if ( keystroke == 27 )          // ESC\r
184                                                         this.onEscape && this.onEscape();\r
185                                         },\r
186                                         this );\r
187 \r
188                                 holder = doc.getBody();\r
189                         }\r
190                         else\r
191                                 holder = this.document.getById( 'cke_' + this.id );\r
192 \r
193                         this._.holder = holder;\r
194                 }\r
195 \r
196                 return holder;\r
197         },\r
198 \r
199         addBlock : function( name, block )\r
200         {\r
201                 block = this._.blocks[ name ] = block || new CKEDITOR.ui.panel.block( this.getHolderElement() );\r
202 \r
203                 if ( !this._.currentBlock )\r
204                         this.showBlock( name );\r
205 \r
206                 return block;\r
207         },\r
208 \r
209         getBlock : function( name )\r
210         {\r
211                 return this._.blocks[ name ];\r
212         },\r
213 \r
214         showBlock : function( name )\r
215         {\r
216                 var blocks = this._.blocks,\r
217                         block = blocks[ name ],\r
218                         current = this._.currentBlock;\r
219 \r
220                 if ( current )\r
221                         current.hide();\r
222 \r
223                 this._.currentBlock = block;\r
224 \r
225                 // Reset the focus index, so it will always go into the first one.\r
226                 block._.focusIndex = -1;\r
227 \r
228                 this._.onKeyDown = block.onKeyDown && CKEDITOR.tools.bind( block.onKeyDown, block );\r
229 \r
230                 block.show();\r
231 \r
232                 return block;\r
233         },\r
234 \r
235         destroy : function()\r
236         {\r
237                 this.element && this.element.remove();\r
238         }\r
239 };\r
240 \r
241 CKEDITOR.ui.panel.block = CKEDITOR.tools.createClass(\r
242 {\r
243         $ : function( blockHolder )\r
244         {\r
245                 this.element = blockHolder.append(\r
246                         blockHolder.getDocument().createElement( 'div',\r
247                                 {\r
248                                         attributes :\r
249                                         {\r
250                                                 'class' : 'cke_panel_block'\r
251                                         },\r
252                                         styles :\r
253                                         {\r
254                                                 display : 'none'\r
255                                         }\r
256                                 }) );\r
257 \r
258                 this.keys = {};\r
259 \r
260                 this._.focusIndex = -1;\r
261 \r
262                 // Disable context menu for panels.\r
263                 this.element.disableContextMenu();\r
264         },\r
265 \r
266         _ : {},\r
267 \r
268         proto :\r
269         {\r
270                 show : function()\r
271                 {\r
272                         this.element.setStyle( 'display', '' );\r
273                 },\r
274 \r
275                 hide : function()\r
276                 {\r
277                         if ( !this.onHide || this.onHide.call( this )  !== true )\r
278                                 this.element.setStyle( 'display', 'none' );\r
279                 },\r
280 \r
281                 onKeyDown : function( keystroke )\r
282                 {\r
283                         var keyAction = this.keys[ keystroke ];\r
284                         switch ( keyAction )\r
285                         {\r
286                                 // Move forward.\r
287                                 case 'next' :\r
288                                         var index = this._.focusIndex,\r
289                                                 links = this.element.getElementsByTag( 'a' ),\r
290                                                 link;\r
291 \r
292                                         while ( ( link = links.getItem( ++index ) ) )\r
293                                         {\r
294                                                 // Move the focus only if the element is marked with\r
295                                                 // the _cke_focus and it it's visible (check if it has\r
296                                                 // width).\r
297                                                 if ( link.getAttribute( '_cke_focus' ) && link.$.offsetWidth )\r
298                                                 {\r
299                                                         this._.focusIndex = index;\r
300                                                         link.focus();\r
301                                                         break;\r
302                                                 }\r
303                                         }\r
304                                         return false;\r
305 \r
306                                 // Move backward.\r
307                                 case 'prev' :\r
308                                         index = this._.focusIndex;\r
309                                         links = this.element.getElementsByTag( 'a' );\r
310 \r
311                                         while ( index > 0 && ( link = links.getItem( --index ) ) )\r
312                                         {\r
313                                                 // Move the focus only if the element is marked with\r
314                                                 // the _cke_focus and it it's visible (check if it has\r
315                                                 // width).\r
316                                                 if ( link.getAttribute( '_cke_focus' ) && link.$.offsetWidth )\r
317                                                 {\r
318                                                         this._.focusIndex = index;\r
319                                                         link.focus();\r
320                                                         break;\r
321                                                 }\r
322                                         }\r
323                                         return false;\r
324 \r
325                                 case 'click' :\r
326                                         index = this._.focusIndex;\r
327                                         link = index >= 0 && this.element.getElementsByTag( 'a' ).getItem( index );\r
328 \r
329                                         if ( link )\r
330                                                 link.$.click ? link.$.click() : link.$.onclick();\r
331 \r
332                                         return false;\r
333                         }\r
334 \r
335                         return true;\r
336                 }\r
337         }\r
338 });\r