Я хочу получить выбор пользователя, а затем заменить их тегом метки на каждом текстовом узле внутри элемента, если пользователь выбрал два текстовых узла, которые являются дочерними, внуками (например: внутри тега, который является дочерним), поэтому окружите первый узел с <mark>first text node</mark>
и второй вот так <mark><a>partial of second</a></mark><a>rest which is not highlighted</a>
<div>
<p id = "first" data-selectable-paragraph = "">
At the very first age, JavaScript was called LiveScript. An engineer named Brendan Eich has created JavaScript in 1995. There was a little confused about the name with Java and JavaScript. After several months Microsoft released JScript with Internet Explorer 3. After that Netscape submitted JavaScript to Ecma International. In 1999 ECMAScript edition 3 launched and it has stayed pretty much stable ever since.
</p>
<p>
Another Selection <span> you could do</span>
</p>
<p id = "second" data-selectable-paragraph = "">
Range is something I discovered recently, which again showed me that the possibilities with the Javascript and the DOM are truly endless. As stated on Mozilla’s developer site, range ‘represents a fragment of a document that can contain nodes and parts of text nodes’. So, if you create of select a section of a document, range could tell you the nodes that it contains, its starting and ending positions relative to the document, it can clone its content ,and much more. (Read more from the docs:
<a href = "https://developer.mozilla.org/en-US/docs/Web/API/Range">
https://developer.mozilla.org/en-US/docs/Web/API/Range
</a>)
</p>
</div>
скажем, что пользователь выбрал 3 текста и выделил их, которые я хочу привести к этой структуре-> Краткое объяснение: если у родителя или дедушки и бабушки есть абзац, выбираемый данными, тогда выделите текстовые узлы внутри элемента и его родителя, если это внук
<div>
<p id = "first" data-selectable-paragraph>
At the very first age, JavaScript was called LiveScript. An engineer named Brendan Eich has created JavaScript in 1995. There was a little confusion about the name with Java and JavaScript. After several months Microsoft released JScript with Internet Explorer 3. After that Netscape submitted JavaScript to Ecma International. In 1999 ECMAScript edition 3 <mark>launched and it has stayed pretty much stable ever since.</mark>
</p>
<p class='second' data-selectable-paragraph>
<mark>Another Selection </mark><mark><span> you could do</span></mark>
</p>
<p id = "third" data-selectable-paragraph>
<mark>
Range is something I discovered recently, which again showed me that the possibilities with the Javascript and the DOM are truly endless. As stated on Mozilla’s developer site, range ‘represents a fragment of a document that can contain nodes and parts of text nodes’. So, if you create of select a section of a document, range could tell you the nodes that it contains, its starting and ending positions relative to the document, it can clone its content ,and much more. (Read more from the docs:
</mark>
<mark>
<a href = "https://developer.mozilla.org/en-US/docs/Web/API/Range">
https://developer.mozilla.org/en-US/docs/Web/API/Range
</a>
</mark>
<mark>)</mark>
</p>
</div>
то, что я нашел до сих пор, было window.getSelection().getRangeAt(0).commonAncestorContainer.hasAttribute("data-selectable-paragraph");
на мышке, но я не знаю, что делать дальше
Обновлено:
Выбранный текст
its parent is the first P.
its parent is the second P.
its parent is the third P.
Есть фрагменты до и после, поэтому, пожалуйста, примите их во внимание.
да, это не работает, если только это не текстовый узел.
пожалуйста, добавьте более подробную информацию, например, что выбрал пользователь, что было текущим родителем и прародителем выбора, какие изменения происходят с выделенным текстом, родителем, прародителем,. и т. д.
@Chandan Я отредактировал его, но если бы вы посмотрели фрагмент до и после, вы бы его увидели.
@Boudyhesham, я не мог понять, выбирает ли пользователь весь текст по одному или весь сразу
У вас есть только одна строка кода. window.getSelection().getRangeAt(0).commonAncestorContainer.hasAttribute("data-selectable-paragraph");
И вы показываете это не в контексте. У вас есть полная страница, которую мы могли бы посмотреть?
Вот начало. Я просто разрешаю вам пометить текст один раз, а не устанавливать и снимать отметки.
window.onload = function () {
var btn = document.getElementsByClassName("get_selection")[0];
btn.addEventListener("click", function () {
var wrap = ["A"]; // nodes that should be wrapped in mark (rather than node's textContent wrapped in mark)
var sel = window.getSelection();
var range = sel.getRangeAt(0);
if (!range.startContainer.isSameNode(range.endContainer)) {
// get all nodes within the range commonAncestorContainer node
var treeWalker = document.createTreeWalker(
range.commonAncestorContainer,
NodeFilter.SHOW_ALL
);
var nodeList = [];
var currentNode = treeWalker.currentNode;
while (currentNode) {
nodeList.push(currentNode);
currentNode = treeWalker.nextNode();
}
var start = null; // index that our selected nodes start
var end = null; // index that our selected nodes end
var selNodes = nodeList.filter(function (val, i) {
// filter the node list
var node = nodeList[i];
start = start ?? (val.isSameNode(range.startContainer) ? i : null); // if same as start node
end = end ?? (val.isSameNode(range.endContainer) ? i : null); // if same as end node
var lesser = start == null || i <= start; // is before start node?
var greater = end != null && i >= end; // is after end node?
return (
!lesser &&
!greater &&
!node.isSameNode(range.endContainer.parentNode) && // node is not same as end node's parent
node != undefined &&
node != null &&
node.textContent.replace(/\t|\n/g, "") != "" &&
node.textContent.replace(/\t|\n/g, "") != undefined &&
!node.contains(range.endContainer) && // node does not contain end node
!node.isSameNode(range.endContainer.parentNode) // node is not same as end node's parent
);
});
// mark node at start of selection
var sParent = range.startContainer.parentNode;
var sText = range.startContainer.textContent;
var mark = document.createElement("mark");
// wrap a tags in mark
if (
wrap.includes(sParent.nodeName) &&
sText.replace(/\t+|\n+/gm, "") ==
sText.substring(range.startOffset).replace(/\t+|\n+/gm, "")
) {
var node = sParent.cloneNode(true);
mark.append(node);
sParent.after(mark);
sParent.remove();
} else {
mark.textContent = sText.substring(range.startOffset);
range.startContainer.textContent = sText.substring(range.startOffset, -1);
range.startContainer.after(mark);
}
// mark node at end of selection
var eParent = range.endContainer.parentNode;
// console.info("end parent: ", eParent);
var eText = range.endContainer.textContent;
var mark = document.createElement("mark");
// wrap a tags in mark
if (
wrap.includes(eParent.nodeName) &&
eText.replace(/\t+|\n+/gm, "") ==
eText.substring(range.endOffset, -1).replace(/\t+|\n+/gm, "")
) {
var node = eParent.cloneNode(true);
mark.append(node);
eParent.after(mark);
eParent.remove();
} else {
mark.textContent = eText.substring(range.endOffset, -1);
range.endContainer.textContent = eText.substring(range.endOffset);
range.endContainer.before(mark);
}
// mark nodes in between start and end
selNodes.forEach(function (val, idx) {
var currentNode = selNodes[idx];
var mark = document.createElement("mark");
if (currentNode.nodeType === Node.TEXT_NODE) {
// if text node, insert mark after node and remove node
mark.textContent = currentNode.textContent;
currentNode.after(mark);
currentNode.remove();
} else {
if (wrap.includes(currentNode.nodeName)) {
var node = currentNode.cloneNode(true);
mark.append(node);
currentNode.after(mark);
currentNode.remove();
} else {
// reset the node's html and append mark
mark.textContent = currentNode.textContent;
currentNode.innerHTML = "";
currentNode.appendChild(mark);
}
}
});
} else {
var parentNode = range.startContainer.parentNode;
var mark = document.createElement("mark");
if (wrap.includes(parentNode.nodeName)) {
var node = parentNode.cloneNode(true);
node.textContent = sel.toString();
mark.append(node);
parentNode.after(mark);
parentNode.remove();
} else {
var sText = document.createTextNode(
range.startContainer.textContent
.substring(range.startOffset, -1)
.toString()
);
var eText = document.createTextNode(
range.endContainer.textContent.substring(range.endOffset).toString()
);
mark.textContent = sel.toString();
range.startContainer.after(eText);
range.startContainer.after(mark);
range.startContainer.after(sText);
range.startContainer.remove();
}
}
});
};
<button class = "get_selection">Set Markers</button>
<div>
<p id = "first" data-selectable-paragraph>
At the very first age, JavaScript was called LiveScript. An engineer named Brendan Eich has created JavaScript in 1995. There was a little confusion about the name with Java and JavaScript. After several months Microsoft released JScript with Internet
Explorer 3. After that Netscape submitted JavaScript to Ecma International. In 1999 ECMAScript edition 3 launched and it has stayed pretty much stable ever since.
</p>
<p class='second' data-selectable-paragraph>
Another Selection <span> you could do</span>
</p>
<p id = "third" data-selectable-paragraph>
Range is something I discovered recently, which again showed me that the possibilities with the Javascript and the DOM are truly endless. As stated on Mozilla’s developer site, range ‘represents a fragment of a document that can contain nodes and parts
of text nodes’. So, if you create of select a section of a document, range could tell you the nodes that it contains, its starting and ending positions relative to the document, it can clone its content ,and much more. (Read more from the docs:
<a href = "https://developer.mozilla.org/en-US/docs/Web/API/Range">
https://developer.mozilla.org/en-US/docs/Web/API/Range
</a> )
</p>
</div>
это то, что я искал, это не то, что я хочу на 100%, но это на 75% то, что я хочу, спасибо, щедрость закончилась, но я собираюсь возобновить ее снова, можете ли вы вкратце объяснить, как древолаз проходит через это, потому что я я никогда не имел дело с API-интерфейсом treeWalker, если вы выберете текстовый узел и текстовый узел тега привязки, вы пометите текст, который находится внутри тега привязки, но я ищу клонирование самого тега и размещение только выбранного текстового узла внутри якоря внутри тега метки это не обязательно, это необязательно, но если вы поможете мне с этим, я ценю это.
@Boudyhesham Хорошо, если тег привязки выбран только частично, вы бы не хотели помечать все это, не так ли?
да, я бы не хотел помечать весь тег, но клонировал сам тег (без каких-либо дочерних узлов), удалял выделенный текстовый узел и помещал его в клонированный тег и помещал его в дом. Примечание: если частично выделенный текст в начале тега якоря я вставлю клонированный тег перед исходным тегом привязки, если он находится в конце, я вставлю его после оригинального тега привязки
и еще один комментарий, не связанный с этим, как вы узнали о treewalker, я имею в виду, что у меня 1 год опыта, и я никогда не имел возможности узнать об этом, можете ли вы сказать мне, есть ли хорошие книги, чтобы стать лучшим js-разработчиком, спасибо, и я очень ценю это.
@Boudyhesham Честно говоря, просто изучение Интернета помогло мне найти его. Например, просмотр codepen и stackoverflow помогает вам находить новые вещи. Кстати, я использую MDN для документации, мне он нравится больше, чем школы ww3, просто он кажется мне более «собранным».
Можете ли вы кратко объяснить, как здесь работает treewalker.
@Boudyhesham API-интерфейс treewalker позволяет вам получать узлы внутри указанного узла (range.commonAncestorContainer, который является общим предком начального узла выбора и конечного узла), вы можете использовать NodeFilter для фильтрации типов отображаемых узлов. Я использую show_all для получения всех типов узлов. Затем прокрутите узлы, используя цикл while. Пока treewalker.currentNode
существует, поместите его в массив списка узлов и установите текущий узел как treewalker.nextNode
, если следующий узел существует, вырваться. Вот документация: developer.mozilla.org/en-US/docs/Web/API/TreeWalker
@Boudyhesham Забыл упомянуть, что мой ответ и код были обновлены, чтобы обернуть теги a
в тег mark
, только когда выбран весь тег, я не совсем понимаю, что вы хотите, когда текст тега a
выделен частично.
Обратите внимание, что вы удаляете остальную часть тега между прочим
О, это потрясающе! Действительно то, что мне нужно! Сложно ли заставить запоминать выделенные места при перезагрузке страницы и удалять отмеченные при длительном нажатии? @Сулесте
@RGS Скорее всего, вы можете хранить диапазоны с помощью файлов cookie. Чтобы удалить при длительном нажатии, вы можете посмотреть дочерние узлы родительского и предыдущего сиблинга, следующего сиблинга узла метки.
Я обрадовался, когда увидел
surroundContents
дляRange
объектов, но это не совсем подходит для этого сценария :( developer.mozilla.org/en-US/docs/Web/API/Range/surroundContents