5

I would like the to paste text in a contenteditable div, but reacting as a textarea.
Note that I want to keep the formatting as I would paste it in my textarea (from word, excel...).
So.
1) Paste text in contenteditable div
2) I get the text from clipboard
3) I push my value from clipboard to my textarea, (dont know how??)
4) Get value from my textarea and place it in my contenteditable div

Any suggestions?

Deduplicator
  • 41,806
  • 6
  • 61
  • 104
Ziggiej
  • 109
  • 1
  • 1
  • 7
  • See http://stackoverflow.com/questions/2176861/javascript-get-clipboard-data-on-paste-event-cross-browser/2177059#2177059. – Tim Down Jun 28 '12 at 08:25
  • The problem is not getting the data, I already used his method to recieve my data from my clipboard. But using my clipboard data to "paste" it into my textarea, there's my problem – Ziggiej Jun 28 '12 at 08:32
  • 3
    You can only do this by focussing the textarea and allowing the browser to paste into it during a paste event. – Tim Down Jun 28 '12 at 08:51
  • Indeed, thank you for that, currently I can make it work with keyboard events, looking deeper to find also as solution when paste on click events – Ziggiej Jun 28 '12 at 08:56
  • In some browsers it's simply not possible. The `paste` event is just too late to redirect the focus. – Tim Down Jun 28 '12 at 09:05
  • I had found a workaround: http://www.mattbenton.net/2012/01/jquery-plugin-paste-events/ But it seems not to be working in IE/FF when i change my focus on prepaste and postpaste, works in SAF – Ziggiej Jun 28 '12 at 09:11
  • That plug-in is still using the paste event and unfortunately fixes nothing. – Tim Down Jun 28 '12 at 09:20
  • isn't there a workaround to fix that? – Ziggiej Jun 28 '12 at 09:23
  • Not that I can think of. The first that JavaScript running in the page knows about a paste from the context or edit menu is when the `paste` event fires. Some browsers do fire a `beforepaste` event but it's not generally useful. – Tim Down Jun 28 '12 at 09:26

3 Answers3

18

I'm CKEditor's core developer and by coincidence for last 4 months I was working on clipboard support and related stuff :) Unfortunately I won't be able to describe you the entire way how pasting is handled, because the tales of the impl are too tricky for me even after writing impl by myself :D

However, here're some hints that may help you:

  1. Don't write wysiwyg editor - use one that exists. It's going to consume all your time and still your editor will be buggy. We and guys from other... two main editors (guess why only three exist) are working on this for years and we still have full bugs lists ;).

  2. If you really need to write your own editor check out http://dev.ckeditor.com/browser/CKEditor/trunk/_source/plugins/clipboard/plugin.js - it's the old impl, before I rewrote it, but it works everywhere where it's possible. The code is horrible... but it may help you.

  3. You won't be possible to handle all browsers by just one event paste. To handle all ways of pasting we're using both - beforepaste and paste.

  4. There's number (huge number :D) of browsers' quirks that you'll need to handle. I can't to describe you them, because even after few weeks I don't remember all of them. However, small excerpt from our docs may be useful for you:

    Paste command (used by non-native paste - e.g. from our toolbar)

    * fire 'paste' on editable ('beforepaste' for IE)
    * !canceled && execCommand 'paste'
    * !success && fire 'pasteDialog' on editor
    

    Paste from native context menu & menubar

    (Fx & Webkits are handled in 'paste' default listner.
    Opera cannot be handled at all because it doesn't fire any events
    Special treatment is needed for IE, for which is this part of doc)
    * listen 'onpaste'
    * cancel native event
    * fire 'beforePaste' on editor
    * !canceled && getClipboardDataByPastebin
    * execIECommand( 'paste' ) -> this fires another 'paste' event, so cancel it
    * fire 'paste' on editor
    * !canceled && fire 'afterPaste' on editor
    

    The rest of the trick - On IEs we listen for both paste events, on the rest only for paste. We need to prevent some events on IE, because since we're listening for both sometimes this may cause doubled handling. This is the trickiest part I guess.

  5. Note that I want to keep the formatting as I would paste it in my textarea (from word, excel...).

    Which parts of formatting do you want to keep? Textarea will keep only basic ones - blocks formatting.

  6. See http://dev.ckeditor.com/browser/CKEditor/trunk/_source/plugins/wysiwygarea/plugin.js#L120 up to line 123 - this is the last part of the task - inserting content into selection.

Reinmar
  • 21,228
  • 4
  • 53
  • 72
  • @Hey ! Any chance you know why the link rendered in iframe are not clickable ? But they are working when using right click -> open in a new window. That would be great. Your product is great by the way ! – Ced Sep 07 '15 at 15:52
1

Current solution works perfect in IE/SAF/FF But still i need a fix for "non" keyboard events, when pasting with mouse click... Current solution for keyboard "paste" events:

$(document).ready(function() {
    bind_paste_textarea();      
});


function bind_paste_textarea(){
    var activeOnPaste = null;
    $("#mypastediv").keydown(function(e){
        var code = e.which || e.keyCode;
        if((code == 86)){
            activeOnPaste = $(this);
            $("#mytextarea").val("").focus();
        }
    });
    $("#mytextarea").keyup(function(){
        if(activeOnPaste != null){
            $(activeOnPaste).focus();
            activeOnPaste = null;
        }
    });
}

<h2>DIV</h2>
<div id="mypastediv" contenteditable="true" style="width: 400px; height: 400px; border: 1px solid orange;">

</div>
<h2>TEXTAREA</h2>
<textarea id="mytextarea" style="width: 400px; height: 400px; border: 1px solid red;"></textarea>
Ziggiej
  • 109
  • 1
  • 1
  • 7
0

I have achieved this using rangy library to save and restore selections.

I also perform some other work using the library in the same functions, which I have stripped out of this example, so this is not optimal code.

HTML

<div><div id="editor"contenteditable="true" type="text"></div><div>

Javascript

var inputArea = $element.find('#editor');
var debounceInterval = 200;

function highlightExcessCharacters() {
    // Bookmark selection so we can restore it later
    var sel = rangy.getSelection();
    var savedSel = sel.saveCharacterRanges(editor);

    // Strip HTML
    // Prevent images etc being pasted into textbox
    inputArea.text(inputArea[0].innerText);

    // Restore the selection
    sel.restoreCharacterRanges(editor, savedSel);
}

// Event to handle checking of text changes
var handleEditorChangeEvent = (function () {

    var timer;

    // Function to run after timer passed
    function debouncer() {
        if (timer) {
            timer = null;
        }
        highlightExcessCharacters();
    }

    return function () {
        if (timer) {
            $timeout.cancel(timer);
        }
        // Pass the text area we want monitored for exess characters into debouncer here
        timer = $timeout(debouncer, debounceInterval);
    };
})();

function listen(target, eventName, listener) {
    if (target.addEventListener) {
        target.addEventListener(eventName, listener, false);
    } else if (target.attachEvent) {
        target.attachEvent("on" + eventName, listener);
    }
}

// Start up library which allows saving of text selections
// This is useful for when you are doing anything that might destroy the original selection
rangy.init();
var editor = inputArea[0];

// Set up debounced event handlers
var editEvents = ["input", "keydown", "keypress", "keyup", "cut", "copy", "paste"];
for (var i = 0, eventName; eventName = editEvents[i++];) {
    listen(editor, eventName, handleEditorChangeEvent);
}
Amicable
  • 2,925
  • 3
  • 45
  • 73