我正在为我的应用程序中的选定文本构建 URL 链接功能。
到目前为止一切顺利。我能够创建和更新 html 中选定文本的 URL。但是,当我在所选文本之前添加空格或任何字符时,这种情况会中断。例如,
<div id="content">
中选择“突出显示”一词。我无法分享重现的 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>
经过一些调试和尝试,我能够通过单击链接按钮时重置范围的起始偏移量来解决此问题,如下所示。
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>