在contentEditable元素上拖放 [英] Drag-n-Drop on contentEditable elements

查看:231
本文介绍了在contentEditable元素上拖放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在互联网上有许多所见所见的编辑器,但我还没有找到实现某种形式的拖放实现。



它是容易创建自己的编辑器,但是我想让用户能够从可编辑区域外部拖动元素(即令牌),并将它们放在可选区域内的某个位置。



很容易在可编辑元素的特定位置注入html,但是当用户在可编辑区域中的某个元素上拖动DIV时,如何确定插入符的位置。为了更好地说明我正在尝试解释的内容,请参阅以下方案。



可编辑区域(编辑模式下的IFRAME或其contentEditable属性设置为DIV true)已经包含以下文本:



亲爱的,请注意....



用户现在将一个元素表示一些元素的元素,在可编辑区域上,将光标移动到文本上,直到插入符号出现在文本中的逗号(,)之前,如上所示。当用户在该位置释放鼠标按钮时,HTML将被注入,可能会导致如下结果:



亲爱的{UserFirstName},请注意.. 。。



我不知道有没有人做过类似的事情,或者至少知道如何使用JavaScript来做这个事情。



任何帮助将不胜感激。

解决方案

这是我的解决方法关于可编辑元素的自定义拖动元素的问题。大问题是,当鼠标悬停在可编辑元素上时,无法确定鼠标光标的文本偏移量。我已经尝试过鼠标点击将插入符号设置在所需的位置,但没有起作用。即使这样做,也不会在拖放时看到插入符号的位置,而只会导致丢失。



由于可以将鼠标悬停事件绑定到元素,不是文本节点,可以将可编辑元素设置为暂时不可编辑。查找所有元素,并在跨度中包装每个文本节点,以免破坏文本的流。每个span应该被赋予一个类名,所以我们可以再次找到它们。



在包装之后,应该再次找到所有包装的文本节点,并用另一个span来包装每个字符使用一个可以再次找到它们的类名。



使用事件委托可以将一个事件添加到主要可编辑元素,该元素将应用于将显示的每个字符跨度的样式插入符号,闪烁的GIF图像作为背景。



再次,使用事件委托,应该为每个字符上的鼠标向上事件(drop event)添加一个事件。现在可以使用字符跨度在其父(包装的文本节点)中的位置(偏移)来确定偏移量。现在可以撤消所有的包装,保留对计算的偏移量的引用,同时撤消包装,保持对适用的文本节点的引用。



使用范围&浏览器的选择对象,现在可以使用计算的偏移量将适用的文本节点设置选择,并在新设置的选择(插入符号位置)et viola!中注入所需的HTML!



以下是使用jQuery查找文本节点的代码片段,将它们包装起来:

  editElement.find(*: not(.text-node))。contents()。filter(function(){
return this.nodeType!= 1;
})wrap(< span class = \文本node\ /> 中);

要查找每个文本节点并包装每个字符,请使用:


每个(function()
{
var textnode = $(this),

  editElement.find(。text-node text = textnode.text(),result = []; 

for(var i = 0; i< text.length; i ++)result.push(text.substr(i,1)) ;

textnode.html(< span class = \char\>
+ result.join(< / span>< span class = \\char \>)+< / span>);
});

撤消包装:



<$ p $每个(function()
{
this.parentNode.replaceChild(document.createTextNode($(this).text ()),this);
});

希望这种方法可以帮助那些有类似挑战的人


There are numerous WYSIWYG editors available on the internet, but I'm yet to find one that implements some form of drag-n-drop implementation.

It is easy to create one's own editor, but I want to the user to be able to drag elements (ie. tokens) from outside the editable area and have them drop it at a location of their choice inside the editable area.

It is easy to inject html at a specific location of an editable element, but how do one determine where the caret should be when the user is dragging a DIV over some element in the editable area. To better illustrate what I'm trying to explain, see the following scenario.

The editable area (either an IFRAME in edit mode or a DIV with its contentEditable attribute set to true) already contains the following text:

"Dear , please take note of ...."

The user now drags an element representing some token from a list of elements, over the editable area, moving the cursor over the text until the caret appear just before the comma (,) in the text as shown above. When the user releases the mouse button at that location, HTML will be injected which could result in something like this:

"Dear {UserFirstName}, please take note of ...".

I do not know if anyone has ever done anything similar to this, or at least know of how one would go about doing this using JavaScript.

Any help will be greatly appreciated.

解决方案

Here is my approach to solving the issue of custom drag elements on editable elements. The big issue is that one cannot determine the text offset of the mouse cursor when hovering over the editable element. I have tried faking a mouse click to set the caret at the desired position but that did not work. Even if it did, one would not visually see the placement of the caret while dragging, but only the resulting drop.

Since one can bind mouse-over events to elements and not text-nodes, one can set the editable element to be temporarily un-editable. Find all elements and wrap each text-node in a span as to not breaking the flow of the text. Each span should be given a classname so we can find them again.

After the wrapping, one should again find all the wrapped text-nodes and wrap each character with another span with a classname that one can find them again.

Using event delegation one can add an event to the main editable element that will apply a style to each character span that will display the caret, a blinking GIF image as a background.

Again, using event delegation, one should add an event for the mouse-up event (drop event) on each character. One can now determine the offset using the character span's position (offset) within its parent (wrapped text-node). One can now undo all the wrapping, keeping a reference to the calculated offset and while undoing the wrapping keeping a reference to the applicable text-node.

Using the range & selection objects of the browser, one can now set the selection using the calculated offset to the applicable text-node and inject the required HTML at the newly set selection (caret position), et viola!

Here follows a snippet using jQuery that will find textnodes, wrap them:

editElement.find("*:not(.text-node)").contents().filter(function(){ 
    return this.nodeType != 1;
}).wrap("<span class=\"text-node\"/>");

To find each text-node and wrap each character, use:

editElement.find(".text-node").each(function()
{
    var textnode = $(this), text = textnode.text(), result = [];

    for (var i = 0; i < text.length; i++) result.push(text.substr(i, 1));

    textnode.html("<span class=\"char\">" 
        + result.join("</span><span class=\"char\">") + "</span>");
});

To undo the wrapping:

editElement.find(".text-node").each(function()
{
    this.parentNode.replaceChild(document.createTextNode($(this).text()), this);
});

Hope this approach helps those having similar challenges

这篇关于在contentEditable元素上拖放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆