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 ' lang="', editor.langCode, '"' + 81 ' style="z-index:' + ( editor.config.baseFloatZIndex + 1 ) + '">' + 82 '<div' + 83 ' id=', id, 84 ' dir=', editor.lang.dir, 85 ' class="cke_panel cke_', editor.lang.dir ); 86 87 if ( this.className ) 88 output.push( ' ', this.className ); 89 90 output.push( 91 '">' ); 92 93 if ( this.forceIFrame || this.css.length ) 94 { 95 output.push( 96 '<iframe id="', id, '_frame"' + 97 ' frameborder="0"' + 98 ' src="javascript:void(' ); 99 100 output.push( 101 // Support for custom document.domain in IE. 102 CKEDITOR.env.isCustomDomain() ? 103 '(function(){' + 104 'document.open();' + 105 'document.domain=\'' + document.domain + '\';' + 106 'document.close();' + 107 '})()' 108 : 109 '0' ); 110 111 output.push( 112 ')"></iframe>' ); 113 } 114 115 output.push( 116 '</div>' + 117 '</div>' ); 118 119 return id; 120 }, 121 122 getHolderElement : function() 123 { 124 var holder = this._.holder; 125 126 if ( !holder ) 127 { 128 if ( this.forceIFrame || this.css.length ) 129 { 130 var iframe = this.document.getById( 'cke_' + this.id + '_frame' ), 131 parentDiv = iframe.getParent(), 132 dir = parentDiv.getAttribute( 'dir' ), 133 className = parentDiv.getParent().getAttribute( 'class' ), 134 langCode = parentDiv.getParent().getAttribute( 'lang' ), 135 doc = iframe.getFrameDocument(); 136 137 // Initialize the IFRAME document body. 138 doc.$.open(); 139 140 // Support for custom document.domain in IE. 141 if ( CKEDITOR.env.isCustomDomain() ) 142 doc.$.domain = document.domain; 143 144 doc.$.write( 145 '<!DOCTYPE html>' + 146 '<html dir="' + dir + '" class="' + className + '_container" lang="' + langCode + '">' + 147 '<head>' + 148 '<style>.' + className + '_container{visibility:hidden}</style>' + 149 '</head>' + 150 '<body class="cke_' + dir + ' cke_panel_frame ' + CKEDITOR.env.cssClass + '" style="margin:0;padding:0">' + 151 '</body>' + 152 // It looks strange, but for FF2, the styles must go 153 // after <body>, so it (body) becames immediatelly 154 // available. (#3031) 155 '<link type="text/css" rel=stylesheet href="' + this.css.join( '"><link type="text/css" rel="stylesheet" href="' ) + '">' + 156 '<\/html>' ); 157 doc.$.close(); 158 159 var win = doc.getWindow(); 160 161 // Register the CKEDITOR global. 162 win.$.CKEDITOR = CKEDITOR; 163 164 win.on( 'load', function( ev ) 165 { 166 this.isLoaded = true; 167 if ( this.onLoad ) 168 this.onLoad(); 169 }, 170 this); 171 172 doc.on( 'keydown', function( evt ) 173 { 174 var keystroke = evt.data.getKeystroke(); 175 176 // Delegate key processing to block. 177 if ( this._.onKeyDown && this._.onKeyDown( keystroke ) === false ) 178 { 179 evt.data.preventDefault(); 180 return; 181 } 182 183 if ( keystroke == 27 ) // ESC 184 this.onEscape && this.onEscape(); 185 }, 186 this ); 187 188 holder = doc.getBody(); 189 } 190 else 191 holder = this.document.getById( 'cke_' + this.id ); 192 193 this._.holder = holder; 194 } 195 196 return holder; 197 }, 198 199 addBlock : function( name, block ) 200 { 201 block = this._.blocks[ name ] = block || new CKEDITOR.ui.panel.block( this.getHolderElement() ); 202 203 if ( !this._.currentBlock ) 204 this.showBlock( name ); 205 206 return block; 207 }, 208 209 getBlock : function( name ) 210 { 211 return this._.blocks[ name ]; 212 }, 213 214 showBlock : function( name ) 215 { 216 var blocks = this._.blocks, 217 block = blocks[ name ], 218 current = this._.currentBlock; 219 220 if ( current ) 221 current.hide(); 222 223 this._.currentBlock = block; 224 225 // Reset the focus index, so it will always go into the first one. 226 block._.focusIndex = -1; 227 228 this._.onKeyDown = block.onKeyDown && CKEDITOR.tools.bind( block.onKeyDown, block ); 229 230 block.show(); 231 232 return block; 233 } 234 }; 235 236 CKEDITOR.ui.panel.block = CKEDITOR.tools.createClass( 237 { 238 $ : function( blockHolder ) 239 { 240 this.element = blockHolder.append( 241 blockHolder.getDocument().createElement( 'div', 242 { 243 attributes : 244 { 245 'class' : 'cke_panel_block' 246 }, 247 styles : 248 { 249 display : 'none' 250 } 251 }) ); 252 253 this.keys = {}; 254 255 this._.focusIndex = -1; 256 }, 257 258 _ : {}, 259 260 proto : 261 { 262 show : function() 263 { 264 this.element.setStyle( 'display', '' ); 265 }, 266 267 hide : function() 268 { 269 if ( !this.onHide || this.onHide.call( this ) !== true ) 270 this.element.setStyle( 'display', 'none' ); 271 }, 272 273 onKeyDown : function( keystroke ) 274 { 275 var keyAction = this.keys[ keystroke ]; 276 switch ( keyAction ) 277 { 278 // Move forward. 279 case 'next' : 280 var index = this._.focusIndex, 281 links = this.element.getElementsByTag( 'a' ), 282 link; 283 284 while ( ( link = links.getItem( ++index ) ) ) 285 { 286 // Move the focus only if the element is marked with 287 // the _cke_focus and it it's visible (check if it has 288 // width). 289 if ( link.getAttribute( '_cke_focus' ) && link.$.offsetWidth ) 290 { 291 this._.focusIndex = index; 292 link.focus(); 293 break; 294 } 295 } 296 return false; 297 298 // Move backward. 299 case 'prev' : 300 index = this._.focusIndex; 301 links = this.element.getElementsByTag( 'a' ); 302 303 while ( index > 0 && ( link = links.getItem( --index ) ) ) 304 { 305 // Move the focus only if the element is marked with 306 // the _cke_focus and it it's visible (check if it has 307 // width). 308 if ( link.getAttribute( '_cke_focus' ) && link.$.offsetWidth ) 309 { 310 this._.focusIndex = index; 311 link.focus(); 312 break; 313 } 314 } 315 return false; 316 317 case 'click' : 318 index = this._.focusIndex; 319 link = index >= 0 && this.element.getElementsByTag( 'a' ).getItem( index ); 320 321 if ( link ) 322 link.$.click ? link.$.click() : link.$.onclick(); 323 324 return false; 325 } 326 327 return true; 328 } 329 } 330 }); 331