Ambidex
Ambidex

Reputation: 877

CKEditor: PasteFromWord ignores pasteFilter

In CKEditor 4.6.2 (currently bundled in Drupal 8) ACF is disabled by default, to make sure some of the special plugins work correctly. So for the record: I do not want to enable ACF and am not able to use allowedContent or disallowedContent. I'm trying to prevent some elements to be injected on paste from Word (like h1 and p[styles]).

To accomplish this, I'm trying to add these to pasteFilter which works perfectly on non-Word-pasted content, though when pasting from Word the pasteFilter seems to be ignored? Is this a bug?

So, how can I:

  1. Keep ACF disabled - In favor of special Drupal elements
  2. Keep pastefromword enabled - To detect special Word styling like indentation and lists.
  3. Add additional filtering to all (including from Word) pastings - To remove some elements and attributes like h1, style="font-family: Verdana" etc...

Upvotes: 5

Views: 1326

Answers (2)

Damien
Damien

Reputation: 3220

This is my current solution, as a plugin:

// Activate the ACF filter only when pasting from Word (the opposite of the default).
// Use config.pasteFilter='semantic-content' to filter non-Word pasted content.
// Tested with ckeditor 4.8.
CKEDITOR.plugins.add('filterOnlyOnPaste', {
    init: function(editor) {
        editor.on('setData', function(evt) {
            editor.activeFilter.disabled = true;
        });
        editor.on('instanceReady', function(evt) {
            editor.activeFilter.disabled = true;
        });
        editor.on('afterPasteFromWord', function(e) {
            editor.activeFilter.disabled = false;
            var filter = editor.activeFilter,
                fragment = CKEDITOR.htmlParser.fragment.fromHtml(e.data.dataValue),
                writer = new CKEDITOR.htmlParser.basicWriter();
            filter.applyTo(fragment);
            fragment.writeHtml(writer);
            e.data.dataValue = writer.getHtml();
            editor.activeFilter.disabled = true;
        });
    }
});

Upvotes: 0

f1ames
f1ames

Reputation: 1744

Handling content pasted from Word requires some serious amount of markup processing to transform it into clean, semantic content. The paste from Word filter is very specific covering many edge cases (especially with nested lists). The reason why pasting from Word has its own filter and does not reuse ACF rules is the fact that it may cause some conflicts - it is described in this issue.

As for now there is now out-of-the-box approach to add additional filtering to content pasted from Word. However, you may utilise afterPasteFromWord event, to filter the pasted data like:

var editor = CKEDITOR.replace( 'editor1' );

editor.on( 'afterPasteFromWord', function( evt ) {
    var filter = editor.activeFilter, // Use activeFilter so it reflects ACF settings.
    // var filter = new CKEDITOR.filter( 'p b' ), // Use custom new filter.
        fragment = CKEDITOR.htmlParser.fragment.fromHtml( evt.data.dataValue ),
        writer = new CKEDITOR.htmlParser.basicWriter();

    filter.applyTo( fragment );
    fragment.writeHtml( writer );
    evt.data.dataValue = writer.getHtml();
} );

Please see this codepen demo.

You may also refer to official docs on CKEDITOR.filter.applyTo and CKEDITOR.editor.activeProperty.

Upvotes: 4

Related Questions