Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TinyMCE onPaste doesn't set content, paste with context menu doesn't trigger change event

I have two related questions regarding TinyMCE (v. 3.5.11) default paste functionality:

Why isn't the text available on paste?

After pasting text into the editor, the content is visible in the editor, but not available via the .getContent() method. Why?

Can I force TinyMCE to get the text it is displaying in the editor during this event?

Why does Ctrl+V trigger a change event, but context menu paste does not?

If you paste text into the editor with key combo Ctrl+V, first TinyMCE's onPaste event is fired and the text is not available via .getContent() (as mentioned above); immediately following that, the onChange event is fired and the text is now available via the .getContent() method.

However, if you paste text into the editor with mouse by right-click, then select Paste from context menu, TinyMCE's onPaste event is fired, but not onChange.

Why the difference? What can be done about this?

See this JSFiddle for a working example.

Note: I am not using the Paste plugin, so please don't offer it or any other plugin as an answer. I am interested in creating my own solution.

like image 916
gfullam Avatar asked Nov 19 '14 06:11

gfullam


2 Answers

Listen to paste event, get clipboard data

Why isn't the text available on paste?

After pasting text into the editor, the content is visible in the editor, but not available via the .getContent() method. Why?

I don't know why, but apparently pasting via context menu doesn't trigger a change event in TinyMCE. From my observation, the text in the editor gets cached by TinyMCE and only updated during an onChange event. So even though the text is visible, it hasn't been cached by TinyMCE and therefore .getContent() returns the last cached value (or undefined if nothing has been cached yet).

Can I force TinyMCE to get the text it is displaying in the editor during this event?

No.

Why does Ctrl+V trigger a change event, but context menu paste does not? … Why the difference?

Ultimately, it is because pasting via Ctrl+V triggers an "Undo level" — which in turn triggers the onChange event — while the context menu paste event does not (to me, this seems like a TincyMCE bug):

Undo levels are added when the user types text and then moves the cursor, performs an action like pressing the bold button while having text selected, or pressing return. There are many ways undo levels get added to the editor.

See: TinyMCE documentation for onchange_callback

What can be done about this?

You can listen for the onPaste event and bind a callback function to get the text directly from the clipboard and insert it into the editor. Using the .execCommand() method to insert the content will trigger an Undo level, which in turn will trigger an onChange event even when pasting via the context menu.

Here is an example using a "Paste as plain text" callback onPaste:

tinyMCE.init({

    // ...,

    setup: function (editor) {

        // Listen for paste event, add "Paste as plain text" callback
        editor.onPaste.add(function (editor, e) {

            // Prevent default paste behavior
            e.preventDefault();

            // Check for clipboard data in various places for cross-browser compatibility.
            // Get that data as text.
            var content = ((e.originalEvent || e).clipboardData || window.clipboardData).getData('Text');

            // Let TinyMCE do the heavy lifting for inserting that content into the editor.
            editor.execCommand('mceInsertContent', false, content);
        });
    }
});

Note: Naturally, you don't have to make this function "paste as plain text". You could choose to get the full HTML from the clipboard if you wanted to retain formatting, but then you get into additional cross-browser compatibility issues outside the scope of this answer. Pasting as plain text requires fewer lines of code and so it is more suited for an example in a Stack Overflow answer. It also happens to be a commonly sought solution for TinyMCE developers, so its inclusion here might be helpful in that regard.

like image 126
gfullam Avatar answered Oct 05 '22 01:10

gfullam


I am currently on version 5 but the issue is not yet resolved in the library. A tested workaround is to use the setDirty() method (see docs):

tinyMCE.init({
    setup: function (editor) {
        editor.on('paste cut', function() {
           this.setDirty(true); // this updates the editor.undoManager
        });
    }
});
like image 35
Frank Etoundi Avatar answered Oct 05 '22 01:10

Frank Etoundi