Last active
December 19, 2015 03:59
-
-
Save jharding/5893957 to your computer and use it in GitHub Desktop.
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
(function(doc) { | |
var defaults = { | |
node: null, | |
pattern: null, | |
depth: -1, | |
tagName: 'strong', | |
className: 'jake', | |
wordsOnly: false, | |
caseSensitive: false | |
}; | |
this.bearhug = function bearhug(o) { | |
var regex, textNodes, textNode, newNode; | |
o = mixin({}, defaults, o); | |
if (!o.node || !o.pattern) { | |
throw new Error('both node and pattern must be set'); | |
} | |
// support wrapping multiple patterns | |
o.pattern = isArray(o.pattern) ? o.pattern : [o.pattern]; | |
regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly); | |
textNodes = traverse(o.node, whatevs, o.depth); | |
function whatevs(textNode) { | |
if (regex.test(textNode.data)) { | |
newNode = strToNode(textNode.data); | |
textNode.parentNode.replaceChild(newNode, textNode); | |
} | |
} | |
function strToNode(str) { | |
var fragment = doc.createDocumentFragment(), nodes = getNodes(str); | |
for (var i = 0; i < nodes.length; i++) { | |
fragment.appendChild(nodes[i]); | |
} | |
return fragment; | |
} | |
function getNodes(str) { | |
var match = regex.exec(str), before, pattern, after, nodes = []; | |
if (match) { | |
before = match[1]; | |
pattern = match[2]; | |
after = match[3]; | |
before && nodes.push.apply(nodes, getNodes(before)); | |
nodes.push(wrapPattern(pattern)); | |
after && nodes.push.apply(nodes, getNodes(after)); | |
} | |
else { | |
nodes.push(doc.createTextNode(str)); | |
} | |
return nodes; | |
} | |
function wrapPattern(str) { | |
var wrapperNode = doc.createElement(o.tagName); | |
o.className && (wrapperNode.className = o.className); | |
wrapperNode.appendChild(doc.createTextNode(str)); | |
return wrapperNode; | |
} | |
}; | |
function getRegex(patterns, caseSensitive, wordsOnly) { | |
var escapedPatterns = [], escapedPattern, regexStr; | |
for (var i = 0; i < patterns.length; i++) { | |
escapedPattern = wordsOnly ? | |
'\\b' + escapeRegexChars(patterns[i]) + '\\b' : | |
escapeRegexChars(patterns[i]); | |
escapedPatterns.push(escapedPattern); | |
} | |
regexStr = '^(.*)(' + escapedPatterns.join('|') + ')(.*)$'; | |
return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, 'i'); | |
} | |
function traverse(el, fn, depth) { | |
var numOfChildren = el.childNodes.length, | |
childNode, | |
textNodes = [], | |
TEXT_NODE_TYPE = 3; | |
for (var i = 0; i < numOfChildren; i++) { | |
childNode = el.childNodes[i]; | |
if (childNode.nodeType === TEXT_NODE_TYPE) { | |
fn(childNode); | |
} | |
else if (childNode.className === 'jake') { | |
console.log('wat?'); | |
} | |
else if (childNode.nodeType === 1 && depth !== 0) { | |
traverse(childNode, fn, depth - 1); | |
} | |
} | |
} | |
function mixin(target) { | |
var objs = [].slice.call(arguments, 1), obj; | |
for (var i = 0; i < objs.length; i++) { | |
obj = objs[i]; | |
for (var key in obj) { | |
obj.hasOwnProperty(key) && (target[key] = obj[key]); | |
} | |
} | |
return target; | |
} | |
// http://stackoverflow.com/a/6969486 | |
function escapeRegexChars(str) { | |
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); | |
} | |
function isArray(obj) { | |
return Object.prototype.toString.call(obj) === '[object Array]'; | |
} | |
})(window.document); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment