在 window.getSelection() 之前添加空格会在选择中插入新节点时将其删除

问题描述 投票:0回答:1

我正在为我的应用程序中的选定文本构建 URL 链接功能。

  1. 我选择一段文字。
  2. 单击“链接”按钮。
  3. 在模式弹出窗口中输入 URL。
  4. 点击保存。
  5. 我再次单击“链接”按钮。
  6. 更新模式弹出窗口中的 URL。
  7. 点击保存。

到目前为止一切顺利。我能够创建和更新 html 中选定文本的 URL。但是,当我在所选文本之前添加空格或任何字符时,这种情况会中断。例如,

  1. 我在
    <div id="content">
    中选择“突出显示”一词。
  2. 单击“链接”按钮。
  3. 输入网址。
  4. 单击“保存”按钮。
  5. 现在“突出显示”一词将应用CSS。
  6. 现在我将光标放在“突出显示”之前并添加任意一个字符或空格。
  7. 单击“链接”按钮。
  8. 单击“保存”按钮。
  9. 这会删除我在“突出显示”一词之前添加的一个字符或空格。
  10. 现在,如果我再次重复步骤 6 - 9,则不会发生。它只是第一次发生,而不是之后发生。

我无法分享重现的 gif 图像。所以这里是重现视频链接 - https://github.com/fingers10/NugetVulnerabilityCheck/assets/43729469/3eac8cfe-4d8a-4e7b-a8a8-64c6d0585638

请您帮忙解决我所缺少的内容吗?

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Text Highlighter</title>
<style>
.highlighted {
    color: blue;
}
#popup {
    display: none;
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background: white;
    padding: 20px;
    border: 1px solid #ccc;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    z-index: 9999;
}
#content {
    white-space: pre;
}
</style>
<script src="js.js"></script>
</head>
<body>

<div id="content" contentEditable="plaintext-only">Select and highlight this text</div>
<button id="linkIcon">Link</button>

<!-- Popup -->
<div id="popup">
<input type="text" id="selectedText">
<input type="text" id="urlInput" placeholder="Enter URL">
<button id="saveBtn">Save</button>
</div>

<script>
document.addEventListener("DOMContentLoaded", function() {
var contentDiv = document.getElementById("content");
var linkIcon = document.getElementById("linkIcon");
var popup = document.getElementById("popup");
var selectedText = document.getElementById("selectedText");
var urlInput = document.getElementById("urlInput");
var selectionRange; // To store selection range
var originalSelection = ""; // To store original selection
var lastAnchorText = "";
var lastUrl = "";
var textSelected = false;
var newNode = document.createElement("a");

// Function to get selected text
function getSelectedText() {
    if (window.getSelection) {
        return window.getSelection().toString();
    } else if (document.selection && document.selection.type != "Control") {
        return document.selection.createRange().text;
    }
    return "";
}

// Function to check if an anchor element already exists in the selection range
function getExistingAnchor() {
    var nodes = selectionRange.cloneContents().childNodes;
    for (var i = 0; i < nodes.length; i++) {
        if (nodes[i].nodeName === "A") {
            return nodes[i];
        }
    }
    return null;
}

// Function to check if there is an existing link in the content
function checkExistingLink() {
    if (!textSelected) {
        return false;
    }

    var anchor = getExistingAnchor();
    if (anchor) {
        var existingLink = anchor.href;
        if (existingLink !== "") {
            urlInput.value = existingLink;
            selectedText.value = anchor.innerText;
            popup.style.display = "block";
            originalSelection = anchor.innerText;
            return true;
        }
    }
    return false;
}

// Event listener for link icon click
linkIcon.addEventListener("click", function() {
    if (!checkExistingLink()) {
        var selection = getSelectedText();
        if (selection !== "") {
            selectionRange = window.getSelection().getRangeAt(0); // Store selection range
            originalSelection = selection; // Store original selection
            selectedText.value = selection;
            if (lastAnchorText !== "" && lastUrl !== "") {
                urlInput.value = lastUrl;
                selectedText.value = lastAnchorText;
            } else {
                urlInput.value = "https://";
            }
            popup.style.display = "block";
        } else {
            alert("Please select some text first.");
        }
    }
});

// Event listener for save button click
document.getElementById("saveBtn").addEventListener("click", function() {
    var url = urlInput.value.trim();
    if (originalSelection !== "") {
        if (url !== "") {
            var existingAnchor = getExistingAnchor();
            if (existingAnchor) {
                existingAnchor.href = url;
                existingAnchor.innerText = originalSelection;
                newNode = existingAnchor;
            } else {
                newNode.href = url;
                newNode.innerText = originalSelection; // Use original selection
                newNode.classList.add("highlighted");
            }
            newNode.innerText = selectedText.value;
            selectionRange.deleteContents();
            selectionRange.insertNode(newNode);
            popup.style.display = "none";
            originalSelection = ""; // Reset original selection
            urlInput.value = "";
            lastAnchorText = originalSelection;
            lastUrl = url;
            textSelected = true;
        } else {
            alert("Please enter a URL.");
        }
    } else {
        alert("No text selected.");
    }
});
});
</script>

</body>
</html>

javascript html
1个回答
0
投票

经过一些调试和尝试,我能够通过单击链接按钮时重置范围的起始偏移量来解决此问题,如下所示。

let startOffset = contentDiv.innerText.indexOf(selectedText.value);
if (startOffset !== -1) {
    selectionRange?.setStart(contentDiv.firstChild, startOffset);   
}

这是满足我的要求的完整工作示例。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Text Highlighter</title>
<style>
    .highlighted {
        color: blue;
    }
    #popup {
        display: none;
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        background: white;
        padding: 20px;
        border: 1px solid #ccc;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
        z-index: 9999;
    }
    #content {
        white-space: pre;
    }
</style>
<script src="js.js"></script>
</head>
<body>

<div id="content" contentEditable="plaintext-only">Select and highlight this text</div>
<button id="linkIcon">Link</button>

<!-- Popup -->
<div id="popup">
    <input type="text" id="selectedText">
    <input type="text" id="urlInput" placeholder="Enter URL">
    <button id="saveBtn">Save</button>
</div>

<script>
document.addEventListener("DOMContentLoaded", function() {
    var contentDiv = document.getElementById("content");
    var linkIcon = document.getElementById("linkIcon");
    var popup = document.getElementById("popup");
    var selectedText = document.getElementById("selectedText");
    var urlInput = document.getElementById("urlInput");
    var selectionRange; // To store selection range
    var originalSelection = ""; // To store original selection
    var lastAnchorText = "";
    var lastUrl = "";
    var textSelected = false;
    var newNode = document.createElement("a");

    // Function to get selected text
    function getSelectedText() {
        if (window.getSelection) {
            return window.getSelection().toString();
        } else if (document.selection && document.selection.type != "Control") {
            return document.selection.createRange().text;
        }
        return "";
    }

    // Function to check if an anchor element already exists in the selection range
    function getExistingAnchor() {
        var nodes = selectionRange.cloneContents().childNodes;
        for (var i = 0; i < nodes.length; i++) {
            if (nodes[i].nodeName === "A") {
                return nodes[i];
            }
        }
        return null;
    }

    // Function to check if there is an existing link in the content
    function checkExistingLink() {
        if (!textSelected) {
            return false;
        }

        var anchor = getExistingAnchor();
        if (anchor) {
            var existingLink = anchor.href;
            if (existingLink !== "") {
                urlInput.value = existingLink;
                selectedText.value = anchor.innerText;
                popup.style.display = "block";
                originalSelection = anchor.innerText;
                return true;
            }
        }
        return false;
    }

    // Event listener for link icon click
    linkIcon.addEventListener("click", function() {
        let startOffset = contentDiv.innerText.indexOf(selectedText.value);
        if (startOffset !== -1) {
            selectionRange?.setStart(contentDiv.firstChild, startOffset);   
        }
        if (!checkExistingLink()) {
            var selection = getSelectedText();
            if (selection !== "") {
                selectionRange = window.getSelection().getRangeAt(0); // Store selection range
                originalSelection = selection; // Store original selection
                selectedText.value = selection;
                if (lastAnchorText !== "" && lastUrl !== "") {
                    urlInput.value = lastUrl;
                    selectedText.value = lastAnchorText;
                } else {
                    urlInput.value = "https://";
                }
                popup.style.display = "block";
            } else {
                alert("Please select some text first.");
            }
        }
    });

    // Event listener for save button click
    document.getElementById("saveBtn").addEventListener("click", function() {
        var url = urlInput.value.trim();
        if (originalSelection !== "") {
            if (url !== "") {
                var existingAnchor = getExistingAnchor();
                if (existingAnchor) {
                    existingAnchor.href = url;
                    existingAnchor.innerText = originalSelection;
                    newNode = existingAnchor;
                } else {
                    newNode.href = url;
                    newNode.innerText = originalSelection; // Use original selection
                    newNode.classList.add("highlighted");
                }
                newNode.innerText = selectedText.value;
                selectionRange.deleteContents();
                selectionRange.insertNode(newNode);
                popup.style.display = "none";
                originalSelection = ""; // Reset original selection
                urlInput.value = "";
                lastAnchorText = originalSelection;
                lastUrl = url;
                textSelected = true;
            } else {
                alert("Please enter a URL.");
            }
        } else {
            alert("No text selected.");
        }
    });
});
</script>

</body>
</html>

© www.soinside.com 2019 - 2024. All rights reserved.