javascript catch paste event in textarea

烂漫一生 提交于 2019-12-05 12:36:20
Tim Down

I answered a similar question a few days ago: Detect pasted text with ctrl+v or right click -> paste. This time I've included quite a long function that accurately gets selection boundaries in textarea in IE; the rest is relatively simple.

You can use the paste event to detect the paste in most browsers (notably not Firefox 2 though). When you handle the paste event, record the current selection, and then set a brief timer that calls a function after the paste has completed. This function can then compare lengths to know where to look for the pasted content. Something like the following:

function getSelectionBoundary(el, start) {
    var property = start ? "selectionStart" : "selectionEnd";
    var originalValue, textInputRange, precedingRange, pos, bookmark, isAtEnd;

    if (typeof el[property] == "number") {
        return el[property];
    } else if (document.selection && document.selection.createRange) {
        el.focus();

        var range = document.selection.createRange();
        if (range) {
            // Collapse the selected range if the selection is not a caret
            if (document.selection.type == "Text") {
                range.collapse(!!start);
            }

            originalValue = el.value;
            textInputRange = el.createTextRange();
            precedingRange = el.createTextRange();
            pos = 0;

            bookmark = range.getBookmark();
            textInputRange.moveToBookmark(bookmark);

            if (/[\r\n]/.test(originalValue)) {
                // Trickier case where input value contains line breaks

                // Test whether the selection range is at the end of the
                // text input by moving it on by one character and
                // checking if it's still within the text input.
                try {
                    range.move("character", 1);
                    isAtEnd = (range.parentElement() != el);
                } catch (ex) {
                    log.warn("Error moving range", ex);
                    isAtEnd = true;
                }
                range.moveToBookmark(bookmark);

                if (isAtEnd) {
                    pos = originalValue.length;
                } else {
                    // Insert a character in the text input range and use
                    // that as a marker
                    textInputRange.text = " ";
                    precedingRange.setEndPoint("EndToStart", textInputRange);
                    pos = precedingRange.text.length - 1;

                    // Delete the inserted character
                    textInputRange.moveStart("character", -1);
                    textInputRange.text = "";
                }
            } else {
                // Easier case where input value contains no line breaks
                precedingRange.setEndPoint("EndToStart", textInputRange);
                pos = precedingRange.text.length;
            }
            return pos;
        }
    }
    return 0;
}

function getTextAreaSelection(textarea) {
    var start = getSelectionBoundary(textarea, true),
        end = getSelectionBoundary(textarea, false);

    return {
        start: start,
        end: end,
        length: end - start,
        text: textarea.value.slice(start, end)
    };
}

function detectPaste(textarea, callback) {
    textarea.onpaste = function() {
        var sel = getTextAreaSelection(textarea);
        var initialLength = textarea.value.length;
        window.setTimeout(function() {
            var val = textarea.value;
            var pastedTextLength = val.length - (initialLength - sel.length);
            var end = sel.start + pastedTextLength;
            callback({
                start: sel.start,
                end: end,
                length: pastedTextLength,
                text: val.slice(sel.start, end),
                replacedText: sel.text
            });
        }, 1);
    };
}

window.onload = function() {
    var textarea = document.getElementById("your_textarea");
    detectPaste(textarea, function(pasteInfo) {
        var val = textarea.value;

        // Delete the pasted text and restore any previously selected text
        textarea.value = val.slice(0, pasteInfo.start) +
            pasteInfo.replacedText + val.slice(pasteInfo.end);

        alert(pasteInfo.text);
    });
};

You might now use FilteredPaste.js (http://willemmulder.github.com/FilteredPaste.js/) instead. It will let you control what content gets pasted into a textarea or contenteditable and you will be able to filter/change/extract content at will.

A quick search shows me that there are different methods for different browsers. I'm not sure if jQuery has a solution. Prototype.js does not appear to have one. Maybe YUI can do this for you?

You can also use TinyMCE, since it does have a gazillion of different event triggers. It is a full fledged word processor, but you can use it as plain text if you want. It might be a bit too much weight to add though. For example, upon initiation, it turns your <textarea> into an iFrame with several sub. But it will do what you ask.

--Dave

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!