🇨🇦Canada @Cottser

Account created on 13 February 2011, over 13 years ago
#

Recent comments

🇨🇦Canada Cottser

I'm going to close this for now. Not to say "never", but to say "not right now". Thank you for the feature request!

🇨🇦Canada Cottser

Great, thanks for following up!

🇨🇦Canada Cottser

Specifically, and I'm not sure the quickest way to test this myself, but something like:

$ $CI_PROJECT_DIR/$_WEB_ROOT/modules/custom/$CI_PROJECT_NAME/node_modules/.bin/eslint --no-error-on-unmatched-pattern --ignore-pattern="*.es6.js" --resolve-plugins-relative-to=$CI_PROJECT_DIR/$_WEB_ROOT/core --ext=.js,.yml --format=junit --output-file=$CI_PROJECT_DIR/junit.xml $_ESLINT_EXTRA . || EXIT_CODE_FILE=$?

🇨🇦Canada Cottser

Thanks for following up! I see what you mean, the current working directory in that CI job is indeed the module (what I'm calling project in the Drupal.org sense because it could be a theme, or other) directory.

I was referring to this command:

$ $CI_PROJECT_DIR/$_WEB_ROOT/core/node_modules/.bin/eslint --no-error-on-unmatched-pattern --ignore-pattern="*.es6.js" --resolve-plugins-relative-to=$CI_PROJECT_DIR/$_WEB_ROOT/core --ext=.js,.yml --format=junit --output-file=$CI_PROJECT_DIR/junit.xml $_ESLINT_EXTRA . || EXIT_CODE_FILE=$?

What I was suggesting is: Although it would only work with the correct dependencies in place in the module's directory, would running eslint from the node_modules of the module help?

🇨🇦Canada Cottser

Having said that, to get this working with eslint-config-drupal, might it just be a matter of running eslint from the project directory rather than core?

🇨🇦Canada Cottser

Reviewing other comments here, maybe what I should do is adopt https://www.npmjs.com/package/eslint-plugin-drupal-contrib and we should adopt others to do the same?

🇨🇦Canada Cottser

I just want to mention that https://www.npmjs.com/package/eslint-config-drupal hasn't been updated since October 15, 2020 but is still recommended in official documentation: https://www.drupal.org/node/1955232 →

https://github.com/theodoreb/eslint-config-drupal/issues/6 seems relevant, because eslint-config-drupal is bringing in dependencies that aren't in core (such as eslint-plugin-jsx-a11y).

🇨🇦Canada Cottser

Thanks for the report and for using the issue template.

I can’t easily test this at the moment but I suspect it’s essentially the same issue as 🐛 Pasting from Google Docs doesn't preserve some formatting Closed: won't fix , please see my first comment there.

The short version is that when you copy the rich text, strong and em are represented as span tags with inline styles. If you don’t remove inline styles ((<[^>]*) (style="[^"]*") expression), then CKEditor 5 converts these to strong and em based on the inline styles matching certain criteria. Since that expression and its replacement does remove inline styles, CKEditor 5 doesn’t have the data it needs to determine the tag type based on the span.

🇨🇦Canada Cottser

I'd be happy with a closed status too :)

At the time it was just an idea, and I agree it's too late.

Thanks @bnjmnm!

🇨🇦Canada Cottser

Another possible approach would be to try to detect the source of the pasted HTML and only filter when certain sources (like MS Word or Google Docs) are detected.

I know CKEditor 5 itself uses logic like this for its paste from office plugin but it's also very easy to get bad markup from other sources, so I'm not totally sure if I want to implement this. Maybe as an opt-in feature with a warning that it only works for Microsoft Word and Google Docs. https://github.com/ckeditor/ckeditor5/blob/e71971206bb3e7e176692a1b973a4...

🇨🇦Canada Cottser

Hi @jacobupal! Thanks for writing this up.

I don't currently have any plans or desire to add this feature. Having a separate "paste from word" style button relies on people remembering it's there and using it. I think your idea of making more specific filter rules for your use case makes the most sense for your use case at this time.

Depending on the details of your use case, perhaps a global permission to allow users to skip filtering would be a simpler implementation. This has its own issues and complexities (administrators would get this permission by default) so I'm not fully sold on it either. It's just an idea at this point.

Some other workarounds to mention that should work with the current code, other than customizing rules or using multiple text formats:

  • Drag and drop the content around inside the editor instead (admittedly cut/copy/paste is just better for some cases and perhaps more accessible, but I think it's worth mentioning)
  • Move content around in the source editor instead
🇨🇦Canada Cottser

I forgot to reference this issue in my commit but: https://git.drupalcode.org/project/ckeditor5_paste_filter/-/commit/f1669...

Keeping this open in case the bot has any other suggestions.

🇨🇦Canada Cottser

This issue is specific to inline entity form (or at least forms-within-forms), it could potentially be incorporated into the linked issue at a later time, but I don't want to add to the confusion at this point.

🇨🇦Canada Cottser

Hi folks, I won’t be able to get back to this until sometime next week. If you want some data sooner feel free to open an MR against this project! From my understanding the existing MR can’t be turned into an issue fork MR but I might be wrong.

🇨🇦Canada Cottser

Hi, I think it might be a misunderstanding.

This module will filter rich text content pasted into the visual editor (WYSIWYG). If you paste plain text (HTML) into the visual editor, there's no rich text to filter.

One way to test and see what the module is doing would be to follow these steps:

  1. Visit https://developer.mozilla.org/en-US/docs/Web/HTML/Element/span#try_it
  2. Select and copy the content in the Output pane (where some words are highlighted in red)
  3. Navigate to your Drupal site where the CKEditor 5 instance is that you want to test, for example node add form
  4. Paste the content in your clipboard into the CKEditor 5 visual editor (WYSIWYG, not source editor)

If you follow these steps without this module installed (or with it disabled), the <span> tags will be preserved. With this modules installed, enabled and with the default filters, the <span> tags will be removed!

If you have another use case like filtering when you paste into the source editor, I'm not sure offhand what is possible there but that is different functionality.

🇨🇦Canada Cottser

Attaching an updated patch that properly handles the field specificity (otherwise errors on all fields within the IEF will be skipped) and adds one defensive check.

🇨🇦Canada Cottser

Here: https://git.drupalcode.org/project/ckeditor5_paste_filter/-/pipelines/12...

It looks like it still ran but I didn’t dig into it. Let me know if I can be of any further help.

🇨🇦Canada Cottser

Hi @jonathan1055 it looks like that’s been merged, would you still like me to test?

As for this issue in general, I am hoping to work on GitLab CI things within the next month or two.

🇨🇦Canada Cottser

I think the direction makes sense. I agree that the way it used to work might be called “overbearing” or similar. Thanks for all your work @dqd!

🇨🇦Canada Cottser

I was just debugging some of this code with a colleague and I have to say it seems the existing code seems to support the use case.

I don't want to stoke the flames here, but it just doesn't seem right to call this a feature request when there is so much code that appears to now be dead code (admittedly I have not tested every use case) thanks to the hastily-added return statement in 🐛 URL validation of link field doesn't work Fixed

https://git.drupalcode.org/project/conditional_fields/-/blob/f988abcf081...

Of course dependentValidate() as well.

🇨🇦Canada Cottser

Thanks for sharing, using a custom CKEditor 5 plugin that executes before our paste filter plugin is a viable approach (or just your custom plugin if you don't need any other paste filtering, no judgment!).

In a perfect world I would love to use the DOM instead of regular expressions for all of our paste filtering, but maintaining the same level of customization we currently have with the UI seems nearly impossible, and it would also make this module significantly more complex.

For specific use cases like this, at this time I am recommending that folks create a custom CKEditor 5 plugin.

🇨🇦Canada Cottser

Minor, but could you please correct the capitalization of the link text:

CKeditor 5 Paste Filter

Should be:

CKEditor 5 Paste Filter

🇨🇦Canada Cottser

@nkraft just to be sure, are you testing HTML comments along with other content? If the editor contains only an HTML comment it will still be stripped because CKEditor 5 doesn’t see any content to render.

🇨🇦Canada Cottser

Marking as fixed as I believe I have addressed the support request and there have been no further questions or follow-up. Thanks!

🇨🇦Canada Cottser

Marking as fixed as I believe I have addressed the support request and there have been no further questions or follow-up. Thanks!

🇨🇦Canada Cottser

Marking as fixed as I believe I have addressed the support request and there have been no further questions or follow-up. Thanks!

🇨🇦Canada Cottser

@annoul4 I have an idea what is happening, but would like to confirm before trying to explain fully. Overall I believe the filtering is working as expected. I suspect CKEditor 5 is transforming your filtered markup in a way that you are not expecting.

Overall I suspect you will both want something different from this module for removing empty paragraphs. Perhaps https://www.drupal.org/project/emptyparagraphkiller → is worth considering, or something similar could be implemented as a custom CKEditor 5 plugin.

🇨🇦Canada Cottser

I’m going to need more information. Please fill out the issue summary template so I can try to help you! You can see it when you create a new issue.

One possibility to keep in mind is that CKEditor 5 might be inserting these empty paragraphs after pasting.

🇨🇦Canada Cottser

Thank you for the detailed bug report and for making use of the issue summary template!

I was able to reproduce this behaviour and the root cause is how Google Docs sends its content to the pasteboard and I don't think much can be done about it within the scope of this module. You may be able to get it to work as you expect with some creative custom filters to preserve more of the formatting based on the original markup coming out of Google Docs, or by creating a custom CKEditor 5 plugin.

In short, our module and plugin is working as expected, but CKEditor 5 has its own magic that makes it seem like it should work differently. I'll break down the details below.

Google docs uses <span> tags to convey all its formatting rather than semantic tags (<strong>/<b> or <em> <i>) as we might expect.

If we leave the span tags and attributes as-is by not filtering them out (your without filtering example), CKEditor 5 sees the span tags with specific style attributes from Google docs and turns them into the corresponding semantic tags. For example, font-style: italic should be converted to <em>. Since our default style removal filter removes all the style attributes before this transformation process, CKEditor 5 no longer has the data it needs to create the semantic tags and therefore does not preserve the formatting.

The example I'm testing with uses the following text in a Google doc:

This is a new paragraph that has bold and italic text.

Below is the markup that can be seen at the ClipboardPipeline#inputTransformation event. This is the same event that our module acts on to do its filtering of the pasted content. The markup at this stage can be seen below and has been run through prettier to make it a bit easier to read.

<p
  style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt"
  dir="ltr"
  id="docs-internal-guid-21dbe10f-7fff-36cd-034d-5b586bd69b9f"
>
  <span
    style="
      background-color: transparent;
      color: #000000;
      font-family: Arial, sans-serif;
      font-size: 11pt;
      font-style: normal;
      font-variant: normal;
      font-weight: 400;
      text-decoration: none;
      vertical-align: baseline;
      white-space: pre-wrap;
    "
    >This is a new paragraph that has&nbsp;</span
  ><span
    style="
      background-color: transparent;
      color: #000000;
      font-family: Arial, sans-serif;
      font-size: 11pt;
      font-style: normal;
      font-variant: normal;
      font-weight: 700;
      text-decoration: none;
      vertical-align: baseline;
      white-space: pre-wrap;
    "
    >bold</span
  ><span
    style="
      background-color: transparent;
      color: #000000;
      font-family: Arial, sans-serif;
      font-size: 11pt;
      font-style: normal;
      font-variant: normal;
      font-weight: 400;
      text-decoration: none;
      vertical-align: baseline;
      white-space: pre-wrap;
    "
  >
    and&nbsp;</span
  ><span
    style="
      background-color: transparent;
      color: #000000;
      font-family: Arial, sans-serif;
      font-size: 11pt;
      font-style: italic;
      font-variant: normal;
      font-weight: 400;
      text-decoration: none;
      vertical-align: baseline;
      white-space: pre-wrap;
    "
    >italic</span
  ><span
    style="
      background-color: transparent;
      color: #000000;
      font-family: Arial, sans-serif;
      font-size: 11pt;
      font-style: normal;
      font-variant: normal;
      font-weight: 400;
      text-decoration: none;
      vertical-align: baseline;
      white-space: pre-wrap;
    "
  >
    text.</span
  >
</p>
🇨🇦Canada Cottser

(Hiding patches from the issue summary)

🇨🇦Canada Cottser

Core has a job that ensures compiled JS has been recompiled if needed: https://git.drupalcode.org/project/drupal/-/blob/02f6f6c68810136d707492c...

🇨🇦Canada Cottser

I decided to do both. I released 1.0.0-rc1 today and will plan to release 1.0.0 in a week or so if no critical issues are found in the release candidate.

Keeping this open until 1.0.0 is out.

🇨🇦Canada Cottser

This seems like a reasonable request. There have been no recent bug reports and the usage numbers keep steadily increasing so it does seem like a good time to cut a stable release.

We also don't have an API or upgrade path to consider: https://www.drupal.org/docs/develop/git/git-for-drupal-project-maintaine... →

I plan to cut a new release in the next week or so, either an rc or stable.

🇨🇦Canada Cottser

Thanks @Wim Leers!

Re: Nightwatch, I can sometimes trigger the failure locally, both with these changes and on 11.x. So it does seem unreliable/random.

This test specifically: core/tests/Drupal/Nightwatch/Tests/Olivero/oliveroSearchFormTest.js

🇨🇦Canada Cottser

Same failure as last time, in Tests/Olivero/oliveroSearchFormTest. https://git.drupalcode.org/issue/drupal-3342874/-/jobs/288500#L174

🇨🇦Canada Cottser

If we remove the Nightwatch change it should be failing every time, in other words we need that change. I'm going to try running Nightwatch again.

🇨🇦Canada Cottser

I was seeing a failure in TimestampFormatterWithTimeDiffTest and one other similar one, seems like a random fail, re-ran and it passed. I re-ran Nightwatch and the failure switched from one to another so also seems random.

🇨🇦Canada Cottser

Hi @Wim Leers! This year I have been leading the project on our team to integrate CKEditor 5 which has involved porting and updating a contrib module → , adding table footer support to CKEditor 5 upstream, a few custom CKEditor plugins, and now this issue! So I suppose it was inevitable we would run into each other and it’s always nice to see a friendly face in the queues (and on GitHub)!

I will work on the test coverage, and agree that it’s missing.

Oh and thanks for adding the related issue. I did that at one point but had to fight with this form a bit (hence why it says there are so many patches from me in Credit & committing, I believe).

🇨🇦Canada Cottser

I found that our core drupalHtmlEngine plugin is stripping out the comments. Tracing it back this was originally added in #3247246: Attribute value encoding not compatible with Xss::filter() → . I've added HTML comment support to the drupalHtmlEngine plugin. I'm not 100% sure about the approach, feedback please!

I opened an MR to make code review easier and I'm attaching a patch with the same changes.

Testing note: If you test by adding only an HTML comment to the editor with no other content, it will still be removed. You need to add something else: an HTML element or text for example. This seems to be the case for the upstream plugin as well so I don't think that bug is on our side: https://ckeditor.com/docs/ckeditor5/latest/features/html/html-comments.html

Issue management note: I'm removing 'upstream' from the title because I think we have what we need to implement this but I do realize there are known issues with the upstream plugin and it's experimental. Maybe we can get something into core and then open another issue to track the known upstream issues?

🇨🇦Canada Cottser

star-szr → made their first commit to this issue’s fork.

🇨🇦Canada Cottser

Shout out to @Wim Leers who is doing some fantastic work in GitLab CI land.

This looks nice for the please fail if phpcs fails part: https://git.drupalcode.org/project/big_pipe_sessionless/-/blob/02e2d957d...

And this does not look that nice yet, but with some more work → I think it will be much cleaner and the testing setup closely aligns with ours (Nightwatch only): https://git.drupalcode.org/project/decoupled_pages/-/blob/9dfe432d560bff...

🇨🇦Canada Cottser

A couple updates to share here.

This looks nice for testing multiple core versions, but may or may not mesh with my plans around Nightwatch testing with a newer Nightwatch version: #3397129: Allow modules to opt in to testing against Drupal previous major, previous minor, next minor →
Example implementation: https://git.drupalcode.org/project/big_pipe_sessionless/-/commit/0d37437...

It looks like PHPStan support is built-in now and would be trivial to add: #3395419: Allow contrib modules to run PHPStan via GitLab CI →

🇨🇦Canada Cottser

I can't speak as much to the code review aspect (though it does look good to me), but this works great, so marking as RTBC!

🇨🇦Canada Cottser

Ah, nevermind it looks like maybe you merged in 1.0.x or something? Sorry about that, I will leave it alone 😬

🇨🇦Canada Cottser

Thank you @Wim Leers and everyone. Catching up here and I can confirm that these changes fix the issue I reported here originally: https://git.drupalcode.org/project/ckeditor5_paste_filter/-/jobs/265709

_GITLAB_TEMPLATES_REF = 3375359-nightwatch
_GITLAB_TEMPLATES_REPO = issue/gitlab_templates-3375359

I tested by updating the CI variables on GitLab, which required a bit of digging and I think the README for this project needs a minor touch-up. I will be creating a small issue and MR for that.

🇨🇦Canada Cottser

Hi, as noted in the Drupal.org interface text please don’t add random tags.

In addition, please consider using our issue template instead of deleting all of that structure and freestyling when reporting issues.

As for your request, just make use of regular expression features! See below.

Search expression:
<(button|canvas|caption)[^>]*>

🇨🇦Canada Cottser

Hi, I looked quickly and noticed that on regex101 there are different flags set. The help in the UI of this module indicates that we use the gimsu flags.

Once I updated the flags on regex101 to match, their UI showed that there was an unnecessary escaping of a quote and removing the backslash made the replacement work again.

Untested, but try this version: https://regex101.com/r/yUjT7w/1

Regex: (<[^>]*) (data-(\S+)="((?:\\.|[^"\\])*)")

🇨🇦Canada Cottser

If the footnote linking to 2 has a href attribute of “sdendnote2sym” and so on, then it should be possible with a filter to add back the missing number.

If not, it may not be feasible since based on your description Word is actually removing the numbers. When “Filter Pasted Content” is unchecked this module isn’t doing anything to the pasted content.

Untested, but you can try something like the following.

Search expression:
<a href="#sdendnote([0-9]+)sym">&nbsp;<\/a>

Replacement:
<a href="#sdendnote$1sym">$1</a>

🇨🇦Canada Cottser

Hi there, please test the behaviour without filtering enabled. What do the footnotes look like in that case?

Also, can you give an example of what happens to the actual footnotes at the end of the document? I think the markup examples only show the link to the footnote.

🇨🇦Canada Cottser

Also you could consider taking a look at the CKEditor 5 Paste from Office plugin, and evaluate whether you could create your own similar plugin with your own logic for what you want to remove.

This is not likely to be a small undertaking, but if you need a sharper tool than this module provides then it may be a path worth considering.

🇨🇦Canada Cottser

For now, I'm going to close this and ask that you please test again.

To add to my previous comment, I also recently ran the full test suite against core 9.5.x, and have some plans to run the tests regularly against 9.5.x on GitLab CI. Currently those plans are somewhat blocked by #3375359: Nightwatch logout steps fail with default template → .

I also released the latest alpha last week which addressed some user interface and user experience issues like the one mentioned in my previous comment.

🇨🇦Canada Cottser

To get back to your original post/question, you certainly could set up a custom paste filter to remove all text-indent styles, but based on what you are sharing that would only be the tip of the iceberg in terms of what you are trying to achieve.

In the bigger picture you may want to take a few steps back and consider other solutions/workflows for getting this content into Drupal. What you are trying to achieve is not simple or easy. If this is really important to get right for your project, then one solution you may want to consider is the paid CKEditor 5 plugin that allows you to import Word documents: https://ckeditor.com/import-from-word/demo/

I'm only mentioning this as an option to consider, I have not used this plugin myself other than on the demo page, and have no connection with CKEditor 5 or CKSource other than I have written some code that may get incorporated into the CKEditor 5 codebase (currently in a pull request on GitHub).

To get an idea of what we are looking at, let's take the document from your comment #5, if you paste that into CKEditor 5 without this module enabled, you will get something similar to the following.

<p class="MsoNormal">
    <a name="OLE_LINK19"><span class="MsoSubtleEmphasis" style="color:red;mso-bookmark:OLE_LINK1;" lang="EN-US">Test of Word cut/paste</span><span class="MsoSubtleEmphasis" style="color:red;mso-bookmark:OLE_LINK1;mso-spacerun:yes;" lang="EN-US">&nbsp; </span><span class="MsoSubtleEmphasis" style="color:red;mso-bookmark:OLE_LINK1;" lang="EN-US">(color Red, italic)</span></a><o:p></o:p>
</p>
<p class="MsoNormal">
    &nbsp;
</p>
<p class="MsoNormal">
    <span style="mso-bookmark:OLE_LINK1;" lang="EN-US">Content from Word should be converted properly, and these two paragraphs use shift-enter for the spacing which should be one line</span>
    <br>
    <br>
    <span style="mso-bookmark:OLE_LINK1;" lang="EN-US">This second paragraph should only be one line below the first and uses a paragraph break for the next section.</span><o:p></o:p>
</p>
<p class="MsoNormal">
    &nbsp;
</p>
<p class="MsoNormal">
    <span style="mso-bookmark:OLE_LINK1;" lang="EN-US">This third section is separated by 2 paragraph breaks.</span><o:p></o:p>
</p>
<p class="MsoNormal">
    &nbsp;
</p>
<p class="MsoNormal">
    <span style="mso-bookmark:OLE_LINK1;" lang="EN-US"><strong>This is a bullet list: (bold)</strong></span><o:p></o:p>
</p>
<ul>
    <li class="MsoListParagraphCxSpFirst" style="mso-list:l0 level1 lfo1;text-indent:-18.0pt;">
        <span style="mso-bookmark:OLE_LINK1;" lang="EN-US">Item 1</span><o:p></o:p>
    </li>
    <li class="MsoListParagraphCxSpMiddle" style="mso-list:l0 level1 lfo1;text-indent:-18.0pt;">
        <span style="mso-bookmark:OLE_LINK1;" lang="EN-US">Item 2</span>
        <br>
        <span style="mso-bookmark:OLE_LINK1;" lang="EN-US">more about item 2</span><o:p></o:p>
    </li>
    <li class="MsoListParagraphCxSpLast" style="mso-list:l0 level1 lfo1;text-indent:-18.0pt;">
        <span style="mso-bookmark:OLE_LINK1;" lang="EN-US">Item 3</span><o:p></o:p>
    </li>
</ul>
<p class="MsoNormal">
    <span style="color:#00B050;mso-bookmark:OLE_LINK1;" lang="EN-US">End of bullet list.(green)</span><o:p></o:p>
</p>
<p class="MsoNormal">
    &nbsp;
</p>
<p class="MsoNormal">
    <span style="mso-bookmark:OLE_LINK1;" lang="EN-US"><strong>This is a numbered list: (bold)</strong></span><o:p></o:p>
</p>
<ol>
    <li class="MsoListParagraphCxSpFirst" style="mso-list:l1 level1 lfo2;text-indent:-18.0pt;">
        <span style="mso-bookmark:OLE_LINK1;" lang="EN-US">Item 1</span><o:p></o:p>
    </li>
    <li class="MsoListParagraphCxSpMiddle" style="mso-list:l1 level1 lfo2;text-indent:-18.0pt;">
        <span style="mso-bookmark:OLE_LINK1;" lang="EN-US">Item 2</span>
        <br>
        <span style="mso-bookmark:OLE_LINK1;" lang="EN-US">more about Item 2</span><o:p></o:p>
    </li>
    <li class="MsoListParagraphCxSpLast" style="mso-list:l1 level1 lfo2;text-indent:-18.0pt;">
        <span style="mso-bookmark:OLE_LINK1;" lang="EN-US">Item 3</span><o:p></o:p>
    </li>
</ol>
<p class="MsoNormal">
    <span style="color:#0070C0;mso-bookmark:OLE_LINK1;" lang="EN-US">End of numbered list (blue)</span><o:p></o:p>
</p>
<p class="MsoNormal">
    &nbsp;
</p>
<p class="MsoNormal">
    <span style="mso-bookmark:OLE_LINK1;" lang="EN-US">This is an alphabetic list:</span><o:p></o:p>
</p>
<ol style="list-style-type:lower-alpha;">
    <li class="MsoListParagraphCxSpFirst" style="mso-list:l2 level1 lfo3;text-indent:-18.0pt;">
        <span style="mso-bookmark:OLE_LINK1;" lang="EN-US">Item a</span><o:p></o:p>
    </li>
    <li class="MsoListParagraphCxSpMiddle" style="mso-list:l2 level1 lfo3;text-indent:-18.0pt;">
        <span style="mso-bookmark:OLE_LINK1;" lang="EN-US">Item b</span>
        <br>
        <span style="mso-bookmark:OLE_LINK1;" lang="EN-US">more about item b</span><o:p></o:p>
    </li>
    <li class="MsoListParagraphCxSpLast" style="mso-list:l2 level1 lfo3;text-indent:-18.0pt;">
        <span style="mso-bookmark:OLE_LINK1;" lang="EN-US">Item c</span><o:p></o:p>
    </li>
</ol>
<p class="MsoNormal">
    <span style="mso-bookmark:OLE_LINK1;" lang="EN-US">End of alphabetic list</span><o:p></o:p>
</p>
<p class="MsoNormal">
    &nbsp;
</p>
<p class="MsoNormal">
    <span style="mso-bookmark:OLE_LINK1;" lang="EN-US">This is the end of the test document.</span><o:p></o:p>
</p>
<p class="MsoNormal">
    &nbsp;
</p>
<p class="MsoNormal">
    &nbsp;
</p>

This is a mess as you can see, and if you enable this module and use the default settings, you will instead get this:

<p>
    Test of Word cut/paste&nbsp; (color Red, italic)
</p>
<p>
    Content from Word should be converted properly, and these two paragraphs use shift-enter for the spacing which should be one line
    <br>
    <br>
    This second paragraph should only be one line below the first and uses a paragraph break for the next section.
</p>
<p>
    This third section is separated by 2 paragraph breaks.
</p>
<p>
    <strong>This is a bullet list: (bold)</strong>
</p>
<ul>
    <li>
        Item 1
    </li>
    <li>
        Item 2
        <br>
        more about item 2
    </li>
    <li>
        Item 3
    </li>
</ul>
<p>
    End of bullet list.(green)
</p>
<p>
    <strong>This is a numbered list: (bold)</strong>
</p>
<ol>
    <li>
        Item 1
    </li>
    <li>
        Item 2
        <br>
        more about Item 2
    </li>
    <li>
        Item 3
    </li>
</ol>
<p>
    End of numbered list (blue)
</p>
<p>
    This is an alphabetic list:
</p>
<ol>
    <li>
        Item a
    </li>
    <li>
        Item b
        <br>
        more about item b
    </li>
    <li>
        Item c
    </li>
</ol>
<p>
    End of alphabetic list
</p>
<p>
    This is the end of the test document.
</p>

Ah, much better. You are then free to layer on whatever styles you would like, on top of the now-cleaned markup. I think this is what most people will end up doing.

Looking for example at the first line with red and italic, the HTML that Word generates makes it very hard to preserve only the color and italics in a reasonable way. I think the closest we could realistically get with the tools provided by this module would be something like the following, and this would require a decent amount of tinkering with regular expressions and may still be fragile or inconsistent:

Before:

<p class="MsoNormal">
    <a name="OLE_LINK2"><span class="MsoSubtleEmphasis" style="color:red;mso-bookmark:OLE_LINK1;" lang="EN-US">Test of Word cut/paste</span><span class="MsoSubtleEmphasis" style="color:red;mso-bookmark:OLE_LINK1;mso-spacerun:yes;" lang="EN-US">&nbsp;</span><span class="MsoSubtleEmphasis" style="color:red;mso-bookmark:OLE_LINK1;" lang="EN-US">(color Red, italic)</span></a><o:p></o:p>
</p>

After:

<p>
    <em style="color:red;">Test of Word cut/paste</em> <em style="color:red;">(color Red, italic)</em>
</p>

I hope that's helpful.

🇨🇦Canada Cottser

Please test again using the default filter settings. In the example you’ve given I don’t see any styles that need preserving, so if you remove all style attributes that should cleanly solve your issue.

If you want to selectively remove styles from the style attribute using this module, it’s possible but will require a more specific search expression than is provided with the default filter set.

🇨🇦Canada Cottser

Can you provide a screenshot and/or config export of your settings for this module in the text format you are testing?

From what I can see this is not using the default settings, since all style attributes should be filtered out if you’re using the default filter set.

🇨🇦Canada Cottser

Draft change record: https://www.drupal.org/node/3382659 →

Once it's published we can update the older change record to link to this one as well.

🇨🇦Canada Cottser

I forgot to mention in my previous comment I also tested this without JavaScript and it works fine. There is an extra step involved if you want to enable the plugin and then customize the filters, but even without JavaScript it's more clear whether the filters are active or not.

🇨🇦Canada Cottser

I have implemented this just using some #access logic since the form gets reloaded with AJAX when you toggle the checkbox.

I also updated the interface text for the checkbox to try to be more clear:

🇨🇦Canada Cottser

Hi, thanks for the report, yes it's working with 9.5.x. I just tested it with a fresh install of 9.5.x and after installing the module and enabling it for the applicable text format (I used Full HTML), it filters rich text pasted into the editor as expected.

Could you provide any more details about what's not working? Please ensure that you have enabled the plugin on the text format configuration page, I think some people may miss that and we have an issue to improve the UI: 🐛 Hide filter fields when plugin not enabled Fixed

→

On your text format configuration form, the Paste Filter vertical tab should look similar to the screenshot, with the 'Enabled' checkbox at the top checked, it may show a different label if you are using a different UI language.

If 'Enabled' is already checked, please try clearing Drupal caches and see if that helps. I haven't reproduced any caching issue so far, but have had one report that a cache clear helped get things working as expected: #3359423-14: See no effect → .

🇨🇦Canada Cottser

Thanks @Anybody!

This might be a core bug with #states and AJAX, I found 🐛 Display Bug when using #states (Forms API) with Ajax Request Needs work . I tried testing patches from there on 9.5.x 🐛 Display Bug when using #states (Forms API) with Ajax Request Needs work and 10.1.x 🐛 Display Bug when using #states (Forms API) with Ajax Request Needs work but didn't find anything workable.

🇨🇦Canada Cottser

Thanks! That error you pasted earlier may be coming from another CKEditor 5 contrib, so it could be their bug causing this module to not work. I know CKEditor 5 has had a number of breaking changes and some contrib modules have had to release different versions for different core branches to maintain compatibility across multiple CKEditor 5 versions.

🇨🇦Canada Cottser

Thanks for your thoughts @Anybody! Restructuring the issue relationships for now, unless/until we create an overarching UX “Plan” issue.

🇨🇦Canada Cottser

Hmm, I missed that the other form issue is a child issue of this but unless we create another child issue I think this makes sense.

We could create a “Plan” type issue if there are even more suggestions and group them all under that.

🇨🇦Canada Cottser

I’m of course open to other improvements but just making the title more specific and updating the component.

🇨🇦Canada Cottser

Thanks for all the issues etc @Anybody!

Indeed there is a todo for this, MRs/patches welcome or I will try to add it for the next alpha: https://git.drupalcode.org/project/ckeditor5_paste_filter/-/blob/daaef41...

🇨🇦Canada Cottser

@Anybody, can you please confirm that you configured and enabled paste filtering in your text format, similarly to what can be seen on the module's project page? A screenshot would be appreciated too. I know you were looking at the configuration form in another issue but in your reproduction steps you don't indicate that you have enabled the functionality from the text format form.

So far, I have not been able to reproduce this bug. As mentioned we have automated tests (running on Drupal 10.1.x) that prove that the module works. The only explanation I can think of at this point is that folks are not enabling the plugin on the text format config form.

If anyone can please provide detailed numbered steps to reproduce from a clean install of D9 or D10 that would be hugely appreciated, then I can hopefully get to the bottom of this and fix it.

🇨🇦Canada Cottser

Hi, first of all thanks for writing this up! I really appreciate you taking the time to do this.

The UI of this module was loosely inspired by https://www.drupal.org/project/stringoverrides → , however this pattern of always having an empty row to fill out probably shows up in other places too. I didn't study this to see if it's a "good" pattern or not, just trying to follow what I see and make a smooth user experience. After reviewing their interface again, I realize I may have missed one important bit of UI/UX polish, more on that below.

With stringoverrides you always get an extra row at the bottom of the form to fill in new overrides, and that is the intention here too. However, the two modules do have some key differences in this aspect:

1. We have the preset set of filters that you always start with when configuring this plugin on a new text format, whereas with stringoverrides you start with a blank slate (and one empty row). With our module if you remove all the pre-configured filters and save, you will also end up with one empty row.
2. With stringoverrides the "Replacement" box is hidden until you enter some text in the "Original" box. This is the bit of polish that I think we are currently missing.

I think we have some options, of course aside from doing nothing:

A. Don't add the empty row when there are filters configured already. Users will need to click the "Add another filter" button to add more filters.
B. Only show the "Replacement" box if there is text in the "Search expression" input box.

We also could do both. After thinking about it, I definitely want to at least do B, but I'm still not sure about whether to do A. I think B also has the added benefit of making the process of deleting filters a little bit more discoverable.

What do you think?

For the record, the empty filter never gets saved into config, so therefore never gets executed on paste. We also have form validation that the search pattern must be filled out and automated tests (Nightwatch) to cover most of what I have described.

🇨🇦Canada Cottser

This module was developed almost exclusively using Firefox so it should work fine there. If the same module configuration is not working consistently across browsers I would need browser version information, and specific reproduction steps so that I can see the bug happening.

If the paste filtering is not working, please upload your exported config YAML for the text format, or screenshot your filter settings (or at least the custom parts), and provide sample text which did not have any filtering applied after pasting?

Finally, CKEditor 5 won’t work without JavaScript enabled, but it is somewhat possible that the JS from this module is being blocked, perhaps a browser extension is interfering in Firefox in @jossensei’s case.

🇨🇦Canada Cottser

Congrats Lauri! You are awesome!

🇨🇦Canada Cottser

Just updating my username on this page

🇨🇦Canada Cottser

If you can also please share the browser and browser version you are using that may be helpful.

🇨🇦Canada Cottser

Hi, thanks for the report. We have automated tests running that show the core functionality works as expected: https://www.drupal.org/pift-ci-job/2659054 →

Can you please confirm that you're pasting into the visual editor, not the source editing view? Right now that's the only thing I can think of that would cause this behaviour.

Can you also check the JavaScript console in your browser after pasting to see if it reports any errors?

Do you have any other CKEditor 5 modules installed?

Production build 0.69.0 2024