Skip to content

Instantly share code, notes, and snippets.

@datchley
Last active March 19, 2019 05:59
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save datchley/11383482 to your computer and use it in GitHub Desktop.
Save datchley/11383482 to your computer and use it in GitHub Desktop.
DOM related utilities, implementations for wrap(), wrapAll(), geStyle() and getElementsByClassName() - try it http://jsbin.com/jozaje/1/
/** Faster rounding function to avoid heavy use of Math.round */
function round(n) {
return (n + 0.5) << 0;
}
/**
* Wrapper for getBoundingClientRect that returns a
* subset ('top','left') and includes a 'width' and 'height'.
* It also rounds the pixel measurements to the nearest integer value
*
* @param {HTMLElement|jQuery} DOM element to get rectangle for
* @returns {Object}
*/
function getRect(element) {
var el = element.jquery ? element[0] : element,
rect = el.getBoundingClientRect();
return {
top: round(rect.top),
left: round(rect.left),
height: round(rect.bottom) - round(rect.top),
width: round(rect.right) - round(rect.left)
};
}
/** Implementation of getElementsByClassName, for IE 9 and below */
var getElementsByClassName = function(className, parentElement) {
var children = (parentElement || document.body).getElementsByTagName('*'),
elements = [],
classRE = new RegExp('\\b' + className + '\\b'),
child;
for (var i = 0, length = children.length; i < length; i++) {
child = children[i];
if (classRE.test(child.className)) {
elements.push(child);
}
}
return elements;
};
/**
* Wrap an HTMLElement around each element in a list of elements
* Modified global function based on Kevin Jurkowski's implementation
* here: http://stackoverflow.com/questions/3337587/wrapping-a-dom-element-using-pure-javascript/13169465#13169465
*/
function wrap(wrapper, elms) {
if (!elms.length) {
elms = [elms];
}
for (var i = elms.length - 1; i >= 0; i--) {
var child = (i > 0) ? wrapper.cloneNode(true) : wrapper;
var el = elms[i];
var parent = el.parentNode;
var sibling = el.nextSibling;
child.appendChild(el);
if (sibling) {
parent.insertBefore(child, sibling);
} else {
parent.appendChild(child);
}
}
}
/**
* Wrap an HTMLElement around another set of elements
* Modified global function based on Kevin Jurkowski's implementation
* here: http://stackoverflow.com/questions/3337587/wrapping-a-dom-element-using-pure-javascript/13169465#13169465
*/
function wrapAll(wrapper, elms) {
var el = elms.length ? elms[0] : elms,
parent = el.parentNode,
sibling = el.nextSibling;
wrapper.appendChild(el);
while (elms.length) {
wrapper.appendChild(elms[0]);
}
if (sibling) {
parent.insertBefore(wrapper, sibling);
}
else {
parent.appendChild(wrapper);
}
}
/** IE8 and below don't have getComputedStyle, so polyfill it... */
var getStyle = (function() {
window.getComputedStyle = window.getComputedStyle || function(el, prop) {
this.el = el;
this.getPropertyValue = function(prop) {
var re = /(\-([a-z]){1})/g;
if (prop == 'float') { prop = 'styleFloat'; }
if (re.test(prop)) {
prop = prop.replace(re, function() {
return arguments[2].toUpperCase();
});
}
return el.currentStyle[prop] ? el.currentStyle[prop] : null;
};
};
// This version calls getPropertyValue() automatically
return function(el, prop) {
return window.getComputedStyle(el, null).getPropertyValue(prop);
};
})();
/**
* Determine the line-height for a given element. This
* is a best guess, as the element may not have uniform line
* height.
*
* @param {HTMLElement|jQuery} - DOM element object
* @return {Number} - the line height as an integer
*/
function getLineHeight(element) {
var el = element.jquery ? element[0] : element,
lineheight = getStyle(el, 'line-height'),
fontsize = getStyle(el, 'font-size');
if (lineheight == 'normal') {
lineheight = Math.floor(parseInt(fontsize, 10) * 1.2);
}
return parseInt(lineheight, 10); // in px
}
/* so we can see elements once wrapped */
.highlight * {
background-color: yellow !important;
}
/* so we can see highlighted elements inside wrapper */
.wrapper .highlight * {
background-color: orange !important;
color: red;
}
/* with out being highlighted, so we can see stuff inside of wrapper */
.wrapper {
color: blue;
}
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<!-- some content to fiddle with -->
<div id="test" class="content">
<p>This paragraph as a leading newline and a trailing newline.</p>
<p>Another paragraph with some text in it</p>
</div>
<!-- we'll wrap other elements in this -->
<div class="wrapper"></div>
</body>
</html>
//
// Unit Test for each of the above
//
// Simple console assert() for use in testing
function assert(s, fn) {
var assertion = !!(fn()),
style = assertion ? 'color: green' : 'color: red';
console.info("> " + s + ": %c" + assertion, style);
}
// Test our getStyle() implementation
assert("getStyle shows line-height as 'normal'", function() {
var orig = window.getComputedStyle(target, null).getPropertyValue('line-height'),
ours = getStyle(target, 'line-height');
return orig === ours;
});
// Test our wrap and wrapAll implementations
var wrapper = getElementsByClassName('wrapper')[0],
target = getElementsByClassName('content')[0];
// Create a span.highlight element to wrap around each 'p' tag
var highlight = document.createElement('span');
highlight.className = 'highlight';
// Wrap each 'p' in a 'span'
wrap(highlight, target.getElementsByTagName('p'));
assert("each <p> is highlighted after wrap() call", function() {
return getElementsByClassName('highlight').length === 2;
});
// Wrap entire '.content' contents in '.wrapper'
wrapAll(wrapper, target);
assert("each <p> is now inside of .wrapper <div> after wrapAll() call", function() {
return getElementsByClassName('wrapper')[0].children.length === 1;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment