Index: _source/plugins/htmldataprocessor/plugin.js
===================================================================
--- _source/plugins/htmldataprocessor/plugin.js (revision 6111)
+++ _source/plugins/htmldataprocessor/plugin.js (revision )
@@ -187,6 +187,13 @@
}
},
+ // Remove dummy span in webkit.
+ span: function( element )
+ {
+ if ( element.attributes[ 'class' ] == 'Apple-style-span' )
+ delete element.name;
+ },
+
html : function( element )
{
delete element.attributes.contenteditable;
Index: _source/core/editor.js
===================================================================
--- _source/core/editor.js (revision 6050)
+++ _source/core/editor.js (revision )
@@ -755,6 +755,22 @@
this.fire( 'insertHtml', data );
},
+ /*
+ * Insert text content into the currently selected position in the
+ * editor, in WYSIWYG mode, styles of the selected element will be applied to the inserted text,
+ * spaces around the text will be leaving untouched.
+ * Note: two subsequent line-breaks will be translated into
+ * one enter-key in effect, result depends on {@link CKEDITOR.config.enterMode};
+ * A single line-break will be translated into per shift-enter-key correspondingly.
+ * @param {String} text Text to be inserted into the editor.
+ * @example
+ * CKEDITOR.instances.editor1.insertText( ' line1 \n\n line2' );
+ */
+ insertText : function( text )
+ {
+ this.fire( 'insertText', text );
+ },
+
/**
* Inserts an element into the currently selected position in the
* editor.
Index: _source/plugins/wysiwygarea/plugin.js
===================================================================
--- _source/plugins/wysiwygarea/plugin.js (revision 6111)
+++ _source/plugins/wysiwygarea/plugin.js (revision )
@@ -26,178 +26,241 @@
return selection.getCommonAncestor().isReadOnly();
}
- function onInsertHtml( evt )
+
+ function onInsert( insertFunc )
{
+ return function( evt )
+ {
- if ( this.mode == 'wysiwyg' )
- {
- this.focus();
+ if ( this.mode == 'wysiwyg' )
+ {
+ this.focus();
- var selection = this.getSelection();
- if ( checkReadOnly( selection ) )
- return;
+ var selection = this.getSelection();
+ if ( checkReadOnly( selection ) )
+ return;
- var data = evt.data;
- this.fire( 'saveSnapshot' );
+ this.fire( 'saveSnapshot' );
+ insertFunc.call( this, evt.data );
+
+ // Save snaps after the whole execution completed.
+ // This's a workaround for make DOM modification's happened after
+ // 'insertElement' to be included either, e.g. Form-based dialogs' 'commitContents'
+ // call.
+ CKEDITOR.tools.setTimeout( function()
+ {
+ this.fire( 'saveSnapshot' );
+ }, 0, this );
+ }
+ }
+ }
+
+ function doInsertHtml( data )
+ {
- if ( this.dataProcessor )
- data = this.dataProcessor.toHtml( data );
+ if ( this.dataProcessor )
+ data = this.dataProcessor.toHtml( data );
+ var selection = this.getSelection();
- if ( CKEDITOR.env.ie )
- {
- var selIsLocked = selection.isLocked;
+ if ( CKEDITOR.env.ie )
+ {
+ var selIsLocked = selection.isLocked;
- if ( selIsLocked )
- selection.unlock();
+ if ( selIsLocked )
+ selection.unlock();
- var $sel = selection.getNative();
+ var $sel = selection.getNative();
- // Delete control selections to avoid IE bugs on pasteHTML.
- if ( $sel.type == 'Control' )
- $sel.clear();
+ // Delete control selections to avoid IE bugs on pasteHTML.
+ if ( $sel.type == 'Control' )
+ $sel.clear();
else if ( selection.getType() == CKEDITOR.SELECTION_TEXT )
- {
- // Due to IE bugs on handling contenteditable=false blocks
- // (#6005), we need to make some checks and eventually
- // delete the selection first.
+ {
+ // Due to IE bugs on handling contenteditable=false blocks
+ // (#6005), we need to make some checks and eventually
+ // delete the selection first.
- var range = selection.getRanges()[0],
+ var range = selection.getRanges()[0],
endContainer = range && range.endContainer;
- if ( endContainer &&
- endContainer.type == CKEDITOR.NODE_ELEMENT &&
- endContainer.getAttribute( 'contenteditable' ) == 'false' &&
- range.checkBoundaryOfElement( endContainer, CKEDITOR.END ) )
- {
- range.setEndAfter( range.endContainer );
- range.deleteContents();
- }
- }
+ if ( endContainer &&
+ endContainer.type == CKEDITOR.NODE_ELEMENT &&
+ endContainer.getAttribute( 'contenteditable' ) == 'false' &&
+ range.checkBoundaryOfElement( endContainer, CKEDITOR.END ) )
+ {
+ range.setEndAfter( range.endContainer );
+ range.deleteContents();
+ }
+ }
- try
- {
- $sel.createRange().pasteHTML( data );
- }
+ try
+ {
+ $sel.createRange().pasteHTML( data );
+ }
catch (e) {}
- if ( selIsLocked )
- this.getSelection().lock();
- }
- else
- this.document.$.execCommand( 'inserthtml', false, data );
+ if ( selIsLocked )
+ this.getSelection().lock();
+ }
+ else
+ this.document.$.execCommand( 'inserthtml', false, data );
- // Webkit does not scroll to the cursor position after pasting (#5558)
- if ( CKEDITOR.env.webkit )
- {
+ // Webkit does not scroll to the cursor position after pasting (#5558)
+ if ( CKEDITOR.env.webkit )
+ {
- this.document.$.execCommand( 'inserthtml', false, '' );
- var marker = this.document.getById( 'cke_paste_marker' );
- marker.scrollIntoView();
- marker.remove();
- marker = null;
+ selection = this.getSelection();
+ selection.scrollIntoView();
- }
+ }
+ }
- CKEDITOR.tools.setTimeout( function()
+ function doInsertText( text )
- {
+ {
- this.fire( 'saveSnapshot' );
- }, 0, this );
+ var selection = this.getSelection(),
+ mode = selection.getStartElement().hasAscendant( 'pre', true ) ?
+ CKEDITOR.ENTER_BR : this.config.enterMode,
+ isEnterBrMode = mode == CKEDITOR.ENTER_BR;
+
+ var html = CKEDITOR.tools.htmlEncode( text.replace( /\r\n|\r/g, '\n' ) );
+
+ // Convert leading and trailing whitespaces into
+ html = html.replace( /^[ \t]+|[ \t]+$/g, function( match, offset, s )
+ {
+ if ( match.length == 1 ) // one space, preserve it
+ return ' ';
+ else if ( !offset ) // beginning of block
+ return CKEDITOR.tools.repeat( ' ', match.length - 1 ) + ' ';
+ else // end of block
+ return ' ' + CKEDITOR.tools.repeat( ' ', match.length - 1 );
+ } );
+
+ // Convert subsequent whitespaces into
+ html = html.replace( /[ \t]{2,}/g, function ( match )
+ {
+ return CKEDITOR.tools.repeat( ' ', match.length - 1 ) + ' ';
+ } );
+
+ var paragraphTag = mode == CKEDITOR.ENTER_P ? 'p' : 'div';
+
+ // Two line-breaks create one paragraph.
+ if ( !isEnterBrMode )
+ {
+ html = html.replace( /(\n{2})([\s\S]*?)(?:$|\1)/g,
+ function( match, group1, text )
+ {
+ return '<'+paragraphTag + '>' + text + '' + paragraphTag + '>';
+ });
}
+
+ // One
per line-break.
+ html = html.replace( /\n/g, '
' );
+
+ // Compensate padding
for non-IE.
+ if ( !( isEnterBrMode || CKEDITOR.env.ie ) )
+ {
+ html = html.replace( new RegExp( '
(?=' + paragraphTag + '>)' ), function( match )
+ {
+ return CKEDITOR.tools.repeat( match, 2 );
+ } );
- }
+ }
- function onInsertElement( evt )
+ // Inline styles have to be inherited in Firefox.
+ if ( CKEDITOR.env.gecko || CKEDITOR.env.webkit )
- {
+ {
- if ( this.mode == 'wysiwyg' )
+ var path = new CKEDITOR.dom.elementPath( selection.getStartElement() ),
+ context = [];
+
+ for ( var i = 0; i < path.elements.length; i++ )
- {
+ {
- this.focus();
+ var tag = path.elements[ i ].getName();
+ if ( tag in CKEDITOR.dtd.$inline )
+ context.unshift( path.elements[ i ].getOuterHtml().match( /^<.*?>/) );
+ else if ( tag in CKEDITOR.dtd.$block )
+ break;
+ }
- var selection = this.getSelection();
- if ( checkReadOnly( selection ) )
- return;
+ // Reproduce the context by preceding the pasted HTML with opening inline tags.
+ html = context.join( '' ) + html;
+ }
- this.fire( 'saveSnapshot' );
+ doInsertHtml.call( this, html );
+ }
- var ranges = selection.getRanges(),
- element = evt.data,
+ function doInsertElement( element )
+ {
+ var selection = this.getSelection(),
+ ranges = selection.getRanges(),
elementName = element.getName(),
isBlock = CKEDITOR.dtd.$block[ elementName ];
- var selIsLocked = selection.isLocked;
+ var selIsLocked = selection.isLocked;
- if ( selIsLocked )
- selection.unlock();
+ if ( selIsLocked )
+ selection.unlock();
- var range, clone, lastElement, bookmark;
+ var range, clone, lastElement, bookmark;
- for ( var i = ranges.length - 1 ; i >= 0 ; i-- )
- {
- range = ranges[ i ];
+ for ( var i = ranges.length - 1 ; i >= 0 ; i-- )
+ {
+ range = ranges[ i ];
- // Remove the original contents.
- range.deleteContents();
+ // Remove the original contents.
+ range.deleteContents();
- clone = !i && element || element.clone( 1 );
+ clone = !i && element || element.clone( 1 );
- // If we're inserting a block at dtd-violated position, split
- // the parent blocks until we reach blockLimit.
- var current, dtd;
- if ( isBlock )
- {
- while ( ( current = range.getCommonAncestor( 0, 1 ) )
- && ( dtd = CKEDITOR.dtd[ current.getName() ] )
- && !( dtd && dtd [ elementName ] ) )
- {
- // Split up inline elements.
- if ( current.getName() in CKEDITOR.dtd.span )
- range.splitElement( current );
- // If we're in an empty block which indicate a new paragraph,
- // simply replace it with the inserting block.(#3664)
- else if ( range.checkStartOfBlock()
- && range.checkEndOfBlock() )
- {
- range.setStartBefore( current );
- range.collapse( true );
- current.remove();
- }
- else
- range.splitBlock();
- }
- }
+ // If we're inserting a block at dtd-violated position, split
+ // the parent blocks until we reach blockLimit.
+ var current, dtd;
+ if ( isBlock )
+ {
+ while ( ( current = range.getCommonAncestor( 0, 1 ) )
+ && ( dtd = CKEDITOR.dtd[ current.getName() ] )
+ && !( dtd && dtd [ elementName ] ) )
+ {
+ // Split up inline elements.
+ if ( current.getName() in CKEDITOR.dtd.span )
+ range.splitElement( current );
+ // If we're in an empty block which indicate a new paragraph,
+ // simply replace it with the inserting block.(#3664)
+ else if ( range.checkStartOfBlock()
+ && range.checkEndOfBlock() )
+ {
+ range.setStartBefore( current );
+ range.collapse( true );
+ current.remove();
+ }
+ else
+ range.splitBlock();
+ }
+ }
- // Insert the new node.
- range.insertNode( clone );
+ // Insert the new node.
+ range.insertNode( clone );
- // Save the last element reference so we can make the
- // selection later.
- if ( !lastElement )
- lastElement = clone;
- }
+ // Save the last element reference so we can make the
+ // selection later.
+ if ( !lastElement )
+ lastElement = clone;
+ }
- range.moveToPosition( lastElement, CKEDITOR.POSITION_AFTER_END );
+ range.moveToPosition( lastElement, CKEDITOR.POSITION_AFTER_END );
- // If we're inserting a block element immediatelly followed by
- // another block element, the selection must move there. (#3100,#5436)
- if ( isBlock )
- {
- var next = lastElement.getNext( notWhitespaceEval ),
+ // If we're inserting a block element immediatelly followed by
+ // another block element, the selection must move there. (#3100,#5436)
+ if ( isBlock )
+ {
+ var next = lastElement.getNext( notWhitespaceEval ),
nextName = next && next.type == CKEDITOR.NODE_ELEMENT && next.getName();
- // Check if it's a block element that accepts text.
- if ( nextName && CKEDITOR.dtd.$block[ nextName ] && CKEDITOR.dtd[ nextName ]['#'] )
- range.moveToElementEditStart( next );
- }
+ // Check if it's a block element that accepts text.
+ if ( nextName && CKEDITOR.dtd.$block[ nextName ] && CKEDITOR.dtd[ nextName ]['#'] )
+ range.moveToElementEditStart( next );
+ }
- selection.selectRanges( [ range ] );
+ selection.selectRanges( [ range ] );
- if ( selIsLocked )
- this.getSelection().lock();
+ if ( selIsLocked )
+ this.getSelection().lock();
-
- // Save snaps after the whole execution completed.
- // This's a workaround for make DOM modification's happened after
- // 'insertElement' to be included either, e.g. Form-based dialogs' 'commitContents'
- // call.
- CKEDITOR.tools.setTimeout( function(){
- this.fire( 'saveSnapshot' );
- }, 0, this );
- }
+ }
- }
// DOM modification here should not bother dirty flag.(#4385)
function restoreDirty( editor )
@@ -959,8 +1022,9 @@
}
});
- editor.on( 'insertHtml', onInsertHtml, null, null, 20 );
- editor.on( 'insertElement', onInsertElement, null, null, 20 );
+ editor.on( 'insertHtml', onInsert( doInsertHtml ) , null, null, 20 );
+ 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 );
});
Index: _source/core/dom/element.js
===================================================================
--- _source/core/dom/element.js (revision 6111)
+++ _source/core/dom/element.js (revision )
@@ -721,13 +721,13 @@
var thisLength = thisAttribs.length,
otherLength = otherAttribs.length;
- if ( !CKEDITOR.env.ie && thisLength != otherLength )
- return false;
-
for ( var i = 0 ; i < thisLength ; i++ )
{
var attribute = thisAttribs[ i ];
+ if ( attribute.nodeName == '_moz_dirty' )
+ continue;
+
if ( ( !CKEDITOR.env.ie || ( attribute.specified && attribute.nodeName != 'data-cke-expando' ) ) && attribute.nodeValue != otherElement.getAttribute( attribute.nodeName ) )
return false;
}
Index: _source/plugins/specialchar/dialogs/specialchar.js
===================================================================
--- _source/plugins/specialchar/dialogs/specialchar.js (revision 6088)
+++ _source/plugins/specialchar/dialogs/specialchar.js (revision )
@@ -12,32 +12,6 @@
var dialog,
lang = editor.lang.specialChar;
- var insertSpecialChar = function ( specialChar )
- {
- var selection = editor.getSelection(),
- ranges = selection.getRanges( true ),
- range, textNode;
-
- editor.fire( 'saveSnapshot' );
-
- for ( var i = ranges.length - 1; i >= 0 ; i-- )
- {
- range = ranges[ i ];
- range.deleteContents();
-
- textNode = CKEDITOR.dom.element.createFromHtml( specialChar );
- range.insertNode( textNode );
- }
-
- if ( range )
- {
- range.moveToPosition( textNode, CKEDITOR.POSITION_AFTER_END );
- range.select();
- }
-
- editor.fire( 'saveSnapshot' );
- };
-
var onChoice = function( evt )
{
var target, value;
@@ -51,11 +25,7 @@
target.removeClass( "cke_light_background" );
dialog.hide();
- // Firefox has bug on insert chars into a element use its own API. (#5170)
- if ( CKEDITOR.env.gecko )
- insertSpecialChar( value );
- else
- editor.insertHtml( value );
+ editor.insertText( value );
}
};
Index: _source/plugins/pastetext/plugin.js
===================================================================
--- _source/plugins/pastetext/plugin.js (revision 5680)
+++ _source/plugins/pastetext/plugin.js (revision )
@@ -37,20 +37,6 @@
}
};
- function doInsertText( doc, text )
- {
- // Native text insertion.
- if ( CKEDITOR.env.ie )
- {
- var selection = doc.selection;
- if ( selection.type == 'Control' )
- selection.clear();
- selection.createRange().pasteHTML( text );
- }
- else
- doc.execCommand( 'inserthtml', false, text );
- }
-
// Register the plugin.
CKEDITOR.plugins.add( 'pastetext',
{
@@ -84,52 +70,6 @@
requires : [ 'clipboard' ]
});
- function doEnter( editor, mode, times, forceMode )
- {
- while ( times-- )
- {
- CKEDITOR.plugins.enterkey[ mode == CKEDITOR.ENTER_BR ? 'enterBr' : 'enterBlock' ]
- ( editor, mode, null, forceMode );
- }
- }
-
- CKEDITOR.editor.prototype.insertText = function( text )
- {
- this.focus();
- this.fire( 'saveSnapshot' );
-
- var mode = this.getSelection().getStartElement().hasAscendant( 'pre', true ) ? CKEDITOR.ENTER_BR : this.config.enterMode,
- isEnterBrMode = mode == CKEDITOR.ENTER_BR,
- doc = this.document.$,
- self = this,
- line;
-
- text = CKEDITOR.tools.htmlEncode( text.replace( /\r\n|\r/g, '\n' ) );
-
- var startIndex = 0;
- text.replace( /\n+/g, function( match, lastIndex )
- {
- line = text.substring( startIndex, lastIndex );
- startIndex = lastIndex + match.length;
- line.length && doInsertText( doc, line );
-
- var lineBreakNums = match.length,
- // Duo consequence line-break as a enter block.
- enterBlockTimes = isEnterBrMode ? 0 : Math.floor( lineBreakNums / 2 ),
- // Per link-break as a enter br.
- enterBrTimes = isEnterBrMode ? lineBreakNums : lineBreakNums % 2;
-
- // Line-breaks are converted to editor enter key strokes.
- doEnter( self, mode, enterBlockTimes );
- doEnter( self, CKEDITOR.ENTER_BR, enterBrTimes, isEnterBrMode ? false : true );
- });
-
- // Insert the last text line of text.
- line = text.substring( startIndex, text.length );
- line.length && doInsertText( doc, line );
-
- this.fire( 'saveSnapshot' );
- };
})();