You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3256 lines
108 KiB
3256 lines
108 KiB
/*!
|
|
* =============================================================
|
|
* Ender: open module JavaScript framework (https://ender.no.de)
|
|
* Build: ender build jeesh reqwest
|
|
* =============================================================
|
|
*/
|
|
|
|
/*!
|
|
* Ender: open module JavaScript framework (client-lib)
|
|
* copyright Dustin Diaz & Jacob Thornton 2011-2012 (@ded @fat)
|
|
* http://ender.jit.su
|
|
* License MIT
|
|
*/
|
|
(function (context) {
|
|
|
|
// a global object for node.js module compatiblity
|
|
// ============================================
|
|
|
|
context['global'] = context
|
|
|
|
// Implements simple module system
|
|
// losely based on CommonJS Modules spec v1.1.1
|
|
// ============================================
|
|
|
|
var modules = {}
|
|
, old = context['$']
|
|
, oldEnder = context['ender']
|
|
, oldRequire = context['require']
|
|
, oldProvide = context['provide']
|
|
|
|
function require (identifier) {
|
|
// modules can be required from ender's build system, or found on the window
|
|
var module = modules['$' + identifier] || window[identifier]
|
|
if (!module) throw new Error("Ender Error: Requested module '" + identifier + "' has not been defined.")
|
|
return module
|
|
}
|
|
|
|
function provide (name, what) {
|
|
return (modules['$' + name] = what)
|
|
}
|
|
|
|
context['provide'] = provide
|
|
context['require'] = require
|
|
|
|
function aug(o, o2) {
|
|
for (var k in o2) k != 'noConflict' && k != '_VERSION' && (o[k] = o2[k])
|
|
return o
|
|
}
|
|
|
|
/**
|
|
* main Ender return object
|
|
* @constructor
|
|
* @param {Array|Node|string} s a CSS selector or DOM node(s)
|
|
* @param {Array.|Node} r a root node(s)
|
|
*/
|
|
function Ender(s, r) {
|
|
var elements
|
|
, i
|
|
|
|
this.selector = s
|
|
// string || node || nodelist || window
|
|
if (typeof s == 'undefined') {
|
|
elements = []
|
|
this.selector = ''
|
|
} else if (typeof s == 'string' || s.nodeName || (s.length && 'item' in s) || s == window) {
|
|
elements = ender._select(s, r)
|
|
} else {
|
|
elements = isFinite(s.length) ? s : [s]
|
|
}
|
|
this.length = elements.length
|
|
for (i = this.length; i--;) this[i] = elements[i]
|
|
}
|
|
|
|
/**
|
|
* @param {function(el, i, inst)} fn
|
|
* @param {Object} opt_scope
|
|
* @returns {Ender}
|
|
*/
|
|
Ender.prototype['forEach'] = function (fn, opt_scope) {
|
|
var i, l
|
|
// opt out of native forEach so we can intentionally call our own scope
|
|
// defaulting to the current item and be able to return self
|
|
for (i = 0, l = this.length; i < l; ++i) i in this && fn.call(opt_scope || this[i], this[i], i, this)
|
|
// return self for chaining
|
|
return this
|
|
}
|
|
|
|
Ender.prototype.$ = ender // handy reference to self
|
|
|
|
|
|
function ender(s, r) {
|
|
return new Ender(s, r)
|
|
}
|
|
|
|
ender['_VERSION'] = '0.4.3-dev'
|
|
|
|
ender.fn = Ender.prototype // for easy compat to jQuery plugins
|
|
|
|
ender.ender = function (o, chain) {
|
|
aug(chain ? Ender.prototype : ender, o)
|
|
}
|
|
|
|
ender._select = function (s, r) {
|
|
if (typeof s == 'string') return (r || document).querySelectorAll(s)
|
|
if (s.nodeName) return [s]
|
|
return s
|
|
}
|
|
|
|
|
|
// use callback to receive Ender's require & provide and remove them from global
|
|
ender.noConflict = function (callback) {
|
|
context['$'] = old
|
|
if (callback) {
|
|
context['provide'] = oldProvide
|
|
context['require'] = oldRequire
|
|
context['ender'] = oldEnder
|
|
if (typeof callback == 'function') callback(require, provide, this)
|
|
}
|
|
return this
|
|
}
|
|
|
|
if (typeof module !== 'undefined' && module.exports) module.exports = ender
|
|
// use subscript notation as extern for Closure compilation
|
|
context['ender'] = context['$'] = ender
|
|
|
|
}(this));
|
|
|
|
(function () {
|
|
|
|
var module = { exports: {} }, exports = module.exports;
|
|
|
|
/*!
|
|
* Reqwest! A general purpose XHR connection manager
|
|
* (c) Dustin Diaz 2012
|
|
* https://github.com/ded/reqwest
|
|
* license MIT
|
|
*/
|
|
!function (name, definition) {
|
|
if (typeof module != 'undefined') module.exports = definition()
|
|
else if (typeof define == 'function' && define.amd) define(definition)
|
|
else this[name] = definition()
|
|
}('reqwest', function () {
|
|
|
|
var win = window
|
|
, doc = document
|
|
, twoHundo = /^20\d$/
|
|
, byTag = 'getElementsByTagName'
|
|
, readyState = 'readyState'
|
|
, contentType = 'Content-Type'
|
|
, requestedWith = 'X-Requested-With'
|
|
, head = doc[byTag]('head')[0]
|
|
, uniqid = 0
|
|
, callbackPrefix = 'reqwest_' + (+new Date())
|
|
, lastValue // data stored by the most recent JSONP callback
|
|
, xmlHttpRequest = 'XMLHttpRequest'
|
|
|
|
var isArray = typeof Array.isArray == 'function' ? Array.isArray : function (a) {
|
|
return a instanceof Array
|
|
}
|
|
var defaultHeaders = {
|
|
contentType: 'application/x-www-form-urlencoded'
|
|
, requestedWith: xmlHttpRequest
|
|
, accept: {
|
|
'*': 'text/javascript, text/html, application/xml, text/xml, */*'
|
|
, xml: 'application/xml, text/xml'
|
|
, html: 'text/html'
|
|
, text: 'text/plain'
|
|
, json: 'application/json, text/javascript'
|
|
, js: 'application/javascript, text/javascript'
|
|
}
|
|
}
|
|
var xhr = win[xmlHttpRequest] ?
|
|
function () {
|
|
return new XMLHttpRequest()
|
|
} :
|
|
function () {
|
|
return new ActiveXObject('Microsoft.XMLHTTP')
|
|
}
|
|
|
|
function handleReadyState(o, success, error) {
|
|
return function () {
|
|
if (o && o[readyState] == 4) {
|
|
if (twoHundo.test(o.status)) {
|
|
success(o)
|
|
} else {
|
|
error(o)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function setHeaders(http, o) {
|
|
var headers = o.headers || {}, h
|
|
headers.Accept = headers.Accept || defaultHeaders.accept[o.type] || defaultHeaders.accept['*']
|
|
// breaks cross-origin requests with legacy browsers
|
|
if (!o.crossOrigin && !headers[requestedWith]) headers[requestedWith] = defaultHeaders.requestedWith
|
|
if (!headers[contentType]) headers[contentType] = o.contentType || defaultHeaders.contentType
|
|
for (h in headers) {
|
|
headers.hasOwnProperty(h) && http.setRequestHeader(h, headers[h])
|
|
}
|
|
}
|
|
|
|
function setCredentials(http, o) {
|
|
if (typeof o.withCredentials !== "undefined" && typeof http.withCredentials !== "undefined") {
|
|
http.withCredentials = !!o.withCredentials
|
|
}
|
|
}
|
|
|
|
function generalCallback(data) {
|
|
lastValue = data
|
|
}
|
|
|
|
function urlappend(url, s) {
|
|
return url + (/\?/.test(url) ? '&' : '?') + s
|
|
}
|
|
|
|
function handleJsonp(o, fn, err, url) {
|
|
var reqId = uniqid++
|
|
, cbkey = o.jsonpCallback || 'callback' // the 'callback' key
|
|
, cbval = o.jsonpCallbackName || reqwest.getcallbackPrefix(reqId)
|
|
// , cbval = o.jsonpCallbackName || ('reqwest_' + reqId) // the 'callback' value
|
|
, cbreg = new RegExp('((^|\\?|&)' + cbkey + ')=([^&]+)')
|
|
, match = url.match(cbreg)
|
|
, script = doc.createElement('script')
|
|
, loaded = 0
|
|
|
|
if (match) {
|
|
if (match[3] === '?') {
|
|
url = url.replace(cbreg, '$1=' + cbval) // wildcard callback func name
|
|
} else {
|
|
cbval = match[3] // provided callback func name
|
|
}
|
|
} else {
|
|
url = urlappend(url, cbkey + '=' + cbval) // no callback details, add 'em
|
|
}
|
|
|
|
win[cbval] = generalCallback
|
|
|
|
script.type = 'text/javascript'
|
|
script.src = url
|
|
script.async = true
|
|
if (typeof script.onreadystatechange !== 'undefined') {
|
|
// need this for IE due to out-of-order onreadystatechange(), binding script
|
|
// execution to an event listener gives us control over when the script
|
|
// is executed. See http://jaubourg.net/2010/07/loading-script-as-onclick-handler-of.html
|
|
script.event = 'onclick'
|
|
script.htmlFor = script.id = '_reqwest_' + reqId
|
|
}
|
|
|
|
script.onload = script.onreadystatechange = function () {
|
|
if ((script[readyState] && script[readyState] !== 'complete' && script[readyState] !== 'loaded') || loaded) {
|
|
return false
|
|
}
|
|
script.onload = script.onreadystatechange = null
|
|
script.onclick && script.onclick()
|
|
// Call the user callback with the last value stored and clean up values and scripts.
|
|
o.success && o.success(lastValue)
|
|
lastValue = undefined
|
|
head.removeChild(script)
|
|
loaded = 1
|
|
}
|
|
|
|
// Add the script to the DOM head
|
|
head.appendChild(script)
|
|
}
|
|
|
|
function getRequest(o, fn, err) {
|
|
var method = (o.method || 'GET').toUpperCase()
|
|
, url = typeof o === 'string' ? o : o.url
|
|
// convert non-string objects to query-string form unless o.processData is false
|
|
, data = (o.processData !== false && o.data && typeof o.data !== 'string')
|
|
? reqwest.toQueryString(o.data)
|
|
: (o.data || null)
|
|
, http
|
|
|
|
// if we're working on a GET request and we have data then we should append
|
|
// query string to end of URL and not post data
|
|
if ((o.type == 'jsonp' || method == 'GET') && data) {
|
|
url = urlappend(url, data)
|
|
data = null
|
|
}
|
|
|
|
if (o.type == 'jsonp') return handleJsonp(o, fn, err, url)
|
|
|
|
http = xhr()
|
|
http.open(method, url, true)
|
|
setHeaders(http, o)
|
|
setCredentials(http, o)
|
|
http.onreadystatechange = handleReadyState(http, fn, err)
|
|
o.before && o.before(http)
|
|
http.send(data)
|
|
return http
|
|
}
|
|
|
|
function Reqwest(o, fn) {
|
|
this.o = o
|
|
this.fn = fn
|
|
|
|
init.apply(this, arguments)
|
|
}
|
|
|
|
function setType(url) {
|
|
var m = url.match(/\.(json|jsonp|html|xml)(\?|$)/)
|
|
return m ? m[1] : 'js'
|
|
}
|
|
|
|
function init(o, fn) {
|
|
|
|
this.url = typeof o == 'string' ? o : o.url
|
|
this.timeout = null
|
|
|
|
// whether request has been fulfilled for purpose
|
|
// of tracking the Promises
|
|
this._fulfilled = false
|
|
// success handlers
|
|
this._fulfillmentHandlers = []
|
|
// error handlers
|
|
this._errorHandlers = []
|
|
// complete (both success and fail) handlers
|
|
this._completeHandlers = []
|
|
this._erred = false
|
|
this._responseArgs = {}
|
|
|
|
var self = this
|
|
, type = o.type || setType(this.url)
|
|
|
|
fn = fn || function () {}
|
|
|
|
if (o.timeout) {
|
|
this.timeout = setTimeout(function () {
|
|
self.abort()
|
|
}, o.timeout)
|
|
}
|
|
|
|
if (o.success) {
|
|
this._fulfillmentHandlers.push(function () {
|
|
o.success.apply(o, arguments)
|
|
})
|
|
}
|
|
|
|
if (o.error) {
|
|
this._errorHandlers.push(function () {
|
|
o.error.apply(o, arguments)
|
|
})
|
|
}
|
|
|
|
if (o.complete) {
|
|
this._completeHandlers.push(function () {
|
|
o.complete.apply(o, arguments)
|
|
})
|
|
}
|
|
|
|
function complete(resp) {
|
|
o.timeout && clearTimeout(self.timeout)
|
|
self.timeout = null
|
|
while (self._completeHandlers.length > 0) {
|
|
self._completeHandlers.shift()(resp)
|
|
}
|
|
}
|
|
|
|
function success(resp) {
|
|
var r = resp.responseText
|
|
if (r) {
|
|
switch (type) {
|
|
case 'json':
|
|
try {
|
|
resp = win.JSON ? win.JSON.parse(r) : eval('(' + r + ')')
|
|
} catch (err) {
|
|
return error(resp, 'Could not parse JSON in response', err)
|
|
}
|
|
break;
|
|
case 'js':
|
|
resp = eval(r)
|
|
break;
|
|
case 'html':
|
|
resp = r
|
|
break;
|
|
case 'xml':
|
|
resp = resp.responseXML;
|
|
break;
|
|
}
|
|
}
|
|
|
|
self._responseArgs.resp = resp
|
|
self._fulfilled = true
|
|
fn(resp)
|
|
while (self._fulfillmentHandlers.length > 0) {
|
|
self._fulfillmentHandlers.shift()(resp)
|
|
}
|
|
|
|
complete(resp)
|
|
}
|
|
|
|
function error(resp, msg, t) {
|
|
self._responseArgs.resp = resp
|
|
self._responseArgs.msg = msg
|
|
self._responseArgs.t = t
|
|
self._erred = true
|
|
while (self._errorHandlers.length > 0) {
|
|
self._errorHandlers.shift()(resp, msg, t)
|
|
}
|
|
complete(resp)
|
|
}
|
|
|
|
this.request = getRequest(o, success, error)
|
|
}
|
|
|
|
Reqwest.prototype = {
|
|
abort: function () {
|
|
this.request.abort()
|
|
}
|
|
|
|
, retry: function () {
|
|
init.call(this, this.o, this.fn)
|
|
}
|
|
|
|
/**
|
|
* Small deviation from the Promises A CommonJs specification
|
|
* http://wiki.commonjs.org/wiki/Promises/A
|
|
*/
|
|
|
|
/**
|
|
* `then` will execute upon successful requests
|
|
*/
|
|
, then: function (success, fail) {
|
|
if (this._fulfilled) {
|
|
success(this._responseArgs.resp)
|
|
} else if (this._erred) {
|
|
fail(this._responseArgs.resp, this._responseArgs.msg, this._responseArgs.t)
|
|
} else {
|
|
this._fulfillmentHandlers.push(success)
|
|
this._errorHandlers.push(fail)
|
|
}
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* `always` will execute whether the request succeeds or fails
|
|
*/
|
|
, always: function (fn) {
|
|
if (this._fulfilled || this._erred) {
|
|
fn(this._responseArgs.resp)
|
|
} else {
|
|
this._completeHandlers.push(fn)
|
|
}
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* `fail` will execute when the request fails
|
|
*/
|
|
, fail: function (fn) {
|
|
if (this._erred) {
|
|
fn(this._responseArgs.resp, this._responseArgs.msg, this._responseArgs.t)
|
|
} else {
|
|
this._errorHandlers.push(fn)
|
|
}
|
|
return this
|
|
}
|
|
}
|
|
|
|
function reqwest(o, fn) {
|
|
return new Reqwest(o, fn)
|
|
}
|
|
|
|
// normalize newline variants according to spec -> CRLF
|
|
function normalize(s) {
|
|
return s ? s.replace(/\r?\n/g, '\r\n') : ''
|
|
}
|
|
|
|
function serial(el, cb) {
|
|
var n = el.name
|
|
, t = el.tagName.toLowerCase()
|
|
, optCb = function (o) {
|
|
// IE gives value="" even where there is no value attribute
|
|
// 'specified' ref: http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-862529273
|
|
if (o && !o.disabled)
|
|
cb(n, normalize(o.attributes.value && o.attributes.value.specified ? o.value : o.text))
|
|
}
|
|
|
|
// don't serialize elements that are disabled or without a name
|
|
if (el.disabled || !n) return;
|
|
|
|
switch (t) {
|
|
case 'input':
|
|
if (!/reset|button|image|file/i.test(el.type)) {
|
|
var ch = /checkbox/i.test(el.type)
|
|
, ra = /radio/i.test(el.type)
|
|
, val = el.value;
|
|
// WebKit gives us "" instead of "on" if a checkbox has no value, so correct it here
|
|
(!(ch || ra) || el.checked) && cb(n, normalize(ch && val === '' ? 'on' : val))
|
|
}
|
|
break;
|
|
case 'textarea':
|
|
cb(n, normalize(el.value))
|
|
break;
|
|
case 'select':
|
|
if (el.type.toLowerCase() === 'select-one') {
|
|
optCb(el.selectedIndex >= 0 ? el.options[el.selectedIndex] : null)
|
|
} else {
|
|
for (var i = 0; el.length && i < el.length; i++) {
|
|
el.options[i].selected && optCb(el.options[i])
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// collect up all form elements found from the passed argument elements all
|
|
// the way down to child elements; pass a '<form>' or form fields.
|
|
// called with 'this'=callback to use for serial() on each element
|
|
function eachFormElement() {
|
|
var cb = this
|
|
, e, i, j
|
|
, serializeSubtags = function (e, tags) {
|
|
for (var i = 0; i < tags.length; i++) {
|
|
var fa = e[byTag](tags[i])
|
|
for (j = 0; j < fa.length; j++) serial(fa[j], cb)
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < arguments.length; i++) {
|
|
e = arguments[i]
|
|
if (/input|select|textarea/i.test(e.tagName)) serial(e, cb)
|
|
serializeSubtags(e, [ 'input', 'select', 'textarea' ])
|
|
}
|
|
}
|
|
|
|
// standard query string style serialization
|
|
function serializeQueryString() {
|
|
return reqwest.toQueryString(reqwest.serializeArray.apply(null, arguments))
|
|
}
|
|
|
|
// { 'name': 'value', ... } style serialization
|
|
function serializeHash() {
|
|
var hash = {}
|
|
eachFormElement.apply(function (name, value) {
|
|
if (name in hash) {
|
|
hash[name] && !isArray(hash[name]) && (hash[name] = [hash[name]])
|
|
hash[name].push(value)
|
|
} else hash[name] = value
|
|
}, arguments)
|
|
return hash
|
|
}
|
|
|
|
// [ { name: 'name', value: 'value' }, ... ] style serialization
|
|
reqwest.serializeArray = function () {
|
|
var arr = []
|
|
eachFormElement.apply(function (name, value) {
|
|
arr.push({name: name, value: value})
|
|
}, arguments)
|
|
return arr
|
|
}
|
|
|
|
reqwest.serialize = function () {
|
|
if (arguments.length === 0) return ''
|
|
var opt, fn
|
|
, args = Array.prototype.slice.call(arguments, 0)
|
|
|
|
opt = args.pop()
|
|
opt && opt.nodeType && args.push(opt) && (opt = null)
|
|
opt && (opt = opt.type)
|
|
|
|
if (opt == 'map') fn = serializeHash
|
|
else if (opt == 'array') fn = reqwest.serializeArray
|
|
else fn = serializeQueryString
|
|
|
|
return fn.apply(null, args)
|
|
}
|
|
|
|
reqwest.toQueryString = function (o) {
|
|
var qs = '', i
|
|
, enc = encodeURIComponent
|
|
, push = function (k, v) {
|
|
qs += enc(k) + '=' + enc(v) + '&'
|
|
}
|
|
|
|
if (isArray(o)) {
|
|
for (i = 0; o && i < o.length; i++) push(o[i].name, o[i].value)
|
|
} else {
|
|
for (var k in o) {
|
|
if (!Object.hasOwnProperty.call(o, k)) continue;
|
|
var v = o[k]
|
|
if (isArray(v)) {
|
|
for (i = 0; i < v.length; i++) push(k, v[i])
|
|
} else push(k, o[k])
|
|
}
|
|
}
|
|
|
|
// spaces should be + according to spec
|
|
return qs.replace(/&$/, '').replace(/%20/g, '+')
|
|
}
|
|
|
|
reqwest.getcallbackPrefix = function (reqId) {
|
|
return callbackPrefix
|
|
}
|
|
|
|
// jQuery and Zepto compatibility, differences can be remapped here so you can call
|
|
// .ajax.compat(options, callback)
|
|
reqwest.compat = function (o, fn) {
|
|
if (o) {
|
|
o.type && (o.method = o.type) && delete o.type
|
|
o.dataType && (o.type = o.dataType)
|
|
o.jsonpCallback && (o.jsonpCallbackName = o.jsonpCallback) && delete o.jsonpCallback
|
|
o.jsonp && (o.jsonpCallback = o.jsonp)
|
|
}
|
|
return new Reqwest(o, fn)
|
|
}
|
|
|
|
return reqwest
|
|
});
|
|
|
|
|
|
provide("reqwest", module.exports);
|
|
|
|
!function ($) {
|
|
var r = require('reqwest')
|
|
, integrate = function(method) {
|
|
return function() {
|
|
var args = Array.prototype.slice.call(arguments, 0)
|
|
, i = (this && this.length) || 0
|
|
while (i--) args.unshift(this[i])
|
|
return r[method].apply(null, args)
|
|
}
|
|
}
|
|
, s = integrate('serialize')
|
|
, sa = integrate('serializeArray')
|
|
|
|
$.ender({
|
|
ajax: r
|
|
, serialize: r.serialize
|
|
, serializeArray: r.serializeArray
|
|
, toQueryString: r.toQueryString
|
|
})
|
|
|
|
$.ender({
|
|
serialize: s
|
|
, serializeArray: sa
|
|
}, true)
|
|
}(ender);
|
|
|
|
|
|
}());
|
|
|
|
(function () {
|
|
|
|
var module = { exports: {} }, exports = module.exports;
|
|
|
|
/*!
|
|
* Bean - copyright (c) Jacob Thornton 2011-2012
|
|
* https://github.com/fat/bean
|
|
* MIT license
|
|
*/
|
|
!(function (name, context, definition) {
|
|
if (typeof module != 'undefined' && module.exports) module.exports = definition(name, context);
|
|
else if (typeof define == 'function' && typeof define.amd == 'object') define(definition);
|
|
else context[name] = definition(name, context);
|
|
}('bean', this, function (name, context) {
|
|
var win = window
|
|
, old = context[name]
|
|
, namespaceRegex = /[^\.]*(?=\..*)\.|.*/
|
|
, nameRegex = /\..*/
|
|
, addEvent = 'addEventListener'
|
|
, removeEvent = 'removeEventListener'
|
|
, doc = document || {}
|
|
, root = doc.documentElement || {}
|
|
, W3C_MODEL = root[addEvent]
|
|
, eventSupport = W3C_MODEL ? addEvent : 'attachEvent'
|
|
, ONE = {} // singleton for quick matching making add() do one()
|
|
|
|
, slice = Array.prototype.slice
|
|
, str2arr = function (s, d) { return s.split(d || ' ') }
|
|
, isString = function (o) { return typeof o == 'string' }
|
|
, isFunction = function (o) { return typeof o == 'function' }
|
|
|
|
// events that we consider to be 'native', anything not in this list will
|
|
// be treated as a custom event
|
|
, standardNativeEvents =
|
|
'click dblclick mouseup mousedown contextmenu ' + // mouse buttons
|
|
'mousewheel mousemultiwheel DOMMouseScroll ' + // mouse wheel
|
|
'mouseover mouseout mousemove selectstart selectend ' + // mouse movement
|
|
'keydown keypress keyup ' + // keyboard
|
|
'orientationchange ' + // mobile
|
|
'focus blur change reset select submit ' + // form elements
|
|
'load unload beforeunload resize move DOMContentLoaded ' + // window
|
|
'readystatechange message ' + // window
|
|
'error abort scroll ' // misc
|
|
// element.fireEvent('onXYZ'... is not forgiving if we try to fire an event
|
|
// that doesn't actually exist, so make sure we only do these on newer browsers
|
|
, w3cNativeEvents =
|
|
'show ' + // mouse buttons
|
|
'input invalid ' + // form elements
|
|
'touchstart touchmove touchend touchcancel ' + // touch
|
|
'gesturestart gesturechange gestureend ' + // gesture
|
|
'textinput' + // TextEvent
|
|
'readystatechange pageshow pagehide popstate ' + // window
|
|
'hashchange offline online ' + // window
|
|
'afterprint beforeprint ' + // printing
|
|
'dragstart dragenter dragover dragleave drag drop dragend ' + // dnd
|
|
'loadstart progress suspend emptied stalled loadmetadata ' + // media
|
|
'loadeddata canplay canplaythrough playing waiting seeking ' + // media
|
|
'seeked ended durationchange timeupdate play pause ratechange ' + // media
|
|
'volumechange cuechange ' + // media
|
|
'checking noupdate downloading cached updateready obsolete ' // appcache
|
|
|
|
// convert to a hash for quick lookups
|
|
, nativeEvents = (function (hash, events, i) {
|
|
for (i = 0; i < events.length; i++) events[i] && (hash[events[i]] = 1)
|
|
return hash
|
|
}({}, str2arr(standardNativeEvents + (W3C_MODEL ? w3cNativeEvents : ''))))
|
|
|
|
// custom events are events that we *fake*, they are not provided natively but
|
|
// we can use native events to generate them
|
|
, customEvents = (function () {
|
|
var isAncestor = 'compareDocumentPosition' in root
|
|
? function (element, container) {
|
|
return container.compareDocumentPosition && (container.compareDocumentPosition(element) & 16) === 16
|
|
}
|
|
: 'contains' in root
|
|
? function (element, container) {
|
|
container = container.nodeType === 9 || container === window ? root : container
|
|
return container !== element && container.contains(element)
|
|
}
|
|
: function (element, container) {
|
|
while (element = element.parentNode) if (element === container) return 1
|
|
return 0
|
|
}
|
|
, check = function (event) {
|
|
var related = event.relatedTarget
|
|
return !related
|
|
? related == null
|
|
: (related !== this && related.prefix !== 'xul' && !/document/.test(this.toString())
|
|
&& !isAncestor(related, this))
|
|
}
|
|
|
|
return {
|
|
mouseenter: { base: 'mouseover', condition: check }
|
|
, mouseleave: { base: 'mouseout', condition: check }
|
|
, mousewheel: { base: /Firefox/.test(navigator.userAgent) ? 'DOMMouseScroll' : 'mousewheel' }
|
|
}
|
|
}())
|
|
|
|
// we provide a consistent Event object across browsers by taking the actual DOM
|
|
// event object and generating a new one from its properties.
|
|
, Event = (function () {
|
|
// a whitelist of properties (for different event types) tells us what to check for and copy
|
|
var commonProps = str2arr('altKey attrChange attrName bubbles cancelable ctrlKey currentTarget ' +
|
|
'detail eventPhase getModifierState isTrusted metaKey relatedNode relatedTarget shiftKey ' +
|
|
'srcElement target timeStamp type view which propertyName')
|
|
, mouseProps = commonProps.concat(str2arr('button buttons clientX clientY dataTransfer ' +
|
|
'fromElement offsetX offsetY pageX pageY screenX screenY toElement'))
|
|
, mouseWheelProps = mouseProps.concat(str2arr('wheelDelta wheelDeltaX wheelDeltaY wheelDeltaZ ' +
|
|
'axis')) // 'axis' is FF specific
|
|
, keyProps = commonProps.concat(str2arr('char charCode key keyCode keyIdentifier ' +
|
|
'keyLocation location'))
|
|
, textProps = commonProps.concat(str2arr('data'))
|
|
, touchProps = commonProps.concat(str2arr('touches targetTouches changedTouches scale rotation'))
|
|
, messageProps = commonProps.concat(str2arr('data origin source'))
|
|
, stateProps = commonProps.concat(str2arr('state'))
|
|
, overOutRegex = /over|out/
|
|
// some event types need special handling and some need special properties, do that all here
|
|
, typeFixers = [
|
|
{ // key events
|
|
reg: /key/i
|
|
, fix: function (event, newEvent) {
|
|
newEvent.keyCode = event.keyCode || event.which
|
|
return keyProps
|
|
}
|
|
}
|
|
, { // mouse events
|
|
reg: /click|mouse(?!(.*wheel|scroll))|menu|drag|drop/i
|
|
, fix: function (event, newEvent, type) {
|
|
newEvent.rightClick = event.which === 3 || event.button === 2
|
|
newEvent.pos = { x: 0, y: 0 }
|
|
if (event.pageX || event.pageY) {
|
|
newEvent.clientX = event.pageX
|
|
newEvent.clientY = event.pageY
|
|
} else if (event.clientX || event.clientY) {
|
|
newEvent.clientX = event.clientX + doc.body.scrollLeft + root.scrollLeft
|
|
newEvent.clientY = event.clientY + doc.body.scrollTop + root.scrollTop
|
|
}
|
|
if (overOutRegex.test(type)) {
|
|
newEvent.relatedTarget = event.relatedTarget
|
|
|| event[(type == 'mouseover' ? 'from' : 'to') + 'Element']
|
|
}
|
|
return mouseProps
|
|
}
|
|
}
|
|
, { // mouse wheel events
|
|
reg: /mouse.*(wheel|scroll)/i
|
|
, fix: function () { return mouseWheelProps }
|
|
}
|
|
, { // TextEvent
|
|
reg: /^text/i
|
|
, fix: function () { return textProps }
|
|
}
|
|
, { // touch and gesture events
|
|
reg: /^touch|^gesture/i
|
|
, fix: function () { return touchProps }
|
|
}
|
|
, { // message events
|
|
reg: /^message$/i
|
|
, fix: function () { return messageProps }
|
|
}
|
|
, { // popstate events
|
|
reg: /^popstate$/i
|
|
, fix: function () { return stateProps }
|
|
}
|
|
, { // everything else
|
|
reg: /.*/
|
|
, fix: function () { return commonProps }
|
|
}
|
|
]
|
|
, typeFixerMap = {} // used to map event types to fixer functions (above), a basic cache mechanism
|
|
|
|
, Event = function (event, element, isNative) {
|
|
if (!arguments.length) return
|
|
event = event || ((element.ownerDocument || element.document || element).parentWindow || win).event
|
|
this.originalEvent = event
|
|
this.isNative = isNative
|
|
this.isBean = true
|
|
|
|
if (!event) return
|
|
|
|
var type = event.type
|
|
, target = event.target || event.srcElement
|
|
, i, l, p, props, fixer
|
|
|
|
this.target = target && target.nodeType === 3 ? target.parentNode : target
|
|
|
|
if (isNative) { // we only need basic augmentation on custom events, the rest expensive & pointless
|
|
fixer = typeFixerMap[type]
|
|
if (!fixer) { // haven't encountered this event type before, map a fixer function for it
|
|
for (i = 0, l = typeFixers.length; i < l; i++) {
|
|
if (typeFixers[i].reg.test(type)) { // guaranteed to match at least one, last is .*
|
|
typeFixerMap[type] = fixer = typeFixers[i].fix
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
props = fixer(event, this, type)
|
|
for (i = props.length; i--;) {
|
|
if (!((p = props[i]) in this) && p in event) this[p] = event[p]
|
|
}
|
|
}
|
|
}
|
|
|
|
// preventDefault() and stopPropagation() are a consistent interface to those functions
|
|
// on the DOM, stop() is an alias for both of them together
|
|
Event.prototype.preventDefault = function () {
|
|
if (this.originalEvent.preventDefault) this.originalEvent.preventDefault()
|
|
else this.originalEvent.returnValue = false
|
|
}
|
|
Event.prototype.stopPropagation = function () {
|
|
if (this.originalEvent.stopPropagation) this.originalEvent.stopPropagation()
|
|
else this.originalEvent.cancelBubble = true
|
|
}
|
|
Event.prototype.stop = function () {
|
|
this.preventDefault()
|
|
this.stopPropagation()
|
|
this.stopped = true
|
|
}
|
|
// stopImmediatePropagation() has to be handled internally because we manage the event list for
|
|
// each element
|
|
// note that originalElement may be a Bean#Event object in some situations
|
|
Event.prototype.stopImmediatePropagation = function () {
|
|
if (this.originalEvent.stopImmediatePropagation) this.originalEvent.stopImmediatePropagation()
|
|
this.isImmediatePropagationStopped = function () { return true }
|
|
}
|
|
Event.prototype.isImmediatePropagationStopped = function () {
|
|
return this.originalEvent.isImmediatePropagationStopped && this.originalEvent.isImmediatePropagationStopped()
|
|
}
|
|
Event.prototype.clone = function (currentTarget) {
|
|
//TODO: this is ripe for optimisation, new events are *expensive*
|
|
// improving this will speed up delegated events
|
|
var ne = new Event(this, this.element, this.isNative)
|
|
ne.currentTarget = currentTarget
|
|
return ne
|
|
}
|
|
|
|
return Event
|
|
}())
|
|
|
|
// if we're in old IE we can't do onpropertychange on doc or win so we use doc.documentElement for both
|
|
, targetElement = function (element, isNative) {
|
|
return !W3C_MODEL && !isNative && (element === doc || element === win) ? root : element
|
|
}
|
|
|
|
/**
|
|
* Bean maintains an internal registry for event listeners. We don't touch elements, objects
|
|
* or functions to identify them, instead we store everything in the registry.
|
|
* Each event listener has a RegEntry object, we have one 'registry' for the whole instance.
|
|
*/
|
|
, RegEntry = (function () {
|
|
// each handler is wrapped so we can handle delegation and custom events
|
|
var wrappedHandler = function (element, fn, condition, args) {
|
|
var call = function (event, eargs) {
|
|
return fn.apply(element, args ? slice.call(eargs, event ? 0 : 1).concat(args) : eargs)
|
|
}
|
|
, findTarget = function (event, eventElement) {
|
|
return fn.__beanDel ? fn.__beanDel.ft(event.target, element) : eventElement
|
|
}
|
|
, handler = condition
|
|
? function (event) {
|
|
var target = findTarget(event, this) // deleated event
|
|
if (condition.apply(target, arguments)) {
|
|
if (event) event.currentTarget = target
|
|
return call(event, arguments)
|
|
}
|
|
}
|
|
: function (event) {
|
|
if (fn.__beanDel) event = event.clone(findTarget(event)) // delegated event, fix the fix
|
|
return call(event, arguments)
|
|
}
|
|
handler.__beanDel = fn.__beanDel
|
|
return handler
|
|
}
|
|
|
|
, RegEntry = function (element, type, handler, original, namespaces, args, root) {
|
|
var customType = customEvents[type]
|
|
, isNative
|
|
|
|
if (type == 'unload') {
|
|
// self clean-up
|
|
handler = once(removeListener, element, type, handler, original)
|
|
}
|
|
|
|
if (customType) {
|
|
if (customType.condition) {
|
|
handler = wrappedHandler(element, handler, customType.condition, args)
|
|
}
|
|
type = customType.base || type
|
|
}
|
|
|
|
this.isNative = isNative = nativeEvents[type] && !!element[eventSupport]
|
|
this.customType = !W3C_MODEL && !isNative && type
|
|
this.element = element
|
|
this.type = type
|
|
this.original = original
|
|
this.namespaces = namespaces
|
|
this.eventType = W3C_MODEL || isNative ? type : 'propertychange'
|
|
this.target = targetElement(element, isNative)
|
|
this[eventSupport] = !!this.target[eventSupport]
|
|
this.root = root
|
|
this.handler = wrappedHandler(element, handler, null, args)
|
|
}
|
|
|
|
// given a list of namespaces, is our entry in any of them?
|
|
RegEntry.prototype.inNamespaces = function (checkNamespaces) {
|
|
var i, j, c = 0
|
|
if (!checkNamespaces) return true
|
|
if (!this.namespaces) return false
|
|
for (i = checkNamespaces.length; i--;) {
|
|
for (j = this.namespaces.length; j--;) {
|
|
if (checkNamespaces[i] == this.namespaces[j]) c++
|
|
}
|
|
}
|
|
return checkNamespaces.length === c
|
|
}
|
|
|
|
// match by element, original fn (opt), handler fn (opt)
|
|
RegEntry.prototype.matches = function (checkElement, checkOriginal, checkHandler) {
|
|
return this.element === checkElement &&
|
|
(!checkOriginal || this.original === checkOriginal) &&
|
|
(!checkHandler || this.handler === checkHandler)
|
|
}
|
|
|
|
return RegEntry
|
|
}())
|
|
|
|
, registry = (function () {
|
|
// our map stores arrays by event type, just because it's better than storing
|
|
// everything in a single array.
|
|
// uses '$' as a prefix for the keys for safety and 'r' as a special prefix for
|
|
// rootListeners so we can look them up fast
|
|
var map = {}
|
|
|
|
// generic functional search of our registry for matching listeners,
|
|
// `fn` returns false to break out of the loop
|
|
, forAll = function (element, type, original, handler, root, fn) {
|
|
var pfx = root ? 'r' : '$'
|
|
if (!type || type == '*') {
|
|
// search the whole registry
|
|
for (var t in map) {
|
|
if (t.charAt(0) == pfx) {
|
|
forAll(element, t.substr(1), original, handler, root, fn)
|
|
}
|
|
}
|
|
} else {
|
|
var i = 0, l, list = map[pfx + type], all = element == '*'
|
|
if (!list) return
|
|
for (l = list.length; i < l; i++) {
|
|
if ((all || list[i].matches(element, original, handler)) && !fn(list[i], list, i, type)) return
|
|
}
|
|
}
|
|
}
|
|
|
|
, has = function (element, type, original, root) {
|
|
// we're not using forAll here simply because it's a bit slower and this
|
|
// needs to be fast
|
|
var i, list = map[(root ? 'r' : '$') + type]
|
|
if (list) {
|
|
for (i = list.length; i--;) {
|
|
if (!list[i].root && list[i].matches(element, original, null)) return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
, get = function (element, type, original, root) {
|
|
var entries = []
|
|
forAll(element, type, original, null, root, function (entry) {
|
|
return entries.push(entry)
|
|
})
|
|
return entries
|
|
}
|
|
|
|
, put = function (entry) {
|
|
var has = !entry.root && !this.has(entry.element, entry.type, null, false)
|
|
, key = (entry.root ? 'r' : '$') + entry.type
|
|
;(map[key] || (map[key] = [])).push(entry)
|
|
return has
|
|
}
|
|
|
|
, del = function (entry) {
|
|
forAll(entry.element, entry.type, null, entry.handler, entry.root, function (entry, list, i) {
|
|
list.splice(i, 1)
|
|
entry.removed = true
|
|
if (list.length === 0) delete map[(entry.root ? 'r' : '$') + entry.type]
|
|
return false
|
|
})
|
|
}
|
|
|
|
// dump all entries, used for onunload
|
|
, entries = function () {
|
|
var t, entries = []
|
|
for (t in map) {
|
|
if (t.charAt(0) == '$') entries = entries.concat(map[t])
|
|
}
|
|
return entries
|
|
}
|
|
|
|
return { has: has, get: get, put: put, del: del, entries: entries }
|
|
}())
|
|
|
|
// we need a selector engine for delegated events, use querySelectorAll if it exists
|
|
// but for older browsers we need Qwery, Sizzle or similar
|
|
, selectorEngine
|
|
, setSelectorEngine = function (e) {
|
|
if (!arguments.length) {
|
|
selectorEngine = doc.querySelectorAll
|
|
? function (s, r) {
|
|
return r.querySelectorAll(s)
|
|
}
|
|
: function () {
|
|
throw new Error('Bean: No selector engine installed') // eeek
|
|
}
|
|
} else {
|
|
selectorEngine = e
|
|
}
|
|
}
|
|
|
|
// we attach this listener to each DOM event that we need to listen to, only once
|
|
// per event type per DOM element
|
|
, rootListener = function (event, type) {
|
|
if (!W3C_MODEL && type && event && event.propertyName != '_on' + type) return
|
|
|
|
var listeners = registry.get(this, type || event.type, null, false)
|
|
, l = listeners.length
|
|
, i = 0
|
|
|
|
event = new Event(event, this, true)
|
|
if (type) event.type = type
|
|
|
|
// iterate through all handlers registered for this type, calling them unless they have
|
|
// been removed by a previous handler or stopImmediatePropagation() has been called
|
|
for (; i < l && !event.isImmediatePropagationStopped(); i++) {
|
|
if (!listeners[i].removed) listeners[i].handler.call(this, event)
|
|
}
|
|
}
|
|
|
|
// add and remove listeners to DOM elements
|
|
, listener = W3C_MODEL
|
|
? function (element, type, add) {
|
|
// new browsers
|
|
element[add ? addEvent : removeEvent](type, rootListener, false)
|
|
}
|
|
: function (element, type, add, custom) {
|
|
// IE8 and below, use attachEvent/detachEvent and we have to piggy-back propertychange events
|
|
// to simulate event bubbling etc.
|
|
var entry
|
|
if (add) {
|
|
registry.put(entry = new RegEntry(
|
|
element
|
|
, custom || type
|
|
, function (event) { // handler
|
|
rootListener.call(element, event, custom)
|
|
}
|
|
, rootListener
|
|
, null
|
|
, null
|
|
, true // is root
|
|
))
|
|
if (custom && element['_on' + custom] == null) element['_on' + custom] = 0
|
|
entry.target.attachEvent('on' + entry.eventType, entry.handler)
|
|
} else {
|
|
entry = registry.get(element, custom || type, rootListener, true)[0]
|
|
if (entry) {
|
|
entry.target.detachEvent('on' + entry.eventType, entry.handler)
|
|
registry.del(entry)
|
|
}
|
|
}
|
|
}
|
|
|
|
, once = function (rm, element, type, fn, originalFn) {
|
|
// wrap the handler in a handler that does a remove as well
|
|
return function () {
|
|
fn.apply(this, arguments)
|
|
rm(element, type, originalFn)
|
|
}
|
|
}
|
|
|
|
, removeListener = function (element, orgType, handler, namespaces) {
|
|
var type = orgType && orgType.replace(nameRegex, '')
|
|
, handlers = registry.get(element, type, null, false)
|
|
, removed = {}
|
|
, i, l
|
|
|
|
for (i = 0, l = handlers.length; i < l; i++) {
|
|
if ((!handler || handlers[i].original === handler) && handlers[i].inNamespaces(namespaces)) {
|
|
// TODO: this is problematic, we have a registry.get() and registry.del() that
|
|
// both do registry searches so we waste cycles doing this. Needs to be rolled into
|
|
// a single registry.forAll(fn) that removes while finding, but the catch is that
|
|
// we'll be splicing the arrays that we're iterating over. Needs extra tests to
|
|
// make sure we don't screw it up. @rvagg
|
|
registry.del(handlers[i])
|
|
if (!removed[handlers[i].eventType] && handlers[i][eventSupport])
|
|
removed[handlers[i].eventType] = { t: handlers[i].eventType, c: handlers[i].type }
|
|
}
|
|
}
|
|
// check each type/element for removed listeners and remove the rootListener where it's no longer needed
|
|
for (i in removed) {
|
|
if (!registry.has(element, removed[i].t, null, false)) {
|
|
// last listener of this type, remove the rootListener
|
|
listener(element, removed[i].t, false, removed[i].c)
|
|
}
|
|
}
|
|
}
|
|
|
|
// set up a delegate helper using the given selector, wrap the handler function
|
|
, delegate = function (selector, fn) {
|
|
//TODO: findTarget (therefore $) is called twice, once for match and once for
|
|
// setting e.currentTarget, fix this so it's only needed once
|
|
var findTarget = function (target, root) {
|
|
var i, array = isString(selector) ? selectorEngine(selector, root) : selector
|
|
for (; target && target !== root; target = target.parentNode) {
|
|
for (i = array.length; i--;) {
|
|
if (array[i] === target) return target
|
|
}
|
|
}
|
|
}
|
|
, handler = function (e) {
|
|
var match = findTarget(e.target, this)
|
|
if (match) fn.apply(match, arguments)
|
|
}
|
|
|
|
// __beanDel isn't pleasant but it's a private function, not exposed outside of Bean
|
|
handler.__beanDel = {
|
|
ft : findTarget // attach it here for customEvents to use too
|
|
, selector : selector
|
|
}
|
|
return handler
|
|
}
|
|
|
|
, fireListener = W3C_MODEL ? function (isNative, type, element) {
|
|
// modern browsers, do a proper dispatchEvent()
|
|
var evt = doc.createEvent(isNative ? 'HTMLEvents' : 'UIEvents')
|
|
evt[isNative ? 'initEvent' : 'initUIEvent'](type, true, true, win, 1)
|
|
element.dispatchEvent(evt)
|
|
} : function (isNative, type, element) {
|
|
// old browser use onpropertychange, just increment a custom property to trigger the event
|
|
element = targetElement(element, isNative)
|
|
isNative ? element.fireEvent('on' + type, doc.createEventObject()) : element['_on' + type]++
|
|
}
|
|
|
|
/**
|
|
* Public API: off(), on(), add(), (remove()), one(), fire(), clone()
|
|
*/
|
|
|
|
/**
|
|
* off(element[, eventType(s)[, handler ]])
|
|
*/
|
|
, off = function (element, typeSpec, fn) {
|
|
var isTypeStr = isString(typeSpec)
|
|
, k, type, namespaces, i
|
|
|
|
if (isTypeStr && typeSpec.indexOf(' ') > 0) {
|
|
// off(el, 't1 t2 t3', fn) or off(el, 't1 t2 t3')
|
|
typeSpec = str2arr(typeSpec)
|
|
for (i = typeSpec.length; i--;)
|
|
off(element, typeSpec[i], fn)
|
|
return element
|
|
}
|
|
|
|
type = isTypeStr && typeSpec.replace(nameRegex, '')
|
|
if (type && customEvents[type]) type = customEvents[type].base
|
|
|
|
if (!typeSpec || isTypeStr) {
|
|
// off(el) or off(el, t1.ns) or off(el, .ns) or off(el, .ns1.ns2.ns3)
|
|
if (namespaces = isTypeStr && typeSpec.replace(namespaceRegex, '')) namespaces = str2arr(namespaces, '.')
|
|
removeListener(element, type, fn, namespaces)
|
|
} else if (isFunction(typeSpec)) {
|
|
// off(el, fn)
|
|
removeListener(element, null, typeSpec)
|
|
} else {
|
|
// off(el, { t1: fn1, t2, fn2 })
|
|
for (k in typeSpec) {
|
|
if (typeSpec.hasOwnProperty(k)) off(element, k, typeSpec[k])
|
|
}
|
|
}
|
|
|
|
return element
|
|
}
|
|
|
|
/**
|
|
* on(element, eventType(s)[, selector], handler[, args ])
|
|
*/
|
|
, on = function(element, events, selector, fn) {
|
|
var originalFn, type, types, i, args, entry, first
|
|
|
|
//TODO: the undefined check means you can't pass an 'args' argument, fix this perhaps?
|
|
if (selector === undefined && typeof events == 'object') {
|
|
//TODO: this can't handle delegated events
|
|
for (type in events) {
|
|
if (events.hasOwnProperty(type)) {
|
|
on.call(this, element, type, events[type])
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
if (!isFunction(selector)) {
|
|
// delegated event
|
|
originalFn = fn
|
|
args = slice.call(arguments, 4)
|
|
fn = delegate(selector, originalFn, selectorEngine)
|
|
} else {
|
|
args = slice.call(arguments, 3)
|
|
fn = originalFn = selector
|
|
}
|
|
|
|
types = str2arr(events)
|
|
|
|
// special case for one(), wrap in a self-removing handler
|
|
if (this === ONE) {
|
|
fn = once(off, element, events, fn, originalFn)
|
|
}
|
|
|
|
for (i = types.length; i--;) {
|
|
// add new handler to the registry and check if it's the first for this element/type
|
|
first = registry.put(entry = new RegEntry(
|
|
element
|
|
, types[i].replace(nameRegex, '') // event type
|
|
, fn
|
|
, originalFn
|
|
, str2arr(types[i].replace(namespaceRegex, ''), '.') // namespaces
|
|
, args
|
|
, false // not root
|
|
))
|
|
if (entry[eventSupport] && first) {
|
|
// first event of this type on this element, add root listener
|
|
listener(element, entry.eventType, true, entry.customType)
|
|
}
|
|
}
|
|
|
|
return element
|
|
}
|
|
|
|
/**
|
|
* add(element[, selector], eventType(s), handler[, args ])
|
|
*
|
|
* Deprecated: kept (for now) for backward-compatibility
|
|
*/
|
|
, add = function (element, events, fn, delfn) {
|
|
return on.apply(
|
|
null
|
|
, !isString(fn)
|
|
? slice.call(arguments)
|
|
: [ element, fn, events, delfn ].concat(arguments.length > 3 ? slice.call(arguments, 5) : [])
|
|
)
|
|
}
|
|
|
|
/**
|
|
* one(element, eventType(s)[, selector], handler[, args ])
|
|
*/
|
|
, one = function () {
|
|
return on.apply(ONE, arguments)
|
|
}
|
|
|
|
/**
|
|
* fire(element, eventType(s)[, args ])
|
|
*
|
|
* The optional 'args' argument must be an array, if no 'args' argument is provided
|
|
* then we can use the browser's DOM event system, otherwise we trigger handlers manually
|
|
*/
|
|
, fire = function (element, type, args) {
|
|
var types = str2arr(type)
|
|
, i, j, l, names, handlers
|
|
|
|
for (i = types.length; i--;) {
|
|
type = types[i].replace(nameRegex, '')
|
|
if (names = types[i].replace(namespaceRegex, '')) names = str2arr(names, '.')
|
|
if (!names && !args && element[eventSupport]) {
|
|
fireListener(nativeEvents[type], type, element)
|
|
} else {
|
|
// non-native event, either because of a namespace, arguments or a non DOM element
|
|
// iterate over all listeners and manually 'fire'
|
|
handlers = registry.get(element, type, null, false)
|
|
args = [false].concat(args)
|
|
for (j = 0, l = handlers.length; j < l; j++) {
|
|
if (handlers[j].inNamespaces(names)) {
|
|
handlers[j].handler.apply(element, args)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return element
|
|
}
|
|
|
|
/**
|
|
* clone(dstElement, srcElement[, eventType ])
|
|
*
|
|
* TODO: perhaps for consistency we should allow the same flexibility in type specifiers?
|
|
*/
|
|
, clone = function (element, from, type) {
|
|
var handlers = registry.get(from, type, null, false)
|
|
, l = handlers.length
|
|
, i = 0
|
|
, args, beanDel
|
|
|
|
for (; i < l; i++) {
|
|
if (handlers[i].original) {
|
|
args = [ element, handlers[i].type ]
|
|
if (beanDel = handlers[i].handler.__beanDel) args.push(beanDel.selector)
|
|
args.push(handlers[i].original)
|
|
on.apply(null, args)
|
|
}
|
|
}
|
|
return element
|
|
}
|
|
|
|
, bean = {
|
|
on : on
|
|
, add : add
|
|
, one : one
|
|
, off : off
|
|
, remove : off
|
|
, clone : clone
|
|
, fire : fire
|
|
, setSelectorEngine : setSelectorEngine
|
|
, noConflict : function () {
|
|
context[name] = old
|
|
return this
|
|
}
|
|
}
|
|
|
|
// for IE, clean up on unload to avoid leaks
|
|
if (win.attachEvent) {
|
|
var cleanup = function () {
|
|
var i, entries = registry.entries()
|
|
for (i in entries) {
|
|
if (entries[i].type && entries[i].type !== 'unload') off(entries[i].element, entries[i].type)
|
|
}
|
|
win.detachEvent('onunload', cleanup)
|
|
win.CollectGarbage && win.CollectGarbage()
|
|
}
|
|
win.attachEvent('onunload', cleanup)
|
|
}
|
|
|
|
// initialize selector engine to internal default (qSA or throw Error)
|
|
setSelectorEngine()
|
|
|
|
return bean
|
|
}));
|
|
|
|
|
|
provide("bean", module.exports);
|
|
|
|
!function ($) {
|
|
var b = require('bean')
|
|
|
|
, integrate = function (method, type, method2) {
|
|
var _args = type ? [type] : []
|
|
return function () {
|
|
for (var i = 0, l = this.length; i < l; i++) {
|
|
if (!arguments.length && method == 'on' && type) method = 'fire'
|
|
b[method].apply(this, [this[i]].concat(_args, Array.prototype.slice.call(arguments, 0)))
|
|
}
|
|
return this
|
|
}
|
|
}
|
|
|
|
, add = integrate('add')
|
|
, on = integrate('on')
|
|
, one = integrate('one')
|
|
, off = integrate('off')
|
|
, fire = integrate('fire')
|
|
, clone = integrate('clone')
|
|
|
|
, hover = function (enter, leave, i) { // i for internal
|
|
for (i = this.length; i--;) {
|
|
b.on.call(this, this[i], 'mouseenter', enter)
|
|
b.on.call(this, this[i], 'mouseleave', leave)
|
|
}
|
|
return this
|
|
}
|
|
|
|
, methods = {
|
|
on : on
|
|
, addListener : on
|
|
, bind : on
|
|
, listen : on
|
|
, delegate : add // jQuery compat, same arg order as add()
|
|
|
|
, one : one
|
|
|
|
, off : off
|
|
, unbind : off
|
|
, unlisten : off
|
|
, removeListener : off
|
|
, undelegate : off
|
|
|
|
, emit : fire
|
|
, trigger : fire
|
|
|
|
, cloneEvents : clone
|
|
|
|
, hover : hover
|
|
}
|
|
|
|
, shortcuts =
|
|
('blur change click dblclick error focus focusin focusout keydown keypress '
|
|
+ 'keyup load mousedown mouseenter mouseleave mouseout mouseover mouseup '
|
|
+ 'mousemove resize scroll select submit unload').split(' ')
|
|
|
|
for (var i = shortcuts.length; i--;) {
|
|
methods[shortcuts[i]] = integrate('on', shortcuts[i])
|
|
}
|
|
|
|
b.setSelectorEngine($)
|
|
|
|
$.ender(methods, true)
|
|
}(ender);
|
|
|
|
}());
|
|
|
|
(function () {
|
|
|
|
var module = { exports: {} }, exports = module.exports;
|
|
|
|
/*!
|
|
* 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 context['define'] == 'function' && context['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 ? 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.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 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.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
|
|
}); // the only line we care about using a semi-colon. placed here for concatenation tools
|
|
|
|
|
|
provide("bonzo", module.exports);
|
|
|
|
(function ($) {
|
|
|
|
var b = require('bonzo')
|
|
b.setQueryEngine($)
|
|
$.ender(b)
|
|
$.ender(b(), true)
|
|
$.ender({
|
|
create: function (node) {
|
|
return $(b.create(node))
|
|
}
|
|
})
|
|
|
|
$.id = function (id) {
|
|
return $([document.getElementById(id)])
|
|
}
|
|
|
|
function indexOf(ar, val) {
|
|
for (var i = 0; i < ar.length; i++) if (ar[i] === val) return i
|
|
return -1
|
|
}
|
|
|
|
function uniq(ar) {
|
|
var r = [], i = 0, j = 0, k, item, inIt
|
|
for (; item = ar[i]; ++i) {
|
|
inIt = false
|
|
for (k = 0; k < r.length; ++k) {
|
|
if (r[k] === item) {
|
|
inIt = true; break
|
|
}
|
|
}
|
|
if (!inIt) r[j++] = item
|
|
}
|
|
return r
|
|
}
|
|
|
|
$.ender({
|
|
parents: function (selector, closest) {
|
|
if (!this.length) return this
|
|
if (!selector) selector = '*'
|
|
var collection = $(selector), j, k, p, r = []
|
|
for (j = 0, k = this.length; j < k; j++) {
|
|
p = this[j]
|
|
while (p = p.parentNode) {
|
|
if (~indexOf(collection, p)) {
|
|
r.push(p)
|
|
if (closest) break;
|
|
}
|
|
}
|
|
}
|
|
return $(uniq(r))
|
|
}
|
|
|
|
, parent: function() {
|
|
return $(uniq(b(this).parent()))
|
|
}
|
|
|
|
, closest: function (selector) {
|
|
return this.parents(selector, true)
|
|
}
|
|
|
|
, first: function () {
|
|
return $(this.length ? this[0] : this)
|
|
}
|
|
|
|
, last: function () {
|
|
return $(this.length ? this[this.length - 1] : [])
|
|
}
|
|
|
|
, next: function () {
|
|
return $(b(this).next())
|
|
}
|
|
|
|
, previous: function () {
|
|
return $(b(this).previous())
|
|
}
|
|
|
|
, appendTo: function (t) {
|
|
return b(this.selector).appendTo(t, this)
|
|
}
|
|
|
|
, prependTo: function (t) {
|
|
return b(this.selector).prependTo(t, this)
|
|
}
|
|
|
|
, insertAfter: function (t) {
|
|
return b(this.selector).insertAfter(t, this)
|
|
}
|
|
|
|
, insertBefore: function (t) {
|
|
return b(this.selector).insertBefore(t, this)
|
|
}
|
|
|
|
, siblings: function () {
|
|
var i, l, p, r = []
|
|
for (i = 0, l = this.length; i < l; i++) {
|
|
p = this[i]
|
|
while (p = p.previousSibling) p.nodeType == 1 && r.push(p)
|
|
p = this[i]
|
|
while (p = p.nextSibling) p.nodeType == 1 && r.push(p)
|
|
}
|
|
return $(r)
|
|
}
|
|
|
|
, children: function () {
|
|
var i, l, el, r = []
|
|
for (i = 0, l = this.length; i < l; i++) {
|
|
if (!(el = b.firstChild(this[i]))) continue;
|
|
r.push(el)
|
|
while (el = el.nextSibling) el.nodeType == 1 && r.push(el)
|
|
}
|
|
return $(uniq(r))
|
|
}
|
|
|
|
, height: function (v) {
|
|
return dimension.call(this, 'height', v)
|
|
}
|
|
|
|
, width: function (v) {
|
|
return dimension.call(this, 'width', v)
|
|
}
|
|
}, true)
|
|
|
|
/**
|
|
* @param {string} type either width or height
|
|
* @param {number=} opt_v becomes a setter instead of a getter
|
|
* @return {number}
|
|
*/
|
|
function dimension(type, opt_v) {
|
|
return typeof opt_v == 'undefined'
|
|
? b(this).dim()[type]
|
|
: this.css(type, opt_v)
|
|
}
|
|
}(ender));
|
|
|
|
}());
|
|
|
|
(function () {
|
|
|
|
var module = { exports: {} }, exports = module.exports;
|
|
|
|
/*!
|
|
* domready (c) Dustin Diaz 2012 - License MIT
|
|
*/
|
|
!function (name, definition) {
|
|
if (typeof module != 'undefined') module.exports = definition()
|
|
else if (typeof define == 'function' && typeof define.amd == 'object') define(definition)
|
|
else this[name] = definition()
|
|
}('domready', function (ready) {
|
|
|
|
var fns = [], fn, f = false
|
|
, doc = document
|
|
, testEl = doc.documentElement
|
|
, hack = testEl.doScroll
|
|
, domContentLoaded = 'DOMContentLoaded'
|
|
, addEventListener = 'addEventListener'
|
|
, onreadystatechange = 'onreadystatechange'
|
|
, readyState = 'readyState'
|
|
, loaded = /^loade|c/.test(doc[readyState])
|
|
|
|
function flush(f) {
|
|
loaded = 1
|
|
while (f = fns.shift()) f()
|
|
}
|
|
|
|
doc[addEventListener] && doc[addEventListener](domContentLoaded, fn = function () {
|
|
doc.removeEventListener(domContentLoaded, fn, f)
|
|
flush()
|
|
}, f)
|
|
|
|
|
|
hack && doc.attachEvent(onreadystatechange, fn = function () {
|
|
if (/^c/.test(doc[readyState])) {
|
|
doc.detachEvent(onreadystatechange, fn)
|
|
flush()
|
|
}
|
|
})
|
|
|
|
return (ready = hack ?
|
|
function (fn) {
|
|
self != top ?
|
|
loaded ? fn() : fns.push(fn) :
|
|
function () {
|
|
try {
|
|
testEl.doScroll('left')
|
|
} catch (e) {
|
|
return setTimeout(function() { ready(fn) }, 50)
|
|
}
|
|
fn()
|
|
}()
|
|
} :
|
|
function (fn) {
|
|
loaded ? fn() : fns.push(fn)
|
|
})
|
|
})
|
|
|
|
provide("domready", module.exports);
|
|
|
|
!function ($) {
|
|
var ready = require('domready')
|
|
$.ender({domReady: ready})
|
|
$.ender({
|
|
ready: function (f) {
|
|
ready(f)
|
|
return this
|
|
}
|
|
}, true)
|
|
}(ender);
|
|
|
|
}());
|
|
|
|
(function () {
|
|
|
|
var module = { exports: {} }, exports = module.exports;
|
|
|
|
/*!
|
|
* @preserve Qwery - A Blazing Fast query selector engine
|
|
* https://github.com/ded/qwery
|
|
* copyright Dustin Diaz 2012
|
|
* MIT License
|
|
*/
|
|
|
|
(function (name, context, definition) {
|
|
if (typeof module != 'undefined' && module.exports) module.exports = definition()
|
|
else if (typeof context['define'] == 'function' && context['define']['amd']) define(definition)
|
|
else context[name] = definition()
|
|
})('qwery', this, function () {
|
|
var doc = document
|
|
, html = doc.documentElement
|
|
, byClass = 'getElementsByClassName'
|
|
, byTag = 'getElementsByTagName'
|
|
, qSA = 'querySelectorAll'
|
|
, useNativeQSA = 'useNativeQSA'
|
|
, tagName = 'tagName'
|
|
, nodeType = 'nodeType'
|
|
, select // main select() method, assign later
|
|
|
|
, id = /#([\w\-]+)/
|
|
, clas = /\.[\w\-]+/g
|
|
, idOnly = /^#([\w\-]+)$/
|
|
, classOnly = /^\.([\w\-]+)$/
|
|
, tagOnly = /^([\w\-]+)$/
|
|
, tagAndOrClass = /^([\w]+)?\.([\w\-]+)$/
|
|
, splittable = /(^|,)\s*[>~+]/
|
|
, normalizr = /^\s+|\s*([,\s\+\~>]|$)\s*/g
|
|
, splitters = /[\s\>\+\~]/
|
|
, splittersMore = /(?![\s\w\-\/\?\&\=\:\.\(\)\!,@#%<>\{\}\$\*\^'"]*\]|[\s\w\+\-]*\))/
|
|
, specialChars = /([.*+?\^=!:${}()|\[\]\/\\])/g
|
|
, simple = /^(\*|[a-z0-9]+)?(?:([\.\#]+[\w\-\.#]+)?)/
|
|
, attr = /\[([\w\-]+)(?:([\|\^\$\*\~]?\=)['"]?([ \w\-\/\?\&\=\:\.\(\)\!,@#%<>\{\}\$\*\^]+)["']?)?\]/
|
|
, pseudo = /:([\w\-]+)(\(['"]?([^()]+)['"]?\))?/
|
|
, easy = new RegExp(idOnly.source + '|' + tagOnly.source + '|' + classOnly.source)
|
|
, dividers = new RegExp('(' + splitters.source + ')' + splittersMore.source, 'g')
|
|
, tokenizr = new RegExp(splitters.source + splittersMore.source)
|
|
, chunker = new RegExp(simple.source + '(' + attr.source + ')?' + '(' + pseudo.source + ')?')
|
|
|
|
var walker = {
|
|
' ': function (node) {
|
|
return node && node !== html && node.parentNode
|
|
}
|
|
, '>': function (node, contestant) {
|
|
return node && node.parentNode == contestant.parentNode && node.parentNode
|
|
}
|
|
, '~': function (node) {
|
|
return node && node.previousSibling
|
|
}
|
|
, '+': function (node, contestant, p1, p2) {
|
|
if (!node) return false
|
|
return (p1 = previous(node)) && (p2 = previous(contestant)) && p1 == p2 && p1
|
|
}
|
|
}
|
|
|
|
function cache() {
|
|
this.c = {}
|
|
}
|
|
cache.prototype = {
|
|
g: function (k) {
|
|
return this.c[k] || undefined
|
|
}
|
|
, s: function (k, v, r) {
|
|
v = r ? new RegExp(v) : v
|
|
return (this.c[k] = v)
|
|
}
|
|
}
|
|
|
|
var classCache = new cache()
|
|
, cleanCache = new cache()
|
|
, attrCache = new cache()
|
|
, tokenCache = new cache()
|
|
|
|
function classRegex(c) {
|
|
return classCache.g(c) || classCache.s(c, '(^|\\s+)' + c + '(\\s+|$)', 1)
|
|
}
|
|
|
|
// not quite as fast as inline loops in older browsers so don't use liberally
|
|
function each(a, fn) {
|
|
var i = 0, l = a.length
|
|
for (; i < l; i++) fn(a[i])
|
|
}
|
|
|
|
function flatten(ar) {
|
|
for (var r = [], i = 0, l = ar.length; i < l; ++i) arrayLike(ar[i]) ? (r = r.concat(ar[i])) : (r[r.length] = ar[i])
|
|
return r
|
|
}
|
|
|
|
function arrayify(ar) {
|
|
var i = 0, l = ar.length, r = []
|
|
for (; i < l; i++) r[i] = ar[i]
|
|
return r
|
|
}
|
|
|
|
function previous(n) {
|
|
while (n = n.previousSibling) if (n[nodeType] == 1) break;
|
|
return n
|
|
}
|
|
|
|
function q(query) {
|
|
return query.match(chunker)
|
|
}
|
|
|
|
// called using `this` as element and arguments from regex group results.
|
|
// given => div.hello[title="world"]:foo('bar')
|
|
// div.hello[title="world"]:foo('bar'), div, .hello, [title="world"], title, =, world, :foo('bar'), foo, ('bar'), bar]
|
|
function interpret(whole, tag, idsAndClasses, wholeAttribute, attribute, qualifier, value, wholePseudo, pseudo, wholePseudoVal, pseudoVal) {
|
|
var i, m, k, o, classes
|
|
if (this[nodeType] !== 1) return false
|
|
if (tag && tag !== '*' && this[tagName] && this[tagName].toLowerCase() !== tag) return false
|
|
if (idsAndClasses && (m = idsAndClasses.match(id)) && m[1] !== this.id) return false
|
|
if (idsAndClasses && (classes = idsAndClasses.match(clas))) {
|
|
for (i = classes.length; i--;) if (!classRegex(classes[i].slice(1)).test(this.className)) return false
|
|
}
|
|
if (pseudo && qwery.pseudos[pseudo] && !qwery.pseudos[pseudo](this, pseudoVal)) return false
|
|
if (wholeAttribute && !value) { // select is just for existance of attrib
|
|
o = this.attributes
|
|
for (k in o) {
|
|
if (Object.prototype.hasOwnProperty.call(o, k) && (o[k].name || k) == attribute) {
|
|
return this
|
|
}
|
|
}
|
|
}
|
|
if (wholeAttribute && !checkAttr(qualifier, getAttr(this, attribute) || '', value)) {
|
|
// select is for attrib equality
|
|
return false
|
|
}
|
|
return this
|
|
}
|
|
|
|
function clean(s) {
|
|
return cleanCache.g(s) || cleanCache.s(s, s.replace(specialChars, '\\$1'))
|
|
}
|
|
|
|
function checkAttr(qualify, actual, val) {
|
|
switch (qualify) {
|
|
case '=':
|
|
return actual == val
|
|
case '^=':
|
|
return actual.match(attrCache.g('^=' + val) || attrCache.s('^=' + val, '^' + clean(val), 1))
|
|
case '$=':
|
|
return actual.match(attrCache.g('$=' + val) || attrCache.s('$=' + val, clean(val) + '$', 1))
|
|
case '*=':
|
|
return actual.match(attrCache.g(val) || attrCache.s(val, clean(val), 1))
|
|
case '~=':
|
|
return actual.match(attrCache.g('~=' + val) || attrCache.s('~=' + val, '(?:^|\\s+)' + clean(val) + '(?:\\s+|$)', 1))
|
|
case '|=':
|
|
return actual.match(attrCache.g('|=' + val) || attrCache.s('|=' + val, '^' + clean(val) + '(-|$)', 1))
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// given a selector, first check for simple cases then collect all base candidate matches and filter
|
|
function _qwery(selector, _root) {
|
|
var r = [], ret = [], i, l, m, token, tag, els, intr, item, root = _root
|
|
, tokens = tokenCache.g(selector) || tokenCache.s(selector, selector.split(tokenizr))
|
|
, dividedTokens = selector.match(dividers)
|
|
|
|
if (!tokens.length) return r
|
|
|
|
token = (tokens = tokens.slice(0)).pop() // copy cached tokens, take the last one
|
|
if (tokens.length && (m = tokens[tokens.length - 1].match(idOnly))) root = byId(_root, m[1])
|
|
if (!root) return r
|
|
|
|
intr = q(token)
|
|
// collect base candidates to filter
|
|
els = root !== _root && root[nodeType] !== 9 && dividedTokens && /^[+~]$/.test(dividedTokens[dividedTokens.length - 1]) ?
|
|
function (r) {
|
|
while (root = root.nextSibling) {
|
|
root[nodeType] == 1 && (intr[1] ? intr[1] == root[tagName].toLowerCase() : 1) && (r[r.length] = root)
|
|
}
|
|
return r
|
|
}([]) :
|
|
root[byTag](intr[1] || '*')
|
|
// filter elements according to the right-most part of the selector
|
|
for (i = 0, l = els.length; i < l; i++) {
|
|
if (item = interpret.apply(els[i], intr)) r[r.length] = item
|
|
}
|
|
if (!tokens.length) return r
|
|
|
|
// filter further according to the rest of the selector (the left side)
|
|
each(r, function (e) { if (ancestorMatch(e, tokens, dividedTokens)) ret[ret.length] = e })
|
|
return ret
|
|
}
|
|
|
|
// compare element to a selector
|
|
function is(el, selector, root) {
|
|
if (isNode(selector)) return el == selector
|
|
if (arrayLike(selector)) return !!~flatten(selector).indexOf(el) // if selector is an array, is el a member?
|
|
|
|
var selectors = selector.split(','), tokens, dividedTokens
|
|
while (selector = selectors.pop()) {
|
|
tokens = tokenCache.g(selector) || tokenCache.s(selector, selector.split(tokenizr))
|
|
dividedTokens = selector.match(dividers)
|
|
tokens = tokens.slice(0) // copy array
|
|
if (interpret.apply(el, q(tokens.pop())) && (!tokens.length || ancestorMatch(el, tokens, dividedTokens, root))) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// given elements matching the right-most part of a selector, filter out any that don't match the rest
|
|
function ancestorMatch(el, tokens, dividedTokens, root) {
|
|
var cand
|
|
// recursively work backwards through the tokens and up the dom, covering all options
|
|
function crawl(e, i, p) {
|
|
while (p = walker[dividedTokens[i]](p, e)) {
|
|
if (isNode(p) && (interpret.apply(p, q(tokens[i])))) {
|
|
if (i) {
|
|
if (cand = crawl(p, i - 1, p)) return cand
|
|
} else return p
|
|
}
|
|
}
|
|
}
|
|
return (cand = crawl(el, tokens.length - 1, el)) && (!root || isAncestor(cand, root))
|
|
}
|
|
|
|
function isNode(el, t) {
|
|
return el && typeof el === 'object' && (t = el[nodeType]) && (t == 1 || t == 9)
|
|
}
|
|
|
|
function uniq(ar) {
|
|
var a = [], i, j;
|
|
o:
|
|
for (i = 0; i < ar.length; ++i) {
|
|
for (j = 0; j < a.length; ++j) if (a[j] == ar[i]) continue o
|
|
a[a.length] = ar[i]
|
|
}
|
|
return a
|
|
}
|
|
|
|
function arrayLike(o) {
|
|
return (typeof o === 'object' && isFinite(o.length))
|
|
}
|
|
|
|
function normalizeRoot(root) {
|
|
if (!root) return doc
|
|
if (typeof root == 'string') return qwery(root)[0]
|
|
if (!root[nodeType] && arrayLike(root)) return root[0]
|
|
return root
|
|
}
|
|
|
|
function byId(root, id, el) {
|
|
// if doc, query on it, else query the parent doc or if a detached fragment rewrite the query and run on the fragment
|
|
return root[nodeType] === 9 ? root.getElementById(id) :
|
|
root.ownerDocument &&
|
|
(((el = root.ownerDocument.getElementById(id)) && isAncestor(el, root) && el) ||
|
|
(!isAncestor(root, root.ownerDocument) && select('[id="' + id + '"]', root)[0]))
|
|
}
|
|
|
|
function qwery(selector, _root) {
|
|
var m, el, root = normalizeRoot(_root)
|
|
|
|
// easy, fast cases that we can dispatch with simple DOM calls
|
|
if (!root || !selector) return []
|
|
if (selector === window || isNode(selector)) {
|
|
return !_root || (selector !== window && isNode(root) && isAncestor(selector, root)) ? [selector] : []
|
|
}
|
|
if (selector && arrayLike(selector)) return flatten(selector)
|
|
if (m = selector.match(easy)) {
|
|
if (m[1]) return (el = byId(root, m[1])) ? [el] : []
|
|
if (m[2]) return arrayify(root[byTag](m[2]))
|
|
if (hasByClass && m[3]) return arrayify(root[byClass](m[3]))
|
|
}
|
|
|
|
return select(selector, root)
|
|
}
|
|
|
|
// where the root is not document and a relationship selector is first we have to
|
|
// do some awkward adjustments to get it to work, even with qSA
|
|
function collectSelector(root, collector) {
|
|
return function (s) {
|
|
var oid, nid
|
|
if (splittable.test(s)) {
|
|
if (root[nodeType] !== 9) {
|
|
// make sure the el has an id, rewrite the query, set root to doc and run it
|
|
if (!(nid = oid = root.getAttribute('id'))) root.setAttribute('id', nid = '__qwerymeupscotty')
|
|
s = '[id="' + nid + '"]' + s // avoid byId and allow us to match context element
|
|
collector(root.parentNode || root, s, true)
|
|
oid || root.removeAttribute('id')
|
|
}
|
|
return;
|
|
}
|
|
s.length && collector(root, s, false)
|
|
}
|
|
}
|
|
|
|
var isAncestor = 'compareDocumentPosition' in html ?
|
|
function (element, container) {
|
|
return (container.compareDocumentPosition(element) & 16) == 16
|
|
} : 'contains' in html ?
|
|
function (element, container) {
|
|
container = container[nodeType] === 9 || container == window ? html : container
|
|
return container !== element && container.contains(element)
|
|
} :
|
|
function (element, container) {
|
|
while (element = element.parentNode) if (element === container) return 1
|
|
return 0
|
|
}
|
|
, getAttr = function () {
|
|
// detect buggy IE src/href getAttribute() call
|
|
var e = doc.createElement('p')
|
|
return ((e.innerHTML = '<a href="#x">x</a>') && e.firstChild.getAttribute('href') != '#x') ?
|
|
function (e, a) {
|
|
return a === 'class' ? e.className : (a === 'href' || a === 'src') ?
|
|
e.getAttribute(a, 2) : e.getAttribute(a)
|
|
} :
|
|
function (e, a) { return e.getAttribute(a) }
|
|
}()
|
|
, hasByClass = !!doc[byClass]
|
|
// has native qSA support
|
|
, hasQSA = doc.querySelector && doc[qSA]
|
|
// use native qSA
|
|
, selectQSA = function (selector, root) {
|
|
var result = [], ss, e
|
|
try {
|
|
if (root[nodeType] === 9 || !splittable.test(selector)) {
|
|
// most work is done right here, defer to qSA
|
|
return arrayify(root[qSA](selector))
|
|
}
|
|
// special case where we need the services of `collectSelector()`
|
|
each(ss = selector.split(','), collectSelector(root, function (ctx, s) {
|
|
e = ctx[qSA](s)
|
|
if (e.length == 1) result[result.length] = e.item(0)
|
|
else if (e.length) result = result.concat(arrayify(e))
|
|
}))
|
|
return ss.length > 1 && result.length > 1 ? uniq(result) : result
|
|
} catch (ex) { }
|
|
return selectNonNative(selector, root)
|
|
}
|
|
// no native selector support
|
|
, selectNonNative = function (selector, root) {
|
|
var result = [], items, m, i, l, r, ss
|
|
selector = selector.replace(normalizr, '$1')
|
|
if (m = selector.match(tagAndOrClass)) {
|
|
r = classRegex(m[2])
|
|
items = root[byTag](m[1] || '*')
|
|
for (i = 0, l = items.length; i < l; i++) {
|
|
if (r.test(items[i].className)) result[result.length] = items[i]
|
|
}
|
|
return result
|
|
}
|
|
// more complex selector, get `_qwery()` to do the work for us
|
|
each(ss = selector.split(','), collectSelector(root, function (ctx, s, rewrite) {
|
|
r = _qwery(s, ctx)
|
|
for (i = 0, l = r.length; i < l; i++) {
|
|
if (ctx[nodeType] === 9 || rewrite || isAncestor(r[i], root)) result[result.length] = r[i]
|
|
}
|
|
}))
|
|
return ss.length > 1 && result.length > 1 ? uniq(result) : result
|
|
}
|
|
, configure = function (options) {
|
|
// configNativeQSA: use fully-internal selector or native qSA where present
|
|
if (typeof options[useNativeQSA] !== 'undefined')
|
|
select = !options[useNativeQSA] ? selectNonNative : hasQSA ? selectQSA : selectNonNative
|
|
}
|
|
|
|
configure({ useNativeQSA: true })
|
|
|
|
qwery.configure = configure
|
|
qwery.uniq = uniq
|
|
qwery.is = is
|
|
qwery.pseudos = {}
|
|
|
|
return qwery
|
|
});
|
|
|
|
|
|
provide("qwery", module.exports);
|
|
|
|
(function ($) {
|
|
var q = function () {
|
|
var r
|
|
try {
|
|
r = require('qwery')
|
|
} catch (ex) {
|
|
r = require('qwery-mobile')
|
|
} finally {
|
|
return r
|
|
}
|
|
}()
|
|
|
|
$.pseudos = q.pseudos
|
|
|
|
$._select = function (s, r) {
|
|
// detect if sibling module 'bonzo' is available at run-time
|
|
// rather than load-time since technically it's not a dependency and
|
|
// can be loaded in any order
|
|
// hence the lazy function re-definition
|
|
return ($._select = (function () {
|
|
var b
|
|
if (typeof $.create == 'function') return function (s, r) {
|
|
return /^\s*</.test(s) ? $.create(s, r) : q(s, r)
|
|
}
|
|
try {
|
|
b = require('bonzo')
|
|
return function (s, r) {
|
|
return /^\s*</.test(s) ? b.create(s, r) : q(s, r)
|
|
}
|
|
} catch (e) { }
|
|
return q
|
|
})())(s, r)
|
|
}
|
|
|
|
$.ender({
|
|
find: function (s) {
|
|
var r = [], i, l, j, k, els
|
|
for (i = 0, l = this.length; i < l; i++) {
|
|
els = q(s, this[i])
|
|
for (j = 0, k = els.length; j < k; j++) r.push(els[j])
|
|
}
|
|
return $(q.uniq(r))
|
|
}
|
|
, and: function (s) {
|
|
var plus = $(s)
|
|
for (var i = this.length, j = 0, l = this.length + plus.length; i < l; i++, j++) {
|
|
this[i] = plus[j]
|
|
}
|
|
this.length += plus.length
|
|
return this
|
|
}
|
|
, is: function(s, r) {
|
|
var i, l
|
|
for (i = 0, l = this.length; i < l; i++) {
|
|
if (q.is(this[i], s, r)) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
}, true)
|
|
}(ender));
|
|
|
|
|
|
}());
|
|
|
|
|