vendor/assets/javascripts/zepto.js in h2ocube_rails_assets-0.0.11 vs vendor/assets/javascripts/zepto.js in h2ocube_rails_assets-0.0.12

- old
+ new

@@ -1,9 +1,11 @@ -/* Zepto v1.0rc1 - polyfill zepto event detect fx ajax form touch - zeptojs.com/license */ +/* Zepto v1.0-1-ga3cab6c - polyfill zepto detect event ajax form fx - zeptojs.com/license */ + + ;(function(undefined){ if (String.prototype.trim === undefined) // fix for iOS 3.2 - String.prototype.trim = function(){ return this.replace(/^\s+/, '').replace(/\s+$/, '') } + String.prototype.trim = function(){ return this.replace(/^\s+|\s+$/g, '') } // For iOS 3.x // from https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/reduce if (Array.prototype.reduce === undefined) Array.prototype.reduce = function(fun){ @@ -29,21 +31,23 @@ } return accumulator } })() + var Zepto = (function() { - var undefined, key, $, classList, emptyArray = [], slice = emptyArray.slice, + var undefined, key, $, classList, emptyArray = [], slice = emptyArray.slice, filter = emptyArray.filter, document = window.document, elementDisplay = {}, classCache = {}, getComputedStyle = document.defaultView.getComputedStyle, cssNumber = { 'column-count': 1, 'columns': 1, 'font-weight': 1, 'line-height': 1,'opacity': 1, 'z-index': 1, 'zoom': 1 }, fragmentRE = /^\s*<(\w+|!)[^>]*>/, + tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rootNodeRE = /^(?:body|html)$/i, - // Used by `$.zepto.init` to wrap elements, text/comment nodes, document, - // and document fragment node types. - elementTypes = [1, 3, 8, 9, 11], + // special attributes that should be get/set via method calls + methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'], adjacencyOperators = [ 'after', 'prepend', 'before', 'append' ], table = document.createElement('table'), tableRow = document.createElement('tr'), containers = { @@ -52,13 +56,14 @@ 'td': tableRow, 'th': tableRow, '*': document.createElement('div') }, readyRE = /complete|loaded|interactive/, classSelectorRE = /^\.([\w-]+)$/, - idSelectorRE = /^#([\w-]+)$/, + idSelectorRE = /^#([\w-]*)$/, tagSelectorRE = /^[\w-]+$/, - toString = ({}).toString, + class2type = {}, + toString = class2type.toString, zepto = {}, camelize, uniq, tempParent = document.createElement('div') zepto.matches = function(element, selector) { @@ -72,34 +77,36 @@ match = ~zepto.qsa(parent, selector).indexOf(element) temp && tempParent.removeChild(element) return match } - function isFunction(value) { return toString.call(value) == "[object Function]" } - function isObject(value) { return value instanceof Object } - function isPlainObject(value) { - var key, ctor - if (toString.call(value) !== "[object Object]") return false - ctor = (isFunction(value.constructor) && value.constructor.prototype) - if (!ctor || !hasOwnProperty.call(ctor, 'isPrototypeOf')) return false - for (key in value); - return key === undefined || hasOwnProperty.call(value, key) + function type(obj) { + return obj == null ? String(obj) : + class2type[toString.call(obj)] || "object" } + + function isFunction(value) { return type(value) == "function" } + function isWindow(obj) { return obj != null && obj == obj.window } + function isDocument(obj) { return obj != null && obj.nodeType == obj.DOCUMENT_NODE } + function isObject(obj) { return type(obj) == "object" } + function isPlainObject(obj) { + return isObject(obj) && !isWindow(obj) && obj.__proto__ == Object.prototype + } function isArray(value) { return value instanceof Array } function likeArray(obj) { return typeof obj.length == 'number' } - function compact(array) { return array.filter(function(item){ return item !== undefined && item !== null }) } - function flatten(array) { return array.length > 0 ? [].concat.apply([], array) : array } + function compact(array) { return filter.call(array, function(item){ return item != null }) } + function flatten(array) { return array.length > 0 ? $.fn.concat.apply([], array) : array } camelize = function(str){ return str.replace(/-+(.)?/g, function(match, chr){ return chr ? chr.toUpperCase() : '' }) } function dasherize(str) { return str.replace(/::/g, '/') .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') .replace(/([a-z\d])([A-Z])/g, '$1_$2') .replace(/_/g, '-') .toLowerCase() } - uniq = function(array){ return array.filter(function(item, idx){ return array.indexOf(item) == idx }) } + uniq = function(array){ return filter.call(array, function(item, idx){ return array.indexOf(item) == idx }) } function classRE(name) { return name in classCache ? classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)')) } @@ -119,32 +126,48 @@ elementDisplay[nodeName] = display } return elementDisplay[nodeName] } + function children(element) { + return 'children' in element ? + slice.call(element.children) : + $.map(element.childNodes, function(node){ if (node.nodeType == 1) return node }) + } + // `$.zepto.fragment` takes a html string and an optional tag name // to generate DOM nodes nodes from the given html string. // The generated DOM nodes are returned as an array. // This function can be overriden in plugins for example to make // it compatible with browsers that don't support the DOM fully. - zepto.fragment = function(html, name) { + zepto.fragment = function(html, name, properties) { + if (html.replace) html = html.replace(tagExpanderRE, "<$1></$2>") if (name === undefined) name = fragmentRE.test(html) && RegExp.$1 if (!(name in containers)) name = '*' - var container = containers[name] + + var nodes, dom, container = containers[name] container.innerHTML = '' + html - return $.each(slice.call(container.childNodes), function(){ + dom = $.each(slice.call(container.childNodes), function(){ container.removeChild(this) }) + if (isPlainObject(properties)) { + nodes = $(dom) + $.each(properties, function(key, value) { + if (methodAttributes.indexOf(key) > -1) nodes[key](value) + else nodes.attr(key, value) + }) + } + return dom } // `$.zepto.Z` swaps out the prototype of the given `dom` array // of nodes with `$.fn` and thus supplying all the Zepto functions // to the array. Note that `__proto__` is not supported on Internet // Explorer. This method can be overriden in plugins. zepto.Z = function(dom, selector) { dom = dom || [] - dom.__proto__ = arguments.callee.prototype + dom.__proto__ = $.fn dom.selector = selector || '' return dom } // `$.zepto.isZ` should return `true` if the given object is a Zepto @@ -166,21 +189,16 @@ else if (zepto.isZ(selector)) return selector else { var dom // normalize array if an array of nodes is given if (isArray(selector)) dom = compact(selector) - // if a JavaScript object is given, return a copy of it - // this is a somewhat peculiar option, but supported by - // jQuery so we'll do it, too - else if (isPlainObject(selector)) - dom = [$.extend({}, selector)], selector = null - // wrap stuff like `document` or `window` - else if (elementTypes.indexOf(selector.nodeType) >= 0 || selector === window) - dom = [selector], selector = null + // Wrap DOM nodes. If a plain object is given, duplicate it. + else if (isObject(selector)) + dom = [isPlainObject(selector) ? $.extend({}, selector) : selector], selector = null // If it's a html fragment, create nodes from it else if (fragmentRE.test(selector)) - dom = zepto.fragment(selector.trim(), RegExp.$1), selector = null + dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null // If there's a context, create a collection on that context first, and select // nodes from there else if (context !== undefined) return $(context).find(selector) // And last but no least, if it's a CSS selector, use it to select nodes. else dom = zepto.qsa(document, selector) @@ -188,36 +206,49 @@ return zepto.Z(dom, selector) } } // `$` will be the base `Zepto` object. When calling this - // function just call `$.zepto.init, whichs makes the implementation + // function just call `$.zepto.init, which makes the implementation // details of selecting nodes and creating Zepto collections // patchable in plugins. $ = function(selector, context){ return zepto.init(selector, context) } + function extend(target, source, deep) { + for (key in source) + if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { + if (isPlainObject(source[key]) && !isPlainObject(target[key])) + target[key] = {} + if (isArray(source[key]) && !isArray(target[key])) + target[key] = [] + extend(target[key], source[key], deep) + } + else if (source[key] !== undefined) target[key] = source[key] + } + // Copy all but undefined properties from one or more // objects to the `target` object. $.extend = function(target){ - slice.call(arguments, 1).forEach(function(source) { - for (key in source) - if (source[key] !== undefined) - target[key] = source[key] - }) + var deep, args = slice.call(arguments, 1) + if (typeof target == 'boolean') { + deep = target + target = args.shift() + } + args.forEach(function(arg){ extend(target, arg, deep) }) return target } // `$.zepto.qsa` is Zepto's CSS selector implementation which // uses `document.querySelectorAll` and optimizes for some special cases, like `#id`. // This method can be overriden in plugins. zepto.qsa = function(element, selector){ var found - return (element === document && idSelectorRE.test(selector)) ? - ( (found = element.getElementById(RegExp.$1)) ? [found] : emptyArray ) : - (element.nodeType !== 1 && element.nodeType !== 9) ? emptyArray : + return (isDocument(element) && idSelectorRE.test(selector)) ? + ( (found = element.getElementById(RegExp.$1)) ? [found] : [] ) : + (element.nodeType !== 1 && element.nodeType !== 9) ? [] : slice.call( classSelectorRE.test(selector) ? element.getElementsByClassName(RegExp.$1) : tagSelectorRE.test(selector) ? element.getElementsByTagName(selector) : element.querySelectorAll(selector) ) @@ -225,27 +256,77 @@ function filtered(nodes, selector) { return selector === undefined ? $(nodes) : $(nodes).filter(selector) } + $.contains = function(parent, node) { + return parent !== node && parent.contains(node) + } + function funcArg(context, arg, idx, payload) { - return isFunction(arg) ? arg.call(context, idx, payload) : arg + return isFunction(arg) ? arg.call(context, idx, payload) : arg } + function setAttribute(node, name, value) { + value == null ? node.removeAttribute(name) : node.setAttribute(name, value) + } + + // access className property while respecting SVGAnimatedString + function className(node, value){ + var klass = node.className, + svg = klass && klass.baseVal !== undefined + + if (value === undefined) return svg ? klass.baseVal : klass + svg ? (klass.baseVal = value) : (node.className = value) + } + + // "true" => true + // "false" => false + // "null" => null + // "42" => 42 + // "42.5" => 42.5 + // JSON => parse if valid + // String => self + function deserializeValue(value) { + var num + try { + return value ? + value == "true" || + ( value == "false" ? false : + value == "null" ? null : + !isNaN(num = Number(value)) ? num : + /^[\[\{]/.test(value) ? $.parseJSON(value) : + value ) + : value + } catch(e) { + return value + } + } + + $.type = type $.isFunction = isFunction - $.isObject = isObject + $.isWindow = isWindow $.isArray = isArray $.isPlainObject = isPlainObject + $.isEmptyObject = function(obj) { + var name + for (name in obj) return false + return true + } + $.inArray = function(elem, array, i){ return emptyArray.indexOf.call(array, elem, i) } + $.camelCase = camelize $.trim = function(str) { return str.trim() } // plugin compatibility $.uuid = 0 + $.support = { } + $.expr = { } $.map = function(elements, callback){ var value, values = [], i, key if (likeArray(elements)) for (i = 0; i < elements.length; i++) { @@ -271,25 +352,37 @@ } return elements } + $.grep = function(elements, callback){ + return filter.call(elements, callback) + } + + if (window.JSON) $.parseJSON = JSON.parse + + // Populate the class2type map + $.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase() + }) + // Define methods that will be available on all // Zepto collections $.fn = { // Because a collection acts like an array // copy over these useful array functions. forEach: emptyArray.forEach, reduce: emptyArray.reduce, push: emptyArray.push, + sort: emptyArray.sort, indexOf: emptyArray.indexOf, concat: emptyArray.concat, // `map` and `slice` in the jQuery API work differently // from their array counterparts map: function(fn){ - return $.map(this, function(el, i){ return fn.call(el, i, el) }) + return $($.map(this, function(el, i){ return fn.call(el, i, el) })) }, slice: function(){ return $(slice.apply(this, arguments)) }, @@ -297,11 +390,11 @@ if (readyRE.test(document.readyState)) callback($) else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false) return this }, get: function(idx){ - return idx === undefined ? slice.call(this) : this[idx] + return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length] }, toArray: function(){ return this.get() }, size: function(){ return this.length }, @@ -310,15 +403,18 @@ if (this.parentNode != null) this.parentNode.removeChild(this) }) }, each: function(callback){ - this.forEach(function(el, idx){ callback.call(el, idx, el) }) + emptyArray.every.call(this, function(el, idx){ + return callback.call(el, idx, el) !== false + }) return this }, filter: function(selector){ - return $([].filter.call(this, function(element){ + if (isFunction(selector)) return this.not(this.not(selector)) + return $(filter.call(this, function(element){ return zepto.matches(element, selector) })) }, add: function(selector,context){ return $(uniq(this.concat($(selector,context)))) @@ -339,10 +435,17 @@ if (excludes.indexOf(el) < 0) nodes.push(el) }) } return $(nodes) }, + has: function(selector){ + return this.filter(function(){ + return isObject(selector) ? + $.contains(this, selector) : + $(this).find(selector).size() + }) + }, eq: function(idx){ return idx === -1 ? this.slice(idx) : this.slice(idx, + idx + 1) }, first: function(){ var el = this[0] @@ -351,49 +454,60 @@ last: function(){ var el = this[this.length - 1] return el && !isObject(el) ? el : $(el) }, find: function(selector){ - var result - if (this.length == 1) result = zepto.qsa(this[0], selector) + var result, $this = this + if (typeof selector == 'object') + result = $(selector).filter(function(){ + var node = this + return emptyArray.some.call($this, function(parent){ + return $.contains(parent, node) + }) + }) + else if (this.length == 1) result = $(zepto.qsa(this[0], selector)) else result = this.map(function(){ return zepto.qsa(this, selector) }) - return $(result) + return result }, closest: function(selector, context){ - var node = this[0] - while (node && !zepto.matches(node, selector)) - node = node !== context && node !== document && node.parentNode + var node = this[0], collection = false + if (typeof selector == 'object') collection = $(selector) + while (node && !(collection ? collection.indexOf(node) >= 0 : zepto.matches(node, selector))) + node = node !== context && !isDocument(node) && node.parentNode return $(node) }, parents: function(selector){ var ancestors = [], nodes = this while (nodes.length > 0) nodes = $.map(nodes, function(node){ - if ((node = node.parentNode) && node !== document && ancestors.indexOf(node) < 0) { + if ((node = node.parentNode) && !isDocument(node) && ancestors.indexOf(node) < 0) { ancestors.push(node) return node } }) return filtered(ancestors, selector) }, parent: function(selector){ return filtered(uniq(this.pluck('parentNode')), selector) }, children: function(selector){ - return filtered(this.map(function(){ return slice.call(this.children) }), selector) + return filtered(this.map(function(){ return children(this) }), selector) }, + contents: function() { + return this.map(function() { return slice.call(this.childNodes) }) + }, siblings: function(selector){ return filtered(this.map(function(i, el){ - return slice.call(el.parentNode.children).filter(function(child){ return child!==el }) + return filter.call(children(el.parentNode), function(child){ return child!==el }) }), selector) }, empty: function(){ return this.each(function(){ this.innerHTML = '' }) }, // `pluck` is borrowed from Prototype.js pluck: function(property){ - return this.map(function(){ return this[property] }) + return $.map(this, function(el){ return el[property] }) }, show: function(){ return this.each(function(){ this.style.display == "none" && (this.style.display = null) if (getComputedStyle(this, '').getPropertyValue("display") == "none") @@ -401,39 +515,61 @@ }) }, replaceWith: function(newContent){ return this.before(newContent).remove() }, - wrap: function(newContent){ - return this.each(function(){ - $(this).wrapAll($(newContent)[0].cloneNode(false)) + wrap: function(structure){ + var func = isFunction(structure) + if (this[0] && !func) + var dom = $(structure).get(0), + clone = dom.parentNode || this.length > 1 + + return this.each(function(index){ + $(this).wrapAll( + func ? structure.call(this, index) : + clone ? dom.cloneNode(true) : dom + ) }) }, - wrapAll: function(newContent){ + wrapAll: function(structure){ if (this[0]) { - $(this[0]).before(newContent = $(newContent)) - newContent.append(this) + $(this[0]).before(structure = $(structure)) + var children + // drill down to the inmost element + while ((children = structure.children()).length) structure = children.first() + $(structure).append(this) } return this }, + wrapInner: function(structure){ + var func = isFunction(structure) + return this.each(function(index){ + var self = $(this), contents = self.contents(), + dom = func ? structure.call(this, index) : structure + contents.length ? contents.wrapAll(dom) : self.append(dom) + }) + }, unwrap: function(){ this.parent().each(function(){ $(this).replaceWith($(this).children()) }) return this }, clone: function(){ - return $(this.map(function(){ return this.cloneNode(true) })) + return this.map(function(){ return this.cloneNode(true) }) }, hide: function(){ return this.css("display", "none") }, toggle: function(setting){ - return (setting === undefined ? this.css("display") == "none" : setting) ? this.show() : this.hide() + return this.each(function(){ + var el = $(this) + ;(setting === undefined ? el.css("display") == "none" : setting) ? el.show() : el.hide() + }) }, - prev: function(){ return $(this.pluck('previousElementSibling')) }, - next: function(){ return $(this.pluck('nextElementSibling')) }, + prev: function(selector){ return $(this.pluck('previousElementSibling')).filter(selector || '*') }, + next: function(selector){ return $(this.pluck('nextElementSibling')).filter(selector || '*') }, html: function(html){ return html === undefined ? (this.length > 0 ? this[0].innerHTML : null) : this.each(function(idx){ var originHtml = this.innerHTML @@ -452,177 +588,296 @@ (name == 'value' && this[0].nodeName == 'INPUT') ? this.val() : (!(result = this[0].getAttribute(name)) && name in this[0]) ? this[0][name] : result ) : this.each(function(idx){ if (this.nodeType !== 1) return - if (isObject(name)) for (key in name) this.setAttribute(key, name[key]) - else this.setAttribute(name, funcArg(this, value, idx, this.getAttribute(name))) + if (isObject(name)) for (key in name) setAttribute(this, key, name[key]) + else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name))) }) }, removeAttr: function(name){ - return this.each(function(){ if (this.nodeType === 1) this.removeAttribute(name) }) + return this.each(function(){ this.nodeType === 1 && setAttribute(this, name) }) }, prop: function(name, value){ return (value === undefined) ? - (this[0] ? this[0][name] : undefined) : + (this[0] && this[0][name]) : this.each(function(idx){ this[name] = funcArg(this, value, idx, this[name]) }) }, data: function(name, value){ var data = this.attr('data-' + dasherize(name), value) - return data !== null ? data : undefined + return data !== null ? deserializeValue(data) : undefined }, val: function(value){ return (value === undefined) ? - (this.length > 0 ? this[0].value : undefined) : + (this[0] && (this[0].multiple ? + $(this[0]).find('option').filter(function(o){ return this.selected }).pluck('value') : + this[0].value) + ) : this.each(function(idx){ this.value = funcArg(this, value, idx, this.value) }) }, - offset: function(){ + offset: function(coordinates){ + if (coordinates) return this.each(function(index){ + var $this = $(this), + coords = funcArg(this, coordinates, index, $this.offset()), + parentOffset = $this.offsetParent().offset(), + props = { + top: coords.top - parentOffset.top, + left: coords.left - parentOffset.left + } + + if ($this.css('position') == 'static') props['position'] = 'relative' + $this.css(props) + }) if (this.length==0) return null var obj = this[0].getBoundingClientRect() return { left: obj.left + window.pageXOffset, top: obj.top + window.pageYOffset, - width: obj.width, - height: obj.height + width: Math.round(obj.width), + height: Math.round(obj.height) } }, css: function(property, value){ - if (value === undefined && typeof property == 'string') - return ( - this.length == 0 - ? undefined - : this[0].style[camelize(property)] || getComputedStyle(this[0], '').getPropertyValue(property)) + if (arguments.length < 2 && typeof property == 'string') + return this[0] && (this[0].style[camelize(property)] || getComputedStyle(this[0], '').getPropertyValue(property)) var css = '' - for (key in property) - if(typeof property[key] == 'string' && property[key] == '') - this.each(function(){ this.style.removeProperty(dasherize(key)) }) - else - css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';' - - if (typeof property == 'string') - if (value == '') + if (type(property) == 'string') { + if (!value && value !== 0) this.each(function(){ this.style.removeProperty(dasherize(property)) }) else css = dasherize(property) + ":" + maybeAddPx(property, value) + } else { + for (key in property) + if (!property[key] && property[key] !== 0) + this.each(function(){ this.style.removeProperty(dasherize(key)) }) + else + css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';' + } return this.each(function(){ this.style.cssText += ';' + css }) }, index: function(element){ return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0]) }, hasClass: function(name){ - if (this.length < 1) return false - else return classRE(name).test(this[0].className) + return emptyArray.some.call(this, function(el){ + return this.test(className(el)) + }, classRE(name)) }, addClass: function(name){ return this.each(function(idx){ classList = [] - var cls = this.className, newName = funcArg(this, name, idx, cls) + var cls = className(this), newName = funcArg(this, name, idx, cls) newName.split(/\s+/g).forEach(function(klass){ if (!$(this).hasClass(klass)) classList.push(klass) }, this) - classList.length && (this.className += (cls ? " " : "") + classList.join(" ")) + classList.length && className(this, cls + (cls ? " " : "") + classList.join(" ")) }) }, removeClass: function(name){ return this.each(function(idx){ - if (name === undefined) - return this.className = '' - classList = this.className + if (name === undefined) return className(this, '') + classList = className(this) funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass){ classList = classList.replace(classRE(klass), " ") }) - this.className = classList.trim() + className(this, classList.trim()) }) }, toggleClass: function(name, when){ return this.each(function(idx){ - var newName = funcArg(this, name, idx, this.className) - ;(when === undefined ? !$(this).hasClass(newName) : when) ? - $(this).addClass(newName) : $(this).removeClass(newName) + var $this = $(this), names = funcArg(this, name, idx, className(this)) + names.split(/\s+/g).forEach(function(klass){ + (when === undefined ? !$this.hasClass(klass) : when) ? + $this.addClass(klass) : $this.removeClass(klass) + }) }) + }, + scrollTop: function(){ + if (!this.length) return + return ('scrollTop' in this[0]) ? this[0].scrollTop : this[0].scrollY + }, + position: function() { + if (!this.length) return + + var elem = this[0], + // Get *real* offsetParent + offsetParent = this.offsetParent(), + // Get correct offsets + offset = this.offset(), + parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset() + + // Subtract element margins + // note: when an element has margin: auto the offsetLeft and marginLeft + // are the same in Safari causing offset.left to incorrectly be 0 + offset.top -= parseFloat( $(elem).css('margin-top') ) || 0 + offset.left -= parseFloat( $(elem).css('margin-left') ) || 0 + + // Add offsetParent borders + parentOffset.top += parseFloat( $(offsetParent[0]).css('border-top-width') ) || 0 + parentOffset.left += parseFloat( $(offsetParent[0]).css('border-left-width') ) || 0 + + // Subtract the two offsets + return { + top: offset.top - parentOffset.top, + left: offset.left - parentOffset.left + } + }, + offsetParent: function() { + return this.map(function(){ + var parent = this.offsetParent || document.body + while (parent && !rootNodeRE.test(parent.nodeName) && $(parent).css("position") == "static") + parent = parent.offsetParent + return parent + }) } } + // for now + $.fn.detach = $.fn.remove + // Generate the `width` and `height` functions ;['width', 'height'].forEach(function(dimension){ $.fn[dimension] = function(value){ - var offset, Dimension = dimension.replace(/./, function(m){ return m[0].toUpperCase() }) - if (value === undefined) return this[0] == window ? window['inner' + Dimension] : - this[0] == document ? document.documentElement['offset' + Dimension] : + var offset, el = this[0], + Dimension = dimension.replace(/./, function(m){ return m[0].toUpperCase() }) + if (value === undefined) return isWindow(el) ? el['inner' + Dimension] : + isDocument(el) ? el.documentElement['offset' + Dimension] : (offset = this.offset()) && offset[dimension] else return this.each(function(idx){ - var el = $(this) + el = $(this) el.css(dimension, funcArg(this, value, idx, el[dimension]())) }) } }) - function insert(operator, target, node) { - var parent = (operator % 2) ? target : target.parentNode - parent ? parent.insertBefore(node, - !operator ? target.nextSibling : // after - operator == 1 ? parent.firstChild : // prepend - operator == 2 ? target : // before - null) : // append - $(node).remove() - } - function traverseNode(node, fun) { fun(node) for (var key in node.childNodes) traverseNode(node.childNodes[key], fun) } // Generate the `after`, `prepend`, `before`, `append`, // `insertAfter`, `insertBefore`, `appendTo`, and `prependTo` methods. - adjacencyOperators.forEach(function(key, operator) { - $.fn[key] = function(){ + adjacencyOperators.forEach(function(operator, operatorIndex) { + var inside = operatorIndex % 2 //=> prepend, append + + $.fn[operator] = function(){ // arguments can be nodes, arrays of nodes, Zepto objects and HTML strings - var nodes = $.map(arguments, function(n){ return isObject(n) ? n : zepto.fragment(n) }) + var argType, nodes = $.map(arguments, function(arg) { + argType = type(arg) + return argType == "object" || argType == "array" || arg == null ? + arg : zepto.fragment(arg) + }), + parent, copyByClone = this.length > 1 if (nodes.length < 1) return this - var size = this.length, copyByClone = size > 1, inReverse = operator < 2 - return this.each(function(index, target){ - for (var i = 0; i < nodes.length; i++) { - var node = nodes[inReverse ? nodes.length-i-1 : i] - traverseNode(node, function(node){ - if (node.nodeName != null && node.nodeName.toUpperCase() === 'SCRIPT' && (!node.type || node.type === 'text/javascript')) - window['eval'].call(window, node.innerHTML) + return this.each(function(_, target){ + parent = inside ? target : target.parentNode + + // convert all methods to a "before" operation + target = operatorIndex == 0 ? target.nextSibling : + operatorIndex == 1 ? target.firstChild : + operatorIndex == 2 ? target : + null + + nodes.forEach(function(node){ + if (copyByClone) node = node.cloneNode(true) + else if (!parent) return $(node).remove() + + traverseNode(parent.insertBefore(node, target), function(el){ + if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' && + (!el.type || el.type === 'text/javascript') && !el.src) + window['eval'].call(window, el.innerHTML) }) - if (copyByClone && index < size - 1) node = node.cloneNode(true) - insert(operator, target, node) - } + }) }) } - $.fn[(operator % 2) ? key+'To' : 'insert'+(operator ? 'Before' : 'After')] = function(html){ - $(html)[key](this) + // after => insertAfter + // prepend => prependTo + // before => insertBefore + // append => appendTo + $.fn[inside ? operator+'To' : 'insert'+(operatorIndex ? 'Before' : 'After')] = function(html){ + $(html)[operator](this) return this } }) zepto.Z.prototype = $.fn // Export internal API functions in the `$.zepto` namespace - zepto.camelize = camelize zepto.uniq = uniq + zepto.deserializeValue = deserializeValue $.zepto = zepto return $ })() -// If `$` is not yet defined, point it to `Zepto` window.Zepto = Zepto '$' in window || (window.$ = Zepto) + ;(function($){ - var $$ = $.zepto.qsa, handlers = {}, _zid = 1, specialEvents={} + function detect(ua){ + var os = this.os = {}, browser = this.browser = {}, + webkit = ua.match(/WebKit\/([\d.]+)/), + android = ua.match(/(Android)\s+([\d.]+)/), + ipad = ua.match(/(iPad).*OS\s([\d_]+)/), + iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/), + webos = ua.match(/(webOS|hpwOS)[\s\/]([\d.]+)/), + touchpad = webos && ua.match(/TouchPad/), + kindle = ua.match(/Kindle\/([\d.]+)/), + silk = ua.match(/Silk\/([\d._]+)/), + blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/), + bb10 = ua.match(/(BB10).*Version\/([\d.]+)/), + rimtabletos = ua.match(/(RIM\sTablet\sOS)\s([\d.]+)/), + playbook = ua.match(/PlayBook/), + chrome = ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/), + firefox = ua.match(/Firefox\/([\d.]+)/) + // Todo: clean this up with a better OS/browser seperation: + // - discern (more) between multiple browsers on android + // - decide if kindle fire in silk mode is android or not + // - Firefox on Android doesn't specify the Android version + // - possibly devide in os, device and browser hashes + + if (browser.webkit = !!webkit) browser.version = webkit[1] + + if (android) os.android = true, os.version = android[2] + if (iphone) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.') + if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.') + if (webos) os.webos = true, os.version = webos[2] + if (touchpad) os.touchpad = true + if (blackberry) os.blackberry = true, os.version = blackberry[2] + if (bb10) os.bb10 = true, os.version = bb10[2] + if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2] + if (playbook) browser.playbook = true + if (kindle) os.kindle = true, os.version = kindle[1] + if (silk) browser.silk = true, browser.version = silk[1] + if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true + if (chrome) browser.chrome = true, browser.version = chrome[1] + if (firefox) browser.firefox = true, browser.version = firefox[1] + + os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) || (firefox && ua.match(/Tablet/))) + os.phone = !!(!os.tablet && (android || iphone || webos || blackberry || bb10 || + (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\/([\d.]+)/)) || (firefox && ua.match(/Mobile/)))) + } + + detect.call($, navigator.userAgent) + // make available to unit tests + $.__detect = detect + +})(Zepto) + +;(function($){ + var $$ = $.zepto.qsa, handlers = {}, _zid = 1, specialEvents={}, + hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' } + specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents' function zid(element) { return element._zid || (element._zid = _zid++) } @@ -644,36 +899,54 @@ function matcherFor(ns) { return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)') } function eachEvent(events, fn, iterator){ - if ($.isObject(events)) $.each(events, iterator) + if ($.type(events) != "string") $.each(events, iterator) else events.split(/\s/).forEach(function(type){ iterator(type, fn) }) } + function eventCapture(handler, captureSetting) { + return handler.del && + (handler.e == 'focus' || handler.e == 'blur') || + !!captureSetting + } + + function realEvent(type) { + return hover[type] || type + } + function add(element, events, fn, selector, getDelegate, capture){ - capture = !!capture var id = zid(element), set = (handlers[id] || (handlers[id] = [])) eachEvent(events, fn, function(event, fn){ - var delegate = getDelegate && getDelegate(fn, event), - callback = delegate || fn - var proxyfn = function (event) { - var result = callback.apply(element, [event].concat(event.data)) - if (result === false) event.preventDefault() + var handler = parse(event) + handler.fn = fn + handler.sel = selector + // emulate mouseenter, mouseleave + if (handler.e in hover) fn = function(e){ + var related = e.relatedTarget + if (!related || (related !== this && !$.contains(this, related))) + return handler.fn.apply(this, arguments) + } + handler.del = getDelegate && getDelegate(fn, event) + var callback = handler.del || fn + handler.proxy = function (e) { + var result = callback.apply(element, [e].concat(e.data)) + if (result === false) e.preventDefault(), e.stopPropagation() return result } - var handler = $.extend(parse(event), {fn: fn, proxy: proxyfn, sel: selector, del: delegate, i: set.length}) + handler.i = set.length set.push(handler) - element.addEventListener(handler.e, proxyfn, capture) + element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) }) } - function remove(element, events, fn, selector){ + function remove(element, events, fn, selector, capture){ var id = zid(element) eachEvent(events || '', fn, function(event, fn){ findHandlers(element, event, fn, selector).forEach(function(handler){ delete handlers[id][handler.i] - element.removeEventListener(handler.e, handler.proxy, false) + element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) }) }) } $.event = { add: add, remove: remove } @@ -712,17 +985,21 @@ }) } var returnTrue = function(){return true}, returnFalse = function(){return false}, + ignoreProperties = /^([A-Z]|layer[XY]$)/, eventMethods = { preventDefault: 'isDefaultPrevented', stopImmediatePropagation: 'isImmediatePropagationStopped', stopPropagation: 'isPropagationStopped' } function createProxy(event) { - var proxy = $.extend({originalEvent: event}, event) + var key, proxy = { originalEvent: event } + for (key in event) + if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key] + $.each(eventMethods, function(name, predicate) { proxy[name] = function(){ this[predicate] = returnTrue return event[name].apply(event, arguments) } @@ -742,28 +1019,20 @@ } } } $.fn.delegate = function(selector, event, callback){ - var capture = false - if(event == 'blur' || event == 'focus'){ - if($.iswebkit) - event = event == 'blur' ? 'focusout' : event == 'focus' ? 'focusin' : event - else - capture = true - } - return this.each(function(i, element){ add(element, event, callback, selector, function(fn){ return function(e){ var evt, match = $(e.target).closest(selector, element).get(0) if (match) { evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element}) return fn.apply(match, [evt].concat([].slice.call(arguments, 1))) } } - }, capture) + }) }) } $.fn.undelegate = function(selector, event, callback){ return this.each(function(){ remove(this, event, callback, selector) @@ -778,20 +1047,20 @@ $(document.body).undelegate(this.selector, event, callback) return this } $.fn.on = function(event, selector, callback){ - return selector == undefined || $.isFunction(selector) ? - this.bind(event, selector) : this.delegate(selector, event, callback) + return !selector || $.isFunction(selector) ? + this.bind(event, selector || callback) : this.delegate(selector, event, callback) } $.fn.off = function(event, selector, callback){ - return selector == undefined || $.isFunction(selector) ? - this.unbind(event, selector) : this.undelegate(selector, event, callback) + return !selector || $.isFunction(selector) ? + this.unbind(event, selector || callback) : this.undelegate(selector, event, callback) } $.fn.trigger = function(event, data){ - if (typeof event == 'string') event = $.Event(event) + if (typeof event == 'string' || $.isPlainObject(event)) event = $.Event(event) fix(event) event.data = data return this.each(function(){ // items in the collection might not be DOM elements // (todo: possibly support events on plain old objects) @@ -815,157 +1084,43 @@ return result } // shortcut methods for `.bind(event, fn)` for each event type ;('focusin focusout load resize scroll unload click dblclick '+ - 'mousedown mouseup mousemove mouseover mouseout '+ + 'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave '+ 'change select keydown keypress keyup error').split(' ').forEach(function(event) { - $.fn[event] = function(callback){ return this.bind(event, callback) } + $.fn[event] = function(callback) { + return callback ? + this.bind(event, callback) : + this.trigger(event) + } }) ;['focus', 'blur'].forEach(function(name) { $.fn[name] = function(callback) { if (callback) this.bind(name, callback) - else if (this.length) try { this.get(0)[name]() } catch(e){} + else this.each(function(){ + try { this[name]() } + catch(e) {} + }) return this } }) $.Event = function(type, props) { + if (typeof type != 'string') props = type, type = props.type var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name]) event.initEvent(type, bubbles, true, null, null, null, null, null, null, null, null, null, null, null, null) + event.isDefaultPrevented = function(){ return this.defaultPrevented } return event } })(Zepto) -;(function($){ - function detect(ua){ - var os = this.os = {}, browser = this.browser = {}, - webkit = ua.match(/WebKit\/([\d.]+)/), - android = ua.match(/(Android)\s+([\d.]+)/), - ipad = ua.match(/(iPad).*OS\s([\d_]+)/), - iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/), - webos = ua.match(/(webOS|hpwOS)[\s\/]([\d.]+)/), - touchpad = webos && ua.match(/TouchPad/), - kindle = ua.match(/Kindle\/([\d.]+)/), - silk = ua.match(/Silk\/([\d._]+)/), - blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/) - // todo clean this up with a better OS/browser - // separation. we need to discern between multiple - // browsers on android, and decide if kindle fire in - // silk mode is android or not - - if (browser.webkit = !!webkit) browser.version = webkit[1] - - if (android) os.android = true, os.version = android[2] - if (iphone) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.') - if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.') - if (webos) os.webos = true, os.version = webos[2] - if (touchpad) os.touchpad = true - if (blackberry) os.blackberry = true, os.version = blackberry[2] - if (kindle) os.kindle = true, os.version = kindle[1] - if (silk) browser.silk = true, browser.version = silk[1] - if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true - } - - detect.call($, navigator.userAgent) - // make available to unit tests - $.__detect = detect - -})(Zepto) -;(function($, undefined){ - var prefix = '', eventPrefix, endEventName, endAnimationName, - vendors = { Webkit: 'webkit', Moz: '', O: 'o', ms: 'MS' }, - document = window.document, testEl = document.createElement('div'), - supportedTransforms = /^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i, - clearProperties = {} - - function downcase(str) { return str.toLowerCase() } - function normalizeEvent(name) { return eventPrefix ? eventPrefix + name : downcase(name) } - - $.each(vendors, function(vendor, event){ - if (testEl.style[vendor + 'TransitionProperty'] !== undefined) { - prefix = '-' + downcase(vendor) + '-' - eventPrefix = event - return false - } - }) - - clearProperties[prefix + 'transition-property'] = - clearProperties[prefix + 'transition-duration'] = - clearProperties[prefix + 'transition-timing-function'] = - clearProperties[prefix + 'animation-name'] = - clearProperties[prefix + 'animation-duration'] = '' - - $.fx = { - off: (eventPrefix === undefined && testEl.style.transitionProperty === undefined), - cssPrefix: prefix, - transitionEnd: normalizeEvent('TransitionEnd'), - animationEnd: normalizeEvent('AnimationEnd') - } - - $.fn.animate = function(properties, duration, ease, callback){ - if ($.isObject(duration)) - ease = duration.easing, callback = duration.complete, duration = duration.duration - if (duration) duration = duration / 1000 - return this.anim(properties, duration, ease, callback) - } - - $.fn.anim = function(properties, duration, ease, callback){ - var transforms, cssProperties = {}, key, that = this, wrappedCallback, endEvent = $.fx.transitionEnd - if (duration === undefined) duration = 0.4 - if ($.fx.off) duration = 0 - - if (typeof properties == 'string') { - // keyframe animation - cssProperties[prefix + 'animation-name'] = properties - cssProperties[prefix + 'animation-duration'] = duration + 's' - endEvent = $.fx.animationEnd - } else { - // CSS transitions - for (key in properties) - if (supportedTransforms.test(key)) { - transforms || (transforms = []) - transforms.push(key + '(' + properties[key] + ')') - } - else cssProperties[key] = properties[key] - - if (transforms) cssProperties[prefix + 'transform'] = transforms.join(' ') - if (!$.fx.off && typeof properties === 'object') { - cssProperties[prefix + 'transition-property'] = Object.keys(properties).join(', ') - cssProperties[prefix + 'transition-duration'] = duration + 's' - cssProperties[prefix + 'transition-timing-function'] = (ease || 'linear') - } - } - - wrappedCallback = function(event){ - if (typeof event !== 'undefined') { - if (event.target !== event.currentTarget) return // makes sure the event didn't bubble from "below" - $(event.target).unbind(endEvent, arguments.callee) - } - $(this).css(clearProperties) - callback && callback.call(this) - } - if (duration > 0) this.bind(endEvent, wrappedCallback) - - setTimeout(function() { - that.css(cssProperties) - if (duration <= 0) setTimeout(function() { - that.each(function(){ wrappedCallback.call(this) }) - }, 0) - }, 0) - - return this - } - - testEl = null -})(Zepto) ;(function($){ var jsonpID = 0, - isObject = $.isObject, document = window.document, key, name, rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, scriptTypeRE = /^(?:text|application)\/javascript/i, @@ -1028,39 +1183,46 @@ // Empty function, used as default callback function empty() {} $.ajaxJSONP = function(options){ + if (!('type' in options)) return $.ajax(options) + var callbackName = 'jsonp' + (++jsonpID), script = document.createElement('script'), - abort = function(){ + cleanup = function() { + clearTimeout(abortTimeout) $(script).remove() - if (callbackName in window) window[callbackName] = empty - ajaxComplete('abort', xhr, options) + delete window[callbackName] }, + abort = function(type){ + cleanup() + // In case of manual abort or timeout, keep an empty function as callback + // so that the SCRIPT tag that eventually loads won't result in an error. + if (!type || type == 'timeout') window[callbackName] = empty + ajaxError(null, type || 'abort', xhr, options) + }, xhr = { abort: abort }, abortTimeout - if (options.error) script.onerror = function() { - xhr.abort() - options.error() + if (ajaxBeforeSend(xhr, options) === false) { + abort('abort') + return false } window[callbackName] = function(data){ - clearTimeout(abortTimeout) - $(script).remove() - delete window[callbackName] + cleanup() ajaxSuccess(data, xhr, options) } - serializeData(options) + script.onerror = function() { abort('error') } + script.src = options.url.replace(/=\?/, '=' + callbackName) $('head').append(script) if (options.timeout > 0) abortTimeout = setTimeout(function(){ - xhr.abort() - ajaxComplete('timeout', xhr, options) - }, options.timeout) + abort('timeout') + }, options.timeout) return xhr } $.ajaxSettings = { @@ -1091,14 +1253,19 @@ text: 'text/plain' }, // Whether the request is to another domain crossDomain: false, // Default timeout - timeout: 0 + timeout: 0, + // Whether data should be serialized to string + processData: true, + // Whether the browser should be allowed to cache GET responses + cache: true, } function mimeToDataType(mime) { + if (mime) mime = mime.split(';', 2)[0] return mime && ( mime == htmlType ? 'html' : mime == jsonType ? 'json' : scriptTypeRE.test(mime) ? 'script' : xmlTypeRE.test(mime) && 'xml' ) || 'text' } @@ -1107,11 +1274,12 @@ return (url + '&' + query).replace(/[&?]{1,2}/, '?') } // serialize payload and append it to the URL for GET requests function serializeData(options) { - if (isObject(options.data)) options.data = $.param(options.data) + if (options.processData && options.data && $.type(options.data) != "string") + options.data = $.param(options.data, options.traditional) if (options.data && (!options.type || options.type.toUpperCase() == 'GET')) options.url = appendQuery(options.url, options.data) } $.ajax = function(options){ @@ -1121,52 +1289,55 @@ ajaxStart(settings) if (!settings.crossDomain) settings.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(settings.url) && RegExp.$2 != window.location.host + if (!settings.url) settings.url = window.location.toString() + serializeData(settings) + if (settings.cache === false) settings.url = appendQuery(settings.url, '_=' + Date.now()) + var dataType = settings.dataType, hasPlaceholder = /=\?/.test(settings.url) if (dataType == 'jsonp' || hasPlaceholder) { if (!hasPlaceholder) settings.url = appendQuery(settings.url, 'callback=?') return $.ajaxJSONP(settings) } - if (!settings.url) settings.url = window.location.toString() - serializeData(settings) - var mime = settings.accepts[dataType], baseHeaders = { }, protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol, - xhr = $.ajaxSettings.xhr(), abortTimeout + xhr = settings.xhr(), abortTimeout if (!settings.crossDomain) baseHeaders['X-Requested-With'] = 'XMLHttpRequest' if (mime) { baseHeaders['Accept'] = mime if (mime.indexOf(',') > -1) mime = mime.split(',', 2)[0] xhr.overrideMimeType && xhr.overrideMimeType(mime) } - if (settings.contentType || (settings.data && settings.type.toUpperCase() != 'GET')) + if (settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() != 'GET')) baseHeaders['Content-Type'] = (settings.contentType || 'application/x-www-form-urlencoded') settings.headers = $.extend(baseHeaders, settings.headers || {}) xhr.onreadystatechange = function(){ if (xhr.readyState == 4) { + xhr.onreadystatechange = empty; clearTimeout(abortTimeout) var result, error = false if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || (xhr.status == 0 && protocol == 'file:')) { dataType = dataType || mimeToDataType(xhr.getResponseHeader('content-type')) result = xhr.responseText try { + // http://perfectionkills.com/global-eval-what-are-the-options/ if (dataType == 'script') (1,eval)(result) else if (dataType == 'xml') result = xhr.responseXML - else if (dataType == 'json') result = blankRE.test(result) ? null : JSON.parse(result) + else if (dataType == 'json') result = blankRE.test(result) ? null : $.parseJSON(result) } catch (e) { error = e } if (error) ajaxError(error, 'parsererror', xhr, settings) else ajaxSuccess(result, xhr, settings) } else { - ajaxError(null, 'error', xhr, settings) + ajaxError(null, xhr.status ? 'error' : 'abort', xhr, settings) } } } var async = 'async' in settings ? settings.async : true @@ -1188,56 +1359,77 @@ // avoid sending empty string (#319) xhr.send(settings.data ? settings.data : null) return xhr } - $.get = function(url, success){ return $.ajax({ url: url, success: success }) } + // handle optional data/success arguments + function parseArguments(url, data, success, dataType) { + var hasData = !$.isFunction(data) + return { + url: url, + data: hasData ? data : undefined, + success: !hasData ? data : $.isFunction(success) ? success : undefined, + dataType: hasData ? dataType || success : success + } + } + $.get = function(url, data, success, dataType){ + return $.ajax(parseArguments.apply(null, arguments)) + } + $.post = function(url, data, success, dataType){ - if ($.isFunction(data)) dataType = dataType || success, success = data, data = null - return $.ajax({ type: 'POST', url: url, data: data, success: success, dataType: dataType }) + var options = parseArguments.apply(null, arguments) + options.type = 'POST' + return $.ajax(options) } - $.getJSON = function(url, success){ - return $.ajax({ url: url, success: success, dataType: 'json' }) + $.getJSON = function(url, data, success){ + var options = parseArguments.apply(null, arguments) + options.dataType = 'json' + return $.ajax(options) } - $.fn.load = function(url, success){ + $.fn.load = function(url, data, success){ if (!this.length) return this - var self = this, parts = url.split(/\s/), selector - if (parts.length > 1) url = parts[0], selector = parts[1] - $.get(url, function(response){ + var self = this, parts = url.split(/\s/), selector, + options = parseArguments(url, data, success), + callback = options.success + if (parts.length > 1) options.url = parts[0], selector = parts[1] + options.success = function(response){ self.html(selector ? - $(document.createElement('div')).html(response.replace(rscript, "")).find(selector).html() + $('<div>').html(response.replace(rscript, "")).find(selector) : response) - success && success.call(self) - }) + callback && callback.apply(self, arguments) + } + $.ajax(options) return this } var escape = encodeURIComponent function serialize(params, obj, traditional, scope){ - var array = $.isArray(obj) + var type, array = $.isArray(obj) $.each(obj, function(key, value) { + type = $.type(value) if (scope) key = traditional ? scope : scope + '[' + (array ? '' : key) + ']' // handle data in serializeArray() format if (!scope && array) params.add(value.name, value.value) // recurse into nested objects - else if (traditional ? $.isArray(value) : isObject(value)) + else if (type == "array" || (!traditional && type == "object")) serialize(params, value, traditional, key) else params.add(key, value) }) } $.param = function(obj, traditional){ var params = [] params.add = function(k, v){ this.push(escape(k) + '=' + escape(v)) } serialize(params, obj, traditional) - return params.join('&').replace('%20', '+') + return params.join('&').replace(/%20/g, '+') } })(Zepto) + ;(function ($) { $.fn.serializeArray = function () { var result = [], el $( Array.prototype.slice.call(this.get(0).elements) ).each(function () { el = $(this) @@ -1270,86 +1462,104 @@ } return this } })(Zepto) -;(function($){ - var touch = {}, touchTimeout - function parentIfText(node){ - return 'tagName' in node ? node : node.parentNode - } +;(function($, undefined){ + var prefix = '', eventPrefix, endEventName, endAnimationName, + vendors = { Webkit: 'webkit', Moz: '', O: 'o', ms: 'MS' }, + document = window.document, testEl = document.createElement('div'), + supportedTransforms = /^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i, + transform, + transitionProperty, transitionDuration, transitionTiming, + animationName, animationDuration, animationTiming, + cssReset = {} - function swipeDirection(x1, x2, y1, y2){ - var xDelta = Math.abs(x1 - x2), yDelta = Math.abs(y1 - y2) - return xDelta >= yDelta ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down') - } + function dasherize(str) { return downcase(str.replace(/([a-z])([A-Z])/, '$1-$2')) } + function downcase(str) { return str.toLowerCase() } + function normalizeEvent(name) { return eventPrefix ? eventPrefix + name : downcase(name) } - var longTapDelay = 750, longTapTimeout - - function longTap(){ - longTapTimeout = null - if (touch.last) { - touch.el.trigger('longTap') - touch = {} + $.each(vendors, function(vendor, event){ + if (testEl.style[vendor + 'TransitionProperty'] !== undefined) { + prefix = '-' + downcase(vendor) + '-' + eventPrefix = event + return false } + }) + + transform = prefix + 'transform' + cssReset[transitionProperty = prefix + 'transition-property'] = + cssReset[transitionDuration = prefix + 'transition-duration'] = + cssReset[transitionTiming = prefix + 'transition-timing-function'] = + cssReset[animationName = prefix + 'animation-name'] = + cssReset[animationDuration = prefix + 'animation-duration'] = + cssReset[animationTiming = prefix + 'animation-timing-function'] = '' + + $.fx = { + off: (eventPrefix === undefined && testEl.style.transitionProperty === undefined), + speeds: { _default: 400, fast: 200, slow: 600 }, + cssPrefix: prefix, + transitionEnd: normalizeEvent('TransitionEnd'), + animationEnd: normalizeEvent('AnimationEnd') } - function cancelLongTap(){ - if (longTapTimeout) clearTimeout(longTapTimeout) - longTapTimeout = null + $.fn.animate = function(properties, duration, ease, callback){ + if ($.isPlainObject(duration)) + ease = duration.easing, callback = duration.complete, duration = duration.duration + if (duration) duration = (typeof duration == 'number' ? duration : + ($.fx.speeds[duration] || $.fx.speeds._default)) / 1000 + return this.anim(properties, duration, ease, callback) } - $(document).ready(function(){ - var now, delta + $.fn.anim = function(properties, duration, ease, callback){ + var key, cssValues = {}, cssProperties, transforms = '', + that = this, wrappedCallback, endEvent = $.fx.transitionEnd - $(document.body).bind('touchstart', function(e){ - now = Date.now() - delta = now - (touch.last || now) - touch.el = $(parentIfText(e.touches[0].target)) - touchTimeout && clearTimeout(touchTimeout) - touch.x1 = e.touches[0].pageX - touch.y1 = e.touches[0].pageY - if (delta > 0 && delta <= 250) touch.isDoubleTap = true - touch.last = now - longTapTimeout = setTimeout(longTap, longTapDelay) - }).bind('touchmove', function(e){ - cancelLongTap() - touch.x2 = e.touches[0].pageX - touch.y2 = e.touches[0].pageY - }).bind('touchend', function(e){ - cancelLongTap() + if (duration === undefined) duration = 0.4 + if ($.fx.off) duration = 0 - // double tap (tapped twice within 250ms) - if (touch.isDoubleTap) { - touch.el.trigger('doubleTap') - touch = {} + if (typeof properties == 'string') { + // keyframe animation + cssValues[animationName] = properties + cssValues[animationDuration] = duration + 's' + cssValues[animationTiming] = (ease || 'linear') + endEvent = $.fx.animationEnd + } else { + cssProperties = [] + // CSS transitions + for (key in properties) + if (supportedTransforms.test(key)) transforms += key + '(' + properties[key] + ') ' + else cssValues[key] = properties[key], cssProperties.push(dasherize(key)) - // swipe - } else if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > 30) || - (touch.y2 && Math.abs(touch.y1 - touch.y2) > 30)) { - touch.el.trigger('swipe') && - touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2))) - touch = {} + if (transforms) cssValues[transform] = transforms, cssProperties.push(transform) + if (duration > 0 && typeof properties === 'object') { + cssValues[transitionProperty] = cssProperties.join(', ') + cssValues[transitionDuration] = duration + 's' + cssValues[transitionTiming] = (ease || 'linear') + } + } - // normal tap - } else if ('last' in touch) { - touch.el.trigger('tap') - - touchTimeout = setTimeout(function(){ - touchTimeout = null - touch.el.trigger('singleTap') - touch = {} - }, 250) + wrappedCallback = function(event){ + if (typeof event !== 'undefined') { + if (event.target !== event.currentTarget) return // makes sure the event didn't bubble from "below" + $(event.target).unbind(endEvent, wrappedCallback) } - }).bind('touchcancel', function(){ - if (touchTimeout) clearTimeout(touchTimeout) - if (longTapTimeout) clearTimeout(longTapTimeout) - longTapTimeout = touchTimeout = null - touch = {} - }) - }) + $(this).css(cssReset) + callback && callback.call(this) + } + if (duration > 0) this.bind(endEvent, wrappedCallback) - ;['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown', 'doubleTap', 'tap', 'singleTap', 'longTap'].forEach(function(m){ - $.fn[m] = function(callback){ return this.bind(m, callback) } - }) + // trigger page reflow so new elements can animate + this.size() && this.get(0).clientLeft + + this.css(cssValues) + + if (duration <= 0) setTimeout(function() { + that.each(function(){ wrappedCallback.call(this) }) + }, 0) + + return this + } + + testEl = null })(Zepto)