minow
Version:
A drop in replacement for jquery based off enders core libs
1,202 lines (1,058 loc) • 36.9 kB
JavaScript
/*!
* Bonzo: DOM Utility (c) Dustin Diaz 2012
* https://github.com/ded/bonzo
* License MIT
*/
(function(name, definition, context) {
if (typeof module != 'undefined' && module.exports) module.exports = definition()
else if (typeof context['define'] == 'function' && context['define']['amd']) define(name, definition)
else context[name] = definition()
})('bonzo', function() {
var win = window,
doc = win.document,
html = doc.documentElement,
parentNode = 'parentNode',
query = null // used for setting a selector engine host
,
specialAttributes = /^(checked|value|selected|disabled)$/i,
specialTags = /^(select|fieldset|table|tbody|tfoot|td|tr|colgroup)$/i // tags that we have trouble inserting *into*
,
table = ['<table>', '</table>', 1],
td = ['<table><tbody><tr>', '</tr></tbody></table>', 3],
option = ['<select>', '</select>', 1],
noscope = ['_', '', 0, 1],
tagMap = { // tags that we have trouble *inserting*
thead: table,
tbody: table,
tfoot: table,
colgroup: table,
caption: table,
tr: ['<table><tbody>', '</tbody></table>', 2],
th: td,
td: td,
col: ['<table><colgroup>', '</colgroup></table>', 2],
fieldset: ['<form>', '</form>', 1],
legend: ['<form><fieldset>', '</fieldset></form>', 2],
option: option,
optgroup: option,
script: noscope,
style: noscope,
link: noscope,
param: noscope,
base: noscope
}, stateAttributes = /^(checked|selected|disabled)$/,
ie = /msie/i.test(navigator.userAgent),
hasClass, addClass, removeClass, uidMap = {}, uuids = 0,
digit = /^-?[\d\.]+$/,
dattr = /^data-(.+)$/,
px = 'px',
setAttribute = 'setAttribute',
getAttribute = 'getAttribute',
byTag = 'getElementsByTagName',
features = function() {
var e = doc.createElement('p')
e.innerHTML = '<a href="#x">x</a><table style="float:left;"></table>'
return {
hrefExtended: e[byTag]('a')[0][getAttribute]('href') != '#x' // IE < 8
,
autoTbody: e[byTag]('tbody').length !== 0 // IE < 8
,
computedStyle: doc.defaultView && doc.defaultView.getComputedStyle,
cssFloat: e[byTag]('table')[0].style.styleFloat ? 'styleFloat' : 'cssFloat',
transform: function() {
var props = ['webkitTransform', 'MozTransform', 'OTransform', 'msTransform', 'Transform'],
i
for (i = 0; i < props.length; i++) {
if (props[i] in e.style) return props[i]
}
}(),
classList: 'classList' in e,
opasity: function() {
return typeof doc.createElement('a').style.opacity !== 'undefined'
}()
}
}(),
trimReplace = /(^\s*|\s*$)/g,
whitespaceRegex = /\s+/,
toString = String.prototype.toString,
unitless = {
lineHeight: 1,
zoom: 1,
zIndex: 1,
opacity: 1,
boxFlex: 1,
WebkitBoxFlex: 1,
MozBoxFlex: 1
}, trim = String.prototype.trim ?
function(s) {
return s.trim()
} :
function(s) {
return s.replace(trimReplace, '')
}
/**
* @param {string} c a class name to test
* @return {boolean}
*/
function classReg(c) {
return new RegExp("(^|\\s+)" + c + "(\\s+|$)")
}
/**
* @param {Bonzo|Array} ar
* @param {function(Object, number, (Bonzo|Array))} fn
* @param {Object=} opt_scope
* @param {boolean=} opt_rev
* @return {Bonzo|Array}
*/
function each(ar, fn, opt_scope, opt_rev) {
var ind, i = 0,
l = ar.length
for (; i < l; i++) {
ind = opt_rev ? ar.length - i - 1 : i
fn.call(opt_scope || ar[ind], ar[ind], ind, ar)
}
return ar
}
/**
* @param {Bonzo|Array} ar
* @param {function(Object, number, (Bonzo|Array))} fn
* @param {Object=} opt_scope
* @return {Bonzo|Array}
*/
function deepEach(ar, fn, opt_scope) {
for (var i = 0, l = ar.length; i < l; i++) {
if (isNode(ar[i])) {
deepEach(ar[i].childNodes, fn, opt_scope)
fn.call(opt_scope || ar[i], ar[i], i, ar)
}
}
return ar
}
/**
* @param {string} s
* @return {string}
*/
function camelize(s) {
return s.replace(/-(.)/g, function(m, m1) {
return m1.toUpperCase()
})
}
/**
* @param {string} s
* @return {string}
*/
function decamelize(s) {
return s ? s.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase() : s
}
/**
* @param {Element} el
* @return {*}
*/
function data(el) {
el[getAttribute]('data-node-uid') || el[setAttribute]('data-node-uid', ++uuids)
var uid = el[getAttribute]('data-node-uid')
return uidMap[uid] || (uidMap[uid] = {})
}
/**
* removes the data associated with an element
* @param {Element} el
*/
function clearData(el) {
var uid = el[getAttribute]('data-node-uid')
if (uid) delete uidMap[uid]
}
function dataValue(d) {
var f
try {
return (d === null || d === undefined) ? undefined :
d === 'true' ? true :
d === 'false' ? false :
d === 'null' ? null :
(f = parseFloat(d)) == d ? f : d;
} catch (e) {}
return undefined
}
function isNode(node) {
return node && node.nodeName && (node.nodeType == 1 || node.nodeType == 11)
}
/**
* @param {Bonzo|Array} ar
* @param {function(Object, number, (Bonzo|Array))} fn
* @param {Object=} opt_scope
* @return {boolean} whether `some`thing was found
*/
function some(ar, fn, opt_scope) {
for (var i = 0, j = ar.length; i < j; ++i)
if (fn.call(opt_scope || null, ar[i], i, ar)) return true
return false
}
/**
* this could be a giant enum of CSS properties
* but in favor of file size sans-closure deadcode optimizations
* we're just asking for any ol string
* then it gets transformed into the appropriate style property for JS access
* @param {string} p
* @return {string}
*/
function styleProperty(p) {
(p == 'transform' && (p = features.transform)) ||
(/^transform-?[Oo]rigin$/.test(p) && (p = features.transform + "Origin")) ||
(p == 'float' && (p = features.cssFloat))
return p ? camelize(p) : null
}
var getStyle = features.computedStyle ?
function(el, property) {
var value = null,
computed = doc.defaultView.getComputedStyle(el, '')
computed && (value = computed[property])
return el.style[property] || value
} :
(ie && html.currentStyle) ?
/**
* @param {Element} el
* @param {string} property
* @return {string|number}
*/
function(el, property) {
if (property == 'opacity' && !features.opasity) {
var val = 100
try {
val = el['filters']['DXImageTransform.Microsoft.Alpha'].opacity
} catch (e1) {
try {
val = el['filters']('alpha').opacity
} catch (e2) {}
}
return val / 100
}
var value = el.currentStyle ? el.currentStyle[property] : null
return el.style[property] || value
} :
function(el, property) {
return el.style[property]
}
// this insert method is intense
function insert(target, host, fn, rev) {
var i = 0,
self = host || this,
r = []
// target nodes could be a css selector if it's a string and a selector engine is present
// otherwise, just use target
,
nodes = query && typeof target == 'string' && target.charAt(0) != '<' ? query(target) : target
// normalize each node in case it's still a string and we need to create nodes on the fly
each(normalize(nodes), function(t, j) {
each(self, function(el) {
fn(t, r[i++] = j > 0 ? cloneNode(self, el) : el)
}, null, rev)
}, this, rev)
self.length = i
each(r, function(e) {
self[--i] = e
}, null, !rev)
return self
}
/**
* sets an element to an explicit x/y position on the page
* @param {Element} el
* @param {?number} x
* @param {?number} y
*/
function xy(el, x, y) {
var $el = bonzo(el),
style = $el.css('position'),
offset = $el.offset(),
rel = 'relative',
isRel = style == rel,
delta = [parseInt($el.css('left'), 10), parseInt($el.css('top'), 10)]
if (style == 'static') {
$el.css('position', rel)
style = rel
}
isNaN(delta[0]) && (delta[0] = isRel ? 0 : el.offsetLeft)
isNaN(delta[1]) && (delta[1] = isRel ? 0 : el.offsetTop)
x != null && (el.style.left = x - offset.left + delta[0] + px)
y != null && (el.style.top = y - offset.top + delta[1] + px)
}
// classList support for class management
// altho to be fair, the api sucks because it won't accept multiple classes at once
if (features.classList) {
hasClass = function(el, c) {
return el.classList.contains(c)
}
addClass = function(el, c) {
el.classList.add(c)
}
removeClass = function(el, c) {
el.classList.remove(c)
}
} else {
hasClass = function(el, c) {
return classReg(c).test(el.className)
}
addClass = function(el, c) {
el.className = trim(el.className + ' ' + c)
}
removeClass = function(el, c) {
el.className = trim(el.className.replace(classReg(c), ' '))
}
}
/**
* this allows method calling for setting values
*
* @example
* bonzo(elements).css('color', function (el) {
* return el.getAttribute('data-original-color')
* })
*
* @param {Element} el
* @param {function (Element)|string}
* @return {string}
*/
function setter(el, v) {
return typeof v == 'function' ? v(el) : v
}
/**
* @constructor
* @param {Array.<Element>|Element|Node|string} elements
*/
function Bonzo(elements) {
this.length = 0
if (elements) {
elements = typeof elements !== 'string' && !elements.nodeType &&
typeof elements.length !== 'undefined' ?
elements :
[elements]
this.length = elements.length
for (var i = 0; i < elements.length; i++) this[i] = elements[i]
}
}
Bonzo.prototype = {
/**
* @param {number} index
* @return {Element|Node}
*/
get: function(index) {
return this[index] || null
}
// itetators
/**
* @param {function(Element|Node)} fn
* @param {Object=} opt_scope
* @return {Bonzo}
*/
,
each: function(fn, opt_scope) {
return each(this, fn, opt_scope)
}
/**
* @param {Function} fn
* @param {Object=} opt_scope
* @return {Bonzo}
*/
,
deepEach: function(fn, opt_scope) {
return deepEach(this, fn, opt_scope)
}
/**
* @param {Function} fn
* @param {Function=} opt_reject
* @return {Array}
*/
,
map: function(fn, opt_reject) {
var m = [],
n, i
for (i = 0; i < this.length; i++) {
n = fn.call(this, this[i], i)
opt_reject ? (opt_reject(n) && m.push(n)) : m.push(n)
}
return m
}
// text and html inserters!
/**
* @param {string} h the HTML to insert
* @param {boolean=} opt_text whether to set or get text content
* @return {Bonzo|string}
*/
,
html: function(h, opt_text) {
var method = opt_text ? html.textContent === undefined ? 'innerText' : 'textContent' : 'innerHTML',
that = this,
append = function(el, i) {
each(normalize(h, that, i), function(node) {
el.appendChild(node)
})
}, updateElement = function(el, i) {
try {
if (opt_text || (typeof h == 'string' && !specialTags.test(el.tagName))) {
return el[method] = h
}
} catch (e) {}
append(el, i)
}
return typeof h != 'undefined' ? this.empty().each(updateElement) : this[0] ? this[0][method] : ''
}
/**
* @param {string=} opt_text the text to set, otherwise this is a getter
* @return {Bonzo|string}
*/
,
text: function(opt_text) {
return this.html(opt_text, true)
}
// more related insertion methods
/**
* @param {Bonzo|string|Element|Array} node
* @return {Bonzo}
*/
,
append: function(node) {
var that = this
return this.each(function(el, i) {
each(normalize(node, that, i), function(i) {
el.appendChild(i)
})
})
}
/**
* @param {Bonzo|string|Element|Array} node
* @return {Bonzo}
*/
,
prepend: function(node) {
var that = this
return this.each(function(el, i) {
var first = el.firstChild
each(normalize(node, that, i), function(i) {
el.insertBefore(i, first)
})
})
}
/**
* @param {Bonzo|string|Element|Array} target the location for which you'll insert your new content
* @param {Object=} opt_host an optional host scope (primarily used when integrated with Ender)
* @return {Bonzo}
*/
,
appendTo: function(target, opt_host) {
return insert.call(this, target, opt_host, function(t, el) {
t.appendChild(el)
})
}
/**
* @param {Bonzo|string|Element|Array} target the location for which you'll insert your new content
* @param {Object=} opt_host an optional host scope (primarily used when integrated with Ender)
* @return {Bonzo}
*/
,
prependTo: function(target, opt_host) {
return insert.call(this, target, opt_host, function(t, el) {
t.insertBefore(el, t.firstChild)
}, 1)
}
/**
* @param {Bonzo|string|Element|Array} node
* @return {Bonzo}
*/
,
before: function(node) {
var that = this
return this.each(function(el, i) {
each(normalize(node, that, i), function(i) {
el[parentNode].insertBefore(i, el)
})
})
}
/**
* @param {Bonzo|string|Element|Array} node
* @return {Bonzo}
*/
,
after: function(node) {
var that = this
return this.each(function(el, i) {
each(normalize(node, that, i), function(i) {
el[parentNode].insertBefore(i, el.nextSibling)
}, null, 1)
})
}
/**
* @param {Bonzo|string|Element|Array} target the location for which you'll insert your new content
* @param {Object=} opt_host an optional host scope (primarily used when integrated with Ender)
* @return {Bonzo}
*/
,
insertBefore: function(target, opt_host) {
return insert.call(this, target, opt_host, function(t, el) {
t[parentNode].insertBefore(el, t)
})
}
/**
* @param {Bonzo|string|Element|Array} target the location for which you'll insert your new content
* @param {Object=} opt_host an optional host scope (primarily used when integrated with Ender)
* @return {Bonzo}
*/
,
insertAfter: function(target, opt_host) {
return insert.call(this, target, opt_host, function(t, el) {
var sibling = t.nextSibling
sibling ?
t[parentNode].insertBefore(el, sibling) :
t[parentNode].appendChild(el)
}, 1)
}
/**
* @param {Bonzo|string|Element|Array} node
* @param {Object=} opt_host an optional host scope (primarily used when integrated with Ender)
* @return {Bonzo}
*/
,
replaceWith: function(node, opt_host) {
var ret = bonzo(normalize(node)).insertAfter(this, opt_host)
this.remove()
Bonzo.call(opt_host || this, ret)
return opt_host || this
}
// class management
/**
* @param {string} c
* @return {Bonzo}
*/
,
addClass: function(c) {
c = toString.call(c).split(whitespaceRegex)
return this.each(function(el) {
// we `each` here so you can do $el.addClass('foo bar')
each(c, function(c) {
if (c && !hasClass(el, setter(el, c)))
addClass(el, setter(el, c))
})
})
}
/**
* @param {string} c
* @return {Bonzo}
*/
,
removeClass: function(c) {
c = toString.call(c).split(whitespaceRegex)
return this.each(function(el) {
each(c, function(c) {
if (c && hasClass(el, setter(el, c)))
removeClass(el, setter(el, c))
})
})
}
/**
* @param {string} c
* @return {boolean}
*/
,
hasClass: function(c) {
c = toString.call(c).split(whitespaceRegex)
return some(this, function(el) {
return some(c, function(c) {
return c && hasClass(el, c)
})
})
}
/**
* @param {string} c classname to toggle
* @param {boolean=} opt_condition whether to add or remove the class straight away
* @return {Bonzo}
*/
,
toggleClass: function(c, opt_condition) {
c = toString.call(c).split(whitespaceRegex)
return this.each(function(el) {
each(c, function(c) {
if (c) {
typeof opt_condition !== 'undefined' ?
opt_condition ? addClass(el, c) : removeClass(el, c) :
hasClass(el, c) ? removeClass(el, c) : addClass(el, c)
}
})
})
}
// display togglers
/**
* @param {string=} opt_type useful to set back to anything other than an empty string
* @return {Bonzo}
*/
,
show: function(opt_type) {
opt_type = typeof opt_type == 'string' ? opt_type : ''
return this.each(function(el) {
el.style.display = opt_type
})
}
/**
* @return {Bonzo}
*/
,
hide: function() {
return this.each(function(el) {
el.style.display = 'none'
})
}
/**
* @param {Function=} opt_callback
* @param {string=} opt_type
* @return {Bonzo}
*/
,
toggle: function(opt_callback, opt_type) {
opt_type = typeof opt_type == 'string' ? opt_type : '';
typeof opt_callback != 'function' && (opt_callback = null)
return this.each(function(el) {
el.style.display = (el.offsetWidth || el.offsetHeight) ? 'none' : opt_type;
opt_callback && opt_callback.call(el)
})
}
// DOM Walkers & getters
/**
* @return {Element|Node}
*/
,
first: function() {
return bonzo(this.length ? this[0] : [])
}
/**
* @return {Element|Node}
*/
,
last: function() {
return bonzo(this.length ? this[this.length - 1] : [])
}
/**
* @return {Element|Node}
*/
,
next: function() {
return this.related('nextSibling')
}
/**
* @return {Element|Node}
*/
,
previous: function() {
return this.related('previousSibling')
}
/**
* @return {Element|Node}
*/
,
parent: function() {
return this.related(parentNode)
}
/**
* @private
* @param {string} method the directional DOM method
* @return {Element|Node}
*/
,
related: function(method) {
return this.map(
function(el) {
el = el[method]
while (el && el.nodeType !== 1) {
el = el[method]
}
return el || 0
},
function(el) {
return el
}
)
}
/**
* @return {Bonzo}
*/
,
focus: function() {
this.length && this[0].focus()
return this
}
/**
* @return {Bonzo}
*/
,
blur: function() {
this.length && this[0].blur()
return this
}
// style getter setter & related methods
/**
* @param {Object|string} o
* @param {string=} opt_v
* @return {Bonzo|string}
*/
,
css: function(o, opt_v) {
var p, iter = o
// is this a request for just getting a style?
if (opt_v === undefined && typeof o == 'string') {
// repurpose 'v'
opt_v = this[0]
if (!opt_v) return null
if (opt_v === doc || opt_v === win) {
p = (opt_v === doc) ? bonzo.doc() : bonzo.viewport()
return o == 'width' ? p.width : o == 'height' ? p.height : ''
}
return (o = styleProperty(o)) ? getStyle(opt_v, o) : null
}
if (typeof o == 'string') {
iter = {}
iter[o] = opt_v
}
if (ie && iter.opacity) {
// oh this 'ol gamut
iter.filter = 'alpha(opacity=' + (iter.opacity * 100) + ')'
// give it layout
iter.zoom = o.zoom || 1;
delete iter.opacity;
}
function fn(el, p, v) {
for (var k in iter) {
if (iter.hasOwnProperty(k)) {
v = iter[k];
// change "5" to "5px" - unless you're line-height, which is allowed
(p = styleProperty(k)) && digit.test(v) && !(p in unitless) && (v += px)
try {
el.style[p] = setter(el, v)
} catch (e) {}
}
}
}
return this.each(fn)
}
/**
* @param {number=} opt_x
* @param {number=} opt_y
* @return {Bonzo|number}
*/
,
offset: function(opt_x, opt_y) {
if (typeof opt_x == 'number' || typeof opt_y == 'number') {
return this.each(function(el) {
xy(el, opt_x, opt_y)
})
}
if (!this[0]) return {
top: 0,
left: 0,
height: 0,
width: 0
}
var el = this[0],
width = el.offsetWidth,
height = el.offsetHeight,
top = el.offsetTop,
left = el.offsetLeft
while (el = el.offsetParent) {
top = top + el.offsetTop
left = left + el.offsetLeft
if (el != doc.body) {
top -= el.scrollTop
left -= el.scrollLeft
}
}
return {
top: top,
left: left,
height: height,
width: width
}
}
/**
* @return {number}
*/
,
dim: function() {
if (!this.length) return {
height: 0,
width: 0
}
var el = this[0],
orig = !el.offsetWidth && !el.offsetHeight ?
// el isn't visible, can't be measured properly, so fix that
function(t) {
var s = {
position: el.style.position || '',
visibility: el.style.visibility || '',
display: el.style.display || ''
}
t.first().css({
position: 'absolute',
visibility: 'hidden',
display: 'block'
})
return s
}(this) : null,
width = el.offsetWidth,
height = el.offsetHeight
orig && this.first().css(orig)
return {
height: height,
width: width
}
}
// attributes are hard. go shopping
/**
* @param {string} k an attribute to get or set
* @param {string=} opt_v the value to set
* @return {Bonzo|string}
*/
,
attr: function(k, opt_v) {
var el = this[0]
if (typeof k != 'string' && !(k instanceof String)) {
for (var n in k) {
k.hasOwnProperty(n) && this.attr(n, k[n])
}
return this
}
return typeof opt_v == 'undefined' ? !el ? null : specialAttributes.test(k) ?
stateAttributes.test(k) && typeof el[k] == 'string' ?
true : el[k] : (k == 'href' || k == 'src') && features.hrefExtended ?
el[getAttribute](k, 2) : el[getAttribute](k) :
this.each(function(el) {
specialAttributes.test(k) ? (el[k] = setter(el, opt_v)) : el[setAttribute](k, setter(el, opt_v))
})
}
/**
* @param {string} k
* @return {Bonzo}
*/
,
removeAttr: function(k) {
return this.each(function(el) {
stateAttributes.test(k) ? (el[k] = false) : el.removeAttribute(k)
})
}
/**
* @param {string=} opt_s
* @return {Bonzo|string}
*/
,
val: function(s) {
return (typeof s == 'string') ?
this.attr('value', s) :
this.length ? this[0].value : null
}
// use with care and knowledge. this data() method uses data attributes on the DOM nodes
// to do this differently costs a lot more code. c'est la vie
/**
* @param {string|Object=} opt_k the key for which to get or set data
* @param {Object=} opt_v
* @return {Bonzo|Object}
*/
,
data: function(opt_k, opt_v) {
var el = this[0],
o, m
if (typeof opt_v === 'undefined') {
if (!el) return null
o = data(el)
if (typeof opt_k === 'undefined') {
each(el.attributes, function(a) {
(m = ('' + a.name).match(dattr)) && (o[camelize(m[1])] = dataValue(a.value))
})
return o
} else {
if (typeof o[opt_k] === 'undefined')
o[opt_k] = dataValue(this.attr('data-' + decamelize(opt_k)))
return o[opt_k]
}
} else {
return this.each(function(el) {
data(el)[opt_k] = opt_v
})
}
}
// DOM detachment & related
/**
* @return {Bonzo}
*/
,
remove: function() {
this.deepEach(clearData)
return this.each(function(el) {
el[parentNode] && el[parentNode].removeChild(el)
})
}
/**
* @return {Bonzo}
*/
,
empty: function() {
return this.each(function(el) {
deepEach(el.childNodes, clearData)
while (el.firstChild) {
el.removeChild(el.firstChild)
}
})
}
/**
* @return {Bonzo}
*/
,
detach: function() {
return this.each(function(el) {
el[parentNode].removeChild(el)
})
}
// who uses a mouse anyway? oh right.
/**
* @param {number} y
*/
,
scrollTop: function(y) {
return scroll.call(this, null, y, 'y')
}
/**
* @param {number} x
*/
,
scrollLeft: function(x) {
return scroll.call(this, x, null, 'x')
}
}
function normalize(node, host, clone) {
var i, l, ret
if (typeof node == 'string') return bonzo.create(node)
if (isNode(node)) node = [node]
if (clone) {
ret = [] // don't change original array
for (i = 0, l = node.length; i < l; i++) ret[i] = cloneNode(host, node[i])
return ret
}
return node
}
function cloneNode(host, el) {
var c = el.cloneNode(true),
cloneElems, elElems
// check for existence of an event cloner
// preferably https://github.com/fat/bean
// otherwise Bonzo won't do this for you
if (host.$ && typeof host.cloneEvents == 'function') {
host.$(c).cloneEvents(el)
// clone events from every child node
cloneElems = host.$(c).find('*')
elElems = host.$(el).find('*')
for (var i = 0; i < elElems.length; i++)
host.$(cloneElems[i]).cloneEvents(elElems[i])
}
return c
}
function scroll(x, y, type) {
var el = this[0]
if (!el) return this
if (x == null && y == null) {
return (isBody(el) ? getWindowScroll() : {
x: el.scrollLeft,
y: el.scrollTop
})[type]
}
if (isBody(el)) {
win.scrollTo(x, y)
} else {
x != null && (el.scrollLeft = x)
y != null && (el.scrollTop = y)
}
return this
}
function isBody(element) {
return element === win || (/^(?:body|html)$/i).test(element.tagName)
}
function getWindowScroll() {
return {
x: win.pageXOffset || html.scrollLeft,
y: win.pageYOffset || html.scrollTop
}
}
/**
* @param {Array.<Element>|Element|Node|string} els
* @return {Bonzo}
*/
function bonzo(els) {
return new Bonzo(els)
}
bonzo.setQueryEngine = function(q) {
query = q;
delete bonzo.setQueryEngine
}
bonzo.aug = function(o, target) {
// for those standalone bonzo users. this love is for you.
for (var k in o) {
o.hasOwnProperty(k) && ((target || Bonzo.prototype)[k] = o[k])
}
}
bonzo.create = function(node) {
// hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
return typeof node == 'string' && node !== '' ?
function() {
var tag = /^\s*<([^\s>]+)/.exec(node),
el = doc.createElement('div'),
els = [],
p = tag ? tagMap[tag[1].toLowerCase()] : null,
dep = p ? p[2] + 1 : 1,
ns = p && p[3],
pn = parentNode,
tb = features.autoTbody && p && p[0] == '<table>' && !(/<tbody/i).test(node)
el.innerHTML = p ? (p[0] + node + p[1]) : node
while (dep--) el = el.firstChild
// for IE NoScope, we may insert cruft at the begining just to get it to work
if (ns && el && el.nodeType !== 1) el = el.nextSibling
do {
// tbody special case for IE<8, creates tbody on any empty table
// we don't want it if we're just after a <thead>, <caption>, etc.
if ((!tag || el.nodeType == 1) && (!tb || el.tagName.toLowerCase() != 'tbody')) {
els.push(el)
}
} while (el = el.nextSibling)
// IE < 9 gives us a parentNode which messes up insert() check for cloning
// `dep` > 1 can also cause problems with the insert() check (must do this last)
each(els, function(el) {
el[pn] && el[pn].removeChild(el)
})
return els
}() : isNode(node) ? [node.cloneNode(true)] : []
}
bonzo.doc = function() {
var vp = bonzo.viewport()
return {
width: Math.max(doc.body.scrollWidth, html.scrollWidth, vp.width),
height: Math.max(doc.body.scrollHeight, html.scrollHeight, vp.height)
}
}
bonzo.firstChild = function(el) {
for (var c = el.childNodes, i = 0, j = (c && c.length) || 0, e; i < j; i++) {
if (c[i].nodeType === 1) e = c[j = i]
}
return e
}
bonzo.viewport = function() {
return {
width: ie ? html.clientWidth : self.innerWidth,
height: ie ? html.clientHeight : self.innerHeight
}
}
bonzo.isAncestor = 'compareDocumentPosition' in html ?
function(container, element) {
return (container.compareDocumentPosition(element) & 16) == 16
} : 'contains' in html ?
function(container, element) {
return container !== element && container.contains(element);
} :
function(container, element) {
while (element = element[parentNode]) {
if (element === container) {
return true
}
}
return false
}
return bonzo
}, this); // the only line we care about using a semi-colon. placed here for concatenation tools