';
+
+ this.editorBots.editor.setData( editorHtml, function() {
+ var widgetUpper = getWidgetById( editor, 'upperwidget' );
+ var widgetNested = getWidgetById( editor, 'nestedwidget' );
+
+ // Check if nested editables belong only to nested widget
+ // and upper edtiables belong only to upper widget.
+ assert.areSame( 'uppercol1', widgetUpper.editables.col1.getId(), 'upper widget has editable .col1 with id' );
+ assert.areSame( 'uppercol2', widgetUpper.editables.col2.getId(), 'upper widget has editable .col2 with id' );
+ assert.areSame( 'nestedcol1', widgetNested.editables.col1.getId(), 'nested widget has editable .col1 with id' );
+ assert.areSame( 'nestedcol2', widgetNested.editables.col2.getId(), 'nested widget has editable .col2 with id' );
+ } );
}
} );
} )();
From 8eaafd398763f75737e32a309d25ce684743198d Mon Sep 17 00:00:00 2001
From: Szymon Cofalik
Date: Fri, 12 Jun 2015 13:06:58 +0200
Subject: [PATCH 04/11] Updated Widget.definition.editables doc.
---
plugins/widget/plugin.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/plugins/widget/plugin.js b/plugins/widget/plugin.js
index 52ba9e6735e..c65506c7e87 100644
--- a/plugins/widget/plugin.js
+++ b/plugins/widget/plugin.js
@@ -3792,6 +3792,8 @@
/**
* An object containing definitions of nested editables (editable name => {@link CKEDITOR.plugins.widget.nestedEditable.definition}).
+ * Note that editables *have to* be defined in the same order as they are in DOM / {@link CKEDITOR.plugins.widget.definition#template template}.
+ * Otherwise errors will occur when nesting widgets inside each other.
*
* editables: {
* header: 'h1',
From c73b689e5705339183f2fb3f903562066b7b1d65 Mon Sep 17 00:00:00 2001
From: Szymon Cofalik
Date: Fri, 12 Jun 2015 16:43:31 +0200
Subject: [PATCH 05/11] Moved findCorrectElement to Widget.prototype, tweaks in
nested widgets tests.
---
plugins/widget/plugin.js | 76 +++++++++++++------------
tests/core/dom/node.js | 2 +
tests/plugins/widget/manual/block.html | 30 +++++++++-
tests/plugins/widget/manual/block.md | 4 +-
tests/plugins/widget/manual/inline.md | 6 +-
tests/plugins/widget/manual/nested.html | 37 ------------
tests/plugins/widget/manual/nested.md | 10 ----
tests/plugins/widget/nestedwidgets.js | 28 +++++++++
8 files changed, 105 insertions(+), 88 deletions(-)
delete mode 100644 tests/plugins/widget/manual/nested.html
delete mode 100644 tests/plugins/widget/manual/nested.md
diff --git a/plugins/widget/plugin.js b/plugins/widget/plugin.js
index c65506c7e87..8538b8bebf4 100644
--- a/plugins/widget/plugin.js
+++ b/plugins/widget/plugin.js
@@ -1204,9 +1204,8 @@
* @returns {Boolean} Whether an editable was successfully initialized.
*/
initEditable: function( editableName, definition ) {
-
// Don't fetch just first element which matched selector but look for a correct one. (#13334)
- var editable = findCorrectEditable( this.wrapper, definition.selector );
+ var editable = this.findCorrectEditable( definition.selector );
if ( editable && editable.is( CKEDITOR.dtd.$editable ) ) {
editable = new NestedEditable( this.editor, editable, {
@@ -1247,6 +1246,46 @@
return false;
},
+ /**
+ * Looks inside wrapper element to find a correct element that matches the selector.
+ * Correct element should not be inside another widget's wrapper because then it is
+ * already a part of other widget.
+ * The path from a matched element to the wrapper element of this widget is checked,
+ * looking of other wrappers. (#13334)
+ *
+ * @param {String} selector Selector to match.
+ * @returns {CKEDITOR.dom.node} Node which matches given selector and is not a part of other widget or
+ * null if such node has not been found.
+ */
+ findCorrectEditable: function( selector ) {
+ var editable = null,
+ parents;
+
+ var matchedElements = this.wrapper.find( selector );
+
+ for ( var i = 0; i < matchedElements.count(); i++ ) {
+ editable = matchedElements.getItem( i );
+
+ parents = editable.getParents( true, this.wrapper );
+ parents.pop(); // Don't include wrapper element.
+
+ for ( var j = 0; j < parents.length; j++ ) {
+ // One of parents is a widget wrapper, so this match is already a part of other widget.
+ if ( Widget.isDomWidgetWrapper( parents[ j ] ) ) {
+ editable = null;
+ break;
+ }
+ }
+
+ // The first match is a good match.
+ // Other matches are probably parts of other widgets instances.
+ if ( editable != null )
+ break;
+ }
+
+ return editable;
+ },
+
/**
* Checks if a widget has already been initialized and has not been destroyed yet.
*
@@ -3359,39 +3398,6 @@
widget.element.data( 'cke-widget-data', encodeURIComponent( JSON.stringify( widget.data ) ) );
}
- // Looks inside wrapper element to find an element that matches the selector
- // and is not inside another widget's wrapper (is not a part of other, already initialized widget).
- // This situation may happen when widgets are nested. If there is other widgets wrapper on a path
- // from a matched node to the wrapper element then the match is incorrect. (#13334)
- function findCorrectEditable( wrapper, selector ) {
- var editable = null,
- parents;
-
- var matchedElements = wrapper.find( selector );
-
- for ( var i = 0; i < matchedElements.count(); i++ ) {
- editable = matchedElements.getItem( i );
-
- parents = editable.getParents( true, wrapper );
- parents.pop(); // Don't include wrapper element.
-
- for ( var j = 0; j < parents.length; j++ ) {
- // One of parents is a widget wrapper, so this match is already a part of other widget.
- if ( Widget.isDomWidgetWrapper( parents[ j ] ) ) {
- editable = null;
- break;
- }
- }
-
- // The first match is a good match.
- // Other matches are probably parts of other widgets instances.
- if ( editable != null )
- break;
- }
-
- return editable;
- }
-
//
// WIDGET STYLE HANDLER ---------------------------------------------------
//
diff --git a/tests/core/dom/node.js b/tests/core/dom/node.js
index ea73ceb5cef..95518c4676e 100644
--- a/tests/core/dom/node.js
+++ b/tests/core/dom/node.js
@@ -686,6 +686,8 @@
assert.areSame( 5, node.getParents( false, wrongParent ).length );
assert.areSame( node.getParents( false, guard )[ 0 ], guard );
assert.areSame( node.getParents( false, guard )[ 0 ], node.getParents( true, guard )[ 2 ] );
+ // guard and base node are the same elements - we should get only that node
+ assert.isTrue( node.getParents( false, node )[ 0 ].equals( node ) );
},
test_getCommonAncestor: function() {
diff --git a/tests/plugins/widget/manual/block.html b/tests/plugins/widget/manual/block.html
index 351d86abb46..792ba2c829d 100644
--- a/tests/plugins/widget/manual/block.html
+++ b/tests/plugins/widget/manual/block.html
@@ -99,9 +99,33 @@
',
+ editables: {
+ col1: { selector: '.col1' },
+ col2: { selector: '.col2' }
+ },
+ upcast: function( element ) {
+ return element.hasClass( 'testwidget' );
+ }
+ } );
+ }
+ } );
+
CKEDITOR.replace( 'editor1', {
- height: 400
+ height: 400,
+ extraPlugins: 'doublecolumn',
+ allowedContent: true
} );
- CKEDITOR.inline( 'editor2' );
-
\ No newline at end of file
+ CKEDITOR.inline( 'editor2', {
+ extraPlugins: 'doublecolumn',
+ allowedContent: true
+ } );
+
diff --git a/tests/plugins/widget/manual/block.md b/tests/plugins/widget/manual/block.md
index 9634cd5bd96..d9ce81cf1ea 100644
--- a/tests/plugins/widget/manual/block.md
+++ b/tests/plugins/widget/manual/block.md
@@ -2,6 +2,7 @@
@bender-ui: collapsed
@bender-ckeditor-plugins: wysiwygarea, toolbar, sourcearea, table, undo, indent, justify, clipboard, floatingspace, basicstyles, image2, codesnippet, link, elementspath, blockquote, format, htmlwriter, list, maximize
+Add some widgets and nested widgets (use 'empty' icon for that).
Test block widgets features:
- create,
- edit,
@@ -10,4 +11,5 @@ Test block widgets features:
- cut/copy and paste,
- editing in nested editable,
- remove,
- - undo/redo.
\ No newline at end of file
+ - undo/redo,
+ - switch multiple times between source and wysiwyg mode.
diff --git a/tests/plugins/widget/manual/inline.md b/tests/plugins/widget/manual/inline.md
index 687e8eb5b0f..e290e4a8b6c 100644
--- a/tests/plugins/widget/manual/inline.md
+++ b/tests/plugins/widget/manual/inline.md
@@ -7,6 +7,8 @@ Test inline widgets features:
- edit,
- select,
- drag and drop,
- - copy and paste,
+ - cut/copy and paste,
+ - editing in nested editable,
- remove,
- - undo/redo.
\ No newline at end of file
+ - undo/redo,
+ - switch multiple times between source and wysiwyg mode.
diff --git a/tests/plugins/widget/manual/nested.html b/tests/plugins/widget/manual/nested.html
deleted file mode 100644
index 8e5db8c0a46..00000000000
--- a/tests/plugins/widget/manual/nested.html
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
-
-
diff --git a/tests/plugins/widget/manual/nested.md b/tests/plugins/widget/manual/nested.md
deleted file mode 100644
index fe4b9f2e27b..00000000000
--- a/tests/plugins/widget/manual/nested.md
+++ /dev/null
@@ -1,10 +0,0 @@
-@bender-tags: widget
-@bender-ui: collapsed
-@bender-ckeditor-plugins: wysiwygarea, toolbar, sourcearea, undo, image2, codesnippet, magicline
-
-Use custom doublecolumn widget ('empty' icon) to create widgets in widgets, then:
- - edit, select, drag and drop,
- - cut/copy and paste,
- - remove,
- - undo/redo,
- - switch multiple times between source and wysiwyg mode.
diff --git a/tests/plugins/widget/nestedwidgets.js b/tests/plugins/widget/nestedwidgets.js
index 23ac35f51b5..c1be19b6af1 100644
--- a/tests/plugins/widget/nestedwidgets.js
+++ b/tests/plugins/widget/nestedwidgets.js
@@ -346,6 +346,34 @@
} );
},
+ 'test findCorrectEditable': function() {
+ var editor = this.editors.editor;
+
+ var editorHtml =
+ '
' +
+ '
' +
+ '
' + // Added wrapper so we simulate that nested widget is already initialized.
+ '
' +
+ '
' +
+ '
' +
+ '' +
+ '
';
+
+ editor.widgets.add( 'test_findCorrectEditable', {} );
+
+ this.editorBots.editor.setData( editorHtml, function() {
+ var widget = getWidgetById( editor, 'test_findCorrectEditable' );
+ var col1 = widget.findCorrectEditable( '.col1' );
+ var col2 = widget.findCorrectEditable( '.col2' );
+
+ // .col1 is only in another widget so it should not be found.
+ assert.areSame( null, col1, 'findCorrectEditable for selector .col1 returns' );
+
+ // findCorrectEditable should find .col2 which is not in another widget.
+ assert.areSame( 'uppercol2', col2.getId(), 'findCorrectEditable returned .col2 with id' );
+ } );
+ },
+
// #13334
'test editables are not matched from among nested widgets': function() {
var editor = this.editors.editor;
From eb8898c88876132528bc7268c73bdaba1f0f6e9a Mon Sep 17 00:00:00 2001
From: Artur Delura
Date: Fri, 12 Jun 2015 17:16:23 +0200
Subject: [PATCH 06/11] Tests: Nested widget also available in inline manual
test.
---
tests/plugins/widget/manual/inline.html | 29 ++++++++++++++++++++++---
1 file changed, 26 insertions(+), 3 deletions(-)
diff --git a/tests/plugins/widget/manual/inline.html b/tests/plugins/widget/manual/inline.html
index 29897f062d1..8f7fa37d8b4 100644
--- a/tests/plugins/widget/manual/inline.html
+++ b/tests/plugins/widget/manual/inline.html
@@ -73,13 +73,36 @@
',
+ editables: {
+ col1: { selector: '.col1' },
+ col2: { selector: '.col2' }
+ },
+ upcast: function( element ) {
+ return element.hasClass( 'testwidget' );
+ }
+ } );
+ }
+ } );
+
CKEDITOR.replace( 'editor1', {
height: 400,
- mathJaxLib: '../../mathjax/' + bender.config.mathJaxLibPath
+ mathJaxLib: '../../mathjax/' + bender.config.mathJaxLibPath,
+ extraPlugins: 'doublecolumn',
+ allowedContent: true
} );
CKEDITOR.inline( 'editor2', {
- mathJaxLib: '../../mathjax/' + bender.config.mathJaxLibPath
+ mathJaxLib: '../../mathjax/' + bender.config.mathJaxLibPath,
+ extraPlugins: 'doublecolumn',
+ allowedContent: true
} );
-
\ No newline at end of file
+
From a7b4bd5472631f92b6f04e23f7dd41e4686cf0d6 Mon Sep 17 00:00:00 2001
From: Artur Delura
Date: Fri, 12 Jun 2015 17:21:01 +0200
Subject: [PATCH 07/11] Added missed tags.
---
plugins/widget/plugin.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/plugins/widget/plugin.js b/plugins/widget/plugin.js
index 8538b8bebf4..604e7471765 100644
--- a/plugins/widget/plugin.js
+++ b/plugins/widget/plugin.js
@@ -1253,6 +1253,8 @@
* The path from a matched element to the wrapper element of this widget is checked,
* looking of other wrappers. (#13334)
*
+ * @since 4.5
+ * @private
* @param {String} selector Selector to match.
* @returns {CKEDITOR.dom.node} Node which matches given selector and is not a part of other widget or
* null if such node has not been found.
From ae708f9e4a77f5dba75d435fb3cb8c94d7b7eceb Mon Sep 17 00:00:00 2001
From: Artur Delura
Date: Fri, 12 Jun 2015 18:20:47 +0200
Subject: [PATCH 08/11] Comment correction.
---
plugins/widget/plugin.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/plugins/widget/plugin.js b/plugins/widget/plugin.js
index 604e7471765..e1836d96d16 100644
--- a/plugins/widget/plugin.js
+++ b/plugins/widget/plugin.js
@@ -1269,7 +1269,8 @@
editable = matchedElements.getItem( i );
parents = editable.getParents( true, this.wrapper );
- parents.pop(); // Don't include wrapper element.
+ // Don't include wrapper element.
+ parents.pop();
for ( var j = 0; j < parents.length; j++ ) {
// One of parents is a widget wrapper, so this match is already a part of other widget.
From bbebc14db5ebdb864770cd7fb272dd621eb7f871 Mon Sep 17 00:00:00 2001
From: Szymon Cofalik
Date: Mon, 15 Jun 2015 08:29:05 +0200
Subject: [PATCH 09/11] Widget plugin change private function name.
---
plugins/widget/plugin.js | 26 +++++++++++---------------
tests/plugins/widget/nestedwidgets.js | 4 ++--
2 files changed, 13 insertions(+), 17 deletions(-)
diff --git a/plugins/widget/plugin.js b/plugins/widget/plugin.js
index e1836d96d16..4887bd91f04 100644
--- a/plugins/widget/plugin.js
+++ b/plugins/widget/plugin.js
@@ -1205,7 +1205,7 @@
*/
initEditable: function( editableName, definition ) {
// Don't fetch just first element which matched selector but look for a correct one. (#13334)
- var editable = this.findCorrectEditable( definition.selector );
+ var editable = this._findOneNotNested( definition.selector );
if ( editable && editable.is( CKEDITOR.dtd.$editable ) ) {
editable = new NestedEditable( this.editor, editable, {
@@ -1247,46 +1247,42 @@
},
/**
- * Looks inside wrapper element to find a correct element that matches the selector.
- * Correct element should not be inside another widget's wrapper because then it is
- * already a part of other widget.
- * The path from a matched element to the wrapper element of this widget is checked,
- * looking of other wrappers. (#13334)
+ * Looks inside wrapper element to find a node that
+ * matches given selector and is not nested in other widget. (#13334)
*
* @since 4.5
* @private
* @param {String} selector Selector to match.
- * @returns {CKEDITOR.dom.node} Node which matches given selector and is not a part of other widget or
- * null if such node has not been found.
+ * @returns {CKEDITOR.dom.node} Matched node or null if a node has not been found.
*/
- findCorrectEditable: function( selector ) {
- var editable = null,
+ _findOneNotNested: function( selector ) {
+ var match = null,
parents;
var matchedElements = this.wrapper.find( selector );
for ( var i = 0; i < matchedElements.count(); i++ ) {
- editable = matchedElements.getItem( i );
+ match = matchedElements.getItem( i );
- parents = editable.getParents( true, this.wrapper );
+ parents = match.getParents( true, this.wrapper );
// Don't include wrapper element.
parents.pop();
for ( var j = 0; j < parents.length; j++ ) {
// One of parents is a widget wrapper, so this match is already a part of other widget.
if ( Widget.isDomWidgetWrapper( parents[ j ] ) ) {
- editable = null;
+ match = null;
break;
}
}
// The first match is a good match.
// Other matches are probably parts of other widgets instances.
- if ( editable != null )
+ if ( match != null )
break;
}
- return editable;
+ return match;
},
/**
diff --git a/tests/plugins/widget/nestedwidgets.js b/tests/plugins/widget/nestedwidgets.js
index c1be19b6af1..83cc23328cf 100644
--- a/tests/plugins/widget/nestedwidgets.js
+++ b/tests/plugins/widget/nestedwidgets.js
@@ -363,8 +363,8 @@
this.editorBots.editor.setData( editorHtml, function() {
var widget = getWidgetById( editor, 'test_findCorrectEditable' );
- var col1 = widget.findCorrectEditable( '.col1' );
- var col2 = widget.findCorrectEditable( '.col2' );
+ var col1 = widget._findOneNotNested( '.col1' );
+ var col2 = widget._findOneNotNested( '.col2' );
// .col1 is only in another widget so it should not be found.
assert.areSame( null, col1, 'findCorrectEditable for selector .col1 returns' );
From 771d93a9254df1f5ef46594bfe76fc33effbc61e Mon Sep 17 00:00:00 2001
From: Artur Delura
Date: Mon, 15 Jun 2015 10:07:33 +0200
Subject: [PATCH 10/11] Tests: Updated comments and test name.
---
tests/plugins/widget/nestedwidgets.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/tests/plugins/widget/nestedwidgets.js b/tests/plugins/widget/nestedwidgets.js
index 83cc23328cf..698a72c99db 100644
--- a/tests/plugins/widget/nestedwidgets.js
+++ b/tests/plugins/widget/nestedwidgets.js
@@ -346,7 +346,7 @@
} );
},
- 'test findCorrectEditable': function() {
+ 'test findOneNotNested': function() {
var editor = this.editors.editor;
var editorHtml =
@@ -367,10 +367,10 @@
var col2 = widget._findOneNotNested( '.col2' );
// .col1 is only in another widget so it should not be found.
- assert.areSame( null, col1, 'findCorrectEditable for selector .col1 returns' );
+ assert.areSame( null, col1, 'findOneNotNested for selector .col1 returns' );
- // findCorrectEditable should find .col2 which is not in another widget.
- assert.areSame( 'uppercol2', col2.getId(), 'findCorrectEditable returned .col2 with id' );
+ // findOneNotNested should find .col2 which is not in another widget.
+ assert.areSame( 'uppercol2', col2.getId(), 'findOneNotNested returned .col2 with id' );
} );
},
From 6cf653826ad617504781f1468fb450cc072a3d37 Mon Sep 17 00:00:00 2001
From: Artur Delura
Date: Mon, 15 Jun 2015 11:14:53 +0200
Subject: [PATCH 11/11] Changelog entry.
---
CHANGES.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGES.md b/CHANGES.md
index 8f2bdc0880d..cd4bb4aec85 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -12,6 +12,7 @@ New Features:
Fixed Issues:
+* [#13334](http://dev.ckeditor.com/ticket/13334): Fixed: Error after nesting widgets and playing with undo/redo.
* [#13118](http://dev.ckeditor.com/ticket/13118): Fixed: The [`editor.getSelectedHtml()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-getSelectedHtml) method throws error when called in the source mode.
* [#13158](http://dev.ckeditor.com/ticket/13158): Fixed: Error after canceling dialog when creating a widget.
* [#13197](http://dev.ckeditor.com/ticket/13197): Fixed: Linked inline image2's alignment class is not transferred to widget wrapper.