Skip to content

Instantly share code, notes, and snippets.

@kidoman
Last active January 9, 2016 15:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kidoman/5625116 to your computer and use it in GitHub Desktop.
Save kidoman/5625116 to your computer and use it in GitHub Desktop.
A annotation library
function highlight(range) {
var textNodes = allTextNodes(range)
// Wrap all child text nodes
textNodes.forEach(function(node) {
var range = document.createRange()
range.selectNodeContents(node)
range.surroundContents(wrapperNode())
})
if (range.startContainer === range.endContainer) {
range.surroundContents(wrapperNode())
} else {
// Wrap start and end elements
wrapPartial(range, range.startContainer, 'start')
wrapPartial(range, range.endContainer, 'end')
}
// Kill existing user selection
window.getSelection().removeAllRanges()
function allTextNodes(range) {
var nodeIterator = document.createNodeIterator(range.commonAncestorContainer, NodeFilter.SHOW_TEXT, rejectEmpty)
, mark = false
, nodes = []
, node
while(node = nodeIterator.nextNode()) {
if (node == range.startContainer) {
mark = true
continue
} else if (node === range.endContainer) {
break
}
if (mark) nodes.push(node)
}
return nodes
function rejectEmpty(node) {
if (node.data.match(/^\s+$/)) return NodeFilter.FILTER_SKIP
return NodeFilter.FILTER_ACCEPT
}
}
function wrapPartial(range, node, position) {
var startOffset = position === 'start' ? range.startOffset : 0
, endOffset = position === 'start' ? node.length : range.endOffset
, range = document.createRange()
range.setStart(node, startOffset)
range.setEnd(node, endOffset)
range.surroundContents(wrapperNode())
}
function wrapperNode(type) {
if (type === undefined) type = 'span'
var elem = document.createElement(type)
elem.style.backgroundColor = 'red'
return elem
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment