从 contenteditable div 内的可拖动内容中删除默认样式

Remove default styles from draggable content inside of contenteditable div

我正在尝试创建简单的 WYSIWYG 编辑器,但我遇到了以下问题。 当用户在 contenteditable div 内复制或拖动文本时。 根据 Google 的信息,我为 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));
});

它就像一个魅力:

但是拖放操作无法按预期工作。 我在 Whosebug 上找到了类似的帖子:

1) This one uses jQuery UI which is irrelevant for my case

2) Event described here doesn't provide ability to customize draggable text, only target

还有其他一些作品,所以我得到了以下代码:

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

结果:

此外,我尝试根据 documentation 执行此操作,但这完全删除了旧元素内容。 代码:

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

示例:

有人可以帮助我,或者给出一些如何处理的建议。

当前状态在此fiddle

中可用

================= PS =============== 这就解决了。适用于大多数浏览器的版本 - fiddle

当放置文本时,放置点的 span 被一分为二,并在其间插入一个新的 span。我还没有看到可以防止这种行为的拖放选项。避免它的一种方法是替换默认传输机制。

drop 事件处理程序中,如果您发现文本将以不同的 span 结束,您可以手动移动文本。可以使用 createCollapsedRangeFromPoint, a function provided by 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 
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);
}