Remove default styles from draggable content inside content containing content

I am trying to create a simple WYSIWYG editor, and I ran into the following problem. When the user copies or drags the text inside the contenteditablediv. According to information from Google, I added the following code to copy / paste:

var $mainInput = $('#main-input');
$mainInput.on('paste', function(e) {
    e.preventDefault();
    var text = e.originalEvent.clipboardData.getData("text/plain");
    lastCaretIndex.insertNode(document.createTextNode(text));
});

And it works like a charm:

enter image description here

But with drag & drop, this does not work properly. I found similar entries in Stackoverflow:

1) This one uses jQuery UI which is not relevant to my case

2) The event described here does not allow you to customize draggable text, only the target

And some other parts, so I got the following code:

$mainInput.on('dragend', function(e) {
 window.getSelection().getRangeAt(0).insertNode(document.createTextNode(strip(t)));
});

And the result:

enter image description here

, documentation, . :

$mainInput.bind('drop', function (e) {
    event.target.textContent = e.originalEvent.dataTransfer.getData("text/plain");
    event.preventDefault();
});

:

enter image description here

-, , , .

fiddle

================= PS =============== . , - fiddle

+4
1

, span , span. , . - .

drop , , span. createCollapsedRangeFromPoint, Tim Down. .

this jsfiddle. Chrome Firefox, IE11. , .

var $mainInput = $('#main-input');
var draggedText;
var dragStartContainer;
var dragEndContainer;
var dragStartOffset;
var dragEndOffset;

$mainInput.on('dragstart', function(e) {
    var dragRange = getSelectionRange();
    dragStartContainer = dragRange.startContainer;
    dragEndContainer = dragRange.endContainer;
    dragStartOffset = dragRange.startOffset;
    dragEndOffset = dragRange.endOffset;
    draggedText = e.originalEvent.dataTransfer.getData("text");
});

$mainInput.on('drop', function(e) {
    // Get caret at mouse cursor position
    var range = createCollapsedRangeFromPoint(e.clientX, e.clientY);
    var container = range.startContainer;
    // If text is moved to another container, do it manually
    if (container && (container !== dragStartContainer || container !== dragEndContainer)) {
        e.preventDefault();
        // Insert dragged text at caret position
        var startOffset = range.startOffset;
        var str = container.textContent;
        var strPrepend = str.substr(0, range.startOffset);
        var strAppend = str.substr(range.startOffset);
        container.textContent = strPrepend + draggedText + strAppend;
        // Delete text at original position
        var spaceCount = getSpaceCountAtStart(container);
        setSelectionRange(dragStartContainer, dragEndContainer, dragStartOffset, dragEndOffset);
        document.execCommand("delete", false);
        var spaceCountCorrection = getSpaceCountAtStart(container) - spaceCount;
        // Select text at new position
        var startRemoved = (dragEndContainer === container ? dragEndOffset - 1 : 0);
        var startOffset = Math.max(0, startOffset + spaceCountCorrection - startRemoved);
        var endOffset = startOffset + draggedText.length;
        setSelectionRange(container, container, startOffset, endOffset);
    }
});

// Get the number of spaces at start of container
// After moving text, that number may change
// and screw up range position calculations
function getSpaceCountAtStart(container) {
    var innerHTML = container.parentNode.innerHTML;
    var count = 0;
    for (var i = 0; i < innerHTML.length; i++) {
        if (innerHTML[i] === ' ') {
            count += 1;
        } else {
            break;
        }
    }
    return count;
}

// Function provided by Tim Down at /questions/571801/creating-a-collapsed-range-from-a-pixel-position-in-ffwebkit/2334683#2334683
function createCollapsedRangeFromPoint(x, y) {
    var doc = document;
    var position, range = null;
    if (typeof doc.caretPositionFromPoint != "undefined") {
        position = doc.caretPositionFromPoint(x, y);
        range = doc.createRange();
        range.setStart(position.offsetNode, position.offset);
        range.collapse(true);
    } else if (typeof doc.caretRangeFromPoint != "undefined") {
        range = doc.caretRangeFromPoint(x, y);
    } else if (typeof doc.body.createTextRange != "undefined") {
        range = doc.body.createTextRange();
        range.moveToPoint(x, y);
    }
    return range;
}

function getSelectionRange() {
    var sel;
    if (window.getSelection) {
        sel = window.getSelection();
        if (sel.rangeCount) {
            return sel.getRangeAt(0);
        }
    } else if (document.selection) {
        return document.createRange();
    }
    return null;
}

function setSelectionRange(startContainer, endContainer, startOffset, endOffset) {
    var sel = window.getSelection();
    sel.removeAllRanges();
    var range = document.createRange();
    range.setStart(startContainer, startOffset);
    range.setEnd(endContainer, endOffset);
    sel.addRange(range);
}
+1

Source: https://habr.com/ru/post/1675142/


All Articles