From f2a1238cc3f0b4e316c6879c343a247d5ad8b5ee Mon Sep 17 00:00:00 2001 From: sbosse Date: Mon, 21 Jul 2025 23:22:08 +0200 Subject: [PATCH] Mon 21 Jul 22:43:21 CEST 2025 --- js/ui/cordova/www/js/app.js | 5759 +++++++++++++++++++++++++++++++++++ 1 file changed, 5759 insertions(+) create mode 100644 js/ui/cordova/www/js/app.js diff --git a/js/ui/cordova/www/js/app.js b/js/ui/cordova/www/js/app.js new file mode 100644 index 0000000..88812a4 --- /dev/null +++ b/js/ui/cordova/www/js/app.js @@ -0,0 +1,5759 @@ +/** + ** ============================== + ** O O O OOOO + ** O O O O O O + ** O O O O O O + ** OOOO OOOO O OOO OOOO + ** O O O O O O O + ** O O O O O O O + ** OOOO OOOO O O OOOO + ** ============================== + ** Dr. Stefan Bosse http://www.sblab.de + ** + ** COPYRIGHT: THIS SOFTWARE, EXECUTABLE AND SOURCE CODE IS OWNED + ** BY THE AUTHOR(S). + ** THIS SOURCE CODE MAY NOT BE COPIED, EXTRACTED, + ** MODIFIED, OR OTHERWISE USED IN A CONTEXT + ** OUTSIDE OF THE SOFTWARE SYSTEM. + ** + ** $AUTHORS: Stefan Bosse, Kik Interactive, Matteo Spinelli + ** $INITIAL: (C) 2006-2019 bLAB + ** $CREATED: 12-12-18 by sbosse. + ** $VERSION: 1.1.10 + ** $ORIGINAL: + ** $INFO: + ** + ** CORDOVA/NW.JS APP.js Framework + ** + ** App.js v3.0.8 + ** Instant mobile web app creation + ** Copyright (c) 2012 Kik Interactive, http://kik.com + ** Released under the MIT license + ** + ** iScroll v4.1.6 + ** Copyright (c) 2011 Matteo Spinelli, http://cubiq.org + ** Released under the MIT license + ** + ** $ENDOFINFO + ** +*/ +var Swapper = function(c, b) { + function a(e, d, f, g) { + a._swapper(e, d, f, g) + } + if (c && c.fn) { + c.extend(c.fn, { + swapper: function(d, e, f) { + d = c(d)[0]; + this.forEach(function(g) { + a._swapper(g, d, e, f) + }); + return this + } + }) + } + if (b && b.fn) { + b.fn.swapper = function(d, e, f) { + d = b(d)[0]; + this.each(function() { + a._swapper(this, d, e, f) + }); + return this + } + } + return a +}(window.Zepto, window.jQuery); +Swapper._os = function(f, d) { + var c, a, b; + if (b = /\bCPU.*OS (\d+(_\d+)?)/i.exec(f)) { + c = "ios"; + a = b[1].replace("_", ".") + } else { + if (b = /\bAndroid (\d+(\.\d+)?)/.exec(f)) { + c = "android"; + a = b[1] + } + } + var e = { + name: c, + version: a && d(a) + }; + e[c] = true; + return e +}(navigator.userAgent, parseFloat); +Swapper._isNode = function(a, b) { + return function(d) { + if (!d) { + return false + } + try { + return (d instanceof a) || (d instanceof b) + } catch (c) {} + if (typeof d !== "object") { + return false + } + if (typeof d.nodeType !== "number") { + return false + } + if (typeof d.nodeName !== "string") { + return false + } + return true + } +}(Node, HTMLElement); +Swapper._isInDOM = function(a) { + return function(c, b) { + if (!b && !a(c)) { + throw TypeError("element must be a DOM node, got " + c) + } + while (c = c.parentNode) { + if (c === document) { + return true + } + } + return false + } +}(Swapper._isNode); +Swapper._insertBefore = function() { + return function(a, b) { + b.parentNode.insertBefore(a, b) + } +}(); +Swapper._insertAfter = function() { + return function(a, c) { + var b = c.parentNode; + if (b.lastchild === c) { + b.appendChild(a) + } else { + b.insertBefore(a, c.nextSibling) + } + } +}(); +Swapper._removeNode = function() { + return function(a) { + if (a.parentNode) { + a.parentNode.removeChild(a) + } + } +}(); +Swapper._setTransform = function() { + return function(b, a) { + b.style["-webkit-transform"] = a; + b.style["-moz-transform"] = a; + b.style["-ms-transform"] = a; + b.style["-o-transform"] = a; + b.style.transform = a + } +}(); +Swapper._setTransition = function() { + return function(a, b) { + if (b) { + a.style["-webkit-transition"] = "-webkit-" + b; + a.style["-moz-transition"] = "-moz-" + b; + a.style["-ms-transition"] = "-ms-" + b; + a.style["-o-transition"] = "-o-" + b; + a.style.transition = b + } else { + a.style["-webkit-transition"] = ""; + a.style["-moz-transition"] = ""; + a.style["-ms-transition"] = ""; + a.style["-o-transition"] = ""; + a.style.transition = "" + } + } +}(); +Swapper._getStyles = function(a) { + return function(c, d) { + var b; + if (d) { + b = c.style + } else { + b = a.defaultView.getComputedStyle(c, null) + } + return { + "-webkit-transition": b["-webkit-transition"], + "-moz-transition": b["-moz-transition"], + "-ms-transition": b["-ms-transition"], + "-o-transition": b["-o-transition"], + transition: b.transition, + display: b.display, + opacity: b.opacity, + top: b.top, + left: b.left, + height: b.height, + width: b.width, + position: b.position + } + } +}(document); +Swapper._easings = { + linear: "linear", + ease: "ease", + "ease-in": "ease-in", + "ease-out": "ease-out", + "ease-in-out": "ease-in-out", + "step-start": "step-start", + "step-end": "step-end" +}; +Swapper._transitions = { + fade: [{ + fade: true + }, { + fade: true + }], + "fade-on": [{ + fade: true + }, {}], + "fade-off": [{}, { + fade: true + }, true], + "scale-in": [{ + transform: "scale(0.01)" + }, {}], + "scale-out": [{}, { + transform: "scale(0.01)" + }, true], + "rotate-left": [{ + transform: "rotateY(-180deg) perspective(360px)", + fade: true + }, { + transform: "rotateY( 180deg) perspective(360px)", + fade: true + }], + "rotate-right": [{ + transform: "rotateY( 180deg) perspective(360px)", + fade: true + }, { + transform: "rotateY(-180deg) perspective(360px)", + fade: true + }], + "cube-left": [{ + transform: "translate3d( 50%,0,0) rotateY(-90deg) perspective(360px)" + }, { + transform: "translate3d(-50%,0,0) rotateY( 90deg) perspective(360px)" + }], + "cube-right": [{ + transform: "translate3d(-50%,0,0) rotateY( 90deg) perspective(360px)" + }, { + transform: "translate3d( 50%,0,0) rotateY(-90deg) perspective(360px)" + }], + "swap-left": [{ + transform: "translate3d( 65%,0,0) rotateY( 90deg) perspective(360px)" + }, { + transform: "translate3d(-65%,0,0) rotateY(-90deg) perspective(360px)" + }], + "swap-right": [{ + transform: "translate3d(-65%,0,0) rotateY(-90deg) perspective(360px)" + }, { + transform: "translate3d( 65%,0,0) rotateY( 90deg) perspective(360px)" + }], + "explode-in": [{ + fade: true, + transform: "scale(1.25)" + }, {}], + "explode-out": [{}, { + fade: true, + transform: "scale(1.25)" + }, true], + "implode-in": [{}, { + fade: true, + transform: "scale(0.60)" + }, true], + "implode-out": [{ + fade: true, + transform: "scale(0.80)" + }, {}], + "slide-left": [{ + transform: "translate3d( 100%,0,0)" + }, { + transform: "translate3d(-100%,0,0)" + }], + "slide-right": [{ + transform: "translate3d(-100%,0,0)" + }, { + transform: "translate3d( 100%,0,0)" + }], + "slide-up": [{ + transform: "translate3d(0, 100%,0)" + }, { + transform: "translate3d(0,-100%,0)" + }], + "slide-down": [{ + transform: "translate3d(0,-100%,0)" + }, { + transform: "translate3d(0, 100%,0)" + }], + "slideon-left": [{ + transform: "translate3d(-100%,0,0)" + }, {}], + "slideoff-left": [{}, { + transform: "translate3d(-100%,0,0)" + }, true], + "slideon-right": [{ + transform: "translate3d(100%,0,0)" + }, {}], + "slideoff-right": [{}, { + transform: "translate3d(100%,0,0)" + }, true], + "slideon-up": [{ + transform: "translate3d(0,-100%,0)" + }, {}], + "slideoff-up": [{}, { + transform: "translate3d(0,-100%,0)" + }, true], + "slideon-down": [{ + transform: "translate3d(0,100%,0)" + }, {}], + "slideoff-down": [{}, { + transform: "translate3d(0,100%,0)" + }, true], + "slideon-left-ios": [{ + transform: "translate3d(100%,0,0)" + }, { + transform: "translate3d(-30%,0,0)" + }], + "slideoff-right-ios": [{ + transform: "translate3d(-30%,0,0)" + }, { + transform: "translate3d(100%,0,0)" + }, true], + "glideon-right": [{ + transform: "translate3d(110%,0,0)" + }, { + transform: "translate3d(-20%,0,0)" + }], + "glideoff-right": [{ + transform: "translate3d(-20%,0,0)" + }, { + transform: "translate3d(110%,0,0)" + }, true], + "glideon-left": [{ + transform: "translate3d(-110%,0,0)" + }, { + transform: "translate3d(20%,0,0)" + }], + "glideoff-left": [{ + transform: "translate3d(20%,0,0)" + }, { + transform: "translate3d(-110%,0,0)" + }, true], + "glideon-down": [{ + transform: "translate3d(0,110%,0)" + }, { + transform: "translate3d(0,-20%,0)" + }], + "glideoff-down": [{ + transform: "translate3d(0,-20%,0)" + }, { + transform: "translate3d(0,110%,0)" + }, true], + "glideon-up": [{ + transform: "translate3d(0,-110%,0)" + }, { + transform: "translate3d(0,20%,0)" + }], + "glideoff-up": [{ + transform: "translate3d(0,20%,0)" + }, { + transform: "translate3d(0,-110%,0)" + }, true], + "android-l-in": [{ + transform: "translate3d(0,6%,0)", + fade: true + }, {}], + "android-l-out": [{}, { + transform: "translate3d(0,6%,0)", + fade: true + }, true] +}; +Swapper._validate = function(e, f, d) { + return { + element: c, + options: b, + callback: a + }; + + function c(g) { + if (!e(g)) { + throw TypeError("element must be a DOM node, got " + g) + } + } + + function b(g) { + switch (typeof g) { + case "string": + g = { + transition: g + }; + break; + case "undefined": + g = {}; + break; + case "object": + break; + default: + throw TypeError("options must be an object if defined, got " + g) + } + switch (typeof g.transition) { + case "string": + if (!(g.transition in f) && (g.transition !== "instant")) { + throw TypeError(g.transition + " is not a valid transition") + } + break; + case "undefined": + break; + default: + throw TypeError("transition must be a string if defined, got " + g.transition) + } + switch (typeof g.duration) { + case "number": + if (g.duration < 0) { + throw TypeError("duration must be a non-negative integer, got " + g.duration) + } + break; + case "undefined": + break; + default: + throw TypeError("duration must be a number if defined, got " + g.duration) + } + switch (typeof g.easing) { + case "string": + if (!(g.easing in d) && (g.easing.substr(0, 13) !== "cubic-bezier(")) { + throw TypeError(g.easing + " is not a valid easing") + } + break; + case "undefined": + break; + default: + throw TypeError("easing must be a string if defined, got " + g.easing) + } + return g + } + + function a(g) { + switch (typeof g) { + case "undefined": + g = function() {}; + break; + case "function": + break; + default: + throw TypeError("callback must be a function if defined, got " + g) + } + return g + } +}(Swapper._isNode, Swapper._transitions, Swapper._easings); +Swapper._swapper = function(k, w, f, e, A, x, g, h, j, D, l, q, m, s) { + var a = "translate3d(0,0,0) scale(1)", + E = "fade", + z = "ease-in-out"; + var p = (k.ios && (Math.floor(k.version) === 5)); + + function r(G, F, H, I) { + q.element(G); + q.element(F); + if (typeof H === "function") { + I = H; + H = {} + } + H = q.options(H); + I = q.callback(I); + if (G._swapper) { + throw Error("elem1 is currently being swapped") + } else { + if (F._swapper) { + throw Error("elem2 is currently being swapped") + } + } + if (!f(G, true)) { + throw Error("elem1 must be in the DOM to be swapped") + } + G._swapper = true; + F._swapper = true; + x(F); + o(G, F, H, function() { + G._swapper = false; + F._swapper = false; + I() + }) + } + + function o(O, N, P, M) { + if (P.transition === "instant") { + A(N, O); + x(O); + M(); + return + } + var L = D[P.transition || E], + K = P.easing || z, + J = P.duration || 300; + if (K.substr(0, 13) !== "cubic-bezier(") { + K = l[K] + } + A(N, O); + var I = j(O), + H = j(N), + G = j(O, true), + F = j(N, true); + C(O, N, I, H); + if (L[2]) { + e(N, O) + } + N.style.opacity = "0"; + u(O, N); + setTimeout(function() { + N.style.opacity = H.opacity; + b(O, N, L); + setTimeout(function() { + n(O, N, J, K); + setTimeout(function() { + y(O, N, L); + B(O, N, I, H, L, J, function() { + x(O); + t(O, N, J, K); + setTimeout(function() { + v(O, N, G, F, L); + d(O, N, G, F); + setTimeout(function() { + c(O, N, G, F); + M() + }, 0) + }, 0) + }) + }, 0) + }, 50) + }, 0) + } + + function C(G, F, I, H) { + var J = G.getBoundingClientRect(); + if (I.display !== "none") { + if (p) { + F.style.position = "absolute" + } else { + F.style.position = "fixed" + } + F.style.top = J.top + "px"; + F.style.left = J.left + "px" + } + F.style.height = H.height || I.height; + F.style.width = H.width || I.width + } + + function d(G, F, I, H) { + F.style.position = H.position; + F.style.top = H.top; + F.style.left = H.left; + F.style.height = H.height; + F.style.width = H.width + } + + function b(G, F, H) { + g(G, a); + g(F, H[0].transform || a); + if (H[0].fade) { + F.style.opacity = "0" + } + if (H[1].fade) { + G.style.opacity = "1" + } + } + + function y(G, F, H) { + g(G, H[1].transform || a); + g(F, a); + if (H[0].fade) { + F.style.opacity = "1" + } + if (H[1].fade) { + G.style.opacity = "0" + } + } + + function v(G, F, I, H, J) { + g(G, ""); + g(F, ""); + if (J[0].fade) { + F.style.opacity = H.opacity + } + if (J[1].fade) { + G.style.opacity = I.opacity + } + } + + function n(G, F, H, J) { + var I = "transform " + (H / 1000) + "s " + J + ",opacity " + (H / 1000) + "s " + J; + h(G, I); + h(F, I) + } + + function t(G, F, H, I) { + h(G, ""); + h(F, "") + } + + function u(G, F) { + h(G, ""); + h(F, "") + } + + function c(G, F, I, H) { + G.style["-webkit-transition"] = I["-webkit-transition"]; + G.style["-moz-transition"] = I["-moz-transition"]; + G.style["-ms-transition"] = I["-ms-transition"]; + G.style["-o-transition"] = I["-o-transition"]; + G.style.transition = I.transition; + F.style["-webkit-transition"] = H["-webkit-transition"]; + F.style["-moz-transition"] = H["-moz-transition"]; + F.style["-ms-transition"] = H["-ms-transition"]; + F.style["-o-transition"] = H["-o-transition"]; + F.style.transition = H.transition + } + + function i(F, G) { + if (F.display === "none") { + return false + } + if (G.fade) { + return true + } + if (!G.transform) { + return false + } else { + if (G.transform === a) { + return false + } else { + return true + } + } + } + + function B(Q, N, H, F, K, I, M) { + var G; + if (i(F, K[0])) { + G = N; + P() + } else { + if (i(H, K[1])) { + G = Q; + P() + } else { + setTimeout(L, I) + } + } + + function P() { + G.addEventListener("webkitTransitionEnd", L, false); + G.addEventListener("transitionend", L, false); + G.addEventListener("oTransitionEnd", L, false); + G.addEventListener("otransitionend", L, false); + G.addEventListener("MSTransitionEnd", L, false); + G.addEventListener("transitionend", L, false) + } + + function O() { + G.removeEventListener("webkitTransitionEnd", L); + G.removeEventListener("transitionend", L); + G.removeEventListener("oTransitionEnd", L); + G.removeEventListener("otransitionend", L); + G.removeEventListener("MSTransitionEnd", L); + G.removeEventListener("transitionend", L) + } + var J = false; + + function L(R) { + if (J || !R || !R.target || (R.target !== G)) { + return + } + J = true; + if (G) { + O() + } + M() + } + } + return r +}(Swapper._os, Swapper._isNode, Swapper._isInDOM, Swapper._insertBefore, Swapper._insertAfter, Swapper._removeNode, Swapper._setTransform, Swapper._setTransition, Swapper._getStyles, Swapper._transitions, Swapper._easings, Swapper._validate, window, document); +var Clickable = function(c, b) { + function a() { + a._enableClicking.apply(this, arguments) + } + a.touchable = function() { + return a._os.touchable + }; + a.sticky = function() { + a._enableStickyClick.apply(this, arguments) + }; + a.unsticky = function(d) { + if (typeof d === "object" && d && typeof d._removeStickyClick === "function") { + d._removeStickyClick() + } + }; + if (b && b.fn) { + b.fn.clickable = function(d) { + this.each(function() { + a._enableClicking(this, d) + }); + return this + }; + b.fn.stickyClick = function(d) { + this.each(function() { + a._enableStickyClick(this, d) + }); + return this + }; + b.fn.unstickyClick = function(d) { + this.each(function() { + a.unsticky(this) + }); + return this + } + } + if (c && c.fn) { + c.extend(c.fn, { + clickable: function(d) { + this.forEach(function(e) { + a._enableClicking(e, d) + }); + return this + }, + stickyClick: function(d) { + this.forEach(function(e) { + a._enableStickyClick(e, d) + }); + return this + }, + unstickyClick: function(d) { + this.forEach(function(e) { + a.unsticky(this) + }); + return this + } + }) + } + return a +}(window.Zepto, window.jQuery); +Clickable._os = function(f, d) { + var c, a, b; + if (b = /\bCPU.*OS (\d+(_\d+)?)/i.exec(f)) { + c = "ios"; + a = b[1].replace("_", ".") + } else { + if (b = /\bAndroid (\d+(\.\d+)?)/.exec(f)) { + c = "android"; + a = b[1] + } + } + var e = { + name: c, + version: a && d(a), + touchable: !!c + }; + e[c] = true; + return e +}(navigator.userAgent, parseFloat); +Clickable._trimString = function(a) { + var b = /^\s+|\s+$/g; + return function(c) { + return a(c).replace(b, "") + } +}(String); +Clickable._isDOMNode = function(a, b) { + return function(d) { + if (!d) { + return false + } + try { + return (d instanceof a) || (d instanceof b) + } catch (c) {} + if (typeof d !== "object") { + return false + } + if (typeof d.nodeType !== "number") { + return false + } + if (typeof d.nodeName !== "string") { + return false + } + return true + } +}(Node, HTMLElement); +Clickable._isInDOM = function() { + return function(a) { + while (a = a.parentNode) { + if (a === document) { + return true + } + } + return false + } +}(); +Clickable._bindEvents = function() { + return function(c, b) { + for (var a in b) { + if (c.addEventListener) { + c.addEventListener(a, b[a], false) + } else { + if (c.attachEvent) { + c.attachEvent("on" + a, b[a]) + } + } + } + } +}(); +Clickable._unbindEvents = function() { + return function(c, b) { + for (var a in b) { + if (c.removeEventListener) { + c.removeEventListener(a, b[a]) + } + } + } +}(); +Clickable._addClass = function() { + return function(b, a) { + b.className += " " + a + } +}(); +Clickable._removeClass = function(a) { + return function(c, b) { + c.className = a(c.className.replace(new RegExp("\\b" + b + "\\b"), "")) + } +}(Clickable._trimString); +Clickable._enableClicking = function(h, o, a, f, c, k, n) { + var i = "active", + m = "data-clickable-class", + g = 40; + var p = false, + l = !!h.ios; + + function b(L, O) { + if (!o(L)) { + throw TypeError("element " + L + " must be a DOM element") + } + if (L._clickable) { + return + } + L._clickable = true; + switch (typeof O) { + case "undefined": + O = i; + break; + case "string": + break; + default: + throw TypeError("active class " + O + " must be a string") + } + var E = false, + q = false, + G, F, J, K, s; + L.setAttribute(m, O); + L.style["-webkit-tap-highlight-color"] = "rgba(255,255,255,0)"; + v(); + return; + + function M(Q, R) { + E = true; + J = +new Date(); + G = Q; + F = R; + K = j(L); + if (K) { + s = K.scrollTop; + K.addEventListener("scroll", A, true) + } + } + + function I() { + if (K) { + K.removeEventListener("scroll", A) + } + K = null; + s = null; + G = null; + F = null; + E = false + } + + function A() { + B() + } + + function P() { + return E + } + + function t() { + k(L, O) + } + + function r() { + n(L, O) + } + + function v() { + f(L, { + click: x + }); + if (!h.touchable) { + f(L, { + mousedown: C, + mousemove: D, + mouseout: D, + mouseup: z + }); + return + } + if (h.ios) { + f(L, { + DOMNodeInsertedIntoDocument: N, + DOMNodeRemovedFromDocument: y + }); + if (a(L)) { + N() + } + } else { + N() + } + } + + function N() { + f(L, { + touchstart: w, + touchmove: H, + touchcancel: B, + touchend: u + }) + } + + function y() { + c(L, { + touchstart: w, + touchmove: H, + touchcancel: B, + touchend: u + }) + } + + function x(Q) { + Q = Q || window.event; + if (!L.disabled && q) { + q = false; + setTimeout(function() { + p = false + }, 0) + } else { + if (Q.stopImmediatePropagation) { + Q.stopImmediatePropagation() + } + Q.preventDefault(); + Q.stopPropagation(); + Q.cancelBubble = true; + Q.returnValue = false; + return false + } + } + + function C(Q) { + q = false; + if (L.disabled || !e(Q.target, L)) { + Q.preventDefault(); + I(); + return + } + M(Q.clientX, Q.clientY); + t() + } + + function D(Q) { + Q.preventDefault(); + I(); + q = false; + r() + } + + function z(Q) { + if (L.disabled) { + Q.preventDefault(); + I(); + q = false; + return + } + if (!P()) { + Q.preventDefault(); + q = false + } else { + q = true + } + I(); + r() + } + + function w(Q) { + q = false; + if (p || L.disabled || (Q.touches.length !== 1) || !e(Q.target, L)) { + I(); + return + } + p = true; + var R = Q.changedTouches[0]; + M(R.clientX, R.clientY); + if (K) { + if (K._isScrolling || (s < 0) || (K.scrollHeight < s)) { + I(); + return + } + } + var R = J; + setTimeout(function() { + if (P() && (R === J)) { + t() + } + }, g) + } + + function B(Q) { + q = false; + I(); + if (Q) { + p = false + } + if (L.disabled) { + return + } + r() + } + + function H(R) { + var Q = document.elementFromPoint(R.touches[0].pageX, R.touches[0].pageY); + if (L !== Q) { + B(R) + } + } + + function u(V) { + var R = P(), + S = K, + T = s, + Q = G, + W = F; + B(); + if (!R || L.disabled) { + p = false; + return + } + if (S) { + if (S._isScrolling || (S.scrollTop !== T)) { + return + } + } + if (!V.stopImmediatePropagation) { + q = true; + return + } + var U = +new Date() - J; + if (U > g) { + q = true; + d(L, Q, W) + } else { + t(); + setTimeout(function() { + r(); + q = true; + d(L, Q, W) + }, 1) + } + } + } + + function e(r, q) { + do { + if (r === q) { + return true + } else { + if (r._clickable) { + return false + } + } + } while (r = r.parentNode); + return false + } + + function d(s, q, t) { + var r = document.createEvent("MouseEvents"); + r.initMouseEvent("click", true, true, window, 1, q || 0, t || 0, q || 0, t || 0, false, false, false, false, 0, null); + s.dispatchEvent(r) + } + + function j(q) { + if (!h.ios || (h.version < 5)) { + return + } + while (q = q.parentNode) { + if (q._scrollable) { + if (q._iScroll) { + return + } + return q + } + } + } + return b +}(Clickable._os, Clickable._isDOMNode, Clickable._isInDOM, Clickable._bindEvents, Clickable._unbindEvents, Clickable._addClass, Clickable._removeClass); +Clickable._enableStickyClick = function(a, c, f) { + var d = "data-clickable-class"; + + function e(i, h, g) { + if (!c(i)) { + throw TypeError("button must be a DOM element, got " + i) + } + switch (typeof h) { + case "string": + break; + case "function": + g = h; + h = undefined; + break; + default: + throw TypeError("button active class must be a string if defined, got " + h) + } + if (typeof g !== "function") { + throw TypeError("sticky click handler must be a function, got " + g) + } + f(i, h); + var j = b(i, g); + i.addEventListener("click", j, false); + if (i._removeStickyClick) { + i._removeStickyClick = function() { + i.removeEventListener("click", j) + } + } + } + + function b(i, h) { + var j = false, + g = i.getAttribute(d); + return function() { + if (j) { + return + } + j = true; + var k = false, + n; + i.disabled = true; + i.className += " " + g; + try { + n = h.call(i, m) + } catch (l) { + if (window.console && window.console.error) { + if ((typeof l === "object") && l.stack) { + window.console.error(l.stack) + } else { + window.console.error(l + "") + } + } + m() + } + if (n === false) { + m() + } + + function m() { + if (k) { + return + } + k = true; + j = false; + if (i.disabled) { + i.disabled = false; + i.className = a(i.className.replace(new RegExp("\\b" + g + "\\b", "g"), "")) + } + } + } + } + return e +}(Clickable._trimString, Clickable._isDOMNode, Clickable._enableClicking); +var iScroll = function(an, Z) { + function ah(f) { + if ("" === am) { + return f + } + f = f.charAt(0).toUpperCase() + f.substr(1); + return am + f + } + var ao = Math, + P = Z.createElement("div").style, + am; + a: { + for (var aj = ["t", "webkitT", "MozT", "msT", "OT"], Y, X = 0, k = aj.length; X < k; X++) { + if (Y = aj[X] + "ransform", Y in P) { + am = aj[X].substr(0, aj[X].length - 1); + break a + } + } + am = !1 + } + var ak = am ? "-" + am.toLowerCase() + "-" : "", + ai = ah("transform"), + g = ah("transitionProperty"), + ad = ah("transitionDuration"), + e = ah("transformOrigin"), + d = ah("transitionTimingFunction"), + i = ah("transitionDelay"), + ag = /android/gi.test(navigator.appVersion), + W = /iphone|ipad/gi.test(navigator.appVersion), + aj = /hp-tablet/gi.test(navigator.appVersion), + V = ah("perspective") in P, + al = "ontouchstart" in an && !aj, + T = !!am, + c = ah("transition") in P, + af = "onorientationchange" in an ? "orientationchange" : "resize", + ac = al ? "touchstart" : "mousedown", + U = al ? "touchmove" : "mousemove", + S = al ? "touchend" : "mouseup", + R = al ? "touchcancel" : "mouseup", + ab = "Moz" == am ? "DOMMouseScroll" : "mousewheel", + aa; + aa = !1 === am ? !1 : { + "": "transitionend", + webkit: "webkitTransitionEnd", + Moz: "transitionend", + O: "oTransitionEnd", + ms: "MSTransitionEnd" + }[am]; + var b = an.requestAnimationFrame || an.webkitRequestAnimationFrame || an.mozRequestAnimationFrame || an.oRequestAnimationFrame || an.msRequestAnimationFrame || function(f) { + return setTimeout(f, 1) + }, + Q = an.cancelRequestAnimationFrame || an.webkitCancelAnimationFrame || an.webkitCancelRequestAnimationFrame || an.mozCancelRequestAnimationFrame || an.oCancelRequestAnimationFrame || an.msCancelRequestAnimationFrame || clearTimeout, + ae = V ? " translateZ(0)" : "", + aj = function(f, h) { + var l = this, + j; + l.wrapper = "object" == typeof f ? f : Z.getElementById(f); + l.wrapper.style.overflow = "hidden"; + l.scroller = l.wrapper.children[0]; + l.options = { + hScroll: !0, + vScroll: !0, + x: 0, + y: 0, + bounce: !0, + bounceLock: !1, + momentum: !0, + lockDirection: !0, + useTransform: !0, + useTransition: !1, + topOffset: 0, + checkDOMChanges: !1, + handleClick: !0, + hScrollbar: !0, + vScrollbar: !0, + fixedScrollbar: ag, + hideScrollbar: W, + fadeScrollbar: W && V, + scrollbarClass: "", + zoom: !1, + zoomMin: 1, + zoomMax: 4, + doubleTapZoom: 2, + wheelAction: "scroll", + snap: !1, + snapThreshold: 1, + onRefresh: null, + onBeforeScrollStart: function(m) { + m.preventDefault() + }, + onScrollStart: null, + onBeforeScrollMove: null, + onScrollMove: null, + onBeforeScrollEnd: null, + onScrollEnd: null, + onTouchEnd: null, + onDestroy: null, + onZoomStart: null, + onZoom: null, + onZoomEnd: null + }; + for (j in h) { + l.options[j] = h[j] + } + l.x = l.options.x; + l.y = l.options.y; + l.options.useTransform = T && l.options.useTransform; + l.options.hScrollbar = l.options.hScroll && l.options.hScrollbar; + l.options.vScrollbar = l.options.vScroll && l.options.vScrollbar; + l.options.zoom = l.options.useTransform && l.options.zoom; + l.options.useTransition = c && l.options.useTransition; + l.options.zoom && ag && (ae = ""); + l.scroller.style[g] = l.options.useTransform ? ak + "transform" : "top left"; + l.scroller.style[ad] = "0"; + l.scroller.style[e] = "0 0"; + l.options.useTransition && (l.scroller.style[d] = "cubic-bezier(0.33,0.66,0.66,1)"); + l.options.useTransform ? l.scroller.style[ai] = "translate(" + l.x + "px," + l.y + "px)" + ae : l.scroller.style.cssText += ";position:absolute;top:" + l.y + "px;left:" + l.x + "px"; + l.options.useTransition && (l.options.fixedScrollbar = !0); + l.refresh(); + l._bind(af, an); + l._bind(ac); + al || (l._bind("mouseout", l.wrapper), "none" != l.options.wheelAction && l._bind(ab)); + l.options.checkDOMChanges && (l.checkDOMTime = setInterval(function() { + l._checkDOMChanges() + }, 500)) + }; + aj.prototype = { + enabled: !0, + x: 0, + y: 0, + steps: [], + scale: 1, + currPageX: 0, + currPageY: 0, + pagesX: [], + pagesY: [], + aniTime: null, + wheelZoomCount: 0, + handleEvent: function(f) { + switch (f.type) { + case ac: + if (!al && 0 !== f.button) { + break + } + this._start(f); + break; + case U: + this._move(f); + break; + case S: + case R: + this._end(f); + break; + case af: + this._resize(); + break; + case ab: + this._wheel(f); + break; + case "mouseout": + this._mouseout(f); + break; + case aa: + this._transitionEnd(f) + } + }, + _checkDOMChanges: function() { + !this.moved && (!this.zoomed && !(this.animating || this.scrollerW == this.scroller.offsetWidth * this.scale && this.scrollerH == this.scroller.offsetHeight * this.scale)) && this.refresh() + }, + _scrollbar: function(f) { + var h; + this[f + "Scrollbar"] ? (this[f + "ScrollbarWrapper"] || (h = Z.createElement("div"), this.options.scrollbarClass ? h.className = this.options.scrollbarClass + f.toUpperCase() : h.style.cssText = "position:absolute;z-index:100;" + ("h" == f ? "height:7px;bottom:1px;left:2px;right:" + (this.vScrollbar ? "7" : "2") + "px" : "width:7px;bottom:" + (this.hScrollbar ? "7" : "2") + "px;top:2px;right:1px"), h.style.cssText += ";pointer-events:none;" + ak + "transition-property:opacity;" + ak + "transition-duration:" + (this.options.fadeScrollbar ? "350ms" : "0") + ";overflow:hidden;opacity:" + (this.options.hideScrollbar ? "0" : "1"), this.wrapper.appendChild(h), this[f + "ScrollbarWrapper"] = h, h = Z.createElement("div"), this.options.scrollbarClass || (h.style.cssText = "position:absolute;z-index:100;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);" + ak + "background-clip:padding-box;" + ak + "box-sizing:border-box;" + ("h" == f ? "height:100%" : "width:100%") + ";" + ak + "border-radius:3px;border-radius:3px"), h.style.cssText += ";pointer-events:none;" + ak + "transition-property:" + ak + "transform;" + ak + "transition-timing-function:cubic-bezier(0.33,0.66,0.66,1);" + ak + "transition-duration:0;" + ak + "transform: translate(0,0)" + ae, this.options.useTransition && (h.style.cssText += ";" + ak + "transition-timing-function:cubic-bezier(0.33,0.66,0.66,1)"), this[f + "ScrollbarWrapper"].appendChild(h), this[f + "ScrollbarIndicator"] = h), "h" == f ? (this.hScrollbarSize = this.hScrollbarWrapper.clientWidth, this.hScrollbarIndicatorSize = ao.max(ao.round(this.hScrollbarSize * this.hScrollbarSize / this.scrollerW), 8), this.hScrollbarIndicator.style.width = this.hScrollbarIndicatorSize + "px", this.hScrollbarMaxScroll = this.hScrollbarSize - this.hScrollbarIndicatorSize, this.hScrollbarProp = this.hScrollbarMaxScroll / this.maxScrollX) : (this.vScrollbarSize = this.vScrollbarWrapper.clientHeight, this.vScrollbarIndicatorSize = ao.max(ao.round(this.vScrollbarSize * this.vScrollbarSize / this.scrollerH), 8), this.vScrollbarIndicator.style.height = this.vScrollbarIndicatorSize + "px", this.vScrollbarMaxScroll = this.vScrollbarSize - this.vScrollbarIndicatorSize, this.vScrollbarProp = this.vScrollbarMaxScroll / this.maxScrollY), this._scrollbarPos(f, !0)) : this[f + "ScrollbarWrapper"] && (T && (this[f + "ScrollbarIndicator"].style[ai] = ""), this[f + "ScrollbarWrapper"].parentNode.removeChild(this[f + "ScrollbarWrapper"]), this[f + "ScrollbarWrapper"] = null, this[f + "ScrollbarIndicator"] = null) + }, + _resize: function() { + var f = this; + setTimeout(function() { + f.refresh() + }, ag ? 200 : 0) + }, + _pos: function(f, h) { + this.zoomed || (f = this.hScroll ? f : 0, h = this.vScroll ? h : 0, this.options.useTransform ? this.scroller.style[ai] = "translate(" + f + "px," + h + "px) scale(" + this.scale + ")" + ae : (f = ao.round(f), h = ao.round(h), this.scroller.style.left = f + "px", this.scroller.style.top = h + "px"), this.x = f, this.y = h, this._scrollbarPos("h"), this._scrollbarPos("v")) + }, + _scrollbarPos: function(f, h) { + var j = "h" == f ? this.x : this.y; + this[f + "Scrollbar"] && (j *= this[f + "ScrollbarProp"], 0 > j ? (this.options.fixedScrollbar || (j = this[f + "ScrollbarIndicatorSize"] + ao.round(3 * j), 8 > j && (j = 8), this[f + "ScrollbarIndicator"].style["h" == f ? "width" : "height"] = j + "px"), j = 0) : j > this[f + "ScrollbarMaxScroll"] && (this.options.fixedScrollbar ? j = this[f + "ScrollbarMaxScroll"] : (j = this[f + "ScrollbarIndicatorSize"] - ao.round(3 * (j - this[f + "ScrollbarMaxScroll"])), 8 > j && (j = 8), this[f + "ScrollbarIndicator"].style["h" == f ? "width" : "height"] = j + "px", j = this[f + "ScrollbarMaxScroll"] + (this[f + "ScrollbarIndicatorSize"] - j))), this[f + "ScrollbarWrapper"].style[i] = "0", this[f + "ScrollbarWrapper"].style.opacity = h && this.options.hideScrollbar ? "0" : "1", this[f + "ScrollbarIndicator"].style[ai] = "translate(" + ("h" == f ? j + "px,0)" : "0," + j + "px)") + ae) + }, + _start: function(f) { + var h = al ? f.touches[0] : f, + l, j; + if (this.enabled) { + this.options.onBeforeScrollStart && this.options.onBeforeScrollStart.call(this, f); + (this.options.useTransition || this.options.zoom) && this._transitionTime(0); + this.zoomed = this.animating = this.moved = !1; + this.dirY = this.dirX = this.absDistY = this.absDistX = this.distY = this.distX = 0; + this.options.zoom && (al && 1 < f.touches.length) && (j = ao.abs(f.touches[0].pageX - f.touches[1].pageX), l = ao.abs(f.touches[0].pageY - f.touches[1].pageY), this.touchesDistStart = ao.sqrt(j * j + l * l), this.originX = ao.abs(f.touches[0].pageX + f.touches[1].pageX - 2 * this.wrapperOffsetLeft) / 2 - this.x, this.originY = ao.abs(f.touches[0].pageY + f.touches[1].pageY - 2 * this.wrapperOffsetTop) / 2 - this.y, this.options.onZoomStart && this.options.onZoomStart.call(this, f)); + if (this.options.momentum && (this.options.useTransform ? (l = getComputedStyle(this.scroller, null)[ai].replace(/[^0-9\-.,]/g, "").split(","), j = 1 * l[4], l = 1 * l[5]) : (j = 1 * getComputedStyle(this.scroller, null).left.replace(/[^0-9-]/g, ""), l = 1 * getComputedStyle(this.scroller, null).top.replace(/[^0-9-]/g, "")), j != this.x || l != this.y)) { + this.options.useTransition ? this._unbind(aa) : Q(this.aniTime), this.steps = [], this._pos(j, l) + } + this.absStartX = this.x; + this.absStartY = this.y; + this.startX = this.x; + this.startY = this.y; + this.pointX = h.pageX; + this.pointY = h.pageY; + this.startTime = f.timeStamp || Date.now(); + this.options.onScrollStart && this.options.onScrollStart.call(this, f); + this._bind(U); + this._bind(S); + this._bind(R) + } + }, + _move: function(f) { + var h = al ? f.touches[0] : f, + o = h.pageX - this.pointX, + n = h.pageY - this.pointY, + m = this.x + o, + l = this.y + n, + j = f.timeStamp || Date.now(); + this.options.onBeforeScrollMove && this.options.onBeforeScrollMove.call(this, f); + if (this.options.zoom && al && 1 < f.touches.length) { + m = ao.abs(f.touches[0].pageX - f.touches[1].pageX), l = ao.abs(f.touches[0].pageY - f.touches[1].pageY), this.touchesDist = ao.sqrt(m * m + l * l), this.zoomed = !0, h = 1 / this.touchesDistStart * this.touchesDist * this.scale, h < this.options.zoomMin ? h = 0.5 * this.options.zoomMin * Math.pow(2, h / this.options.zoomMin) : h > this.options.zoomMax && (h = 2 * this.options.zoomMax * Math.pow(0.5, this.options.zoomMax / h)), this.lastScale = h / this.scale, m = this.originX - this.originX * this.lastScale + this.x, l = this.originY - this.originY * this.lastScale + this.y, this.scroller.style[ai] = "translate(" + m + "px," + l + "px) scale(" + h + ")" + ae, this.options.onZoom && this.options.onZoom.call(this, f) + } else { + this.pointX = h.pageX; + this.pointY = h.pageY; + if (0 < m || m < this.maxScrollX) { + m = this.options.bounce ? this.x + o / 2 : 0 <= m || 0 <= this.maxScrollX ? 0 : this.maxScrollX + } + if (l > this.minScrollY || l < this.maxScrollY) { + l = this.options.bounce ? this.y + n / 2 : l >= this.minScrollY || 0 <= this.maxScrollY ? this.minScrollY : this.maxScrollY + } + this.distX += o; + this.distY += n; + this.absDistX = ao.abs(this.distX); + this.absDistY = ao.abs(this.distY); + 6 > this.absDistX && 6 > this.absDistY || (this.options.lockDirection && (this.absDistX > this.absDistY + 5 ? (l = this.y, n = 0) : this.absDistY > this.absDistX + 5 && (m = this.x, o = 0)), this.moved = !0, this._pos(m, l), this.dirX = 0 < o ? -1 : 0 > o ? 1 : 0, this.dirY = 0 < n ? -1 : 0 > n ? 1 : 0, 300 < j - this.startTime && (this.startTime = j, this.startX = this.x, this.startY = this.y), this.options.onScrollMove && this.options.onScrollMove.call(this, f)) + } + }, + _end: function(s) { + if (!(al && 0 !== s.touches.length)) { + var t = this, + r = al ? s.changedTouches[0] : s, + q, p, o = { + dist: 0, + time: 0 + }, + m = { + dist: 0, + time: 0 + }, + n = (s.timeStamp || Date.now()) - t.startTime, + f = t.x, + l = t.y; + t._unbind(U); + t._unbind(S); + t._unbind(R); + t.options.onBeforeScrollEnd && t.options.onBeforeScrollEnd.call(t, s); + if (t.zoomed) { + f = t.scale * t.lastScale, f = Math.max(t.options.zoomMin, f), f = Math.min(t.options.zoomMax, f), t.lastScale = f / t.scale, t.scale = f, t.x = t.originX - t.originX * t.lastScale + t.x, t.y = t.originY - t.originY * t.lastScale + t.y, t.scroller.style[ad] = "200ms", t.scroller.style[ai] = "translate(" + t.x + "px," + t.y + "px) scale(" + t.scale + ")" + ae, t.zoomed = !1, t.refresh(), t.options.onZoomEnd && t.options.onZoomEnd.call(t, s) + } else { + if (t.moved) { + if (300 > n && t.options.momentum) { + o = f ? t._momentum(f - t.startX, n, -t.x, t.scrollerW - t.wrapperW + t.x, t.options.bounce ? t.wrapperW : 0) : o; + m = l ? t._momentum(l - t.startY, n, -t.y, 0 > t.maxScrollY ? t.scrollerH - t.wrapperH + t.y - t.minScrollY : 0, t.options.bounce ? t.wrapperH : 0) : m; + f = t.x + o.dist; + l = t.y + m.dist; + if (0 < t.x && 0 < f || t.x < t.maxScrollX && f < t.maxScrollX) { + o = { + dist: 0, + time: 0 + } + } + if (t.y > t.minScrollY && l > t.minScrollY || t.y < t.maxScrollY && l < t.maxScrollY) { + m = { + dist: 0, + time: 0 + } + } + } + o.dist || m.dist ? (o = ao.max(ao.max(o.time, m.time), 10), t.options.snap && (m = f - t.absStartX, n = l - t.absStartY, ao.abs(m) < t.options.snapThreshold && ao.abs(n) < t.options.snapThreshold ? t.scrollTo(t.absStartX, t.absStartY, 200) : (m = t._snap(f, l), f = m.x, l = m.y, o = ao.max(m.time, o))), t.scrollTo(ao.round(f), ao.round(l), o)) : t.options.snap ? (m = f - t.absStartX, n = l - t.absStartY, ao.abs(m) < t.options.snapThreshold && ao.abs(n) < t.options.snapThreshold ? t.scrollTo(t.absStartX, t.absStartY, 200) : (m = t._snap(t.x, t.y), (m.x != t.x || m.y != t.y) && t.scrollTo(m.x, m.y, m.time))) : t._resetPos(200) + } else { + al && (t.doubleTapTimer && t.options.zoom ? (clearTimeout(t.doubleTapTimer), t.doubleTapTimer = null, t.options.onZoomStart && t.options.onZoomStart.call(t, s), t.zoom(t.pointX, t.pointY, 1 == t.scale ? t.options.doubleTapZoom : 1), t.options.onZoomEnd && setTimeout(function() { + t.options.onZoomEnd.call(t, s) + }, 200)) : this.options.handleClick && (t.doubleTapTimer = setTimeout(function() { + t.doubleTapTimer = null; + for (q = r.target; 1 != q.nodeType;) { + q = q.parentNode + } + "SELECT" != q.tagName && ("INPUT" != q.tagName && "TEXTAREA" != q.tagName) && (p = Z.createEvent("MouseEvents"), p.initMouseEvent("click", !0, !0, s.view, 1, r.screenX, r.screenY, r.clientX, r.clientY, s.ctrlKey, s.altKey, s.shiftKey, s.metaKey, 0, null), p._fake = !0, q.dispatchEvent(p)) + }, t.options.zoom ? 250 : 0))), t._resetPos(200) + } + t.options.onTouchEnd && t.options.onTouchEnd.call(t, s) + } + } + }, + _resetPos: function(f) { + var h = 0 <= this.x ? 0 : this.x < this.maxScrollX ? this.maxScrollX : this.x, + j = this.y >= this.minScrollY || 0 < this.maxScrollY ? this.minScrollY : this.y < this.maxScrollY ? this.maxScrollY : this.y; + if (h == this.x && j == this.y) { + if (this.moved && (this.moved = !1, this.options.onScrollEnd && this.options.onScrollEnd.call(this)), this.hScrollbar && this.options.hideScrollbar && ("webkit" == am && (this.hScrollbarWrapper.style[i] = "300ms"), this.hScrollbarWrapper.style.opacity = "0"), this.vScrollbar && this.options.hideScrollbar) { + "webkit" == am && (this.vScrollbarWrapper.style[i] = "300ms"), this.vScrollbarWrapper.style.opacity = "0" + } + } else { + this.scrollTo(h, j, f || 0) + } + }, + _wheel: function(f) { + var h = this, + l, j; + if ("wheelDeltaX" in f) { + l = f.wheelDeltaX / 12, j = f.wheelDeltaY / 12 + } else { + if ("wheelDelta" in f) { + l = j = f.wheelDelta / 12 + } else { + if ("detail" in f) { + l = j = 3 * -f.detail + } else { + return + } + } + } + if ("zoom" == h.options.wheelAction) { + if (j = h.scale * Math.pow(2, 1 / 3 * (j ? j / Math.abs(j) : 0)), j < h.options.zoomMin && (j = h.options.zoomMin), j > h.options.zoomMax && (j = h.options.zoomMax), j != h.scale) { + !h.wheelZoomCount && h.options.onZoomStart && h.options.onZoomStart.call(h, f), h.wheelZoomCount++, h.zoom(f.pageX, f.pageY, j, 400), setTimeout(function() { + h.wheelZoomCount--; + !h.wheelZoomCount && h.options.onZoomEnd && h.options.onZoomEnd.call(h, f) + }, 400) + } + } else { + l = h.x + l, j = h.y + j, 0 < l ? l = 0 : l < h.maxScrollX && (l = h.maxScrollX), j > h.minScrollY ? j = h.minScrollY : j < h.maxScrollY && (j = h.maxScrollY), 0 > h.maxScrollY && h.scrollTo(l, j, 0) + } + }, + _mouseout: function(f) { + var h = f.relatedTarget; + if (h) { + for (; h = h.parentNode;) { + if (h == this.wrapper) { + return + } + } + } + this._end(f) + }, + _transitionEnd: function(f) { + f.target == this.scroller && (this._unbind(aa), this._startAni()) + }, + _startAni: function() { + var f = this, + h = f.x, + o = f.y, + n = Date.now(), + m, l, j; + f.animating || (f.steps.length ? (m = f.steps.shift(), m.x == h && m.y == o && (m.time = 0), f.animating = !0, f.moved = !0, f.options.useTransition) ? (f._transitionTime(m.time), f._pos(m.x, m.y), f.animating = !1, m.time ? f._bind(aa) : f._resetPos(0)) : (j = function() { + var q = Date.now(), + p; + if (q >= n + m.time) { + f._pos(m.x, m.y); + f.animating = false; + f.options.onAnimationEnd && f.options.onAnimationEnd.call(f); + f._startAni() + } else { + q = (q - n) / m.time - 1; + l = ao.sqrt(1 - q * q); + q = (m.x - h) * l + h; + p = (m.y - o) * l + o; + f._pos(q, p); + if (f.animating) { + f.aniTime = b(j) + } + } + }, j()) : f._resetPos(400)) + }, + _transitionTime: function(f) { + f += "ms"; + this.scroller.style[ad] = f; + this.hScrollbar && (this.hScrollbarIndicator.style[ad] = f); + this.vScrollbar && (this.vScrollbarIndicator.style[ad] = f) + }, + _momentum: function(f, h, n, m, l) { + var h = ao.abs(f) / h, + j = h * h / 0.0012; + 0 < f && j > n ? (n += l / (6 / (0.0006 * (j / h))), h = h * n / j, j = n) : 0 > f && j > m && (m += l / (6 / (0.0006 * (j / h))), h = h * m / j, j = m); + return { + dist: j * (0 > f ? -1 : 1), + time: ao.round(h / 0.0006) + } + }, + _offset: function(f) { + for (var h = -f.offsetLeft, j = -f.offsetTop; f = f.offsetParent;) { + h -= f.offsetLeft, j -= f.offsetTop + } + f != this.wrapper && (h *= this.scale, j *= this.scale); + return { + left: h, + top: j + } + }, + _snap: function(f, h) { + var m, l, j; + j = this.pagesX.length - 1; + m = 0; + for (l = this.pagesX.length; m < l; m++) { + if (f >= this.pagesX[m]) { + j = m; + break + } + } + j == this.currPageX && (0 < j && 0 > this.dirX) && j--; + f = this.pagesX[j]; + l = (l = ao.abs(f - this.pagesX[this.currPageX])) ? 500 * (ao.abs(this.x - f) / l) : 0; + this.currPageX = j; + j = this.pagesY.length - 1; + for (m = 0; m < j; m++) { + if (h >= this.pagesY[m]) { + j = m; + break + } + } + j == this.currPageY && (0 < j && 0 > this.dirY) && j--; + h = this.pagesY[j]; + m = (m = ao.abs(h - this.pagesY[this.currPageY])) ? 500 * (ao.abs(this.y - h) / m) : 0; + this.currPageY = j; + j = ao.round(ao.max(l, m)) || 200; + return { + x: f, + y: h, + time: j + } + }, + _bind: function(f, h, j) { + (h || this.scroller).addEventListener(f, this, !!j) + }, + _unbind: function(f, h, j) { + (h || this.scroller).removeEventListener(f, this, !!j) + }, + destroy: function() { + this.scroller.style[ai] = ""; + this.vScrollbar = this.hScrollbar = !1; + this._scrollbar("h"); + this._scrollbar("v"); + this._unbind(af, an); + this._unbind(ac); + this._unbind(U); + this._unbind(S); + this._unbind(R); + this.options.hasTouch || (this._unbind("mouseout", this.wrapper), this._unbind(ab)); + this.options.useTransition && this._unbind(aa); + this.options.checkDOMChanges && clearInterval(this.checkDOMTime); + this.options.onDestroy && this.options.onDestroy.call(this) + }, + refresh: function() { + var f, h, l, j = 0; + h = 0; + this.scale < this.options.zoomMin && (this.scale = this.options.zoomMin); + this.wrapperW = this.wrapper.clientWidth || 1; + this.wrapperH = this.wrapper.clientHeight || 1; + this.minScrollY = -this.options.topOffset || 0; + this.scrollerW = ao.round(this.scroller.offsetWidth * this.scale); + this.scrollerH = ao.round((this.scroller.offsetHeight + this.minScrollY) * this.scale); + this.maxScrollX = this.wrapperW - this.scrollerW; + this.maxScrollY = this.wrapperH - this.scrollerH + this.minScrollY; + this.dirY = this.dirX = 0; + this.options.onRefresh && this.options.onRefresh.call(this); + this.hScroll = this.options.hScroll && 0 > this.maxScrollX; + this.vScroll = this.options.vScroll && (!this.options.bounceLock && !this.hScroll || this.scrollerH > this.wrapperH); + this.hScrollbar = this.hScroll && this.options.hScrollbar; + this.vScrollbar = this.vScroll && this.options.vScrollbar && this.scrollerH > this.wrapperH; + f = this._offset(this.wrapper); + this.wrapperOffsetLeft = -f.left; + this.wrapperOffsetTop = -f.top; + if ("string" == typeof this.options.snap) { + this.pagesX = []; + this.pagesY = []; + l = this.scroller.querySelectorAll(this.options.snap); + f = 0; + for (h = l.length; f < h; f++) { + j = this._offset(l[f]), j.left += this.wrapperOffsetLeft, j.top += this.wrapperOffsetTop, this.pagesX[f] = j.left < this.maxScrollX ? this.maxScrollX : j.left * this.scale, this.pagesY[f] = j.top < this.maxScrollY ? this.maxScrollY : j.top * this.scale + } + } else { + if (this.options.snap) { + for (this.pagesX = []; j >= this.maxScrollX;) { + this.pagesX[h] = j, j -= this.wrapperW, h++ + } + this.maxScrollX % this.wrapperW && (this.pagesX[this.pagesX.length] = this.maxScrollX - this.pagesX[this.pagesX.length - 1] + this.pagesX[this.pagesX.length - 1]); + h = j = 0; + for (this.pagesY = []; j >= this.maxScrollY;) { + this.pagesY[h] = j, j -= this.wrapperH, h++ + } + this.maxScrollY % this.wrapperH && (this.pagesY[this.pagesY.length] = this.maxScrollY - this.pagesY[this.pagesY.length - 1] + this.pagesY[this.pagesY.length - 1]) + } + } + this._scrollbar("h"); + this._scrollbar("v"); + this.zoomed || (this.scroller.style[ad] = "0", this._resetPos(200)) + }, + scrollTo: function(f, h, m, l) { + var j = f; + this.stop(); + j.length || (j = [{ + x: f, + y: h, + time: m, + relative: l + }]); + f = 0; + for (h = j.length; f < h; f++) { + j[f].relative && (j[f].x = this.x - j[f].x, j[f].y = this.y - j[f].y), this.steps.push({ + x: j[f].x, + y: j[f].y, + time: j[f].time || 0 + }) + } + this._startAni() + }, + scrollToElement: function(f, h) { + var j; + if (f = f.nodeType ? f : this.scroller.querySelector(f)) { + j = this._offset(f), j.left += this.wrapperOffsetLeft, j.top += this.wrapperOffsetTop, j.left = 0 < j.left ? 0 : j.left < this.maxScrollX ? this.maxScrollX : j.left, j.top = j.top > this.minScrollY ? this.minScrollY : j.top < this.maxScrollY ? this.maxScrollY : j.top, h = void 0 === h ? ao.max(2 * ao.abs(j.left), 2 * ao.abs(j.top)) : h, this.scrollTo(j.left, j.top, h) + } + }, + scrollToPage: function(f, h, j) { + j = void 0 === j ? 400 : j; + this.options.onScrollStart && this.options.onScrollStart.call(this); + if (this.options.snap) { + f = "next" == f ? this.currPageX + 1 : "prev" == f ? this.currPageX - 1 : f, h = "next" == h ? this.currPageY + 1 : "prev" == h ? this.currPageY - 1 : h, f = 0 > f ? 0 : f > this.pagesX.length - 1 ? this.pagesX.length - 1 : f, h = 0 > h ? 0 : h > this.pagesY.length - 1 ? this.pagesY.length - 1 : h, this.currPageX = f, this.currPageY = h, f = this.pagesX[f], h = this.pagesY[h] + } else { + if (f *= -this.wrapperW, h *= -this.wrapperH, f < this.maxScrollX && (f = this.maxScrollX), h < this.maxScrollY) { + h = this.maxScrollY + } + } + this.scrollTo(f, h, j) + }, + disable: function() { + this.stop(); + this._resetPos(0); + this.enabled = !1; + this._unbind(U); + this._unbind(S); + this._unbind(R) + }, + enable: function() { + this.enabled = !0 + }, + stop: function() { + this.options.useTransition ? this._unbind(aa) : Q(this.aniTime); + this.steps = []; + this.animating = this.moved = !1 + }, + zoom: function(f, h, m, l) { + var j = m / this.scale; + this.options.useTransform && (this.zoomed = !0, l = void 0 === l ? 200 : l, f = f - this.wrapperOffsetLeft - this.x, h = h - this.wrapperOffsetTop - this.y, this.x = f - f * j + this.x, this.y = h - h * j + this.y, this.scale = m, this.refresh(), this.x = 0 < this.x ? 0 : this.x < this.maxScrollX ? this.maxScrollX : this.x, this.y = this.y > this.minScrollY ? this.minScrollY : this.y < this.maxScrollY ? this.maxScrollY : this.y, this.scroller.style[ad] = l + "ms", this.scroller.style[ai] = "translate(" + this.x + "px," + this.y + "px) scale(" + m + ")" + ae, this.zoomed = !1) + }, + isReady: function() { + return !this.moved && !this.zoomed && !this.animating + } + }; + P = null; + return aj +}(window, document); +var Scrollable = function(h, g) { + function b() { + b._enableScrolling.apply(this, arguments) + } + b.node = function() { + return b._getScrollableNode.apply(this, arguments) + }; + b.infinite = function() { + return b._enableInfiniteScrolling.apply(this, arguments) + }; + if (h && h.fn) { + h.extend(h.fn, { + scrollable: function(i) { + this.forEach(function(j) { + b._enableScrolling(j, i) + }); + return this + }, + scrollableNode: function() { + return h(this.map(function() { + return b._getScrollableNode(this) + })) + }, + scrollableInfinite: function(j, k) { + var i; + this.forEach(function(m) { + var l = b._enableInfiniteScrolling(m, j, k); + if (!i) { + i = l + } + }); + return i + } + }); + var d = h.fn.scrollTop, + f = h.fn.scrollLeft; + h.fn.scrollTop = function(k) { + if (typeof k === "undefined") { + var i = this[0], + j = b._isDOMNode(i); + if (j && i._scrollTop) { + return i._scrollTop() + } else { + if (d) { + return d.apply(this, arguments) + } else { + if (j) { + return i.scrollTop + } else { + return null + } + } + } + } + this.forEach(function(l) { + var m = b._isDOMNode(l); + if (m && l._scrollTop) { + l._scrollTop(k) + } else { + if (d) { + d.call(h(l), k) + } else { + if (m) { + l.scrollTop = k + } + } + } + }); + return this + }; + h.fn.scrollLeft = function(k) { + if (typeof k === "undefined") { + var i = this[0], + j = b._isDOMNode(i); + if (j && i._scrollLeft) { + return i._scrollLeft() + } else { + if (d) { + return f.apply(this, arguments) + } else { + if (j) { + return i.scrollLeft + } else { + return null + } + } + } + } + this.forEach(function(l) { + var m = b._isDOMNode(l); + if (m && l._scrollLeft) { + l._scrollLeft(k) + } else { + if (f) { + f.call(h(l), k) + } else { + if (m) { + l.scrollLeft = k + } + } + } + }); + return this + } + } + if (g && g.fn) { + g.fn.scrollable = function(i) { + this.each(function() { + b._enableScrolling(this, i) + }); + return this + }; + g.fn.scrollableNode = function() { + return g(this.map(function() { + return b._getScrollableNode(this) + })) + }; + g.fn.scrollableInfinite = function(j, k) { + var i; + this.each(function() { + var l = b._enableInfiniteScrolling(this, j, k); + if (!i) { + i = l + } + }); + return i + }; + var c = g.fn.scrollTop, + e = g.fn.scrollLeft; + g.fn.scrollTop = function(j) { + if (typeof j === "undefined") { + var i = this[0]; + if (b._isDOMNode(i) && i._scrollTop) { + return i._scrollTop() + } else { + return c.apply(this, arguments) + } + } + this.each(function() { + if (b._isDOMNode(this) && this._scrollTop) { + this._scrollTop(j) + } else { + c.call(g(this), j) + } + }); + return this + }; + g.fn.scrollLeft = function(j) { + if (typeof j === "undefined") { + var i = this[0]; + if (b._isDOMNode(i) && i._scrollLeft) { + return i._scrollLeft() + } else { + return e.apply(this, arguments) + } + } + this.each(function() { + if (b._isDOMNode(this) && this._scrollLeft) { + this._scrollLeft(j) + } else { + e.call(g(this), j) + } + }); + return this + } + } + return b +}(window.Zepto, window.jQuery); +Scrollable._os = function(g, e) { + var d, b, c; + if (c = /\bCPU.*OS (\d+(_\d+)?)/i.exec(g)) { + d = "ios"; + b = c[1].replace("_", ".") + } else { + if (c = /\bAndroid (\d+(\.\d+)?)/.exec(g)) { + d = "android"; + b = c[1] + } + } + var f = { + name: d, + version: b && e(b), + mobile: !!d + }; + f[d] = true; + return f +}(navigator.userAgent, parseFloat); +Scrollable._isArray = function(b) { + return function(c) { + if (b) { + return b(c) + } else { + return Object.prototype.toString.call(c) !== "[object Array]" + } + } +}(Array.isArray); +Scrollable._isDOMNode = function(b, c) { + return function(e) { + if (!e) { + return false + } + try { + return (e instanceof b) || (e instanceof c) + } catch (d) {} + if (typeof e !== "object") { + return false + } + if (typeof e.nodeType !== "number") { + return false + } + if (typeof e.nodeName !== "string") { + return false + } + return true + } +}(Node, HTMLElement); +Scrollable._isjQueryElem = function(b) { + if (typeof b !== "object" || b === null) { + return false + } else { + return (b.val && b.addClass && b.css && b.html && b.show) + } +}; +Scrollable._findInArray = function(b) { + return function(d, f, g) { + if (b) { + return b.call(d, f, g) + } + for (var e = g || 0, c = d.length; e < c; e++) { + if ((e in d) && (d[e] === f)) { + return e + } + } + return -1 + } +}(Array.prototype.indexOf); +Scrollable._forEachInArray = function(b) { + return function(d, g, e) { + if (b) { + return b.call(d, g, e) + } + for (var f = 0, c = d.length; f < c; f++) { + if (f in d) { + g.call(e, d[f], f, d) + } + } + } +}(Array.prototype.forEach); +Scrollable._onReady = function(c, d, i) { + var h = [], + g = false; + e(f); + return function(j) { + if (g) { + j() + } else { + h.push(j) + } + }; + + function f() { + if (g) { + return + } + g = true; + i(h, function(j) { + setTimeout(j, 0) + }) + } + + function b(k) { + try { + c.documentElement.doScroll("left") + } catch (j) { + setTimeout(function() { + b(k) + }, 1); + return + } + k() + } + + function e(l) { + if (c.readyState === "complete") { + setTimeout(l, 0); + return + } + if (c.addEventListener) { + c.addEventListener("DOMContentLoaded", l, false); + d.addEventListener("load", l, false) + } else { + if (c.attachEvent) { + c.attachEvent("onreadystatechange", l); + d.attachEvent("onload", l); + var j = false; + try { + j = (d.frameElement === null) + } catch (k) {} + if (c.documentElement.doScroll && j) { + setTimeout(function() { + b(l) + }, 0) + } + } + } + } +}(document, window, Scrollable._forEachInArray); +Scrollable._scrollWatcher = function(b) { + return c; + + function c(i) { + var j = false, + e = false, + l = i.scrollTop; + i.addEventListener("touchstart", h); + i.addEventListener("touchmove", d); + i.addEventListener("touchcancel", g); + i.addEventListener("touchend", o); + i.addEventListener("scroll", k); + n(); + i._resetScrolling = f; + return; + + function n() { + i._isScrolling = (e || j) + } + + function f() { + e = false; + j = false; + n() + } + + function m(r, q, p) { + if ((r.touches.length <= q) && ((typeof p === "undefined") || (r.changedTouches.length <= p))) { + return false + } + r.preventDefault(); + f(); + return true + } + + function h(p) { + if (m(p, 1)) { + return + } + f() + } + + function d(p) { + if (m(p, 1)) { + return + } + j = true; + l = i.scrollTop; + n() + } + + function g(p) { + if (m(p, 0, 1)) { + return + } + f() + } + + function o(p) { + if (m(p, 0, 1)) { + return + } + var q; + if (j) { + q = Math.abs(i.scrollTop - l); + if (q > 5) { + e = true + } + j = false; + n() + } + } + + function k() { + if (!j && e) { + f() + } + } + } +}(Scrollable._os); +Scrollable._enableScrolling = function(f, o, k, e, d, p, m, n) { + var j = i(); + return q; + + function i() { + if ((f.ios && (f.version >= 5)) || (f.android && (f.version >= 4))) { + return true + } else { + return false + } + } + + function q(t, s) { + if (!o(t)) { + throw t + " is not a DOM element" + } + if (t._scrollable) { + return + } + t._scrollable = true; + var r; + t._scrollTop = function(u, v) { + if (typeof u === "undefined") { + return r ? Math.max(parseInt(-r.y), 0) : t.scrollTop + } + if (!r && (!f.mobile || j)) { + t.scrollTop = u; + v && v(); + return + } + k(function() { + r.scrollTo(r.x, Math.min(-u, 0), 1); + v && v() + }) + }; + t._scrollLeft = function(u) { + if (typeof u === "undefined") { + return r ? Math.max(parseInt(-r.x), 0) : t.scrollLeft + } + if (!r && (!f.mobile || j)) { + t.scrollLeft = u; + return + } + k(function() { + r.scrollTo(Math.min(-u, 0), r.y, 1) + }) + }; + t.style.overflow = "scroll"; + if (!s) { + if (!f.mobile) { + return + } + if (j) { + t.style["-webkit-overflow-scrolling"] = "touch"; + if (f.ios) { + d(t) + } + return + } + } + c(t, function(u) { + r = u + }) + } + + function c(s, t) { + s._iScroll = true; + l(s); + var r = g(s); + k(function() { + var u = new p(s, { + checkDOMChanges: true, + useTransform: true, + useTransition: true, + hScrollbar: false, + vScrollbar: false, + bounce: !!f.ios, + onScrollMove: r, + onBeforeScrollEnd: r, + onScrollEnd: function() { + s._iScrolling = false; + r() + }, + onBeforeScrollStart: h, + onScrollStart: function() { + s._iScrolling = true + } + }); + s._iScroll = u; + t(u) + }) + } + + function l(s) { + var t = n.createElement("div"), + r = Array.prototype.slice.call(s.childNodes || []); + e(r, function(v) { + var u = s.removeChild(v); + t.appendChild(u) + }); + s.appendChild(t); + s.style.position = "relative"; + t.style["min-height"] = "100%"; + t.style["min-width"] = "100%" + } + + function g(s) { + var r, t; + return function() { + var v = s._scrollTop(), + u = s._scrollLeft(); + if ((v === r) && (u === t)) { + return + } + r = v; + t = u; + b(s) + } + } + + function b(s) { + if (s.dispatchEvent) { + var r = n.createEvent("MouseEvents"); + r.initMouseEvent("scroll", false, false, m, 0, 0, 0, 0, 0, false, false, false, false, 0, null); + s.dispatchEvent(r) + } + } + + function h(s) { + var r = s.target; + while (r.nodeType !== 1) { + r = r.parentNode + } + if ((r.tagName !== "SELECT") && (r.tagName !== "INPUT") && (r.tagName !== "TEXTAREA")) { + s.preventDefault() + } + } +}(Scrollable._os, Scrollable._isDOMNode, Scrollable._onReady, Scrollable._forEachInArray, Scrollable._scrollWatcher, iScroll, window, document); +Scrollable._getScrollableNode = function(b) { + return function(c) { + if (b(c) && c._iScroll) { + return c.childNodes[0] + } else { + return c + } + } +}(Scrollable._isDOMNode); +Scrollable._enableInfiniteScrolling = function(g, l, f, h, i, m, d, n) { + var e = 320; + return j; + + function j(J, q, y) { + if (f(J)) { + if (J.length) { + var E = J.length - 1; + for (var F = 0; F < E; F++) { + j(J[F], q, y) + } + return j(J[E], q, y) + } else { + return + } + } + if (!l(J)) { + throw J + " is not a DOM element" + } + if (!y && typeof q === "function") { + y = q; + q = {} + } + if (y) { + if (q.downGenerator) { + throw Error("Two downGenerator functions specified") + } + q.downGenerator = y + } + if ((typeof q !== "object") || (q === null)) { + throw TypeError("options must be an object if defined, got " + q) + } + if (!q.downGenerator && !q.upGenerator) { + throw Error("No generators specified. What are you even scrolling?") + } + if (typeof q.autoStart === "undefined") { + q.autoStart = true + } + if (q.downGenerator && typeof q.downGenerator !== "function") { + throw "downGenerator " + downGenerator + " is not a function" + } + if (q.upGenerator && typeof q.upGenerator !== "function") { + throw "upGenerator " + upGenerator + " is not a function" + } + if (q.scroller && !l(q.scroller)) { + throw TypeError("options.scroller must be a DOM node, got " + q.scroller) + } + var I = q.scroller || b(J), + t = q.loading, + s = q.triggerRadius, + x = false, + z = !q.upGenerator, + G = !q.downGenerator, + B = false, + L = false, + C, K, w; + if (f(I)) { + I = I[0] + } + if (f(t)) { + t = t[0] + } + if (t === null) { + t = undefined + } + if (typeof t !== "undefined") { + if (q.downGenerator) { + C = c([t])[0]; + if (q.downGenerator) { + K = C.cloneNode(true) + } + } else { + K = c([t])[0] + } + } + if (s === null) { + s = undefined + } + switch (typeof s) { + case "undefined": + s = e; + case "number": + break; + default: + throw TypeError("trigger radius must be a number if defined, got " + s) + } + if (!I) { + m(J); + I = J + } + if (C) { + d(J).appendChild(C) + } + D(); + if (q.autoStart) { + A() + } + var H = { + layout: A, + forceLayout: v, + isEnabled: M, + enable: D, + disable: u, + destroy: p + }; + if (!I._infinites) { + I._infinites = [] + } + I._infinites.push(H); + return H; + + function M() { + return x + } + + function D() { + if (x) { + return + } + if (B) { + throw Error("cannot enable infinite scroller that has been destroyed") + } + x = true; + I.addEventListener("scroll", A, false) + } + + function u() { + if (!x) { + return + } + x = false; + I.removeEventListener("scroll", A) + } + + function A() { + if (!x || L || B) { + return + } + var O = o(I, s); + if (!O) { + return + } + var N = (O === "up"); + if (N && (J._isScrolling || J._iScrolling)) { + if (w) { + clearTimeout(w) + } + w = setTimeout(function() { + A() + }, 100); + return + } + L = true; + r(N, function(P) { + L = false; + if (P) { + A() + } else { + p(N) + } + }) + } + + function v(N) { + if (!x || B || L) { + return + } + L = true; + if (typeof N === "undefined") { + N = !q.downGenerator + } + r(N, function(O) { + L = false; + if (O) { + A() + } else { + p(N) + } + }) + } + + function r(Q, S) { + var R = Q ? q.upGenerator : q.downGenerator; + var N = R(O); + if (typeof N !== "undefined") { + O(N) + } + + function O(U, X) { + if (B || (z && Q) || (G && !Q)) { + return + } + var aa = Q ? K : C; + var T = U && U.length && !X; + if (U) { + if (!h(U) && !f(U)) { + U = [U] + } + U = c(U); + var Y = d(J); + var W = I.scrollHeight; + i(U, function(ab) { + P(Y, ab) + }); + if (aa) { + P(Y, aa) + } + var V = I.scrollHeight; + if (Q) { + var Z = V - W; + I._scrollTop(I._scrollTop() + Z, function() { + if (!!g.ios && !I._iScroll) { + k(U) + } + S(T) + }) + } else { + S(T) + } + } else { + S(T) + } + } + + function P(U, T) { + if (Q) { + U.insertBefore(T, U.firstChild) + } else { + U.appendChild(T) + } + } + } + + function p(N) { + if (B) { + return + } + if (N) { + z = true; + if (K && K.parentNode) { + K.parentNode.removeChild(K) + } + } else { + G = true; + if (C && C.parentNode) { + C.parentNode.removeChild(C) + } + } + B = (G || !q.downGenerator) && (z || !q.upGenerator); + if (B) { + u() + } + } + + function o(O, N) { + var R = O; + while (R !== document.documentElement) { + if (R.parentNode) { + R = R.parentNode + } else { + return false + } + } + var P = O.clientHeight, + S = (O._scrollTop ? O._scrollTop() : O.scrollTop), + Q = O.scrollHeight; + if (!G && Q - S - P <= N) { + return "down" + } else { + if (!z && S < N) { + return "up" + } else { + return false + } + } + } + } + + function b(o) { + do { + if (o._scrollable) { + return o + } + o = o.parentNode + } while (o) + } + + function c(o) { + var p = []; + i(o, function(q) { + switch (typeof q) { + case "undefined": + return; + case "string": + var r = document.createElement("div"); + r.innerHTML = q; + if (r.childNodes) { + i(c(r.childNodes), function(s) { + p.push(s) + }) + } + return; + case "object": + if (q === null) { + return + } else { + if (l(q)) { + p.push(q); + return + } else { + if (f(q)) { + i(q, function(s) { + p.push(s) + }); + return + } + } + } + default: + throw TypeError("expected an element, got " + q) + } + }); + return p + } + + function k(o) { + i(o, function(q) { + var p = q.style.webkitTransform; + q.style.webkitTransform = "translate3d(0,0,0)"; + setTimeout(function() { + q.style.webkitTransform = p + }, 0) + }) + } +}(Scrollable._os, Scrollable._isDOMNode, Scrollable._isjQueryElem, Scrollable._isArray, Scrollable._forEachInArray, Scrollable._enableScrolling, Scrollable._getScrollableNode, window.jQuery); +window.App = function(OldApp) { + var App = { + noConflict: noConflict + }; + return App; + + function noConflict() { + if (window.App === App) { + window.App = OldApp; + } + return App; + } +}(window.App); +App._Utils = function(window, document, App) { + var query = function(queryString) { + var re = /([^&=]+)=([^&]+)/g, + decodedSpace = /\+/g; + + var result = {}, + m, key, value; + + if (queryString) { + queryString = queryString.replace(decodedSpace, '%20'); + + while ((m = re.exec(queryString))) { + key = decodeURIComponent(m[1]); + value = decodeURIComponent(m[2]); + result[key] = value; + } + } + + return result; + }(window.location.href.split('?')[1]); + + var os = function(userAgent) { + var faked = false, + name, version, match; + + if (query['_app_platform'] === 'android') { + faked = true; + name = 'android'; + version = '5.0'; + } else if (query['_app_platform'] === 'ios') { + faked = true; + name = 'ios'; + version = '8.1'; + } else if (match = /\bCPU.*OS (\d+(_\d+)?)/i.exec(userAgent)) { + name = 'ios'; + version = match[1].replace('_', '.'); + } else if (match = /\bAndroid (\d+(\.\d+)?)/.exec(userAgent)) { + name = 'android'; + version = match[1]; + } else { + if (typeof process != 'undefined' && process.versions) { + name = 'node-webkit'; + version = process.versions['node-webkit']; + } else + name = 'unknown'; + } + + var data = { + faked: faked, + name: name, + versionString: version, + version: version && parseFloat(version) + }; + + data[name] = true; + + if (data.ios) { + document.body.className += ' app-ios app-ios-' + parseInt(version); + } else if (data.android) { + document.body.className += ' app-android app-android-' + parseInt(version); + } + if (data.faked || !data.ios) { + document.body.className += ' app-no-scrollbar'; + } + + return data; + }(navigator.userAgent); + + var forEach = function(forEach) { + if (forEach) { + return function(arr, callback, self) { + return forEach.call(arr, callback, self); + }; + } else { + return function(arr, callback, self) { + for (var i = 0, len = arr.length; i < len; i++) { + if (i in arr) { + callback.call(self, arr[i], i, arr); + } + } + }; + } + }(Array.prototype.forEach); + + function isArray(arr) { + if (Array.isArray) { + return Array.isArray(arr); + } else { + return Object.prototype.toString.call(arr) !== '[object Array]'; + } + } + + function isNode(elem) { + if (!elem) { + return false; + } + + try { + return (elem instanceof Node) || (elem instanceof HTMLElement); + } catch (err) {} + + if (typeof elem !== 'object') { + return false; + } + + if (typeof elem.nodeType !== 'number') { + return false; + } + + if (typeof elem.nodeName !== 'string') { + return false; + } + + return true; + } + + function isjQueryElem($elem) { + if (typeof $elem !== 'object' || $elem === null) { + return false; + } else { + return ($elem.val && $elem.addClass && $elem.css && $elem.html && $elem.show); + } + } + + function onReady(func) { + if (document.readyState === 'complete') { + setTimeout(function() { + func(); + }, 0); + return; + } + + window.addEventListener('load', runCallback, false); + + function runCallback() { + window.removeEventListener('load', runCallback); + + setTimeout(function() { + func(); + }, 0); + } + } + + var queueAnimation = function() { + var animationQueue; + return queueAnimation; + + function queueAnimation(func) { + if (animationQueue) { + animationQueue.push(func); + } else { + animationQueue = [func]; + foregroundFlush(); + } + } + + function foregroundFlush() { + if (typeof kik === 'object' && typeof kik.browser === 'object' && kik.browser.background && typeof kik.browser.once === 'function') { + kik.browser.once('foreground', flushAnimations); + } else { + flushAnimations(); + } + } + + function flushAnimations() { + var anim = animationQueue.shift(); + if (anim) { + onReady(function() { + var unlocked = false; + + function unlock() { + // prevent unlocking mult. times + if (unlocked) { + return; + } + unlocked = true; + setTimeout(foregroundFlush, 0); + } + anim(unlock); + }); + } else { + animationQueue = null; + } + } + }(); + + function setTransform(elem, transform) { + elem.style['-webkit-transform'] = transform; + elem.style['-moz-transform'] = transform; + elem.style['-ms-transform'] = transform; + elem.style['-o-transform'] = transform; + elem.style['transform'] = transform; + } + + function setTransition(elem, transition) { + if (transition) { + elem.style['-webkit-transition'] = '-webkit-' + transition; + elem.style['-moz-transition'] = '-moz-' + transition; + elem.style['-ms-transition'] = '-ms-' + transition; + elem.style['-o-transition'] = '-o-' + transition; + elem.style['transition'] = transition; + } else { + elem.style['-webkit-transition'] = ''; + elem.style['-moz-transition'] = ''; + elem.style['-ms-transition'] = ''; + elem.style['-o-transition'] = ''; + elem.style['transition'] = ''; + } + } + + function getStyles(elem, notComputed) { + var styles; + + if (notComputed) { + styles = elem.style; + } else { + styles = document.defaultView.getComputedStyle(elem, null); + } + + return { + display: styles.display, + opacity: styles.opacity, + paddingRight: styles.paddingRight, + paddingLeft: styles.paddingLeft, + marginRight: styles.marginRight, + marginLeft: styles.marginLeft, + borderRightWidth: styles.borderRightWidth, + borderLeftWidth: styles.borderLeftWidth, + top: styles.top, + left: styles.left, + height: styles.height, + width: styles.width, + position: styles.position + }; + } + + function isVisible(elem) { + var styles = getStyles(elem); + return (styles.display !== 'none' && styles.opacity !== '0'); + } + + // this is tuned for use with the iOS transition + // be careful if using this elsewhere + function transitionElems(transitions, timeout, easing, callback) { + if (typeof transitions.length !== 'number') { + transitions = [transitions]; + } + + var opacities = transitions.map(function(transition) { + return transition.elem.style.opacity; + }); + + setInitialStyles(function() { + animateElems(function() { + restoreStyles(function() { + callback(); + }); + }); + }); + + function setInitialStyles(callback) { + forEach(transitions, function(transition) { + if (typeof transition.transitionStart !== 'undefined') { + setTransform(transition.elem, transition.transitionStart); + } + if (typeof transition.opacityStart !== 'undefined') { + transition.elem.style.opacity = transition.opacityStart + ''; + } + }); + + setTimeout(function() { + forEach(transitions, function(transition) { + var e = transition.easing || easing, + transitionString = 'transform ' + (timeout / 1000) + 's ' + e + ', opacity ' + (timeout / 1000) + 's ' + e; + setTransition(transition.elem, transitionString); + }); + + setTimeout(callback, 0); + }, 0); + } + + function animateElems(callback) { + forEach(transitions, function(transition) { + if (typeof transition.transitionEnd !== 'undefined') { + setTransform(transition.elem, transition.transitionEnd); + } + if (typeof transition.opacityEnd !== 'undefined') { + transition.elem.style.opacity = transition.opacityEnd + ''; + } + }); + + var lastTransition = transitions[transitions.length - 1]; + lastTransition.elem.addEventListener('webkitTransitionEnd', transitionFinished, false); + lastTransition.elem.addEventListener('transitionend', transitionFinished, false); + lastTransition.elem.addEventListener('onTransitionEnd', transitionFinished, false); + lastTransition.elem.addEventListener('ontransitionend', transitionFinished, false); + lastTransition.elem.addEventListener('MSTransitionEnd', transitionFinished, false); + lastTransition.elem.addEventListener('transitionend', transitionFinished, false); + + var done = false; + + function transitionFinished(e) { + if (done || (e.target !== lastTransition.elem)) { + return; + } + done = true; + + forEach(transitions, function(transition) { + lastTransition.elem.removeEventListener('webkitTransitionEnd', transitionFinished); + lastTransition.elem.removeEventListener('transitionend', transitionFinished); + lastTransition.elem.removeEventListener('onTransitionEnd', transitionFinished); + lastTransition.elem.removeEventListener('ontransitionend', transitionFinished); + lastTransition.elem.removeEventListener('MSTransitionEnd', transitionFinished); + lastTransition.elem.removeEventListener('transitionend', transitionFinished); + }); + + callback(); + } + } + + function restoreStyles(callback) { + forEach(transitions, function(transition) { + setTransition(transition.elem, ''); + }); + + setTimeout(function() { + forEach(transitions, function(transition, i) { + setTransform(transition.elem, ''); + transition.elem.style.opacity = opacities[i]; + }); + + callback(); + }, 0); + } + } + + + + App.platform = os.name; + App.platformVersion = os.version; + App.queue = queueAnimation; + + return { + query: query, + os: os, + ready: onReady, + forEach: forEach, + isArray: isArray, + isNode: isNode, + isjQueryElem: isjQueryElem, + setTransform: setTransform, + setTransition: setTransition, + animate: transitionElems, + getStyles: getStyles, + isVisible: isVisible + }; +}(window, document, App); +App._Events = function(Utils) { + var APPJS_EVENTS_VAR = '__appjsCustomEventing'; + + var hasCustomEvents = supportsCustomEventing(); + + return { + init: setupCustomEventing, + fire: fireEvent + }; + + + + function supportsCustomEventing() { + try { + var elem = document.createElement('div'), + evt = document.createEvent('CustomEvent'); + evt.initEvent('fooBarFace', false, true); + elem.dispatchEvent(evt); + return true; + } catch (err) { + return false; + } + } + + function setupCustomEventing(elem, names) { + if (hasCustomEvents) { + return; + } + + if (elem[APPJS_EVENTS_VAR]) { + Utils.forEach(names, elem[APPJS_EVENTS_VAR].addEventType); + return; + } + + elem[APPJS_EVENTS_VAR] = { + fire: fireElemEvent, + addEventType: addEventType, + addEventListener: elem.addEventListener, + removeEventListener: elem.removeEventListener + }; + + var listeners = {}; + Utils.forEach(names, function(name) { + listeners[name] = []; + }); + + function addEventType(name) { + if (names.indexOf(name) !== -1) { + return; + } + names.push(name); + listeners[name] = []; + } + + function fireElemEvent(name) { + if (names.indexOf(name) === -1) { + return false; + } + + var prevented = false, + evt = { + preventDefault: function() { + prevented = true + } + }; + + Utils.forEach(listeners[name], function(listener) { + setTimeout(function() { + if (listener.call(elem, evt) === false) { + prevented = true; + } + }, 0); + }); + + return !prevented; + } + + elem.addEventListener = function(name, listener) { + if (names.indexOf(name) === -1) { + elem[APPJS_EVENTS_VAR].addEventListener.apply(this, arguments); + return; + } + + var eventListeners = listeners[name]; + + if (eventListeners.indexOf(listener) === -1) { + eventListeners.push(listener); + } + }; + + elem.removeEventListener = function(name, listener) { + if (names.indexOf(name) === -1) { + elem[APPJS_EVENTS_VAR].removeEventListener.apply(this, arguments); + return; + } + + var eventListeners = listeners[name], + index = eventListeners.indexOf(listener); + + if (index !== -1) { + eventListeners.splice(index, 1); + } + }; + } + + function fireEvent(elem, eventName) { + if (elem[APPJS_EVENTS_VAR]) { + return elem[APPJS_EVENTS_VAR].fire(eventName); + } else { + var evt = document.createEvent('CustomEvent'); + evt.initEvent(eventName, false, true); + return elem.dispatchEvent(evt); + } + } +}(App._Utils); +App._Metrics = function(window, App) { + var analyticsEnabled = false; + + App.enableGoogleAnalytics = function() { + enableGoogleAnalytics(); + }; + + return { + watchPage: watchPage + }; + + + + function enableGoogleAnalytics() { + analyticsEnabled = true; + } + + function addPageView(pageName, pageID) { + if (!analyticsEnabled) { + return; + } + + var pathname = '/' + pageName; + if (typeof pageID !== 'undefined') { + pathname += '/' + pageID; + } + + if (typeof window.ga === 'function') { + window.ga('send', 'pageview', pathname); + return; + } + + if (!window._gaq) { + window._gaq = []; + } + if (typeof window._gaq.push === 'function') { + window._gaq.push([ + '_trackPageview', + pathname + ]); + } + } + + function watchPage(page, pageName, pageArgs) { + var data; + + if ((typeof pageArgs === 'object') && (typeof pageArgs.id !== 'undefined')) { + data = pageArgs.id + ''; + } + + page.addEventListener('appShow', function() { + addPageView(pageName, data); + }, false); + } +}(window, App); +App._Dialog = function(window, document, Clickable, App, Utils) { + var DIALOG_INDICATOR_CLASS = 'app-dialog-visible'; + + var currentCallback, + dialogQueue; + + App.dialog = function(options, callback) { + if ((typeof options !== 'object') || (options === null)) { + throw TypeError('dialog options must be an object, got ' + options); + } + switch (typeof options.text) { + case 'undefined': + case 'string': + break; + default: + if (!Utils.isNode(options.text)) { + throw TypeError('dialog text must be a string if defined, got ' + options.text); + } + } + for (var key in options) { + if ((key === 'theme') || (key === 'title') || (key.substr(key.length - 6) === 'Button')) { + switch (typeof options[key]) { + case 'undefined': + case 'string': + break; + default: + throw TypeError('dialog button (' + key + ') must be a string if defined, got ' + options[key]); + } + } + } + switch (typeof callback) { + case 'undefined': + callback = function() {}; + case 'function': + break; + default: + throw TypeError('callback must be a function if defined, got ' + callback); + } + + return showDialog(options, callback); + }; + + App.dialog.close = function(status) { + return closeDialog(status || false); + }; + + App.dialog.status = function() { + return hasDialog(); + }; + + return App.dialog; + + + + function createDialog(options, callback) { + var dialogContainer = document.createElement('div'); + dialogContainer.className += ' app-dialog-container'; + if (!Utils.os.android || (Utils.os.version >= 4)) { + dialogContainer.addEventListener('touchstart', function(e) { + if (e.target === dialogContainer) { + e.preventDefault(); + } + }, false); + } + + var dialog = document.createElement('div'); + dialog.className = 'app-dialog'; + if (options.theme) { + dialog.className += ' ' + options.theme; + } + dialogContainer.appendChild(dialog); + + if (options.title) { + var title = document.createElement('div'); + title.className = 'title'; + title.textContent = options.title; + dialog.appendChild(title); + } + + if (options.text || options.rawText) { + var text = document.createElement('div'); + text.className = 'text'; + if (Utils.isNode(options.text)) { + text.appendChild(options.text); + } else if (options.rawText) { + text.innerHTML = options.rawText; + } else { + text.textContent = options.text; + } + dialog.appendChild(text); + } + + if (options.rawHTML) { + dialog.appendChild(options.rawHTML); + } + + if (options.okButton) { + var button = document.createElement('div'); + button.className = 'button ok last'; + if (!options.cancelButton) { + button.className += ' first'; + } + button.setAttribute('data-button', 'ok'); + button.textContent = options.okButton; + Clickable(button); + button.addEventListener('click', handleChoice, false); + dialog.appendChild(button); + } + + if (options.cancelButton) { + var button = document.createElement('div'); + button.className = 'button cancel first'; + if (!options.okButton) { + button.className += ' last'; + } + button.setAttribute('data-button', 'cancel'); + button.textContent = options.cancelButton; + Clickable(button); + button.addEventListener('click', handleChoice, false); + dialog.appendChild(button); + } + + function handleChoice() { + var buttonName = this.getAttribute('data-button'); + if (buttonName === 'cancel') { + buttonName = false; + } + callback(buttonName); + } + + return dialogContainer; + } + + function showDialog(options, callback, force) { + if (dialogQueue && !force) { + dialogQueue.push([options, callback]); + return; + } + dialogQueue = dialogQueue || []; + + var dialogLock = false, + dialog = createDialog(options, dialogClosed), + innerDialog = dialog.firstChild; + currentCallback = dialogClosed; + + Utils.ready(function() { + document.body.appendChild(dialog); + setTimeout(function() { + dialog.className += ' enabled'; + document.body.className += ' ' + DIALOG_INDICATOR_CLASS; + }, 50); + }); + + function dialogClosed(status) { + if (dialogLock) { + return; + } + dialogLock = true; + + currentCallback = null; + + dialog.className = dialog.className.replace(/\benabled\b/g, '') + ' closing'; + if (status) { + dialog.className += ' closing-success'; + } else { + dialog.className += ' closing-fail'; + } + document.body.className = document.body.className.replace(new RegExp('\\b' + DIALOG_INDICATOR_CLASS + '\\b', 'g'), ''); + + setTimeout(function() { + processDialogQueue(); + callback(status); + }, 0); + + setTimeout(function() { + try { + dialog.parentNode.removeChild(dialog); + } catch (err) {} + }, 600); + + return true; + } + } + + function closeDialog(status) { + if (currentCallback) { + return currentCallback(status || false); + } + } + + function hasDialog() { + return !!currentCallback; + } + + function processDialogQueue() { + if (!dialogQueue) { + return; + } + + if (!dialogQueue.length) { + dialogQueue = null; + return; + } + + var args = dialogQueue.shift(); + args.push(true); + showDialog.apply(window, args); + } +}(window, document, Clickable, App, App._Utils); +App._Form = function(window, document, App, Utils) { + App.form = function(form, callback) { + if (Utils.isjQueryElem(form)) { + form.each(function() { + App.form(this, callback); + }); + return; + } + if (!Utils.isNode(form)) { + throw TypeError('form must be a DOM node, got ' + form); + } + if (typeof callback !== 'function') { + throw TypeError('callback must be a function, got ' + callback); + } + + setupForm(form, callback); + }; + + return {}; + + function setupForm(form, callback) { + var isForm = (form.nodeName === 'FORM'), + locked = false, + submitButtons; + + if (isForm) { + var submit = document.createElement('input'); + submit.style.display = 'none'; + submit.type = 'submit'; + form.appendChild(submit); + form.addEventListener('submit', function(e) { + e.preventDefault(); + submitForm(); + }, false); + submitButtons = form.querySelectorAll('.app-submit'); + } else { + submitButtons = [form]; + } + + Utils.forEach(submitButtons, function(submitButton) { + if (submitButton.nodeName === 'TEXTAREA') { + isText = true; + } else if (submitButton.nodeName !== 'INPUT') { + isText = false; + } else { + switch ((submitButton.type || '').toLowerCase()) { + case 'button': + case 'submit': + case 'reset': + case 'hidden': + isText = false; + break; + default: + isText = true; + break; + } + } + if (isText) { + submitButton.addEventListener('keydown', function(e) { + if (e.which === 13) { + e.preventDefault(); + submitForm(); + } + }, false); + } else { + submitButton.addEventListener('click', function(e) { + e.preventDefault(); + submitForm(); + }, false); + } + }); + + function submitForm() { + if (locked) { + return; + } + locked = true; + form.disabled = true; + + var params = {}, + inputs = isForm ? form.querySelectorAll('[name]') : [form], + done = false; + + if (isForm) { + Utils.forEach( + form.querySelectorAll('[name]'), + function(elem) { + params[elem.name] = elem.value; + } + ); + } else { + params.value = form.value; + if (form.name) { + params[form.name] = form.value; + } + } + + Utils.forEach(inputs, function(elem) { + elem.disabled = true; + if (elem.blur) { + elem.blur(); + } + }); + if (isForm && form.blur) { + form.blur(); + } + + callback.call(this, params, function() { + if (done) { + return; + } + done = true; + + Utils.forEach(inputs, function(elem) { + elem.disabled = false; + }); + + locked = false; + form.disabled = false; + }); + } + } +}(window, document, App, App._Utils); +App._Scroll = function(Scrollable, App, Utils) { + var TAGS = { + APP_CONTENT: 'app-content', + APP_SCROLLABLE: 'app-scrollable', + APP_SCROLLHACK: 'app-scrollhack', + NO_SCROLL: 'data-no-scroll', + SCROLLABLE: 'data-scrollable', + LAST_SCROLL: 'data-last-scroll', + SCROLL_STYLE: 'data-scroll-style', + TOUCH_SCROLL: '-webkit-overflow-scrolling' + }, + PAGE_MANAGER_VAR = '__appjsPageManager'; + + App.infiniteScroll = function(elem, options, generator) { + if (Utils.isjQueryElem(elem)) { + if (elem.length) { + var l = elem.length - 1; + for (var i = 0; i < l; i++) { + App.infiniteScroll(elem[i], options, generator); + } + return App.infiniteScroll(elem[l], options, generator); + } else { + return; + } + } + if (!Utils.isNode(elem)) { + throw TypeError('infinite scroll container must be a DOM node, got ' + elem); + } + return setupInfiniteScroll(elem, options, generator); + }; + + return { + setup: setupScrollers, + disable: disableScrolling, + saveScrollPosition: savePageScrollPosition, + saveScrollStyle: savePageScrollStyle, + restoreScrollPosition: restorePageScrollPosition, + restoreScrollStyle: restorePageScrollStyle + }; + + + + function setupScrollers(page) { + Utils.forEach( + page.querySelectorAll('.' + TAGS.APP_CONTENT), + function(content) { + if (content.getAttribute(TAGS.NO_SCROLL) === null) { + setupScroller(content); + } + } + ); + + Utils.forEach( + page.querySelectorAll('[' + TAGS.SCROLLABLE + ']'), + function(content) { + setupScroller(content); + } + ); + } + + function setupScroller(content) { + var forceIScroll = !!window['APP_FORCE_ISCROLL']; + Scrollable(content, forceIScroll); + content.className += ' ' + TAGS.APP_SCROLLABLE; + if (!forceIScroll && Utils.os.ios && Utils.os.version < 6) { + content.className += ' ' + TAGS.APP_SCROLLHACK; + } + } + + function disableScrolling(page) { + Utils.forEach( + page.querySelectorAll('*'), + function(elem) { + elem.style[TAGS.TOUCH_SCROLL] = ''; + } + ); + } + + function getScrollableElems(page) { + var elems = []; + + if (page) { + Utils.forEach( + page.querySelectorAll('.' + TAGS.APP_SCROLLABLE), + function(elem) { + if (elem._scrollable) { + elems.push(elem); + } + } + ); + } + + return elems; + } + + function savePageScrollPosition(page) { + Utils.forEach( + getScrollableElems(page), + function(elem) { + if (elem._iScroll) { + return; + } + + var scrollTop = elem._scrollTop(); + elem.setAttribute(TAGS.LAST_SCROLL, scrollTop + ''); + } + ); + } + + function savePageScrollStyle(page) { + Utils.forEach( + getScrollableElems(page), + function(elem) { + if (elem._iScroll) { + return; + } + + var scrollStyle = elem.style[TAGS.TOUCH_SCROLL] || ''; + elem.style[TAGS.TOUCH_SCROLL] = ''; + elem.setAttribute(TAGS.SCROLL_STYLE, scrollStyle); + } + ); + } + + function restorePageScrollPosition(page, noTimeout) { + Utils.forEach( + getScrollableElems(page), + function(elem) { + if (elem._iScroll) { + return; + } + + var scrollTop = parseInt(elem.getAttribute(TAGS.LAST_SCROLL)); + + if (scrollTop) { + if (!noTimeout) { + setTimeout(function() { + elem._scrollTop(scrollTop); + }, 0); + } else { + elem._scrollTop(scrollTop); + } + } + } + ); + } + + function restorePageScrollStyle(page) { + Utils.forEach( + getScrollableElems(page), + function(elem) { + if (elem._iScroll) { + return; + } + + var scrollStyle = elem.getAttribute(TAGS.SCROLL_STYLE) || ''; + + if (scrollStyle) { + elem.style[TAGS.TOUCH_SCROLL] = scrollStyle; + } + + } + ); + + restorePageScrollPosition(page, true); + } + + + + function setupInfiniteScroll(elem, options, generator) { + var page = options.page || getParentPage(elem), + pageManager = getPageManager(page); + + if (!page || !pageManager) { + throw Error('could not find parent app-page'); + } + + if (!options) { + options = {}; + } + if (typeof options.scroller === 'undefined') { + options.scroller = getParentScroller(elem); + } + options.autoStart = false; + + var scroller = Scrollable.infinite(elem, options, generator); + scroller.forceLayout(); + scroller.disable(); + pageManager.ready(function() { + scrollReady = true; + try { + scroller.enable(); + } catch (err) { + // scroll is already destroyed + return; + } + scroller.layout(); + page.addEventListener('appShow', function() { + scroller.layout(); + }); + page.addEventListener('appDestroy', function() { + scroller.destroy(); + }); + }); + + return scroller; + } + + function getParentPage(elem) { + var parent = elem; + do { + if (/\bapp\-page\b/.test(parent.className)) { + return parent; + } + } while (parent = parent.parentNode); + } + + function getParentScroller(elem) { + var parent = elem; + do { + if (parent._scrollable || /\bapp\-content\b/.test(parent.className)) { + return parent; + } + } while (parent = parent.parentNode); + } + + function getPageManager(page) { + if (page) { + return page[PAGE_MANAGER_VAR]; + } + } +}(Scrollable, App, App._Utils); +// fixes ios bounce scrolling in mobile safari + +(function(document, App, Utils) { + var touches = {}; + + if (App.platform === 'ios' && App.platformVersion >= 5 && !Utils.os.faked && (typeof kik !== 'object' || kik === null || !kik.enabled)) { + bindListeners(); + } + return; + + function bindListeners() { + document.addEventListener('touchstart', function(e) { + var target = getTargetScroller(e); + if (target && !target._iScroll) { + if ((target.scrollHeight - target.clientHeight > 1) && ((target.scrollTop <= 0) || (target.scrollTop + target.clientHeight >= target.scrollHeight))) { + addTouches(e); + } + } + }); + document.addEventListener('touchmove', function(e) { + var target = getTargetScroller(e); + if (!target) { + e.preventDefault(); + } else if (target._iScroll) { + e.preventDefault(); + } else if (e.changedTouches) { + if (e.changedTouches.length === 1) { + onMove(e); + } + updateTouches(e); + } + }); + document.addEventListener('touchcancel', function(e) { + clearTouches(e); + }); + document.addEventListener('touchend', function(e) { + clearTouches(e); + }); + } + + function getTargetScroller(e) { + var target = e.target; + if (target) { + do { + if (target._scrollable) { + break; + } + } while (target = target.parentNode); + } + return target; + } + + function onMove(e) { + var target = getTargetScroller(e), + touch = e.changedTouches[0], + y0 = touches[touch.identifier], + y1 = touch.pageY; + if (target && typeof y0 !== 'undefined') { + if (target.scrollTop <= 0) { + if (y0 > y1) { + delete touches[touch.identifier]; + } else { + e.preventDefault(); + } + } else if (target.scrollTop + target.clientHeight >= target.scrollHeight) { + if (y0 < y1) { + delete touches[touch.identifier]; + } else { + e.preventDefault(); + } + } else { + delete touches[touch.identifier]; + } + } + } + + function addTouches(e) { + if (e.changedTouches) { + for (var i = 0, l = e.changedTouches.length; i < l; i++) { + touches[e.changedTouches[i].identifier] = e.changedTouches[i].pageY; + } + } + } + + function updateTouches(e) { + if (e.changedTouches) { + for (var i = 0, l = e.changedTouches.length; i < l; i++) { + if (e.changedTouches[i].identifier in touches) { + touches[e.changedTouches[i].identifier] = e.changedTouches[i].pageY; + } + } + } + } + + function clearTouches(e) { + if (e.changedTouches) { + for (var i = 0, l = e.changedTouches.length; i < l; i++) { + delete touches[e.changedTouches[i].identifier]; + } + } + if (e.touches) { + var ids = []; + for (var i = 0, l = e.touches.length; i < l; i++) { + ids.push(e.touches[i].identifier + ''); + } + for (var id in touches) { + if (ids.indexOf(id) === -1) { + delete touches[id]; + } + } + } + } +})(document, App, App._Utils); +App._Pages = function(window, document, Clickable, Scrollable, App, Utils, Events, Metrics, Scroll) { + var PAGE_NAME = 'data-page', + PAGE_CLASS = 'app-page', + APP_LOADED = 'app-loaded', + APP_IOS_STATUSBAR = 'app-ios-statusbar', + APP_ANDROID_STATUSBAR = 'app-android-statusbar', + PAGE_READY_VAR = '__appjsFlushReadyQueue', + PAGE_MANAGER_VAR = '__appjsPageManager', + EVENTS = { + SHOW: 'show', + HIDE: 'hide', + BACK: 'back', + FORWARD: 'forward', + BEFORE_BACK: 'beforeBack', + READY: 'ready', + DESTROY: 'destroy', + LAYOUT: 'layout', + ONLINE: 'online', + OFFLINE: 'offline' + }; + + var preloaded = false, + forceIScroll = !!window['APP_FORCE_ISCROLL'], + pages = {}, + controllers = {}, + cleanups = {}, + statusBarEnabled = false; + + setupPageListeners(); + if (window.APP_ENABLE_STATUSBAR || window.APP_ENABLE_IOS_STATUSBAR) { + enableStatusBar(); + } + + + App.add = function(pageName, page) { + if (typeof pageName !== 'string') { + page = pageName; + pageName = undefined; + } + + if (!Utils.isNode(page)) { + throw TypeError('page template node must be a DOM node, got ' + page); + } + + addPage(page, pageName); + }; + + App.controller = function(pageName, controller, cleanup) { + if (typeof pageName !== 'string') { + throw TypeError('page name must be a string, got ' + pageName); + } + + if (typeof controller !== 'function') { + throw TypeError('page controller must be a function, got ' + controller); + } + + switch (typeof cleanup) { + case 'undefined': + cleanup = function() {}; + break; + + case 'function': + break; + + default: + throw TypeError('page cleanup handler must be a function, got ' + cleanup); + } + + if (controller) { + addController(pageName, controller); + } + if (cleanup) { + addCleanup(pageName, cleanup); + } + }; + App.populator = App.controller; // backwards compat + + App.generate = function(pageName, args) { + if (typeof pageName !== 'string') { + throw TypeError('page name must be a string, got ' + pageName); + } + + switch (typeof args) { + case 'undefined': + args = {}; + break; + + case 'object': + break; + + default: + throw TypeError('page arguments must be an object if defined, got ' + args); + } + + return generatePage(pageName, args); + }; + + App.destroy = function(page) { + if (!Utils.isNode(page)) { + throw TypeError('page node must be a DOM node, got ' + page); + } + + return destroyPage(page); + }; + + App._layout = triggerPageSizeFix; + App._enableStatusBar = enableStatusBar; + App._enableIOSStatusBar = enableStatusBar; + + + return { + EVENTS: EVENTS, + has: hasPage, + createManager: createPageManager, + startGeneration: startPageGeneration, + finishGeneration: finishPageGeneration, + fire: firePageEvent, + startDestruction: startPageDestruction, + finishDestruction: finishPageDestruction, + fixContent: fixContentHeight, + populateBackButton: populatePageBackButton + }; + + + + /* Page elements */ + + function preloadPages() { + if (preloaded) { + return; + } + preloaded = true; + + var pageNodes = document.getElementsByClassName(PAGE_CLASS); + + for (var i = pageNodes.length; i--;) { + addPage(pageNodes[i]); + } + + document.body.className += ' ' + APP_LOADED; + } + + function addPage(page, pageName) { + if (!pageName) { + pageName = page.getAttribute(PAGE_NAME); + } + + if (!pageName) { + throw TypeError('page name was not specified'); + } + + page.setAttribute(PAGE_NAME, pageName); + if (page.parentNode) { + page.parentNode.removeChild(page); + } + pages[pageName] = page.cloneNode(true); + } + + function hasPage(pageName) { + preloadPages(); + return (pageName in pages); + } + + function clonePage(pageName) { + if (!hasPage(pageName)) { + throw TypeError(pageName + ' is not a known page'); + } + return pages[pageName].cloneNode(true); + } + + + + /* Page controllers */ + + function addController(pageName, controller) { + controllers[pageName] = controller; + } + + function addCleanup(pageName, cleanup) { + cleanups[pageName] = cleanup; + } + + function populatePage(pageName, pageManager, page, args) { + var controller = controllers[pageName]; + if (!controller) { + return; + } + for (var prop in controller) { + pageManager[prop] = controller[prop]; + } + for (var prop in controller.prototype) { + pageManager[prop] = controller.prototype[prop]; + } + pageManager.page = page; //TODO: getter + pageManager.args = args; //TODO: getter (dont want this to hit localStorage) + controller.call(pageManager, page, args); + } + + function unpopulatePage(pageName, pageManager, page, args) { + var cleanup = cleanups[pageName]; + if (cleanup) { + cleanup.call(pageManager, page, args); + } + firePageEvent(pageManager, page, EVENTS.DESTROY); + } + + + + /* Page generation */ + + function createPageManager(restored) { + var pageManager = { + restored: restored, + showing: false, + online: navigator.onLine + }; + + var readyQueue = []; + + pageManager.ready = function(func) { + if (typeof func !== 'function') { + throw TypeError('ready must be called with a function, got ' + func); + } + + if (readyQueue) { + readyQueue.push(func); + } else { + func.call(pageManager); + } + }; + + pageManager[PAGE_READY_VAR] = function() { + Utils.ready(function() { + if (!readyQueue) { + return; + } + var queue = readyQueue.slice(); + readyQueue = null; + if (Utils.isNode(pageManager.page)) { + firePageEvent(pageManager, pageManager.page, EVENTS.READY); + } + Utils.forEach(queue, function(func) { + func.call(pageManager); + }); + }); + }; + + return pageManager; + } + + function generatePage(pageName, args) { + var pageManager = {}, + page = startPageGeneration(pageName, pageManager, args); + + finishPageGeneration(pageName, pageManager, page, args); + + return page; + } + + function destroyPage(page) { + var pageName = page.getAttribute(PAGE_NAME); + startPageDestruction(pageName, {}, page, {}); + finishPageDestruction(pageName, {}, page, {}); + } + + function startPageGeneration(pageName, pageManager, args) { + var page = clonePage(pageName); + + var eventNames = []; + for (var evt in EVENTS) { + eventNames.push(eventTypeToName(EVENTS[evt])); + } + Events.init(page, eventNames); + Metrics.watchPage(page, pageName, args); + + page[PAGE_MANAGER_VAR] = pageManager; + + fixContentHeight(page); + + Utils.forEach(page.querySelectorAll('.app-button'), attachButtonEvent); + + //Attach click events for buttons added later on + page.addEventListener('DOMNodeInserted', function(e) { + var element = e.srcElement; + if (element && element.classList && element.classList.contains('app-button')) { + attachButtonEvent(element); + } + }); + + populatePage(pageName, pageManager, page, args); + + page.addEventListener(eventTypeToName(EVENTS.SHOW), function() { + setTimeout(function() { + if (typeof pageManager[PAGE_READY_VAR] === 'function') { + pageManager[PAGE_READY_VAR](); + } + }, 0); + }, false); + + return page; + } + + function attachButtonEvent(button) { + if (button.getAttribute('data-no-click') !== null || button._clickable) { + return; + } + + Clickable(button); + button.addEventListener('click', function() { + var target = button.getAttribute('data-target'), + targetArgs = button.getAttribute('data-target-args'), + back = (button.getAttribute('data-back') !== null), + manualBack = (button.getAttribute('data-manual-back') !== null), + args; + + try { + args = JSON.parse(targetArgs); + } catch (err) {} + if ((typeof args !== 'object') || (args === null)) { + args = {}; + } + + if (!back && !target) { + return; + } + if (back && manualBack) { + return; + } + + var clickableClass = button.getAttribute('data-clickable-class'); + if (clickableClass) { + button.disabled = true; + button.classList.add(clickableClass); + } + + if (back) { + App.back(finish); + } else if (target) { + App.load(target, args, {}, finish); + } + + function finish() { + if (clickableClass) { + button.disabled = false; + button.classList.remove(clickableClass); + } + } + + }, false); + } + + function firePageEvent(pageManager, page, eventType) { + var eventName = eventTypeToName(eventType), + funcName = eventTypeToFunctionName(eventType), + success = true; + if (!Events.fire(page, eventName)) { + success = false; + } + if (typeof pageManager[funcName] === 'function') { + if (pageManager[funcName]() === false) { + success = false; + } + } + return success; + } + + function eventTypeToName(eventType) { + return 'app' + eventType[0].toUpperCase() + eventType.slice(1); + } + + function eventTypeToFunctionName(eventType) { + return 'on' + eventType[0].toUpperCase() + eventType.slice(1); + } + + function finishPageGeneration(pageName, pageManager, page, args) { + Scroll.setup(page); + } + + function startPageDestruction(pageName, pageManager, page, args) { + if (!Utils.os.ios || Utils.os.version < 6) { + Scroll.disable(page); + } + if (typeof pageManager.reply === 'function') { + pageManager._appNoBack = true; + pageManager.reply(); + } + } + + function finishPageDestruction(pageName, pageManager, page, args) { + unpopulatePage(pageName, pageManager, page, args); + } + + + + /* Page layout */ + + function setupPageListeners() { + window.addEventListener('orientationchange', triggerPageSizeFix); + window.addEventListener('resize', triggerPageSizeFix); + window.addEventListener('load', triggerPageSizeFix); + setTimeout(triggerPageSizeFix, 0); + + window.addEventListener('online', function() { + if (App._Stack) { + Utils.forEach(App._Stack.get(), function(pageInfo) { + pageInfo[2].online = true; + firePageEvent(pageInfo[2], pageInfo[3], EVENTS.ONLINE); + }); + } + }, false); + window.addEventListener('offline', function() { + if (App._Stack) { + Utils.forEach(App._Stack.get(), function(pageInfo) { + pageInfo[2].online = false; + firePageEvent(pageInfo[2], pageInfo[3], EVENTS.OFFLINE); + }); + } + }, false); + } + + function triggerPageSizeFix() { + fixContentHeight(); + var pageData; + if (App._Stack) { + pageData = App._Stack.getCurrent(); + } + if (pageData) { + firePageEvent(pageData[2], pageData[3], EVENTS.LAYOUT); + } + + //TODO: turns out this isnt all that expensive, but still, lets kill it if we can + setTimeout(fixContentHeight, 0); + setTimeout(fixContentHeight, 10); + setTimeout(fixContentHeight, 100); + } + + function fixContentHeight(page) { + if (!page) { + if (App._Navigation) { + page = App._Navigation.getCurrentNode(); + } + if (!page) { + return; + } + } + + var topbar = page.querySelector('.app-topbar'), + content = page.querySelector('.app-content'), + height = window.innerHeight; + + if (!content) { + return; + } + if (!topbar) { + content.style.height = height + 'px'; + return; + } + + var topbarStyles = document.defaultView.getComputedStyle(topbar, null), + topbarHeight = Utils.os.android ? 56 : 44; + if (statusBarEnabled) { + topbarHeight += Utils.os.android ? 24 : 20; + } + if (topbarStyles.height) { + topbarHeight = (parseInt(topbarStyles.height) || 0); + if ((topbarStyles.boxSizing || topbarStyles.webkitBoxSizing) !== 'border-box') { + topbarHeight += (parseInt(topbarStyles.paddingBottom) || 0) + (parseInt(topbarStyles.paddingTop) || 0); + topbarHeight += (parseInt(topbarStyles.borderBottomWidth) || 0) + (parseInt(topbarStyles.borderTopWidth) || 0); + } + } + content.style.height = (height - topbarHeight) + 'px'; + } + + function populatePageBackButton(page, oldPage) { + if (!oldPage) { + return; + } + var backButton = page.querySelector('.app-topbar .left.app-button'), + oldTitle = oldPage.querySelector('.app-topbar .app-title'); + if (!backButton || !oldTitle || (backButton.getAttribute('data-autotitle') === null)) { + return; + } + var oldText = oldTitle.textContent, + newText = backButton.textContent; + if (!oldText || newText) { + return; + } + if (oldText.length > 13) { + oldText = oldText.substr(0, 12) + '..'; + } + backButton.textContent = oldText; + } + + function enableStatusBar() { + if (statusBarEnabled) { + return; + } + statusBarEnabled = true; + if (Utils.os.android) { + document.body.className += ' ' + APP_ANDROID_STATUSBAR; + } else { + document.body.className += ' ' + APP_IOS_STATUSBAR; + } + Utils.ready(function() { + setTimeout(triggerPageSizeFix, 6); + }); + } +}(window, document, Clickable, Scrollable, App, App._Utils, App._Events, App._Metrics, App._Scroll); +App._Stack = function(window, document, App, Utils, Scroll, Pages) { + var STACK_KEY = '__APP_JS_STACK__' + window.location.pathname, + STACK_TIME = '__APP_JS_TIME__' + window.location.pathname; + + var stack = []; + + App.getStack = function() { + return fetchStack(); + }; + + App.getPage = function(index) { + var stackSize = stack.length - 1; + switch (typeof index) { + case 'undefined': + index = stackSize; + break; + case 'number': + if (Math.abs(index) > stackSize) { + throw TypeError('absolute index cannot be greater than stack size, got ' + index); + } + if (index < 0) { + index = stackSize + index; + } + break; + default: + throw TypeError('page index must be a number if defined, got ' + index); + } + return fetchPage(index); + }; + + App.removeFromStack = function(startIndex, endIndex) { + // minus 1 because last item on stack is current page (which is untouchable) + var stackSize = stack.length - 1; + switch (typeof startIndex) { + case 'undefined': + startIndex = 0; + break; + case 'number': + if (Math.abs(startIndex) > stackSize) { + throw TypeError('absolute start index cannot be greater than stack size, got ' + startIndex); + } + if (startIndex < 0) { + startIndex = stackSize + startIndex; + } + break; + default: + throw TypeError('start index must be a number if defined, got ' + startIndex); + } + switch (typeof endIndex) { + case 'undefined': + endIndex = stackSize; + break; + case 'number': + if (Math.abs(endIndex) > stackSize) { + throw TypeError('absolute end index cannot be greater than stack size, got ' + endIndex); + } + if (endIndex < 0) { + endIndex = stackSize + endIndex; + } + break; + default: + throw TypeError('end index must be a number if defined, got ' + endIndex); + } + if (startIndex > endIndex) { + throw TypeError('start index cannot be greater than end index'); + } + + removeFromStack(startIndex, endIndex); + }; + + App.addToStack = function(index, newPages) { + // minus 1 because last item on stack is current page (which is untouchable) + var stackSize = stack.length - 1; + switch (typeof index) { + case 'undefined': + index = 0; + break; + case 'number': + if (Math.abs(index) > stackSize) { + throw TypeError('absolute index cannot be greater than stack size, got ' + index); + } + if (index < 0) { + index = stackSize + index; + } + break; + default: + throw TypeError('index must be a number if defined, got ' + index); + } + if (!Utils.isArray(newPages)) { + throw TypeError('added pages must be an array, got ' + newPages); + } + newPages = newPages.slice(); + Utils.forEach(newPages, function(page, i) { + if (typeof page === 'string') { + page = [page, {}]; + } else if (Utils.isArray(page)) { + page = page.slice(); + } else { + throw TypeError('page description must be an array (page name, arguments), got ' + page); + } + if (typeof page[0] !== 'string') { + throw TypeError('page name must be a string, got ' + page[0]); + } + switch (typeof page[1]) { + case 'undefined': + page[1] = {}; + case 'object': + break; + default: + throw TypeError('page arguments must be an object if defined, got ' + page[1]); + } + switch (typeof page[2]) { + case 'undefined': + page[2] = {}; + case 'object': + break; + default: + throw TypeError('page options must be an object if defined, got ' + page[2]); + } + newPages[i] = page; + }); + + addToStack(index, newPages); + }; + + App.saveStack = function() { + saveStack(); + }; + + App.destroyStack = function() { + destroyStack(); + }; + + App.restore = setupRestoreFunction(); + + return { + get: fetchStack, + getCurrent: fetchLastStackItem, + getPage: fetchPage, + pop: popLastStackItem, + push: pushNewStackItem, + size: fetchStackSize, + save: saveStack, + destroy: destroyStack + }; + + + + function saveStack() { + try { + var storedStack = []; + for (var i = 0, l = stack.length; i < l; i++) { + if (stack[i][4].restorable === false) { + break; + } + storedStack.push([stack[i][0], stack[i][3], stack[i][2]]); + } + localStorage[STACK_KEY] = JSON.stringify(storedStack); + localStorage[STACK_TIME] = +new Date() + ''; + } catch (err) {} + } + + function destroyStack() { + delete localStorage[STACK_KEY]; + delete localStorage[STACK_TIME]; + } + + function fetchStack() { + return stack.slice().map(reorganisePageData); + } + + function fetchStackSize() { + return stack.length; + } + + function fetchLastStackItem() { + var pageData = stack[stack.length - 1]; + if (pageData) { + return reorganisePageData(pageData); + } + } + + function popLastStackItem() { + var pageData = stack.pop(); + if (pageData) { + return reorganisePageData(pageData); + } + } + + function pushNewStackItem(pageData) { + stack.push([pageData[0], pageData[3], pageData[4], pageData[1], pageData[2]]); + } + + function fetchPage(index) { + var pageData = stack[index]; + if (pageData) { + return pageData[1]; + } + } + + function reorganisePageData(pageData) { + var pageArgs = {}; + for (var key in pageData[3]) { + pageArgs[key] = pageData[3][key]; + } + return [pageData[0], pageArgs, pageData[4], pageData[1], pageData[2]]; + } + + + + // you must manually save the stack if you choose to use this method + function removeFromStackNow(startIndex, endIndex) { + var deadPages = stack.splice(startIndex, endIndex - startIndex); + + Utils.forEach(deadPages, function(pageData) { + Pages.startDestruction(pageData[0], pageData[4], pageData[1], pageData[3]); + Pages.finishDestruction(pageData[0], pageData[4], pageData[1], pageData[3]); + }); + } + + function removeFromStack(startIndex, endIndex) { + App._Navigation.enqueue(function(finish) { + removeFromStackNow(startIndex, endIndex); + finish(); + }); + } + + // you must manually save the stack if you choose to use this method + function addToStackNow(index, newPages, restored) { + var pageDatas = [], + lastPage; + + Utils.forEach(newPages, function(pageData) { + var pageManager = Pages.createManager(true), + page = Pages.startGeneration(pageData[0], pageManager, pageData[1]); + + if (!pageData[2].transition && pageManager.transition) { + pageData[2].transition = pageManager.transition; + } + if (!pageData[2].duration && pageManager.duration) { + pageData[2].duration = pageManager.duration; + } + + Pages.populateBackButton(page, lastPage); + + Pages.finishGeneration(pageData[0], pageManager, page, pageData[1]); + + Scroll.saveScrollPosition(page); + Scroll.saveScrollStyle(page); + + pageDatas.push([pageData[0], page, pageData[2], pageData[1], pageManager]); + + lastPage = page; + }); + + pageDatas.unshift(0); + pageDatas.unshift(index); + Array.prototype.splice.apply(stack, pageDatas); + } + + function addToStack(index, newPages) { + App._Navigation.enqueue(function(finish) { + addToStackNow(index, newPages); + finish(); + }); + } + + function setupRestoreFunction(options) { + var storedStack, lastPage; + + try { + storedStack = JSON.parse(localStorage[STACK_KEY]); + storedTime = parseInt(localStorage[STACK_TIME]); + lastPage = storedStack.pop(); + } catch (err) { + return; + } + + if (!lastPage) { + return; + } + + return function(options, callback) { + switch (typeof options) { + case 'function': + callback = options; + case 'undefined': + options = {}; + case 'object': + if (options !== null) { + break; + } + default: + throw TypeError('restore options must be an object if defined, got ' + options); + } + + switch (typeof callback) { + case 'undefined': + callback = function() {}; + case 'function': + break; + default: + throw TypeError('restore callback must be a function if defined, got ' + callback); + } + + if (+new Date() - storedTime >= options.maxAge) { + throw TypeError('restore content is too old'); + } + + if (!Pages.has(lastPage[0])) { + throw TypeError(lastPage[0] + ' is not a known page'); + } + + Utils.forEach(storedStack, function(pageData) { + if (!Pages.has(pageData[0])) { + throw TypeError(pageData[0] + ' is not a known page'); + } + }); + + try { + addToStackNow(0, storedStack, true); + } catch (err) { + removeFromStackNow(0, stack.length); + throw Error('failed to restore stack'); + } + + saveStack(); + + try { + App.load(lastPage[0], lastPage[1], lastPage[2], callback); + } catch (err) { + removeFromStackNow(0, stack.length); + throw Error('failed to restore stack'); + } + }; + } +}(window, document, App, App._Utils, App._Scroll, App._Pages); +App._Transitions = function(window, document, Swapper, App, Utils, Scroll, Pages, Stack) { + var TRANSITION_CLASS = 'app-transition', + DEFAULT_TRANSITION_IOS = 'slide-left', + DEFAULT_TRANSITION_ANDROID = 'android-l-in', + DEFAULT_TRANSITION_ANDROID_OLD = 'fade-on', + DEFAULT_TRANSITION_ANDROID_GHETTO = 'instant', + REVERSE_TRANSITION = { + 'instant': 'instant', + 'fade': 'fade', + 'fade-on': 'fade-off', + 'fade-off': 'fade-on', + 'scale-in': 'scale-out', + 'scale-out': 'scale-in', + 'rotate-left': 'rotate-right', + 'rotate-right': 'rotate-left', + 'cube-left': 'cube-right', + 'cube-right': 'cube-left', + 'swap-left': 'swap-right', + 'swap-right': 'swap-left', + 'explode-in': 'explode-out', + 'explode-out': 'explode-in', + 'implode-in': 'implode-out', + 'implode-out': 'implode-in', + 'slide-left': 'slide-right', + 'slide-right': 'slide-left', + 'slide-up': 'slide-down', + 'slide-down': 'slide-up', + 'slideon-left': 'slideoff-left', + 'slideon-right': 'slideoff-right', + 'slideon-up': 'slideoff-up', + 'slideon-down': 'slideoff-down', + 'slideoff-left': 'slideon-left', + 'slideoff-right': 'slideon-right', + 'slideoff-up': 'slideon-up', + 'slideoff-down': 'slideon-down', + 'slideon-left-ios': 'slideoff-right-ios', + 'glideon-right': 'glideoff-right', + 'glideoff-right': 'slideon-right', + 'glideon-left': 'glideoff-left', + 'glideoff-left': 'slideon-left', + 'glideon-down': 'glideoff-down', + 'glideoff-down': 'slideon-down', + 'glideon-up': 'glideoff-up', + 'glideoff-up': 'slideon-up', + 'android-l-in': 'android-l-out', + 'android-l-out': 'android-l-in' + }, + WALL_RADIUS = 10; + + + var shouldDrag = false, + defaultTransition, reverseTransition, dragLock; + + if (Utils.os.ios) { + setDefaultTransition(DEFAULT_TRANSITION_IOS); + } else if (Utils.os.android) { + if (Utils.os.version >= 4) { + setDefaultTransition(DEFAULT_TRANSITION_ANDROID); + } else if ((Utils.os.version < 2.3) || /LT15a/i.test(navigator.userAgent)) { + setDefaultTransition(DEFAULT_TRANSITION_ANDROID_GHETTO); + } else { + setDefaultTransition(DEFAULT_TRANSITION_ANDROID_OLD); + } + } + + checkForDragTransitionMetaTag(); + + + App.setDefaultTransition = function(transition) { + if (typeof transition === 'object') { + switch (Utils.os.name) { + case 'android': + if ((Utils.os.version < 4) && transition.androidFallback) { + transition = transition.androidFallback; + } else { + transition = transition.android; + } + break; + case 'ios': + if ((Utils.os.version < 5) && transition.iosFallback) { + transition = transition.iosFallback; + } else { + transition = transition.ios; + } + break; + default: + transition = transition.fallback; + break; + } + if (!transition) { + return; + } + } + + if (typeof transition !== 'string') { + throw TypeError('transition must be a string if defined, got ' + transition); + } + + if (!(transition in REVERSE_TRANSITION)) { + throw TypeError('invalid transition type, got ' + transition); + } + + setDefaultTransition(transition); + }; + + App.getDefaultTransition = function() { + return defaultTransition; + }; + + App.getReverseTransition = function() { + return reverseTransition; + }; + + App.enableDragTransition = function() { + allowDragging(); + }; + + + return { + REVERSE_TRANSITION: REVERSE_TRANSITION, + run: performTransition, + enableDrag: enableIOS7DragTransition, + disableDrag: disableIOS7DragTransition + }; + + + + function setDefaultTransition(transition) { + defaultTransition = transition; + reverseTransition = REVERSE_TRANSITION[defaultTransition]; + } + + function shouldUseNativeIOSTransition(transition) { + if (!Utils.os.ios) { + return false; + } else if (transition === 'slide-left') { + return true; + } else if (transition === 'slide-right') { + return true; + } else { + return false; + } + } + + + + function performTransition(oldPage, page, options, callback, reverse) { + if (!options.transition) { + options.transition = (reverse ? reverseTransition : defaultTransition); + } + var isIOS7SlideUp = (Utils.os.ios && (Utils.os.version >= 7) && { + 'slideon-down': 1, + 'slideoff-down': 1 + }[options.transition]); + if (!options.duration) { + if (!Utils.os.ios) { + options.duration = 180; + } else if (Utils.os.version < 7) { + options.duration = 325; + } else if (isIOS7SlideUp) { + options.duration = 475; + } else { + options.duration = 425; + } + } + if (!options.easing) { + if (Utils.os.ios) { + if (isIOS7SlideUp) { + options.easing = 'cubic-bezier(0.4,0.6,0.05,1)'; + } else if (options.transition === 'slideon-left-ios' || options.transition === 'slideoff-right-ios') { + if (Utils.os.version < 7) { + options.easing = 'ease-in-out'; + } else { + options.easing = 'cubic-bezier(0.4,0.6,0.2,1)'; + } + } + } else if (Utils.os.android) { + if (options.transition === 'android-l-in') { + options.easing = 'ease-out'; + } else if (options.transition === 'android-l-out') { + options.easing = 'ease-in'; + } + } + } + + document.body.className += ' ' + TRANSITION_CLASS; + + if (options.transition === 'instant') { + Swapper(oldPage, page, options, function() { + //TODO: this is stupid. let it be synchronous if it can be. + //TODO: fix the root of the race in core navigation. + setTimeout(finish, 0); + }); + } else if (shouldUseNativeIOSTransition(options.transition)) { + performNativeIOSTransition(oldPage, page, options, finish); + } else { + Swapper(oldPage, page, options, finish); + } + + function finish() { + document.body.className = document.body.className.replace(new RegExp('\\b' + TRANSITION_CLASS + '\\b'), ''); + callback(); + } + } + + + + function performNativeIOSTransition(oldPage, page, options, callback) { + var slideLeft = (options.transition === 'slide-left'), + topPage = slideLeft ? page : oldPage, + transitions = getNativeIOSTransitionList(page, oldPage, slideLeft); + + if (!transitions) { + // proper iOS transition not possible, fallback to normal + Swapper(oldPage, page, options, callback); + return; + } + + var oldPosition = topPage.style.position, + oldZIndex = topPage.style.zIndex, + oldBackground = topPage.style.background; + topPage.style.position = 'fixed'; + topPage.style.zIndex = '4000'; + topPage.style.background = 'none'; + + if (slideLeft) { + oldPage.parentNode.insertBefore(page, oldPage); + } else if (oldPage.nextSibling) { + oldPage.parentNode.insertBefore(page, oldPage.nextSibling); + } else { + oldPage.parentNode.appendChild(page); + } + + if (App._Pages) { + App._Pages.fixContent(oldPage); + App._Pages.fixContent(page); + } + + if (Utils.os.version < 7) { + options.easing = 'ease-in-out'; + } else { + options.easing = 'cubic-bezier(0.4,0.6,0.2,1)'; + } + + Utils.animate(transitions, options.duration, options.easing, function() { + oldPage.parentNode.removeChild(oldPage); + + topPage.style.position = oldPosition; + topPage.style.zIndex = oldZIndex; + topPage.style.background = oldBackground; + + callback(); + }); + } + + function getNativeIOSTransitionList(page, oldPage, slideLeft) { + var currentBar = oldPage.querySelector('.app-topbar'), + currentTitle = oldPage.querySelector('.app-topbar .app-title'), + currentBack = oldPage.querySelector('.app-topbar .left.app-button'), + currentContent = oldPage.querySelector('.app-content'), + newBar = page.querySelector('.app-topbar'), + newTitle = page.querySelector('.app-topbar .app-title'), + newBack = page.querySelector('.app-topbar .left.app-button'), + newContent = page.querySelector('.app-content'), + transitions = []; + + if (!currentBar || !newBar || !currentContent || !newContent || !Utils.isVisible(currentBar) || !Utils.isVisible(newBar)) { + return; + } + + if (currentBack && (currentBack.getAttribute('data-noslide') !== null)) { + currentBack = undefined; + } + if (newBack && (newBack.getAttribute('data-noslide') !== null)) { + newBack = undefined; + } + + // fade topbar + if (slideLeft) { + transitions.push({ + opacityStart: 0, + opacityEnd: 1, + elem: newBar + }); + } else { + transitions.push({ + opacityStart: 1, + opacityEnd: 0, + elem: currentBar + }); + } + + // slide titles + if (currentTitle) { + transitions.push({ + transitionStart: 'translate3d(0,0,0)', + transitionEnd: 'translate3d(' + getTitleTransform(newBack, slideLeft) + 'px,0,0)', + elem: currentTitle + }); + } + if (newTitle) { + transitions.push({ + transitionStart: 'translate3d(' + getTitleTransform(currentBack, !slideLeft) + 'px,0,0)', + transitionEnd: 'translate3d(0,0,0)', + elem: newTitle + }); + } + + // slide back button + if (Utils.os.version >= 5) { + if (currentBack) { + transitions.push({ + transitionStart: 'translate3d(0,0,0)', + transitionEnd: 'translate3d(' + getBackTransform(currentBack, newBack, !slideLeft) + 'px,0,0)', + elem: currentBack + }); + } + if (newBack) { + transitions.push({ + transitionStart: 'translate3d(' + getBackTransform(newBack, currentBack, slideLeft) + 'px,0,0)', + transitionEnd: 'translate3d(0,0,0)', + elem: newBack + }); + } + } + + // slide contents + if (Utils.os.version < 7) { + transitions.push({ + transitionStart: 'translate3d(0,0,0)', + transitionEnd: 'translate3d(' + (slideLeft ? -100 : 100) + '%,0,0)', + elem: currentContent + }, { + transitionStart: 'translate3d(' + (slideLeft ? 100 : -100) + '%,0,0)', + transitionEnd: 'translate3d(0,0,0)', + elem: newContent + }); + } else { + transitions.push({ + transitionStart: 'translate3d(0,0,0)', + transitionEnd: 'translate3d(' + (slideLeft ? -30 : 100) + '%,0,0)', + elem: currentContent + }, { + transitionStart: 'translate3d(' + (slideLeft ? 100 : -30) + '%,0,0)', + transitionEnd: 'translate3d(0,0,0)', + elem: newContent + }); + } + + return transitions; + } + + function getBackTransform(backButton, oldButton, toCenter) { + var fullWidth = backButton.textContent.length * (Utils.os.version < 7 ? 10 : 12), + oldWidth = oldButton ? (oldButton.textContent.length * 15) : 0; + if (!toCenter) { + return (oldWidth - window.innerWidth) / 2; + } else { + return (window.innerWidth - fullWidth) / 2; + } + } + + function getTitleTransform(backButton, toLeft) { + var fullWidth = 0; + if (backButton && (Utils.os.version >= 5)) { + fullWidth = backButton.textContent.length * (Utils.os.version < 7 ? 10 : 12); + } + if (!toLeft) { + return (window.innerWidth / 2); + } else { + return (fullWidth - window.innerWidth) / 2; + } + } + + + + function allowDragging() { + shouldDrag = true; + } + + function checkForDragTransitionMetaTag() { + var metas = document.querySelectorAll('meta'); + for (var i = 0, l = metas.length; i < l; i++) { + if ((metas[i].name === 'app-drag-transition') && (metas[i].content === 'true')) { + allowDragging(); + return; + } + } + } + + function enableIOS7DragTransition() { + if (!shouldDrag || !Utils.os.ios || (Utils.os.version < 7)) { + return; + } + + var pages = Stack.get().slice(-2), + previousPage = pages[0], + currentPage = pages[1], + draggingTouch, lastTouch, navigationLock, dead, slideLeft; + if (!previousPage || !currentPage) { + return; + } + + var currentNode = currentPage[3], + currentBar = currentPage[3].querySelector('.app-topbar'), + currentTitle = currentPage[3].querySelector('.app-topbar .app-title'), + currentBack = currentPage[3].querySelector('.app-topbar .left.app-button'), + currentContent = currentPage[3].querySelector('.app-content'), + oldNode = previousPage[3], + oldBar = previousPage[3].querySelector('.app-topbar'), + oldTitle = previousPage[3].querySelector('.app-topbar .app-title'), + oldBack = previousPage[3].querySelector('.app-topbar .left.app-button'), + oldContent = previousPage[3].querySelector('.app-content'); + + if (!currentNode || !currentBar || !currentContent || !oldNode || !oldBar || !oldContent) { + return; + } + + var dragableTransitions = ['slide-left', 'slideon-left-ios']; + if ((dragableTransitions.indexOf(currentPage[4].transition) === -1) && (currentPage[4].transition || dragableTransitions.indexOf(defaultTransition) === -1)) { + return; + } else if ((currentPage[4].transition === 'slide-left') || (!currentPage[4].transition && 'slide-left' === defaultTransition)) { + slideLeft = true; + } + + var oldPosition = currentPage[3].style.position, + oldZIndex = currentPage[3].style.zIndex, + oldBackground = currentPage[3].style.background; + currentPage[3].style.position = 'fixed'; + currentPage[3].style.zIndex = '4000'; + currentPage[3].style.background = 'none'; //TODO: this sucks + if (currentPage[3].nextSibling) { + currentPage[3].parentNode.insertBefore(previousPage[3], currentPage[3].nextSibling); + } else { + currentPage[3].parentNode.appendChild(previousPage[3]); + } + + Pages.fixContent(oldNode); + Scroll.restoreScrollPosition(oldNode); + + window.addEventListener('touchstart', startDrag, false); + window.addEventListener('touchmove', dragMove, false); + window.addEventListener('touchcancel', finishDrag, false); + window.addEventListener('touchend', finishDrag, false); + + var goBack = false; + + dragLock = function() { + unbindListeners(); + cleanupElems(); + }; + + function unbindListeners() { + window.removeEventListener('touchstart', startDrag); + window.removeEventListener('touchmove', dragMove); + window.removeEventListener('touchcancel', finishDrag); + window.removeEventListener('touchend', finishDrag); + } + + function cleanupElems() { + currentPage[3].style.position = oldPosition; + currentPage[3].style.zIndex = oldZIndex; + currentPage[3].style.background = oldBackground; + if (previousPage[3].parentNode) { + previousPage[3].parentNode.removeChild(previousPage[3]); + } + } + + function startDrag(e) { + if (draggingTouch || navigationLock || dead) { + return; + } + var touch = (e.touches && e.touches[0]); + if (!touch || (touch.pageX > WALL_RADIUS)) { + return; + } + + if (!Pages.fire(currentPage[2], currentPage[3], Pages.EVENTS.BEFORE_BACK)) { + return; + } + + e.preventDefault(); + + App._Navigation.enqueue(function(unlock) { + navigationLock = unlock; + //TODO: what if transition is already over? + }, true); + + document.body.className += ' ' + TRANSITION_CLASS; + + draggingTouch = lastTouch = { + x: touch.pageX, + y: touch.pageY + }; + + currentBar.style.webkitTransition = 'all 0s linear'; + if (currentTitle) { + currentTitle.style.webkitTransition = 'all 0s linear'; + } + if (currentBack) { + currentBack.style.webkitTransition = 'all 0s linear'; + } + currentContent.style.webkitTransition = 'all 0s linear'; + oldBar.style.webkitTransition = 'all 0s linear'; + if (oldTitle) { + oldTitle.style.webkitTransition = 'all 0s linear'; + } + if (oldBack) { + oldBack.style.webkitTransition = 'all 0s linear'; + } + oldContent.style.webkitTransition = 'all 0s linear'; + } + + function dragMove(e) { + if (draggingTouch && e.touches && e.touches[0] && !dead) { + if (lastTouch) { + goBack = (lastTouch.x < e.touches[0].pageX); + } + lastTouch = { + x: e.touches[0].pageX, + y: e.touches[0].pageY + }; + + var progress = Math.min(Math.max(0, (lastTouch.x - draggingTouch.x) / window.innerWidth), 1); + setDragPosition(progress); + } + } + + function finishDrag(e) { + if (!draggingTouch || !navigationLock || dead) { + return; + } + + unbindListeners(); + + lastTouch = (e.touches && e.touches[0]) || lastTouch; + var progess = 0; + if (lastTouch) { + progress = (lastTouch.x - draggingTouch.x) / window.innerWidth; + } + var dontTransition = ((progress < 0.1 && !goBack) || (0.9 < progress && goBack)); + + if (!dontTransition) { + currentBar.style.webkitTransitionDuration = '0.15s'; + if (currentTitle) { + currentTitle.style.webkitTransitionDuration = '0.15s'; + } + if (currentBack) { + currentBack.style.webkitTransitionDuration = '0.15s'; + } + currentContent.style.webkitTransitionDuration = '0.15s'; + oldBar.style.webkitTransitionDuration = '0.15s'; + if (oldTitle) { + oldTitle.style.webkitTransitionDuration = '0.15s'; + } + if (oldBack) { + oldBack.style.webkitTransitionDuration = '0.15s'; + } + oldContent.style.webkitTransitionDuration = '0.15s'; + } + + if (goBack) { + Pages.fire(currentPage[2], currentPage[3], Pages.EVENTS.BACK); + setDragPosition(1); + } else { + setDragPosition(0); + } + draggingTouch = lastTouch = null; + + if (!dontTransition) { + currentPage[3].addEventListener('webkitTransitionEnd', finishTransition, false); + } else { + finishTransition(); + } + + function finishTransition() { + currentPage[3].removeEventListener('webkitTransitionEnd', finishTransition); + + if (goBack) { + if (currentPage[3].parentNode) { + currentPage[3].parentNode.removeChild(currentPage[3]); + } + } else { + if (previousPage[3].parentNode) { + previousPage[3].parentNode.removeChild(previousPage[3]); + } + } + + currentPage[3].style.position = oldPosition; + currentPage[3].style.zIndex = oldZIndex; + currentPage[3].style.background = oldBackground; + + currentBar.style.webkitTransition = ''; + currentBar.style.webkitTransform = ''; + if (currentTitle) { + currentTitle.style.webkitTransition = ''; + currentTitle.style.webkitTransform = ''; + } + if (currentBack) { + currentBack.style.webkitTransition = ''; + currentBack.style.webkitTransform = ''; + } + currentContent.style.webkitTransition = ''; + currentContent.style.webkitTransform = ''; + oldBar.style.webkitTransition = ''; + oldBar.style.webkitTransform = ''; + if (oldTitle) { + oldTitle.style.webkitTransition = ''; + oldTitle.style.webkitTransform = ''; + } + if (oldBack) { + oldBack.style.webkitTransition = ''; + oldBack.style.webkitTransform = ''; + } + oldContent.style.webkitTransition = ''; + oldContent.style.webkitTransform = ''; + + document.body.className = document.body.className.replace(new RegExp('\\b' + TRANSITION_CLASS + '\\b'), ''); + + if (goBack) { + Pages.startDestruction(currentPage[0], currentPage[2], currentPage[3], currentPage[1]); + Pages.fixContent(oldNode); + Scroll.restoreScrollStyle(oldNode); + currentPage[2].showing = false + Pages.fire(currentPage[2], currentPage[3], Pages.EVENTS.HIDE); + previousPage[2].showing = true + Pages.fire(previousPage[2], oldNode, Pages.EVENTS.SHOW); + Pages.finishDestruction(currentPage[0], currentPage[2], currentPage[3], currentPage[1]); + + Stack.pop(); + App._Navigation.update(); + } + + dragLock = null; + navigationLock(); + } + } + + function setDragPosition(progress) { + if (slideLeft) { + currentBar.style.opacity = 1 - progress; + if (currentTitle) { + currentTitle.style.webkitTransform = 'translate3d(' + (progress * window.innerWidth / 2) + 'px,0,0)'; + } + if (currentBack) { + currentBack.style.webkitTransform = 'translate3d(' + (progress * (window.innerWidth - currentBack.textContent.length * 12) / 2) + 'px,0,0)'; + } + if (oldTitle) { + oldTitle.style.webkitTransform = 'translate3d(' + ((1 - progress) * (window.innerWidth - currentBack.textContent.length * 12) / -2) + 'px,0,0)'; + } + if (oldBack) { + oldBack.style.webkitTransform = 'translate3d(' + ((1 - progress) * -150) + '%,0,0)'; + } + } else { + currentBar.style.webkitTransform = 'translate3d(' + (progress * 100) + '%,0,0)'; + oldBar.style.webkitTransform = 'translate3d(' + ((1 - progress) * -30) + '%,0,0)'; + } + currentContent.style.webkitTransform = 'translate3d(' + (progress * 100) + '%,0,0)'; + oldContent.style.webkitTransform = 'translate3d(' + ((1 - progress) * -30) + '%,0,0)'; + } + } + + function disableIOS7DragTransition() { + if (dragLock) { + dragLock(); + dragLock = null; + } + } +}(window, document, Swapper, App, App._Utils, App._Scroll, App._Pages, App._Stack); +App._Navigation = function(window, document, App, Dialog, Scroll, Pages, Stack, Transitions) { + var navQueue = [], + navLock = false, + current, currentNode; + + App.current = function() { + return current; + }; + + App.load = function(pageName, args, options, callback) { + if (typeof pageName !== 'string') { + throw TypeError('page name must be a string, got ' + pageName); + } + switch (typeof args) { + case 'function': + options = args; + args = {}; + case 'string': + callback = options; + options = args; + case 'undefined': + args = {}; + case 'object': + break; + default: + throw TypeError('page arguments must be an object if defined, got ' + args); + } + switch (typeof options) { + case 'function': + callback = options; + case 'undefined': + options = {}; + case 'object': + break; + case 'string': + options = { + transition: options + }; + break; + default: + throw TypeError('options must be an object if defined, got ' + options); + } + switch (typeof callback) { + case 'undefined': + callback = function() {}; + case 'function': + break; + default: + throw TypeError('callback must be a function if defined, got ' + callback); + } + + return loadPage(pageName, args, options, callback); + }; + + App.back = function(pageName, callback) { + switch (typeof pageName) { + case 'function': + callback = pageName; + case 'undefined': + pageName = undefined; + case 'string': + break; + default: + throw TypeError('pageName must be a string if defined, got ' + pageName); + } + switch (typeof callback) { + case 'undefined': + callback = function() {}; + case 'function': + break; + default: + throw TypeError('callback must be a function if defined, got ' + callback); + } + + return navigateBack(pageName, callback); + }; + + App.pick = function(pageName, args, options, loadCallback, callback) { + if (typeof pageName !== 'string') { + throw TypeError('page name must be a string, got ' + pageName); + } + switch (typeof args) { + case 'function': + options = args; + args = {}; + case 'string': + callback = loadCallback; + loadCallback = options; + options = args; + case 'undefined': + args = {}; + case 'object': + break; + default: + throw TypeError('page arguments must be an object if defined, got ' + args); + } + switch (typeof options) { + case 'function': + callback = loadCallback; + loadCallback = options; + case 'undefined': + options = {}; + case 'object': + break; + case 'string': + options = { + transition: options + }; + break; + default: + throw TypeError('options must be an object if defined, got ' + options); + } + if (typeof loadCallback !== 'function') { + throw TypeError('callback must be a function, got ' + loadCallback); + } + switch (typeof callback) { + case 'undefined': + callback = loadCallback; + loadCallback = function() {}; + case 'function': + break; + default: + throw TypeError('callback must be a function, got ' + callback); + } + + return pickPage(pageName, args, options, loadCallback, callback); + }; + + App.info = function () { + return { + platform:App.platform + } + } + + return { + getCurrentNode: getCurrentNode, + update: updateCurrentNode, + enqueue: navigate + }; + + + + function navigate(handler, dragTransition) { + if (navLock) { + navQueue.push(handler); + return false; + } + + navLock = true; + if (!dragTransition) { + Transitions.disableDrag(); + } + + handler(function() { + Stack.save(); + + navLock = false; + if (!processNavigationQueue()) { + Transitions.enableDrag(); + } + }); + + return true; + } + + function processNavigationQueue() { + if (navQueue.length) { + navigate(navQueue.shift()); + return true; + } else { + return false; + } + } + + + + function getCurrentNode() { + return currentNode; + } + + function updateCurrentNode() { + var lastStackItem = Stack.getCurrent(); + current = lastStackItem[0] + currentNode = lastStackItem[3]; + } + + function loadPage(pageName, args, options, callback, setupPickerMode) { + navigate(function(unlock) { + var oldNode = currentNode, + pageManager = Pages.createManager(false); + + if (setupPickerMode) { + setupPickerMode(pageManager); + } + + var page = Pages.startGeneration(pageName, pageManager, args), + restoreData = Stack.getCurrent(), + restoreNode = restoreData && restoreData[3], + restoreManager = restoreData && restoreData[2]; + + if (!options.transition && pageManager.transition) { + options.transition = pageManager.transition; + } + if (!options.duration && pageManager.duration) { + options.duration = pageManager.duration; + } + + Pages.populateBackButton(page, oldNode || restoreNode); + + if (!current) { + App.restore = null; + document.body.appendChild(page); + Pages.fire(pageManager, page, Pages.EVENTS.LAYOUT); + updatePageData(); + finish(); + } else { + Scroll.saveScrollPosition(currentNode); + var newOptions = {}; + for (var key in options) { + newOptions[key] = options[key]; + } + uiBlockedTask(function(unlockUI) { + Transitions.run(currentNode, page, newOptions, function() { + Pages.fixContent(page); + unlockUI(); + finish(); + }); + Pages.fire(pageManager, page, Pages.EVENTS.LAYOUT); + }); + //TODO: what if instant swap? + updatePageData(); + } + + function updatePageData() { + current = pageName; + currentNode = page; + Stack.push([pageName, args, pageManager, page, options]); + if (oldNode && restoreManager) { + Pages.fire(restoreManager, oldNode, Pages.EVENTS.FORWARD); + } + } + + function finish() { + Scroll.saveScrollStyle(oldNode); + Pages.finishGeneration(pageName, pageManager, page, args); + + unlock(); + callback(); + + if (oldNode && restoreManager) { + restoreManager.showing = false + Pages.fire(restoreManager, oldNode, Pages.EVENTS.HIDE); + } + pageManager.showing = true; + Pages.fire(pageManager, page, Pages.EVENTS.SHOW); + } + }); + + if (!Pages.has(pageName)) { + return false; + } + } + + function navigateBack(backPageName, callback) { + if (Dialog.status() && Dialog.close() && !backPageName) { + callback(); + return; + } + + var stack = Stack.get().map(function(page) { + return page[0]; + }); + + if (!stack.length) { + throw Error(backPageName + ' is not currently in the stack, cannot go back to it'); + } + + if (backPageName) { + var index = -1; + for (var i = stack.length - 1; i >= 0; i--) { + if (stack[i] === backPageName) { + index = i; + break; + } + } + if (index === -1) { + throw Error(backPageName + ' is not currently in the stack, cannot go back to it'); + } + if (index !== stack.length - 2) { + App.removeFromStack(index + 1); + } + } + + var stackLength = stack.length, + cancelled = false; + + var navigatedImmediately = navigate(function(unlock) { + if (Stack.size() < 2) { + unlock(); + callback(); + return; + } + + var oldPage = Stack.getCurrent(); + + if (!Pages.fire(oldPage[2], oldPage[3], Pages.EVENTS.BEFORE_BACK)) { + cancelled = true; + unlock(); + callback(); + return; + } else { + Stack.pop(); + } + + var data = Stack.getCurrent(), + pageName = data[0], + page = data[3], + oldOptions = oldPage[4]; + + Pages.fire(oldPage[2], oldPage[3], Pages.EVENTS.BACK); + + Pages.fixContent(page); + + Pages.startDestruction(oldPage[0], oldPage[2], oldPage[3], oldPage[1]); + + Scroll.restoreScrollPosition(page); + + var newOptions = {}; + for (var key in oldOptions) { + if (key === 'transition') { + newOptions[key] = Transitions.REVERSE_TRANSITION[oldOptions[key]] || oldOptions[key]; + } else { + newOptions[key] = oldOptions[key]; + } + } + + uiBlockedTask(function(unlockUI) { + Transitions.run(currentNode, page, newOptions, function() { + Pages.fixContent(page); + Scroll.restoreScrollStyle(page); + unlockUI(); + + oldPage[2].showing = false + Pages.fire(oldPage[2], oldPage[3], Pages.EVENTS.HIDE); + data[2].showing = true + Pages.fire(data[2], page, Pages.EVENTS.SHOW); + + setTimeout(function() { + Pages.finishDestruction(oldPage[0], oldPage[2], oldPage[3], oldPage[1]); + + unlock(); + callback(); + }, 0); + }, true); + Pages.fixContent(page); + Pages.fire(data[2], page, Pages.EVENTS.LAYOUT); + }); + + current = pageName; + currentNode = page; + }); + + if (cancelled || (navigatedImmediately && (stackLength < 2))) { + return false; + } + } + + function pickPage(pageName, args, options, loadCallback, callback) { + var finished = false; + loadPage(pageName, args, options, loadCallback, function(pageManager) { + pageManager.restorable = false; + pageManager.reply = function() { + if (!finished) { + finished = true; + if (!pageManager._appNoBack) { + navigateBack(undefined, function() {}); + } + callback.apply(App, arguments); + } + }; + }); + } + + + + // blocks UI interaction during some aysnchronous task + // is not locked because multiple calls dont effect eachother + function uiBlockedTask(task) { + var taskComplete = false; + + var clickBlocker = document.createElement('div'); + clickBlocker.className = 'app-clickblocker'; + document.body.appendChild(clickBlocker); + clickBlocker.addEventListener('touchstart', function(e) { + e.preventDefault(); + }, false); + + task(function() { + if (taskComplete) { + return; + } + taskComplete = true; + + document.body.removeChild(clickBlocker); + }); + } +}(window, document, App, App._Dialog, App._Scroll, App._Pages, App._Stack, App._Transitions); +// Hack to fix Android L issue where touch events don't get propagated +(function(document, App, Utils) { + if (App.platform !== 'android' || App.platformVersion < 5) { + return; + } + Utils.ready(function() { + setTimeout(function() { + var nodes = [].slice.call(document.body.childNodes); + nodes.forEach(function(node) { + document.body.removeChild(node); + }); + nodes.forEach(function(node) { + document.body.appendChild(node); + }); + }, 200); + }); +})(document, App, App._Utils);