diff --git a/vendor/assets/javascripts/zepto.js b/vendor/assets/javascripts/zepto.js index 18e9e70..7e8aa09 100644 --- a/vendor/assets/javascripts/zepto.js +++ b/vendor/assets/javascripts/zepto.js @@ -1,15 +1,17 @@ -// Zepto.js -// (c) 2010, 2011 Thomas Fuchs -// Zepto.js may be freely distributed under the MIT license. - +/* Zepto v1.0rc1-107-gdea8af9 - zepto event fx ajax form data touch - zeptojs.com/license */ 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+)[^>]*>/, - elementTypes = [1, 9, 11], + fragmentRE = /^\s*<(\w+|!)[^>]*>/, + tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rootNodeRE = /^(?:body|html)$/i, + + // 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'), @@ -21,565 +23,857 @@ var Zepto = (function() { }, readyRE = /complete|loaded|interactive/, classSelectorRE = /^\.([\w-]+)$/, - idSelectorRE = /^#([\w-]+)$/, - tagSelectorRE = /^[\w-]+$/; + idSelectorRE = /^#([\w-]*)$/, + tagSelectorRE = /^[\w-]+$/, + toString = {}.toString, + zepto = {}, + camelize, uniq, + tempParent = document.createElement('div') + + zepto.matches = function(element, selector) { + if (!element || element.nodeType !== 1) return false + var matchesSelector = element.webkitMatchesSelector || element.mozMatchesSelector || + element.oMatchesSelector || element.matchesSelector + if (matchesSelector) return matchesSelector.call(element, selector) + // fall back to performing a selector: + var match, parent = element.parentNode, temp = !parent + if (temp) (parent = tempParent).appendChild(element) + match = ~zepto.qsa(parent, selector).indexOf(element) + temp && tempParent.removeChild(element) + return match + } - function isF(value) { return ({}).toString.call(value) == "[object Function]" } - function isO(value) { return value instanceof Object } - function isA(value) { return value instanceof Array } + function isFunction(value) { return toString.call(value) == "[object Function]" } + function isObject(value) { return value instanceof Object } + function isPlainObject(value) { + return isObject(value) && value.__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 camelize(str) { return str.replace(/-+(.)?/g, function(match, chr){ return chr ? chr.toUpperCase() : '' }) } - function dasherize(str){ + function compact(array) { return filter.call(array, function(item){ return item !== undefined && 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(); + .toLowerCase() } - function uniq(array) { return array.filter(function(item,index,array){ return array.indexOf(item) == index }) } + uniq = function(array){ return filter.call(array, function(item, idx){ return array.indexOf(item) == idx }) } - function classRE(name){ + function classRE(name) { return name in classCache ? - classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)')); + classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)')) } - function maybeAddPx(name, value) { return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value; } + function maybeAddPx(name, value) { + return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value + } function defaultDisplay(nodeName) { - var element, display; + var element, display if (!elementDisplay[nodeName]) { - element = document.createElement(nodeName); - document.body.appendChild(element); - display = getComputedStyle(element, '').getPropertyValue("display"); - element.parentNode.removeChild(element); - display == "none" && (display = "block"); - elementDisplay[nodeName] = display; + element = document.createElement(nodeName) + document.body.appendChild(element) + display = getComputedStyle(element, '').getPropertyValue("display") + element.parentNode.removeChild(element) + display == "none" && (display = "block") + elementDisplay[nodeName] = display } - return elementDisplay[nodeName]; + return elementDisplay[nodeName] } - function fragment(html, name) { - if (name === undefined) fragmentRE.test(html) && RegExp.$1; - if (!(name in containers)) name = '*'; - var container = containers[name]; - container.innerHTML = '' + html; - return slice.call(container.childNodes); + function children(element) { + return 'children' in element ? + slice.call(element.children) : + $.map(element.childNodes, function(node){ if (node.nodeType == 1) return node }) } - function Z(dom, selector){ - dom = dom || emptyArray; - dom.__proto__ = Z.prototype; - dom.selector = selector || ''; - return dom; + // `$.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, properties) { + if (html.replace) html = html.replace(tagExpanderRE, "<$1>") + if (name === undefined) name = fragmentRE.test(html) && RegExp.$1 + if (!(name in containers)) name = '*' + + var nodes, dom, container = containers[name] + container.innerHTML = '' + html + 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.selector = selector || '' + return dom } - function $(selector, context){ - if (!selector) return Z(); - if (context !== undefined) return $(context).find(selector); - else if (isF(selector)) return $(document).ready(selector); - else if (selector instanceof Z) return selector; + // `$.zepto.isZ` should return `true` if the given object is a Zepto + // collection. This method can be overriden in plugins. + zepto.isZ = function(object) { + return object instanceof zepto.Z + } + + // `$.zepto.init` is Zepto's counterpart to jQuery's `$.fn.init` and + // takes a CSS selector and an optional context (and handles various + // special cases). + // This method can be overriden in plugins. + zepto.init = function(selector, context) { + // If nothing given, return an empty Zepto collection + if (!selector) return zepto.Z() + // If a function is given, call it when the DOM is ready + else if (isFunction(selector)) return $(document).ready(selector) + // If a Zepto collection is given, juts return it + else if (zepto.isZ(selector)) return selector else { - var dom; - if (isA(selector)) dom = compact(selector); - else if (elementTypes.indexOf(selector.nodeType) >= 0 || selector === window) - dom = [selector], selector = null; + var dom + // normalize array if an array of nodes is given + if (isArray(selector)) dom = compact(selector) + // 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 = fragment(selector.trim(), RegExp.$1), selector = null; - else if (selector.nodeType && selector.nodeType == 3) dom = [selector]; - else dom = $$(document, selector); - return Z(dom, selector); + 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) + // create a new Zepto collection from the nodes found + return zepto.Z(dom, selector) } } + // `$` will be the base `Zepto` object. When calling this + // 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])) { + if (!isPlainObject(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) target[key] = source[key]; - }) - return target; + 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 } - $.qsa = $$ = function(element, selector){ - var found; + // `$.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 ) : + ( (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) - ); + ) + } + + function filtered(nodes, selector) { + return selector === undefined ? $(nodes) : $(nodes).filter(selector) } - 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 isF(arg) ? arg.call(context, idx, payload) : arg; + function funcArg(context, arg, idx, payload) { + return isFunction(arg) ? arg.call(context, idx, payload) : arg } - $.isFunction = isF; - $.isObject = isO; - $.isArray = isA; + 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 + } + } - $.map = function(elements, callback) { - var value, values = [], i, key; + $.isFunction = isFunction + $.isObject = isObject + $.isArray = isArray + $.isPlainObject = isPlainObject + + $.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++) { - value = callback(elements[i], i); - if (value != null) values.push(value); + value = callback(elements[i], i) + if (value != null) values.push(value) } else for (key in elements) { - value = callback(elements[key], key); - if (value != null) values.push(value); + value = callback(elements[key], key) + if (value != null) values.push(value) } - return flatten(values); + return flatten(values) } - $.each = function(elements, callback) { - var i, key; - if (likeArray(elements)) - for(i = 0; i < elements.length; i++) { - if(callback(i, elements[i]) === false) return elements; - } - else - for(key in elements) { - if(callback(key, elements[key]) === false) return elements; - } - return elements; + $.each = function(elements, callback){ + var i, key + if (likeArray(elements)) { + for (i = 0; i < elements.length; i++) + if (callback.call(elements[i], i, elements[i]) === false) return elements + } else { + for (key in elements) + if (callback.call(elements[key], key, elements[key]) === false) return elements + } + + return elements + } + + $.grep = function(elements, callback){ + return filter.call(elements, callback) } + if (window.JSON) $.parseJSON = JSON.parse + + // 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)); + return $(slice.apply(this, arguments)) }, + ready: function(callback){ - if (readyRE.test(document.readyState)) callback($); - else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false); - return this; + if (readyRE.test(document.readyState)) callback($) + else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false) + return this }, - get: function(idx){ return idx === undefined ? this : this[idx] }, - size: function(){ return this.length }, - remove: function () { - return this.each(function () { - if (this.parentNode != null) { - this.parentNode.removeChild(this); - } - }); + get: function(idx){ + return idx === undefined ? slice.call(this) : this[idx] }, - each: function(callback){ - this.forEach(function(el, idx){ callback.call(el, idx, el) }); - return this; + toArray: function(){ return this.get() }, + size: function(){ + return this.length }, - filter: function(selector){ - return $([].filter.call(this, function(element){ - return element.parentNode && $$(element.parentNode, selector).indexOf(element) >= 0; - })); + remove: function(){ + return this.each(function(){ + if (this.parentNode != null) + this.parentNode.removeChild(this) + }) }, - end: function(){ - return this.prevObject || $(); + each: function(callback){ + this.forEach(function(el, idx){ callback.call(el, idx, el) }) + return this }, - andSelf:function(){ - return this.add(this.prevObject || $()) + filter: function(selector){ + 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)))); + add: function(selector,context){ + return $(uniq(this.concat($(selector,context)))) }, is: function(selector){ - return this.length > 0 && $(this[0]).filter(selector).length > 0; + return this.length > 0 && zepto.matches(this[0], selector) }, not: function(selector){ - var nodes=[]; - if (isF(selector) && selector.call !== undefined) + var nodes=[] + if (isFunction(selector) && selector.call !== undefined) this.each(function(idx){ - if (!selector.call(this,idx)) nodes.push(this); - }); + if (!selector.call(this,idx)) nodes.push(this) + }) else { var excludes = typeof selector == 'string' ? this.filter(selector) : - (likeArray(selector) && isF(selector.item)) ? slice.call(selector) : $(selector); + (likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector) this.forEach(function(el){ - if (excludes.indexOf(el) < 0) nodes.push(el); - }); + if (excludes.indexOf(el) < 0) nodes.push(el) + }) } - return $(nodes); + 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); + return idx === -1 ? this.slice(idx) : this.slice(idx, + idx + 1) + }, + first: function(){ + var el = this[0] + return el && !isObject(el) ? el : $(el) + }, + last: function(){ + var el = this[this.length - 1] + return el && !isObject(el) ? el : $(el) }, - first: function(){ var el = this[0]; return el && !isO(el) ? el : $(el) }, - last: function(){ var el = this[this.length - 1]; return el && !isO(el) ? el : $(el) }, find: function(selector){ - var result; - if (this.length == 1) result = $$(this[0], selector); - else result = this.map(function(){ return $$(this, selector) }); - return $(result); + var result + if (this.length == 1) result = $(zepto.qsa(this[0], selector)) + else result = this.map(function(){ return zepto.qsa(this, selector) }) + return result }, closest: function(selector, context){ - var node = this[0], candidates = $$(context || document, selector); - if (!candidates.length) node = null; - while (node && candidates.indexOf(node) < 0) - node = node !== context && node !== document && node.parentNode; - return $(node); + var node = this[0] + while (node && !zepto.matches(node, selector)) + node = node !== context && node !== document && node.parentNode + return $(node) }, parents: function(selector){ - var ancestors = [], nodes = this; + var ancestors = [], nodes = this while (nodes.length > 0) nodes = $.map(nodes, function(node){ if ((node = node.parentNode) && node !== document && ancestors.indexOf(node) < 0) { - ancestors.push(node); - return node; + ancestors.push(node) + return node } - }); - return filtered(ancestors, selector); + }) + return filtered(ancestors, selector) }, parent: function(selector){ - return filtered(uniq(this.pluck('parentNode')), 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 }); - }), selector); + 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 $.map(this, function(el){ return el[property] }) }, - empty: function(){ return this.each(function(){ this.innerHTML = '' }) }, - pluck: function(property){ return this.map(function(){ return this[property] }) }, show: function(){ - return this.each(function() { - this.style.display == "none" && (this.style.display = null); - if (getComputedStyle(this, '').getPropertyValue("display") == "none") { + return this.each(function(){ + this.style.display == "none" && (this.style.display = null) + if (getComputedStyle(this, '').getPropertyValue("display") == "none") this.style.display = defaultDisplay(this.nodeName) - } }) }, - replaceWith: function(newContent) { - return this.each(function() { - $(this).before(newContent).remove(); - }); + 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; + 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; + $(this).replaceWith($(this).children()) + }) + return this + }, + clone: function(){ + 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; - $(this).empty().append( funcArg(this, html, idx, originHtml) ); - }); + this.each(function(idx){ + var originHtml = this.innerHTML + $(this).empty().append( funcArg(this, html, idx, originHtml) ) + }) }, text: function(text){ return text === undefined ? (this.length > 0 ? this[0].textContent : null) : - this.each(function(){ this.textContent = text }); + this.each(function(){ this.textContent = text }) }, attr: function(name, value){ - var res; + var result return (typeof name == 'string' && value === undefined) ? - (this.length == 0 ? undefined : + (this.length == 0 || this[0].nodeType !== 1 ? undefined : (name == 'value' && this[0].nodeName == 'INPUT') ? this.val() : - (!(res = this[0].getAttribute(name)) && name in this[0]) ? this[0][name] : res + (!(result = this[0].getAttribute(name)) && name in this[0]) ? this[0][name] : result ) : this.each(function(idx){ - if (isO(name)) for (key in name) this.setAttribute(key, name[key]) - else this.setAttribute(name, funcArg(this, value, idx, this.getAttribute(name))); - }); + if (this.nodeType !== 1) return + 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() { this.removeAttribute(name); }); + removeAttr: function(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.each(function(idx){ + this[name] = funcArg(this, value, idx, this[name]) + }) }, data: function(name, value){ - return this.attr('data-' + name, value); + var data = this.attr('data-' + dasherize(name), value) + return data !== null ? deserializeValue(data) : undefined }, val: function(value){ return (value === undefined) ? - (this.length > 0 ? this[0].value : null) : + (this.length > 0 ? + (this[0].multiple ? $(this[0]).find('option').filter(function(o){ return this.selected }).pluck('value') : this[0].value) : + undefined) : this.each(function(idx){ - this.value = funcArg(this, value, idx, this.value); - }); + this.value = funcArg(this, value, idx, this.value) + }) }, offset: function(){ - if(this.length==0) return null; - var obj = this[0].getBoundingClientRect(); + 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 - }; + } }, css: function(property, value){ - if (value === undefined && typeof property == 'string') { - return( + if (arguments.length < 2 && typeof property == 'string') + return ( this.length == 0 ? undefined - : this[0].style[camelize(property)] || getComputedStyle(this[0], '').getPropertyValue(property) - ); - } - var css = ''; - for (key in property) css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';'; - if (typeof property == 'string') css = dasherize(property) + ":" + maybeAddPx(property, value); - return this.each(function() { this.style.cssText += ';' + css }); + : this[0].style[camelize(property)] || getComputedStyle(this[0], '').getPropertyValue(property)) + + var css = '' + 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]) + ';' + + if (typeof property == 'string') + if (!value && value !== 0) + this.each(function(){ this.style.removeProperty(dasherize(property)) }) + else + css = dasherize(property) + ":" + maybeAddPx(property, value) + + return this.each(function(){ this.style.cssText += ';' + css }) }, index: function(element){ - return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0]); + 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); + if (this.length < 1) return false + else return classRE(name).test(className(this[0])) }, addClass: function(name){ - return this.each(function(idx) { - classList = []; - var cls = this.className, 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(" ")) - }); + return this.each(function(idx){ + classList = [] + 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 && className(this, cls + (cls ? " " : "") + classList.join(" ")) + }) }, removeClass: function(name){ - return this.each(function(idx) { - if(name === undefined) - return this.className = ''; - classList = this.className; - funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass) { + return this.each(function(idx){ + 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); - }); - } - }; - - 'filter,add,not,eq,first,last,find,closest,parents,parent,children,siblings'.split(',').forEach(function(property){ - var fn = $.fn[property]; - $.fn[property] = function() { - var ret = fn.apply(this, arguments); - ret.prevObject = this; - return ret; + var newName = funcArg(this, name, idx, className(this)) + ;(when === undefined ? !$(this).hasClass(newName) : when) ? + $(this).addClass(newName) : $(this).removeClass(newName) + }) + }, + 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 + }) } - }); + } - ['width', 'height'].forEach(function(dimension){ - $.fn[dimension] = function(value) { - var offset, Dimension = dimension.replace(/./, function(m) { return m[0].toUpperCase() }); + // 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] : - (offset = this.offset()) && offset[dimension]; + (offset = this.offset()) && offset[dimension] else return this.each(function(idx){ - var el = $(this); - el.css(dimension, funcArg(this, value, idx, el[dimension]())); - }); + var 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 + function traverseNode(node, fun) { + fun(node) + for (var key in node.childNodes) traverseNode(node.childNodes[key], fun) } - 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(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) }), + parent, copyByClone = this.length > 1 + if (nodes.length < 1) return this + + 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) + }) + }) + }) } - } - - adjacencyOperators.forEach(function(key, operator) { - $.fn[key] = function(html){ - var nodes = isO(html) ? html : fragment(html); - if (!('length' in nodes) || nodes.nodeType) nodes = [nodes]; - 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); - } - }); - if (copyByClone && index < size - 1) node = node.cloneNode(true); - insert(operator, target, node); - } - }); - }; - var reverseKey = (operator % 2) ? key+'To' : 'insert'+(operator ? 'Before' : 'After'); - $.fn[reverseKey] = function(html) { - $(html)[key](this); - return this; - }; - }); + // after => insertAfter + // prepend => prependTo + // before => insertBefore + // append => appendTo + $.fn[inside ? operator+'To' : 'insert'+(operatorIndex ? 'Before' : 'After')] = function(html){ + $(html)[operator](this) + return this + } + }) - Z.prototype = $.fn; + zepto.Z.prototype = $.fn - return $; -})(); + // Export internal API functions in the `$.zepto` namespace + zepto.uniq = uniq + zepto.deserializeValue = deserializeValue + $.zepto = zepto -window.Zepto = Zepto; -'$' in window || (window.$ = Zepto); -// Zepto.js -// (c) 2010, 2011 Thomas Fuchs -// Zepto.js may be freely distributed under the MIT license. + return $ +})() -(function($){ - var $$ = $.qsa, handlers = {}, _zid = 1, specialEvents={}; +// If `$` is not yet defined, point it to `Zepto` +window.Zepto = Zepto +'$' in window || (window.$ = Zepto) +;(function($){ + var $$ = $.zepto.qsa, handlers = {}, _zid = 1, specialEvents={}, + hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' } - specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents'; + specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents' function zid(element) { - return element._zid || (element._zid = _zid++); + return element._zid || (element._zid = _zid++) } function findHandlers(element, event, fn, selector) { - event = parse(event); - if (event.ns) var matcher = matcherFor(event.ns); + event = parse(event) + if (event.ns) var matcher = matcherFor(event.ns) return (handlers[zid(element)] || []).filter(function(handler) { return handler && (!event.e || handler.e == event.e) && (!event.ns || matcher.test(handler.ns)) - && (!fn || handler.fn == fn) - && (!selector || handler.sel == selector); - }); + && (!fn || zid(handler.fn) === zid(fn)) + && (!selector || handler.sel == selector) + }) } function parse(event) { - var parts = ('' + event).split('.'); - return {e: parts[0], ns: parts.slice(1).sort().join(' ')}; + var parts = ('' + event).split('.') + return {e: parts[0], ns: parts.slice(1).sort().join(' ')} } function matcherFor(ns) { - return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)'); + return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)') } function eachEvent(events, fn, iterator){ - if ($.isObject(events)) $.each(events, iterator); - else events.split(/\s/).forEach(function(type){ iterator(type, fn) }); + if ($.isObject(events)) $.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 add(element, events, fn, selector, getDelegate){ - var id = zid(element), set = (handlers[id] || (handlers[id] = [])); + function realEvent(type) { + return hover[type] || type + } + + function add(element, events, fn, selector, getDelegate, 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(); - return result; - }; - var handler = $.extend(parse(event), {fn: fn, proxy: proxyfn, sel: selector, del: delegate, i: set.length}); - set.push(handler); - element.addEventListener(handler.e, proxyfn, false); - }); - } - function remove(element, events, fn, selector){ - var id = zid(element); + 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 + } + handler.i = set.length + set.push(handler) + element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + } + 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); - }); - }); + delete handlers[id][handler.i] + element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + }) } $.event = { add: add, remove: remove } + $.proxy = function(fn, context) { + if ($.isFunction(fn)) { + var proxyFn = function(){ return fn.apply(context, arguments) } + proxyFn._zid = zid(fn) + return proxyFn + } else if (typeof context == 'string') { + return $.proxy(fn[context], fn) + } else { + throw new TypeError("expected function") + } + } + $.fn.bind = function(event, callback){ return this.each(function(){ - add(this, event, callback); - }); - }; + add(this, event, callback) + }) + } $.fn.unbind = function(event, callback){ return this.each(function(){ - remove(this, event, callback); - }); - }; + remove(this, event, callback) + }) + } $.fn.one = function(event, callback){ return this.each(function(i, element){ add(this, event, callback, null, function(fn, type){ return function(){ - var result = fn.apply(element, arguments); - remove(element, type, fn); - return result; + var result = fn.apply(element, arguments) + remove(element, type, fn) + return result } - }); - }); - }; + }) + }) + } 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); - }; - proxy[predicate] = returnFalse; + this[predicate] = returnTrue + return event[name].apply(event, arguments) + } + proxy[predicate] = returnFalse }) - return proxy; + return proxy } // emulates the 'defaultPrevented' property for browsers that have none function fix(event) { if (!('defaultPrevented' in event)) { - event.defaultPrevented = false; - var prevent = event.preventDefault; + event.defaultPrevented = false + var prevent = event.preventDefault event.preventDefault = function() { - this.defaultPrevented = true; - prevent.call(this); + this.defaultPrevented = true + prevent.call(this) } } } @@ -588,285 +882,300 @@ window.Zepto = Zepto; 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); + 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))); + evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element}) + return fn.apply(match, [evt].concat([].slice.call(arguments, 1))) } } - }); - }); - }; + }) + }) + } $.fn.undelegate = function(selector, event, callback){ return this.each(function(){ - remove(this, event, callback, selector); - }); + remove(this, event, callback, selector) + }) } $.fn.live = function(event, callback){ - $(document.body).delegate(this.selector, event, callback); - return this; - }; + $(document.body).delegate(this.selector, event, callback) + return this + } $.fn.die = function(event, callback){ - $(document.body).undelegate(this.selector, event, callback); - return this; - }; + $(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); - fix(event); - event.data = data; - return this.each(function(){ this.dispatchEvent(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) + if('dispatchEvent' in this) this.dispatchEvent(event) + }) + } // triggers event handlers on current element just as if an event occurred, // doesn't trigger an actual event, doesn't bubble $.fn.triggerHandler = function(event, data){ - var e, result; + var e, result this.each(function(i, element){ - e = createProxy(typeof event == 'string' ? $.Event(event) : event); - e.data = data; e.target = element; + e = createProxy(typeof event == 'string' ? $.Event(event) : event) + e.data = data + e.target = element $.each(findHandlers(element, event.type || event), function(i, handler){ - result = handler.proxy(e); - if (e.isImmediatePropagationStopped()) return false; - }); - }); - return result; - }; + result = handler.proxy(e) + if (e.isImmediatePropagationStopped()) return false + }) + }) + 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 '+ + ;('focusin focusout load resize scroll unload click dblclick '+ + '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) { + ;['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){}; - return this; - }; - }); + if (callback) this.bind(name, callback) + else this.each(function(){ + try { this[name]() } + catch(e) {} + }) + return this + } + }) $.Event = function(type, props) { - 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); - return event; - }; - -})(Zepto); -// Zepto.js -// (c) 2010, 2011 Thomas Fuchs -// Zepto.js may be freely distributed under the MIT license. - -(function($, undefined){ + 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($, undefined){ var prefix = '', eventPrefix, endEventName, endAnimationName, - vendors = {Webkit: 'webkit', Moz: '', O: 'o', ms: 'MS'}, + 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; + supportedTransforms = /^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i, + transform, + transitionProperty, transitionDuration, transitionTiming, + animationName, animationDuration, animationTiming, + cssReset = {} + 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) }; + 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; + 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') - }; + } $.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); - }; + 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) + } $.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; + var key, cssValues = {}, cssProperties, transforms = '', + 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; + 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 || (transforms = []); - transforms.push(key + '(' + properties[key] + ')'); - } - else cssProperties[key] = properties[key]; - - if (transforms) cssProperties[prefix + 'transform'] = transforms.join(' '); - if (!$.fx.off) cssProperties[prefix + 'transition'] = 'all ' + duration + 's ' + (ease || ''); + if (supportedTransforms.test(key)) transforms += key + '(' + properties[key] + ') ' + else cssValues[key] = properties[key], cssProperties.push(dasherize(key)) + + 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') + } } - wrappedCallback = function(){ - var props = {}; - props[prefix + 'transition'] = props[prefix + 'animation-name'] = 'none'; - $(this).css(props); - callback && callback.call(this); + 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(cssReset) + callback && callback.call(this) } - if (duration > 0) this.one(endEvent, wrappedCallback); + 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); + // trigger page reflow so new elements can animate + this.size() && this.get(0).clientLeft - return this; - }; + this.css(cssValues) - testEl = null; -})(Zepto); -// Zepto.js -// (c) 2010, 2011 Thomas Fuchs -// Zepto.js may be freely distributed under the MIT license. + if (duration <= 0) setTimeout(function() { + that.each(function(){ wrappedCallback.call(this) }) + }, 0) -(function($){ + return this + } + + testEl = null +})(Zepto) +;(function($){ var jsonpID = 0, isObject = $.isObject, document = window.document, key, - name; + name, + rscript = /)<[^<]*)*<\/script>/gi, + scriptTypeRE = /^(?:text|application)\/javascript/i, + xmlTypeRE = /^(?:text|application)\/xml/i, + jsonType = 'application/json', + htmlType = 'text/html', + blankRE = /^\s*$/ // trigger a custom event and return false if it was cancelled function triggerAndReturn(context, eventName, data) { - var event = $.Event(eventName); - $(context).trigger(event, data); - return !event.defaultPrevented; + var event = $.Event(eventName) + $(context).trigger(event, data) + return !event.defaultPrevented } // trigger an Ajax "global" event function triggerGlobal(settings, context, eventName, data) { - if (settings.global) return triggerAndReturn(context || document, eventName, data); + if (settings.global) return triggerAndReturn(context || document, eventName, data) } // Number of active Ajax requests - $.active = 0; + $.active = 0 function ajaxStart(settings) { - if (settings.global && $.active++ === 0) triggerGlobal(settings, null, 'ajaxStart'); + if (settings.global && $.active++ === 0) triggerGlobal(settings, null, 'ajaxStart') } function ajaxStop(settings) { - if (settings.global && !(--$.active)) triggerGlobal(settings, null, 'ajaxStop'); + if (settings.global && !(--$.active)) triggerGlobal(settings, null, 'ajaxStop') } // triggers an extra global event "ajaxBeforeSend" that's like "ajaxSend" but cancelable function ajaxBeforeSend(xhr, settings) { - var context = settings.context; + var context = settings.context if (settings.beforeSend.call(context, xhr, settings) === false || triggerGlobal(settings, context, 'ajaxBeforeSend', [xhr, settings]) === false) - return false; + return false - triggerGlobal(settings, context, 'ajaxSend', [xhr, settings]); + triggerGlobal(settings, context, 'ajaxSend', [xhr, settings]) } function ajaxSuccess(data, xhr, settings) { - var context = settings.context, status = 'success'; - settings.success.call(context, data, status, xhr); - triggerGlobal(settings, context, 'ajaxSuccess', [xhr, settings, data]); - ajaxComplete(status, xhr, settings); + var context = settings.context, status = 'success' + settings.success.call(context, data, status, xhr) + triggerGlobal(settings, context, 'ajaxSuccess', [xhr, settings, data]) + ajaxComplete(status, xhr, settings) } // type: "timeout", "error", "abort", "parsererror" function ajaxError(error, type, xhr, settings) { - var context = settings.context; - settings.error.call(context, xhr, type, error); - triggerGlobal(settings, context, 'ajaxError', [xhr, settings, error]); - ajaxComplete(type, xhr, settings); + var context = settings.context + settings.error.call(context, xhr, type, error) + triggerGlobal(settings, context, 'ajaxError', [xhr, settings, error]) + ajaxComplete(type, xhr, settings) } // status: "success", "notmodified", "error", "timeout", "abort", "parsererror" function ajaxComplete(status, xhr, settings) { - var context = settings.context; - settings.complete.call(context, xhr, status); - triggerGlobal(settings, context, 'ajaxComplete', [xhr, settings]); - ajaxStop(settings); + var context = settings.context + settings.complete.call(context, xhr, status) + triggerGlobal(settings, context, 'ajaxComplete', [xhr, settings]) + ajaxStop(settings) } // Empty function, used as default callback function empty() {} - // ### $.ajaxJSONP - // - // Load JSON from a server in a different domain (JSONP) - // - // *Arguments:* - // - // options — object that configure the request, - // see avaliable options below - // - // *Avaliable options:* - // - // url — url to which the request is sent - // success — callback that is executed if the request succeeds - // error — callback that is executed if the server drops error - // context — in which context to execute the callbacks in - // - // *Example:* - // - // $.ajaxJSONP({ - // url: 'http://example.com/projects?callback=?', - // success: function (data) { - // projects.push(json); - // } - // }); - // $.ajaxJSONP = function(options){ + if (!('type' in options)) return $.ajax(options) + var callbackName = 'jsonp' + (++jsonpID), script = document.createElement('script'), abort = function(){ - $(script).remove(); - if (callbackName in window) window[callbackName] = empty; - ajaxComplete(xhr, options, 'abort'); + $(script).remove() + if (callbackName in window) window[callbackName] = empty + ajaxComplete('abort', xhr, options) }, - xhr = { abort: abort }, abortTimeout; + xhr = { abort: abort }, abortTimeout + + if (options.error) script.onerror = function() { + xhr.abort() + options.error() + } window[callbackName] = function(data){ - clearTimeout(abortTimeout); - $(script).remove(); - delete window[callbackName]; - ajaxSuccess(data, xhr, options); - }; + clearTimeout(abortTimeout) + $(script).remove() + delete window[callbackName] + ajaxSuccess(data, xhr, options) + } - script.src = options.url.replace(/=\?/, '=' + callbackName); - $('head').append(script); + serializeData(options) + script.src = options.url.replace(/=\?/, '=' + callbackName) + $('head').append(script) if (options.timeout > 0) abortTimeout = setTimeout(function(){ - xhr.abort(); - ajaxComplete(xhr, options, 'timeout'); - }, options.timeout); + xhr.abort() + ajaxComplete('timeout', xhr, options) + }, options.timeout) - return xhr; - }; + return xhr + } - // ### $.ajaxSettings - // - // AJAX settings - // $.ajaxSettings = { // Default type of request type: 'GET', @@ -884,570 +1193,368 @@ window.Zepto = Zepto; global: true, // Transport xhr: function () { - return new window.XMLHttpRequest(); + return new window.XMLHttpRequest() }, // MIME types mapping accepts: { script: 'text/javascript, application/javascript', - json: 'application/json', + json: jsonType, xml: 'application/xml, text/xml', - html: 'text/html', + html: htmlType, text: 'text/plain' }, // Whether the request is to another domain crossDomain: false, // Default timeout - timeout: 0 - }; - - // ### $.ajax - // - // Perform AJAX request - // - // *Arguments:* - // - // options — object that configure the request, - // see avaliable options below - // - // *Avaliable options:* - // - // type ('GET') — type of request GET / POST - // url (window.location) — url to which the request is sent - // data — data to send to server, - // can be string or object - // dataType ('json') — what response type you accept from - // the server: - // 'json', 'xml', 'html', or 'text' - // timeout (0) — request timeout - // beforeSend — callback that is executed before - // request send - // complete — callback that is executed on request - // complete (both: error and success) - // success — callback that is executed if - // the request succeeds - // error — callback that is executed if - // the server drops error - // context — in which context to execute the - // callbacks in - // - // *Example:* - // - // $.ajax({ - // type: 'POST', - // url: '/projects', - // data: { name: 'Zepto.js' }, - // dataType: 'html', - // timeout: 100, - // context: $('body'), - // success: function (data) { - // this.append(data); - // }, - // error: function (xhr, type) { - // alert('Error!'); - // } - // }); - // - $.ajax = function(options){ - var settings = $.extend({}, options || {}); - for (key in $.ajaxSettings) if (settings[key] === undefined) settings[key] = $.ajaxSettings[key]; + timeout: 0, + // Whether data should be serialized to string + processData: true + } - ajaxStart(settings); + function mimeToDataType(mime) { + return mime && ( mime == htmlType ? 'html' : + mime == jsonType ? 'json' : + scriptTypeRE.test(mime) ? 'script' : + xmlTypeRE.test(mime) && 'xml' ) || 'text' + } - if (!settings.crossDomain) settings.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(settings.url) && - RegExp.$2 != window.location.host; + function appendQuery(url, query) { + return (url + '&' + query).replace(/[&?]{1,2}/, '?') + } - if (/=\?/.test(settings.url)) return $.ajaxJSONP(settings); + // serialize payload and append it to the URL for GET requests + function serializeData(options) { + if (options.processData && isObject(options.data)) + options.data = $.param(options.data, options.traditional) + if (options.data && (!options.type || options.type.toUpperCase() == 'GET')) + options.url = appendQuery(options.url, options.data) + } - if (!settings.url) settings.url = window.location.toString(); - if (settings.data && !settings.contentType) settings.contentType = 'application/x-www-form-urlencoded'; - if (isObject(settings.data)) settings.data = $.param(settings.data); + $.ajax = function(options){ + var settings = $.extend({}, options || {}) + for (key in $.ajaxSettings) if (settings[key] === undefined) settings[key] = $.ajaxSettings[key] - if (settings.type.match(/get/i) && settings.data) { - var queryString = settings.data; - if (settings.url.match(/\?.*=/)) { - queryString = '&' + queryString; - } else if (queryString[0] != '?') { - queryString = '?' + queryString; - } - settings.url += queryString; + ajaxStart(settings) + + if (!settings.crossDomain) settings.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(settings.url) && + RegExp.$2 != window.location.host + + var dataType = settings.dataType, hasPlaceholder = /=\?/.test(settings.url) + if (dataType == 'jsonp' || hasPlaceholder) { + if (!hasPlaceholder) settings.url = appendQuery(settings.url, 'callback=?') + return $.ajaxJSONP(settings) } - var mime = settings.accepts[settings.dataType], + 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 = $.ajaxSettings.xhr(), abortTimeout - if (!settings.crossDomain) baseHeaders['X-Requested-With'] = 'XMLHttpRequest'; - if (mime) baseHeaders['Accept'] = mime; - settings.headers = $.extend(baseHeaders, settings.headers || {}); + 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.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) { - clearTimeout(abortTimeout); - var result, error = false; - if ((xhr.status >= 200 && xhr.status < 300) || (xhr.status == 0 && protocol == 'file:')) { - if (mime == 'application/json' && !(/^\s*$/.test(xhr.responseText))) { - try { result = JSON.parse(xhr.responseText); } - catch (e) { error = e; } - } - else result = xhr.responseText; - if (error) ajaxError(error, 'parsererror', xhr, settings); - else ajaxSuccess(result, xhr, settings); + 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 { + if (dataType == 'script') (1,eval)(result) + else if (dataType == 'xml') result = xhr.responseXML + 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, 'error', xhr, settings) } } - }; + } - xhr.open(settings.type, settings.url, true); + var async = 'async' in settings ? settings.async : true + xhr.open(settings.type, settings.url, async) - if (settings.contentType) settings.headers['Content-Type'] = settings.contentType; - for (name in settings.headers) xhr.setRequestHeader(name, settings.headers[name]); + for (name in settings.headers) xhr.setRequestHeader(name, settings.headers[name]) if (ajaxBeforeSend(xhr, settings) === false) { - xhr.abort(); - return false; + xhr.abort() + return false } if (settings.timeout > 0) abortTimeout = setTimeout(function(){ - xhr.onreadystatechange = empty; - xhr.abort(); - ajaxError(null, 'timeout', xhr, settings); - }, settings.timeout); - - xhr.send(settings.data); - return xhr; - }; - - // ### $.get - // - // Load data from the server using a GET request - // - // *Arguments:* - // - // url — url to which the request is sent - // success — callback that is executed if the request succeeds - // - // *Example:* - // - // $.get( - // '/projects/42', - // function (data) { - // $('body').append(data); - // } - // ); - // - $.get = function(url, success){ return $.ajax({ url: url, success: success }) }; - - // ### $.post - // - // Load data from the server using POST request - // - // *Arguments:* - // - // url — url to which the request is sent - // [data] — data to send to server, can be string or object - // [success] — callback that is executed if the request succeeds - // [dataType] — type of expected response - // 'json', 'xml', 'html', or 'text' - // - // *Example:* - // - // $.post( - // '/projects', - // { name: 'Zepto.js' }, - // function (data) { - // $('body').append(data); - // }, - // 'html' - // ); - // + xhr.onreadystatechange = empty + xhr.abort() + ajaxError(null, 'timeout', xhr, settings) + }, settings.timeout) + + // avoid sending empty string (#319) + xhr.send(settings.data ? settings.data : null) + return xhr + } + + $.get = function(url, success){ return $.ajax({ url: url, success: success }) } + $.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 }); - }; - - // ### $.getJSON - // - // Load JSON from the server using GET request - // - // *Arguments:* - // - // url — url to which the request is sent - // success — callback that is executed if the request succeeds - // - // *Example:* - // - // $.getJSON( - // '/projects/42', - // function (json) { - // projects.push(json); - // } - // ); - // + if ($.isFunction(data)) dataType = dataType || success, success = data, data = null + return $.ajax({ type: 'POST', url: url, data: data, success: success, dataType: dataType }) + } + $.getJSON = function(url, success){ - return $.ajax({ url: url, success: success, dataType: 'json' }); - }; - - // ### $.fn.load - // - // Load data from the server into an element - // - // *Arguments:* - // - // url — url to which the request is sent - // [success] — callback that is executed if the request succeeds - // - // *Examples:* - // - // $('#project_container').get( - // '/projects/42', - // function () { - // alert('Project was successfully loaded'); - // } - // ); - // - // $('#project_comments').get( - // '/projects/42 #comments', - // function () { - // alert('Comments was successfully loaded'); - // } - // ); - // + return $.ajax({ url: url, success: success, dataType: 'json' }) + } + $.fn.load = function(url, success){ - if (!this.length) return this; - var self = this, parts = url.split(/\s/), selector; - if (parts.length > 1) url = parts[0], selector = parts[1]; + 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){ self.html(selector ? - $(document.createElement('div')).html(response).find(selector).html() - : response); - success && success.call(self); - }); - return this; - }; + $('
').html(response.replace(rscript, "")).find(selector) + : response) + success && success.apply(self, arguments) + }) + return this + } - var escape = encodeURIComponent; + var escape = encodeURIComponent function serialize(params, obj, traditional, scope){ - var array = $.isArray(obj); + var array = $.isArray(obj) $.each(obj, function(key, value) { - if (scope) key = traditional ? scope : scope + '[' + (array ? '' : key) + ']'; + if (scope) key = traditional ? scope : scope + '[' + (array ? '' : key) + ']' // handle data in serializeArray() format - if (!scope && array) params.add(value.name, value.value); + if (!scope && array) params.add(value.name, value.value) // recurse into nested objects else if (traditional ? $.isArray(value) : isObject(value)) - serialize(params, value, traditional, key); - else params.add(key, value); - }); - } - - // ### $.param - // - // Encode object as a string of URL-encoded key-value pairs - // - // *Arguments:* - // - // obj — object to serialize - // [traditional] — perform shallow serialization - // - // *Example:* - // - // $.param( { name: 'Zepto.js', version: '0.6' } ); - // + 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', '+'); - }; -})(Zepto); -// Zepto.js -// (c) 2010, 2011 Thomas Fuchs -// Zepto.js may be freely distributed under the MIT license. - -(function ($) { - - // ### $.fn.serializeArray - // - // Encode a set of form elements as an array of names and values - // - // *Example:* - // - // $('#login_form').serializeArray(); - // - // returns - // - // [ - // { - // name: 'email', - // value: 'koss@nocorp.me' - // }, - // { - // name: 'password', - // value: '123456' - // } - // ] - // + var params = [] + params.add = function(k, v){ this.push(escape(k) + '=' + escape(v)) } + serialize(params, obj, traditional) + return params.join('&').replace(/%20/g, '+') + } +})(Zepto) +;(function ($) { $.fn.serializeArray = function () { - var result = [], el; + var result = [], el $( Array.prototype.slice.call(this.get(0).elements) ).each(function () { - el = $(this); - var type = el.attr('type'); - if ( + el = $(this) + var type = el.attr('type') + if (this.nodeName.toLowerCase() != 'fieldset' && !this.disabled && type != 'submit' && type != 'reset' && type != 'button' && - ((type != 'radio' && type != 'checkbox') || this.checked) - ) { + ((type != 'radio' && type != 'checkbox') || this.checked)) result.push({ name: el.attr('name'), value: el.val() - }); - } - }); - return result; - }; - - // ### $.fn.serialize - // - // - // Encode a set of form elements as a string for submission - // - // *Example:* - // - // $('#login_form').serialize(); - // - // returns - // - // "email=koss%40nocorp.me&password=123456" - // + }) + }) + return result + } + $.fn.serialize = function () { - var result = []; + var result = [] this.serializeArray().forEach(function (elm) { - result.push( encodeURIComponent(elm.name) + '=' + encodeURIComponent(elm.value) ); - }); - return result.join('&'); - }; - - // ### $.fn.submit - // - // Bind or trigger the submit event for a form - // - // *Examples:* - // - // To bind a handler for the submit event: - // - // $('#login_form').submit(function (e) { - // alert('Form was submitted!'); - // e.preventDefault(); - // }); - // - // To trigger form submit: - // - // $('#login_form').submit(); - // + result.push( encodeURIComponent(elm.name) + '=' + encodeURIComponent(elm.value) ) + }) + return result.join('&') + } + $.fn.submit = function (callback) { if (callback) this.bind('submit', callback) else if (this.length) { - var event = $.Event('submit'); - this.eq(0).trigger(event); + var event = $.Event('submit') + this.eq(0).trigger(event) if (!event.defaultPrevented) this.get(0).submit() } - return this; + return this } -})(Zepto); -// Zepto.js -// (c) 2010, 2011 Thomas Fuchs -// Zepto.js may be freely distributed under the MIT license. +})(Zepto) +;(function($) { + var data = {}, dataAttr = $.fn.data, camelize = $.camelCase, + exp = $.expando = 'Zepto' + (+new Date()) -(function($){ - var touch = {}, touchTimeout; + // Get value from node: + // 1. first try key as given, + // 2. then try camelized key, + // 3. fall back to reading "data-*" attribute. + function getData(node, name) { + var id = node[exp], store = id && data[id] + if (name === undefined) return store || setData(node) + else { + if (store) { + if (name in store) return store[name] + var camelName = camelize(name) + if (camelName in store) return store[camelName] + } + return dataAttr.call($(node), name) + } + } - function parentIfText(node){ - return 'tagName' in node ? node : node.parentNode; + // Store value under camelized key on node + function setData(node, name, value) { + var id = node[exp] || (node[exp] = ++$.uuid), + store = data[id] || (data[id] = attributeData(node)) + if (name !== undefined) store[camelize(name)] = value + return store } - function swipeDirection(x1, x2, y1, y2){ - var xDelta = Math.abs(x1 - x2), yDelta = Math.abs(y1 - y2); - if (xDelta >= yDelta) { - return (x1 - x2 > 0 ? 'Left' : 'Right'); - } else { - return (y1 - y2 > 0 ? 'Up' : 'Down'); - } + // Read all "data-*" attributes from a node + function attributeData(node) { + var store = {} + $.each(node.attributes, function(i, attr){ + if (attr.name.indexOf('data-') == 0) + store[camelize(attr.name.replace('data-', ''))] = + $.zepto.deserializeValue(attr.value) + }) + return store } - var longTapDelay = 750; - function longTap(){ - if (touch.last && (Date.now() - touch.last >= longTapDelay)) { - $(touch.target).trigger('longTap'); - touch = {}; - } + $.fn.data = function(name, value) { + return value === undefined ? + // set multiple values via object + $.isPlainObject(name) ? + this.each(function(i, node){ + $.each(name, function(key, value){ setData(node, key, value) }) + }) : + // get value from first element + this.length == 0 ? undefined : getData(this[0], name) : + // set value on all elements + this.each(function(){ setData(this, name, value) }) } - $(document).ready(function(){ - $(document.body).bind('touchstart', function(e){ - var now = Date.now(), delta = now - (touch.last || now); - touch.target = 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; - setTimeout(longTap, longTapDelay); - }).bind('touchmove', function(e){ - touch.x2 = e.touches[0].pageX; - touch.y2 = e.touches[0].pageY; - }).bind('touchend', function(e){ - if (touch.isDoubleTap) { - $(touch.target).trigger('doubleTap'); - touch = {}; - } else if (touch.x2 > 0 || touch.y2 > 0) { - (Math.abs(touch.x1 - touch.x2) > 30 || Math.abs(touch.y1 - touch.y2) > 30) && - $(touch.target).trigger('swipe') && - $(touch.target).trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2))); - touch.x1 = touch.x2 = touch.y1 = touch.y2 = touch.last = 0; - } else if ('last' in touch) { - touchTimeout = setTimeout(function(){ - touchTimeout = null; - $(touch.target).trigger('tap') - touch = {}; - }, 250); - } - }).bind('touchcancel', function(){ touch = {} }); - }); + $.fn.removeData = function(names) { + if (typeof names == 'string') names = names.split(/\s+/) + return this.each(function(){ + var id = this[exp], store = id && data[id] + if (store) $.each(names, function(){ delete store[camelize(this)] }) + }) + } +})(Zepto) +;(function($){ + var touch = {}, + touchTimeout, tapTimeout, swipeTimeout, + longTapDelay = 750, longTapTimeout + + function parentIfText(node) { + return 'tagName' in node ? node : node.parentNode + } - ['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown', 'doubleTap', 'tap', 'longTap'].forEach(function(m){ - $.fn[m] = function(callback){ return this.bind(m, callback) } - }); -})(Zepto); -// Zepto.js -// (c) 2010, 2011 Thomas Fuchs -// Zepto.js may be freely distributed under the MIT license. - -(function($, undefined){ - var document = window.document, docElem = document.documentElement, - origShow = $.fn.show, origHide = $.fn.hide, origToggle = $.fn.toggle, - speeds = { _default: 400, fast: 200, slow: 600 }; - - function translateSpeed(speed) { - return typeof speed == 'number' ? speed : (speeds[speed] || speeds._default); - } - - function anim(el, speed, opacity, scale, callback) { - if (typeof speed == 'function' && !callback) callback = speed, speed = undefined; - var props = { opacity: opacity }; - if (scale) { - if ($.fx.transforms3d) props.scale3d = scale + ',1'; - else props.scale = scale; - el.css($.fx.cssPrefix + 'transform-origin', '0 0'); + 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 longTap() { + longTapTimeout = null + if (touch.last) { + touch.el.trigger('longTap') + touch = {} } - return el.anim(props, translateSpeed(speed) / 1000, null, callback); - } - - function hide(el, speed, scale, callback) { - return anim(el, speed, 0, scale, function(){ - origHide.call($(this)); - callback && callback.call(this); - }); - } - - $.fn.show = function(speed, callback) { - origShow.call(this); - if (speed === undefined) speed = 0; - else this.css('opacity', 0); - return anim(this, speed, 1, '1,1', callback); - }; - - $.fn.hide = function(speed, callback) { - if (speed === undefined) return origHide.call(this); - else return hide(this, speed, '0,0', callback); - } - - $.fn.toggle = function(speed, callback) { - if (speed === undefined || typeof speed == 'boolean') return origToggle.call(this, speed); - else return this[this.css('display') == 'none' ? 'show' : 'hide'](speed, callback); - }; - - $.fn.fadeTo = function(speed, opacity, callback) { - return anim(this, speed, opacity, null, callback); - }; - - $.fn.fadeIn = function(speed, callback) { - var target = this.css('opacity') - if (target > 0) this.css('opacity', 0) - else target = 1 - return origShow.call(this).fadeTo(speed, target, callback); - }; - - $.fn.fadeOut = function(speed, callback) { - return hide(this, speed, null, callback); - }; - - $.fn.fadeToggle = function(speed, callback) { - var hidden = this.css('opacity') == 0 || this.css('display') == 'none'; - return this[hidden ? 'fadeIn' : 'fadeOut'](speed, callback); - }; - - $.extend($.fx, { - speeds: speeds, - // feature detection for 3D transforms adapted from Modernizr - transforms3d: (function(props){ - var ret = false; - $.each(props, function(i, prop){ - if (docElem.style[prop] !== undefined) { - ret = i != 1 || webkitTransforms3d(); - return false; - } - }); - return ret; - })('perspectiveProperty WebkitPerspective MozPerspective OPerspective msPerspective'.split(' ')) - }); - - function webkitTransforms3d() { - var ret, div = document.createElement('div'), - testEl = document.createElement('div'), - css = '@media (-webkit-transform-3d){#zeptotest{left:9px;position:absolute}}', - style = ['­', ''].join(''); - - div.innerHTML += style; - testEl.id = 'zeptotest'; - div.appendChild(testEl); - docElem.appendChild(div); - ret = testEl.offsetLeft === 9; - div.parentNode.removeChild(div); - return ret; - } -})(Zepto); -// Zepto.js -// (c) 2010, 2011 Thomas Fuchs -// Zepto.js may be freely distributed under the MIT license. - -// The following code is heavily inspired by jQuery's $.fn.data() - -(function($) { - var data = {}, dataAttr = $.fn.data, - uuid = $.uuid = +new Date(), - exp = $.expando = 'Zepto' + uuid; + } - function getData(node, name) { - var id = node[exp], store = id && data[id]; - return name === undefined ? store || setData(node) : - (store && store[name]) || dataAttr.call($(node), name); + function cancelLongTap() { + if (longTapTimeout) clearTimeout(longTapTimeout) + longTapTimeout = null } - function setData(node, name, value) { - var id = node[exp] || (node[exp] = ++uuid), - store = data[id] || (data[id] = {}); - if (name !== undefined) store[name] = value; - return store; - }; + function cancelAll() { + if (touchTimeout) clearTimeout(touchTimeout) + if (tapTimeout) clearTimeout(tapTimeout) + if (swipeTimeout) clearTimeout(swipeTimeout) + if (longTapTimeout) clearTimeout(longTapTimeout) + touchTimeout = tapTimeout = swipeTimeout = longTapTimeout = null + touch = {} + } - $.fn.data = function(name, value) { - return value === undefined ? - this.length == 0 ? undefined : getData(this[0], name) : - this.each(function(idx){ - setData(this, name, $.isFunction(value) ? - value.call(this, idx, getData(this, name)) : value); - }); - }; -})(Zepto); + $(document).ready(function(){ + var now, delta + + $(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() + + // swipe + if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > 30) || + (touch.y2 && Math.abs(touch.y1 - touch.y2) > 30)) + + swipeTimeout = setTimeout(function() { + touch.el.trigger('swipe') + touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2))) + touch = {} + }, 0) + + // normal tap + else if ('last' in touch) + + // delay by one tick so we can cancel the 'tap' event if 'scroll' fires + // ('tap' fires before 'scroll') + tapTimeout = setTimeout(function() { + + // trigger universal 'tap' with the option to cancelTouch() + // (cancelTouch cancels processing of single vs double taps for faster 'tap' response) + var event = $.Event('tap') + event.cancelTouch = cancelAll + touch.el.trigger(event) + + // trigger double tap immediately + if (touch.isDoubleTap) { + touch.el.trigger('doubleTap') + touch = {} + } + + // trigger single tap after 250ms of inactivity + else { + touchTimeout = setTimeout(function(){ + touchTimeout = null + touch.el.trigger('singleTap') + touch = {} + }, 250) + } + + }, 0) + + }) + .bind('touchcancel', cancelAll) + + $(window).bind('scroll', cancelAll) + }) + + ;['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown', 'doubleTap', 'tap', 'singleTap', 'longTap'].forEach(function(m){ + $.fn[m] = function(callback){ return this.bind(m, callback) } + }) +})(Zepto)