From d99f1567747c3b80d62d886be1d46bba56b27ad5 Mon Sep 17 00:00:00 2001 From: Aleksander Nowodzinski Date: Fri, 10 Jan 2014 15:06:25 +0100 Subject: [PATCH 1/5] Extended htmlParser's filter with excludeNestedEditable configuration option. --- core/htmlparser/element.js | 6 +++++- core/htmlparser/filter.js | 16 ++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/core/htmlparser/element.js b/core/htmlparser/element.js index 77ac453fbbd..3a92c02f4f2 100644 --- a/core/htmlparser/element.js +++ b/core/htmlparser/element.js @@ -484,7 +484,8 @@ CKEDITOR.htmlParser.cssStyle = function() { if ( !ctx ) { ctx = { off: false, - nonEditable: false + nonEditable: false, + nestedEditable: false }; } @@ -493,6 +494,9 @@ CKEDITOR.htmlParser.cssStyle = function() { if ( !ctx.nonEditable && this.attributes[ 'contenteditable' ] == 'false' ) changes.push( 'nonEditable', true ); + // A context to be given nestedEditable must be nonEditable first (by inheritance). + else if ( !ctx.nestedEditable && this.attributes[ 'contenteditable' ] == 'true' ) + changes.push( 'nestedEditable', true ); if ( changes.length ) { ctx = CKEDITOR.tools.copy( ctx ); diff --git a/core/htmlparser/filter.js b/core/htmlparser/filter.js index cad8383b471..06d28a07180 100644 --- a/core/htmlparser/filter.js +++ b/core/htmlparser/filter.js @@ -390,8 +390,20 @@ } function isRuleApplicable( context, rule ) { - // Do not apply rule if context is nonEditable and rule doesn't have applyToAll option. - return !context.nonEditable || rule.options.applyToAll; + if ( context.nonEditable ) { + // Do not apply rule if context is nonEditable and rule doesn't have applyToAll option. + if ( rule.options.applyToAll ) { + // Do not apply the rule if context is nestedEditable and the rule **has** excludeNestedEditable option. + if ( context.nestedEditable ) + return !rule.options.excludeNestedEditable; + + return true; + } + + return false; + } + + return true; } } )(); From d0da5bab705be2dfbc77929f76300ed1875015a3 Mon Sep 17 00:00:00 2001 From: Aleksander Nowodzinski Date: Fri, 10 Jan 2014 17:04:18 +0100 Subject: [PATCH 2/5] Postponed downcast of nestededitables to give "excludeNestedEditable" in dataFilter a chance to recognize nested editables. --- plugins/widget/plugin.js | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/plugins/widget/plugin.js b/plugins/widget/plugin.js index c962f29b65c..cab5a7e955b 100644 --- a/plugins/widget/plugin.js +++ b/plugins/widget/plugin.js @@ -2234,7 +2234,8 @@ toBeDowncasted.push( { wrapper: element, element: widgetElement, - widget: widget + widget: widget, + editables: {} } ); // If widget did not have data-cke-widget attribute before upcasting remove it. @@ -2244,11 +2245,11 @@ } // Nested editable. else if ( 'data-cke-widget-editable' in attrs ) { - delete attrs[ 'contenteditable' ]; - - // Replace nested editable's content with its output data. - var editable = toBeDowncasted[ toBeDowncasted.length - 1 ].widget.editables[ attrs[ 'data-cke-widget-editable' ] ]; - element.setHtml( editable.getData() ); + // Save the reference to this nested editable in the closest widget to be downcasted. + // Nested editables are downcasted in the successive toDataFormat to create an opportunity + // for dataFilter's "excludeNestedEditable" option to do its job (that option relies on + // contenteditable="true" attribute) (#11372). + toBeDowncasted[ toBeDowncasted.length - 1 ].editables[ attrs[ 'data-cke-widget-editable' ] ] = element; // Don't check children - there won't be next wrapper or nested editable which we // should process in this session. @@ -2265,13 +2266,21 @@ return; var toBeDowncasted = downcastingSessions[ evt.data.downcastingSessionId ], - toBe, widget, widgetElement, retElement; + toBe, widget, widgetElement, retElement, editableElement, e; while ( ( toBe = toBeDowncasted.shift() ) ) { widget = toBe.widget; widgetElement = toBe.element; retElement = widget._.downcastFn && widget._.downcastFn.call( widget, widgetElement ); + // Replace nested editables' content with their output data. + for ( e in toBe.editables ) { + editableElement = toBe.editables[ e ]; + + delete editableElement.attributes[ 'contenteditable' ]; + editableElement.setHtml( widget.editables[ e ].getData() ); + } + // Returned element always defaults to widgetElement. if ( !retElement ) retElement = widgetElement; From cf35ab3cfa0549cd8d6f686fdead1d2f5b202ffc Mon Sep 17 00:00:00 2001 From: Aleksander Nowodzinski Date: Fri, 10 Jan 2014 15:08:07 +0100 Subject: [PATCH 3/5] Use excludeNestedEditable for filtering rules to avoid duplicated replacements in Entities plugin. --- plugins/entities/plugin.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/entities/plugin.js b/plugins/entities/plugin.js index 26d4c828bc7..c8b783baba0 100644 --- a/plugins/entities/plugin.js +++ b/plugins/entities/plugin.js @@ -151,7 +151,10 @@ text: function( text ) { return text.replace( baseEntitiesRegex, getChar ).replace( entitiesRegex, getEntity ); } - }, { applyToAll: true } ); + }, { + applyToAll: true, + excludeNestedEditable: true + } ); } } } ); From 1fcf5f16c1a9ed283a1bd714d6041c3e57aff310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotrek=20Reinmar=20Koszuli=C5=84ski?= Date: Mon, 13 Jan 2014 13:58:01 +0100 Subject: [PATCH 4/5] Made context independent. --- core/htmlparser/filter.js | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/core/htmlparser/filter.js b/core/htmlparser/filter.js index 06d28a07180..02e7f5a403f 100644 --- a/core/htmlparser/filter.js +++ b/core/htmlparser/filter.js @@ -390,18 +390,11 @@ } function isRuleApplicable( context, rule ) { - if ( context.nonEditable ) { - // Do not apply rule if context is nonEditable and rule doesn't have applyToAll option. - if ( rule.options.applyToAll ) { - // Do not apply the rule if context is nestedEditable and the rule **has** excludeNestedEditable option. - if ( context.nestedEditable ) - return !rule.options.excludeNestedEditable; - - return true; - } + if ( context.nonEditable && !rule.options.applyToAll ) + return false; + if ( context.nestedEditable && rule.options.excludeNestedEditable ) return false; - } return true; } From d7507d9d070a0b4a779526f7695ccfc3caaa103d Mon Sep 17 00:00:00 2001 From: Aleksander Nowodzinski Date: Mon, 13 Jan 2014 15:44:16 +0100 Subject: [PATCH 5/5] Changelog entry. --- CHANGES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 687f677f3ac..a8400dae6d6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -26,7 +26,8 @@ CKEditor 4 Changelog * [#10787](http://dev.ckeditor.com/ticket/10787): [Firefox] Fixed: Broken replacement of text while pasting into div-based editor. * [#10884](http://dev.ckeditor.com/ticket/10884): Widgets integration with [Showblocks](http://ckeditor.com/addon/showblocks) plugin. * [#11021](http://dev.ckeditor.com/ticket/11021): Fixed: An error thrown when selecting entire editable's contents while fake selection is on. -* [#11086](http://dev.ckeditor.com/ticket/11086): [IE8]Re enable inline widgets drag & drop on IE8. +* [#11086](http://dev.ckeditor.com/ticket/11086): [IE8] Re-enable inline widgets drag&drop on IE8. +* [#11372](http://dev.ckeditor.com/ticket/11372): Widgets: Special characters encoded twice in nested editables. ## CKEditor 4.3.1