UNPKG

2gis-maps

Version:

Interactive 2GIS maps API, based on Leaflet

1,138 lines (992 loc) 33.4 kB
/*! * Bonzo: DOM Utility (c) Dustin Diaz 2012 * https://github.com/ded/bonzo * License MIT */ (function (name, context, definition) { if (typeof module != 'undefined' && module.exports) module.exports = definition() else if (typeof define == 'function' && define.amd) define(definition) else context[name] = definition() })('bonzo', this, function() { var win = window , doc = win.document , html = doc.documentElement , parentNode = 'parentNode' , specialAttributes = /^(checked|value|selected|disabled)$/i , specialTags = /^(select|fieldset|table|tbody|tfoot|td|tr|colgroup)$/i // tags that we have trouble inserting *into* , simpleScriptTagRe = /\s*<script +src=['"]([^'"]+)['"]>/ , 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 = ['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 } , query = doc.querySelectorAll && function (selector) { return doc.querySelectorAll(selector) } , trim = String.prototype.trim ? function (s) { return s.trim() } : function (s) { return s.replace(trimReplace, '') } function isNode(node) { return node && node.nodeName && (node.nodeType == 1 || node.nodeType == 11) } 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 } /** * @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 } /** * @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 * @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 ? !hasClass(el, c) && 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 (opt_x && typeof opt_x == 'object' && (typeof opt_x.top == 'number' || typeof opt_x.left == 'number')) { return this.each(function (el) { xy(el, opt_x.left, opt_x.top) }) } else 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.scrollHeight, de.offsetHeight, 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 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 } } function createScriptFromHtml(html) { var scriptEl = document.createElement('script') , matches = html.match(simpleScriptTagRe) scriptEl.src = matches[1] return scriptEl } /** * @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 () { if (simpleScriptTagRe.test(node)) return [createScriptFromHtml(node)] var tag = node.match(/^\s*<([^\s>]+)/) , 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 && el.tagName != '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 }); // the only line we care about using a semi-colon. placed here for concatenation tools