Я пытаюсь создать небольшой скрипт, который я мог бы использовать для простой маркировки (выделения) текста на любой странице, которую можно использовать для изучения (цифровая версия выделения текста в книге желтым маркером).
У меня не так много знаний о функции .getSelection () и о том, как поэкспериментировать с выбором и диапазоном, которые вы получаете из нее, поэтому я надеюсь, что кто-то здесь может мне помочь.
Вот некоторые изображения, показывающие и, я надеюсь, объясняющие, что я пытаюсь выполнить.
Первое изображение объяснения
Второе изображение объяснения
Третье объяснительное изображение
Четвертое пояснительное изображение
Вот мой код сценария.Я относительно новичок в кодировании 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 и т.д.Я действительно не знаю, почему это изменилось, поскольку оно просто сохраняется в «выбранном» массиве, но, пожалуйста, объясните, почему это происходит, если кто-то знает:)