我正在尝试创建一个小脚本,以便可以在任何可用于学习的页面(数字版本的带有黄色标记的书中突出显示文本)上轻松标记(突出显示)文本。
我真的不太了解.getSelection()函数,以及如何处理从中获得的Selection和Range,所以我希望这里有人可以帮助我。
以下是一些图片,希望能解释我要完成的工作。
这是我的脚本代码。我是JS编码的新手,我主要是为了练习和娱乐,所以很抱歉,如果某些代码看起来不好:
https://codepen.io/MathiasWP/pen/axREWb
// The pop-up box is created from scratch here in JS
const mainText = `
<p>Export</p>
<h2>Marked elements:</h2>
<span class="marked"></span>`;
const popup = document.createElement("div");
setTimeout(() => {
document.body.appendChild(popup);
// Pop-up box gets some preset text
popup.innerHTML = mainText;
}, 200);
// Styling of the pop-up box
popup.style.visibility = "hidden";
popup.style.width = "300px";
popup.style.position = "fixed";
popup.style.zIndex = "100";
popup.style.bottom = "0";
popup.style.right = "0";
popup.style.marginRight = "10px";
popup.style.color = "white";
popup.style.backgroundColor = "#282c34";
popup.style.padding = "20px";
popup.style.borderRadius = "15px 15px 0px 0px";
popup.style.maxHeight = "400px";
popup.style.overflowY = "scroll";
popup.style.fontFamily = '"Trebuchet MS", Helvetica, sans-serif';
// The selected text gets set to the variable
let selection = window.getSelection();
// Array where all selected text will be stored
const selected = [];
// Variable that stores all of the text on the entire page as a string
setTimeout(() => {
const pageText = document.body.innerText.toString();
}, 200);
mouseUp = e => {
// If nothing is selected, return
if (selection.isCollapsed) return;
//Kind of a bug fix, where if the marked text is 100% equal the last selected then it also will return (this fixed a small bug where if you marked a text and clicked on the screen it would be stored again)
else if (selection.toString() === selected.slice(-1)[0]) {
return;
}
// Here's where all the fun begins
else {
// If selected text is just whitespace then nothing happens (just for practical use)
if (!selection.toString().replace(/\s/g, "").length) return;
else {
if (!e) e = window.event;
// If command/ctrl button is held when text is marked, the function will run the main stuff
if (e.metaKey) {
// Just an awkard way to make the popup show up when text has been marked, could find a better way to to this but i'm lazy right now
popup.style.visibility = "visible";
// The selected text gets pushed to the selected-text-array
selected.push([
selection,
selection.toString(),
selection.anchorOffset,
selection.focusOffset,
selection.getRangeAt(0)
]);
// Design Mode gets turned on, found this was the easiest way to highlight the selected text on the page
document.designMode = "on";
// Where the selected text gets the background-color changed
// The color of selected text in Google Chrome is #bad6fb. That one can also be used (looks kinda cool).
document.execCommand("backColor", false, "yellow");
// Design mode gets turned off
document.designMode = "off";
console.log(selection);
console.log(selection.getRangeAt(0));
console.log(selected);
// Runs the function that writes everything in the pop-up box
updateBox();
}
}
}
};
// Function that removes the chosen element in the list. Could've made everything prettier and easier with for example jQuery, but decided to make everything pure vanilla JS
removeMark = element => {
let thisElement = [selected[element.id.replace("marked-id-", "")][0], selected[element.id.replace("marked-id-", "")][4]];
console.log(thisElement);
node = thisElement[1].startContainer;
if (document.body.createTextRange) {
const range = document.body.createTextRange();
range.moveToElementText(node);
range.select();
} else if (window.getSelection) {
const selection = thisElement[0];
const range = thisElement[1];
range.selectNodeContents(node);
selection.removeAllRanges();
selection.addRange(range);
} else {
console.warn("Could not select text in body: Unsupported browser.");
}
// Desin mode ON
document.designMode = "on";
// Removes selected color
//document.execCommand("backColor", false, "pink");
// Design mode OFF
document.designMode = "off";
// Removes the element from the selected-text array
selected.splice(thisElement, 1);
// Runs function that writes what should be in the box (doing this everytime to update the id's of the other elements in the box when something gets removed)
updateBox();
// Hides the pop-up box if nothing selected (used to remove the pop-up box if everything in it is removed by the user)
if (selected.length === 0) {
popup.style.visibility = "hidden";
}
};
updateBox = () => {
// Awkward way to make all the selected text displayed in the pop-up box. First everything gets removed and set to start...
popup.innerHTML = mainText;
// ... and then every element gets inserted adjacently after each other
selected.forEach(el =>
document
.querySelector(".marked")
.insertAdjacentHTML(
"beforeend",
`<span><br><b>-</b> ${
el[1]
} <p style="color:red;cursor:pointer" id="marked-id-${selected.indexOf(el)}" onclick="removeMark(this); return false;">(remove)</p><br></span>`
)
);
}
// Part of the script that actually makes everything happen after mouse is no longer held down
window.addEventListener("mouseup", mouseUp);
我还遇到了其他一些问题。例如,当我尝试选择上一个文本时(如图4所示),那么有时会选中整个段落。我遇到的另一个错误是当我在控制台日志“ thisElement”中登录时,baseNode,anchorNode,endContainer等变量被更改。我真的不知道为什么更改它,因为它只是存储在“ selected”数组中,但是如果有人知道,请解释为什么这样做:)