diff --git a/core/editable.js b/core/editable.js index e25cc77e5fe..1e01c3f574d 100644 --- a/core/editable.js +++ b/core/editable.js @@ -1619,7 +1619,7 @@ var context = that.blockLimit.getName(); - // Wrap data to be inserted, to avoid loosing leading whitespaces + // Wrap data to be inserted, to avoid losing leading whitespaces // when going through the below procedure. if ( /^\s+|\s+$/.test( data ) && 'span' in CKEDITOR.dtd[ context ] ) { var protect = ' '; @@ -1632,6 +1632,7 @@ data = that.editor.dataProcessor.toHtml( data, { context: null, fixForBody: false, + protectedWhitespaces: !!protect, dontFilter: that.dontFilter, // Use the current, contextual settings. filter: that.editor.activeFilter, diff --git a/core/htmldataprocessor.js b/core/htmldataprocessor.js index f5c25993f61..451bbd41ce8 100644 --- a/core/htmldataprocessor.js +++ b/core/htmldataprocessor.js @@ -224,11 +224,13 @@ * @param {Boolean} [options.dontFilter] Do not filter data with {@link CKEDITOR.filter} (note: transformations * will be still applied). * @param {Number} [options.enterMode] When specified it will be used instead of the {@link CKEDITOR.editor#enterMode main enterMode}. + * @param {Boolean} [options.protectedWhitespaces] Indicates that content has been wrapped with `span` elements to preserve + * leading and trailing whitespaces. Option used by the {@link CKEDITOR.editor#insertHtml} method. * @returns {String} */ toHtml: function( data, options, fixForBody, dontFilter ) { var editor = this.editor, - context, filter, enterMode; + context, filter, enterMode, protectedWhitespaces; // Typeof null == 'object', so check truthiness of options too. if ( options && typeof options == 'object' ) { @@ -237,6 +239,7 @@ dontFilter = options.dontFilter; filter = options.filter; enterMode = options.enterMode; + protectedWhitespaces = options.protectedWhitespaces; } // Backward compatibility. Since CKEDITOR 4.3 every option was a separate argument. else { @@ -253,7 +256,8 @@ fixForBody: fixForBody, dontFilter: dontFilter, filter: filter || editor.filter, - enterMode: enterMode || editor.enterMode + enterMode: enterMode || editor.enterMode, + protectedWhitespaces: protectedWhitespaces } ).dataValue; }, @@ -989,6 +993,7 @@ * @param {Boolean} data.dontFilter See {@link CKEDITOR.htmlDataProcessor#toHtml} The `dontFilter` argument. * @param {Boolean} data.filter See {@link CKEDITOR.htmlDataProcessor#toHtml} The `filter` argument. * @param {Boolean} data.enterMode See {@link CKEDITOR.htmlDataProcessor#toHtml} The `enterMode` argument. + * @param {Boolean} [data.protectedWhitespaces] See {@link CKEDITOR.htmlDataProcessor#toHtml} The `protectedWhitespaces` argument. */ /** diff --git a/plugins/widget/plugin.js b/plugins/widget/plugin.js index 6dab026be33..ddf516c4d3b 100644 --- a/plugins/widget/plugin.js +++ b/plugins/widget/plugin.js @@ -2662,8 +2662,14 @@ } // Used to determine whether only widget was pasted. - processedWidgetOnly = evt.data.dataValue.children.length == 1 && - Widget.isParserWidgetWrapper( evt.data.dataValue.children[ 0 ] ); + if ( evt.data.protectedWhitespaces ) { + // Whitespaces are protected by wrapping content with spans. Take the middle node only. + processedWidgetOnly = evt.data.dataValue.children.length == 3 && + Widget.isParserWidgetWrapper( evt.data.dataValue.children[ 1 ] ); + } else { + processedWidgetOnly = evt.data.dataValue.children.length == 1 && + Widget.isParserWidgetWrapper( evt.data.dataValue.children[ 0 ] ); + } }, null, null, 8 ); editor.on( 'dataReady', function() { diff --git a/tests/core/editable/insertion.js b/tests/core/editable/insertion.js index f51699360e2..9f1da7c9682 100644 --- a/tests/core/editable/insertion.js +++ b/tests/core/editable/insertion.js @@ -134,6 +134,16 @@ assert.areSame( '

bar

', bot.editor.getData(), 'text was inserted' ); } ); + }, + + 'test insertHtml sets options.protectedWhitespaces of dP.toHtml': function() { + var editor = this.editor; + + editor.once( 'toHtml', function( evt ) { + assert.isTrue( evt.data.protectedWhitespaces ); + } ); + + editor.insertHtml( ' foo ' ); } } ); } )(); \ No newline at end of file diff --git a/tests/core/htmldataprocessor.js b/tests/core/htmldataprocessor.js index d2a843aa85a..290944abd67 100644 --- a/tests/core/htmldataprocessor.js +++ b/tests/core/htmldataprocessor.js @@ -1010,6 +1010,16 @@ } ), 'br mode' ); }, + 'test toHtml options.protectedWhitespaces defaults falsy': function() { + var editor = this.editor; + + editor.once( 'toHtml', function( evt ) { + assert.isUndefined( evt.data.protectedWhitespaces ); + } ); + + editor.dataProcessor.toHtml( 'foo', {} ); + }, + 'test leading br is removed by toDataFormat in ENTER_P and ENTER_DIV': function() { var htmlDP = this.editor.dataProcessor, opts = { enterMode: CKEDITOR.ENTER_P }; diff --git a/tests/plugins/widget/nestedwidgets.js b/tests/plugins/widget/nestedwidgets.js index 236016a9009..dfe4d529a18 100644 --- a/tests/plugins/widget/nestedwidgets.js +++ b/tests/plugins/widget/nestedwidgets.js @@ -298,6 +298,11 @@ // #12008 'test pasting widget with nested editable into nested editable': function() { + if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) { + assert.ignore(); + return; + } + var editor = this.editors.editor, bot = this.editorBots.editor; @@ -340,4 +345,4 @@ } ); } } ); -} )(); \ No newline at end of file +} )();