'
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 = ['transform', 'webkitTransform', 'MozTransform', 'OTransform', 'msTransform'], 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|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
* @return {Bonzo}
*/
, replaceWith: function (node) {
bonzo(normalize(node)).insertAfter(this)
return this.remove()
}
// 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]
, de = el.ownerDocument.documentElement
, bcr = el.getBoundingClientRect()
, scroll = getWindowScroll()
, width = el.offsetWidth
, height = el.offsetHeight
, top = bcr.top + scroll.y - Math.max(0, de && de.clientTop, doc.body.clientTop)
, left = bcr.left + scroll.x - Math.max(0, de && de.clientLeft, doc.body.clientLeft)
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]
, de = el.nodeType == 9 && el.documentElement // document
, orig = !de && !!el.style && !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 = de
? Math.max(el.body.scrollWidth, el.body.offsetWidth, de.scrollWidth, de.offsetWidth, de.clientWidth)
: el.offsetWidth
, height = de
? Math.max(el.body.scrollHeight, el.body.offsetHeight, de.scrollWidth, de.offsetWidth, de.clientHeight)
: 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.detach()
}
/**
* @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] && 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|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] == '
' && !(/,
, 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