25

I need to implement task which is quite common feature for RichTextEditors - take HTML from clipboard. Can anyone help with guide on how to solve this task?

It has to be cross platform (IE, FF, Chrome, Opera). I just started from this code:

<script type="text/javascript">
    $('.historyText').live('input paste', function(e) {

        var paste = e.clipboardData && e.clipboardData.getData ?
        e.clipboardData.getData('text/plain') :                // Standard
        window.clipboardData && window.clipboardData.getData ?
        window.clipboardData.getData('Text') :                 // MS
        false;

        alert(paste);
    });</script>

Both window.clipboardData and e.clipboardData are null (Chrome, Firefox).

Update: User wants to paste article content from other browser windows, and I need to get html tags.

2

4 Answers 4

31

I actually have done a lot of work on this, and just wrote a nice blog post describing how we did it in detail at Lucidchart (as a disclaimer, I work at Lucidchart). We have a JSFiddle that shows copying and pasting (tested in Firefox, Safari, Chrome, and IE9+).

The short of the answer is that you will need to get the HTML during the system paste event. In most (non-IE) browsers, this can be done with something as simple as the following:

document.addEventListener('paste', function(e) {
  var html = e.clipboardData.getData('text/html');
  // Whatever you want to do with the html
}

The problem is when you want to get HTML in IE. For whatever reason, IE doesn't make the text/html clipboard data accessible via javascript. What you have to do is let the browser paste to a contenteditable div and then get the html after the paste event is over.

<div id="ie-clipboard-contenteditable" class="hidden" contenteditable="true"></div>
var ieClipboardDiv = $('#ie-clipboard-contenteditable'); 

var focusIeClipboardDiv = function() {
  ieClipboardDiv.focus();
  var range = document.createRange();
  range.selectNodeContents((ieClipboardDiv.get(0)));
  var selection = window.getSelection();
  selection.removeAllRanges();
  selection.addRange(range);
};

document.addEventListener('beforepaste', function() {
  if (hiddenInput.is(':focus')) {
    focusIeClipboardDiv();
  }
}, true);

document.addEventListener('paste', function(e) {
  ieClipboardDiv.empty();
  setTimeout(function() {
    var html = ieClipboardDiv.html();
    // Do whatever you want with the html
    ieClipboardDiv.empty();
    // Return focus here
  }, 0);
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, this was very helpful! Note that in IE 10 and 11, all the extra selection stuff in focusIeClipboardDiv seems to be unnecessary. Also, why is there is an extra ieClipboardDiv.empty() in the paste listener before setTimeout?
I suspect the extra selection stuff in focusIeClipboardDiv is for the corresponding copy operation, not the paste.
In Chrome 92, 'text/plain' allows me to get the right text, but 'text/html' returns only an empty string. Of course, e.clipboardData is empty, using window.event.clipboardData.getData() instead
11

You won't be able to get data from the clipboard using JavaScript alone, which is the way it should be. The way current versions of TinyMCE and CKEditor do this is as follows:

  1. Detect a ctrl-v / shift-ins event using a keypress event handler
  2. In that handler, save the current user selection, add a div element off-screen (say at left -1000px) to the document, move the caret to be inside that div, thus effectively redirecting the paste
  3. Set a very brief timer (say 1 millisecond) in the event handler to call another function that retrieves the HTML content from the div and does whatever processing is required, removes the div from the document, restores the user selection and inserts the processed HTML.

Note that this will only work for keyboard paste events and not pastes from the context or edit menus. By the time the paste event fires, it's too late to redirect the caret into the div (in some browsers, at least).

4 Comments

Tim, it makes sense, but I am not able to do process which called "redirect paste" - I can only get plain text, not html. I need to allow copy of html articles from browser to chat. Basic "paste" just past text version with out HTML tags
Hi Tim, by 'div' I guess you meant, contenteditable div, right?
@Cupidvogel: Yes, or other element. Looks like a copy-paste job by me.
Almost, but there are nuances. Assuming that the contenteditable div does allow you to retrieve the HTML, Word HTML often leaves a mess in browser, so it requires a pre-processing before insertion. And that is really tricky..In Word, you can drag an image anywhere, and the text acordingly wraps around..(stackoverflow.com/questions/14915931/…). So after one has done some dragging around to place the image in the middle of a paragraph, and then does this operation, since the image won't be copied, only the text, the HTML will be really messy!
1

In Chrome, I access clipboardData through the event using this code:

$(document).bind('paste', function(e) {
    var clipboardData = e.originalEvent.clipboardData;
});

1 Comment

I'm getting text [object DataTransfer] on this in Chrome
-1

This piece of code did the job for me.

setTimeout(() => {
  navigator.clipboard.read()
    .then(text => {
        for (const item of text) {
            console.log('content type:', item.types);
            const blob = item.getType(item.types[0]).then(
                blob => {
                    const reader = new FileReader();
                    reader.onload = function(event) {
                        console.log('result:\n', event.target.result);
                    };
                    reader.readAsText(blob);
                },
                err => {
                    console.error('Failed to read clipboard content: ', err);
                }
            );
        }
    })
    .catch(err => {
      console.error('Failed to read clipboard contents: ', err);
    });
}, 3000);

2 things to keep in mind.

  • this code works in the browser console
  • After running the code in the console, we will have to click somewhere in the browser window for the focus or press tab. reference

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.