1 /*
  2 Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
  3 For licensing, see LICENSE.html or http://ckeditor.com/license
  4 */
  5 
  6 /**
  7  * @fileOverview The "sourcearea" plugin. It registers the "source" editing
  8  *		mode, which displays the raw data being edited in the editor.
  9  */
 10 
 11 CKEDITOR.plugins.add( 'sourcearea',
 12 {
 13 	requires : [ 'editingblock' ],
 14 
 15 	init : function( editor )
 16 	{
 17 		var sourcearea = CKEDITOR.plugins.sourcearea,
 18 			win = CKEDITOR.document.getWindow();
 19 
 20 		editor.on( 'editingBlockReady', function()
 21 			{
 22 				var textarea,
 23 					onResize;
 24 
 25 				editor.addMode( 'source',
 26 					{
 27 						load : function( holderElement, data )
 28 						{
 29 							if ( CKEDITOR.env.ie && CKEDITOR.env.version < 8 )
 30 								holderElement.setStyle( 'position', 'relative' );
 31 
 32 							// Create the source area <textarea>.
 33 							editor.textarea = textarea = new CKEDITOR.dom.element( 'textarea' );
 34 							textarea.setAttributes(
 35 								{
 36 									dir : 'ltr',
 37 									tabIndex : CKEDITOR.env.webkit ? -1 : editor.tabIndex,
 38 									'role' : 'textbox',
 39 									'aria-label' : editor.lang.editorTitle.replace( '%1', editor.name )
 40 								});
 41 							textarea.addClass( 'cke_source' );
 42 							textarea.addClass( 'cke_enable_context_menu' );
 43 
 44 							editor.readOnly && textarea.setAttribute( 'readOnly', 'readonly' );
 45 
 46 							var styles =
 47 							{
 48 								// IE7 has overflow the <textarea> from wrapping table cell.
 49 								width	: CKEDITOR.env.ie7Compat ?  '99%' : '100%',
 50 								height	: '100%',
 51 								resize	: 'none',
 52 								outline	: 'none',
 53 								'text-align' : 'left'
 54 							};
 55 
 56 							// Having to make <textarea> fixed sized to conque the following bugs:
 57 							// 1. The textarea height/width='100%' doesn't constraint to the 'td' in IE6/7.
 58 							// 2. Unexpected vertical-scrolling behavior happens whenever focus is moving out of editor
 59 							// if text content within it has overflowed. (#4762)
 60 							if ( CKEDITOR.env.ie )
 61 							{
 62 								onResize = function()
 63 								{
 64 									// Holder rectange size is stretched by textarea,
 65 									// so hide it just for a moment.
 66 									textarea.hide();
 67 									textarea.setStyle( 'height', holderElement.$.clientHeight + 'px' );
 68 									textarea.setStyle( 'width', holderElement.$.clientWidth + 'px' );
 69 									// When we have proper holder size, show textarea again.
 70 									textarea.show();
 71 								};
 72 
 73 								editor.on( 'resize', onResize );
 74 								win.on( 'resize', onResize );
 75 								setTimeout( onResize, 0 );
 76 							}
 77 
 78 							// Reset the holder element and append the
 79 							// <textarea> to it.
 80 							holderElement.setHtml( '' );
 81 							holderElement.append( textarea );
 82 							textarea.setStyles( styles );
 83 
 84 							editor.fire( 'ariaWidget', textarea );
 85 
 86 							textarea.on( 'blur', function()
 87 								{
 88 									editor.focusManager.blur();
 89 								});
 90 
 91 							textarea.on( 'focus', function()
 92 								{
 93 									editor.focusManager.focus();
 94 								});
 95 
 96 							// The editor data "may be dirty" after this point.
 97 							editor.mayBeDirty = true;
 98 
 99 							// Set the <textarea> value.
100 							this.loadData( data );
101 
102 							var keystrokeHandler = editor.keystrokeHandler;
103 							if ( keystrokeHandler )
104 								keystrokeHandler.attach( textarea );
105 
106 							setTimeout( function()
107 							{
108 								editor.mode = 'source';
109 								editor.fire( 'mode', { previousMode : editor._.previousMode } );
110 							},
111 							( CKEDITOR.env.gecko || CKEDITOR.env.webkit ) ? 100 : 0 );
112 						},
113 
114 						loadData : function( data )
115 						{
116 							textarea.setValue( data );
117 							editor.fire( 'dataReady' );
118 						},
119 
120 						getData : function()
121 						{
122 							return textarea.getValue();
123 						},
124 
125 						getSnapshotData : function()
126 						{
127 							return textarea.getValue();
128 						},
129 
130 						unload : function( holderElement )
131 						{
132 							textarea.clearCustomData();
133 							editor.textarea = textarea = null;
134 
135 							if ( onResize )
136 							{
137 								editor.removeListener( 'resize', onResize );
138 								win.removeListener( 'resize', onResize );
139 							}
140 
141 							if ( CKEDITOR.env.ie && CKEDITOR.env.version < 8 )
142 								holderElement.removeStyle( 'position' );
143 						},
144 
145 						focus : function()
146 						{
147 							textarea.focus();
148 						}
149 					});
150 			});
151 
152 		editor.on( 'readOnly', function()
153 			{
154 				if ( editor.mode == 'source' )
155 				{
156 					if ( editor.readOnly )
157 						editor.textarea.setAttribute( 'readOnly', 'readonly' );
158 					else
159 						editor.textarea.removeAttribute( 'readOnly' );
160 				}
161 			});
162 
163 		editor.addCommand( 'source', sourcearea.commands.source );
164 
165 		if ( editor.ui.addButton )
166 		{
167 			editor.ui.addButton( 'Source',
168 				{
169 					label : editor.lang.source,
170 					command : 'source'
171 				});
172 		}
173 
174 		editor.on( 'mode', function()
175 			{
176 				editor.getCommand( 'source' ).setState(
177 					editor.mode == 'source' ?
178 						CKEDITOR.TRISTATE_ON :
179 						CKEDITOR.TRISTATE_OFF );
180 			});
181 	}
182 });
183 
184 /**
185  * Holds the definition of commands an UI elements included with the sourcearea
186  * plugin.
187  * @example
188  */
189 CKEDITOR.plugins.sourcearea =
190 {
191 	commands :
192 	{
193 		source :
194 		{
195 			modes : { wysiwyg:1, source:1 },
196 			editorFocus : false,
197 			readOnly : 1,
198 			exec : function( editor )
199 			{
200 				if ( editor.mode == 'wysiwyg' )
201 					editor.fire( 'saveSnapshot' );
202 				editor.getCommand( 'source' ).setState( CKEDITOR.TRISTATE_DISABLED );
203 				editor.setMode( editor.mode == 'source' ? 'wysiwyg' : 'source' );
204 			},
205 
206 			canUndo : false
207 		}
208 	}
209 };
210