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 (function() 7 { 8 function protectFormStyles( formElement ) 9 { 10 if ( !formElement || formElement.type != CKEDITOR.NODE_ELEMENT || formElement.getName() != 'form' ) 11 return []; 12 13 var hijackRecord = []; 14 var hijackNames = [ 'style', 'className' ]; 15 for ( var i = 0 ; i < hijackNames.length ; i++ ) 16 { 17 var name = hijackNames[i]; 18 var $node = formElement.$.elements.namedItem( name ); 19 if ( $node ) 20 { 21 var hijackNode = new CKEDITOR.dom.element( $node ); 22 hijackRecord.push( [ hijackNode, hijackNode.nextSibling ] ); 23 hijackNode.remove(); 24 } 25 } 26 27 return hijackRecord; 28 } 29 30 function restoreFormStyles( formElement, hijackRecord ) 31 { 32 if ( !formElement || formElement.type != CKEDITOR.NODE_ELEMENT || formElement.getName() != 'form' ) 33 return; 34 35 if ( hijackRecord.length > 0 ) 36 { 37 for ( var i = hijackRecord.length - 1 ; i >= 0 ; i-- ) 38 { 39 var node = hijackRecord[i][0]; 40 var sibling = hijackRecord[i][1]; 41 if ( sibling ) 42 node.insertBefore( sibling ); 43 else 44 node.appendTo( formElement ); 45 } 46 } 47 } 48 49 function saveStyles( element, isInsideEditor ) 50 { 51 var data = protectFormStyles( element ); 52 var retval = {}; 53 54 var $element = element.$; 55 56 if ( !isInsideEditor ) 57 { 58 retval[ 'class' ] = $element.className || ''; 59 $element.className = ''; 60 } 61 62 retval.inline = $element.style.cssText || ''; 63 if ( !isInsideEditor ) // Reset any external styles that might interfere. (#2474) 64 $element.style.cssText = 'position: static; overflow: visible'; 65 66 restoreFormStyles( data ); 67 return retval; 68 } 69 70 function restoreStyles( element, savedStyles ) 71 { 72 var data = protectFormStyles( element ); 73 var $element = element.$; 74 if ( 'class' in savedStyles ) 75 $element.className = savedStyles[ 'class' ]; 76 if ( 'inline' in savedStyles ) 77 $element.style.cssText = savedStyles.inline; 78 restoreFormStyles( data ); 79 } 80 81 function getResizeHandler( mainWindow, editor ) 82 { 83 return function() 84 { 85 var viewPaneSize = mainWindow.getViewPaneSize(); 86 editor.resize( viewPaneSize.width, viewPaneSize.height, null, true ); 87 }; 88 } 89 90 CKEDITOR.plugins.add( 'maximize', 91 { 92 init : function( editor ) 93 { 94 var lang = editor.lang; 95 var mainDocument = CKEDITOR.document; 96 var mainWindow = mainDocument.getWindow(); 97 98 // Saved selection and scroll position for the editing area. 99 var savedSelection; 100 var savedScroll; 101 102 // Saved scroll position for the outer window. 103 var outerScroll; 104 105 // Saved resize handler function. 106 var resizeHandler = getResizeHandler( mainWindow, editor ); 107 108 // Retain state after mode switches. 109 var savedState = CKEDITOR.TRISTATE_OFF; 110 111 editor.addCommand( 'maximize', 112 { 113 modes : { wysiwyg : 1, source : 1 }, 114 115 exec : function() 116 { 117 var container = editor.container.getChild( [ 0, 0 ] ); 118 var contents = editor.getThemeSpace( 'contents' ); 119 120 // Save current selection and scroll position in editing area. 121 if ( editor.mode == 'wysiwyg' ) 122 { 123 savedSelection = editor.getSelection().getRanges(); 124 savedScroll = mainWindow.getScrollPosition(); 125 } 126 else 127 { 128 var $textarea = editor.textarea.$; 129 savedSelection = !CKEDITOR.env.ie && [ $textarea.selectionStart, $textarea.selectionEnd ]; 130 savedScroll = [ $textarea.scrollLeft, $textarea.scrollTop ]; 131 } 132 133 if ( this.state == CKEDITOR.TRISTATE_OFF ) // Go fullscreen if the state is off. 134 { 135 // Add event handler for resizing. 136 mainWindow.on( 'resize', resizeHandler ); 137 138 // Save the scroll bar position. 139 outerScroll = mainWindow.getScrollPosition(); 140 141 // Save and reset the styles for the entire node tree. 142 var currentNode = editor.container; 143 while ( ( currentNode = currentNode.getParent() ) ) 144 { 145 currentNode.setCustomData( 'maximize_saved_styles', saveStyles( currentNode ) ); 146 currentNode.setStyle( 'z-index', editor.config.baseFloatZIndex - 1 ); 147 } 148 contents.setCustomData( 'maximize_saved_styles', saveStyles( contents, true ) ); 149 container.setCustomData( 'maximize_saved_styles', saveStyles( container, true ) ); 150 151 // Hide scroll bars. 152 if ( CKEDITOR.env.ie ) 153 { 154 mainDocument.$.documentElement.style.overflow = 155 mainDocument.getBody().$.style.overflow = 'hidden'; 156 } 157 else 158 { 159 mainDocument.getBody().setStyles( 160 { 161 overflow : 'hidden', 162 width : '0px', 163 height : '0px' 164 } ); 165 } 166 167 // Scroll to the top left. 168 mainWindow.$.scrollTo( 0, 0 ); 169 170 // Resize and move to top left. 171 var viewPaneSize = mainWindow.getViewPaneSize(); 172 container.setStyle( 'position', 'absolute' ); 173 container.$.offsetLeft; // SAFARI BUG: See #2066. 174 container.setStyles( 175 { 176 'z-index' : editor.config.baseFloatZIndex - 1, 177 left : '0px', 178 top : '0px' 179 } ); 180 editor.resize( viewPaneSize.width, viewPaneSize.height, null, true ); 181 182 // Still not top left? Fix it. (Bug #174) 183 var offset = container.getDocumentPosition(); 184 container.setStyles( 185 { 186 left : ( -1 * offset.x ) + 'px', 187 top : ( -1 * offset.y ) + 'px' 188 } ); 189 190 // Add cke_maximized class. 191 container.addClass( 'cke_maximized' ); 192 } 193 else if ( this.state == CKEDITOR.TRISTATE_ON ) // Restore from fullscreen if the state is on. 194 { 195 // Remove event handler for resizing. 196 mainWindow.removeListener( 'resize', resizeHandler ); 197 198 // Restore CSS styles for the entire node tree. 199 var editorElements = [ contents, container ]; 200 for ( var i = 0 ; i < editorElements.length ; i++ ) 201 { 202 restoreStyles( editorElements[i], editorElements[i].getCustomData( 'maximize_saved_styles' ) ); 203 editorElements[i].removeCustomData( 'maximize_saved_styles' ); 204 } 205 206 currentNode = editor.container; 207 while ( ( currentNode = currentNode.getParent() ) ) 208 { 209 restoreStyles( currentNode, currentNode.getCustomData( 'maximize_saved_styles' ) ); 210 currentNode.removeCustomData( 'maximize_saved_styles' ); 211 } 212 213 // Restore the window scroll position. 214 mainWindow.$.scrollTo( outerScroll.x, outerScroll.y ); 215 216 // Remove cke_maximized class. 217 container.removeClass( 'cke_maximized' ); 218 219 // Emit a resize event, because this time the size is modified in 220 // restoreStyles. 221 editor.fire( 'resize' ); 222 } 223 224 this.toggleState(); 225 226 // Restore selection and scroll position in editing area. 227 if ( editor.mode == 'wysiwyg' ) 228 { 229 editor.getSelection().selectRanges( savedSelection ); 230 231 var element = editor.getSelection().getStartElement(); 232 if ( element ) 233 element.scrollIntoView( true ); 234 else 235 mainWindow.$.scrollTo( savedScroll.x, savedScroll.y ); 236 } 237 else 238 { 239 if ( savedSelection ) 240 { 241 $textarea.selectionStart = savedSelection[0]; 242 $textarea.selectionEnd = savedSelection[1]; 243 } 244 $textarea.scrollLeft = savedScroll[0]; 245 $textarea.scrollTop = savedScroll[1]; 246 } 247 248 savedSelection = savedScroll = null; 249 savedState = this.state; 250 }, 251 canUndo : false 252 } ); 253 254 editor.ui.addButton( 'Maximize', 255 { 256 label : lang.maximize, 257 command : 'maximize' 258 } ); 259 260 // Restore the command state after mode change. 261 editor.on( 'mode', function() 262 { 263 editor.getCommand( 'maximize' ).setState( savedState ); 264 }, null, null, 100 ); 265 } 266 } ); 267 })(); 268