X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=_source%2Fplugins%2Fwysiwygarea%2Fplugin.js;h=d6ab1d8f209e6a4a4d49276014a3011738d847e2;hb=e73319a12b56100b29ef456fd74114fe5519e01c;hp=c71f0401677a982cbd71f9e91c00cbbe80f96a83;hpb=4e90e78dc97789709ee7404359a5517540c27553;p=ckeditor.git
diff --git a/_source/plugins/wysiwygarea/plugin.js b/_source/plugins/wysiwygarea/plugin.js
index c71f040..d6ab1d8 100644
--- a/_source/plugins/wysiwygarea/plugin.js
+++ b/_source/plugins/wysiwygarea/plugin.js
@@ -10,19 +10,15 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
(function()
{
- // List of elements in which has no way to move editing focus outside.
- var nonExitableElementNames = { table:1,pre:1 };
-
// Matching an empty paragraph at the end of document.
- var emptyParagraphRegexp = /(^|
]*>)\s*<(p|div|address|h\d|center)[^>]*>\s*(?:
]*>| |\u00A0| )?\s*(:?<\/\2>)?\s*(?=$|<\/body>)/gi;
+ var emptyParagraphRegexp = /(^|]*>)\s*<(p|div|address|h\d|center|pre)[^>]*>\s*(?:
]*>| |\u00A0| )?\s*(:?<\/\2>)?\s*(?=$|<\/body>)/gi;
var notWhitespaceEval = CKEDITOR.dom.walker.whitespaces( true );
- // Elements that could have empty new line around, including table, pre-formatted block, hr, page-break. (#6554)
- function nonExitable( element )
+ // Elements that could blink the cursor anchoring beside it, like hr, page-break. (#6554)
+ function nonEditable( element )
{
- return ( element.getName() in nonExitableElementNames )
- || element.isBlockBoundary() && CKEDITOR.dtd.$empty[ element.getName() ];
+ return element.isBlockBoundary() && CKEDITOR.dtd.$empty[ element.getName() ];
}
@@ -55,6 +51,9 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
if ( this.dataProcessor )
data = this.dataProcessor.toHtml( data );
+ if ( !data )
+ return;
+
// HTML insertion only considers the first range.
var selection = this.getSelection(),
range = selection.getRanges()[ 0 ];
@@ -62,6 +61,26 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
if ( range.checkReadOnly() )
return;
+ // Opera: force block splitting when pasted content contains block. (#7801)
+ if ( CKEDITOR.env.opera )
+ {
+ var path = new CKEDITOR.dom.elementPath( range.startContainer );
+ if ( path.block )
+ {
+ var nodes = CKEDITOR.htmlParser.fragment.fromHtml( data, false ).children;
+ for ( var i = 0, count = nodes.length; i < count; i++ )
+ {
+ if ( nodes[ i ]._.isBlockLike )
+ {
+ range.splitBlock( this.enterMode == CKEDITOR.ENTER_DIV ? 'div' : 'p' );
+ range.insertNode( range.document.createText( '' ) );
+ range.select();
+ break;
+ }
+ }
+ }
+ }
+
if ( CKEDITOR.env.ie )
{
var selIsLocked = selection.isLocked;
@@ -93,11 +112,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
}
}
- try
- {
- $sel.createRange().pasteHTML( data );
- }
- catch (e) {}
+ $sel.createRange().pasteHTML( data );
if ( selIsLocked )
this.getSelection().lock();
@@ -369,29 +384,28 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
var pathBlock = path.block || path.blockLimit,
lastNode = pathBlock && pathBlock.getLast( isNotEmpty );
- // In case it's not ended with block element and doesn't have bogus yet. (#7467)
+ // Check some specialities of the current path block:
+ // 1. It is really displayed as block; (#7221)
+ // 2. It doesn't end with one inner block; (#7467)
+ // 3. It doesn't have bogus br yet.
if ( pathBlock
+ && pathBlock.isBlockBoundary()
&& !( lastNode && lastNode.type == CKEDITOR.NODE_ELEMENT && lastNode.isBlockBoundary() )
&& !pathBlock.is( 'pre' )
&& !pathBlock.getBogus() )
{
- editor.fire( 'updateSnapshot' );
- restoreDirty( editor );
pathBlock.appendBogus();
}
}
- // When enterMode set to block, we'll establing new paragraph only if we're
- // selecting inline contents right under body. (#3657)
- if ( enterMode != CKEDITOR.ENTER_BR
- && range.collapsed
- && blockLimit.getName() == 'body'
- && !path.block )
+ // When we're in block enter mode, a new paragraph will be established
+ // to encapsulate inline contents right under body. (#3657)
+ if ( editor.config.autoParagraph !== false
+ && enterMode != CKEDITOR.ENTER_BR
+ && range.collapsed
+ && blockLimit.getName() == 'body'
+ && !path.block )
{
- editor.fire( 'updateSnapshot' );
- restoreDirty( editor );
- CKEDITOR.env.ie && restoreSelection( selection );
-
var fixedBlock = range.fixBlock( true,
editor.config.enterMode == CKEDITOR.ENTER_DIV ? 'div' : 'p' );
@@ -409,7 +423,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
var element = fixedBlock.getNext( isNotWhitespace );
if ( element &&
element.type == CKEDITOR.NODE_ELEMENT &&
- !nonExitable( element ) )
+ !nonEditable( element ) )
{
range.moveToElementEditStart( element );
fixedBlock.remove();
@@ -419,7 +433,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
element = fixedBlock.getPrevious( isNotWhitespace );
if ( element &&
element.type == CKEDITOR.NODE_ELEMENT &&
- !nonExitable( element ) )
+ !nonEditable( element ) )
{
range.moveToElementEditEnd( element );
fixedBlock.remove();
@@ -432,30 +446,17 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
evt.cancel();
}
- // All browsers are incapable to moving cursor out of certain non-exitable
- // blocks (e.g. table, list, pre) at the end of document, make this happen by
- // place a bogus node there, which would be later removed by dataprocessor.
- var walkerRange = new CKEDITOR.dom.range( editor.document ),
- walker = new CKEDITOR.dom.walker( walkerRange );
- walkerRange.selectNodeContents( body );
- walker.evaluator = function( node )
- {
- return node.type == CKEDITOR.NODE_ELEMENT && ( node.getName() in nonExitableElementNames );
- };
- walker.guard = function( node, isMoveout )
+ // Browsers are incapable of moving cursor out of certain block elements (e.g. table, div, pre)
+ // at the end of document, makes it unable to continue adding content, we have to make this
+ // easier by opening an new empty paragraph.
+ var testRange = new CKEDITOR.dom.range( editor.document );
+ testRange.moveToElementEditEnd( editor.document.getBody() );
+ var testPath = new CKEDITOR.dom.elementPath( testRange.startContainer );
+ if ( !testPath.blockLimit.is( 'body') )
{
- return !( ( node.type == CKEDITOR.NODE_TEXT && isNotWhitespace( node ) ) || isMoveout );
- };
-
- if ( walker.previous() )
- {
- editor.fire( 'updateSnapshot' );
- restoreDirty( editor );
- CKEDITOR.env.ie && restoreSelection( selection );
-
var paddingBlock;
if ( enterMode != CKEDITOR.ENTER_BR )
- paddingBlock = body.append( new CKEDITOR.dom.element( enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' ) );
+ paddingBlock = body.append( editor.document.createElement( enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' ) );
else
paddingBlock = body;
@@ -470,7 +471,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
init : function( editor )
{
- var fixForBody = ( editor.config.enterMode != CKEDITOR.ENTER_BR )
+ var fixForBody = ( editor.config.enterMode != CKEDITOR.ENTER_BR && editor.config.autoParagraph !== false )
? editor.config.enterMode == CKEDITOR.ENTER_DIV ? 'div' : 'p' : false;
var frameLabel = editor.lang.editorTitle.replace( '%1', editor.name );
@@ -544,30 +545,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
if ( document.location.protocol == 'chrome:' )
CKEDITOR.event.useCapture = false;
- // The container must be visible when creating the iframe in FF (#5956)
- var element = editor.element,
- isHidden = CKEDITOR.env.gecko && !element.isVisible(),
- previousStyles = {};
- if ( isHidden )
- {
- element.show();
- previousStyles = {
- position : element.getStyle( 'position' ),
- top : element.getStyle( 'top' )
- };
- element.setStyles( { position : 'absolute', top : '-3000px' } );
- }
-
mainElement.append( iframe );
-
- if ( isHidden )
- {
- setTimeout( function()
- {
- element.hide();
- element.setStyles( previousStyles );
- }, 1000 );
- }
};
// The script that launches the bootstrap logic on 'domReady', so the document
@@ -597,6 +575,8 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
body.spellcheck = !editor.config.disableNativeSpellChecker;
+ var editable = !editor.readOnly;
+
if ( CKEDITOR.env.ie )
{
// Don't display the focus border.
@@ -605,7 +585,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
// Disable and re-enable the body to avoid IE from
// taking the editing focus at startup. (#141 / #523)
body.disabled = true;
- body.contentEditable = true;
+ body.contentEditable = editable;
body.removeAttribute( 'disabled' );
}
else
@@ -617,20 +597,20 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
// Prefer 'contentEditable' instead of 'designMode'. (#3593)
if ( CKEDITOR.env.gecko && CKEDITOR.env.version >= 10900
|| CKEDITOR.env.opera )
- domDocument.$.body.contentEditable = true;
+ domDocument.$.body.contentEditable = editable;
else if ( CKEDITOR.env.webkit )
- domDocument.$.body.parentNode.contentEditable = true;
+ domDocument.$.body.parentNode.contentEditable = editable;
else
- domDocument.$.designMode = 'on';
+ domDocument.$.designMode = editable? 'off' : 'on';
}, 0 );
}
- CKEDITOR.env.gecko && CKEDITOR.tools.setTimeout( activateEditing, 0, null, editor );
+ editable && CKEDITOR.env.gecko && CKEDITOR.tools.setTimeout( activateEditing, 0, null, editor );
domWindow = editor.window = new CKEDITOR.dom.window( domWindow );
domDocument = editor.document = new CKEDITOR.dom.document( domDocument );
- domDocument.on( 'dblclick', function( evt )
+ editable && domDocument.on( 'dblclick', function( evt )
{
var element = evt.data.getTarget(),
data = { element : element, dialog : '' };
@@ -711,8 +691,8 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
// IE standard compliant in editing frame doesn't focus the editor when
// clicking outside actual content, manually apply the focus. (#1659)
- if ( CKEDITOR.env.ie
- && domDocument.$.compatMode == 'CSS1Compat'
+ if ( editable &&
+ CKEDITOR.env.ie && domDocument.$.compatMode == 'CSS1Compat'
|| CKEDITOR.env.gecko
|| CKEDITOR.env.opera )
{
@@ -743,7 +723,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
{
var doc = editor.document;
- if ( CKEDITOR.env.gecko && CKEDITOR.env.version >= 10900 )
+ if ( editable && CKEDITOR.env.gecko && CKEDITOR.env.version >= 10900 )
blinkCursor();
else if ( CKEDITOR.env.opera )
doc.getBody().focus();
@@ -761,83 +741,86 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
});
var keystrokeHandler = editor.keystrokeHandler;
- if ( keystrokeHandler )
- keystrokeHandler.attach( domDocument );
+ // Prevent backspace from navigating off the page.
+ keystrokeHandler.blockedKeystrokes[ 8 ] = !editable;
+ keystrokeHandler.attach( domDocument );
- if ( CKEDITOR.env.ie )
+ domDocument.getDocumentElement().addClass( domDocument.$.compatMode );
+ // Override keystroke behaviors.
+ editable && domDocument.on( 'keydown', function( evt )
{
- domDocument.getDocumentElement().addClass( domDocument.$.compatMode );
- // Override keystrokes which should have deletion behavior
- // on control types in IE . (#4047)
- domDocument.on( 'keydown', function( evt )
+ var keyCode = evt.data.getKeystroke();
+
+ // Backspace OR Delete.
+ if ( keyCode in { 8 : 1, 46 : 1 } )
{
- var keyCode = evt.data.getKeystroke();
+ var sel = editor.getSelection(),
+ selected = sel.getSelectedElement(),
+ range = sel.getRanges()[ 0 ];
- // Backspace OR Delete.
- if ( keyCode in { 8 : 1, 46 : 1 } )
+ // Override keystrokes which should have deletion behavior
+ // on fully selected element . (#4047) (#7645)
+ if ( selected )
{
- var sel = editor.getSelection(),
- control = sel.getSelectedElement();
+ // Make undo snapshot.
+ editor.fire( 'saveSnapshot' );
- if ( control )
- {
- // Make undo snapshot.
- editor.fire( 'saveSnapshot' );
-
- // Delete any element that 'hasLayout' (e.g. hr,table) in IE8 will
- // break up the selection, safely manage it here. (#4795)
- var bookmark = sel.getRanges()[ 0 ].createBookmark();
- // Remove the control manually.
- control.remove();
- sel.selectBookmarks( [ bookmark ] );
+ // Delete any element that 'hasLayout' (e.g. hr,table) in IE8 will
+ // break up the selection, safely manage it here. (#4795)
+ range.moveToPosition( selected, CKEDITOR.POSITION_BEFORE_START );
+ // Remove the control manually.
+ selected.remove();
+ range.select();
- editor.fire( 'saveSnapshot' );
+ editor.fire( 'saveSnapshot' );
- evt.data.preventDefault();
- }
+ evt.data.preventDefault();
+ return;
}
- } );
+ }
+ } );
- // PageUp/PageDown scrolling is broken in document
- // with standard doctype, manually fix it. (#4736)
- if ( domDocument.$.compatMode == 'CSS1Compat' )
+ // PageUp/PageDown scrolling is broken in document
+ // with standard doctype, manually fix it. (#4736)
+ if ( CKEDITOR.env.ie && domDocument.$.compatMode == 'CSS1Compat' )
+ {
+ var pageUpDownKeys = { 33 : 1, 34 : 1 };
+ domDocument.on( 'keydown', function( evt )
{
- var pageUpDownKeys = { 33 : 1, 34 : 1 };
- domDocument.on( 'keydown', function( evt )
+ if ( evt.data.getKeystroke() in pageUpDownKeys )
{
- if ( evt.data.getKeystroke() in pageUpDownKeys )
+ setTimeout( function ()
{
- setTimeout( function ()
- {
- editor.getSelection().scrollIntoView();
- }, 0 );
- }
- } );
- }
+ editor.getSelection().scrollIntoView();
+ }, 0 );
+ }
+ } );
+ }
- // Prevent IE from leaving new paragraph after deleting all contents in body. (#6966)
- editor.config.enterMode != CKEDITOR.ENTER_P
- && domDocument.on( 'selectionchange', function()
- {
- var body = domDocument.getBody(),
- range = editor.getSelection().getRanges()[ 0 ];
+ // Prevent IE from leaving new paragraph after deleting all contents in body. (#6966)
+ if ( CKEDITOR.env.ie && editor.config.enterMode != CKEDITOR.ENTER_P )
+ {
+ domDocument.on( 'selectionchange', function()
+ {
+ var body = domDocument.getBody(),
+ range = editor.getSelection().getRanges()[ 0 ];
- if ( body.getHtml().match( /^ <\/p>$/i )
- && range.startContainer.equals( body ) )
+ if ( body.getHtml().match( /^
<\/p>$/i )
+ && range.startContainer.equals( body ) )
+ {
+ // Avoid the ambiguity from a real user cursor position.
+ setTimeout( function ()
{
- // Avoid the ambiguity from a real user cursor position.
- setTimeout( function ()
+ range = editor.getSelection().getRanges()[ 0 ];
+ if ( !range.startContainer.equals ( 'body' ) )
{
- range = editor.getSelection().getRanges()[ 0 ];
- if ( !range.startContainer.equals ( 'body' ) )
- {
- body.getFirst().remove( 1 );
- range.moveToElementEditEnd( body );
- range.select( 1 );
- }
- }, 0 );
- }
- });
+ body.getFirst().remove( 1 );
+ range.moveToElementEditEnd( body );
+ range.select( 1 );
+ }
+ }, 0 );
+ }
+ });
}
// Adds the document body as a context menu target.
@@ -851,7 +834,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
if ( fireMode )
{
editor.mode = 'wysiwyg';
- editor.fire( 'mode' );
+ editor.fire( 'mode', { previousMode : editor._.previousMode } );
fireMode = false;
}
@@ -958,6 +941,10 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
{
editor.docType = docType = match;
return '';
+ }).replace( /<\?xml\s[^\?]*\?>/i, function( match )
+ {
+ editor.xmlDeclaration = match;
+ return '';
});
}
@@ -1030,6 +1017,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
var config = editor.config,
fullPage = config.fullPage,
docType = fullPage && editor.docType,
+ xmlDeclaration = fullPage && editor.xmlDeclaration,
doc = iframe.getFrameDocument();
var data = fullPage
@@ -1047,6 +1035,8 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
if ( config.ignoreEmptyParagraph )
data = data.replace( emptyParagraphRegexp, function( match, lookback ) { return lookback; } );
+ if ( xmlDeclaration )
+ data = xmlDeclaration + '\n' + data;
if ( docType )
data = docType + '\n' + data;
@@ -1099,18 +1089,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
if ( isLoadingData )
isPendingFocus = true;
- // Temporary solution caused by #6025, supposed be unified by #6154.
- else if ( CKEDITOR.env.opera && editor.document )
- {
- // Required for Opera when switching focus
- // from another iframe, e.g. panels. (#6444)
- var iframe = editor.window.$.frameElement;
- iframe.blur(), iframe.focus();
- editor.document.getBody().focus();
-
- editor.selectionChange();
- }
- else if ( !CKEDITOR.env.opera && win )
+ else if ( win )
{
// AIR needs a while to focus when moving from a link.
CKEDITOR.env.air ? setTimeout( function () { win.focus(); }, 0 ) : win.focus();
@@ -1123,7 +1102,23 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
editor.on( 'insertElement', onInsert( doInsertElement ), null, null, 20 );
editor.on( 'insertText', onInsert( doInsertText ), null, null, 20 );
// Auto fixing on some document structure weakness to enhance usabilities. (#3190 and #3189)
- editor.on( 'selectionChange', onSelectionChangeFixBody, null, null, 1 );
+ editor.on( 'selectionChange', function( evt )
+ {
+ if ( editor.readOnly )
+ return;
+
+ var sel = editor.getSelection();
+ // Do it only when selection is not locked. (#8222)
+ if ( sel && !sel.isLocked )
+ {
+ var isDirty = editor.checkDirty();
+ editor.fire( 'saveSnapshot', { contentOnly : 1 } );
+ onSelectionChangeFixBody.call( this, evt );
+ editor.fire( 'updateSnapshot' );
+ !isDirty && editor.resetDirty();
+ }
+
+ }, null, null, 1 );
});
var titleBackup;
@@ -1136,6 +1131,16 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
editor.document.$.title = frameLabel;
});
+ editor.on( 'readOnly', function()
+ {
+ if ( editor.mode == 'wysiwyg' )
+ {
+ // Symply reload the wysiwyg area. It'll take care of read-only.
+ var wysiwyg = editor.getMode();
+ wysiwyg.loadData( wysiwyg.getData() );
+ }
+ });
+
// IE>=8 stricts mode doesn't have 'contentEditable' in effect
// on element unless it has layout. (#5562)
if ( CKEDITOR.document.$.documentMode >= 8 )
@@ -1149,11 +1154,25 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
}
// Set the HTML style to 100% to have the text cursor in affect (#6341)
else if ( CKEDITOR.env.gecko )
+ {
editor.addCss( 'html { height: 100% !important; }' );
+ editor.addCss( 'img:-moz-broken { -moz-force-broken-image-icon : 1; width : 24px; height : 24px; }' );
+ }
+
+ /* #3658: [IE6] Editor document has horizontal scrollbar on long lines
+ To prevent this misbehavior, we show the scrollbar always */
+ /* #6341: The text cursor must be set on the editor area. */
+ /* #6632: Avoid having "text" shape of cursor in IE7 scrollbars.*/
+ editor.addCss( 'html { _overflow-y: scroll; cursor: text; *cursor:auto;}' );
+ // Use correct cursor for these elements
+ editor.addCss( 'img, input, textarea { cursor: default;}' );
// Switch on design mode for a short while and close it after then.
function blinkCursor( retry )
{
+ if ( editor.readOnly )
+ return;
+
CKEDITOR.tools.tryThese(
function()
{
@@ -1213,9 +1232,12 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
{
// We should flag that the element was locked by our code so
// it'll be editable by the editor functions (#6046).
- if ( !element.isReadOnly() )
+ var readonly = element.getAttribute( 'contenteditable' ) == 'false';
+ if ( !readonly )
+ {
element.data( 'cke-editable', element.hasAttribute( 'contenteditable' ) ? 'true' : '1' );
- element.setAttribute( 'contentEditable', false );
+ element.setAttribute( 'contenteditable', false );
+ }
}
});
@@ -1306,6 +1328,18 @@ CKEDITOR.config.ignoreEmptyParagraph = true;
*/
/**
+ * Whether automatically create wrapping blocks around inline contents inside document body,
+ * this helps to ensure the integrality of the block enter mode.
+ * Note: Changing the default value might introduce unpredictable usability issues.
+ * @name CKEDITOR.config.autoParagraph
+ * @since 3.6
+ * @type Boolean
+ * @default true
+ * @example
+ * config.autoParagraph = false;
+ */
+
+/**
* Fired when some elements are added to the document
* @name CKEDITOR.editor#ariaWidget
* @event