/**
 * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
 * For licensing, see LICENSE.md or http://ckeditor.com/license
 */
/**
 * @fileOverview The "wysiwygarea" plugin. It registers the "wysiwyg" editing
 *		mode, which handles the main editing area space.
 */
( function() {
	CKEDITOR.plugins.add( 'wysiwygarea', {
		init: function( editor ) {
			if ( editor.config.fullPage ) {
				editor.addFeature( {
					allowedContent: 'html head title; style [media,type]; body (*)[id]; meta link [*]',
					requiredContent: 'body'
				} );
			}
			editor.addMode( 'wysiwyg', function( callback ) {
				var src = 'document.open();' +
					// In IE, the document domain must be set any time we call document.open().
					( CKEDITOR.env.ie ? '(' + CKEDITOR.tools.fixDomain + ')();' : '' ) +
					'document.close();';
				// With IE, the custom domain has to be taken care at first,
				// for other browers, the 'src' attribute should be left empty to
				// trigger iframe's 'load' event.
				src = CKEDITOR.env.air ? 'javascript:void(0)' : CKEDITOR.env.ie ? 'javascript:void(function(){' + encodeURIComponent( src ) + '}())'
					:
					'';
				var iframe = CKEDITOR.dom.element.createFromHtml( '' );
				iframe.setStyles( { width: '100%', height: '100%' } );
				iframe.addClass( 'cke_wysiwyg_frame cke_reset' );
				var contentSpace = editor.ui.space( 'contents' );
				contentSpace.append( iframe );
				// Asynchronous iframe loading is only required in IE>8 and Gecko (other reasons probably).
				// Do not use it on WebKit as it'll break the browser-back navigation.
				var useOnloadEvent = CKEDITOR.env.ie || CKEDITOR.env.gecko;
				if ( useOnloadEvent )
					iframe.on( 'load', onLoad );
				var frameLabel = editor.title,
					frameDesc = editor.lang.common.editorHelp;
				if ( frameLabel ) {
					if ( CKEDITOR.env.ie )
						frameLabel += ', ' + frameDesc;
					iframe.setAttribute( 'title', frameLabel );
				}
				var labelId = CKEDITOR.tools.getNextId(),
					desc = CKEDITOR.dom.element.createFromHtml( '' + frameDesc + '' );
				contentSpace.append( desc, 1 );
				// Remove the ARIA description.
				editor.on( 'beforeModeUnload', function( evt ) {
					evt.removeListener();
					desc.remove();
				} );
				iframe.setAttributes( {
					'aria-describedby': labelId,
					tabIndex: editor.tabIndex,
					allowTransparency: 'true'
				} );
				// Execute onLoad manually for all non IE||Gecko browsers.
				!useOnloadEvent && onLoad();
				if ( CKEDITOR.env.webkit ) {
					// Webkit: iframe size doesn't auto fit well. (#7360)
					var onResize = function() {
						// Hide the iframe to get real size of the holder. (#8941)
						contentSpace.setStyle( 'width', '100%' );
						iframe.hide();
						iframe.setSize( 'width', contentSpace.getSize( 'width' ) );
						contentSpace.removeStyle( 'width' );
						iframe.show();
					};
					iframe.setCustomData( 'onResize', onResize );
					CKEDITOR.document.getWindow().on( 'resize', onResize );
				}
				editor.fire( 'ariaWidget', iframe );
				function onLoad( evt ) {
					evt && evt.removeListener();
					editor.editable( new framedWysiwyg( editor, iframe.$.contentWindow.document.body ) );
					editor.setData( editor.getData( 1 ), callback );
				}
			} );
		}
	} );
	function onDomReady( win ) {
		var editor = this.editor,
			doc = win.document,
			body = doc.body;
		// Remove helper scripts from the DOM.
		var script = doc.getElementById( 'cke_actscrpt' );
		script && script.parentNode.removeChild( script );
		script = doc.getElementById( 'cke_shimscrpt' );
		script && script.parentNode.removeChild( script );
		if ( CKEDITOR.env.gecko ) {
			// Force Gecko to change contentEditable from false to true on domReady
			// (because it's previously set to true on iframe's body creation).
			// Otherwise del/backspace and some other editable features will be broken in Fx <4
			// See: #107 and https://bugzilla.mozilla.org/show_bug.cgi?id=440916
			body.contentEditable = false;
			// Remove any leading 
 which is between the 
(?: |
)<\/p>$/i ) && range.startContainer.equals( body ) ) {
					// Avoid the ambiguity from a real user cursor position.
					setTimeout( function() {
						range = editor.getSelection().getRanges()[ 0 ];
						if ( !range.startContainer.equals( 'body' ) ) {
							body.getFirst().remove( 1 );
							range.moveToElementEditEnd( body );
							range.select();
						}
					}, 0 );
				}
			} );
		}
		// Fix problem with cursor not appearing in Webkit and IE11+ when clicking below the body (#10945, #10906).
		// Fix for older IEs (8-10 and QM) is placed inside selection.js.
		if ( CKEDITOR.env.webkit || ( CKEDITOR.env.ie && CKEDITOR.env.version > 10 ) ) {
			doc.getDocumentElement().on( 'mousedown', function( evt ) {
				if ( evt.data.getTarget().is( 'html' ) ) {
					// IE needs this timeout. Webkit does not, but it does not cause problems too.
					setTimeout( function() {
						editor.editable().focus();
					} );
				}
			} );
		}
		// ## START : disableNativeTableHandles and disableObjectResizing settings.
		// Enable dragging of position:absolute elements in IE.
		try {
			editor.document.$.execCommand( '2D-position', false, true );
		} catch ( e ) {}
		// IE, Opera and Safari may not support it and throw errors.
		try {
			editor.document.$.execCommand( 'enableInlineTableEditing', false, !editor.config.disableNativeTableHandles );
		} catch ( e ) {}
		if ( editor.config.disableObjectResizing ) {
			try {
				this.getDocument().$.execCommand( 'enableObjectResizing', false, false );
			} catch ( e ) {
				// For browsers in which the above method failed, we can cancel the resizing on the fly (#4208)
				this.attachListener( this, CKEDITOR.env.ie ? 'resizestart' : 'resize', function( evt ) {
					evt.data.preventDefault();
				} );
			}
		}
		if ( CKEDITOR.env.gecko || CKEDITOR.env.ie && editor.document.$.compatMode == 'CSS1Compat' ) {
			this.attachListener( this, 'keydown', function( evt ) {
				var keyCode = evt.data.getKeystroke();
				// PageUp OR PageDown
				if ( keyCode == 33 || keyCode == 34 ) {
					// PageUp/PageDown scrolling is broken in document
					// with standard doctype, manually fix it. (#4736)
					if ( CKEDITOR.env.ie ) {
						setTimeout( function() {
							editor.getSelection().scrollIntoView();
						}, 0 );
					}
					// Page up/down cause editor selection to leak
					// outside of editable thus we try to intercept
					// the behavior, while it affects only happen
					// when editor contents are not overflowed. (#7955)
					else if ( editor.window.$.innerHeight > this.$.offsetHeight ) {
						var range = editor.createRange();
						range[ keyCode == 33 ? 'moveToElementEditStart' : 'moveToElementEditEnd' ]( this );
						range.select();
						evt.data.preventDefault();
					}
				}
			} );
		}
		if ( CKEDITOR.env.ie ) {
			// [IE] Iframe will still keep the selection when blurred, if
			// focus is moved onto a non-editing host, e.g. link or button, but
			// it becomes a problem for the object type selection, since the resizer
			// handler attached on it will mark other part of the UI, especially
			// for the dialog. (#8157)
			// [IE<8 & Opera] Even worse For old IEs, the cursor will not vanish even if
			// the selection has been moved to another text input in some cases. (#4716)
			//
			// Now the range restore is disabled, so we simply force IE to clean
			// up the selection before blur.
			this.attachListener( doc, 'blur', function() {
				// Error proof when the editor is not visible. (#6375)
				try {
					doc.$.selection.empty();
				} catch ( er ) {}
			} );
		}
		// ## END
		var title = editor.document.getElementsByTag( 'title' ).getItem( 0 );
		title.data( 'cke-title', editor.document.$.title );
		// [IE] JAWS will not recognize the aria label we used on the iframe
		// unless the frame window title string is used as the voice label,
		// backup the original one and restore it on output.
		if ( CKEDITOR.env.ie )
			editor.document.$.title = this._.docTitle;
		CKEDITOR.tools.setTimeout( function() {
			editor.fire( 'contentDom' );
			if ( this._.isPendingFocus ) {
				editor.focus();
				this._.isPendingFocus = false;
			}
			setTimeout( function() {
				editor.fire( 'dataReady' );
			}, 0 );
			// IE BUG: IE might have rendered the iframe with invisible contents.
			// (#3623). Push some inconsequential CSS style changes to force IE to
			// refresh it.
			//
			// Also, for some unknown reasons, short timeouts (e.g. 100ms) do not
			// fix the problem. :(
			if ( CKEDITOR.env.ie ) {
				setTimeout( function() {
					if ( editor.document ) {
						var $body = editor.document.$.body;
						$body.runtimeStyle.marginBottom = '0px';
						$body.runtimeStyle.marginBottom = '';
					}
				}, 1000 );
			}
		}, 0, this );
	}
	var framedWysiwyg = CKEDITOR.tools.createClass( {
		$: function( editor ) {
			this.base.apply( this, arguments );
			this._.frameLoadedHandler = CKEDITOR.tools.addFunction( function( win ) {
				// Avoid opening design mode in a frame window thread,
				// which will cause host page scrolling.(#4397)
				CKEDITOR.tools.setTimeout( onDomReady, 0, this, win );
			}, this );
			this._.docTitle = this.getWindow().getFrame().getAttribute( 'title' );
		},
		base: CKEDITOR.editable,
		proto: {
			setData: function( data, isSnapshot ) {
				var editor = this.editor;
				if ( isSnapshot ) {
					this.setHtml( data );
					// Fire dataReady for the consistency with inline editors
					// and because it makes sense. (#10370)
					editor.fire( 'dataReady' );
				}
				else {
					this._.isLoadingData = true;
					editor._.dataStore = { id: 1 };
					var config = editor.config,
						fullPage = config.fullPage,
						docType = config.docType;
					// Build the additional stuff to be included into