Skip to content

Commit

Permalink
Merge branch 't/12008' into major
Browse files Browse the repository at this point in the history
  • Loading branch information
Reinmar committed Jun 10, 2014
2 parents 3d0b46e + 2730297 commit c17735f
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 10 deletions.
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ CKEditor 4 Changelog

## CKEditor 4.5

Fixed Issues:

* [#12006](http://dev.ckeditor.com/ticket/12006): [Nested widgets] Drag and drop of nested block widgets.
* [#12008](http://dev.ckeditor.com/ticket/12008): Fixed various cases of inserting single non-editable element using [`editor.insertHtml()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-insertHtml) method. Fixes pasting widget with nested editable inside other widget's nested editable.

## CKEditor 4.4.2

Expand Down
5 changes: 4 additions & 1 deletion bender.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ var config = {
'tests/plugins/widget/nestededitables#test pasting widget which was copied (d&d) when its nested editable was focused': 'env.ie && env.version == 8',

// Firefox (#11399)
'tests/plugins/widget/nestededitables#test selection in nested editable is preserved after opening and closing dialog - inline editor': 'env.gecko'
'tests/plugins/widget/nestededitables#test selection in nested editable is preserved after opening and closing dialog - inline editor': 'env.gecko',

// IE8 (http://dev.ckeditor.com/ticket/12008#comment:6)
'tests/plugins/widget/nestedwidgets#test pasting widget with nested editable into nested editable': 'env.ie && env.version == 8',
}
},

Expand Down
21 changes: 20 additions & 1 deletion core/editable.js
Original file line number Diff line number Diff line change
Expand Up @@ -1519,6 +1519,14 @@
range.collapse();
}

// Rule 9. Non-editable content should be selected as a whole.
if ( isSingleNonEditableElement( nodesData ) ) {
dontMoveCaret = true;
node = nodesData[ 0 ].node;
range.setStartAt( node, CKEDITOR.POSITION_BEFORE_START );
range.setEndAt( node, CKEDITOR.POSITION_AFTER_END );
}

that.dontMoveCaret = dontMoveCaret;
that.bogusNeededBlocks = bogusNeededBlocks;
}
Expand Down Expand Up @@ -1747,6 +1755,16 @@
return node && checkIfElement( node ) && ( node.is( DTD.$removeEmpty ) || node.is( 'a' ) && !node.isBlockBoundary() );
}

// Checks if only non-editable element is being inserted.
function isSingleNonEditableElement( nodesData ) {
if ( nodesData.length != 1 )
return false;

var nodeData = nodesData[ 0 ];

return nodeData.isElement && ( nodeData.node.getAttribute( 'contenteditable' ) == 'false' );
}

var blockMergedTags = { p: 1, div: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1, ul: 1, ol: 1, li: 1, pre: 1, dl: 1, blockquote: 1 };

// See rule 5. in TCs.
Expand Down Expand Up @@ -1836,7 +1854,8 @@

if ( dataWrapper.getChildCount() == 1 && // Only one node bein inserted.
checkIfElement( block = dataWrapper.getFirst() ) && // And it's an element.
block.is( stripSingleBlockTags ) ) // That's <p> or <div> or header.
block.is( stripSingleBlockTags ) && // That's <p> or <div> or header.
!block.hasAttribute( 'contenteditable' ) ) // It's not a non-editable block or nested editable.
{
// Check children not containing block.
children = block.getElementsByTag( '*' );
Expand Down
57 changes: 50 additions & 7 deletions tests/core/editable/inserthtml.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@
// "<p><b>x^y</b></p>" + "<p>abc</p><p>def</p>" => "<p><b>x</b></p><p><b>abc</b></p><p><b>def^</b></p><p><b>y</b></p>"
// - in html mode:
// "<p><b>x^y</b></p>" + "<p>abc</p><p>def</p>" => "<p><b>x</b></p><p>abc</p><p>def^</p><p><b>y</b></p>"
// 9. Non-editable element must be selected as a whole, even if it has a nested editable.
//
// Example:
// "<p>x^x</p>" + "<span contenteditable='false'>foo</span>" => "<p>x[<span contenteditable='false'>foo</span>]x</p>"

// TCs groups:
// 1. text -> text
Expand Down Expand Up @@ -621,11 +625,11 @@
},

//
// TCs groups 7-9.
// TCs groups 7-8.
// block elements -> elements
//

'G7-9. splitting' : function() {
'G7-8. splitting' : function() {
var a = this.createAssertInsertionFunction( 'body,div', '<p>bam</p><p>bar</p>' );

a( '<p>a^b</p>',
Expand Down Expand Up @@ -686,14 +690,14 @@
a( '<h1>a^b</h1>', '<h1>a</h1><form>bam^</form><h1>b</h1>', 'case 8b' );
},

'G7-9. splitting - reuse element' : function() {
'G7-8. splitting - reuse element' : function() {
var a = this.createAssertInsertionFunction( 'body,div', 'x<p title="1">bam</p>y', 'html' );

a( '<p title="2">a^b</p>',
'<p title="2">ax</p><p title="1">bam</p><p title="2">y^b</p>', 'case 1a' );
},

'G7-9. splitting - multi selection' : function() {
'G7-8. splitting - multi selection' : function() {
var a = this.createAssertInsertionFunction( 'body,div', 'x<p>bam</p>y' );

a( '<p>a[b</p><p>c]d</p>',
Expand All @@ -719,7 +723,7 @@
},

// See _docs/blockselections.txt
'G7-9. splitting - text + eol' : function() {
'G7-8. splitting - text + eol' : function() {
var a = this.createAssertInsertionFunction( 'body,div', '<br data-cke-eol="1" />bam' );

a( '<p>a^b</p>', '<p>a</p><p>bam^b</p>', 'case 1a' );
Expand Down Expand Up @@ -759,7 +763,7 @@
},

// These cases were previously handled positively. Test for regressions.
'G7-9. splitting - text + eol - reverted cases' : function() {
'G7-8. splitting - text + eol - reverted cases' : function() {
var a = this.createAssertInsertionFunction( 'body,div', '<br />bam' );

a( '<p>a^b</p>', '<p>a<br />bam^b</p>', 'case 1' );
Expand All @@ -786,7 +790,7 @@
a( '<div>a^b</div>', '<div>a<br /><br />^b</div>', 'case 6d' );
},

'G7-9. filtering content' : function() {
'G7-8. filtering content' : function() {
// Form chosen, so it's not stripped by rule 7.
var a = this.createAssertInsertionFunction( 'h1', '<form>bam</form>', 'html' );

Expand Down Expand Up @@ -814,6 +818,45 @@
a( 'a^b', 'a<b>b</b>a<br />m^b', 'case 6a' );
},

//
// TCs group 9.
// non-editable content
//

'G9. non-editable inline element' : function() {
var span = '<span contenteditable="false">xxx</span>',
a = this.createAssertInsertionFunction( 'body,div', span, 'html' );

a( 'a^b', 'a[' + span + ']b', 'case 1a' );
a( '<p>a^b</p>', '<p>a[' + span + ']b</p>', 'case 1b' );
a( '<p>a[b</p><p>c]d</p>', '<p>a[' + span + ']d</p>', 'case 1c' );
},

'G9. non-editable inline element with inline content' : function() {
var span = '<span contenteditable="false"><b>xxx</b></span>',
a = this.createAssertInsertionFunction( 'body,div', span, 'html' );

a( 'a^b', 'a[' + span + ']b', 'case 1a' );
a( '<p>a^b</p>', '<p>a[' + span + ']b</p>', 'case 1b' );
a( '<p>a[b</p><p>c]d</p>', '<p>a[' + span + ']d</p>', 'case 1c' );
},

'G9. non-editable block element' : function() {
var div = '<div contenteditable="false">xxx</div>',
a = this.createAssertInsertionFunction( 'body,div', div, 'html' );

a( '<p>a^b</p>', '<p>a</p>[' + div + ']<p>b</p>', 'case 1a' );
a( '<p>a[b</p><p>c]d</p>', '<p>a</p>[' + div + ']<p>d</p>', 'case 1b' );
},

'G9. non-editable block element with nested editable' : function() {
var div = '<div contenteditable="false">xx<p contenteditable="true">yy</p></div>',
a = this.createAssertInsertionFunction( 'body,div', div, 'html' );

a( '<p>a^b</p>', '<p>a</p>[' + div + ']<p>b</p>', 'case 1a' );
a( '<p>a[b</p><p>c]d</p>', '<p>a</p>[' + div + ']<p>d</p>', 'case 1b' );
},

//
// TCs group special.
//
Expand Down
44 changes: 44 additions & 0 deletions tests/plugins/widget/nestedwidgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,50 @@
function log() {
destroyed.push( this.element.$.id );
}
},

// #12008
'test pasting widget with nested editable into nested editable': function() {
var editor = this.editors.editor,
bot = this.editorBots.editor;

editor.widgets.add( 'testpaste1', {
editables: {
ned2: '.ned2' // The name has to be different
}
} );

var widget2Data =
'<div data-widget="testpaste1" id="wp-1">' +
'<p class="ned2">foo</p>' +
'</div>';

bot.setData( generateWidgetsData( 1 ) + '<p>xxx</p>' + widget2Data, function() {
var w1 = getWidgetById( editor, 'wp-0' ),
w2 = getWidgetById( editor, 'wp-1' ),
html = w2.wrapper.getOuterHtml();

w2.wrapper.remove();
editor.widgets.checkWidgets();

w1.editables.ned.focus();
var range = editor.createRange();
range.moveToPosition( editor.document.getById( 'p-0' ), CKEDITOR.POSITION_AFTER_START );
editor.getSelection().selectRanges( [ range ] );

editor.on( 'afterPaste', function() {
resume( function() {
w2 = getWidgetById( editor, 'wp-1', true );

assert.isNotNull( w2, 'widget was pasted' );
assert.areSame( w2, editor.widgets.focused, 'pasted widget is focused' );
} );
} );

wait( function() {
editor.execCommand( 'paste', html );
} );
} );
}

} );
Expand Down
3 changes: 2 additions & 1 deletion tests/plugins/widget/widgetsintegration.js
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,8 @@
data2Attr( { 'classes': null } ) +
'" data-cke-widget-keep-attr="0" data-cke-widget-upcasted="1" data-widget="test_upcasted_pasting"><i class="upcasted_pasting">foo</i></span>' +
widgetTestsTools.widgetDragHanlder +
'</span>X?(<br />)?</p>$'
'</span>X?(<br />)?</p>' +
'(<div [^>]+>&nbsp;</div>)?$' // Hidden sel container.
);

var editor = this.editor,
Expand Down

0 comments on commit c17735f

Please sign in to comment.