Created
August 16, 2016 17:09
-
-
Save adamnew123456/7858cbc9320cc95af9bc119719fffec0 to your computer and use it in GitHub Desktop.
Various Small DOM-manipulation Utilities
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Returns a list of all the text nodes under the given node. | |
* | |
* The order should be depth-first, first-to-last across siblings. | |
*/ | |
function findTextNodes(node) { | |
var HTML_TEXT_NODE = 3; | |
if (node.nodeType == HTML_TEXT_NODE) { | |
return [node]; | |
} | |
var text_nodes = []; | |
var to_search = []; | |
function recordChildren(node) { | |
for (var i = 0; i < node.childNodes.length; i++) { | |
to_search.push(node.childNodes[i]); | |
} | |
} | |
recordChildren(node); | |
while (to_search.length > 0) { | |
var node = to_search.shift(); | |
if (node.nodeType == HTML_TEXT_NODE) { | |
text_nodes.push(node); | |
} else { | |
recordChildren(node); | |
} | |
} | |
return text_nodes; | |
} | |
/* | |
* Creates a new text node, and returns it. | |
*/ | |
function Text(text) { | |
var node = document.createTextNode(text); | |
return node; | |
} | |
/* | |
* Takes a text node, and splits it into three parts: | |
* | |
* - The text before some range | |
* - The text of the range | |
* - The text after some range | |
* | |
* Note that the range is of the form [start, end) - i.e. Python style slices/ranges. | |
* | |
* Returns the three nodes as a list. | |
*/ | |
function splitText(text_node, range_start, range_end) { | |
var before = text_node.textContent.substring(0, range_start); | |
var range = text_node.textContent.substring(range_start, range_end); | |
var after = text_node.textContent.substring(range_end); | |
var before_text = Text(before); | |
var after_text = Text(after); | |
text_node.textContent = range; | |
text_node.parentNode.insertBefore(before_text, text_node); | |
text_node.parentNode.insertBefore(after_text, text_node.nextSibling); | |
return [before_text, text_node, after_text]; | |
} | |
/* | |
* Wraps a text node with a highlight. | |
*/ | |
function highlightText(node) { | |
var highlight_style = document.createElement('span'); | |
highlight_style.style.background = 'yellow'; | |
highlight_style.style.color = 'black'; | |
node.parentNode.replaceChild(highlight_style, node); | |
highlight_style.appendChild(node); | |
} | |
/* | |
* Highlights the contents of the selection. | |
*/ | |
function highlightSelection() { | |
var selection = document.getSelection(); | |
var range = selection.getRangeAt(0); | |
/* | |
* Ranges cover a series of nodes in the DOm, like this (caps are in the range): | |
* | |
* a | |
* B c | |
* D E | |
* | |
* The range goes from [B, E] and its common ancestor is a. | |
*/ | |
var start_node = range.startContainer; | |
var end_node = range.endContainer; | |
// These are the actual indexes into the startnig and ending text nodes | |
var start_idx = range.startOffset; | |
var end_idx = range.endOffset; | |
var toplevel_node = range.commonAncestorContainer; | |
var text_nodes = findTextNodes(toplevel_node); | |
var in_selection = false; | |
for (var i = 0; i < text_nodes.length; i++) { | |
var node = text_nodes[i]; | |
if (node === start_node) { | |
// If we stay in the same node, then we have to extract a portion of the node | |
// that goes from the startOffset to the endOffset | |
if (start_node === end_node) { | |
var replaced = splitText(node, start_idx, end_idx); | |
highlightText(replaced[1]); | |
break; | |
} else { | |
in_selection = true; | |
var replaced = splitText(node, start_idx, node.textContent.length); | |
highlightText(replaced[1]); | |
} | |
} else if (node === end_node) { | |
var replaced = splitText(node, 0, end_idx); | |
highlightText(replaced[1]); | |
break; | |
} else if (in_selection) { | |
highlightText(node); | |
} | |
} | |
} | |
/* | |
* Redacts the content of a text node. | |
*/ | |
function redactText(node) { | |
var block = "■"; | |
var node_length = node.textContent.length; | |
var blocks = []; | |
for (var i = 0; i < node_length; i++) { | |
blocks.push(block); | |
} | |
node.textContent = blocks.join(''); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment