用Rangy保存位置时,插入符号在Firefox中消失

Dar*_*kkz 5 html javascript firefox selection rangy

这仅在Firefox中发生。

重要提示:我正在使用rangy.saveSelection()保存插入符号的位置:

  • 单击内容可编辑div时
  • 在键盘上
  • 将外部html元素(作为节点)添加到内容可编辑div时

我需要通过多种方式不断保存的位置,以便能够在单击时插入html元素(我有一些标签)。

当我单击contentEditable div且div为空时(假设是第一个焦点),除非开始输入,否则看不到插入符号。如果插入符号在末尾,我也看不到它。

另一个怪异的行为是我不能使用箭头在contentEditable div中的文本之间导航。

如果我删除了(始终)保存插入符号位置的功能(在输入时单击等),则插入符号将恢复正常(插入符号可见)。

当我开始保存插入符号的位置时出现问题。显然,我应该进行某种重置或清除操作。但是,据我了解,这些操作似乎适得其反(因为据我了解,它们会破坏保存的插入符号位置)。

内容可编辑div

                <div class="input__boolean input__boolean--no-focus">
                    <div 
                            @keydown.enter.prevent
                            @blur="addPlaceholder"
                            @keyup="saveCursorLocation($event); fixDelete(); clearHtmlElem($event);"
                            @input="updateBooleanInput($event); clearHtmlElem($event);"
                            @paste="pasted"
                            v-on:click="clearPlaceholder(); saveCursorLocation($event);"
                            class="input__boolean-content"
                            ref="divInput"
                            contenteditable="true">Cuvinte cheie, cautare booleana..</div>
                </div>
Run Code Online (Sandbox Code Playgroud)

我的方法/功能

            inputLength($event){
                this.input_length = $event.target.innerText.length;
                if(this.input_length == 0)
                    this.typed = false;
            },
            addPlaceholder(){
                if(this.input_length == 0 && this.typed == false){
                    this.$refs.divInput.innerHTML = 'Cuvinte cheie, cautare booleana..'
                }
            },
            clearPlaceholder(){
                if(this.input_length == 0 && this.typed == false){
                    this.$refs.divInput.innerHTML = '';
                }
            },
            updateBooleanInput($event){
                this.typed = true;
                this.inputLength($event);
            },
            saveCursorLocation($event){
                if($event.which != 8){
                    if(this.saved_sel)
                        rangy.removeMarkers(this.saved_sel)
                    this.saved_sel = rangy.saveSelection();
                }
                // if(this.input_length == 0 && this.typed == false){
                //  var div = this.$refs.divInput;
                //  var sel = rangy.getSelection();
                //  sel.collapse(div, 0);
                // }
            },
            insertNode: function(node){
                var selection = rangy.getSelection();
                var range = selection.getRangeAt(0);
                range.insertNode(node);
                range.setStartAfter(node);
                range.setEndAfter(node);
                selection.removeAllRanges();
                selection.addRange(range);
            },
            addBooleanTag($event){
                // return this.$refs.ChatInput.insertEmoji($event.img);
                this.$refs.divInput.focus();
                console.log(this.input_length);
                if(this.typed == false & this.input_length == 0){
                    this.$refs.divInput.innerHTML = ''
                    var space = '';
                    this.typed = true
                    this.saveCursorLocation($event);
                }
                rangy.restoreSelection(this.saved_sel);

                var node = document.createElement('img');
                node.src = $event.img;
                node.className = "boolean-button--img boolean-button--no-margin";
                node.addEventListener('click', (event) => {
                    // event.currentTarget.node.setAttribute('contenteditable','false');
                    this.$refs.divInput.removeChild(node);
                })
                this.insertNode(node);
                this.saveCursorLocation($event);
            },
            clearHtmlElem($event){
                var i = 0;
                var temp = $event.target.querySelectorAll("span, br");
                if(temp.length > 0){
                    for(i = 0; i < temp.length; i++){
                        if(!temp[i].classList.contains('rangySelectionBoundary')){
                            if (temp[i].tagName == "br"){
                                temp[i].parentNode.removeChild(temp[i]);
                            } else {
                                temp[i].outerHTML = temp[i].innerHTML;
                            }
                        }
                    }
                }
            },
            pasted($event){
                $event.preventDefault();
                var text = $event.clipboardData.getData('text/plain');
                this.insert(document.createTextNode(text));
                this.inputLength($event);
                this.typed == true;
            },
            insert(node){
                this.$refs.divInput.focus();
                this.insertNode(node);
                this.saveCursorLocation($event);
            },
Run Code Online (Sandbox Code Playgroud)

正如您在saveCursorLocation()中看到的那样,我正在尝试解决这种情况,即您单击contentEditable div并且没有插入符号-这会使用户感到困惑。

                // if(this.input_length == 0 && this.typed == false){
                //  var div = this.$refs.divInput;
                //  var sel = rangy.getSelection();
                //  sel.collapse(div, 0);
                // }
Run Code Online (Sandbox Code Playgroud)

这是一个死胡同-很有可能是由于我对Rangy的了解不足以及我应该如何使用这些功能。

Firefox上的预期行为与实际结果

当我单击contentEditable div时,我希望插入符号出现(在后台保存我的位置)。键入时,我希望插入符号出现在最后一个键入的字符之后,同时也要进行键入以保存插入符号的位置。我也希望能够通过左/右箭头导航文本,并在这样做时看到插入符号。

所有这些都是由

v-on:click="..... saveCursorLocation($event);"
Run Code Online (Sandbox Code Playgroud)

@keyup="saveCursorLocation($event);....."
Run Code Online (Sandbox Code Playgroud)

如果有人认为这会有所帮助,则可以在Firefox中记录可编辑div的内容及其行为。

编辑:我设法隔离问题并将其重现为JSFiddle- https ://jsfiddle.net/Darkkz/6Landbj5/13 。

要找什么?

  • 在Firefox中打开小提琴链接,然后按蓝色按钮之一(SI,SAU,NU),然后查看输入,不显示插入符号。
  • 单击输入,不显示插入符号
  • 输入输入时,不显示插入符号。虽然,如果单击内容之间的单词/插入,将显示插入符号

Nic*_*lay 3

显然,当用户与 交互时,rangey 的选择保存和恢复模块不能用于跟踪当前选择contenteditable,就像您想要的那样。

我深入研究了一下,问题是 rangy 插入隐藏<span>s 作为标记,并将选择更新为标记之后,而不是将其保留在#text用户编辑的节点内:

 <div contenteditable>
    #text [This is something I typed <!-- selection is moved from here -->] 
    <span class="rangySelectionBoundary"/>
    <!-- to here -->
 </div>
Run Code Online (Sandbox Code Playgroud)

Firefox 在这种情况下显示插入符号时遇到问题(我还没有发现有关此特定问题的错误,但这里有一个类似的问题,当选择在两个s之间时,插入符号不会显示<span>)。

注释掉这段代码似乎可以解决插入符号消失的问题。我不清楚为什么需要该代码 - 它是在 1.0 之前的一次大型提交中添加的,其消息是:“修复了控制范围和多个范围选择的保存/恢复问题。添加了保存/恢复和 CSS 类应用程序的演示模块。” ——所以我不太愿意建议在 rangy 中修复这个问题(而且由于它已经有几年没有维护了,所以我对得到其作者的意见没有太大希望)。

所以我试图弄清楚为什么你首先需要这个,并建议其他不涉及的解决方案rangy.saveSelection(例如,rangy 的Text Range 模块提供了getSelection().saveCharacterRanges(containerNode)无需修改 DOM 即可工作的解决方案)。

看起来您有一个<div contenteditable>和一些“按钮” <span>,单击它们会在插入符号位置插入一些 HTML。您试图解决的问题是,当单击“按钮”时,选择范围从 移动到contenteditable按钮,并且您无法检测插入位置。

您可以制作按钮,而不是存储和恢复选择user-select: none- 这将使内容中的插入符号保持可编辑。

为了测试这一点,我注释掉了对rangy.saveSelection和 的所有引用rangy.restoreSelection,并将this.$refs.divInput.focus();“按钮”onclick处理程序中的调用更改为仅在contenteditable尚未聚焦时运行,将其包装在if (!this.$refs.divInput.contains(document.activeElement)). 看看这个更新的小提琴是如何工作的:
https://jsfiddle.net/fjxsgvm2/