Skip to content

Instantly share code, notes, and snippets.

@sardinecan
Created June 17, 2024 14:06
Show Gist options
  • Save sardinecan/1b291d2b9efe515a92c713b19dcf2d80 to your computer and use it in GitHub Desktop.
Save sardinecan/1b291d2b9efe515a92c713b19dcf2d80 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Selection Info</title>
</head>
<body>
<div id="example">
<p>With <i>mixed</i> content <u>and</u> text...</p>
<p>...running over <b>more</b> than <span>one paragraph</span>...</p>
<p>...and over, and <span>over</span>!</p>
</div>
<script>
function getSelectionInfo() {
const selection = window.getSelection();
if (!selection.rangeCount) return null;
const range = selection.getRangeAt(0);
const startNode = range.startContainer;
const endNode = range.endContainer;
// Get XPath
function getXPath(node) {
if (node.nodeType === Node.TEXT_NODE) {
node = node.parentNode;
}
const parts = [];
while (node && node.nodeType === Node.ELEMENT_NODE) {
let count = 0;
let sibling;
for (sibling = node.previousSibling; sibling; sibling = sibling.previousSibling) {
if (sibling.nodeType === Node.ELEMENT_NODE && sibling.nodeName === node.nodeName) {
count++;
}
}
const part = node.nodeName.toLowerCase() + (count > 0 ? '[' + (count + 1) + ']' : '');
parts.unshift(part);
node = node.parentNode;
}
return parts.length ? '/' + parts.join('/') : null;
}
// Get the XPath of the start and end nodes
const startXPath = getXPath(startNode);
const endXPath = getXPath(endNode);
// Calculate index and length
const startIndex = range.startOffset;
const endIndex = range.endOffset;
const textLength = range.toString().length;
return {
startXPath: startXPath,
endXPath: endXPath,
startIndex: startIndex,
endIndex: endIndex,
length: textLength
};
}
document.addEventListener('mouseup', () => {
const selectionInfo = getSelectionInfo();
if (selectionInfo) {
console.log('Selection Info:', selectionInfo);
}
});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Highlight Text</title>
<style>
.highlight {
background-color: yellow;
}
</style>
</head>
<body>
<div id="example">
<p>With <i>mixed</i> content <u>and</u> text...</p>
<p>...running over <b>more</b> than <span>one paragraph</span>...</p>
<p>...and over, and <span>over</span>!</p>
</div>
<script>
function highlightText(startXPath, startIndex, highlightLength) {
function getNodeByXPath(xpath) {
const evaluator = new XPathEvaluator();
const result = evaluator.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
return result.singleNodeValue;
}
const startNode = getNodeByXPath(startXPath);
if (!startNode || startNode.nodeType !== Node.TEXT_NODE) {
console.error('Invalid XPath or the node is not a text node.');
return;
}
let remainingLength = highlightLength;
let nodesToHighlight = [];
let foundStart = false;
function traverse(node) {
if (node.nodeType === Node.TEXT_NODE) {
let textContent = node.textContent;
if (!foundStart) {
if (node === startNode) {
foundStart = true;
let textToEnd = textContent.slice(startIndex);
nodesToHighlight.push({ node, start: startIndex, length: Math.min(remainingLength, textToEnd.length) });
remainingLength -= textToEnd.length;
}
} else if (remainingLength > 0) {
nodesToHighlight.push({ node, start: 0, length: Math.min(remainingLength, textContent.length) });
remainingLength -= textContent.length;
}
} else if (node.nodeType === Node.ELEMENT_NODE) {
for (let i = 0; i < node.childNodes.length; i++) {
if (remainingLength <= 0) return;
traverse(node.childNodes[i]);
}
}
}
// Start traversal from the root container
traverse(document.body);
// Apply the highlighting
nodesToHighlight.forEach(({ node, start, length }) => {
const highlightedText = node.textContent.slice(0, start) +
`<span class="highlight">${node.textContent.slice(start, start + length)}</span>` +
node.textContent.slice(start + length);
const span = document.createElement('span');
span.innerHTML = highlightedText;
node.replaceWith(...span.childNodes);
});
}
// Example usage
highlightText('//div/p[1]/text()', 0, 36); // Highlight starting at <i>mixed</i> and including the next 37 characters
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment