/** * @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 and the comment. // This one fixes Firefox 3.6 bug: the browser inserts a leading
// on document.write if the body has contenteditable="true". if ( CKEDITOR.env.version < 20000 ) { body.innerHTML = body.innerHTML.replace( /^.*/, '' ); // The above hack messes up the selection in FF36. // To clean this up, manually select collapsed range that // starts within the body. setTimeout( function() { var range = new CKEDITOR.dom.range( new CKEDITOR.dom.document( doc ) ); range.setStart( new CKEDITOR.dom.node( body ), 0 ); editor.getSelection().selectRanges( [ range ] ); }, 0 ); } } body.contentEditable = true; if ( CKEDITOR.env.ie ) { // Don't display the focus border. body.hideFocus = true; // Disable and re-enable the body to avoid IE from // taking the editing focus at startup. (#141 / #523) body.disabled = true; body.removeAttribute( 'disabled' ); } delete this._.isLoadingData; // Play the magic to alter element reference to the reloaded one. this.$ = body; doc = new CKEDITOR.dom.document( doc ); this.setup(); if ( CKEDITOR.env.ie ) { doc.getDocumentElement().addClass( doc.$.compatMode ); // Prevent IE from leaving new paragraph after deleting all contents in body. (#6966) editor.config.enterMode != CKEDITOR.ENTER_P && this.attachListener( doc, 'selectionchange', function() { var body = doc.getBody(), sel = editor.getSelection(), range = sel && sel.getRanges()[ 0 ]; if ( range && body.getHtml().match( /^

(?: |
)<\/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 . var headExtra = CKEDITOR.tools.buildStyleHtml( iframeCssFixes() ) .replace( /