zepto.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. (function(undefined){
  2. if (String.prototype.trim === undefined) // fix for iOS 3.2
  3. String.prototype.trim = function(){ return this.replace(/^\s+/, '').replace(/\s+$/, '') };
  4. // For iOS 3.x
  5. // from https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/reduce
  6. if (Array.prototype.reduce === undefined)
  7. Array.prototype.reduce = function(fun){
  8. if(this === void 0 || this === null) throw new TypeError();
  9. var t = Object(this), len = t.length >>> 0, k = 0, accumulator;
  10. if(typeof fun != 'function') throw new TypeError();
  11. if(len == 0 && arguments.length == 1) throw new TypeError();
  12. if(arguments.length >= 2)
  13. accumulator = arguments[1];
  14. else
  15. do{
  16. if(k in t){
  17. accumulator = t[k++];
  18. break;
  19. }
  20. if(++k >= len) throw new TypeError();
  21. } while (true);
  22. while (k < len){
  23. if(k in t) accumulator = fun.call(undefined, accumulator, t[k], k, t);
  24. k++;
  25. }
  26. return accumulator;
  27. };
  28. })();
  29. var Zepto = (function() {
  30. var undefined, key, css, $$, classList,
  31. emptyArray = [], slice = emptyArray.slice,
  32. document = window.document,
  33. elementDisplay = {}, classCache = {},
  34. getComputedStyle = document.defaultView.getComputedStyle,
  35. fragmentRE = /^\s*<[^>]+>/,
  36. container = document.createElement('div');
  37. function isF(value) { return ({}).toString.call(value) == "[object Function]" }
  38. function isO(value) { return value instanceof Object }
  39. function isA(value) { return value instanceof Array }
  40. function compact(array) { return array.filter(function(item){ return item !== undefined && item !== null }) }
  41. function flatten(array) { return [].concat.apply([], array) }
  42. function camelize(str) { return str.replace(/-+(.)?/g, function(match, chr){ return chr ? chr.toUpperCase() : '' }) }
  43. function uniq(array) { return array.filter(function(item,index,array){ return array.indexOf(item) == index }) }
  44. function classRE(name){
  45. return name in classCache ?
  46. classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)'));
  47. }
  48. function defaultDisplay(nodeName) {
  49. var element, display;
  50. if (!elementDisplay[nodeName]) {
  51. element = document.createElement(nodeName);
  52. document.body.insertAdjacentElement("beforeEnd", element);
  53. display = getComputedStyle(element, '').getPropertyValue("display");
  54. element.parentNode.removeChild(element);
  55. display == "none" && (display = "block");
  56. elementDisplay[nodeName] = display;
  57. }
  58. return elementDisplay[nodeName];
  59. }
  60. function fragment(html) {
  61. container.innerHTML = ('' + html).trim();
  62. return slice.call(container.childNodes);
  63. }
  64. function Z(dom, selector){
  65. dom = dom || emptyArray;
  66. dom.__proto__ = Z.prototype;
  67. dom.selector = selector || '';
  68. return dom;
  69. }
  70. function $(selector, context){
  71. if (!selector) return Z();
  72. if (context !== undefined) return $(context).find(selector);
  73. else if (isF(selector)) return $(document).ready(selector);
  74. else if (selector instanceof Z) return selector;
  75. else {
  76. var dom;
  77. if (isA(selector)) dom = compact(selector);
  78. else if (selector instanceof Element || selector === window || selector === document)
  79. dom = [selector], selector = null;
  80. else if (fragmentRE.test(selector)) dom = fragment(selector);
  81. else if (selector.nodeType && selector.nodeType == 3) dom = [selector];
  82. else dom = $$(document, selector);
  83. return Z(dom, selector);
  84. }
  85. }
  86. $.extend = function(target, source){ for (key in source) target[key] = source[key]; return target }
  87. $.qsa = $$ = function(element, selector){ return slice.call(element.querySelectorAll(selector)) }
  88. function filtered(nodes, selector){
  89. return selector === undefined ? $(nodes) : $(nodes).filter(selector);
  90. }
  91. function funcArg(context, arg, idx, payload){
  92. return isF(arg) ? arg.call(context, idx, payload) : arg;
  93. }
  94. $.isFunction = isF;
  95. $.isObject = isO;
  96. $.isArray = isA;
  97. $.fn = {
  98. forEach: emptyArray.forEach,
  99. map: emptyArray.map,
  100. reduce: emptyArray.reduce,
  101. push: emptyArray.push,
  102. indexOf: emptyArray.indexOf,
  103. concat: emptyArray.concat,
  104. ready: function(callback){
  105. if (document.readyState == 'complete' || document.readyState == 'loaded') callback();
  106. document.addEventListener('DOMContentLoaded', callback, false); return this;
  107. },
  108. get: function(idx){ return idx === undefined ? this : this[idx] },
  109. size: function(){ return this.length },
  110. remove: function(){ return this.each(function(){ this.parentNode.removeChild(this) }) },
  111. each: function(callback){
  112. this.forEach(function(el, idx){ callback.call(el, idx, el) });
  113. return this;
  114. },
  115. filter: function(selector){
  116. return $([].filter.call(this, function(element){
  117. return $$(element.parentNode, selector).indexOf(element) >= 0;
  118. }));
  119. },
  120. add:function(selector,context){
  121. return $(uniq(this.concat($(selector,context))));
  122. },
  123. is: function(selector){
  124. return this.length > 0 && $(this[0]).filter(selector).length > 0;
  125. },
  126. not: function(selector){
  127. var nodes=[];
  128. if (isF(selector) && selector.call !== undefined)
  129. this.each(function(idx){
  130. if (!selector.call(this,idx)) nodes.push(this);
  131. });
  132. else {
  133. var ignores = slice.call(
  134. typeof selector == 'string' ?
  135. this.filter(selector) :
  136. selector instanceof NodeList ? selector : $(selector));
  137. slice.call(this).forEach(function(el){
  138. if (ignores.indexOf(el) < 0) nodes.push(el);
  139. });
  140. }
  141. return $(nodes);
  142. },
  143. eq: function(idx){ return $(this[idx]) },
  144. first: function(){ return $(this[0]) },
  145. last: function(){ return $(this[this.length - 1]) },
  146. find: function(selector){
  147. var result;
  148. if (this.length == 1) result = $$(this[0], selector);
  149. else result = flatten(this.map(function(el){ return $$(el, selector) }));
  150. return $(result);
  151. },
  152. closest: function(selector, context){
  153. var node = this[0], nodes = $$(context !== undefined ? context : document, selector);
  154. if (nodes.length === 0) node = null;
  155. while(node && node !== document && nodes.indexOf(node) < 0) node = node.parentNode;
  156. return $(node !== document && node);
  157. },
  158. parents: function(selector){
  159. var ancestors = [], nodes = this;
  160. while (nodes.length > 0)
  161. nodes = compact(nodes.map(function(node){
  162. if ((node = node.parentNode) && node !== document && ancestors.indexOf(node) < 0) {
  163. ancestors.push(node);
  164. return node;
  165. }
  166. }));
  167. return filtered(ancestors, selector);
  168. },
  169. parent: function(selector){
  170. return filtered(uniq(compact(this.pluck('parentNode'))), selector);
  171. },
  172. children: function(selector){
  173. return filtered(flatten(this.map(function(el){ return slice.call(el.children) })), selector);
  174. },
  175. siblings: function(selector){
  176. return filtered(flatten(this.map(function(el){
  177. return slice.call(el.parentNode.children).filter(function(child){ return child!==el });
  178. })), selector);
  179. },
  180. empty: function(){ return this.each(function(){ this.innerHTML = '' }) },
  181. pluck: function(property){ return this.map(function(element){ return element[property] }) },
  182. show: function(){
  183. return this.each(function() {
  184. this.style.display == "none" && (this.style.display = null);
  185. if (getComputedStyle(this, '').getPropertyValue("display") == "none") {
  186. this.style.display = defaultDisplay(this.nodeName)
  187. }
  188. })
  189. },
  190. replaceWith: function(newContent) {
  191. return this.each(function() {
  192. var element = $(this),
  193. prev = element.prev();
  194. element.remove();
  195. prev.after(newContent);
  196. });
  197. },
  198. hide: function(){
  199. return this.css("display", "none")
  200. },
  201. toggle: function(){
  202. return this.css("display") == "none" ? this.show() : this.hide();
  203. },
  204. prev: function(){ return $(this.pluck('previousElementSibling')) },
  205. next: function(){ return $(this.pluck('nextElementSibling')) },
  206. html: function(html){
  207. return html === undefined ?
  208. (this.length > 0 ? this[0].innerHTML : null) :
  209. this.each(function(idx){ this.innerHTML = funcArg(this, html, idx, this.innerHTML) });
  210. },
  211. text: function(text){
  212. return text === undefined ?
  213. (this.length > 0 ? this[0].innerText : null) :
  214. this.each(function(){ this.innerText = text });
  215. },
  216. attr: function(name, value){
  217. return (typeof name == 'string' && value === undefined) ?
  218. (this.length > 0 && this[0].nodeName == 'INPUT' && this[0].type == 'text' && name == 'value') ? (this.val()) :
  219. (this.length > 0 ? this[0].getAttribute(name) || (name in this[0] ? this[0][name] : undefined) : undefined) :
  220. this.each(function(idx){
  221. if (isO(name)) for (key in name) this.setAttribute(key, name[key])
  222. else this.setAttribute(name, funcArg(this, value, idx, this.getAttribute(name)));
  223. });
  224. },
  225. removeAttr: function(name) {
  226. return this.each(function() { this.removeAttribute(name); });
  227. },
  228. data: function(name, value){
  229. return this.attr('data-' + name, value);
  230. },
  231. val: function(value){
  232. return (value === undefined) ?
  233. (this.length > 0 ? this[0].value : null) :
  234. this.each(function(){
  235. this.value = value;
  236. });
  237. },
  238. offset: function(){
  239. if(this.length==0) return null;
  240. var obj = this[0].getBoundingClientRect();
  241. return {
  242. left: obj.left + document.body.scrollLeft,
  243. top: obj.top + document.body.scrollTop,
  244. width: obj.width,
  245. height: obj.height
  246. };
  247. },
  248. css: function(property, value){
  249. if (value === undefined && typeof property == 'string')
  250. return this[0].style[camelize(property)] || getComputedStyle(this[0], '').getPropertyValue(property);
  251. css = '';
  252. for (key in property) css += key + ':' + property[key] + ';';
  253. if (typeof property == 'string') css = property + ':' + value;
  254. return this.each(function() { this.style.cssText += ';' + css });
  255. },
  256. index: function(element){
  257. return this.indexOf($(element)[0]);
  258. },
  259. hasClass: function(name){
  260. return classRE(name).test(this[0].className);
  261. },
  262. addClass: function(name){
  263. return this.each(function(idx) {
  264. classList = [];
  265. var cls = this.className, newName = funcArg(this, name, idx, cls);
  266. newName.split(/\s+/g).forEach(function(klass) {
  267. if (!$(this).hasClass(klass)) {
  268. classList.push(klass)
  269. }
  270. }, this);
  271. classList.length && (this.className += (cls ? " " : "") + classList.join(" "))
  272. })
  273. },
  274. removeClass: function(name){
  275. return this.each(function(idx) {
  276. classList = this.className;
  277. funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass) {
  278. classList = classList.replace(classRE(klass), " ")
  279. });
  280. this.className = classList.trim()
  281. })
  282. },
  283. toggleClass: function(name, when){
  284. return this.each(function(idx){
  285. var cls = this.className, newName = funcArg(this, name, idx, cls);
  286. ((when !== undefined && !when) || $(this).hasClass(newName)) ?
  287. $(this).removeClass(newName) : $(this).addClass(newName)
  288. });
  289. },
  290. submit: function () {
  291. return this.each(function () {
  292. try {
  293. // Submit first form element
  294. this.submit();
  295. return;
  296. } catch(e) {};
  297. });
  298. }
  299. };
  300. ['width', 'height'].forEach(function(property){
  301. $.fn[property] = function(){ var offset = this.offset(); return offset ? offset[property] : null }
  302. });
  303. var adjacencyOperators = [ 'prepend', 'after', 'before', 'append' ];
  304. function insert(operator, element, other) {
  305. var parent = (!operator || operator == 3) ? element : element.parentNode;
  306. parent.insertBefore(other,
  307. !operator ? parent.firstChild : // prepend
  308. operator == 1 ? element.nextSibling : // after
  309. operator == 2 ? element : // before
  310. null); // append
  311. }
  312. adjacencyOperators.forEach(function(key, operator) {
  313. $.fn[key] = function(html){
  314. if (typeof(html) != 'object')
  315. html = fragment(html);
  316. return this.each(function(index, element){
  317. if (html.length || html instanceof Z) {
  318. dom = html;
  319. for (var i=0; i<dom.length; i++) {
  320. var e = dom[operator < 2 ? dom.length-i-1 : i];
  321. insert(operator, element, e);
  322. }
  323. } else {
  324. insert(operator, element, html);
  325. }
  326. });
  327. };
  328. });
  329. var reverseAdjacencyOperators = [ 'append', 'prepend' ];
  330. reverseAdjacencyOperators.forEach(function(key) {
  331. $.fn[key+'To'] = function(html){
  332. if (typeof(html) != 'object')
  333. html = fragment(html);
  334. html[key](this);
  335. return this;
  336. };
  337. });
  338. Z.prototype = $.fn;
  339. return $;
  340. })();
  341. '$' in window || (window.$ = Zepto);
  342. (function($){
  343. var $$ = $.qsa, handlers = {}, _zid = 1;
  344. function zid(element) {
  345. return element._zid || (element._zid = _zid++);
  346. }
  347. function findHandlers(element, event, fn, selector) {
  348. event = parse(event);
  349. if (event.ns) var matcher = matcherFor(event.ns);
  350. return (handlers[zid(element)] || []).filter(function(handler) {
  351. return handler
  352. && (!event.e || handler.e == event.e)
  353. && (!event.ns || matcher.test(handler.ns))
  354. && (!fn || handler.fn == fn)
  355. && (!selector || handler.sel == selector);
  356. });
  357. }
  358. function parse(event) {
  359. var parts = ('' + event).split('.');
  360. return {e: parts[0], ns: parts.slice(1).sort().join(' ')};
  361. }
  362. function matcherFor(ns) {
  363. return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)');
  364. }
  365. function add(element, events, fn, selector, delegate){
  366. var id = zid(element), set = (handlers[id] || (handlers[id] = []));
  367. events.split(/\s/).forEach(function(event){
  368. var callback = delegate || fn;
  369. var proxyfn = function(event) { return callback(event, event.data) };
  370. var handler = $.extend(parse(event), {fn: fn, proxy: proxyfn, sel: selector, del: delegate, i: set.length});
  371. set.push(handler);
  372. element.addEventListener(handler.e, proxyfn, false);
  373. });
  374. }
  375. function remove(element, events, fn, selector){
  376. var id = zid(element);
  377. (events || '').split(/\s/).forEach(function(event){
  378. findHandlers(element, event, fn, selector).forEach(function(handler){
  379. delete handlers[id][handler.i];
  380. element.removeEventListener(handler.e, handler.proxy, false);
  381. });
  382. });
  383. }
  384. $.event = { add: add, remove: remove }
  385. $.fn.bind = function(event, callback){
  386. return this.each(function(){
  387. add(this, event, callback);
  388. });
  389. };
  390. $.fn.unbind = function(event, callback){
  391. return this.each(function(){
  392. remove(this, event, callback);
  393. });
  394. };
  395. $.fn.one = function(event, callback){
  396. return this.each(function(){
  397. var self = this;
  398. add(this, event, function wrapper(){
  399. callback();
  400. remove(self, event, arguments.callee);
  401. });
  402. });
  403. };
  404. var eventMethods = ['preventDefault', 'stopImmediatePropagation', 'stopPropagation'];
  405. function createProxy(event) {
  406. var proxy = $.extend({originalEvent: event}, event);
  407. eventMethods.forEach(function(key) {
  408. proxy[key] = function() {return event[key].apply(event, arguments)};
  409. });
  410. return proxy;
  411. }
  412. $.fn.delegate = function(selector, event, callback){
  413. return this.each(function(i, element){
  414. add(element, event, callback, selector, function(e, data){
  415. var target = e.target, nodes = $$(element, selector);
  416. while (target && nodes.indexOf(target) < 0) target = target.parentNode;
  417. if (target && !(target === element) && !(target === document)) {
  418. callback.call(target, $.extend(createProxy(e), {
  419. currentTarget: target, liveFired: element
  420. }), data);
  421. }
  422. });
  423. });
  424. };
  425. $.fn.undelegate = function(selector, event, callback){
  426. return this.each(function(){
  427. remove(this, event, callback, selector);
  428. });
  429. }
  430. $.fn.live = function(event, callback){
  431. $(document.body).delegate(this.selector, event, callback);
  432. return this;
  433. };
  434. $.fn.die = function(event, callback){
  435. $(document.body).undelegate(this.selector, event, callback);
  436. return this;
  437. };
  438. $.fn.trigger = function(event, data){
  439. return this.each(function(){
  440. var e = document.createEvent('Events');
  441. e.initEvent(event, true, true)
  442. e.data = data;
  443. this.dispatchEvent(e);
  444. });
  445. };
  446. })(Zepto);
  447. (function($){
  448. function detect(ua){
  449. var ua = ua, os = {},
  450. android = ua.match(/(Android)\s+([\d.]+)/),
  451. iphone = ua.match(/(iPhone\sOS)\s([\d_]+)/),
  452. ipad = ua.match(/(iPad).*OS\s([\d_]+)/),
  453. webos = ua.match(/(webOS)\/([\d.]+)/),
  454. blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/);
  455. if (android) os.android = true, os.version = android[2];
  456. if (iphone) os.ios = true, os.version = iphone[2].replace(/_/g, '.'), os.iphone = true;
  457. if (ipad) os.ios = true, os.version = ipad[2].replace(/_/g, '.'), os.ipad = true;
  458. if (webos) os.webos = true, os.version = webos[2];
  459. if (blackberry) os.blackberry = true, os.version = blackberry[2];
  460. return os;
  461. }
  462. $.os = detect(navigator.userAgent);
  463. $.__detect = detect;
  464. var v = navigator.userAgent.match(/WebKit\/([\d.]+)/);
  465. $.browser = v ? { webkit: true, version: v[1] } : { webkit: false };
  466. })(Zepto);
  467. (function($, undefined){
  468. $.fn.anim = function(properties, duration, ease, callback){
  469. var transforms = [], opacity, key;
  470. for (key in properties)
  471. if (key === 'opacity') opacity = properties[key];
  472. else transforms.push(key + '(' + properties[key] + ')');
  473. $.isFunction(callback) && this.one('webkitTransitionEnd', callback);
  474. return this.css({
  475. '-webkit-transition': 'all ' + (duration !== undefined ? duration : 0.5) + 's ' + (ease || ''),
  476. '-webkit-transform': transforms.join(' '),
  477. opacity: opacity
  478. });
  479. }
  480. })(Zepto);
  481. (function($){
  482. var jsonpID = 0,
  483. isObject = $.isObject,
  484. key;
  485. function empty() {}
  486. $.ajaxJSONP = function(options){
  487. var jsonpString = 'jsonp' + ++jsonpID,
  488. script = document.createElement('script');
  489. window[jsonpString] = function(data){
  490. options.success(data);
  491. delete window[jsonpString];
  492. };
  493. script.src = options.url.replace(/=\?/, '=' + jsonpString);
  494. $('head').append(script);
  495. };
  496. $.ajaxSettings = {
  497. type: 'GET',
  498. beforeSend: empty, success: empty, error: empty, complete: empty,
  499. accepts: {
  500. script: 'text/javascript, application/javascript',
  501. json: 'application/json',
  502. xml: 'application/xml, text/xml',
  503. html: 'text/html',
  504. text: 'text/plain'
  505. }
  506. };
  507. $.ajax = function(options){
  508. options = options || {};
  509. var settings = $.extend({}, options);
  510. for (key in $.ajaxSettings) if (!settings[key]) settings[key] = $.ajaxSettings[key];
  511. if (/=\?/.test(settings.url)) return $.ajaxJSONP(settings);
  512. if (!settings.url) settings.url = window.location.toString();
  513. if (settings.data && !settings.contentType) settings.contentType = 'application/x-www-form-urlencoded';
  514. if (isObject(settings.data)) settings.data = $.param(settings.data);
  515. if (settings.type.match(/get/i) && settings.data) {
  516. var queryString = settings.data;
  517. if (settings.url.match(/\?.*=/)) {
  518. queryString = '&' + queryString;
  519. } else if (queryString[0] != '?') {
  520. queryString = '?' + queryString;
  521. }
  522. settings.url += queryString;
  523. }
  524. var mime = settings.accepts[settings.dataType],
  525. xhr = new XMLHttpRequest();
  526. settings.headers = $.extend({'X-Requested-With': 'XMLHttpRequest'}, settings.headers || {});
  527. if (mime) settings.headers['Accept'] = mime;
  528. xhr.onreadystatechange = function(){
  529. if (xhr.readyState == 4) {
  530. var result, error = false;
  531. if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 0) {
  532. if (mime == 'application/json') {
  533. try { result = JSON.parse(xhr.responseText); }
  534. catch (e) { error = e; }
  535. }
  536. else result = xhr.responseText;
  537. if (error) settings.error(xhr, 'parsererror', error);
  538. else settings.success(result, 'success', xhr);
  539. } else {
  540. error = true;
  541. settings.error(xhr, 'error');
  542. }
  543. settings.complete(xhr, error ? 'error' : 'success');
  544. }
  545. };
  546. xhr.open(settings.type, settings.url, true);
  547. if (settings.beforeSend(xhr, settings) === false) {
  548. xhr.abort();
  549. return false;
  550. }
  551. if (settings.contentType) settings.headers['Content-Type'] = settings.contentType;
  552. for (name in settings.headers) xhr.setRequestHeader(name, settings.headers[name]);
  553. xhr.send(settings.data);
  554. return xhr;
  555. };
  556. $.get = function(url, success){ $.ajax({ url: url, success: success }) };
  557. $.post = function(url, data, success, dataType){
  558. if ($.isFunction(data)) dataType = dataType || success, success = data, data = null;
  559. $.ajax({ type: 'POST', url: url, data: data, success: success, dataType: dataType });
  560. };
  561. $.getJSON = function(url, success){ $.ajax({ url: url, success: success, dataType: 'json' }) };
  562. $.fn.load = function(url, success){
  563. if (!this.length) return this;
  564. var self = this, parts = url.split(/\s/), selector;
  565. if (parts.length > 1) url = parts[0], selector = parts[1];
  566. $.get(url, function(response){
  567. self.html(selector ?
  568. $(document.createElement('div')).html(response).find(selector).html()
  569. : response);
  570. success && success();
  571. });
  572. return this;
  573. };
  574. $.param = function(obj, v){
  575. var result = [], add = function(key, value){
  576. result.push(encodeURIComponent(v ? v + '[' + key + ']' : key)
  577. + '=' + encodeURIComponent(value));
  578. },
  579. isObjArray = $.isArray(obj);
  580. for(key in obj)
  581. if(isObject(obj[key]))
  582. result.push($.param(obj[key], (v ? v + '[' + key + ']' : key)));
  583. else
  584. add(isObjArray ? '' : key, obj[key]);
  585. return result.join('&').replace('%20', '+');
  586. };
  587. })(Zepto);
  588. (function($){
  589. var touch = {}, touchTimeout;
  590. function parentIfText(node){
  591. return 'tagName' in node ? node : node.parentNode;
  592. }
  593. function swipeDirection(x1, x2, y1, y2){
  594. var xDelta = Math.abs(x1 - x2), yDelta = Math.abs(y1 - y2);
  595. if (xDelta >= yDelta) {
  596. return (x1 - x2 > 0 ? 'Left' : 'Right');
  597. } else {
  598. return (y1 - y2 > 0 ? 'Up' : 'Down');
  599. }
  600. }
  601. $(document).ready(function(){
  602. $(document.body).bind('touchstart', function(e){
  603. var now = Date.now(), delta = now - (touch.last || now);
  604. touch.target = parentIfText(e.touches[0].target);
  605. touchTimeout && clearTimeout(touchTimeout);
  606. touch.x1 = e.touches[0].pageX;
  607. touch.y1 = e.touches[0].pageY;
  608. if (delta > 0 && delta <= 250) touch.isDoubleTap = true;
  609. touch.last = now;
  610. }).bind('touchmove', function(e){
  611. touch.x2 = e.touches[0].pageX;
  612. touch.y2 = e.touches[0].pageY;
  613. }).bind('touchend', function(e){
  614. if (touch.isDoubleTap) {
  615. $(touch.target).trigger('doubleTap');
  616. touch = {};
  617. } else if (touch.x2 > 0 || touch.y2 > 0) {
  618. (Math.abs(touch.x1 - touch.x2) > 30 || Math.abs(touch.y1 - touch.y2) > 30) &&
  619. $(touch.target).trigger('swipe') &&
  620. $(touch.target).trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2)));
  621. touch.x1 = touch.x2 = touch.y1 = touch.y2 = touch.last = 0;
  622. } else if ('last' in touch) {
  623. touchTimeout = setTimeout(function(){
  624. touchTimeout = null;
  625. $(touch.target).trigger('tap')
  626. touch = {};
  627. }, 250);
  628. }
  629. }).bind('touchcancel', function(){ touch = {} });
  630. });
  631. ['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown', 'doubleTap', 'tap'].forEach(function(m){
  632. $.fn[m] = function(callback){ return this.bind(m, callback) }
  633. });
  634. })(Zepto);