Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Loading ImageResize before ImageStyle might lead to crash #8270

Closed
ansorensen opened this issue Oct 15, 2020 · 7 comments · Fixed by #8819
Closed

Loading ImageResize before ImageStyle might lead to crash #8270

ansorensen opened this issue Oct 15, 2020 · 7 comments · Fixed by #8819
Assignees
Labels
package:image squad:core Issue to be handled by the Core team. type:bug This issue reports a buggy (incorrect) behavior.

Comments

@ansorensen
Copy link

I'm dealing with a computer generated HTML source that sometimes leads to poorly formed HTML. In some cases, CKEditor will ignore items that have this issues. However, the image and image-resize packages seem brittle and crash the whole editor with they encounter a problem.

📝 Provide a description of the improvement

As a short term, I'd could use some tips on how to create a plugin that can screen out tags with no source, or <figure class="image image_resized" style="width:331px;"></figure>. Create an elementToElement conversion with an upcast helper that returns null for images with no sources works fine. But then I need to handle the case of figures that got resized and no longer have an image. More details in what I have tried before.

In the long term, I suggest we check for image sources before using them (or throw an error that can be displayed in the console without crashing the entire editor). Same with checking that children of a figure element exist before performing operations on them.

How the feature works now and what you'd like to change?

I have these two test cases:

`

`

The first case, , I can deal with just fine with this plugin code:

editor.conversion.for( 'upcast' ).elementToElement( { view: { name: 'img', attribute: { src: false } }, model: ( viewImage, modelWriter ) => null, priority: 'high' } );

However, when I try to convert

elements with no image children, I get an error from the image-resize package (goes away when I comment out that package in the plugin list). Here's the error:

// removes figures without children editor.conversion.for( 'upcast' ).elementToElement( { view: (element) => { if(element.name === 'figure' && element.childCount === 0) { return { name: true}; } return null; }, model: ( viewFigure, modelWriter ) => null, priority: 'highest' } );

The above code does seem to run without throwing errors, but some how it still does not actually prevent image-resizing from erroring on the childless figure. Here's the error:

`index.html:42 CKEditorError: unexpected-error {"originalError":{"message":"Cannot read property 'getAncestors' of null","stack":"TypeError: Cannot read property 'getAncestors' of null\n at new SchemaContext (http://127.0.0.1:5500/build/ch-editor.js:73253:25)\n at Schema.on.priority (http://127.0.0.1:5500/build/ch-editor.js:71803:17)\n at Schema.fire (http://127.0.0.1:5500/build/ch-editor.js:131491:33)\n at Schema. [as checkAttribute] (http://127.0.0.1:5500/build/ch-editor.js:133759:19)\n at UpcastDispatcher. (http://127.0.0.1:5500/build/ch-editor.js:99538:31)\n at UpcastDispatcher.fire (http://127.0.0.1:5500/build/ch-editor.js:131491:33)\n at UpcastDispatcher._convertItem (http://127.0.0.1:5500/build/ch-editor.js:52946:14)\n at UpcastDispatcher._convertChildren (http://127.0.0.1:5500/build/ch-editor.js:52984:27)\n at UpcastDispatcher. (http://127.0.0.1:5500/build/ch-editor.js:53889:49)\n at UpcastDispatcher.fire (http://127.0.0.1:5500/build/ch-editor.js:131491:33)","name":"TypeError"}}
at Function.rethrowUnexpectedError (http://127.0.0.1:5500/build/ch-editor.js:127397:13)
at Schema.fire (http://127.0.0.1:5500/build/ch-editor.js:131523:62)
at Schema. [as checkAttribute] (http://127.0.0.1:5500/build/ch-editor.js:133759:19)
at UpcastDispatcher. (http://127.0.0.1:5500/build/ch-editor.js:99538:31)
at UpcastDispatcher.fire (http://127.0.0.1:5500/build/ch-editor.js:131491:33)
at UpcastDispatcher._convertItem (http://127.0.0.1:5500/build/ch-editor.js:52946:14)
at UpcastDispatcher._convertChildren (http://127.0.0.1:5500/build/ch-editor.js:52984:27)
at UpcastDispatcher. (http://127.0.0.1:5500/build/ch-editor.js:53889:49)
at UpcastDispatcher.fire (http://127.0.0.1:5500/build/ch-editor.js:131491:33)
at UpcastDispatcher._convertItem (http://127.0.0.1:5500/build/ch-editor.js:52950:14)
(anonymous) @ index.html:42
Promise.catch (async)
(anonymous) @ index.html:41
ckeditorerror.js:15 Uncaught CKEditorError: unexpected-error {"originalError":{"message":"Cannot read property 'is' of undefined","stack":"TypeError: Cannot read property 'is' of undefined\n at isWidget (http://127.0.0.1:5500/build/ch-editor.js:135173:13)\n at Widget._onMousedown (http://127.0.0.1:5500/build/ch-editor.js:135740:67)\n at Document. (http://127.0.0.1:5500/build/ch-editor.js:135687:35)\n at Document.fire (http://127.0.0.1:5500/build/ch-editor.js:131491:33)\n at MouseObserver.fire (http://127.0.0.1:5500/build/ch-editor.js:88643:23)\n at MouseObserver.onDomEvent (http://127.0.0.1:5500/build/ch-editor.js:89276:12)\n at ProxyEmitter._this2.listenTo.useCapture (http://127.0.0.1:5500/build/ch-editor.js:88622:20)\n at ProxyEmitter.fire (http://127.0.0.1:5500/build/ch-editor.js:131491:33)\n at HTMLDivElement.domListener (http://127.0.0.1:5500/build/ch-editor.js:129156:13)","name":"TypeError"}}
at Function.rethrowUnexpectedError (http://127.0.0.1:5500/build/ch-editor.js:127397:13)
at Document.fire (http://127.0.0.1:5500/build/ch-editor.js:131523:62)
at MouseObserver.fire (http://127.0.0.1:5500/build/ch-editor.js:88643:23)
at MouseObserver.onDomEvent (http://127.0.0.1:5500/build/ch-editor.js:89276:12)
at ProxyEmitter._this2.listenTo.useCapture (http://127.0.0.1:5500/build/ch-editor.js:88622:20)
at ProxyEmitter.fire (http://127.0.0.1:5500/build/ch-editor.js:131491:33)
at HTMLDivElement.domListener (http://127.0.0.1:5500/build/ch-editor.js:129156:13)

Is there a way without CKEditor5 to screen out junk HTML before brittle plugins like image-resize run? Admittedly, I could perform an operation outside of CKEditor5 using some fancy regex on the string... however, I'd rather have this logic packaged with ckeditor so that it doesn't get accidentally forgotten in some editor instances.

📃 Other details

  • Browser: Chrome
  • OS: Mac
  • CKEditor version: 15.0.0
  • Installed CKEditor plugins: Image, Image Resize

If you'd like to see this improvement implemented, add a 👍 reaction to this post.

@ansorensen ansorensen added the type:improvement This issue reports a possible enhancement of an existing feature. label Oct 15, 2020
@Mgsy
Copy link
Member

Mgsy commented Oct 19, 2020

Hi, thanks for the detailed report. In order to start investigating it, I'd like to ask you to provide steps to reproduce, so we'll be able to see the issue locally.

@Mgsy Mgsy added the pending:feedback This issue is blocked by necessary feedback. label Oct 19, 2020
@ansorensen
Copy link
Author

ansorensen commented Oct 19, 2020

Steps to reproduce:

  1. Use a classic editor with the image, image styling, and image resize plugins
  2. Create an editor instance with the HTML above that crashes the editor provided on init: <img /> or <figure class="image image_resized" style="width:331px;"></figure>
  3. See errors also listed above.

@Mgsy
Copy link
Member

Mgsy commented Oct 20, 2020

Thanks for the steps! I'm able to reproduce the issue and it seems that it occurs if ImageResize plugin is placed before ImageStyle plugin in plugins array. Could you please confirm that moving ImageResize after ImageStyle solves the issue?

ClassicEditor
    .create( document.querySelector( '#editor' ), {
        plugins: [
           // ...
           ImageStyle,
           ImageResize,
           // ...
        ]
   } );

@Mgsy Mgsy added type:bug This issue reports a buggy (incorrect) behavior. and removed type:improvement This issue reports a possible enhancement of an existing feature. labels Oct 20, 2020
@ansorensen
Copy link
Author

Thanks, the change in plugin order did fix the issue. The order had been:

Image,
ImageToolbar,
ImageResize,
ImageStyle,

which broke, but this order seems to work

Image,
ImageToolbar,
ImageStyle,
ImageResize,

@Mgsy
Copy link
Member

Mgsy commented Oct 21, 2020

Thanks for the confirmation! I'll leave this issue open, as it might be worth investigating.

@Mgsy Mgsy changed the title Image and image resize crash editor with malformed HTML Loading ImageResize before ImageStyle might lead to crash Oct 21, 2020
@Mgsy Mgsy added package:image squad:core Issue to be handled by the Core team. and removed pending:feedback This issue is blocked by necessary feedback. labels Oct 21, 2020
@Reinmar Reinmar added this to the nice-to-have milestone Nov 9, 2020
@maxbarnas maxbarnas self-assigned this Jan 7, 2021
@maxbarnas maxbarnas modified the milestones: nice-to-have, iteration 39 Jan 7, 2021
@maxbarnas
Copy link
Contributor

maxbarnas commented Jan 11, 2021

Converters for plugin ImageStyle and ImageResize have the same priority (low) which makes the order of those plugins relevant. The error we see when ImageResize is the first plugin listed, happens because ImageResize converter, attributeToAttribute, creates a modelRange in one of its helper functions: 0d785a0/packages/ckeditor5-engine/src/conversion/upcasthelpers.js#L896.

Then the condition in ImageStyle converter, that checks if modelRange is empty never stops the converter and subsequently, the schema is checked using a non-existent model element: 0d785a0/packages/ckeditor5-image/src/imagestyle/converters.js#L61.

This is another case (previously: ckeditor/ckeditor5/issues/8393#issuecomment-752125780) where the code assumes that if modelRange is not falsy, we are free to play with its items without checking their existence first. To fix that I can either add another condition or implement something more elaborate - I am open to suggestions.

@niegowski
Copy link
Contributor

We can simply skip upcasting if there is no modelImageElement because this happens only for incomplete image HTML that won't get upcasted anyway. https://github.com/ckeditor/ckeditor5/blob/0d785a0/packages/ckeditor5-image/src/imagestyle/converters.js#L61.

niegowski added a commit that referenced this issue Jan 14, 2021
Fix (image): Image plugins can be loaded in any order without causing an error. Closes #8270.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package:image squad:core Issue to be handled by the Core team. type:bug This issue reports a buggy (incorrect) behavior.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants