javascript:使用html标签的focusOffset [英] javascript : focusOffset with html tags

查看:170
本文介绍了javascript:使用html标签的focusOffset的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

 < div id =mydivcontenteditable 

我有一个contenteditable div如下(| =游标位置) =true> lorem ipsum< spanclass =highlight> indol | or sit< / span> amet consectetur< span class ='tag'> adipiscing< / span> ELIT< / DIV>

我想要获取当前光标位置,包括html标记。我的代码:

  var offset = document.getSelection()。focusOffset; 

偏移返回5(最后一个标记为全文),但我需要它来处理html标记。预期的返回值是40.代码必须适用于所有最近的浏览器。
(我也检查了这个: window.getSelection()偏移与HTML标签? 但它不回答我的问题)。
任何想法?解决方案另一种方法是在DOM中添加一个临时标记并计算该标记的偏移量。该算法在内部序列化( innerHTML )中查找标记的HTML序列化(它的 outerHTML )感兴趣的 div 重复的文本不是这个解决方案的问题。

为此,标记的序列化必须在其div中唯一。 您无法控制用户输入到字段中的内容,但您可以控制放入DOM的内容,因此这应该不难实现。在我的例子中,标记是静态唯一的:通过选择一个不太可能导致冲突的类名。通过检查DOM并更改类直到它是唯一的,也可以动态地执行它。



我有一个小提琴(源自阿尔瓦罗蒙托罗自己的小提琴)。主要部分是:

$ p $ function getOffset(){

if($(。+ unique).length)
抛出新错误(标记存在于文档中;或者唯一类不是唯一的);

//我们也可以使用rangy.getSelection(),但这里没有理由这样做。
var sel = document.getSelection();

if(!sel.rangeCount)
return; //没有范围。

if(!sel.isCollapsed)
return; //我们只使用折叠选择。

if(sel.rangeCount> 1)
throw new错误(无法处理多个范围);

var range = sel.getRangeAt(0);
var saved = rangy.serializeSelection();
//见下面的评论。
$ mydiv [0] .normalize();

range.insertNode($ marker [0]);
var offset = $ mydiv.html()。indexOf($ marker [0] .outerHTML);
$ marker.remove();

//标准化之前和之后确保DOM在
//之前以及插入和移除标记之后的形状相同。
$ mydiv [0] .normalize();
rangy.deserializeSelection(saved);

返回抵消;

$ / code>

正如您所看到的,代码必须补偿添加和删除标记到DOM中,因为这会导致当前选择丢失:


  1. Rangy 用于保存选择并在之后恢复。请注意,保存和恢复可以使用比Rangy更轻的东西来完成,但我不想用细节加载答案。如果您决定使用Rangy完成此任务,请阅读文档,因为它是可以优化序列化和反序列化。

  2. 为了使Rangy能够工作,DOM在保存之前和之后必须处于完全相同的状态。这就是为什么< normalize()在我们添加标记之前以及删除之后调用的原因。它所做的是将紧邻的文本节点合并到单个文本节点中。问题是添加一个标记到DOM可以导致文本节点被分解成两个新的文本节点。这会导致选择丢失,并且如果不通过正常化撤消,会导致Rangy无法恢复选择。再次,比调用 normalize 更轻的东西可以做到这一点,但我不想用细节加载答案。


  3. ol>

    I have a contenteditable div as follow (| = cursor position):

    <div id="mydiv" contenteditable="true">lorem ipsum <spanclass="highlight">indol|or sit</span> amet consectetur <span class='tag'>adipiscing</span> elit</div>
    

    I would like to get the current cursor position including html tags. My code :

    var offset = document.getSelection().focusOffset;
    

    Offset is returning 5 (full text from the last tag) but i need it to handle html tags. The expected return value is 40. The code has to work with all recents browsers. (i also checked this : window.getSelection() offset with HTML tags? but it doesn't answer my question). Any ideas ?

    解决方案

    Another way to do it is by adding a temporary marker in the DOM and calculating the offset from this marker. The algorithm looks for the HTML serialization of the marker (its outerHTML) within the inner serialization (the innerHTML) of the div of interest. Repeated text is not a problem with this solution.

    For this to work, the marker's serialization must be unique within its div. You cannot control what users type into a field but you can control what you put into the DOM so this should not be difficult to achieve. In my example, the marker is made unique statically: by choosing a class name unlikely to cause a clash ahead of time. It would also be possible to do it dynamically, by checking the DOM and changing the class until it is unique.

    I have a fiddle for it (derived from Alvaro Montoro's own fiddle). The main part is:

    function getOffset() {
    
        if ($("." + unique).length)
            throw new Error("marker present in document; or the unique class is not unique");
    
        // We could also use rangy.getSelection() but there's no reason here to do this.
        var sel = document.getSelection();
    
        if (!sel.rangeCount)
            return; // No ranges.
    
        if (!sel.isCollapsed)
            return; // We work only with collapsed selections.
    
        if (sel.rangeCount > 1)
            throw new Error("can't handle multiple ranges");
    
        var range = sel.getRangeAt(0);
        var saved = rangy.serializeSelection();
        // See comment below.
        $mydiv[0].normalize();
    
        range.insertNode($marker[0]);
        var offset = $mydiv.html().indexOf($marker[0].outerHTML);
        $marker.remove();
    
        // Normalizing before and after ensures that the DOM is in the same shape before 
        // and after the insertion and removal of the marker.
        $mydiv[0].normalize();
        rangy.deserializeSelection(saved);
    
        return offset;
    }
    

    As you can see, the code has to compensate for the addition and removal of the marker into the DOM because this causes the current selection to get lost:

    1. Rangy is used to save the selection and restore it afterwards. Note that the save and restore could be done with something lighter than Rangy but I did not want to load the answer with minutia. If you decide to use Rangy for this task, please read the documentation because it is possible to optimize the serialization and deserialization.

    2. For Rangy to work, the DOM must be in exactly the same state before and after the save. This is why normalize() is called before we add the marker and after we remove it. What this does is merge immediately adjacent text nodes into a single text node. The issue is that adding a marker to the DOM can cause a text node to be broken into two new text nodes. This causes the selection to be lost and, if not undone with a normalization, would cause Rangy to be unable to restore the selection. Again, something lighter than calling normalize could do the trick but I did not want to load the answer with minutia.

    这篇关于javascript:使用html标签的focusOffset的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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