From 493d30081e69795ccac2e1cafcfeb65fff24f0af Mon Sep 17 00:00:00 2001 From: lh_wang Date: Wed, 19 Aug 2015 18:47:22 +0800 Subject: [PATCH] add cat app --- catapp/.project | 37 + catapp/css/Jingle.css | 2070 ++++++++ catapp/css/main.css | 76 + catapp/html/appMonitor_section.html | 64 + catapp/html/index.html | 148 + catapp/index.html | 177 + catapp/js/JChart.debug.js | 2121 ++++++++ catapp/js/Jingle.debug.js | 2117 ++++++++ catapp/js/barcodescanner.js | 15 + catapp/js/cordova.js | 6947 +++++++++++++++++++++++++++ catapp/js/iscroll.js | 1104 +++++ catapp/js/main.js | 243 + catapp/js/template.min.js | 1 + catapp/js/zepto.js | 2420 ++++++++++ catapp/js/zepto.touch2mouse.js | 89 + 15 files changed, 17629 insertions(+) create mode 100644 catapp/.project create mode 100644 catapp/css/Jingle.css create mode 100644 catapp/css/main.css create mode 100644 catapp/html/appMonitor_section.html create mode 100755 catapp/html/index.html create mode 100644 catapp/index.html create mode 100644 catapp/js/JChart.debug.js create mode 100644 catapp/js/Jingle.debug.js create mode 100644 catapp/js/barcodescanner.js create mode 100644 catapp/js/cordova.js create mode 100644 catapp/js/iscroll.js create mode 100644 catapp/js/main.js create mode 100644 catapp/js/template.min.js create mode 100644 catapp/js/zepto.js create mode 100644 catapp/js/zepto.touch2mouse.js diff --git a/catapp/.project b/catapp/.project new file mode 100644 index 0000000..31ab36c --- /dev/null +++ b/catapp/.project @@ -0,0 +1,37 @@ + + + catdemoapp + Create By HBuilder + + + + + com.aptana.ide.core.unifiedBuilder + + + + + + com.aptana.projects.webnature + + + + 1439967738909 + + 10 + + org.eclipse.ui.ide.orFilterMatcher + + + org.eclipse.ui.ide.multiFilter + 1.0-projectRelativePath-matches-false-false-bin + + + org.eclipse.ui.ide.multiFilter + 1.0-projectRelativePath-matches-false-false-setting + + + + + + diff --git a/catapp/css/Jingle.css b/catapp/css/Jingle.css new file mode 100644 index 0000000..f0b2721 --- /dev/null +++ b/catapp/css/Jingle.css @@ -0,0 +1,2070 @@ +a, abbr, address, article, aside, audio, b, blockquote, body, caption, cite, code, dd, del, dfn, dialog, div, dl, dt, em, fieldset, figure, footer, form, h1, h2, h3, h4, h5, h6, header, hgroup, hr, html, i, iframe, img, ins, kbd, label, legend, li, mark, menu, nav, object, ol, p, pre, q, samp, section, small, span, strong, sub, sup, tfoot, th, thead, time, tr, ul, var, video { + border: 0; + margin: 0; + outline: 0; + padding: 0; + font-size: 100%; + font-weight: normal +} +body { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + -webkit-user-select: none; + -webkit-touch-callout: none; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + -webkit-text-size-adjust:none; + /* background-color: #222;*/ + font: 16px/1.25 "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: bold; + letter-spacing: -0.05em; + overflow: hidden; +} +html{ + -webkit-text-size-adjust: none; +} + +body * { + -webkit-box-sizing: border-box; + box-sizing: border-box; + margin: 0; + padding: 0; + -webkit-user-select: none; + -webkit-tap-highlight-color: rgba(255, 255, 255, 0); + -webkit-font-smoothing: antialiased; +} + +a { + text-decoration: none; + color: #fff; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +a:hover { + opacity: 1 +} + +img { + border: 0; + -ms-interpolation-mode: bicubic; + vertical-align: middle; + font-size: 0 +} + +table { + border-collapse: collapse; + border-spacing: 0 +} + +th, td, caption { + vertical-align: top; + text-align: left +} + +sub,sup{ + font-size: 10px; +} + +.bold{ + font-weight: 600; +} +.fr{ + float:right; +} +.fl{ + float:left; +} +.clearfix:before, +.clearfix:after { + content: ""; + display: table; +} + +.clearfix:after { + clear: both; +} +h1,h2,h3,h4,h5,h6, +.h1,.h2,.h3,.h4,.h5,.h6 { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: 500; + line-height: 1.1; + color: inherit; +} + +h1 small,h2 small,h3 small,h4 small,h5 small,h6 small, +.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small, +h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small { + font-weight: normal; + line-height: 1; + color: #999999; +} + +h1,h2,h3 { + margin-top: 20px; + margin-bottom: 10px; +} + +h1 small,h2 small,h3 small,h1 .small,h2 .small,h3 .small { + font-size: 65%; +} + +h4,h5,h6 { + margin-top: 10px; + margin-bottom: 10px; +} + +h4 small,h5 small,h6 small,h4 .small,h5 .small,h6 .small { + font-size: 75%; +} + +h1,.h1 { + font-size: 36px; +} + +h2,.h2 { + font-size: 30px; +} + +h3,.h3 { + font-size: 24px; +} + +h4,.h4 { + font-size: 18px; +} + +h5,.h5 { + font-size: 14px; +} + +h6,.h6 { + font-size: 12px; +} +/******colors**********/ +.turquoise{background-color: #1ABC9C !important;} +.green-sea{background-color: #16A085 !important;} +.emerland{background-color: #78ba00 !important;} +.nephritis{background-color: #27AE60 !important;} +.peter-river{background-color: #3498DB !important;} +.belize-hole{background-color: #2980B9 !important;} +.amethyst{background-color: #9B59B6 !important;} +.wisteria{background-color: #8E44AD !important;} +.wet-asphalt{background-color: #2C3E50 !important;} +.midnight-blue{background-color: #2C3E50 !important;} +.concrete{background-color: #95A5A6 !important;} +.asbestos{background-color: #7F8C8D !important;} +.clouds{background-color: #ECF0F1 !important;color:#666 !important} +.sliver{background-color:#BDC3C7 !important;} +.alizarin{background-color:#E74C3C !important;} +.pomegranate{background-color:#C0392B !important;} +.carrot{background-color:#E67E22 !important;} +.pumpkin{background-color:#D35400 !important;} +.sun-flower{background-color:#F1C40F !important;} +.orange{background-color:#F39C12 !important;} +.violet{background-color: #9f00a7 !important;} +/********** tip arrow*****************/ +.tip-arrow-down:after{ + content: "▼"; + position: relative; + left: 1px; + font-size: 0.9em +} +.tip-arrow-up:after{ + content: "▲"; + position: relative; + left: 1px; + font-size: 0.9em; +} +[data-scroll="true"]{ + overflow: auto; +} +#jingle_welcome{ + position: absolute; + top:0; + left: 0; + bottom: 0; + right: 0; + z-index: 999; + overflow: hidden; + background-color: #fff; +} +/**** for page ***/ +@-webkit-keyframes emptyAnim{ + 0% { -webkit-transform: scale(1)} + 100% { -webkit-transform:scale(1)} +} +@-webkit-keyframes slideLeftIn { + 0% { -webkit-transform: translate3d(100%,0,0)} + 100% { -webkit-transform: translate3d(0,0,0)} +} +@-webkit-keyframes slideLeftOut { + 0% { -webkit-transform: translate3d(0,0,0)} + 100% { -webkit-transform: translate3d(-100%,0,0)} +} +@-webkit-keyframes slideRightIn { + 0% { -webkit-transform: translate3d(-100%,0,0)} + 100% { -webkit-transform: translate3d(0%,0,0) } +} +@-webkit-keyframes slideRightOut { + 0% { -webkit-transform: translate3d(0%,0,0)} + 100% { -webkit-transform: translate3d(100%,0,0)} +} +@-webkit-keyframes scaleIn { + 0% {opacity: 0;-webkit-transform: scale(.5)} + 100% {opacity: 1;-webkit-transform: scale(1)} +} +@-webkit-keyframes scaleOut { + 0% {opacity: 1;-webkit-transform: scale(1)} + 100% {opacity: 0;-webkit-transform: scale(.5)} +} +@-webkit-keyframes slideDownIn { + 0% {opacity: 0;-webkit-transform: translate3d(0,-100%,0)} + 100% {opacity: 1;-webkit-transform: translate3d(0,0,0)} +} +@-webkit-keyframes slideUpOut { + 0% {opacity: 1;-webkit-transform: translate3d(0,0,0)} + 100% {opacity: 0;-webkit-transform: translate3d(0,-100%,0)} +} +@-webkit-keyframes slideDownOut { + 0% {-webkit-transform: translate3d(0,0,0)} + 100% {-webkit-transform: translate3d(0,100%,0)} +} +@-webkit-keyframes slideUpIn { + 0% {-webkit-transform: translate3d(0,90%,0)} + 100% {-webkit-transform: translate3d(0,0,0)} +} + +section.anim{ + -webkit-animation-duration: 250ms; + -webkit-animation-fill-mode: both; + -webkit-animation-timing-function: ease-in-out +} +.empty{ + z-index: 4 !important; + -webkit-animation-name: emptyAnim; +} + +.slideLeftOut{ + -webkit-animation-name: slideLeftOut; +} +.slideLeftIn{ + -webkit-animation-name: slideLeftIn; +} +.slideRightIn{ + -webkit-animation-name: slideRightIn; +} +.slideRightOut{ + -webkit-animation-name: slideRightOut; +} +.scaleIn{ + -webkit-animation-name: scaleIn; +} +.scaleOut{ + -webkit-animation-name: scaleOut; +} +.slideDownIn{ + -webkit-animation-name: slideDownIn; +} +.slideDownOut{ + -webkit-animation-name: slideDownOut; +} +.slideUpIn{ + z-index: 10; + -webkit-animation-name: slideUpIn; +} +.slideUpOut{ + -webkit-animation-name: slideUpOut; +} +/******** for calendar *******/ +@-webkit-keyframes slideLeftRound { + 0% { -webkit-transform: translate3d(0%,0,0)} + 40% { -webkit-transform: translate3d(-40%,0,0)} + 41% { -webkit-transform: translate3d(60%,0,0)} + 100% { -webkit-transform: translate3d(0%,0,0)} +} +@-webkit-keyframes slideRightRound { + 0% { -webkit-transform: translate3d(0%,0,0)} + 40% { -webkit-transform: translate3d(40%,0,0)} + 41% { -webkit-transform: translate3d(-60%,0,0)} + 100% { -webkit-transform: translate3d(0%,0,0)} +} +/********** for popup toast **********/ +@-webkit-keyframes bounceIn { + 0% {opacity: 0;-webkit-transform: scale(.3);} + 50% {opacity: 1;-webkit-transform: scale(1.1);} + 100% {-webkit-transform: scale(1);} +} +@-webkit-keyframes bounceOut { + 0% {-webkit-transform: scale(1);} + 100% {opacity: 0;-webkit-transform: scale(.5);} +} +aside[data-position="left"]{ + left:0; + -webkit-transform:translateX(-100%); + transform:translateX(-100%); +} +aside[data-position="right"]{ + right:0; + -webkit-transform:translateX(100%); + transform:translateX(100%); +} +aside[data-transition="overlay"]{ + z-index: 4; +} +aside[data-transition="reveal"]{ + z-index: 2; +} +aside[data-position][data-transition="reveal"]{ + -webkit-transform:translateX(0); + transform:translateX(0); +} +aside{ + display: none; + font-size: 1.1em; + box-orient:vertical; + -webkit-box-orient:vertical; +} +aside.active{ + display: -webkit-box; + display: box; +} +.aside-close{ + position: absolute; + top:0; + color: #ECF0F1; + padding: 10px; +} +aside[data-position="left"] .aside-close{ + right: 0; +} +aside[data-position="right"] .aside-close{ + left: 0; +} +aside > *{ + -webkit-box-flex : 0; +} +aside>.header{ + overflow: hidden; + height: 44px; + line-height: 44px; + text-align: center; + font-size: 1.2em; + font-weight: bold; +} +aside>.center{ + -webkit-box-flex : 1; + overflow: auto; +} +aside ul.menu li { + border-bottom: 1px solid rgba(0, 0, 0, .1); +} +aside ul.menu li a { + padding: 10px 20px; + display: block; +} +aside ul.menu li a .icon{ + float:left; +} +aside ul.menu li.anchor{ + padding: 2px 10px; + font-size: 0.9em; +} +.back-mask{ + width: 200px;margin:60px auto;text-align: center;color: #7F8C8D +} +.back-mask .icon{ + font-size: 80px;line-height: 80px;display: block;margin-bottom: 10px; +} +.button, button { + display: inline-block; + padding: 8px 14px; + border: none; + cursor: pointer; + text-align: center; + text-decoration: none; + outline: none; + border-radius: 4px; +} + +.button:disabled, button:disabled, .button.disabled, button.disabled { + background: rgba(185, 180, 182, 0.20); + color: #999 !important +} + +.button.small, button.small { + height: 30px; + padding: 0 8px; + font-size: 1em; + line-height: 28px +} +.button:active,button:active { + opacity: .6; +} +.button.block,button.block{ + width:100%; +} +.button .icon, button .icon{ + float:left; +} +.jingle-calendar{ + width: 100%; + overflow: hidden; +} +.jingle-calendar-nav{ + height: 50px; + line-height: 50px; + display: -webkit-box; + display: box; + text-align: center; +} +.jingle-calendar-nav>div{ + -webkit-box-flex : 1; +} +.jingle-calendar-nav i.icon{ + padding: 10px; +} +.jingle-calendar-body{ + overflow-x: hidden; +} +.jingle-calendar table{ + width: 100%; +} +.jingle-calendar table th{ + text-align: center; + padding: 5px 0; +} +.jingle-calendar table td{ + text-align: center; + padding: 15px 0; +} + +.control-group { + display: -webkit-box; + display: box; + overflow: hidden; + list-style: none; + border-radius: 4px; +} + +.control-group li { + overflow: hidden; + text-align: center; + white-space: nowrap; + -webkit-box-flex: 1; + box-flex: 1; + padding: 5px 0; + border-width: 1px; + border-style: solid; + border-right-width: 0; +} + +.control-group li > a { + display: block; + overflow: hidden; + text-overflow: ellipsis; +} + +.control-group li:first-child { + border-radius: 4px 0 0 4px; +} +.control-group li:last-child { + border-right-width: 1px; + border-radius: 0 4px 4px 0; +} +.control-group i.icon ~ a { + padding: 0; +} + +[data-count]{ + position: relative; +} +.count{ + position:absolute; + border-radius: 30px; + color: #fff; + line-height: 18px; + padding: 0 5px; + font-size: 12px; + font-weight: 500; + min-width: 8px; + text-align: center; + right: 7px; + left: auto; + top:0; + opacity: .8; +} +.count.left{ + left:7px; + right:auto; +} +footer{ + bottom:0; + display: -webkit-box; + display: box; + border-top: 1px solid #C8C8C8; +} +footer > a{ + -webkit-box-flex : 1; + box-flex : 1; + display: block; + text-align: center; + font-size: 0.85em; +} +footer > a > .icon{ + float: none; + display: block; + height: 25px; + line-height: 25px; + padding-top: 5px; + margin-bottom: 5px; + font-size: 1.5em; +} +footer > a.label-right{ + text-align: left; + line-height: 51px; +} +footer > a.label-right .icon{ + float: left; + line-height: 51px; + padding: 0 5px; + font-size: 2em; +} +.footer-secondary{ + position: absolute; + bottom: 51px; + left: 0; + width: 100%; + z-index: 2; + padding: 10px; + display: none; +} +input, +textarea, +button, +select { + font-family: inherit; + font-size: inherit; +} + +select, +textarea, +input[type="text"], +input[type=search], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="tel"], +input[type="color"], +.input-group { + width: 100%; + height: 40px; + padding: 10px; + margin-bottom: 10px; + border: 1px solid rgba(0, 0, 0, .2); + border-radius: 3px; + -webkit-box-shadow: 0 1px 1px rgba(255, 255, 255, .2), inset 0 1px 1px rgba(0, 0, 0, .1); + box-shadow: 0 1px 1px rgba(255, 255, 255, .2), inset 0 1px 1px rgba(0, 0, 0, .1); + -webkit-appearance: none; + -webkit-user-select: text; + -webkit-font-smoothing: antialiased; + -wekbit-box-sizing: border-box; + box-sizing: border-box; + outline: none; +} + +input[type=search] { + height: 34px; + font-size: 1em; + border-radius: 30px; +} + +textarea { + height: auto; +} + +select { + height: auto; + font-size: 1em; + background-color: #f8f8f8; + background-image: -webkit-linear-gradient(top, #f8f8f8 0%, #d4d4d4 100%); + background-image: linear-gradient(to bottom, #f8f8f8 0%, #d4d4d4 100%); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .1); +} + +.input-group { + width: auto; + height: auto; + padding: 0; +} + +.input-group input { + margin-bottom: 0; + background-color: transparent; + border: 0; + border-bottom: 1px solid rgba(0, 0, 0, .2); + border-radius: 0; + box-shadow: none; +} + +.input-group input:last-child { + border-bottom-width: 0; +} + +.input-row { + display: -webkit-box; + display: box; + overflow: hidden; + border-bottom: 1px solid rgba(0, 0, 0, .2); +} + +.input-row:last-child { + border-bottom-width: 0; +} + +.input-row label { + display: block; + width: 100px; + padding: 11px 10px 9px 13px; + font-weight: 400; +} + +.input-row label + input { + display: block; + -webkit-box-flex: 1; + box-flex : 1; + padding-left: 0; + margin-bottom: 0; + border-bottom: 0; +} + +.input-row label + .toggle { + margin: 10px; +} + +.label { + background-color: #E67E22; + color: #fff; + padding: 2px 5px; + border-radius: 3px; + margin: 0 5px; +} +.grid{ + display: -webkit-box; + display: box; +} +.grid.middle{ + -webkit-box-pack:center; + -webkit-box-align:center; + box-pack:center; + box-align:center; +} +.grid.vertical{ + -webkit-box-orient:vertical; + box-orient:vertical; +} +.grid-label{ + -webkit-box-flex:0; + box-flex:0; + width: 100px; + font-weight: 600; +} +.col-0 {-webkit-box-flex:0;box-flex:0;} +.col-1 {-webkit-box-flex:1;box-flex:1;} +.col-2 {-webkit-box-flex:2;box-flex:2;} +.col-3 {-webkit-box-flex:3;box-flex:3;} +.col-4 {-webkit-box-flex:4;box-flex:3;} +.col-5 {-webkit-box-flex:5;box-flex:5;} + +header { + top: 0; + display: -webkit-box; + display: box; +} +header > *{ + -webkit-box-flex : 0; + box-flex : 0; +} +header nav.left{ + position: absolute; + left:0; + top:0; + z-index: 2; +} +header nav.right{ + position: absolute; + right:0; + top:0; + z-index: 2; +} +header .title { + position: absolute; + top: 0; + left: 0; + display: block; + margin: 0; + width: 100%; + font-size: 1.2em; + line-height: 44px; + text-align: center; + white-space: nowrap; + z-index: 1; +} + +header .button,header button{ + height: 30px; + line-height: 30px; + margin: 5px; + padding: 0 5px; +} +header .button:active, +header button:active { + opacity: .6; +} +header nav{ + padding: 0 5px; +} +header nav a{ + float: left; +} +header nav a:not(.button) { + height: 44px; +} +header nav a:not(.button):active { + opacity: .6; +} + +header nav a:not(.button) > .icon { + font-size: 1.5em; + float:left; +} + +header .control-group{ + margin: 0 auto; + width:140px; + height: 30px; + margin-top: 8px; +} + +.header-secondary{ + display: -webkit-box; + display: box; + text-align: center; +} +.header-secondary > a{ + -webkit-box-flex : 1; + box-flex : 1; + display: block; +} +@font-face { + font-family: 'Jingle'; + src: url(data:application/x-font-ttf;charset=utf-8;base64,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AA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF8AYABhAQIBAwEEAQUBBgEHAQgBCQEKAQsBDAENAQ4BDwEQAREBEgETARQBFQEWARcBGAEZARoBGwEcAR0BHgEfASABIQEiASMBJAElASYBJwEoASkBKgErASwBLQEuAS8BMAExATIBMwE0ATUBNgE3ATgBOQE6ATsBPAE9AT4BPwFAAUEBQgFDAUQBRQFGAUcBSAFJAUoBSwFMAU0BTgFPAVAHdW5pRTAwMAd1bmlFMDAxB3VuaUUwMDIHdW5pRTAwMwd1bmlFMDA0B3VuaUUwMDUHdW5pRTAwNgd1bmlFMDA3B3VuaUUwMDgHdW5pRTAwOQd1bmlFMDBBB3VuaUUwMEIHdW5pRTAwQwd1bmlFMDBEB3VuaUUwMEUHdW5pRTAwRgd1bmlFMDE0B3VuaUUwMTUHdW5pRTAxNgd1bmlFMDE3B3VuaUUwMTgHdW5pRTAxOQd1bmlFMDFBB3VuaUUwMUIHdW5pRTAxQwd1bmlFMDFEB3VuaUUwMUUHdW5pRTAxRgd1bmlFMDIwB3VuaUUwMjEHdW5pRTAyMgd1bmlFMDIzB3VuaUUwMjQHdW5pRTAyNQd1bmlFMDI2B3VuaUUwMjcHdW5pRTAyOAd1bmlFMDI5B3VuaUUwMkEHdW5pRTAyQgd1bmlFMDJDB3VuaUUwMkQHdW5pRTAyRQd1bmlFMDJGB3VuaUUwMzAHdW5pRTAzMQd1bmlFMDMyB3VuaUUwMzMHdW5pRTAzNAd1bmlFMDM1B3VuaUUwMzYHdW5pRTAzNwd1bmlFMDM4B3VuaUUwMzkHdW5pRTAzQQd1bmlFMDNCB3VuaUUwM0MHdW5pRTAzRAd1bmlFMDNFB3VuaUUwM0YHdW5pRTA0MAd1bmlFMDQxB3VuaUUwNDIHdW5pRTA0Mwd1bmlFMDQ0B3VuaUUwNDUHdW5pRTA0Ngd1bmlFMDQ3B3VuaUUwNDkHdW5pRTA0QQd1bmlFMDRCB3VuaUUwNEMHdW5pRTA0RAd1bmlFMDRFB3VuaUUwNEYHdW5pRTA1MAd1bmlFMDQ4B3VuaUUwNTEHdW5pRjAwMAAAAAAAAf//AAIAAQAAAA4AAAAYAAAAAAACAAEAAwCvAAEABAAAAAIAAAAAAAEAAAAAzD2izwAAAADNt0rPAAAAAM23Ss8=) format('truetype'); + font-weight: normal; + font-style: normal; +} + +.icon{ + font-family: 'Jingle'; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + /* reset */ + display: inline; + width: auto; + height: auto; + line-height: inherit;; + vertical-align: baseline; + background-image: none; + background-position: 0% 0%; + background-repeat: repeat; + margin: 0 3px; +} +.icon.left{ + float:left; +} +.icon.right{ + float:right; +} +.icon:before { + text-decoration: inherit; + display: inline-block; + speak: none; +} + +.icon.diamonds:before { + content: "\21"; +} +.icon.next:before { + content: "\22"; +} +.icon.arrow-down:before { + content: "\23"; +} +.icon.arrow-up:before { + content: "\24"; +} +.icon.home:before { + content: "\25"; +} +.icon.home-2:before { + content: "\26"; +} +.icon.office:before { + content: "\27"; +} +.icon.newspaper:before { + content: "\28"; +} +.icon.pencil:before { + content: "\29"; +} +.icon.pencil-2:before { + content: "\2a"; +} +.icon.quill:before { + content: "\2b"; +} +.icon.image:before { + content: "\2c"; +} +.icon.camera:before { + content: "\2d"; +} +.icon.music:before { + content: "\2e"; +} +.icon.headphones:before { + content: "\2f"; +} +.icon.camera-2:before { + content: "\30"; +} +.icon.pacman:before { + content: "\31"; +} +.icon.connection:before { + content: "\32"; +} +.icon.podcast:before { + content: "\33"; +} +.icon.book:before { + content: "\34"; +} +.icon.books:before { + content: "\35"; +} +.icon.stack:before { + content: "\36"; +} +.icon.folder:before { + content: "\37"; +} +.icon.folder-open:before { + content: "\38"; +} +.icon.tag:before { + content: "\39"; +} +.icon.tags:before { + content: "\3a"; +} +.icon.barcode:before { + content: "\3b"; +} +.icon.qrcode:before { + content: "\3c"; +} +.icon.cart:before { + content: "\3d"; +} +.icon.phone:before { + content: "\3e"; +} +.icon.phone-hang-up:before { + content: "\3f"; +} +.icon.address-book:before { + content: "\40"; +} +.icon.envelop:before { + content: "\41"; +} +.icon.pushpin:before { + content: "\42"; +} +.icon.location:before { + content: "\43"; +} +.icon.map:before { + content: "\44"; +} +.icon.alarm:before { + content: "\45"; +} +.icon.bell:before { + content: "\46"; +} +.icon.calendar:before { + content: "\47"; +} +.icon.mobile:before { + content: "\48"; +} +.icon.cabinet:before { + content: "\49"; +} +.icon.drawer:before { + content: "\4a"; +} +.icon.drawer-2:before { + content: "\4b"; +} +.icon.drawer-3:before { + content: "\4c"; +} +.icon.redo:before { + content: "\4d"; +} +.icon.forward:before { + content: "\4e"; +} +.icon.reply:before { + content: "\4f"; +} +.icon.bubble:before { + content: "\50"; +} +.icon.bubbles:before { + content: "\51"; +} +.icon.user:before { + content: "\52"; +} +.icon.users:before { + content: "\53"; +} +@-webkit-keyframes spinner { + 0% { -webkit-transform: rotate(0deg); } + 50% { -webkit-transform: rotate(180deg); } + 100% { -webkit-transform: rotate(360deg); } +} +.icon.spinner{ + display: inline-block; + -webkit-animation: spinner .8s infinite linear; + animation: spinner .8s infinite linear; +} +.icon.spinner:before { + content: "\54"; +} +.icon.search:before { + content: "\55"; +} +.icon.expand:before { + content: "\56"; +} +.icon.contract:before { + content: "\57"; +} +.icon.expand-2:before { + content: "\58"; +} +.icon.contract-2:before { + content: "\59"; +} +.icon.key:before { + content: "\5a"; +} +.icon.lock:before { + content: "\5b"; +} +.icon.unlocked:before { + content: "\5c"; +} +.icon.wrench:before { + content: "\5d"; +} +.icon.cogs:before { + content: "\5e"; +} +.icon.cog:before { + content: "\5f"; +} +.icon.wand:before { + content: "\60"; +} +.icon.pie:before { + content: "\61"; +} +.icon.stats:before { + content: "\62"; +} +.icon.bars:before { + content: "\63"; +} +.icon.bars-2:before { + content: "\64"; +} +.icon.gift:before { + content: "\65"; +} +.icon.meter:before { + content: "\66"; +} +.icon.remove:before { + content: "\67"; +} +.icon.airplane:before { + content: "\68"; +} +.icon.truck:before { + content: "\69"; +} +.icon.road:before { + content: "\6a"; +} +.icon.accessibility:before { + content: "\6b"; +} +.icon.target:before { + content: "\6c"; +} +.icon.lightning:before { + content: "\6d"; +} +.icon.switch:before { + content: "\6e"; +} +.icon.power-cord:before { + content: "\6f"; +} +.icon.signup:before { + content: "\70"; +} +.icon.options:before { + content: "\71"; +} +.icon.tree:before { + content: "\72"; +} +.icon.cloud:before { + content: "\73"; +} +.icon.cloud-download:before { + content: "\74"; +} +.icon.cloud-upload:before { + content: "\75"; +} +.icon.earth:before { + content: "\76"; +} +.icon.attachment:before { + content: "\77"; +} +.icon.brightness-medium:before { + content: "\78"; +} +.icon.brightness-contrast:before { + content: "\79"; +} +.icon.contrast:before { + content: "\7a"; +} +.icon.thumbs-up:before { + content: "\7b"; +} +.icon.thumbs-up-2:before { + content: "\7c"; +} +.icon.notification:before { + content: "\7d"; +} +.icon.question:before { + content: "\7e"; +} +.icon.info:before { + content: "\e000"; +} +.icon.info-2:before { + content: "\e001"; +} +.icon.blocked:before { + content: "\e002"; +} +.icon.cancel-circle:before { + content: "\e003"; +} +.icon.checkmark-circle:before { + content: "\e004"; +} +.icon.close:before { + content: "\e005"; +} +.icon.checkmark:before { + content: "\e006"; +} +.icon.minus:before { + content: "\e007"; +} +.icon.plus:before { + content: "\e008"; +} +.icon.enter:before { + content: "\e009"; +} +.icon.exit:before { + content: "\e00a"; +} +.icon.play:before { + content: "\e00b"; +} +.icon.pause:before { + content: "\e00c"; +} +.icon.stop:before { + content: "\e00d"; +} +.icon.backward:before { + content: "\e00e"; +} +.icon.forward-2:before { + content: "\e00f"; +} +.icon.eject:before { + content: "\e014"; +} +.icon.volume-high:before { + content: "\e015"; +} +.icon.volume-medium:before { + content: "\e016"; +} +.icon.volume-low:before { + content: "\e017"; +} +.icon.volume-mute:before { + content: "\e018"; +} +.icon.tab:before { + content: "\e019"; +} +.icon.previous:before { + content: "\e01a"; +} +.icon.checkbox-unchecked:before { + content: "\e01b"; +} +.icon.checkbox-partial:before { + content: "\e01c"; +} +.icon.radio-checked:before { + content: "\e01d"; +} +.icon.radio-unchecked:before { + content: "\e01e"; +} +.icon.crop:before { + content: "\e01f"; +} +.icon.scissors:before { + content: "\e020"; +} +.icon.share:before { + content: "\e021"; +} +.icon.html5:before { + content: "\e022"; +} +.icon.html5-2:before { + content: "\e023"; +} +.icon.chrome:before { + content: "\e024"; +} +.icon.libreoffice:before { + content: "\e025"; +} +.icon.IE:before { + content: "\e026"; +} +.icon.firefox:before { + content: "\e027"; +} +.icon.volume-mute-2:before { + content: "\e028"; +} +.icon.volume-increase:before { + content: "\e029"; +} +.icon.volume-decrease:before { + content: "\e02a"; +} +.icon.loop:before { + content: "\e02b"; +} +.icon.shuffle:before { + content: "\e02c"; +} +.icon.arrow-left:before { + content: "\e02d"; +} +.icon.arrow-right:before { + content: "\e02e"; +} +.icon.arrow-down-right:before { + content: "\e02f"; +} +.icon.arrow-down-2:before { + content: "\e030"; +} +.icon.arrow-down-left:before { + content: "\e031"; +} +.icon.checkbox-checked:before { + content: "\e032"; +} +.icon.file:before { + content: "\e033"; +} +.icon.file-2:before { + content: "\e034"; +} +.icon.rocket:before { + content: "\e035"; +} +.icon.flag:before { + content: "\e036"; +} +.icon.arrow-up-left:before { + content: "\e037"; +} +.icon.arrow-up-2:before { + content: "\e038"; +} +.icon.arrow-up-right:before { + content: "\e039"; +} +.icon.arrow-right-2:before { + content: "\e03a"; +} +.icon.arrow-down-right-2:before { + content: "\e03b"; +} +.icon.arrow-down-3:before { + content: "\e03c"; +} +.icon.arrow-down-left-2:before { + content: "\e03d"; +} +.icon.arrow-left-2:before { + content: "\e03e"; +} +.icon.area:before { + content: "\e03f"; +} +.icon.sina-weibo:before { + content: "\e040"; +} +.icon.renren:before { + content: "\e041"; +} +.icon.qq:before { + content: "\e042"; +} +.icon.signal:before { + content: "\e043"; +} +.icon.database:before { + content: "\e044"; +} +.icon.undo:before { + content: "\e045"; +} +.icon.menu:before { + content: "\e046"; +} +.icon.list:before { + content: "\e047"; +} +.icon.grid:before { + content: "\e049"; +} +.icon.ellipsis:before { + content: "\e04a"; +} +.icon.star:before { + content: "\e04b"; +} +.icon.star-2:before { + content: "\e04c"; +} +.icon.star-3:before { + content: "\e04d"; +} +.icon.arrow-up-3:before { + content: "\e04e"; +} +.icon.arrow-up-right-2:before { + content: "\e04f"; +} +.icon.arrow-up-left-2:before { + content: "\e050"; +} +.icon.target-2:before { + content: "\e048"; +} +.icon.images:before { + content: "\e051"; +} +/** + ****************************** + * * header * + * ********************** + * * * + * aside * * + * * article * + * * * + * * * + * ********************** + * * footer * + ****************************** + +**/ +aside{ + position: absolute; + width: 264px; + top:0; + bottom:0; + -webkit-transform : translateX(-100%); + transform : translateX(-100%); + z-index: 3; +} + +#section_container{ + position: absolute; + overflow: hidden; + top:0; + left:0; + right:0; + bottom: 0; + z-index: 3; + background: #64A4E1; + background-image: -webkit-linear-gradient(top left, #64A4E1, #2CCD8A); + background-image: -moz-linear-gradient(top left, #64A4E1, #2CCD8A); + background-image: -o-linear-gradient(top left, #64A4E1, #2CCD8A); + background-image: linear-gradient(to bottom right, #64A4E1, #2CCD8A); +} +#section_container_mask{ + position: absolute; + overflow: hidden; + top:0; + left:0; + right:0; + bottom: 0; + z-index: 10; + display: none; +} + +section{ + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-color: #fff; + z-index: 4; + overflow:hidden; + display: none; +} +section.anim:after { + content: ""; + position: absolute; + display: block; + top: 0; + left: 0; + bottom: 0; + right: 0 +} +section.active{ + z-index: 6 ; + display: block; +} +section.animating{ + z-index: 5 ; + display: block; +} +article{ + position: absolute; + top: 0; + bottom: 0; + width: 100%; + visibility: hidden; + display: none; + overflow:hidden; + z-index: 0; + background-color: #fff; +} +article.active{ + visibility: visible; + display: block; + z-index: 1; +} +header,footer,.header-secondary{ + position: absolute; + left: 0; + width: 100%; + z-index: 10 +} +header{ + top:0; + height: 44px; + line-height: 44px; +} +.header-secondary{ + top:44px; + height: 30px; + line-height: 30px; + font-size: .9em; +} +footer{ + bottom: 0; + height: 51px; +} +footer ~ article { + bottom: 51px; +} +header ~ article{ + top:44px; +} +.header-secondary{ + top:44px; +} +.header-secondary ~ article{ + top:74px; +} + +/* Lists +-------------------------------------------------- */ +ul.list { + list-style: none; +} + +.list>li { + position: relative; + padding: 15px 20px 15px 10px;; + border-bottom: 1px solid rgba(0, 0, 0, .1); +} +.list>li:first-child { + border-top: 1px solid rgba(0, 0, 0, .1); +} + +.list>li > a:not([class*="button"]) { + position: relative; + display: block; + padding: inherit; + margin:-15px -20px -15px -10px;; + color: inherit; +} +.list>li strong{ + color: #333; + font-size: 1.2em; +} +.list>li p{ + color:#7a7a7a; + font-size: 0.9em; + padding-top: 5px; +} +.list>li > .icon{ + position: absolute; + right: 5px; + top:50%; + font-size: 18px; + margin-top: -9px; + color: #BDC3C7; +} + +.list>li .tag{ + position: absolute; + top:10px; + right: 10px; + padding: 1px 5px; + border-radius: 3px; + font-size: 0.8em; +} +.icon ~ .tag{ + right: 30px !important; +} + + +/* Inset list +-------------------------------------------------- */ + +.list.inset { + width: auto; + margin-right: 10px; + margin-left: 10px; + border: 1px solid rgba(0, 0, 0, .1); + border-radius: 6px; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +.list.inset>li:first-child { + border-top-width: 0; +} +.list.inset>li:last-child { + border-bottom-width: 0; +} + + +.list .divider { + position: relative; + top: -1px; + padding-top: 6px; + padding-bottom: 6px; + font-size: 0.9em; + font-weight: 400; + line-height: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, .5); + background-color: #f8f8f8; + border-top: 1px solid rgba(0, 0, 0, .1); + border-bottom: 1px solid rgba(0, 0, 0, .1); +} + +.list.inset .divider:first-child { + top: 0; + border-top-width: 0; + border-radius: 6px 6px 0 0; +} + +.list.inset .divider:last-child { + border-radius: 0 0 6px 6px; +} +#jingle_popup_mask{ + display: none; + position: absolute; + z-index: 90; + left: 0; + right:0; + top:0; + bottom: 0; + opacity: 0; +} +#jingle_popup{ + display: none; + position: absolute; + left: 0; + right:0; + z-index: 98; + min-height: 50px; +} +#jingle_popup.arrow{ + border-radius: 5px; +} +#jingle_popup.arrow:after{ + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; + border-width: 10px; +} +#jingle_popup.arrow.top:after{ + bottom: 100%; + left: 50%; + margin-left: -10px; + } +#jingle_popup.arrow.right:after{ + left: 100%; + top: 50%; + margin-top: -10px; +} +#jingle_popup.arrow.bottom:after{ + top: 100%; + left: 50%; + margin-left: -10px; +} +#jingle_popup.arrow.left:after{ + top: 50%; + right: 100%; + margin-top: -10px; +} +#popup_btn_container{ + text-align: center; + margin-top: 10px; + display: -webkit-box; + display: box; +} +#popup_btn_container > a{ + -webkit-box-flex:1; + box-flex:1; + padding: 10px; + display: block; + color: #222; + border:1px solid rgba(0, 0, 0, 0.2); + border-left: none; + border-bottom: none; +} +#popup_btn_container > a:last-child{ + border-right: 0 none; +} +.popup-title{ + text-align: left; + padding: 10px; +} +.popup-content{ + padding: 0 10px 10px 10px; + line-height: 1.2em; +} +#tag_close_popup{ + position: absolute; + top: 0; + right: 0; + font-size: 1em; + padding: 5px 5px 10px 10px; +} +#jingle_popup .nav{ + text-align: center; + font-size: 1em; +} + +#jingle_popup.loading{ + top:50%; + left: 50%; + margin: -75px 0 0 -75px; + opacity: .9; + text-align: center; + width: 150px; + height: 150px; + border-radius: 10px; +} +#jingle_popup.loading i.icon{ + font-size: 4em; + line-height: 110px; + margin:0; +} +.actionsheet{ + display: -webkit-box; + display: box; + -webkit-box-orient:vertical; + box-orient:vertical; + padding: 20px; +} +.actionsheet > button{ + -webkit-box-flex:1; + box-flex:1; + margin : 10px 0; + display: block; + width:100%; +} +[data-progress]{ + border-radius: 10px; + height: 25px; + line-height: 25px; + text-align: center; + font-size: 0.9em; +} +[data-progress] .bar{ + float: left; + width:0; + height: 100%; + white-space: nowrap; + border-radius: 10px 0 0 10px; + margin-left: -1px; + +} +[data-rangeinput] input[type="range"]{ + width:80%; +} +input[type="range"] { + width: 100%; + height: 12px; + border-radius: 5px; + -webkit-appearance: none !important; + outline: none; + display: inline-block; +} + +input[type="range"]::-webkit-slider-thumb{ + width: 22px; + height: 22px; + border-radius: 14px; + -webkit-appearance: none !important; +} +[data-rangeinput] input[type="text"]{ + width: 15%; + padding: 5px; + margin:0 5px; + height: 30px; + display: inline-block; +} +.refresh-container{ + padding:10px; + text-align: center; +} +.refresh-icon{ + font-size: 1.1em; + display: inline-block; +} +.refresh-label{ + font-size: 1em; + display: inline-block; +} +.refresh-tip{ + display: block; + padding: 3px; + font-size: .9em; +} +.icon-reverse{ + -webkit-transform:rotate(180deg); + transform:rotate(180deg); + -webkit-transition-duration:.5s; + transition-duration:.5s; +} +.slider{ + position: relative; + overflow: hidden; +} +.slider>div>*{ + display: none; +} +.dots{ + width:100%;height: 20px;position:absolute;left: 0;bottom: 10px;z-index: 999; + opacity: .7; +} +.dots ul{ + margin:0 auto; + width: 112px; + height: 20px; + padding: 0px 8px; + display: -webkit-box; + display: box; +} +.dots ul li{ + list-style: none; + -webkit-box-flex : 1; + height: 20px; + padding:5px 10px; +} +.dots ul li a{ + display: block; + width: 10px;height: 10px; + border-radius: 10px; +} +/*** aside ****/ +aside{ + background: #393939; + color: #fff; +} +.aside-close{ + color: #ECF0F1; +} +aside>.header{ + border-bottom: 1px solid #000; + background-color: #393939; + background-image: -webkit-linear-gradient(top, #393939 0, #2b2b2b 100%); + color: #fff; +} +aside ul.menu li a { + color: #fff; +} +aside ul.menu li.anchor{ + color: #8b9195; +} +/*** background mask **/ +.back-mask{ + color: #7F8C8D +} +/**** button ****/ +.button, button { + color: #fff; + background-color: #46CA5E; +} +.button.light,button.light{ + border: 1px solid #46CA5E; + color: #46CA5E; + background: none; +} +/**** control group **/ +.control-group li{ + border-color:#368CE9; +} +.control-group li > a { + color: #46CA5E; +} +.control-group li.active { + background: #368CE9; + color:#fff; +} +.control-group .icon{ + color: #46CA5E; +} +header .control-group { + margin: 0 auto; + width: 140px; + height: 30px; + margin-top: 8px; + line-height: 30px; +} +header .control-group li{ + border-color: #fff; + padding: 0; +} +header .control-group li.active{ + background: #fff; + color: #158f75; +} +.control-group li.active a,.control-group li.active .icon{ + color: #fff; +} +.control-group .icon{ + color: #46CA5E; +} + +/**** counts ****/ +.count{ + background-color: #E74C3C; +} +/**** dots ****/ +.dots ul li a{ + background: #b9b4b6; +} +.dots ul li.active a{ + background-color: #4c4d4c; +} +/**** footer ****/ +footer{ + background-color: #262F3D; +} +footer > a{ + color: #fff; +} +footer > a.active{ + color: #46CA5E; +} +footer .active .icon{ + color: #46CA5E; +} +.footer-secondary{ + background-color: #262F3D; + color: #fff; +} +/**** header ****/ +header{ + background-color: #46CA5E; + border-bottom: 1px solid #c8c8c8; + color: #fff; +} +header .title{ + color: #fff; +} +header .button,header button{ + background: none; + border: 1px solid #fff; + color: #fff; +} +header nav a:not(.button){ + color: #fff; +} +.header-secondary{ + background-color: #6A7991; + color: #fff; +} +/**** list ****/ +ul.list { + background-color: #fff; +} +.list>li.active{ + background-color: rgba(231, 238, 229, 0.75) !important; +} +.list>li.active>.icon{ + color: #46CA5E; +} +.list>li .tag{ + background-color: #3498DB; + color: #fff; +} +/**** popup ****/ +#jingle_popup_mask{ + background-color: #222; +} +#jingle_popup{ + background-color: #eef3f3; + color: #222; + -webkit-box-shadow: 0px 1px 10px rgba(0, 0, 0, 0.6); +} +#jingle_popup.arrow.top:after{ + border-bottom-color: #CAD1DA; +} +#jingle_popup.arrow.right:after{ + border-left-color: #CAD1DA; +} +#jingle_popup.arrow.bottom:after{ + border-top-color: #CAD1DA; +} +#jingle_popup.arrow.left:after{ + border-right-color: #CAD1DA; +} +#popup_btn_container{ +} +.popup-title{ + color: #33b4db; +} +#tag_close_popup{ + color: #BDC3C7; +} +#jingle_popup .nav{ + color: #000; +} +#jingle_popup .nav.active,#jingle_popup .nav:active{ + background-color: #79db8d !important; + color: #fff; +} +#jingle_popup.loading{ + background-color: #2C3E50; +} +#jingle_popup.loading p{ + color: #BDC3C7; +} +#jingle_popup.loading i.icon{ + color: #fff; +} +/**** progress ****/ +[data-progress]{ + background: #fff; + border: 1px solid #46CA5E; +} +[data-progress] .bar{ + background: #46CA5E; + color: #fff; +} +/**** range ****/ +input[type="range"]{ + border:1px solid #46CA5E; +} +input[type="range"]::-webkit-slider-thumb{ + background: #46CA5E; +} +/**** toggles ****/ +.toggle { + background-color: #656968; +} +.toggle-handle{ + background-color: #fff; + border: 1px solid #656968; +} +.toggle.active { + background-color: #46CA5E; +} +.toggle.active .toggle-handle{ + background-color: #fff; + border:1px solid #46CA5E; +} +/**** selected ****/ +.selected{ + background-color: #E6E6E6 !important; + color: #fff; +} +/**** calendar ****/ +.jingle-calendar{ + background-color: #eee; +} +.jingle-calendar-nav{ + background-color: #262F3D; + color: #fff; +} +.jingle-calendar table thead{ + background: #eee; +} +.jingle-calendar table tbody{ + background: #f5f5f5; +} +.jingle-calendar table td{ + border: 1px solid #fff; +} +.jingle-calendar table td.active{ + background-color: #46CA5E; +} +#jingle_toast{ + display: none; + position: absolute; + z-index: 99; + color: #fff; +} +#jingle_toast{ + top: 70%; + font-size: 1em; + text-align: center; + width: 100%;;left: 0; +} +#jingle_toast.top{ + top: 50px; + opacity: .7; +} +#jingle_toast>a{ + padding: 10px 15px; + background: #222; + display: inline-block; + max-width: 90%; + margin: 0 auto; + color:#fff; + text-align: center; +} +#jingle_toast.top>a{ + width:90%; +} +#jingle_toast.success>a{background-color: #27AE60;!important} +#jingle_toast.error>a{background-color: #E74C3C;!important} +#jingle_toast.info>a{background-color: #F1C40F;!important} + +#jingle_toast i.icon{ + margin-right: 10px; +} +.toggle { + position: relative; + width: 70px; + height: 28px; + border-radius: 8px; + display:inline-block; + text-align: center; +} +/** 自定义文本 **/ +[data-on]:before { + content: attr(data-off) !important; + font-family: "Open Sans" !important; + font-size: .9em !important; + line-height: 28px; + color: #fff; + margin-left: 30px; +} + +[data-on].active:before { + content: attr(data-on) !important; + margin-right: 30px; + margin-left: 0; +} +.toggle-handle { + position: absolute; + top: 0; + left: 0; + z-index: 2; + width: 30px; + height: 28px; + -webkit-transition : left 0.1s ease-in-out; + transition : left 0.1s ease-in-out; + border-radius: 7px 0 0 7px; +} +.toggle.active .toggle-handle { + left:40px; + border-radius:0 7px 7px 0; +} diff --git a/catapp/css/main.css b/catapp/css/main.css new file mode 100644 index 0000000..626553e --- /dev/null +++ b/catapp/css/main.css @@ -0,0 +1,76 @@ +/**** control group **/ +.control-group li{ + border-color:#368CE9; +} + +.control-group li.active { + background: #368CE9; + color:#fff; +} + +.selected{ + background-color: #E6E6E6 !important; + color: #fff; +} + +.chartTitle{ + text-align: center; + font-weight: 600; + font-size: 0.7em; + margin:10px; +} + + +.legend{ + border: 1px solid #b9b4b6; + margin:0 auto; + width: 150px; + border-radius:4px; + padding:3px; + display: -webkit-box; +} +.legend>div{ + -webkit-box-flex : 1; + box-flex : 1; + font-size: 0.7em; +} + +.item_list{ + font-size:0.8em;width:100%;height:25px; +} + +.item_listl_left{ + float:left; + margin-left:10px; +} + + +.item_list_high{ + color:#A1A1A1; +} + +.item_list_right{ + float:right; + margin-right:10px; +} + + +.item_list_green{ + color:#A1A1A1; +} + + +header{ + background-color:#368CE9; +} + +.one-part{ + -webkit-box-flex: 1; + -moz-box-flex: 1; +} + + + + + + diff --git a/catapp/html/appMonitor_section.html b/catapp/html/appMonitor_section.html new file mode 100644 index 0000000..301045c --- /dev/null +++ b/catapp/html/appMonitor_section.html @@ -0,0 +1,64 @@ +
+
+ +

App趋势图

+
+ +
+
    +
  • 请求数
  • +
  • 成功率
  • +
  • 成功延时
  • +
+
请求数(个/每分钟)
+ + + +
+
当前值
+
对比值
+
+ +

当前值

+
+
+ 成功率: 95.799% +
+
+ 总请求数: 85,773 +
+
+ +
+
+ 总请求数(%): 100.000% +
+
+ 成功平均延迟(ms): 13,240 +
+
+ +

对比值

+
+
+ 成功率: 95.799% +
+
+ 总请求数: 85,773 +
+
+
+
+ 总请求数(%): 100.000% +
+
+ 成功平均延迟(ms): 13,240 +
+
+ +
+
+ + diff --git a/catapp/html/index.html b/catapp/html/index.html new file mode 100755 index 0000000..08807d9 --- /dev/null +++ b/catapp/html/index.html @@ -0,0 +1,148 @@ + + + + + CAT V0.1 + + + + + + + + + + + + +
+ +
+
+
+
+

CAT(Central Application Tracking)

+
+ +
+ app_article +
+
+ event_article +
+
+ No_article +
+
+
+
+ +

选择模块

+
+
+
    +
  • Cache
  • +
  • Database
  • +
  • Matraix
  • +
  • State
  • +
+
+
+ +
+ + + \ No newline at end of file diff --git a/catapp/index.html b/catapp/index.html new file mode 100644 index 0000000..c7f874b --- /dev/null +++ b/catapp/index.html @@ -0,0 +1,177 @@ + + + + + + + + + + CAT V0.0.1 + + + + + + + + + + + + + + + + +
+ +
+
+
+
+

CAT

+
+ +
+
    +
  • 请求数
  • +
  • 成功率
  • +
  • 成功延时
  • +
+
请求数(个/每分钟)
+ + + +
+
当前值
+
对比值
+
+ +

当前值

+
+
+ 成功率: 95.799% +
+
+ 总请求数: 85,773 +
+
+ +
+
+ 总请求数(%): 100.000% +
+
+ 成功平均延迟(ms): 13,240 +
+
+ +

对比值

+
+
+ 成功率: 95.799% +
+
+ 总请求数: 85,773 +
+
+
+
+ 总请求数(%): 100.000% +
+
+ 成功平均延迟(ms): 13,240 +
+
+
+
+ event_article +
+
+ No_article +
+
+
+
+ +

选择模块

+
+
+
    +
  • Cache
  • +
  • Database
  • +
  • Matraix
  • +
  • State
  • +
+
+
+
+ + diff --git a/catapp/js/JChart.debug.js b/catapp/js/JChart.debug.js new file mode 100644 index 0000000..476f737 --- /dev/null +++ b/catapp/js/JChart.debug.js @@ -0,0 +1,2121 @@ +window.JingleChart = JChart = { + version : '0.1', + animationOptions : { + linear : function (t){ + return t; + }, + easeInQuad: function (t) { + return t*t; + }, + easeOutQuad: function (t) { + return -1 *t*(t-2); + }, + easeInOutQuad: function (t) { + if ((t/=1/2) < 1) return 1/2*t*t; + return -1/2 * ((--t)*(t-2) - 1); + }, + easeInCubic: function (t) { + return t*t*t; + }, + easeOutCubic: function (t) { + return 1*((t=t/1-1)*t*t + 1); + }, + easeInOutCubic: function (t) { + if ((t/=1/2) < 1) return 1/2*t*t*t; + return 1/2*((t-=2)*t*t + 2); + }, + easeInQuart: function (t) { + return t*t*t*t; + }, + easeOutQuart: function (t) { + return -1 * ((t=t/1-1)*t*t*t - 1); + }, + easeInOutQuart: function (t) { + if ((t/=1/2) < 1) return 1/2*t*t*t*t; + return -1/2 * ((t-=2)*t*t*t - 2); + }, + easeInQuint: function (t) { + return 1*(t/=1)*t*t*t*t; + }, + easeOutQuint: function (t) { + return 1*((t=t/1-1)*t*t*t*t + 1); + }, + easeInOutQuint: function (t) { + if ((t/=1/2) < 1) return 1/2*t*t*t*t*t; + return 1/2*((t-=2)*t*t*t*t + 2); + }, + easeInSine: function (t) { + return -1 * Math.cos(t/1 * (Math.PI/2)) + 1; + }, + easeOutSine: function (t) { + return 1 * Math.sin(t/1 * (Math.PI/2)); + }, + easeInOutSine: function (t) { + return -1/2 * (Math.cos(Math.PI*t/1) - 1); + }, + easeInExpo: function (t) { + return (t==0) ? 1 : 1 * Math.pow(2, 10 * (t/1 - 1)); + }, + easeOutExpo: function (t) { + return (t==1) ? 1 : 1 * (-Math.pow(2, -10 * t/1) + 1); + }, + easeInOutExpo: function (t) { + if (t==0) return 0; + if (t==1) return 1; + if ((t/=1/2) < 1) return 1/2 * Math.pow(2, 10 * (t - 1)); + return 1/2 * (-Math.pow(2, -10 * --t) + 2); + }, + easeInCirc: function (t) { + if (t>=1) return t; + return -1 * (Math.sqrt(1 - (t/=1)*t) - 1); + }, + easeOutCirc: function (t) { + return 1 * Math.sqrt(1 - (t=t/1-1)*t); + }, + easeInOutCirc: function (t) { + if ((t/=1/2) < 1) return -1/2 * (Math.sqrt(1 - t*t) - 1); + return 1/2 * (Math.sqrt(1 - (t-=2)*t) + 1); + }, + easeInElastic: function (t) { + var s=1.70158;var p=0;var a=1; + if (t==0) return 0; if ((t/=1)==1) return 1; if (!p) p=1*.3; + if (a < Math.abs(1)) { a=1; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (1/a); + return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*1-s)*(2*Math.PI)/p )); + }, + easeOutElastic: function (t) { + var s=1.70158;var p=0;var a=1; + if (t==0) return 0; if ((t/=1)==1) return 1; if (!p) p=1*.3; + if (a < Math.abs(1)) { a=1; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (1/a); + return a*Math.pow(2,-10*t) * Math.sin( (t*1-s)*(2*Math.PI)/p ) + 1; + }, + easeInOutElastic: function (t) { + var s=1.70158;var p=0;var a=1; + if (t==0) return 0; if ((t/=1/2)==2) return 1; if (!p) p=1*(.3*1.5); + if (a < Math.abs(1)) { a=1; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (1/a); + if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*1-s)*(2*Math.PI)/p )); + return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*1-s)*(2*Math.PI)/p )*.5 + 1; + }, + easeInBack: function (t) { + var s = 1.70158; + return 1*(t/=1)*t*((s+1)*t - s); + }, + easeOutBack: function (t) { + var s = 1.70158; + return 1*((t=t/1-1)*t*((s+1)*t + s) + 1); + }, + easeInOutBack: function (t) { + var s = 1.70158; + if ((t/=1/2) < 1) return 1/2*(t*t*(((s*=(1.525))+1)*t - s)); + return 1/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2); + }, + easeInBounce: function (t) { + return 1 - JChart.animationOptions.easeOutBounce (1-t); + }, + easeOutBounce: function (t) { + if ((t/=1) < (1/2.75)) { + return 1*(7.5625*t*t); + } else if (t < (2/2.75)) { + return 1*(7.5625*(t-=(1.5/2.75))*t + .75); + } else if (t < (2.5/2.75)) { + return 1*(7.5625*(t-=(2.25/2.75))*t + .9375); + } else { + return 1*(7.5625*(t-=(2.625/2.75))*t + .984375); + } + }, + easeInOutBounce: function (t) { + if (t < 1/2) return JChart.animationOptions.easeInBounce (t*2) * .5; + return JChart.animationOptions.easeOutBounce (t*2-1) * .5 + 1*.5; + } + }, + /** + * 通用的计时控制器 + */ + requestAnimFrame : (function(){ + return window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function(callback) { + window.setTimeout(callback, 1000 / 60); + }; + })(), + isNumber : function(n){ + return !isNaN(parseFloat(n)) && isFinite(n); + }, + isEqual : function(number1, number2, digits){ + digits = digits == undefined? 10: digits; // 默认精度为10 + return number1.toFixed(digits) === number2.toFixed(digits); + }, + /** + * 取有效区域内的值 + * @param valueToCap + * @param maxValue + * @param minValue + * @return {*} + */ + capValue : function(valueToCap, maxValue, minValue){ + var value; + if(this.isNumber(maxValue) && valueToCap > maxValue) { + return maxValue; + } + if(this.isNumber(minValue) && valueToCap < minValue ){ + return minValue; + } + return valueToCap; + }, + getDecimalPlaces : function(num){ + if (num%1!=0){ + return num.toString().split(".")[1].length + } + else{ + return 0; + } + }, + extend : function(target){ + var args = Array.prototype.slice.call(arguments,1); + this.each(args,function(v,i){ + extend(target,v); + }); + function extend(target,source){ + for(var key in source){ + var o = source[key]; + if(o instanceof Array){ + target[key] = extend([], o); + }else if(o instanceof Object){ + target[key] = extend({},o); + }else{ + target[key] = o; + } + } + return target; + } + return target; + + }, + clone : function(obj){ + var o; + if (typeof obj == "object") { + if (obj === null) { + o = null; + } else { + if (obj instanceof Array) { + o = []; + for (var i = 0, len = obj.length; i < len; i++) { + o.push(this.clone(obj[i])); + } + } else { + o = {}; + for (var j in obj) { + o[j] = this.clone(obj[j]); + } + } + } + } else { + o = obj; + } + return o; + }, + //只对array有效 + each : function(array,fn,context){ + for(var i = 0,len=array.length;i)[^\t]*)'/g, "$1\r") + .replace(/\t=(.*?)%>/g, "',$1,'") + .split("\t").join("');") + .split("%>").join("p.push('") + .split("\r").join("\\'") + + "');}return p.join('');"); + + // Provide some basic currying to the user + return data ? fn( data ) : fn; + }; + return tmpl; + })() +}; + + +;(function(_){ + function Bar(data,cfg){ + _.Scale.apply(this); + var barRanges = [];//记录柱状图的占据的位置 + this._type_ = 'bar'; + var _this = this; + this.data = data;//所有的数据 + this.chartData = null;//图表当前展示的数据 + //配置项 + _.extend(this.config,{ + //是否显示bar的边框 + showBarBorder : true, + //bar边框宽度 + barBorderWidth : 2, + //每两个bar之间的间距 + barSpacing : 1, + //每两组bar之间的间距 + barSetSpacing : 5, + //是否可以对数据进行拖动 + datasetGesture : false, + //每次显示的数据条数 + datasetShowNumber : 12 + }); + /** + * 绑定canvas dom元素上的事件 如:click、touch + */ + this.bindEvents = function(){ + this.on('_tap',function(x,y){tapHandler(x,y,'tap.bar')}); + //this.on('_doubleTap',function(x,y){tapHandler(x,y,'doubleTap.bar')}); + this.on('_longTap',function(x,y){tapHandler(x,y,'longTap.bar')}); + if(this.config.datasetGesture){ + this.bindDataGestureEvent(); + } + } + /** + * 初始化部分元素值 + */ + this.draw = function(noAnim){ + if(this.config.datasetGesture && this.data.labels.length > _this.config.datasetShowNumber){ + this.chartData = this.sliceData(this.data,0,this.data.labels.length,this.config.datasetShowNumber); + }else{ + this.chartData = this.data; + } + this.mergeFont(['scaleFont','textFont']); + this.initScale(true); + if(noAnim){ + this.drawScale(); + this.drawBars(1); + }else{ + this.doAnim(this.drawScale,this.drawBars); + } + } + this.redraw = function(data){ + this.chartData = data; + this.clear(); + this.initScale(true); + this.drawScale(); + this.drawBars(1); + } + + this.drawBars = function(animPc){ + if(animPc >= 1)barRanges = []; + var ctx = _this.ctx,cfg = _this.config,scale = _this.scaleData; + _.each(_this.chartData.datasets,function(set,i){ + if(!cfg.showBarBorder)borderColor = null; + _.each(set.data,function(d,j){ + var x = scale.x + cfg.barSetSpacing + scale.xHop*j + scale.barWidth*i + cfg.barSpacing*i + cfg.barBorderWidth* i, + y = scale.y,width = scale.barWidth,height = animPc*_this.calcOffset(d,scale.yScaleValue,scale.yHop)+(cfg.barBorderWidth/2), + color = set.color,borderColor,bgColor = _.hex2Rgb(color,0.6); + if(cfg.showBarBorder){ + //边框颜色默认与设置颜色一致 + borderColor = set.borderColor || color; + } + ctx.rect(x,y,width,-height,bgColor,borderColor,cfg.barBorderWidth); + if(animPc >= 1){ + barRanges.push([x,x+width,y,y-height,j,i]); + } + cfg.showText && _this.drawText(d,x+width/2,y-height-3,[j,i]); + + }); + }) + } + + function tapHandler(x,y,event){ + var p = isInBarRange(x,y); + if(p){ + _this.trigger(event,[_this.chartData.datasets[p[5]].data[p[4]],p[4],p[5]]); + } + } + + function isInBarRange(x,y){ + var range; + _.each(barRanges,function(r){ + if(x >= r[0] && x <= r[1] && y >= r[3] && y <= r[2]){ + range = r; + return false; + } + }); + return range; + } + //初始化参数 + if(cfg)this.initial(cfg); + } + _.Bar = Bar; +})(JChart) +/** + * 简单的Canvas帮助类,使canvas支持类似于jquery的链式操作,支持CanvasRenderingContext2D所有的方法,并提供一些常用的工具方法 + */ +;(function(_){ + function Chain(el){ + //需要返回结果的方法,这些方法将不能进行后续的链式调用 + var needReturnValueFn = ['isPointInPath','measureText','getImageData','createLinearGradient','createPattern','createRadialGradient','isPointInPath']; + function Canvas(){ + this.el = el = (typeof el === 'string') ? document.getElementById(el) : el; + this.ctx = el.getContext('2d'); + this.width = el.width; + this.height = el.height; + addProtoFunc(this.ctx); + } + + //添加canvas原生方法到prototype中 + function addProtoFunc(ctx){ + for(var fn in CanvasRenderingContext2D.prototype){ + if(Canvas.prototype[fn])continue; + Canvas.prototype[fn] = function(fn){ + return function(){ + var args = Array.prototype.slice.call(arguments); + var result = ctx[fn].apply(ctx,args); + if(needReturnValueFn.indexOf(fn)>-1){ + return result; + } + return this; + } + }(fn); + } + } + + Canvas.prototype = { + /** + * 设置context的属性值 + * @param name 属性名 + * @param value 属性值 + * @return this + */ + set : function(name,value){ + if(typeof name == 'object'){ + for(var p in name){ + this.ctx[p] && (this.ctx[p] = name[p]); + } + }else{ + this.ctx[name] && (this.ctx[name] = value); + } + return this; + }, + /** + * 获取context的属性值 + * @param name 属性名 + * @return value 属性值 + */ + get : function(name){ + return this.ctx[name]; + }, + /** + * context填充 + * @param color 填充颜色 + * @return this + */ + fill : function (color) { + color && this.set('fillStyle', color); + this.ctx.fill(); + return this; + }, + /** + * context描边 + * @param color 描边颜色 + * @return this + */ + stroke : function (color,width) { + if (color) { + this.set('strokeStyle', color); + width && this.set('lineWidth',width); + } + this.ctx.stroke(); + return this; + }, + /** + * 填充文本,在文本中加入\n可实现换行 + * @param text + * @param x + * @param y + * @param style + * @return {*} + */ + fillText : function(text,x,y,style){ + this.ctx.save(); + if(style && typeof style == 'object'){ + for(var p in style){ + this.set(p,style[p]); + } + } + var texts = (text+'').split('\n'); + if(texts.length > 1){ + var fontsize = this.getFontSize(); + for(var i=0;i 0 && delta <= 250) touch.isDoubleTap = true; + touch.last = now; + longTapTimeout = setTimeout(longTap, longTapDelay); + } + function touchmove(e){ + if(!touch.last)return; + var ev = e.touches ? e.touches[0] : e; + touch.x2 = ev.pageX - offset.left; + touch.y2 = ev.pageY - offset.top; + if (Math.abs(touch.x1 - touch.x2) > 15){ + e.preventDefault(); + cancelAll(); + } + } + function touchend(e){ + cancelLongTap(); + if ('last' in touch){ + //tap事件,单击/双击都会触发,0延迟,建议在不使用doubleTap的环境中使用,如果要同时使用tap和doubleTap,请使用singleTap + _this.trigger('_tap',[touch.x1,touch.y1]); + _this.trigger('tap',[touch.x1,touch.y1]); + if (touch.isDoubleTap) { + cancelAll(); + _this.trigger('_doubleTap',[touch.x1,touch.y1]); + _this.trigger('doubleTap',[touch.x1,touch.y1]); + }else { + touchTimeout = setTimeout(function(){ + touchTimeout = null; + _this.trigger('_singleTap',[touch.x1,touch.y1]); + _this.trigger('singleTap',[touch.x1,touch.y1]); + touch = {}; + }, 250) + + } + }; + } + + function longTap() { + longTapTimeout = null; + if (touch.last) { + _this.trigger('_longTap',[touch.x1,touch.y1]); + _this.trigger('longTap',[touch.x1,touch.y1]); + touch = {}; + } + } + + function cancelLongTap() { + if (longTapTimeout) clearTimeout(longTapTimeout); + longTapTimeout = null; + } + + function cancelAll() { + if (touchTimeout) clearTimeout(touchTimeout); + if (longTapTimeout) clearTimeout(longTapTimeout); + touchTimeout = longTapTimeout = null; + touch = {}; + } + } + } + _.Chart = Chart; +})(JChart); +;(function(_){ + function Line(data,cfg){ + _.Scale.apply(this); + var pointRanges = [];//记录线的节点位置 (for click 事件) + this._type_ = 'line'; + this.data = data; + this.chartData = null; + var _this = this; + _.extend(this.config,{ + //平滑曲线 + smooth : true, + //是否显示线的连接点 + showPoint : true, + //连接圆点半径 + pointRadius : 4, + //连接点的边框宽度 + pointBorderWidth : 2, + //连接点的点击范围(方便手指触摸) + pointClickBounds : 20, + //连接线的宽度 + lineWidth : 2, + //是否填充为面积图 + fill : true, + //是否可以对数据进行拖动 + datasetGesture : false, + //每次显示的数据条数 + datasetShowNumber : 12 + }); + /** + * 绑定canvas dom元素上的事件 如:click、touch + */ + this.bindEvents = function(){ + //this.ctx.canvas.addEventListener('click',tapHandler); + this.on('_tap',tapHandler); + if(this.config.datasetGesture){ + this.bindDataGestureEvent(); + } + } + /** + * 初始化部分元素值 + */ + this.draw = function(noAnim){ + this.mergeFont(['textFont','scaleFont']); + if(this.config.datasetGesture && this.data.labels.length > _this.config.datasetShowNumber){ + this.chartData = this.sliceData(this.data,0,this.data.labels.length,this.config.datasetShowNumber); + }else{ + this.chartData = this.data; + } + _this.initScale(true); + if(noAnim){ + this.drawScale(); + this.drawLines(1); + }else{ + this.doAnim(this.drawScale,this.drawLines); + } + } + this.redraw = function(data){ + this.chartData = data; + this.clear(); + this.initScale(true); + this.drawScale(); + this.drawLines(1); + } + this.drawLines = function(animPc){ + if(animPc >= 1)pointRanges = []; + var ctx = _this.ctx,cfg = _this.config,dataset = _this.chartData.datasets,scale = _this.scaleData; + _.each(dataset,function(set,i){ + //画连接线 + ctx.beginPath().moveTo(scale.x, yPos(i,0)); + _.each(set.data,function(d,j){ + var pointX = xPos(j),pointY = yPos(i,j); + if (cfg.smooth){//贝塞尔曲线 + ctx.bezierCurveTo(xPos(j-0.5),yPos(i,j-1),xPos(j-0.5),pointY,pointX,pointY); + }else{ + ctx.lineTo(pointX,pointY); + } + if(animPc >= 1){ + pointRanges.push([pointX,pointY,j,i]); + } + }); + ctx.stroke(set.color,cfg.lineWidth); + //填充区域 + cfg.fill ? ctx.lineTo(scale.x + (scale.xHop*(set.data.length-1)),scale.y).lineTo(scale.x,scale.y).closePath() + .fill(set.fillColor?set.fillColor : _.hex2Rgb(set.color,0.6)) : ctx.closePath(); + + //画点以及点上文本 + _.each(set.data,function(d,k){ + var x = xPos(k),y = yPos(i,k); + cfg.showPoint && _this.drawPoint(x,y,set); + cfg.showText && _this.drawText(d,x,y-3,[k,i]); + }); + }); + + function yPos(i,j){ + return scale.y - animPc*(_this.calcOffset(dataset[i].data[j],scale.yScaleValue,scale.yHop)); + } + function xPos(i){ + return scale.x + (scale.xHop * i); + } + } + function tapHandler(x,y){ + var p = isInPointRange(x,y); + if(p){ + _this.trigger('tap.point',[_this.chartData.datasets[p[3]].data[p[2]],p[2],p[3]]); + } + } + + function isInPointRange(x,y){ + var point,pb = _this.config.pointClickBounds; + _.each(pointRanges,function(p){ + if(x >= p[0] - pb && x <= p[0] + pb && y >= p[1]-pb && y <= p[1] + pb){ + point = p; + return false; + } + }); + return point; + } + + //初始化参数 + if(cfg)this.initial(cfg); + } + _.Line = Line; +})(JChart) +;(function(_){ + function Pie(data,cfg){ + _.Chart.apply(this); + var angleRanges;//记录每个扇形的起始角度(从0开始) + var _this = this; + this.data = data; + var radius,totalData = 0,startAngle = 0,rotateAngle = 0,currentOutIndex = -1,origin = {}; + //覆盖配置项 + _.extend(this.config,{ + //border + showBorder : true, + //border color + borderColor : "#fff", + //border width + borderWidth : 2, + //开始角度,默认为12点钟方向 + startAngle : -Math.PI/2, + //旋转扇形,使其中线对应的角度 + rotateAngle : Math.PI/2, + //扇形弹出距离 + pullOutDistance : 10, + //点击扇形默认触发的事件类型 + clickType : 'pullOut',// pullOut||rotate + //环形图 + isDount : false, + dountRadiusPercent :0.4, + totalAngle : Math.PI*2, + dountText : '', + dountFont : { + size : 20, + style : 600, + color : '#3498DB' + } + }); + /** + * 计算各个扇形的起始角度 + * @param data + */ + function calcAngel(){ + var angle = 0; + angleRanges = []; + _.each(_this.data,function(d,i){ + var start = angle; + var percent = d.value/totalData; + angle = angle + percent * _this.config.totalAngle; + var end = angle; + angleRanges.push([start,end,d,i,percent]); + }) + } + + function animRotate(percent){ + drawPie(percent,'rotate'); + } + + /** + * 画饼图 + * @param percent 动画比例 + */ + function drawPie (percent,type){ + _this.clear(); + percent = _this.config.animation ? percent : 1; + _.each(angleRanges,function(a){ + drawSector(a,percent,type); + }); + _this.config.isDount && _this.config.dountText && drawDountText(); + } + + /** + * 计算扇形真实的角度 + */ + function calcSectorAngle(r,p,t){ + var start = r[0],end = r[1]; + if(t == 'rotate'){ + //旋转 + start = start + startAngle + rotateAngle*p; + end = end + startAngle + rotateAngle*p; + }else{ + //默认动画 + start = start*p + startAngle; + end = end*p + startAngle + } + return { + start : start, + end : end + } + } + + /** + * 画扇形 + * @param i + * @param animPercent + */ + function drawSector(r,p,t){ + var x = origin.x,y = origin.y,cfg = _this.config, + index = r[3],angle = calcSectorAngle(r,p,t); + + if(index == currentOutIndex){ + var midAngle = (r[0] + r[1])/2+startAngle; + x += Math.cos(midAngle) * cfg.pullOutDistance; + y += Math.sin(midAngle) * cfg.pullOutDistance; + } + if(cfg.isDount){ + _this.ctx.dountSector(x,y,radius*cfg.dountRadiusPercent,radius,angle.start,angle.end,_this.data[index].color); + }else{ + _this.ctx.sector(x,y,radius,angle.start,angle.end,_this.data[index].color); + } + cfg.showBorder && _this.ctx.stroke(cfg.borderColor,cfg.borderWidth); + cfg.showText && drawText(x,y,radius,angle.start,angle.end,r); + } + + function drawText(x,y,r,start,end,data){ + //计算文本位置 + var middAngle = (start+end)/ 2, dis = r/ 2, + percent = data[4],d = data[2]; + if(_this.config.isDount){ + dis = r/2 + r*_this.config.dountRadiusPercent/2; + } + percent = (percent * 100).toFixed(1)+'%'; + var xaxis = Math.cos(middAngle) * dis + x, yaxis = Math.sin(middAngle) * dis + y; + _this.drawText(percent,xaxis,yaxis,[d,data[3],data[4]]); + } + function drawDountText(){ + _this.ctx.fillText(_this.config.dountText,origin.x,origin.y,_this.config.dountFont); + } + /** + * 绑定canvas dom元素上的事件 如:click、touch + */ + this.bindEvents = function(){ + this.on('_tap',function(x,y){tapHandler(x,y,'tap.pie')}); + //暂时关闭doubleTap事件 + //this.on('_doubleTap',function(x,y){tapHandler(x,y,'doubleTap.pie')}); + this.on('_longTap',function(x,y){tapHandler(x,y,'longTap.pie')}); + //添加一个默认点击事件 + this.on('tap.pie',function(){return true;}) + } + + function tapHandler(x,y,event){ + var type = _this.config.clickType; + var angle = isInSegment(x,y); + if(angle){ + if(event == 'tap.pie'){//处理一些默认行为 + if(!_this.trigger(event,[angle[2],angle[3]]))return; + if(type == 'rotate'){ + _this.rotate(angle[3]); + }else if(type == 'pullOut'){ + _this.toggleSegment(angle[3]); + } + }else{ + _this.trigger(type,[angle[2],angle[3]]); + } + } + } + + function isInSegment(offsetX,offsetY){ + var angle; + var x = offsetX - origin.x; + var y = offsetY - origin.y; + //距离圆点的距离 + var dfc = Math.sqrt( Math.pow( Math.abs(x), 2 ) + Math.pow( Math.abs(y), 2 ) ); + var isInPie = (dfc <= radius); + if(isInPie && _this.config.isDount){//排除dount图中心区 + isInPie = (dfc >= radius*_this.config.dountRadiusPercent); + } + if(!isInPie)return; + var clickAngle = Math.atan2(y, x)-startAngle; + if ( clickAngle < 0 ) clickAngle += 2 * Math.PI; + if(clickAngle > 2 * Math.PI) clickAngle -= 2 * Math.PI; + + _.each(angleRanges,function(a){ + if(clickAngle >= a[0] && clickAngle < a[1]){ + angle = a; + return false; + } + }); + return angle; + } + + /** + * 弹出/收起扇形块 + * @param i 扇形索引 + */ + this.toggleSegment = function(i){ + if(i == currentOutIndex){ + this.pushIn(); + }else{ + this.pullOut(i); + } + } + /** + * 收起所有弹出的扇形块 + */ + this.pushIn = function(){ + currentOutIndex = -1; + drawPie(1); + this.trigger('pushIn'); + } + /** + * 弹出指定的扇形块 + * @param i 扇形索引 + */ + this.pullOut = function(i){ + if ( currentOutIndex == i ) return; + currentOutIndex = i; + drawPie(1); + this.trigger('pullOut',[_this.data[i],i,angleRanges[i][4]]); + } + /** + * 旋转扇形块的中线指向6点钟方向 + * @param i 扇形索引 + */ + this.rotate = function(i){ + if(_this.isAnimating)return; + var middAngle = (angleRanges[i][0] + angleRanges[i][1]) / 2 + startAngle; + var newRotateAngle = _this.config.rotateAngle-middAngle; + if(_.isEqual(newRotateAngle,0))return; + this.pushIn(); + rotateAngle = newRotateAngle; + this.doAnim(null,animRotate,function(){ + startAngle += rotateAngle; + _this.trigger('rotate',[_this.data[i],i,angleRanges[i][4]]); + }); + } + this.setDountText = function(text){ + _this.config.dountText = text; + drawPie(1); + } + /** + * 画图 + */ + this.draw = function(noAnim){ + this.mergeFont(['textFont','dountFont']); + calcOrigin(); + totalData = 0; + currentOutIndex = -1; + _.each(_this.data,function(d){ + totalData += d.value; + }); + calcAngel(); + startAngle = _this.config.startAngle; + if(noAnim){ + drawPie(1); + }else{ + this.doAnim(null,drawPie); + } + } + //计算原点位置及半径 + function calcOrigin(){ + if(_this.config.totalAngle == Math.PI){ + origin = { + x : _this.width/2, + y : _this.height - 20 + } + radius = Math.min(origin.x,origin.y) - 10; + }else{ + origin = {x:_this.width/2,y:_this.height/2}; + radius = Math.min(origin.x,origin.y) - 10; + } + } + //初始化参数 + if(cfg)this.initial(cfg); + } + _.Pie = Pie; +}(JChart)); + + ;(function(_){ + function Polar(data,cfg){ + _.Scale.apply(this); + var _this = this; + this.data = this.chartData = data; + //配置项 + _.extend(this.config,{ + drawScaleFirst : false, + //是否显示刻度文本背景 + showScaleLabelBackdrop : true, + //刻度背景颜色 + scaleBackdropColor : "rgba(255,255,255,0.75)", + //刻度padding-top bottom + scaleBackdropPaddingY : 2, + //刻度padding-left right + scaleBackdropPaddingX : 2, + //是否显示角度分割线 + showAngleLine : true, + //分割线颜色 + angleLineColor : "rgba(0,0,0,.1)", + showBorder : true, + borderColor : '#fff', + borderWidth : 1, + textFont : { + size : 16, + color : '#666', + textBaseline : 'middle' + }, + //分割线宽度 + angleLineWidth : 1, + //是否开启旋转动画 + animateRotate : true, + //是否开启缩放动画 + animateScale : false + }); + /** + * 绑定canvas dom元素上的事件 + */ + this.bindEvents = function(){ + this.on('_tap',tapHandler); + } + + this.draw = function(noAnim){ + this.mergeFont(['scaleFont','textFont']); + this.initScale(); + if(noAnim){ + this.drawAllSegments(1); + this.drawScale(); + } + this.doAnim(this.drawScale,this.drawAllSegments); + } + function tapHandler(x,y){ + var i = isInSegment(x,y); + if(i>-1){ + this.trigger('tap.pie',[this.data[i],i]); + } + } + this.calcDrawingSizes = function(){ + var maxSize = Math.min(this.width,this.height)/2, + cfg = this.config,size = cfg.scaleFont.size,lh = size*2; + + maxSize -= Math.max(size*0.5,cfg.scaleLineWidth*0.5); + if (cfg.showScaleLabelBackdrop){ + lh += (2 * cfg.scaleBackdropPaddingY); + maxSize -= cfg.scaleBackdropPaddingY*1.5; + } + this.scaleData.yHeight = maxSize - 10; + this.scaleData.yLabelHeight = lh; + } + + this.drawScale = function(){ + var cfg = this.config,scale = this.scaleData,x = this.width/2, y = this.height/2 + size = cfg.scaleFont.size,px = cfg.scaleBackdropPaddingX,py = cfg.scaleBackdropPaddingY; + this.ctx.save().translate(x,y); + + //画圆圈 + for (var i=0; i upperValue) {upperValue = data[i].value;} + if (data[i].value < lowerValue) {lowerValue = data[i].value;} + }; + var yh = this.scaleData.yHeight; + var lh = this.scaleData.yLabelHeight; + var maxSteps = Math.floor((yh/(lh*0.66))); + var minSteps = Math.floor((yh/lh*0.5)); + return { + maxValue : upperValue, + minValue : lowerValue, + maxSteps : maxSteps, + minSteps : minSteps + }; + } + + function isInSegment(x,y){ + var startAngle = -Math.PI/2, + angleStep = (Math.PI*2)/this.data.length; + var x = x-_this.width/ 2,y = y-_this.height/2; + //距离圆点的距离 + var dfc = Math.sqrt( Math.pow( Math.abs(x), 2 ) + Math.pow( Math.abs(y), 2 ) ); + var isInPie = (dfc <= _this.scaleData.yHeight); + if(!isInPie)return -1; + var clickAngle = Math.atan2(y, x)-startAngle; + if ( clickAngle < 0 ) clickAngle = 2 * Math.PI + clickAngle; + if(clickAngle > 2 * Math.PI) clickAngle = clickAngle - 2 * Math.PI; + return Math.floor(clickAngle/angleStep); + } + + //初始化参数 + if(cfg)this.initial(cfg); + + } + _.Polar = Polar; + })(JChart); +;(function (_) { + function Radar(data, cfg) { + _.Scale.apply(this); + var pointRanges = [];//记录线的节点位置 (for click 事件) + var _this = this; + this.data = this.chartData = data; + //配置项 + _.extend(this.config, { + drawScaleFirst : false, + //是否显示刻度文本背景 + scaleShowLabelBackdrop:true, + //刻度背景颜色 + scaleBackdropColor:"rgba(255,255,255,0.75)", + //刻度padding-top bottom + scaleBackdropPaddingY:2, + //刻度padding-left right + scaleBackdropPaddingX:2, + //图形形状,菱形 diamond,圆形 circle + graphShape:'circle', + //是否显示角度分割线 + showAngleLine:true, + //角度分割线颜色 + angleLineColor:"rgba(0,0,0,.1)", + //角度分割线宽度 + angleLineWidth:1, + //是否显示线的连接点 + showPoint:true, + //连接圆点半径 + pointRadius:3, + //连接点的边框宽度 + pointBorderWidth:1, + //连接点的点击范围(方便手指触摸) + pointClickBounds:20, + //连接线的宽度 + lineWidth:2, + //是否填充为面积图 + fill:true, + showScaleLabel:true, + showText : false, + gridLineColor:'rgb(0,0,0,.5)' + }); + + /** + * 绑定canvas dom元素上的事件 如:click、touch + */ + this.bindEvents = function () { + this.on('_tap', tapHandler); + } + + this.draw = function (noAnim) { + this.mergeFont(['scaleFont','textFont']); + this.initScale(); + if (noAnim) { + this.drawAllDataPoints(1); + this.drawScale(); + } else { + this.doAnim(this.drawScale, this.drawAllDataPoints); + } + } + + function tapHandler(x, y) { + var p = isInPointRange(x,y); + if(p){ + _this.trigger('tap.point',[_this.data.datasets[p[3]].data[p[2]],p[2],p[3]]); + } + } + + this.calcDrawingSizes = function () { + var maxSize = (Math.min(this.width, this.height) / 2), + cfg = this.config, + labelHeight = cfg.scaleFont.size * 2; + var labelLength = 0; + _.each(_this.data.labels, function (label) { + this.ctx.set(cfg.textFont); + var w = this.ctx.measureText(label).width; + if (w > labelLength) labelLength = w; + }, this); + maxSize -= Math.max(labelLength, ((cfg.textFont.size/2) * 1.5)); + maxSize -= cfg.textFont.size; + maxSize = _.capValue(maxSize, null, 0); + this.scaleData.yHeight = maxSize; + this.scaleData.yLabelHeight = labelHeight; + } + + this.drawScale = function () { + var ctx = this.ctx, cfg = this.config, scale = this.scaleData,scaleSize = cfg.scaleFont.size,textSize = cfg.textFont.size, + dataLen = this.data.labels.length,px = cfg.scaleBackdropPaddingX,py = cfg.scaleBackdropPaddingY; + //计算每条数据的角度 + var rotationDegree = (2 * Math.PI) / dataLen; + ctx.save().translate(this.width / 2, this.height / 2); + //显示角度分割线 + if (cfg.showAngleLine) { + var w = scale.yHeight - (scale.yHeight % scale.yHop); + //画每个角度的分割线 + for (var h = 0; h < dataLen; h++) { + ctx.rotate(rotationDegree).line(0,0,0,-w,cfg.angleLineColor,cfg.angleLineWidth); + } + } + //画刻度线 + for (var i = 0; i < scale.yScaleValue.step; i++) { + var hop = scale.yHop * (i + 1); + ctx.beginPath(); + if (cfg.showGridLine) { + ctx.set({strokeStyle : cfg.gridLineColor,lineWidth : cfg.gridLineWidth}) + if (cfg.graphShape == 'diamond') { + ctx.moveTo(0, -hop); + for (var j = 0; j < dataLen; j++) { + ctx.rotate(rotationDegree).lineTo(0, -hop); + } + } else { + ctx.circle(0, 0, hop); + } + ctx.closePath().stroke(); + } + //画刻度值 + if (cfg.showScaleLabel) { + var label = scale.yScaleValue.labels[i]; + //显示刻度值的背景 + if (cfg.showScaleLabelBackdrop){ + var textWidth = this.ctx.measureText(label).width; + this.ctx.rect( + Math.round(-textWidth/2 - px), //X + Math.round(-hop - scaleSize/2 - py),//Y + Math.round(textWidth + px*2), //Width + Math.round(scaleSize + py*2), //Height + cfg.scaleBackdropColor + ); + } + this.ctx.fillText(label,0,-hop,cfg.scaleFont); + } + + } + + //设置文本样式 + this.ctx.set(cfg.textFont); + //显示数据标签文本 + for (var k = 0; k < dataLen; k++) { + var opposite = Math.sin(rotationDegree * k) * (scale.yHeight + textSize); + var adjacent = Math.cos(rotationDegree * k) * (scale.yHeight + textSize); + var align; + if (rotationDegree * k == Math.PI || rotationDegree * k == 0) { + align = 'center'; + } else if (rotationDegree * k > Math.PI) { + align = 'right'; + }else { + align = 'left'; + } + this.ctx.fillText(this.data.labels[k], opposite, -adjacent,{textAlign:align}); + } + ctx.restore(); + } + + this.drawAllDataPoints = function (animPc) { + if (animPc >= 1)pointRanges = []; + var dataLen = data.datasets[0].data.length, + rotationDegree = (2 * Math.PI) / dataLen, + scale = this.scaleData, + ctx = this.ctx, cfg = this.config; + ctx.save().translate(this.width / 2, this.height / 2); + _.each(this.data.datasets, function (set, i) { + ctx.beginPath().moveTo(0, getY(set.data[0])); + //画连接线 + _.each(set.data, function (d, j) { + if (j == 0)return true; + ctx.rotate(rotationDegree).lineTo(0, getY(d)); + }); + ctx.closePath(); + + cfg.fill && ctx.fill(set.fillColor||_.hex2Rgb(set.color,0.6)); + ctx.stroke(set.color,cfg.lineWidth); + + //画连接点 + _.each(set.data,function(d,j){ + var y = getY(d); + if (cfg.showPoint) { + ctx.rotate(rotationDegree).circle(0, y, cfg.pointRadius,set.pointColor,set.pointBorderColor,cfg.pointBorderWidth); + } + if(animPc >= 1){ + var p = getPosition(y,j); + pointRanges.push([p[0],p[1],j,i]); + } + }); + ctx.rotate(rotationDegree); + + }, this); + ctx.restore(); + if(cfg.showText){ + drawText(); + } + function getY(d){ + return -animPc * _this.calcOffset(d, scale.yScaleValue, scale.yHop); + } + function getPosition(radius,i){ + radius = Math.abs(radius); + var x,y; + var angel = -Math.PI/2 + i * rotationDegree; + x = Math.cos(angel)*radius + _this.width/2; + y = Math.sin(angel)*radius + _this.height/2; + return [x,y]; + } + } + + function drawText(){ + _.each(pointRanges,function(p){ + var y = p[1]; + if(y > _this.height/2){ + y += 6; + } + _this.drawText(_this.data.datasets[p[3]].data[p[2]],p[0],y,[p[2],p[3]]); + }); + + } + + function isInPointRange(x,y){ + var point,pb = _this.config.pointClickBounds; + _.each(pointRanges,function(p){ + if(x >= p[0] - pb && x <= p[0] + pb && y >= p[1]-pb && y <= p[1] + pb){ + point = p; + return false; + } + }); + return point; + } + //初始化参数 + if (cfg)this.initial(cfg); + } + _.Radar = Radar; +})(JChart); +;(function(_){ + /** + * 抽象类-刻度值 + * 用来初始化XY轴各项数据 + * @constructor + */ + function Scale(){ + var P_T = 5,//图表顶部空白 + P_R = 5,//图表右侧空白 + P_Y = 20,//y轴左侧空白 + P_X = 10;//x轴文本与x之间的间距 + _.Chart.apply(this); + _.extend(this.config,{ + /** + * @Object + * Y轴刻度值,默认为null,会自动生成,也可以自己指定 + * { + * step : 10,//刻度个数,必选项 + * stepValue : 10//每两个刻度线之间的差值,必选项 + * start : 0//起始刻度值,默认为0 + * } + */ + scale : null, + //xy轴刻度线的颜色 + scaleLineColor : "rgba(0,0,0,.3)", + //刻度线宽度 + scaleLineWidth:1, + //是否显示Y轴刻度值 + showScaleLabel : true, + //是否显示X轴刻度值 + showLabel : true, + //刻度值字体属性 + scaleFont : { + size:12, + color : '#666' + }, + textFont : { + size : 14, + textBaseline : 'bottom' + }, + //是否显示网格线 + showGridLine : true, + //网格线颜色 + gridLineColor : "rgba(0,0,0,.1)", + //网格线宽度 + gridLineWidth : 1, + //水平线{value : 50,color : #fff,width : 1} + horizonLine : null + + }); + //数据偏移量-已经偏移 + this.dataOffset = 0; + this.scaleData = { + x : 0,//圆点坐标 + y : 0, + xHop : 0,//x轴数据项宽度 + yHop : 0,//y轴每个刻度的高度 + xLength : 0,//x轴长度 + yHeight : 0,//y轴高度 + yLabelHeight : 0,//y轴刻度文本高度 + yScaleValue : null,//y轴刻度指标 + labelRotate : 0,//x轴label旋转角度 + xLabelWidth : 0,//x轴label宽度 + xLabelHeight : 0,//x轴label宽度 + barWidth : 0//柱形图柱子宽度 + } + /** + * 计算X轴文本宽度、旋转角度及Y轴高度 + */ + this.calcDrawingSizes = function(){ + var maxSize = this.height,widestX = 0,scaleFontSize = this.config.scaleFont.size, xLabelWidth = 0,xLabelHeight = scaleFontSize, + labelRotate = 0,dataLen = this.chartData.labels.length; + //计算X轴,如果发现数据宽度超过总宽度,需要将label进行旋转 + this.ctx.set(this.config.scaleFont); + //找出最宽的label + _.each(this.chartData.labels,function(o){ + var w = this.ctx.measureText(o).width; + widestX = (w > widestX)? w : widestX; + },this); + xLabelWidth = widestX; + if (this.width/dataLen < widestX){ + labelRotate = 45; + xLabelWidth = Math.cos(labelRotate*Math.PI/180) * widestX; + xLabelHeight = Math.sin(labelRotate*Math.PI/180) * widestX ; + if (this.width/dataLen < xLabelHeight){ + labelRotate = 90; + xLabelWidth = scaleFontSize; + xLabelHeight = widestX; + } + } + //减去x轴label的高度 + maxSize -= xLabelHeight; + //减去x轴文本与x轴之间的间距 + maxSize -= P_X; + //给Y轴顶部留一点空白 + maxSize -= P_T; + maxSize -= this.config.showText?scaleFontSize:0; + //y轴高度 + this.scaleData.yHeight = maxSize; + //y轴刻度高度 + this.scaleData.yLabelHeight = scaleFontSize; + //x轴文本旋转角度 + this.scaleData.labelRotate = labelRotate; + //x轴文本的宽度 + this.scaleData.xLabelWidth = xLabelWidth; + //x轴文本的高度 + this.scaleData.xLabelHeight = xLabelHeight; + } + + /** + * 计算Y轴刻度的边界及刻度步数 + * @return {Object} + */ + this.getValueBounds = function(dataset) { + var upperValue = Number.MIN_VALUE; + var lowerValue = Number.MAX_VALUE; + _.each(dataset,function(o){ + _.each(o.data,function(obj){ + if(obj > upperValue){upperValue = obj}; + if (obj < lowerValue) { lowerValue = obj}; + }); + }) + var yh = this.scaleData.yHeight; + var lh = this.scaleData.yLabelHeight; + var maxSteps = Math.floor((yh/(lh*0.66))); + var minSteps = Math.floor((yh/lh*0.5)); + + return { + maxValue : upperValue, + minValue : lowerValue, + maxSteps : maxSteps, + minSteps : minSteps + }; + } + + /** + * 计算Y轴刻度的各项数据 + */ + this.calcYAxis = function(){ + var scale = this.config.scale; + if (scale){ + scale.start = scale.start || 0; + scale.labels = this.populateLabels(scale.step,scale.start,scale.stepValue); + }else { + var bounds = this.getValueBounds(this.chartData.datasets); + scale = this.calcScale(this.scaleData.yHeight,bounds.maxSteps,bounds.minSteps,bounds.maxValue,bounds.minValue); + } + this.scaleData.yScaleValue = scale; + this.scaleData.yHop = Math.floor(this.scaleData.yHeight/scale.step); + } + + /** + * 计算X轴宽度,每个数据项宽度大小及坐标原点 + */ + this.calcXAxis = function(){ + var config = this.config,scale = this.scaleData,yLabelWidth = 0,xAxisLength,valueHop, x,y; + if (config.showScaleLabel){ + //找出Y轴刻度的最宽值 + _.each(scale.yScaleValue.labels,function(o){ + var w = this.ctx.measureText(o).width; + yLabelWidth = (w > yLabelWidth)? w : yLabelWidth; + },this); + yLabelWidth += P_Y; + } + //x轴的宽度 + xAxisLength = this.width - yLabelWidth-P_R-(this.config.showText?this.config.textFont.size:0); + + if(this._type_ == 'bar'){//计算柱形图柱子宽度,柱形图x轴文本居中显示,需要重新计算数据项宽度 + valueHop = Math.floor(xAxisLength/this.chartData.labels.length); + var len = this.chartData.datasets.length; + scale.barWidth = (valueHop - config.gridLineWidth*2 - (config.barSetSpacing*2) - (config.barSpacing*len-1) - ((config.barBorderWidth/2)*len-1))/len; + }else{ + valueHop = Math.floor(xAxisLength/(this.chartData.labels.length-1)); + } + scale.x = yLabelWidth; + scale.y = this.height - scale.xLabelHeight - P_X; + scale.xWidth = xAxisLength; + scale.xHop = valueHop; + } + + this.drawScale = function(){ + var ctx = this.ctx,cfg = this.config,scale = this.scaleData,align; + ctx.set({ + strokeStyle : cfg.scaleLineColor, + lineWidth : cfg.scaleLineWidth + }) + //画X轴 + ctx.line(scale.x-3, scale.y, scale.x+scale.xWidth, scale.y, true); + //画Y轴 + ctx.line(scale.x,scale.y+3, scale.x,scale.y-scale.yHeight, true); + + //画X轴刻度文本 + if (scale.labelRotate > 0){ + ctx.save(); + align = 'right'; + }else{ + align = 'center'; + } + ctx.set({ + fillStyle : cfg.scaleFont.color, + textAlign : align, + textBaseline : 'hanging', + strokeStyle : cfg.gridLineColor, + lineWidth : cfg.gridLineWidth + }); + _.each(this.chartData.labels,function(label,i){ + ctx.save(); + var cx = scale.x + i*scale.xHop,labelY = scale.y + P_X/ 2, + labelX = this._type_ == 'bar'?cx + scale.xHop/2 : cx; + if (scale.labelRotate > 0){ + ctx.translate(labelX,labelY).rotate(-(scale.labelRotate * (Math.PI/180))).fillText(label,0,0).restore(); + }else{ + ctx.fillText(label, labelX,labelY); + } + //画纵向的网格线 + if(cfg.showGridLine){ + var x = (this._type_ == 'bar')?cx + scale.xHop : cx; + ctx.line(x, scale.y, x, scale.y-scale.yHeight,true); + } + },this); + + //画横向网格线 + ctx.set({textAlign:'right',textBaseline:'middle'}); + for (var j=0; j maxSteps) { + if (step < minSteps){ + stepValue /= 2; + step = Math.round(range/stepValue); + } + else{ + stepValue *=2; + step = Math.round(range/stepValue); + } + }; + var labels = this.populateLabels(step, min, stepValue);; + return { + step : step, + stepValue : stepValue, + start : min, + labels : labels + } + function calculateOrderOfMagnitude(val){ + return Math.floor(Math.log(val) / Math.LN10); + } + } + + /** + * 构造刻度值 + * @param labels + * @param numberOfSteps + * @param graphMin + * @param stepValue + */ + this.populateLabels = function (step, start, stepValue) { + var labels = []; + for (var i = 1; i < step + 1; i++) { + if(!this.config.showScaleLabel){ + labels.push(''); + continue; + } + //小数点位数与stepValue后的小数点一致 + var value = (start + (stepValue * i)).toFixed(_.getDecimalPlaces(stepValue)); + var text = this.trigger('renderYLabel',[value]); + text = text ? text : value; + labels.push(text); + } + return labels; + }, + this.calcOffset = function(val,scale,scaleHop){ + var outerValue = scale.step * scale.stepValue; + var adjustedValue = val - scale.start; + var scalingFactor = _.capValue(adjustedValue/outerValue,1,0); + return (scaleHop*scale.step) * scalingFactor; + }, + + this.sliceData = function(data,offset,len,num){ + var newdata = _.clone(data); + var min = offset,max = offset + num; + if(max > len){ + min = len - num; + max = len; + } + newdata.labels = newdata.labels.slice(min,max); + _.each(newdata.datasets,function(d){ + d.data = d.data.slice(min,max) + }); + return newdata; + } + this.bindDataGestureEvent = function(){ + var _this = this, + touchDistanceX,//手指滑动偏移量 + startPosition,//触摸初始位置记录 + currentOffset = 0,//当前一次滑动的偏移量 + dataNum = this.config.datasetShowNumber,//每屏显示的数据条数 + gestureStarted, + hasTouch = 'ontouchstart' in window, + START_EV = hasTouch ? 'touchstart' : 'mousedown', + MOVE_EV = hasTouch ? 'touchmove' : 'mousemove', + END_EV = hasTouch ? 'touchend' : 'mouseup'; + + this.ctx.el.addEventListener(START_EV,touchstart); + this.ctx.el.addEventListener(MOVE_EV,touchmove); + this.ctx.el.addEventListener(END_EV,touchend); + + function touchstart(e){ + e = e.touches ? e.touches[0] : e; + startPosition = { + x : e.pageX, + y : e.pageY + } + touchDistanceX = 0; + gestureStarted = true; + } + function touchmove(e){ + if(!gestureStarted || !_this.config.datasetGesture)return; + e = e.touches ? e.touches[0] : e; + var x = e.pageX; + var y = e.pageY; + touchDistanceX = x - startPosition.x; + //每滑动xHop加载下一组数据 + var totalLen = _this.data.labels.length;//数据总长度 + var offset = _this.dataOffset - Math.floor(touchDistanceX/_this.scaleData.xHop); + if(offset < 0 || offset == currentOffset||(offset+dataNum > totalLen))return; + currentOffset = offset; + console.log(offset); + //将操作加入系统队列,解决android系统下touchmove的bug + setTimeout(function(){ + _this.redraw(_this.sliceData(_this.data,offset,totalLen,dataNum)); + },0) + } + function touchend(event){ + gestureStarted = false; + _this.dataOffset = currentOffset; + } + } + } + _.Scale = Scale; +})(JChart); \ No newline at end of file diff --git a/catapp/js/Jingle.debug.js b/catapp/js/Jingle.debug.js new file mode 100644 index 0000000..6b48c32 --- /dev/null +++ b/catapp/js/Jingle.debug.js @@ -0,0 +1,2117 @@ +/* + * Jingle v0.4 Copyright (c) 2013 shixy, http://shixy.github.io/Jingle/ + * Released under MIT license + * walker.shixy@gmail.com + */ +var Jingle = J = { + version : '0.41', + $ : window.Zepto, + //参数设置 + settings : { + //single 单页面工程 muti 多页面工程 + appType : 'single', + //page默认动画效果 + transitionType : 'slide', + //自定义动画时的默认动画时间(非page转场动画时间) + transitionTime : 250, + //自定义动画时的默认动画函数(非page转场动画函数) + transitionTimingFunc : 'ease-in', + //toast 持续时间,默认为3s + toastDuration : 3000, + //是否显示欢迎界面 + showWelcome : false, + //欢迎界面卡片切换时的执行函数,可以制作酷帅吊炸天的欢迎界面 + welcomeSlideChange : null, + //加载page模板时,是否显示遮罩 + showPageLoading : false, + //page模板默认的相对位置,主要用于开发hybrid应用,实现page的自动装载 + basePagePath : 'html/', + basePageSuffix : '.html', + //page模板的远程路径{#id: href,#id: href} + remotePage:{} + }, + //手机或者平板 + mode : window.innerWidth < 800 ? "phone" : "tablet", + hasTouch : 'ontouchstart' in window, + //是否启动完成 + launchCompleted : false, + //是否有打开的侧边菜单 + hasMenuOpen : false, + //是否有打开的弹出框 + hasPopupOpen : false, + isWebApp : location.protocol == 'http:', + /** + * 启动Jingle + * @param opts {object} + */ + launch : function(opts){ + $.extend(this.settings,opts); + var hasShowWelcome = window.localStorage.getItem('hasShowWelcome'); + if(!hasShowWelcome && this.settings.showWelcome){ + this.Welcome.show(); + } + this.Element.init(); + this.Element.initControlGroup(); + this.Router.init(); + this.Menu.init(); + } +}; + +/** + * 初始化页面组件元素 + */ +J.Element = (function($){ + var SELECTOR = { + 'icon' : '[data-icon]', + 'scroll' : '[data-scroll="true"]', + 'toggle' : '.toggle', + 'range' : '[data-rangeinput]', + 'progress' : '[data-progress]', + 'count' : '[data-count]', + 'checkbox' : '[data-checkbox]' + } + /** + * 初始化容器内组件 + * @param {String} 父元素的css选择器 + * @param {Object} 父元素或者父元素的zepto实例 + */ + var init = function(selector){ + if(!selector){ + //iscroll 必须在元素可见的情况下才能初始化 + $(document).on('articleshow','article',function(){ + J.Element.scroll(this); + }); + }; + var $el = $(selector || 'body'); + if($el.length == 0)return; + + $.map(_getMatchElements($el,SELECTOR.icon),_init_icon); + $.map(_getMatchElements($el,SELECTOR.toggle),_init_toggle); + $.map(_getMatchElements($el,SELECTOR.range),_init_range); + $.map(_getMatchElements($el,SELECTOR.progress),_init_progress); + $.map(_getMatchElements($el,SELECTOR.count),_init_badge); + $.map(_getMatchElements($el,SELECTOR.checkbox),_init_checkbox); + $el = null; + } + + /** + * 初始化按钮组(绑定事件) + */ + var initControlGroup = function(){ + $(document).on('tap','ul.control-group li',function(){ + var $this = $(this); + if($this.hasClass('active'))return; + $this.addClass('active').siblings('.active').removeClass('active').parent().trigger('change',[$this]); + }); + } + /** + * 自身与子集相结合 + */ + var _getMatchElements = function($el,selector){ + return $el.find(selector).add($el.filter(selector)); + } + /** + * 初始化iscroll组件或容器内iscroll组件 + */ + var initScroll = function(selector){ + $.map(_getMatchElements($(selector),SELECTOR.scroll),function(el){J.Scroll(el);}); + } + /** + * 构造icon组件 + */ + var _init_icon = function(el){ + var $el = $(el),$icon=$el.children('i.icon'),icon = $el.data('icon'); + if($icon.length > 0){//已经初始化,就更新icon + $icon.attr('class','icon '+icon); + }else{ + $el.prepend(''); + } + } + /** + * 构造toggle切换组件 + */ + var _init_toggle = function(el){ + var $el = $(el); + if($el.find('div.toggle-handle').length>0){//已经初始化 + return; + } + var name = $el.attr('name'); + //添加隐藏域,方便获取值 + if(name){ + $el.append(''); + } + $el.append('
'); + $el.tap(function(){ + var $t = $(this),v = !$t.hasClass('active'); + $t.toggleClass('active').trigger('toggle',[v]);//定义toggle事件 + $t.find('input').val(v); + }) + } + /** + * 构造range滑块组件 + */ + var _init_range = function(el){ + var $el = $(el),$input; + var $range = $('input[type="range"]',el); + var align = $el.data('rangeinput'); + var input = $(''); + if(align == 'left'){ + $input = input.prependTo($el); + }else{ + $input = input.appendTo($el); + } + var max = parseInt($range.attr('max'),10); + var min = parseInt($range.attr('min'),10); + $range.change(function(){ + $input.val($range.val()); + }); + $input.on('input',function(){ + var value = parseInt($input.val(),10); + value = value>max?max:(value').appendTo($el); + } + $bar.width(progress).text(title+progress); + if(progress == '100%'){ + $bar.css('border-radius','10px'); + } + } + /** + * 构造badge组件 + */ + var _init_badge = function(el){ + var $el = $(el),$count = $el.find('span.count'),count = parseInt($el.data('count')), + orient = $el.data('orient'), className = (orient == 'left')?'left':''; + if($count.length>0){ + $count.text(count).show();//更新数字 + }else{ + $count = $(''+count+'').appendTo($el); + } + if(count == 0){ + $count.hide(); + } + } + + var _init_checkbox = function(el){ + var $el = $(el); + var value = $el.data('checkbox'); + if($el.find('i.icon').length>0){ + return; + } + $el.prepend(''); + $el.on('tap',function(){ + var status = ($el.data('checkbox') == 'checked') ? 'unchecked':'checked'; + $el.data('checkbox',status).find('i.icon').attr('class','icon checkbox-'+status); + //自定义change事件 + $el.trigger('change'); + }); + + } + + return { + init : init, + initControlGroup : initControlGroup, + icon : _init_icon, + toggle : _init_toggle, + progress : _init_progress, + range : _init_range, + badge : _init_badge, + scroll : initScroll + } +})(J.$); +/** + * 侧边菜单 + */ +J.Menu = (function($){ + var $asideContainer,$sectionContainer,$sectionMask; + var init = function(){ + $asideContainer = $('#aside_container'); + $sectionContainer = $('#section_container'); + $sectionMask = $('
').appendTo('#section_container'); + //添加各种关闭事件 + $sectionMask.on('tap',hideMenu); + $asideContainer.on('swipeRight','aside',function(){ + if($(this).data('position') == 'right'){ + hideMenu(); + } + }); + $asideContainer.on('swipeLeft','aside',function(){ + if($(this).data('position') != 'right'){ + hideMenu(); + } + }); + $asideContainer.on('tap','.aside-close',hideMenu); + } + /** + * 打开侧边菜单 + * @param selector css选择器或element实例 + */ + var showMenu = function(selector){ + var $aside = $(selector).addClass('active'), + transition = $aside.data('transition'),// push overlay reveal + position = $aside.data('position') || 'left', + showClose = $aside.data('show-close'), + width = $aside.width(), + translateX = position == 'left'?width+'px':'-'+width+'px'; + if(showClose && $aside.find('div.aside-close').length == 0){ + $aside.append('
'); + } + + //aside中可能需要scroll组件 + J.Element.scroll($aside); + + if(transition == 'overlay'){ + J.anim($aside,{translateX : '0%'}); + }else if(transition == 'reveal'){ + J.anim($sectionContainer,{translateX : translateX}); + }else{//默认为push + J.anim($aside,{translateX : '0%'}); + J.anim($sectionContainer,{translateX : translateX}); + } + $('#section_container_mask').show(); + J.hasMenuOpen = true; + } + /** + * 关闭侧边菜单 + * @param duration {int} 动画持续时间 + * @param callback 动画完毕回调函数 + */ + var hideMenu = function(duration,callback){ + var $aside = $('#aside_container aside.active'), + transition = $aside.data('transition'),// push overlay reveal + position = $aside.data('position') || 'left', + translateX = position == 'left'?'-100%':'100%'; + + var _finishTransition = function(){ + $aside.removeClass('active'); + J.hasMenuOpen = false; + callback && callback.call(this); + }; + + if(transition == 'overlay'){ + J.anim($aside,{translateX : translateX},duration,_finishTransition); + }else if(transition == 'reveal'){ + J.anim($sectionContainer,{translateX : '0'},duration,_finishTransition); + }else{//默认为push + J.anim($aside,{translateX : translateX},duration); + J.anim($sectionContainer,{translateX : '0'},duration,_finishTransition); + } + + $('#section_container_mask').hide(); + } + return { + init : init, + show : showMenu, + hide : hideMenu + } +})(J.$); +/** + * section 页面远程加载 + */ +J.Page = (function($){ + var _formatHash = function(hash){ + return hash.indexOf('#') == 0 ? hash.substr(1) : hash; + } + /** + * 加载section模板 + * @param {string} hash信息 + * @param {string} url参数 + */ + var loadSectionTpl = function(hash,callback){ + var param = {},query,replaceSection = false; + if($.type(hash) == 'object'){ + param = hash.param; + query = hash.query; + hash = hash.tag; + } + var q = $(hash).data('query'); + //已经存在则直接跳转到对应的页面 + if($(hash).length == 1){ + if(q == query){ + callback(); + return; + }else{ + replaceSection = true; + } + } + var id = _formatHash(hash); + //当前dom中不存在,需要从服务端加载 + var url = J.settings.remotePage[hash]; + //检查remotePage中是否有配置,没有则自动从basePagePath中装载模板 + url || (url = J.settings.basePagePath+id+J.settings.basePageSuffix); + J.settings.showPageLoading && J.showMask(); + loadContent(url,param,function(html){ + J.settings.showPageLoading && J.hideMask(); + //添加到dom树中 + $(hash).remove(); + var $h = $(html); + $('#section_container').append($h); + if(replaceSection){ + $h.addClass('active'); + } + //触发pageload事件 + $h.trigger('pageload').data('query',query); + //构造组件 + J.Element.init(hash); + callback(); + $h = null; + }); + } + var loadSectionRemote = function(url,section){ + var param = J.Util.parseHash(window.location.hash).param; + loadContent(url,param,function(html){ + $(section).html(html); + J.Element.init(section); + }); + } + /** + * 加载文档片段 + * @param url + */ + var loadContent = function(url,param,callback){ + return $.ajax({ + url : url, + timeout : 20000, + data : param, + success : function(html){ + callback && callback(html); + } + }); + } + return { + load : loadSectionTpl, + loadSection : loadSectionRemote, + loadContent : loadContent + } +})(J.$); +/** + * 路由控制器 + */ +J.Router = (function($){ + var _history = []; + /** + * 初始化events、state + */ + var init = function(){ + $(window).on('popstate', _popstateHandler); + //阻止含data-target或者href以'#'开头的的a元素的默认行为 + $(document).on('click','a',function(e){ + var target = $(this).data('target'), + href = $(this).attr('href'); + if(!href || href.match(/^#/) || target){ + e.preventDefault(); + return false; + } + }); + $(document).on('tap','a[data-target]',_targetHandler); + _initIndex(); + } + + //处理app页面初始化 + var _initIndex = function(){ + var targetHash = location.hash; + //取页面中第一个section作为app的起始页 + var $section = $('#section_container section').first(); + var indexHash = '#'+$section.attr('id'); + _add2History(indexHash,true); + if(targetHash != '' && targetHash != indexHash){ + _showSection(targetHash);//跳转到指定的页面 + }else{ + $section.trigger('pageinit').trigger('pageshow').data('init',true).find('article.active').trigger('articleshow'); + } + } + + /** + * 处理浏览器的后退事件 + * 前进事件不做处理 + * @private + */ + var _popstateHandler = function(e){ + if(e.state && e.state.hash){ + var hash = e.state.hash; + if(_history[1] && hash === _history[1].hash){//存在历史记录,证明是后退事件 + J.hasMenuOpen && J.Menu.hide();//关闭当前页面的菜单 + J.hasPopupOpen && J.Popup.close();//关闭当前页面的弹出窗口 + back(); + }else{//其他认为是非法后退或者前进 + return; + } + }else{ + return; + } + + } + var _targetHandler = function(){ + var _this = $(this), + target = _this.attr('data-target'), + href = _this.attr('href'); + + switch(target){ + case 'section' : + if(J.settings.appType == 'single'){ + _showSection(href); + } + break; + case 'article' : + _showArticle(href,_this); + break; + case 'menu' : + _toggleMenu(href); + break; + case 'back' : + window.history.go(-1); + break; + } + } + + /** + * 跳转到新页面 + * @param hash 新page的'#id' + */ + var _showSection = function(hash){ + if(J.hasMenuOpen){//关闭菜单后再转场 + J.Menu.hide(200,function(){ + _showSection(hash); + }); + return; + } + //读取hash信息 + var hashObj = J.Util.parseHash(hash); + var current = _history[0]; + //同一个页面,则不重新加载 + if(current.hash === hashObj.hash){ + return; + } + //加载模板 + J.Page.load(hashObj,function(){ + var sameSection = (current.tag == hashObj.tag); + if(sameSection){//相同页面,触发相关事件 + $(current.tag).trigger('pageshow').find('article.active').trigger('articlehide'); + }else{//不同卡片页跳转动画 + _changePage(current.tag,hashObj.tag); + } + _add2History(hash,sameSection); + }); + } + /** + * 后退 + */ + var back = function(){ + if(J.settings.appType == 'single'){ + _changePage(_history.shift().tag,_history[0].tag,true) + } + } + var _changePage = function(current,target,isBack){ + J.Transition.run(current,target,isBack); + } + /** + * 缓存访问记录 + */ + var _add2History = function(hash,noState){ + var hashObj = J.Util.parseHash(hash); + if(noState){//不添加浏览器历史记录 + _history.shift(hashObj); + window.history.replaceState(hashObj,'',hash); + }else{ + window.history.pushState(hashObj,'',hash); + } + _history.unshift(hashObj); + } + + /** + * 激活href对应的article + * @param href #id + * @param el 当前锚点 + */ + var _showArticle = function(href,el){ + var article = $(href); + if(article.hasClass('active'))return; + el.addClass('active').siblings('.active').removeClass('active'); + var activeArticle = article.addClass('active').siblings('.active').removeClass('active'); + article.trigger('articleshow'); + activeArticle.trigger('articlehide'); + } + + var _toggleMenu = function(hash){ + J.hasMenuOpen?J.Menu.hide():J.Menu.show(hash); + } + + return { + init : init, + goTo : _showSection, + showArticle : _showArticle, + back : back + } +})(J.$); +/** + * 对zeptojs的ajax进行封装,实现离线访问 + * 推荐纯数据的ajax请求调用本方法,其他的依旧使用zeptojs自己的ajax + * @Deprecated 用J.Cache代替 + */ +J.Service = (function($){ + var UNPOST_KEY = 'JINGLE_POST_DATA', + GET_KEY_PREFIX = 'JINGLE_GET_'; + var ajax = function(options){ + if(options.type == 'post'){ + _doPost(options); + }else{ + _doGet(options); + } + } + + var _doPost = function(options){ + if(J.offline){//离线模式,将数据存到本地,连线时进行提交 + _setUnPostData(options.url,options.data); + options.success('数据已存至本地'); + }else{//在线模式,直接提交 + $.ajax(options); + } + } + var _doGet = function(options){ + var key = options.url +JSON.stringify(options.data); + if(J.offline){//离线模式,直接从本地读取 + var result = _getCache(key); + if(result){ + options.success(result.data,key,result.cacheTime); + }else{//未缓存该数据 + options.success(result); + } + }else{//在线模式,将数据保存到本地 + var callback = options.success; + options.success = function(result){ + _saveData2local(key,result); + callback(result,key); + } + $.ajax(options); + } + } + + /** + * 获取本地已缓存的数据 + * @private + */ + var _getCache = function(key){ + return JSON.parse(window.localStorage.getItem(GET_KEY_PREFIX+key)); + } + /** + * 缓存数据到本地 + * @private + */ + var _saveData2local = function(key,result){ + var data = { + data : result, + cacheTime : new Date() + } + window.localStorage.setItem(GET_KEY_PREFIX+key,JSON.stringify(data)); + } + + /** + * 将post的数据保存至本地 + * @param url + * @param result + * @private + */ + var _setUnPostData = function(url,result){ + var data = getUnPostData(); + data = data || {}; + data[url] = { + data : result, + createdTime : new Date() + } + window.localStorage.setItem(UNPOST_KEY,JSON.stringify(data)); + } + /** + * 获取尚未同步的post数据 + * @param url 没有就返回所有未同步的数据 + */ + var getUnPostData = function(url){ + var data = JSON.parse(window.localStorage.getItem(UNPOST_KEY)); + return (data && url ) ? data[url] : data; + } + /** + * 移除未同步的数据 + * @param url 没有就移除所有未同步的数据 + */ + var removeUnPostData = function(url){ + if(url){ + var data = getUnPostData(); + delete data[url]; + window.localStorage.setItem(UNPOST_KEY,JSON.stringify(data)); + }else{ + window.localStorage.removeItem(UNPOST_KEY); + } + } + + /** + * 同步本地缓存的post数据 + * @param url + */ + var syncPostData = function(url,success,error){ + var unPostData = getUnPostData(url).data; + $.ajax({ + url : url, + contentType:'application/json', + data : unPostData, + type : 'post', + success : function(){ + success(url); + }, + error : function(){ + error(url); + } + }) + } + /** + * 同步所有的数据 + * @param callback + */ + var syncAllPostData = function(success,error){ + var unPostData = getUnPostData(); + for(var url in unPostData){ + syncPostData(url,success,error); + } + removeUnPostData(); + } + + //copy from zepto + function parseArguments(url, data, success, dataType) { + var hasData = !$.isFunction(data) + return { + url: url, + data: hasData ? data : undefined, + success: !hasData ? data : $.isFunction(success) ? success : undefined, + dataType: hasData ? dataType || success : success + } + } + + var get = function(url, data, success, dataType){ + return ajax(parseArguments.apply(null, arguments)) + } + + var post = function(url, data, success, dataType){ + var options = parseArguments.apply(null, arguments) + options.type = 'POST' + return ajax(options) + } + + var getJSON = function(url, data, success){ + var options = parseArguments.apply(null, arguments); + options.dataType = 'json' + return ajax(options) + } + var clear = function(){ + var storage = window.localStorage; + var keys = []; + for(var i = 0; i< storage.length; i++){ + var key = storage.key(i); + key.indexOf(GET_KEY_PREFIX) == 0 && keys.push(key); + } + for(var i = 0; i < keys.length; i++){ + storage.removeItem(keys[i]); + } + storage.removeItem(UNPOST_KEY); + } + return { + ajax : ajax, + get : get, + post : post, + getJSON : getJSON, + getUnPostData : getUnPostData, + removeUnPostData : removeUnPostData, + syncPostData : syncPostData, + syncAllPostData : syncAllPostData, + getCacheData : _getCache, + saveCacheData : _saveData2local, + clear : clear + } +})(J.$); +/** + * 提供一些简单的模板,及artTemplate的渲染 + */ +J.Template = (function($){ + /** + * 背景模板 + * @param el selector + * @param title 显示文本 + * @param icon 图标 + */ + var background = function(el,title,icon){ + var markup = '
'+title+'
'; + $(el).html(markup); + } + + /** + * 无记录背景模板 + * @param el + */ + var no_result = function(el){ + background(el,'没有找到相关数据','drawer'); + } + /** + * 加载等待背景模板 + * @param el + */ + var loading = function(el){ + background(el,'加载中...','cloud-download'); + } + + /** + * 借助artTemplate模板来渲染页面 + * @param containerSelector 目标容器 + * @param templateId artTemplate模板ID + * @param data 模板数据 + * @param type replace|add 渲染好的文档片段是替换还是添加到目标容器中 + */ + var render = function(containerSelector,templateId,data,type){ + var el = $(containerSelector), + type = type || 'replace';//replace add + if($.type(data) == 'array' && data.length == 0 ){ + no_result(el); + }else{ + var html = template(templateId,data); + if(type == 'replace'){ + el.html(html); + }else{ + el.append(html); + } + J.Element.init(html); + } + } + return { + render : render, + background : background, + loading : loading, + no_result : no_result + } +})(J.$); + +/** + * 消息组件 + */ +J.Toast = (function($){ + var toast_type = 'toast',_toast,timer, + //定义模板 + TEMPLATE = { + toast : '{value}', + success : '{value}', + error : '{value}', + info : '{value}' + } + + var _init = function(){ + //全局只有一个实例 + $('body').append('
'); + _toast = $('#jingle_toast'); + _subscribeCloseTag(); + } + + /** + * 关闭消息提示 + */ + var hide = function(){ + J.anim(_toast,'scaleOut',function(){ + _toast.hide(); + _toast.empty(); + }); + } + /** + * 显示消息提示 + * @param type 类型 toast|success|error|info 空格 + class name 可以实现自定义样式 + * @param text 文字内容 + * @param duration 持续时间 为0则不自动关闭,默认为3000ms + */ + var show = function(type,text,duration){ + if(timer) clearTimeout(timer); + var classname = type.split(/\s/); + toast_type = classname[0]; + _toast.attr('class',type).html(TEMPLATE[toast_type].replace('{value}',text)).show(); + J.anim(_toast,'scaleIn'); + if(duration !== 0){//为0 不自动关闭 + timer = setTimeout(hide,duration || J.settings.toastDuration); + } + } + var _subscribeCloseTag = function(){ + _toast.on('tap','[data-target="close"]',function(){ + hide(); + }) + } + _init(); + return { + show : show, + hide : hide + } +})(J.$); +/** + * page转场动画 + * 可自定义css动画 + */ +J.Transition = (function($){ + var isBack,$current,$target,transitionName, + animationClass = { + //[[currentOut,targetIn],[currentOut,targetIn]] + slide : [['slideLeftOut','slideLeftIn'],['slideRightOut','slideRightIn']], + cover : [['','slideLeftIn'],['slideRightOut','']], + slideUp : [['','slideUpIn'],['slideDownOut','']], + slideDown : [['','slideDownIn'],['slideUpOut','']], + popup : [['','scaleIn'],['scaleOut','']] + }; + + var _doTransition = function(){ + //触发 beforepagehide 事件 + $current.trigger('beforepagehide',[isBack]); + //触发 beforepageshow 事件 + $target.trigger('beforepageshow',[isBack]); + var c_class = transitionName[0]||'empty' ,t_class = transitionName[1]||'empty'; + $current.bind('webkitAnimationEnd.jingle', _finishTransition).addClass('anim '+ c_class); + $target.addClass('anim animating '+ t_class); + } + var _finishTransition = function() { + $current.off('webkitAnimationEnd.jingle'); + $target.off('webkitAnimationEnd.jingle'); + //reset class + $current.attr('class',''); + $target.attr('class','active'); + //add custom events + !$target.data('init') && $target.trigger('pageinit').data('init',true); + !$current.data('init') && $current.trigger('pageinit').data('init',true); + //触发pagehide事件 + $current.trigger('pagehide',[isBack]); + //触发pageshow事件 + $target.trigger('pageshow',[isBack]); + + $current.find('article.active').trigger('articlehide'); + $target.find('article.active').trigger('articleshow'); + $current = $target = null;//释放 + } + + /** + * 执行转场动画,动画类型取决于目标page上动画配置(返回时取决于当前page) + * @param current 当前page + * @param target 目标page + * @param back 是否为后退 + */ + var run = function(current,target,back){ + //关闭键盘 + $(':focus').trigger('blur'); + isBack = back; + $current = $(current); + $target = $(target); + var type = isBack?$current.attr('data-transition'):$target.attr('data-transition'); + type = type|| J.settings.transitionType; + //后退时取相反的动画效果组 + transitionName = isBack ? animationClass[type][1] : animationClass[type][0]; + _doTransition(); + } + + /** + * 添加自定义转场动画效果 + * @param name 动画名称 + * @param currentOut 正常情况下当前页面退去的动画class + * @param targetIn 正常情况下目标页面进入的动画class + * @param backCurrentOut 后退情况下当前页面退去的动画class + * @param backCurrentIn 后退情况下目标页面进入的动画class + */ + var addAnimation = function(name,currentOut,targetIn,backCurrentOut,backCurrentIn){ + if(animationClass[name]){ + console.error('该转场动画已经存在,请检查你自定义的动画名称(名称不能重复)'); + return; + } + animationClass[name] = [[currentOut,targetIn],[backCurrentOut,backCurrentIn]]; + } + return { + run : run, + add : addAnimation + } + +})(J.$); +/** + * 常用工具类 + */ +J.Util = (function($){ + var parseHash = function(hash){ + var tag,query,param={}; + var arr = hash.split('?'); + tag = arr[0]; + if(arr.length>1){ + var seg,s; + query = arr[1]; + seg = query.split('&'); + for(var i=0;i{title}', + confirm : '', + loading : '

{title}

' + }; + + /** + * 全局只有一个popup实例 + * @private + */ + var _init = function(){ + $('body').append('
'); + _mask = $('#jingle_popup_mask'); + _popup = $('#jingle_popup'); + _subscribeEvents(); + } + + var show = function(options){ + var settings = { + height : undefined,//高度 + width : undefined,//宽度 + opacity : 0.3,//透明度 + url : null,//远程加载url + tplId : null,//加载模板ID + tplData : null,//模板数据,配合tplId使用 + html : '',//popup内容 + pos : 'center',//位置 {@String top|top-second|center|bottom|bottom-second} {@object css样式} + clickMask2Close : true,// 是否点击外层遮罩关闭popup + showCloseBtn : true,// 是否显示关闭按钮 + arrowDirection : undefined,//popover的箭头指向 + animation : true,//是否显示动画 + timingFunc : 'linear', + duration : 200,//动画执行时间 + onShow : undefined //@event 在popup内容加载完毕,动画开始前触发 + } + $.extend(settings,options); + clickMask2close = settings.clickMask2Close; + _mask.css('opacity',settings.opacity); + //rest position and class + _popup.attr({'style':'','class':''}); + settings.width && _popup.width(settings.width); + settings.height && _popup.height(settings.height); + var pos_type = $.type(settings.pos); + if(pos_type == 'object'){// style + _popup.css(settings.pos); + transition = ANIM['defaultAnim']; + }else if(pos_type == 'string'){ + if(POSITION[settings.pos]){ //已经默认的样式 + _popup.css(POSITION[settings.pos]) + var trans_key = settings.pos.indexOf('top')>-1?'top':(settings.pos.indexOf('bottom')>-1?'bottom':'defaultAnim'); + transition = ANIM[trans_key]; + }else{// pos 为 class + _popup.addClass(settings.pos); + transition = ANIM['defaultAnim']; + } + }else{ + console.error('错误的参数!'); + return; + } + _mask.show(); + var html; + if(settings.html){ + html = settings.html; + }else if(settings.url){//远程加载 + html = J.Page.loadContent(settings.url); + }else if(settings.tplId){//加载模板 + html = template(settings.tplId,settings.tplData) + } + + //是否显示关闭按钮 + if(settings.showCloseBtn){ + html += '
'; + } + //popover 箭头方向 + if(settings.arrowDirection){ + _popup.addClass('arrow '+settings.arrowDirection); + _popup.css('padding','8px'); + if(settings.arrowDirection=='top'||settings.arrowDirection=='bottom'){ + transition = ANIM[settings.arrowDirection]; + } + } + + _popup.html(html).show(); + J.Element.init(_popup); + //执行onShow事件,可以动态添加内容 + settings.onShow && settings.onShow.call(_popup); + + //显示获取容器高度,调整至垂直居中 + if(settings.pos == 'center'){ + var height = _popup.height(); + _popup.css('margin-top','-'+height/2+'px') + } + if(settings.animation){ + J.anim(_popup,transition[0],settings.duration,settings.timingFunc); + } + J.hasPopupOpen = true; + } + + /** + * 关闭弹出框 + * @param noTransition 立即关闭,无动画 + */ + var hide = function(noTransition){ + _mask.hide(); + if(transition && !noTransition){ + J.anim(_popup,transition[1],200,function(){ + _popup.hide().empty(); + J.hasPopupOpen = false; + }); + }else{ + _popup.hide().empty(); + J.hasPopupOpen = false; + } + + } + var _subscribeEvents = function(){ + _mask.on('tap',function(){ + clickMask2close && hide(); + }); + _popup.on('tap','[data-target="closePopup"]',function(){hide();}); + } + + /** + * alert组件 + * @param title 标题 + * @param content 内容 + */ + var alert = function(title,content,btnName){ + var markup = TEMPLATE.alert.replace('{title}',title).replace('{content}',content).replace('{ok}',btnName || '确定'); + show({ + html : markup, + pos : 'center', + clickMask2Close : false, + showCloseBtn : false + }); + } + + /** + * confirm 组件 + * @param title 标题 + * @param content 内容 + * @param okCall 确定按钮handler + * @param cancelCall 取消按钮handler + */ + var confirm = function(title,content,okCall,cancelCall){ + var markup = TEMPLATE.confirm.replace('{title}',title).replace('{content}',content).replace('{cancel}','取消').replace('{ok}','确定'); + show({ + html : markup, + pos : 'center', + clickMask2Close : false, + showCloseBtn : false + }); + $('#popup_btn_container [data-icon="checkmark"]').tap(function(){ + hide(); + okCall.call(this); + }); + $('#popup_btn_container [data-icon="close"]').tap(function(){ + hide(); + cancelCall.call(this); + }); + } + + /** + * 带箭头的弹出框 + * @param html 弹出框内容 + * @param pos 位置 + * @param arrow_direction 箭头方向 + * @param onShow onShow事件 + */ + var popover = function(html,pos,arrow_direction,onShow){ + show({ + html : html, + pos : pos, + showCloseBtn : false, + arrowDirection : arrow_direction, + onShow : onShow + }); + } + + /** + * loading组件 + * @param text 文本,默认为“加载中...” + */ + var loading = function(text){ + var markup = TEMPLATE.loading.replace('{title}',text||'加载中...'); + show({ + html : markup, + pos : 'loading', + opacity :.1, + animation : true, + clickMask2Close : false + }); + } + + /** + * actionsheet组件 + * @param buttons 按钮集合 + * [{color:'red',text:'btn',handler:function(){}},{color:'red',text:'btn',handler:function(){}}] + */ + var actionsheet = function(buttons){ + var markup = '
'; + $.each(buttons,function(i,n){ + markup += ''; + }); + markup += ''; + markup += '
'; + show({ + html : markup, + pos : 'bottom', + showCloseBtn : false, + onShow : function(){ + $(this).find('button').each(function(i,button){ + $(button).on('tap',function(){ + if(buttons[i] && buttons[i].handler){ + buttons[i].handler.call(button); + } + hide(); + }); + }); + } + }); + } + + _init(); + + return { + show : show, + close : hide, + alert : alert, + confirm : confirm, + popover : popover, + loading : loading, + actionsheet : actionsheet + } +})(J.$); +/** + * 高亮组件 + * 在zepto的tap事件里注入了一个延时器,来实现点击态 + */ +J.Selected = (function($){ + var DELAY = 100,SELECTOR='[data-selected]'; + var _trigger = $.fn.trigger; + $.fn.trigger = function (event) { + var $this = $(this), args = arguments, classname; + if (event === 'tap' || event.type === 'tap') { + var match = $this.closest(SELECTOR).get(0); + if(match){ + match = $(match); + classname = match.data('selected'); + match.addClass(classname); + setTimeout(function () { + match.removeClass(classname); + _trigger.apply($this, args); + $this = match = null; + }, DELAY); + return this; + } + } + _trigger.apply($this, args); + return this; + } +})(J.$); +/** + * 数据缓存 + * todo 对数据进行加密 + */ +J.Cache = (function($){ + var UNPOST_KEY = '_J_P_', + GET_KEY_PREFIX = '_J_'; + + /** + * 缓存从服务端获取的数据 + * @param key + * @param value + */ + var save = function(key,value){ + var data = { + data : value, + cacheTime : new Date() + } + window.localStorage.setItem(GET_KEY_PREFIX+key,JSON.stringify(data)); + } + /** + * 获取本地已缓存的数据 + */ + var get = function(key){ + return JSON.parse(window.localStorage.getItem(GET_KEY_PREFIX+key)); + } + + /** + * 缓存本地待提交到服务端的数据(离线操作) + * @param url + * @param result + */ + var savePost = function(url,result){ + var data = getPost(); + data = data || {}; + data[url] = { + data : result, + createdTime : new Date() + } + window.localStorage.setItem(UNPOST_KEY,JSON.stringify(data)); + } + + /** + * 获取本地尚未提交到服务端的缓存数据 + * @param url 没有就返回所有未同步的数据 + */ + var getPost = function(url){ + var data = JSON.parse(window.localStorage.getItem(UNPOST_KEY)); + return (data && url ) ? data[url] : data; + } + /** + * 移除未提交的待提交到服务端的缓存数据 + * @param url 没有就移除所有未提交的数据 + */ + var removePost = function(url){ + if(url){ + var data = getPost(); + delete data[url]; + window.localStorage.setItem(UNPOST_KEY,JSON.stringify(data)); + }else{ + window.localStorage.removeItem(UNPOST_KEY); + } + } + /** + * 同步本地未提交的数据到服务端 + * * @param url 没有就同步所有未提交的数据 + */ + var syncPost = function(url,success,error){ + var dataLen,index = 0; + if($.type(url) == 'string'){ + dataLen = 1; + sync(url); + }else{ + var postData = getPost(); + if(!postData)return; + dataLen = postData.length; + for(var url in postData){ + sync(url); + } + } + function sync(url){ + var data = getPost(url).data; + $.ajax({ + url : url, + contentType:'application/json', + data : data, + type : 'post', + success : function(){ + index++; + removePost(url); + if(index == dataLen)success(url); + }, + error : function(){ + error(url); + } + }) + } + } + + /** + * 清空本地缓存 + */ + var clear = function(){ + var storage = window.localStorage; + for(var key in storage){ + if(key.indexOf(GET_KEY_PREFIX) == 0){ + storage.removeItem(key); + } + } + storage.removeItem(UNPOST_KEY); + } + + + return { + get : get, + save : save, + getPost : getPost, + savePost : savePost, + removePost : removePost, + syncPost : syncPost, + clear : clear + } + +})(J.$); +;(function($){ + /** + * 日历组件 + * @param selector selector + * @param options 配置参数 + */ + var calendar = function(selector,options){ + var defaults = { + months : ["01月", "02月", "03月", "04月", "05月", "06月", + "07月", "08月", "09月", "10月", "11月", "12月"], + days : ["日", "一", "二", "三", "四", "五", "六"], + swipeable : true,//是否可通过手指滑动 + date : new Date(),//日历当前日期 + onRenderDay : undefined,//渲染单元格时的事件 + onSelect : undefined //选中日期时的事件 + }, + _this = this, + $el = $(selector), + $yearText, + $monthText, + $calendarBody, + currentDate,currentYear,currentMonth; + + var _init = function(){ + _this.settings = $.extend({},defaults,options); + currentYear = _this.settings.date.getFullYear(); + currentMonth = _this.settings.date.getMonth(); + currentDate = new Date(currentYear,currentMonth,_this.settings.date.getDate()); + _render(); + _subscribeEvents(); + } + + /** + * 获取月份第一天是星期几[0-6] + */ + var _fisrtDayOfMonth = function(date){ + return ( new Date(date.getFullYear(), date.getMonth(), 1) ).getDay(); + } + /** + * 获取月份总天数[1-31] + */ + var _daysInMonth = function(date){ + return ( new Date(date.getFullYear(),date.getMonth()+1,0) ).getDate(); + } + + /** + * 渲染日历 + * @private + */ + var _render = function(){ + var html = ''; + html += '
'; + html += _renderNav(currentYear,currentMonth); + html += _renderHead(); + html += '
'; + html += _renderBody(currentDate); + html += '
' + $el.html(html); + var $span = $el.find('span'); + $yearText = $span.eq(0); + $monthText = $span.eq(1); + $calendarBody = $el.find('.jingle-calendar-body'); + } + + var _renderNav = function(year,month){ + var html = '
'; + html += '
'+year+'
'; + html += '
'+_this.settings.months[month]+'
'; + html += '
'; + return html; + } + + var _renderHead = function(){ + var html = ''; + for(var i = 0; i < 7; i++){ + html += ''; + } + html += '
'+_this.settings.days[i]+'
' + return html; + } + + var _renderBody = function(date){ + var firstDay = _fisrtDayOfMonth(date), + days = _daysInMonth(date), + rows = Math.ceil((firstDay+days) / 7), + beginDate, + html = ''; + currentYear = date.getFullYear(); + currentMonth = date.getMonth(); + beginDate = new Date(currentYear,currentMonth,1-firstDay);//日历开始的日期 + html += ''; + for(var i = 0; i < rows; i++){ + html += ''; + for(var j = 0; j < 7; j++){ + html += _renderDay(beginDate,currentMonth); + beginDate.setDate(beginDate.getDate() + 1); + } + html += ''; + } + html += '
'; + return html; + } + var _renderDay = function(date,month){ + var otherMonth = (date.getMonth() !== month); + var dateStr = _this.format(date); + var classname = (_this.format(_this.settings.date) == dateStr) ? 'active':''; + var dayStr = date.getDate(); + if(_this.settings.onRenderDay){ + dayStr = _this.settings.onRenderDay.call(null,dayStr,dateStr); + } + return otherMonth ? ' ' : ''+dayStr+''; + } + + var _subscribeEvents = function(){ + var $target,$ctarget; + $el.on('tap',function(e){ + $target = $(e.target); + if($target.is('[data-year].next')){ + //后一年 + currentDate.setFullYear(currentDate.getFullYear()+1); + _this.refresh(currentDate); + }else if($target.is('[data-year].previous')){ + //前一年 + currentDate.setFullYear(currentDate.getFullYear()-1); + _this.refresh(currentDate); + }else if($target.is('[data-month].next')){ + //后一月 + currentDate.setMonth(currentDate.getMonth()+1); + _this.refresh(currentDate); + }else if($target.is('[data-month].previous')){ + //前一月 + currentDate.setMonth(currentDate.getMonth()-1); + _this.refresh(currentDate); + } + $ctarget = $target.closest('td'); + if(!$target.is('td') && $ctarget.length > 0){ + $target = $ctarget; + } + if($target.is('td')){ + var dateStr = $target.data('date'); + if(dateStr && _this.settings.onSelect){ + _this.settings.onSelect.call(_this,dateStr) + } + } + + }); + $el.on('swipeLeft',function(){ + currentDate.setMonth(currentDate.getMonth()+1); + _this.refresh(currentDate); + }); + $el.on('swipeRight',function(){ + currentDate.setMonth(currentDate.getMonth()-1); + _this.refresh(currentDate); + }) + } + + /** + * 刷新日历为指定日期 + * @param date 指定日期 + */ + this.refresh = function(date){ + var oldDate = new Date(currentYear,currentMonth,1), + newDate = new Date(date.getFullYear(),date.getMonth(),1), + transition = undefined,$table; + + if(oldDate.getTime() == newDate.getTime())return; + transition = oldDate0){ + dots.show(); + }else{ + var dotsWidth = slideNum*30+20+2; + var html = '
    '; + for(var i=0;i 0 || index == slideNum - 1 && deltaX < 0; + if(isPastBounds)return; + var pos = (deltaX - index * slideWidth); + container[0].style.webkitTransform = 'translate3D('+pos+'px,0,0)'; + } + }; + + var _touchEnd = function(e) { + //判定是否跳转到下一个卡片 + //滑动时间小于250ms或者滑动X轴的距离大于屏幕宽度的1/3,则直接跳转到下一个卡片 + var isValidSlide = (Number(new Date()) - start.time < 250 && Math.abs(deltaX) > 20) || Math.abs(deltaX) > slideWidth/3; + //判定是否达到了边界即第一个右滑、最后一个左滑 + var isPastBounds = !index && deltaX > 0 || index == slideNum - 1 && deltaX < 0; + if (!isScrolling) { + if(beforeSlide(index,deltaX)){ + _slide( index + ( isValidSlide && !isPastBounds ? (deltaX < 0 ? 1 : -1) : 0 ), speed ); + }else{ + _slide(index); + } + } + gestureStarted = false; + }; + + + _init(); + _bindEvents(); + + this.refresh = function(){ + container.attr('style',''); + _init(); + }; + + this.prev = function() { + if (index) _slide(index-1, speed); + }; + + this.next = function() { + if(index < slideNum-1){ + _slide(index+1, speed); + } + }; + this.index = function(i) { + _slide(i); + }; + } + J.Slider = slider; +})(J.$); +/** + * 上拉/下拉组件 + */ +;(function($){ + var refreshCache = {},index = 1; + function Refresh(selector,type,callback){ + var iscroll, scroller,refreshEl,iconEl,labelEl,topOffset,isPullDown, + options = { + selector : undefined, + type : 'pullDown',//pullDown|pullUp 默认为pullDown + minPullHeight : 10,//拉动的像素相对值,超过才会翻转 + pullText: "下拉刷新...", + releaseText: "松开立即刷新...", + refreshText: "刷新中...", + refreshTip : false,//下拉时显示的文本,比如:最后更新时间:2013-.... + onPullIcon : 'arrow-down-2', + onReleaseIcon : 'icon-reverse', + onRefreshIcon : 'spinner', + callback : undefined + }; + //装载配置 + if(typeof selector === 'object'){ + $.extend(options,selector); + }else{ + options.selector = selector; + options.type = type; + options.callback = callback; + if(type === 'pullUp'){ + $.extend(options,{ + pullText: "上拉加载更多...", + releaseText: "松开开立即加载...", + refreshText: "加载中...", + onPullIcon : 'arrow-up-3' + }) + } + } + isPullDown = options.type === 'pullDown' ? true : false; + + /** + * 初始化dom节点 + * @param opts + * @private + */ + var _init = function(opts){ + scroller = $(opts.selector).children()[0]; + var refreshTpl = '
    ' + +opts.pullText+'' + +(opts.refreshTip?'
    '+opts.refreshTip+'
    ':'')+'
    '; + if(isPullDown){ + refreshEl = $(refreshTpl).prependTo(scroller); + }else{ + refreshEl = $(refreshTpl).appendTo(scroller); + } + topOffset = refreshEl.height(); + iconEl = refreshEl.find('.refresh-icon'); + labelEl = refreshEl.find('.refresh-label'); + } + + /** + * 构造iscroll组件,并绑定滑动事件 + * @param opts + * @private + */ + var _excuteScroll = function(opts){ + return J.Scroll(opts.selector,{ + topOffset:isPullDown?topOffset:0, + bounce : true, + onScrollMove : function(){ + if (this.y > opts.minPullHeight && isPullDown && !iconEl.hasClass(opts.onReleaseIcon)) { + iconEl.addClass(opts.onReleaseIcon); + labelEl.html(opts.releaseText); + this.minScrollY = 0; + } else if (this.y < opts.minPullHeight && isPullDown && iconEl.hasClass(opts.onReleaseIcon)) { + iconEl.removeClass(opts.onReleaseIcon); + labelEl.html(opts.pullText); + this.minScrollY = -topOffset; + }else if (this.y < (this.maxScrollY - opts.minPullHeight) && !isPullDown && !iconEl.hasClass(opts.onReleaseIcon)) { + iconEl.addClass(opts.onReleaseIcon); + labelEl.html(opts.releaseText); + this.maxScrollY = this.maxScrollY; + } else if (this.y > (this.maxScrollY + opts.minPullHeight) && !isPullDown && iconEl.hasClass(opts.onReleaseIcon)) { + iconEl.removeClass(opts.onReleaseIcon); + labelEl.html(opts.pullText); + this.maxScrollY = topOffset; + } + }, + onScrollEnd : function(){ + if(iconEl.hasClass(opts.onReleaseIcon)){ + iconEl.removeClass(opts.onReleaseIcon).removeClass(opts.onPullIcon).addClass(opts.onRefreshIcon); + labelEl.html(opts.refreshText); + var _this = this; + setTimeout(function(){//解决在chrome下onRefresh的时候文本无法更改的问题。奇怪的问题! + opts.callback.call(_this); + },1); + + } + }, + onRefresh: function () { + iconEl.removeClass(opts.onRefreshIcon).addClass(opts.onPullIcon); + labelEl.html(opts.pullText); + } + }); + } + + //run + _init(options); + iscroll = _excuteScroll(options); + return iscroll; + + } + + /** + * 刷新组件 + * @param selector selector + * @param type 类型 pullDown(下拉) pullUp(上拉) + * @param callback 回调函数 + */ + J.Refresh = function(selector,type,callback){ + var el,jRefreshId; + if(selector.selector){ + el = $(selector.selector) + }else{ + el = $(selector); + } + jRefreshId = el.data('_jrefresh_'); + //因上拉下拉可能会使用的比较频繁,故缓存起来节省开销,亦可防止重复绑定 + if(jRefreshId && refreshCache[jRefreshId]){ + return refreshCache[jRefreshId]; + }else{ + jRefreshId = '_jrefresh_'+index++; + el.data('_jrefresh_',jRefreshId); + var refresh = new Refresh(selector,type,callback); + return refreshCache[jRefreshId] = { + scroller : refresh.scroller, + destroy : function(){ + delete refreshCache[jRefreshId]; + refresh.scroller.destroy(); + $('.refresh-container',selector).remove(); + } + }; + } + } +})(J.$); \ No newline at end of file diff --git a/catapp/js/barcodescanner.js b/catapp/js/barcodescanner.js new file mode 100644 index 0000000..ae3a7b8 --- /dev/null +++ b/catapp/js/barcodescanner.js @@ -0,0 +1,15 @@ +(function(){ + function BarcodeScanner() {}; + + BarcodeScanner.prototype.scan = function(mode,win,err){ + cordova.exec(win, err, "BarcodeScanner", "scan", [mode]); + }; + + + if(!window.plugins) { + window.plugins = {}; + } + if (!window.plugins.barcodeScanner) { + window.plugins.barcodeScanner = new BarcodeScanner(); + } +})(); diff --git a/catapp/js/cordova.js b/catapp/js/cordova.js new file mode 100644 index 0000000..936911d --- /dev/null +++ b/catapp/js/cordova.js @@ -0,0 +1,6947 @@ +// Platform: android +// 2.9.0-0-g83dc4bd +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ +;(function() { +var CORDOVA_JS_BUILD_LABEL = '2.9.0-0-g83dc4bd'; +// file: lib/scripts/require.js + +var require, + define; + +(function () { + var modules = {}, + // Stack of moduleIds currently being built. + requireStack = [], + // Map of module ID -> index into requireStack of modules currently being built. + inProgressModules = {}, + SEPERATOR = "."; + + + + function build(module) { + var factory = module.factory, + localRequire = function (id) { + var resultantId = id; + //Its a relative path, so lop off the last portion and add the id (minus "./") + if (id.charAt(0) === ".") { + resultantId = module.id.slice(0, module.id.lastIndexOf(SEPERATOR)) + SEPERATOR + id.slice(2); + } + return require(resultantId); + }; + module.exports = {}; + delete module.factory; + factory(localRequire, module.exports, module); + return module.exports; + } + + require = function (id) { + if (!modules[id]) { + throw "module " + id + " not found"; + } else if (id in inProgressModules) { + var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id; + throw "Cycle in require graph: " + cycle; + } + if (modules[id].factory) { + try { + inProgressModules[id] = requireStack.length; + requireStack.push(id); + return build(modules[id]); + } finally { + delete inProgressModules[id]; + requireStack.pop(); + } + } + return modules[id].exports; + }; + + define = function (id, factory) { + if (modules[id]) { + throw "module " + id + " already defined"; + } + + modules[id] = { + id: id, + factory: factory + }; + }; + + define.remove = function (id) { + delete modules[id]; + }; + + define.moduleMap = modules; +})(); + +//Export for use in node +if (typeof module === "object" && typeof require === "function") { + module.exports.require = require; + module.exports.define = define; +} + +// file: lib/cordova.js +define("cordova", function(require, exports, module) { + + +var channel = require('cordova/channel'); + +/** + * Listen for DOMContentLoaded and notify our channel subscribers. + */ +document.addEventListener('DOMContentLoaded', function() { + channel.onDOMContentLoaded.fire(); +}, false); +if (document.readyState == 'complete' || document.readyState == 'interactive') { + channel.onDOMContentLoaded.fire(); +} + +/** + * Intercept calls to addEventListener + removeEventListener and handle deviceready, + * resume, and pause events. + */ +var m_document_addEventListener = document.addEventListener; +var m_document_removeEventListener = document.removeEventListener; +var m_window_addEventListener = window.addEventListener; +var m_window_removeEventListener = window.removeEventListener; + +/** + * Houses custom event handlers to intercept on document + window event listeners. + */ +var documentEventHandlers = {}, + windowEventHandlers = {}; + +document.addEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + if (typeof documentEventHandlers[e] != 'undefined') { + documentEventHandlers[e].subscribe(handler); + } else { + m_document_addEventListener.call(document, evt, handler, capture); + } +}; + +window.addEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + if (typeof windowEventHandlers[e] != 'undefined') { + windowEventHandlers[e].subscribe(handler); + } else { + m_window_addEventListener.call(window, evt, handler, capture); + } +}; + +document.removeEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + // If unsubscribing from an event that is handled by a plugin + if (typeof documentEventHandlers[e] != "undefined") { + documentEventHandlers[e].unsubscribe(handler); + } else { + m_document_removeEventListener.call(document, evt, handler, capture); + } +}; + +window.removeEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + // If unsubscribing from an event that is handled by a plugin + if (typeof windowEventHandlers[e] != "undefined") { + windowEventHandlers[e].unsubscribe(handler); + } else { + m_window_removeEventListener.call(window, evt, handler, capture); + } +}; + +function createEvent(type, data) { + var event = document.createEvent('Events'); + event.initEvent(type, false, false); + if (data) { + for (var i in data) { + if (data.hasOwnProperty(i)) { + event[i] = data[i]; + } + } + } + return event; +} + +if(typeof window.console === "undefined") { + window.console = { + log:function(){} + }; +} + +var cordova = { + define:define, + require:require, + /** + * Methods to add/remove your own addEventListener hijacking on document + window. + */ + addWindowEventHandler:function(event) { + return (windowEventHandlers[event] = channel.create(event)); + }, + addStickyDocumentEventHandler:function(event) { + return (documentEventHandlers[event] = channel.createSticky(event)); + }, + addDocumentEventHandler:function(event) { + return (documentEventHandlers[event] = channel.create(event)); + }, + removeWindowEventHandler:function(event) { + delete windowEventHandlers[event]; + }, + removeDocumentEventHandler:function(event) { + delete documentEventHandlers[event]; + }, + /** + * Retrieve original event handlers that were replaced by Cordova + * + * @return object + */ + getOriginalHandlers: function() { + return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener}, + 'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}}; + }, + /** + * Method to fire event from native code + * bNoDetach is required for events which cause an exception which needs to be caught in native code + */ + fireDocumentEvent: function(type, data, bNoDetach) { + var evt = createEvent(type, data); + if (typeof documentEventHandlers[type] != 'undefined') { + if( bNoDetach ) { + documentEventHandlers[type].fire(evt); + } + else { + setTimeout(function() { + // Fire deviceready on listeners that were registered before cordova.js was loaded. + if (type == 'deviceready') { + document.dispatchEvent(evt); + } + documentEventHandlers[type].fire(evt); + }, 0); + } + } else { + document.dispatchEvent(evt); + } + }, + fireWindowEvent: function(type, data) { + var evt = createEvent(type,data); + if (typeof windowEventHandlers[type] != 'undefined') { + setTimeout(function() { + windowEventHandlers[type].fire(evt); + }, 0); + } else { + window.dispatchEvent(evt); + } + }, + + /** + * Plugin callback mechanism. + */ + // Randomize the starting callbackId to avoid collisions after refreshing or navigating. + // This way, it's very unlikely that any new callback would get the same callbackId as an old callback. + callbackId: Math.floor(Math.random() * 2000000000), + callbacks: {}, + callbackStatus: { + NO_RESULT: 0, + OK: 1, + CLASS_NOT_FOUND_EXCEPTION: 2, + ILLEGAL_ACCESS_EXCEPTION: 3, + INSTANTIATION_EXCEPTION: 4, + MALFORMED_URL_EXCEPTION: 5, + IO_EXCEPTION: 6, + INVALID_ACTION: 7, + JSON_EXCEPTION: 8, + ERROR: 9 + }, + + /** + * Called by native code when returning successful result from an action. + */ + callbackSuccess: function(callbackId, args) { + try { + cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback); + } catch (e) { + console.log("Error in error callback: " + callbackId + " = "+e); + } + }, + + /** + * Called by native code when returning error result from an action. + */ + callbackError: function(callbackId, args) { + // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative. + // Derive success from status. + try { + cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback); + } catch (e) { + console.log("Error in error callback: " + callbackId + " = "+e); + } + }, + + /** + * Called by native code when returning the result from an action. + */ + callbackFromNative: function(callbackId, success, status, args, keepCallback) { + var callback = cordova.callbacks[callbackId]; + if (callback) { + if (success && status == cordova.callbackStatus.OK) { + callback.success && callback.success.apply(null, args); + } else if (!success) { + callback.fail && callback.fail.apply(null, args); + } + + // Clear callback if not expecting any more results + if (!keepCallback) { + delete cordova.callbacks[callbackId]; + } + } + }, + addConstructor: function(func) { + channel.onCordovaReady.subscribe(function() { + try { + func(); + } catch(e) { + console.log("Failed to run constructor: " + e); + } + }); + } +}; + +// Register pause, resume and deviceready channels as events on document. +channel.onPause = cordova.addDocumentEventHandler('pause'); +channel.onResume = cordova.addDocumentEventHandler('resume'); +channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready'); + +module.exports = cordova; + +}); + +// file: lib/common/argscheck.js +define("cordova/argscheck", function(require, exports, module) { + +var exec = require('cordova/exec'); +var utils = require('cordova/utils'); + +var moduleExports = module.exports; + +var typeMap = { + 'A': 'Array', + 'D': 'Date', + 'N': 'Number', + 'S': 'String', + 'F': 'Function', + 'O': 'Object' +}; + +function extractParamName(callee, argIndex) { + return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex]; +} + +function checkArgs(spec, functionName, args, opt_callee) { + if (!moduleExports.enableChecks) { + return; + } + var errMsg = null; + var typeName; + for (var i = 0; i < spec.length; ++i) { + var c = spec.charAt(i), + cUpper = c.toUpperCase(), + arg = args[i]; + // Asterix means allow anything. + if (c == '*') { + continue; + } + typeName = utils.typeName(arg); + if ((arg === null || arg === undefined) && c == cUpper) { + continue; + } + if (typeName != typeMap[cUpper]) { + errMsg = 'Expected ' + typeMap[cUpper]; + break; + } + } + if (errMsg) { + errMsg += ', but got ' + typeName + '.'; + errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg; + // Don't log when running jake test. + if (typeof jasmine == 'undefined') { + console.error(errMsg); + } + throw TypeError(errMsg); + } +} + +function getValue(value, defaultValue) { + return value === undefined ? defaultValue : value; +} + +moduleExports.checkArgs = checkArgs; +moduleExports.getValue = getValue; +moduleExports.enableChecks = true; + + +}); + +// file: lib/common/builder.js +define("cordova/builder", function(require, exports, module) { + +var utils = require('cordova/utils'); + +function each(objects, func, context) { + for (var prop in objects) { + if (objects.hasOwnProperty(prop)) { + func.apply(context, [objects[prop], prop]); + } + } +} + +function clobber(obj, key, value) { + exports.replaceHookForTesting(obj, key); + obj[key] = value; + // Getters can only be overridden by getters. + if (obj[key] !== value) { + utils.defineGetter(obj, key, function() { + return value; + }); + } +} + +function assignOrWrapInDeprecateGetter(obj, key, value, message) { + if (message) { + utils.defineGetter(obj, key, function() { + console.log(message); + delete obj[key]; + clobber(obj, key, value); + return value; + }); + } else { + clobber(obj, key, value); + } +} + +function include(parent, objects, clobber, merge) { + each(objects, function (obj, key) { + try { + var result = obj.path ? require(obj.path) : {}; + + if (clobber) { + // Clobber if it doesn't exist. + if (typeof parent[key] === 'undefined') { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } else if (typeof obj.path !== 'undefined') { + // If merging, merge properties onto parent, otherwise, clobber. + if (merge) { + recursiveMerge(parent[key], result); + } else { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } + } + result = parent[key]; + } else { + // Overwrite if not currently defined. + if (typeof parent[key] == 'undefined') { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } else { + // Set result to what already exists, so we can build children into it if they exist. + result = parent[key]; + } + } + + if (obj.children) { + include(result, obj.children, clobber, merge); + } + } catch(e) { + utils.alert('Exception building cordova JS globals: ' + e + ' for key "' + key + '"'); + } + }); +} + +/** + * Merge properties from one object onto another recursively. Properties from + * the src object will overwrite existing target property. + * + * @param target Object to merge properties into. + * @param src Object to merge properties from. + */ +function recursiveMerge(target, src) { + for (var prop in src) { + if (src.hasOwnProperty(prop)) { + if (target.prototype && target.prototype.constructor === target) { + // If the target object is a constructor override off prototype. + clobber(target.prototype, prop, src[prop]); + } else { + if (typeof src[prop] === 'object' && typeof target[prop] === 'object') { + recursiveMerge(target[prop], src[prop]); + } else { + clobber(target, prop, src[prop]); + } + } + } + } +} + +exports.buildIntoButDoNotClobber = function(objects, target) { + include(target, objects, false, false); +}; +exports.buildIntoAndClobber = function(objects, target) { + include(target, objects, true, false); +}; +exports.buildIntoAndMerge = function(objects, target) { + include(target, objects, true, true); +}; +exports.recursiveMerge = recursiveMerge; +exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter; +exports.replaceHookForTesting = function() {}; + +}); + +// file: lib/common/channel.js +define("cordova/channel", function(require, exports, module) { + +var utils = require('cordova/utils'), + nextGuid = 1; + +/** + * Custom pub-sub "channel" that can have functions subscribed to it + * This object is used to define and control firing of events for + * cordova initialization, as well as for custom events thereafter. + * + * The order of events during page load and Cordova startup is as follows: + * + * onDOMContentLoaded* Internal event that is received when the web page is loaded and parsed. + * onNativeReady* Internal event that indicates the Cordova native side is ready. + * onCordovaReady* Internal event fired when all Cordova JavaScript objects have been created. + * onCordovaInfoReady* Internal event fired when device properties are available. + * onCordovaConnectionReady* Internal event fired when the connection property has been set. + * onDeviceReady* User event fired to indicate that Cordova is ready + * onResume User event fired to indicate a start/resume lifecycle event + * onPause User event fired to indicate a pause lifecycle event + * onDestroy* Internal event fired when app is being destroyed (User should use window.onunload event, not this one). + * + * The events marked with an * are sticky. Once they have fired, they will stay in the fired state. + * All listeners that subscribe after the event is fired will be executed right away. + * + * The only Cordova events that user code should register for are: + * deviceready Cordova native code is initialized and Cordova APIs can be called from JavaScript + * pause App has moved to background + * resume App has returned to foreground + * + * Listeners can be registered as: + * document.addEventListener("deviceready", myDeviceReadyListener, false); + * document.addEventListener("resume", myResumeListener, false); + * document.addEventListener("pause", myPauseListener, false); + * + * The DOM lifecycle events should be used for saving and restoring state + * window.onload + * window.onunload + * + */ + +/** + * Channel + * @constructor + * @param type String the channel name + */ +var Channel = function(type, sticky) { + this.type = type; + // Map of guid -> function. + this.handlers = {}; + // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired. + this.state = sticky ? 1 : 0; + // Used in sticky mode to remember args passed to fire(). + this.fireArgs = null; + // Used by onHasSubscribersChange to know if there are any listeners. + this.numHandlers = 0; + // Function that is called when the first listener is subscribed, or when + // the last listener is unsubscribed. + this.onHasSubscribersChange = null; +}, + channel = { + /** + * Calls the provided function only after all of the channels specified + * have been fired. All channels must be sticky channels. + */ + join: function(h, c) { + var len = c.length, + i = len, + f = function() { + if (!(--i)) h(); + }; + for (var j=0; jNative bridge. + POLLING: 0, + // For LOAD_URL to be viable, it would need to have a work-around for + // the bug where the soft-keyboard gets dismissed when a message is sent. + LOAD_URL: 1, + // For the ONLINE_EVENT to be viable, it would need to intercept all event + // listeners (both through addEventListener and window.ononline) as well + // as set the navigator property itself. + ONLINE_EVENT: 2, + // Uses reflection to access private APIs of the WebView that can send JS + // to be executed. + // Requires Android 3.2.4 or above. + PRIVATE_API: 3 + }, + jsToNativeBridgeMode, // Set lazily. + nativeToJsBridgeMode = nativeToJsModes.ONLINE_EVENT, + pollEnabled = false, + messagesFromNative = []; + +function androidExec(success, fail, service, action, args) { + // Set default bridge modes if they have not already been set. + // By default, we use the failsafe, since addJavascriptInterface breaks too often + if (jsToNativeBridgeMode === undefined) { + androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT); + } + + // Process any ArrayBuffers in the args into a string. + for (var i = 0; i < args.length; i++) { + if (utils.typeName(args[i]) == 'ArrayBuffer') { + args[i] = window.btoa(String.fromCharCode.apply(null, new Uint8Array(args[i]))); + } + } + + var callbackId = service + cordova.callbackId++, + argsJson = JSON.stringify(args); + + if (success || fail) { + cordova.callbacks[callbackId] = {success:success, fail:fail}; + } + + if (jsToNativeBridgeMode == jsToNativeModes.LOCATION_CHANGE) { + window.location = 'http://cdv_exec/' + service + '#' + action + '#' + callbackId + '#' + argsJson; + } else { + var messages = nativeApiProvider.get().exec(service, action, callbackId, argsJson); + // If argsJson was received by Java as null, try again with the PROMPT bridge mode. + // This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2. See CB-2666. + if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && messages === "@Null arguments.") { + androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT); + androidExec(success, fail, service, action, args); + androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT); + return; + } else { + androidExec.processMessages(messages); + } + } +} + +function pollOnce() { + var msg = nativeApiProvider.get().retrieveJsMessages(); + androidExec.processMessages(msg); +} + +function pollingTimerFunc() { + if (pollEnabled) { + pollOnce(); + setTimeout(pollingTimerFunc, 50); + } +} + +function hookOnlineApis() { + function proxyEvent(e) { + cordova.fireWindowEvent(e.type); + } + // The network module takes care of firing online and offline events. + // It currently fires them only on document though, so we bridge them + // to window here (while first listening for exec()-releated online/offline + // events). + window.addEventListener('online', pollOnce, false); + window.addEventListener('offline', pollOnce, false); + cordova.addWindowEventHandler('online'); + cordova.addWindowEventHandler('offline'); + document.addEventListener('online', proxyEvent, false); + document.addEventListener('offline', proxyEvent, false); +} + +hookOnlineApis(); + +androidExec.jsToNativeModes = jsToNativeModes; +androidExec.nativeToJsModes = nativeToJsModes; + +androidExec.setJsToNativeBridgeMode = function(mode) { + if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) { + console.log('Falling back on PROMPT mode since _cordovaNative is missing. Expected for Android 3.2 and lower only.'); + mode = jsToNativeModes.PROMPT; + } + nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT); + jsToNativeBridgeMode = mode; +}; + +androidExec.setNativeToJsBridgeMode = function(mode) { + if (mode == nativeToJsBridgeMode) { + return; + } + if (nativeToJsBridgeMode == nativeToJsModes.POLLING) { + pollEnabled = false; + } + + nativeToJsBridgeMode = mode; + // Tell the native side to switch modes. + nativeApiProvider.get().setNativeToJsBridgeMode(mode); + + if (mode == nativeToJsModes.POLLING) { + pollEnabled = true; + setTimeout(pollingTimerFunc, 1); + } +}; + +// Processes a single message, as encoded by NativeToJsMessageQueue.java. +function processMessage(message) { + try { + var firstChar = message.charAt(0); + if (firstChar == 'J') { + eval(message.slice(1)); + } else if (firstChar == 'S' || firstChar == 'F') { + var success = firstChar == 'S'; + var keepCallback = message.charAt(1) == '1'; + var spaceIdx = message.indexOf(' ', 2); + var status = +message.slice(2, spaceIdx); + var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1); + var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx); + var payloadKind = message.charAt(nextSpaceIdx + 1); + var payload; + if (payloadKind == 's') { + payload = message.slice(nextSpaceIdx + 2); + } else if (payloadKind == 't') { + payload = true; + } else if (payloadKind == 'f') { + payload = false; + } else if (payloadKind == 'N') { + payload = null; + } else if (payloadKind == 'n') { + payload = +message.slice(nextSpaceIdx + 2); + } else if (payloadKind == 'A') { + var data = message.slice(nextSpaceIdx + 2); + var bytes = window.atob(data); + var arraybuffer = new Uint8Array(bytes.length); + for (var i = 0; i < bytes.length; i++) { + arraybuffer[i] = bytes.charCodeAt(i); + } + payload = arraybuffer.buffer; + } else if (payloadKind == 'S') { + payload = window.atob(message.slice(nextSpaceIdx + 2)); + } else { + payload = JSON.parse(message.slice(nextSpaceIdx + 1)); + } + cordova.callbackFromNative(callbackId, success, status, [payload], keepCallback); + } else { + console.log("processMessage failed: invalid message:" + message); + } + } catch (e) { + console.log("processMessage failed: Message: " + message); + console.log("processMessage failed: Error: " + e); + console.log("processMessage failed: Stack: " + e.stack); + } +} + +// This is called from the NativeToJsMessageQueue.java. +androidExec.processMessages = function(messages) { + if (messages) { + messagesFromNative.push(messages); + // Check for the reentrant case, and enqueue the message if that's the case. + if (messagesFromNative.length > 1) { + return; + } + while (messagesFromNative.length) { + // Don't unshift until the end so that reentrancy can be detected. + messages = messagesFromNative[0]; + // The Java side can send a * message to indicate that it + // still has messages waiting to be retrieved. + if (messages == '*') { + messagesFromNative.shift(); + window.setTimeout(pollOnce, 0); + return; + } + + var spaceIdx = messages.indexOf(' '); + var msgLen = +messages.slice(0, spaceIdx); + var message = messages.substr(spaceIdx + 1, msgLen); + messages = messages.slice(spaceIdx + msgLen + 1); + processMessage(message); + if (messages) { + messagesFromNative[0] = messages; + } else { + messagesFromNative.shift(); + } + } + } +}; + +module.exports = androidExec; + +}); + +// file: lib/common/modulemapper.js +define("cordova/modulemapper", function(require, exports, module) { + +var builder = require('cordova/builder'), + moduleMap = define.moduleMap, + symbolList, + deprecationMap; + +exports.reset = function() { + symbolList = []; + deprecationMap = {}; +}; + +function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) { + if (!(moduleName in moduleMap)) { + throw new Error('Module ' + moduleName + ' does not exist.'); + } + symbolList.push(strategy, moduleName, symbolPath); + if (opt_deprecationMessage) { + deprecationMap[symbolPath] = opt_deprecationMessage; + } +} + +// Note: Android 2.3 does have Function.bind(). +exports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('c', moduleName, symbolPath, opt_deprecationMessage); +}; + +exports.merges = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('m', moduleName, symbolPath, opt_deprecationMessage); +}; + +exports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('d', moduleName, symbolPath, opt_deprecationMessage); +}; + +function prepareNamespace(symbolPath, context) { + if (!symbolPath) { + return context; + } + var parts = symbolPath.split('.'); + var cur = context; + for (var i = 0, part; part = parts[i]; ++i) { + cur = cur[part] = cur[part] || {}; + } + return cur; +} + +exports.mapModules = function(context) { + var origSymbols = {}; + context.CDV_origSymbols = origSymbols; + for (var i = 0, len = symbolList.length; i < len; i += 3) { + var strategy = symbolList[i]; + var moduleName = symbolList[i + 1]; + var symbolPath = symbolList[i + 2]; + var lastDot = symbolPath.lastIndexOf('.'); + var namespace = symbolPath.substr(0, lastDot); + var lastName = symbolPath.substr(lastDot + 1); + + var module = require(moduleName); + var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null; + var parentObj = prepareNamespace(namespace, context); + var target = parentObj[lastName]; + + if (strategy == 'm' && target) { + builder.recursiveMerge(target, module); + } else if ((strategy == 'd' && !target) || (strategy != 'd')) { + if (!(symbolPath in origSymbols)) { + origSymbols[symbolPath] = target; + } + builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg); + } + } +}; + +exports.getOriginalSymbol = function(context, symbolPath) { + var origSymbols = context.CDV_origSymbols; + if (origSymbols && (symbolPath in origSymbols)) { + return origSymbols[symbolPath]; + } + var parts = symbolPath.split('.'); + var obj = context; + for (var i = 0; i < parts.length; ++i) { + obj = obj && obj[parts[i]]; + } + return obj; +}; + +exports.loadMatchingModules = function(matchingRegExp) { + for (var k in moduleMap) { + if (matchingRegExp.exec(k)) { + require(k); + } + } +}; + +exports.reset(); + + +}); + +// file: lib/android/platform.js +define("cordova/platform", function(require, exports, module) { + +module.exports = { + id: "android", + initialize:function() { + var channel = require("cordova/channel"), + cordova = require('cordova'), + exec = require('cordova/exec'), + modulemapper = require('cordova/modulemapper'); + + modulemapper.loadMatchingModules(/cordova.*\/symbols$/); + modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app'); + + modulemapper.mapModules(window); + + // Inject a listener for the backbutton on the document. + var backButtonChannel = cordova.addDocumentEventHandler('backbutton'); + backButtonChannel.onHasSubscribersChange = function() { + // If we just attached the first handler or detached the last handler, + // let native know we need to override the back button. + exec(null, null, "App", "overrideBackbutton", [this.numHandlers == 1]); + }; + + // Add hardware MENU and SEARCH button handlers + cordova.addDocumentEventHandler('menubutton'); + cordova.addDocumentEventHandler('searchbutton'); + + // Let native code know we are all done on the JS side. + // Native code will then un-hide the WebView. + channel.join(function() { + exec(null, null, "App", "show", []); + }, [channel.onCordovaReady]); + } +}; + +}); + +// file: lib/common/plugin/Acceleration.js +define("cordova/plugin/Acceleration", function(require, exports, module) { + +var Acceleration = function(x, y, z, timestamp) { + this.x = x; + this.y = y; + this.z = z; + this.timestamp = timestamp || (new Date()).getTime(); +}; + +module.exports = Acceleration; + +}); + +// file: lib/common/plugin/Camera.js +define("cordova/plugin/Camera", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), + Camera = require('cordova/plugin/CameraConstants'), + CameraPopoverHandle = require('cordova/plugin/CameraPopoverHandle'); + +var cameraExport = {}; + +// Tack on the Camera Constants to the base camera plugin. +for (var key in Camera) { + cameraExport[key] = Camera[key]; +} + +/** + * Gets a picture from source defined by "options.sourceType", and returns the + * image as defined by the "options.destinationType" option. + + * The defaults are sourceType=CAMERA and destinationType=FILE_URI. + * + * @param {Function} successCallback + * @param {Function} errorCallback + * @param {Object} options + */ +cameraExport.getPicture = function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'Camera.getPicture', arguments); + options = options || {}; + var getValue = argscheck.getValue; + + var quality = getValue(options.quality, 50); + var destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI); + var sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA); + var targetWidth = getValue(options.targetWidth, -1); + var targetHeight = getValue(options.targetHeight, -1); + var encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG); + var mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE); + var allowEdit = !!options.allowEdit; + var correctOrientation = !!options.correctOrientation; + var saveToPhotoAlbum = !!options.saveToPhotoAlbum; + var popoverOptions = getValue(options.popoverOptions, null); + var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK); + + var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType, + mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection]; + + exec(successCallback, errorCallback, "Camera", "takePicture", args); + return new CameraPopoverHandle(); +}; + +cameraExport.cleanup = function(successCallback, errorCallback) { + exec(successCallback, errorCallback, "Camera", "cleanup", []); +}; + +module.exports = cameraExport; + +}); + +// file: lib/common/plugin/CameraConstants.js +define("cordova/plugin/CameraConstants", function(require, exports, module) { + +module.exports = { + DestinationType:{ + DATA_URL: 0, // Return base64 encoded string + FILE_URI: 1, // Return file uri (content://media/external/images/media/2 for Android) + NATIVE_URI: 2 // Return native uri (eg. asset-library://... for iOS) + }, + EncodingType:{ + JPEG: 0, // Return JPEG encoded image + PNG: 1 // Return PNG encoded image + }, + MediaType:{ + PICTURE: 0, // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType + VIDEO: 1, // allow selection of video only, ONLY RETURNS URL + ALLMEDIA : 2 // allow selection from all media types + }, + PictureSourceType:{ + PHOTOLIBRARY : 0, // Choose image from picture library (same as SAVEDPHOTOALBUM for Android) + CAMERA : 1, // Take picture from camera + SAVEDPHOTOALBUM : 2 // Choose image from picture library (same as PHOTOLIBRARY for Android) + }, + PopoverArrowDirection:{ + ARROW_UP : 1, // matches iOS UIPopoverArrowDirection constants to specify arrow location on popover + ARROW_DOWN : 2, + ARROW_LEFT : 4, + ARROW_RIGHT : 8, + ARROW_ANY : 15 + }, + Direction:{ + BACK: 0, + FRONT: 1 + } +}; + +}); + +// file: lib/common/plugin/CameraPopoverHandle.js +define("cordova/plugin/CameraPopoverHandle", function(require, exports, module) { + +var exec = require('cordova/exec'); + +/** + * A handle to an image picker popover. + */ +var CameraPopoverHandle = function() { + this.setPosition = function(popoverOptions) { + console.log('CameraPopoverHandle.setPosition is only supported on iOS.'); + }; +}; + +module.exports = CameraPopoverHandle; + +}); + +// file: lib/common/plugin/CameraPopoverOptions.js +define("cordova/plugin/CameraPopoverOptions", function(require, exports, module) { + +var Camera = require('cordova/plugin/CameraConstants'); + +/** + * Encapsulates options for iOS Popover image picker + */ +var CameraPopoverOptions = function(x,y,width,height,arrowDir){ + // information of rectangle that popover should be anchored to + this.x = x || 0; + this.y = y || 32; + this.width = width || 320; + this.height = height || 480; + // The direction of the popover arrow + this.arrowDir = arrowDir || Camera.PopoverArrowDirection.ARROW_ANY; +}; + +module.exports = CameraPopoverOptions; + +}); + +// file: lib/common/plugin/CaptureAudioOptions.js +define("cordova/plugin/CaptureAudioOptions", function(require, exports, module) { + +/** + * Encapsulates all audio capture operation configuration options. + */ +var CaptureAudioOptions = function(){ + // Upper limit of sound clips user can record. Value must be equal or greater than 1. + this.limit = 1; + // Maximum duration of a single sound clip in seconds. + this.duration = 0; +}; + +module.exports = CaptureAudioOptions; + +}); + +// file: lib/common/plugin/CaptureError.js +define("cordova/plugin/CaptureError", function(require, exports, module) { + +/** + * The CaptureError interface encapsulates all errors in the Capture API. + */ +var CaptureError = function(c) { + this.code = c || null; +}; + +// Camera or microphone failed to capture image or sound. +CaptureError.CAPTURE_INTERNAL_ERR = 0; +// Camera application or audio capture application is currently serving other capture request. +CaptureError.CAPTURE_APPLICATION_BUSY = 1; +// Invalid use of the API (e.g. limit parameter has value less than one). +CaptureError.CAPTURE_INVALID_ARGUMENT = 2; +// User exited camera application or audio capture application before capturing anything. +CaptureError.CAPTURE_NO_MEDIA_FILES = 3; +// The requested capture operation is not supported. +CaptureError.CAPTURE_NOT_SUPPORTED = 20; + +module.exports = CaptureError; + +}); + +// file: lib/common/plugin/CaptureImageOptions.js +define("cordova/plugin/CaptureImageOptions", function(require, exports, module) { + +/** + * Encapsulates all image capture operation configuration options. + */ +var CaptureImageOptions = function(){ + // Upper limit of images user can take. Value must be equal or greater than 1. + this.limit = 1; +}; + +module.exports = CaptureImageOptions; + +}); + +// file: lib/common/plugin/CaptureVideoOptions.js +define("cordova/plugin/CaptureVideoOptions", function(require, exports, module) { + +/** + * Encapsulates all video capture operation configuration options. + */ +var CaptureVideoOptions = function(){ + // Upper limit of videos user can record. Value must be equal or greater than 1. + this.limit = 1; + // Maximum duration of a single video clip in seconds. + this.duration = 0; +}; + +module.exports = CaptureVideoOptions; + +}); + +// file: lib/common/plugin/CompassError.js +define("cordova/plugin/CompassError", function(require, exports, module) { + +/** + * CompassError. + * An error code assigned by an implementation when an error has occurred + * @constructor + */ +var CompassError = function(err) { + this.code = (err !== undefined ? err : null); +}; + +CompassError.COMPASS_INTERNAL_ERR = 0; +CompassError.COMPASS_NOT_SUPPORTED = 20; + +module.exports = CompassError; + +}); + +// file: lib/common/plugin/CompassHeading.js +define("cordova/plugin/CompassHeading", function(require, exports, module) { + +var CompassHeading = function(magneticHeading, trueHeading, headingAccuracy, timestamp) { + this.magneticHeading = magneticHeading; + this.trueHeading = trueHeading; + this.headingAccuracy = headingAccuracy; + this.timestamp = timestamp || new Date().getTime(); +}; + +module.exports = CompassHeading; + +}); + +// file: lib/common/plugin/ConfigurationData.js +define("cordova/plugin/ConfigurationData", function(require, exports, module) { + +/** + * Encapsulates a set of parameters that the capture device supports. + */ +function ConfigurationData() { + // The ASCII-encoded string in lower case representing the media type. + this.type = null; + // The height attribute represents height of the image or video in pixels. + // In the case of a sound clip this attribute has value 0. + this.height = 0; + // The width attribute represents width of the image or video in pixels. + // In the case of a sound clip this attribute has value 0 + this.width = 0; +} + +module.exports = ConfigurationData; + +}); + +// file: lib/common/plugin/Connection.js +define("cordova/plugin/Connection", function(require, exports, module) { + +/** + * Network status + */ +module.exports = { + UNKNOWN: "unknown", + ETHERNET: "ethernet", + WIFI: "wifi", + CELL_2G: "2g", + CELL_3G: "3g", + CELL_4G: "4g", + CELL:"cellular", + NONE: "none" +}; + +}); + +// file: lib/common/plugin/Contact.js +define("cordova/plugin/Contact", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), + ContactError = require('cordova/plugin/ContactError'), + utils = require('cordova/utils'); + +/** +* Converts primitives into Complex Object +* Currently only used for Date fields +*/ +function convertIn(contact) { + var value = contact.birthday; + try { + contact.birthday = new Date(parseFloat(value)); + } catch (exception){ + console.log("Cordova Contact convertIn error: exception creating date."); + } + return contact; +} + +/** +* Converts Complex objects into primitives +* Only conversion at present is for Dates. +**/ + +function convertOut(contact) { + var value = contact.birthday; + if (value !== null) { + // try to make it a Date object if it is not already + if (!utils.isDate(value)){ + try { + value = new Date(value); + } catch(exception){ + value = null; + } + } + if (utils.isDate(value)){ + value = value.valueOf(); // convert to milliseconds + } + contact.birthday = value; + } + return contact; +} + +/** +* Contains information about a single contact. +* @constructor +* @param {DOMString} id unique identifier +* @param {DOMString} displayName +* @param {ContactName} name +* @param {DOMString} nickname +* @param {Array.} phoneNumbers array of phone numbers +* @param {Array.} emails array of email addresses +* @param {Array.} addresses array of addresses +* @param {Array.} ims instant messaging user ids +* @param {Array.} organizations +* @param {DOMString} birthday contact's birthday +* @param {DOMString} note user notes about contact +* @param {Array.} photos +* @param {Array.} categories +* @param {Array.} urls contact's web sites +*/ +var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, addresses, + ims, organizations, birthday, note, photos, categories, urls) { + this.id = id || null; + this.rawId = null; + this.displayName = displayName || null; + this.name = name || null; // ContactName + this.nickname = nickname || null; + this.phoneNumbers = phoneNumbers || null; // ContactField[] + this.emails = emails || null; // ContactField[] + this.addresses = addresses || null; // ContactAddress[] + this.ims = ims || null; // ContactField[] + this.organizations = organizations || null; // ContactOrganization[] + this.birthday = birthday || null; + this.note = note || null; + this.photos = photos || null; // ContactField[] + this.categories = categories || null; // ContactField[] + this.urls = urls || null; // ContactField[] +}; + +/** +* Removes contact from device storage. +* @param successCB success callback +* @param errorCB error callback +*/ +Contact.prototype.remove = function(successCB, errorCB) { + argscheck.checkArgs('FF', 'Contact.remove', arguments); + var fail = errorCB && function(code) { + errorCB(new ContactError(code)); + }; + if (this.id === null) { + fail(ContactError.UNKNOWN_ERROR); + } + else { + exec(successCB, fail, "Contacts", "remove", [this.id]); + } +}; + +/** +* Creates a deep copy of this Contact. +* With the contact ID set to null. +* @return copy of this Contact +*/ +Contact.prototype.clone = function() { + var clonedContact = utils.clone(this); + clonedContact.id = null; + clonedContact.rawId = null; + + function nullIds(arr) { + if (arr) { + for (var i = 0; i < arr.length; ++i) { + arr[i].id = null; + } + } + } + + // Loop through and clear out any id's in phones, emails, etc. + nullIds(clonedContact.phoneNumbers); + nullIds(clonedContact.emails); + nullIds(clonedContact.addresses); + nullIds(clonedContact.ims); + nullIds(clonedContact.organizations); + nullIds(clonedContact.categories); + nullIds(clonedContact.photos); + nullIds(clonedContact.urls); + return clonedContact; +}; + +/** +* Persists contact to device storage. +* @param successCB success callback +* @param errorCB error callback +*/ +Contact.prototype.save = function(successCB, errorCB) { + argscheck.checkArgs('FFO', 'Contact.save', arguments); + var fail = errorCB && function(code) { + errorCB(new ContactError(code)); + }; + var success = function(result) { + if (result) { + if (successCB) { + var fullContact = require('cordova/plugin/contacts').create(result); + successCB(convertIn(fullContact)); + } + } + else { + // no Entry object returned + fail(ContactError.UNKNOWN_ERROR); + } + }; + var dupContact = convertOut(utils.clone(this)); + exec(success, fail, "Contacts", "save", [dupContact]); +}; + + +module.exports = Contact; + +}); + +// file: lib/common/plugin/ContactAddress.js +define("cordova/plugin/ContactAddress", function(require, exports, module) { + +/** +* Contact address. +* @constructor +* @param {DOMString} id unique identifier, should only be set by native code +* @param formatted // NOTE: not a W3C standard +* @param streetAddress +* @param locality +* @param region +* @param postalCode +* @param country +*/ + +var ContactAddress = function(pref, type, formatted, streetAddress, locality, region, postalCode, country) { + this.id = null; + this.pref = (typeof pref != 'undefined' ? pref : false); + this.type = type || null; + this.formatted = formatted || null; + this.streetAddress = streetAddress || null; + this.locality = locality || null; + this.region = region || null; + this.postalCode = postalCode || null; + this.country = country || null; +}; + +module.exports = ContactAddress; + +}); + +// file: lib/common/plugin/ContactError.js +define("cordova/plugin/ContactError", function(require, exports, module) { + +/** + * ContactError. + * An error code assigned by an implementation when an error has occurred + * @constructor + */ +var ContactError = function(err) { + this.code = (typeof err != 'undefined' ? err : null); +}; + +/** + * Error codes + */ +ContactError.UNKNOWN_ERROR = 0; +ContactError.INVALID_ARGUMENT_ERROR = 1; +ContactError.TIMEOUT_ERROR = 2; +ContactError.PENDING_OPERATION_ERROR = 3; +ContactError.IO_ERROR = 4; +ContactError.NOT_SUPPORTED_ERROR = 5; +ContactError.PERMISSION_DENIED_ERROR = 20; + +module.exports = ContactError; + +}); + +// file: lib/common/plugin/ContactField.js +define("cordova/plugin/ContactField", function(require, exports, module) { + +/** +* Generic contact field. +* @constructor +* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard +* @param type +* @param value +* @param pref +*/ +var ContactField = function(type, value, pref) { + this.id = null; + this.type = (type && type.toString()) || null; + this.value = (value && value.toString()) || null; + this.pref = (typeof pref != 'undefined' ? pref : false); +}; + +module.exports = ContactField; + +}); + +// file: lib/common/plugin/ContactFindOptions.js +define("cordova/plugin/ContactFindOptions", function(require, exports, module) { + +/** + * ContactFindOptions. + * @constructor + * @param filter used to match contacts against + * @param multiple boolean used to determine if more than one contact should be returned + */ + +var ContactFindOptions = function(filter, multiple) { + this.filter = filter || ''; + this.multiple = (typeof multiple != 'undefined' ? multiple : false); +}; + +module.exports = ContactFindOptions; + +}); + +// file: lib/common/plugin/ContactName.js +define("cordova/plugin/ContactName", function(require, exports, module) { + +/** +* Contact name. +* @constructor +* @param formatted // NOTE: not part of W3C standard +* @param familyName +* @param givenName +* @param middle +* @param prefix +* @param suffix +*/ +var ContactName = function(formatted, familyName, givenName, middle, prefix, suffix) { + this.formatted = formatted || null; + this.familyName = familyName || null; + this.givenName = givenName || null; + this.middleName = middle || null; + this.honorificPrefix = prefix || null; + this.honorificSuffix = suffix || null; +}; + +module.exports = ContactName; + +}); + +// file: lib/common/plugin/ContactOrganization.js +define("cordova/plugin/ContactOrganization", function(require, exports, module) { + +/** +* Contact organization. +* @constructor +* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard +* @param name +* @param dept +* @param title +* @param startDate +* @param endDate +* @param location +* @param desc +*/ + +var ContactOrganization = function(pref, type, name, dept, title) { + this.id = null; + this.pref = (typeof pref != 'undefined' ? pref : false); + this.type = type || null; + this.name = name || null; + this.department = dept || null; + this.title = title || null; +}; + +module.exports = ContactOrganization; + +}); + +// file: lib/common/plugin/Coordinates.js +define("cordova/plugin/Coordinates", function(require, exports, module) { + +/** + * This class contains position information. + * @param {Object} lat + * @param {Object} lng + * @param {Object} alt + * @param {Object} acc + * @param {Object} head + * @param {Object} vel + * @param {Object} altacc + * @constructor + */ +var Coordinates = function(lat, lng, alt, acc, head, vel, altacc) { + /** + * The latitude of the position. + */ + this.latitude = lat; + /** + * The longitude of the position, + */ + this.longitude = lng; + /** + * The accuracy of the position. + */ + this.accuracy = acc; + /** + * The altitude of the position. + */ + this.altitude = (alt !== undefined ? alt : null); + /** + * The direction the device is moving at the position. + */ + this.heading = (head !== undefined ? head : null); + /** + * The velocity with which the device is moving at the position. + */ + this.speed = (vel !== undefined ? vel : null); + + if (this.speed === 0 || this.speed === null) { + this.heading = NaN; + } + + /** + * The altitude accuracy of the position. + */ + this.altitudeAccuracy = (altacc !== undefined) ? altacc : null; +}; + +module.exports = Coordinates; + +}); + +// file: lib/common/plugin/DirectoryEntry.js +define("cordova/plugin/DirectoryEntry", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + utils = require('cordova/utils'), + exec = require('cordova/exec'), + Entry = require('cordova/plugin/Entry'), + FileError = require('cordova/plugin/FileError'), + DirectoryReader = require('cordova/plugin/DirectoryReader'); + +/** + * An interface representing a directory on the file system. + * + * {boolean} isFile always false (readonly) + * {boolean} isDirectory always true (readonly) + * {DOMString} name of the directory, excluding the path leading to it (readonly) + * {DOMString} fullPath the absolute full path to the directory (readonly) + * TODO: implement this!!! {FileSystem} filesystem on which the directory resides (readonly) + */ +var DirectoryEntry = function(name, fullPath) { + DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath); +}; + +utils.extend(DirectoryEntry, Entry); + +/** + * Creates a new DirectoryReader to read entries from this directory + */ +DirectoryEntry.prototype.createReader = function() { + return new DirectoryReader(this.fullPath); +}; + +/** + * Creates or looks up a directory + * + * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a directory + * @param {Flags} options to create or exclusively create the directory + * @param {Function} successCallback is called with the new entry + * @param {Function} errorCallback is called with a FileError + */ +DirectoryEntry.prototype.getDirectory = function(path, options, successCallback, errorCallback) { + argscheck.checkArgs('sOFF', 'DirectoryEntry.getDirectory', arguments); + var win = successCallback && function(result) { + var entry = new DirectoryEntry(result.name, result.fullPath); + successCallback(entry); + }; + var fail = errorCallback && function(code) { + errorCallback(new FileError(code)); + }; + exec(win, fail, "File", "getDirectory", [this.fullPath, path, options]); +}; + +/** + * Deletes a directory and all of it's contents + * + * @param {Function} successCallback is called with no parameters + * @param {Function} errorCallback is called with a FileError + */ +DirectoryEntry.prototype.removeRecursively = function(successCallback, errorCallback) { + argscheck.checkArgs('FF', 'DirectoryEntry.removeRecursively', arguments); + var fail = errorCallback && function(code) { + errorCallback(new FileError(code)); + }; + exec(successCallback, fail, "File", "removeRecursively", [this.fullPath]); +}; + +/** + * Creates or looks up a file + * + * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a file + * @param {Flags} options to create or exclusively create the file + * @param {Function} successCallback is called with the new entry + * @param {Function} errorCallback is called with a FileError + */ +DirectoryEntry.prototype.getFile = function(path, options, successCallback, errorCallback) { + argscheck.checkArgs('sOFF', 'DirectoryEntry.getFile', arguments); + var win = successCallback && function(result) { + var FileEntry = require('cordova/plugin/FileEntry'); + var entry = new FileEntry(result.name, result.fullPath); + successCallback(entry); + }; + var fail = errorCallback && function(code) { + errorCallback(new FileError(code)); + }; + exec(win, fail, "File", "getFile", [this.fullPath, path, options]); +}; + +module.exports = DirectoryEntry; + +}); + +// file: lib/common/plugin/DirectoryReader.js +define("cordova/plugin/DirectoryReader", function(require, exports, module) { + +var exec = require('cordova/exec'), + FileError = require('cordova/plugin/FileError') ; + +/** + * An interface that lists the files and directories in a directory. + */ +function DirectoryReader(path) { + this.path = path || null; +} + +/** + * Returns a list of entries from a directory. + * + * @param {Function} successCallback is called with a list of entries + * @param {Function} errorCallback is called with a FileError + */ +DirectoryReader.prototype.readEntries = function(successCallback, errorCallback) { + var win = typeof successCallback !== 'function' ? null : function(result) { + var retVal = []; + for (var i=0; i= 2) { + if (end < 0) { + newEnd = Math.max(size + end, 0); + } else { + newEnd = Math.min(end, size); + } + } + + var newFile = new File(this.name, this.fullPath, this.type, this.lastModifiedData, this.size); + newFile.start = this.start + newStart; + newFile.end = this.start + newEnd; + return newFile; +}; + + +module.exports = File; + +}); + +// file: lib/common/plugin/FileEntry.js +define("cordova/plugin/FileEntry", function(require, exports, module) { + +var utils = require('cordova/utils'), + exec = require('cordova/exec'), + Entry = require('cordova/plugin/Entry'), + FileWriter = require('cordova/plugin/FileWriter'), + File = require('cordova/plugin/File'), + FileError = require('cordova/plugin/FileError'); + +/** + * An interface representing a file on the file system. + * + * {boolean} isFile always true (readonly) + * {boolean} isDirectory always false (readonly) + * {DOMString} name of the file, excluding the path leading to it (readonly) + * {DOMString} fullPath the absolute full path to the file (readonly) + * {FileSystem} filesystem on which the file resides (readonly) + */ +var FileEntry = function(name, fullPath) { + FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath]); +}; + +utils.extend(FileEntry, Entry); + +/** + * Creates a new FileWriter associated with the file that this FileEntry represents. + * + * @param {Function} successCallback is called with the new FileWriter + * @param {Function} errorCallback is called with a FileError + */ +FileEntry.prototype.createWriter = function(successCallback, errorCallback) { + this.file(function(filePointer) { + var writer = new FileWriter(filePointer); + + if (writer.fileName === null || writer.fileName === "") { + errorCallback && errorCallback(new FileError(FileError.INVALID_STATE_ERR)); + } else { + successCallback && successCallback(writer); + } + }, errorCallback); +}; + +/** + * Returns a File that represents the current state of the file that this FileEntry represents. + * + * @param {Function} successCallback is called with the new File object + * @param {Function} errorCallback is called with a FileError + */ +FileEntry.prototype.file = function(successCallback, errorCallback) { + var win = successCallback && function(f) { + var file = new File(f.name, f.fullPath, f.type, f.lastModifiedDate, f.size); + successCallback(file); + }; + var fail = errorCallback && function(code) { + errorCallback(new FileError(code)); + }; + exec(win, fail, "File", "getFileMetadata", [this.fullPath]); +}; + + +module.exports = FileEntry; + +}); + +// file: lib/common/plugin/FileError.js +define("cordova/plugin/FileError", function(require, exports, module) { + +/** + * FileError + */ +function FileError(error) { + this.code = error || null; +} + +// File error codes +// Found in DOMException +FileError.NOT_FOUND_ERR = 1; +FileError.SECURITY_ERR = 2; +FileError.ABORT_ERR = 3; + +// Added by File API specification +FileError.NOT_READABLE_ERR = 4; +FileError.ENCODING_ERR = 5; +FileError.NO_MODIFICATION_ALLOWED_ERR = 6; +FileError.INVALID_STATE_ERR = 7; +FileError.SYNTAX_ERR = 8; +FileError.INVALID_MODIFICATION_ERR = 9; +FileError.QUOTA_EXCEEDED_ERR = 10; +FileError.TYPE_MISMATCH_ERR = 11; +FileError.PATH_EXISTS_ERR = 12; + +module.exports = FileError; + +}); + +// file: lib/common/plugin/FileReader.js +define("cordova/plugin/FileReader", function(require, exports, module) { + +var exec = require('cordova/exec'), + modulemapper = require('cordova/modulemapper'), + utils = require('cordova/utils'), + File = require('cordova/plugin/File'), + FileError = require('cordova/plugin/FileError'), + ProgressEvent = require('cordova/plugin/ProgressEvent'), + origFileReader = modulemapper.getOriginalSymbol(this, 'FileReader'); + +/** + * This class reads the mobile device file system. + * + * For Android: + * The root directory is the root of the file system. + * To read from the SD card, the file name is "sdcard/my_file.txt" + * @constructor + */ +var FileReader = function() { + this._readyState = 0; + this._error = null; + this._result = null; + this._fileName = ''; + this._realReader = origFileReader ? new origFileReader() : {}; +}; + +// States +FileReader.EMPTY = 0; +FileReader.LOADING = 1; +FileReader.DONE = 2; + +utils.defineGetter(FileReader.prototype, 'readyState', function() { + return this._fileName ? this._readyState : this._realReader.readyState; +}); + +utils.defineGetter(FileReader.prototype, 'error', function() { + return this._fileName ? this._error: this._realReader.error; +}); + +utils.defineGetter(FileReader.prototype, 'result', function() { + return this._fileName ? this._result: this._realReader.result; +}); + +function defineEvent(eventName) { + utils.defineGetterSetter(FileReader.prototype, eventName, function() { + return this._realReader[eventName] || null; + }, function(value) { + this._realReader[eventName] = value; + }); +} +defineEvent('onloadstart'); // When the read starts. +defineEvent('onprogress'); // While reading (and decoding) file or fileBlob data, and reporting partial file data (progress.loaded/progress.total) +defineEvent('onload'); // When the read has successfully completed. +defineEvent('onerror'); // When the read has failed (see errors). +defineEvent('onloadend'); // When the request has completed (either in success or failure). +defineEvent('onabort'); // When the read has been aborted. For instance, by invoking the abort() method. + +function initRead(reader, file) { + // Already loading something + if (reader.readyState == FileReader.LOADING) { + throw new FileError(FileError.INVALID_STATE_ERR); + } + + reader._result = null; + reader._error = null; + reader._readyState = FileReader.LOADING; + + if (typeof file.fullPath == 'string') { + reader._fileName = file.fullPath; + } else { + reader._fileName = ''; + return true; + } + + reader.onloadstart && reader.onloadstart(new ProgressEvent("loadstart", {target:reader})); +} + +/** + * Abort reading file. + */ +FileReader.prototype.abort = function() { + if (origFileReader && !this._fileName) { + return this._realReader.abort(); + } + this._result = null; + + if (this._readyState == FileReader.DONE || this._readyState == FileReader.EMPTY) { + return; + } + + this._readyState = FileReader.DONE; + + // If abort callback + if (typeof this.onabort === 'function') { + this.onabort(new ProgressEvent('abort', {target:this})); + } + // If load end callback + if (typeof this.onloadend === 'function') { + this.onloadend(new ProgressEvent('loadend', {target:this})); + } +}; + +/** + * Read text file. + * + * @param file {File} File object containing file properties + * @param encoding [Optional] (see http://www.iana.org/assignments/character-sets) + */ +FileReader.prototype.readAsText = function(file, encoding) { + if (initRead(this, file)) { + return this._realReader.readAsText(file, encoding); + } + + // Default encoding is UTF-8 + var enc = encoding ? encoding : "UTF-8"; + var me = this; + var execArgs = [this._fileName, enc, file.start, file.end]; + + // Read file + exec( + // Success callback + function(r) { + // If DONE (cancelled), then don't do anything + if (me._readyState === FileReader.DONE) { + return; + } + + // Save result + me._result = r; + + // If onload callback + if (typeof me.onload === "function") { + me.onload(new ProgressEvent("load", {target:me})); + } + + // DONE state + me._readyState = FileReader.DONE; + + // If onloadend callback + if (typeof me.onloadend === "function") { + me.onloadend(new ProgressEvent("loadend", {target:me})); + } + }, + // Error callback + function(e) { + // If DONE (cancelled), then don't do anything + if (me._readyState === FileReader.DONE) { + return; + } + + // DONE state + me._readyState = FileReader.DONE; + + // null result + me._result = null; + + // Save error + me._error = new FileError(e); + + // If onerror callback + if (typeof me.onerror === "function") { + me.onerror(new ProgressEvent("error", {target:me})); + } + + // If onloadend callback + if (typeof me.onloadend === "function") { + me.onloadend(new ProgressEvent("loadend", {target:me})); + } + }, "File", "readAsText", execArgs); +}; + + +/** + * Read file and return data as a base64 encoded data url. + * A data url is of the form: + * data:[][;base64], + * + * @param file {File} File object containing file properties + */ +FileReader.prototype.readAsDataURL = function(file) { + if (initRead(this, file)) { + return this._realReader.readAsDataURL(file); + } + + var me = this; + var execArgs = [this._fileName, file.start, file.end]; + + // Read file + exec( + // Success callback + function(r) { + // If DONE (cancelled), then don't do anything + if (me._readyState === FileReader.DONE) { + return; + } + + // DONE state + me._readyState = FileReader.DONE; + + // Save result + me._result = r; + + // If onload callback + if (typeof me.onload === "function") { + me.onload(new ProgressEvent("load", {target:me})); + } + + // If onloadend callback + if (typeof me.onloadend === "function") { + me.onloadend(new ProgressEvent("loadend", {target:me})); + } + }, + // Error callback + function(e) { + // If DONE (cancelled), then don't do anything + if (me._readyState === FileReader.DONE) { + return; + } + + // DONE state + me._readyState = FileReader.DONE; + + me._result = null; + + // Save error + me._error = new FileError(e); + + // If onerror callback + if (typeof me.onerror === "function") { + me.onerror(new ProgressEvent("error", {target:me})); + } + + // If onloadend callback + if (typeof me.onloadend === "function") { + me.onloadend(new ProgressEvent("loadend", {target:me})); + } + }, "File", "readAsDataURL", execArgs); +}; + +/** + * Read file and return data as a binary data. + * + * @param file {File} File object containing file properties + */ +FileReader.prototype.readAsBinaryString = function(file) { + if (initRead(this, file)) { + return this._realReader.readAsBinaryString(file); + } + + var me = this; + var execArgs = [this._fileName, file.start, file.end]; + + // Read file + exec( + // Success callback + function(r) { + // If DONE (cancelled), then don't do anything + if (me._readyState === FileReader.DONE) { + return; + } + + // DONE state + me._readyState = FileReader.DONE; + + me._result = r; + + // If onload callback + if (typeof me.onload === "function") { + me.onload(new ProgressEvent("load", {target:me})); + } + + // If onloadend callback + if (typeof me.onloadend === "function") { + me.onloadend(new ProgressEvent("loadend", {target:me})); + } + }, + // Error callback + function(e) { + // If DONE (cancelled), then don't do anything + if (me._readyState === FileReader.DONE) { + return; + } + + // DONE state + me._readyState = FileReader.DONE; + + me._result = null; + + // Save error + me._error = new FileError(e); + + // If onerror callback + if (typeof me.onerror === "function") { + me.onerror(new ProgressEvent("error", {target:me})); + } + + // If onloadend callback + if (typeof me.onloadend === "function") { + me.onloadend(new ProgressEvent("loadend", {target:me})); + } + }, "File", "readAsBinaryString", execArgs); +}; + +/** + * Read file and return data as a binary data. + * + * @param file {File} File object containing file properties + */ +FileReader.prototype.readAsArrayBuffer = function(file) { + if (initRead(this, file)) { + return this._realReader.readAsArrayBuffer(file); + } + + var me = this; + var execArgs = [this._fileName, file.start, file.end]; + + // Read file + exec( + // Success callback + function(r) { + // If DONE (cancelled), then don't do anything + if (me._readyState === FileReader.DONE) { + return; + } + + // DONE state + me._readyState = FileReader.DONE; + + me._result = r; + + // If onload callback + if (typeof me.onload === "function") { + me.onload(new ProgressEvent("load", {target:me})); + } + + // If onloadend callback + if (typeof me.onloadend === "function") { + me.onloadend(new ProgressEvent("loadend", {target:me})); + } + }, + // Error callback + function(e) { + // If DONE (cancelled), then don't do anything + if (me._readyState === FileReader.DONE) { + return; + } + + // DONE state + me._readyState = FileReader.DONE; + + me._result = null; + + // Save error + me._error = new FileError(e); + + // If onerror callback + if (typeof me.onerror === "function") { + me.onerror(new ProgressEvent("error", {target:me})); + } + + // If onloadend callback + if (typeof me.onloadend === "function") { + me.onloadend(new ProgressEvent("loadend", {target:me})); + } + }, "File", "readAsArrayBuffer", execArgs); +}; + +module.exports = FileReader; + +}); + +// file: lib/common/plugin/FileSystem.js +define("cordova/plugin/FileSystem", function(require, exports, module) { + +var DirectoryEntry = require('cordova/plugin/DirectoryEntry'); + +/** + * An interface representing a file system + * + * @constructor + * {DOMString} name the unique name of the file system (readonly) + * {DirectoryEntry} root directory of the file system (readonly) + */ +var FileSystem = function(name, root) { + this.name = name || null; + if (root) { + this.root = new DirectoryEntry(root.name, root.fullPath); + } +}; + +module.exports = FileSystem; + +}); + +// file: lib/common/plugin/FileTransfer.js +define("cordova/plugin/FileTransfer", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), + FileTransferError = require('cordova/plugin/FileTransferError'), + ProgressEvent = require('cordova/plugin/ProgressEvent'); + +function newProgressEvent(result) { + var pe = new ProgressEvent(); + pe.lengthComputable = result.lengthComputable; + pe.loaded = result.loaded; + pe.total = result.total; + return pe; +} + +function getBasicAuthHeader(urlString) { + var header = null; + + if (window.btoa) { + // parse the url using the Location object + var url = document.createElement('a'); + url.href = urlString; + + var credentials = null; + var protocol = url.protocol + "//"; + var origin = protocol + url.host; + + // check whether there are the username:password credentials in the url + if (url.href.indexOf(origin) !== 0) { // credentials found + var atIndex = url.href.indexOf("@"); + credentials = url.href.substring(protocol.length, atIndex); + } + + if (credentials) { + var authHeader = "Authorization"; + var authHeaderValue = "Basic " + window.btoa(credentials); + + header = { + name : authHeader, + value : authHeaderValue + }; + } + } + + return header; +} + +var idCounter = 0; + +/** + * FileTransfer uploads a file to a remote server. + * @constructor + */ +var FileTransfer = function() { + this._id = ++idCounter; + this.onprogress = null; // optional callback +}; + +/** +* Given an absolute file path, uploads a file on the device to a remote server +* using a multipart HTTP request. +* @param filePath {String} Full path of the file on the device +* @param server {String} URL of the server to receive the file +* @param successCallback (Function} Callback to be invoked when upload has completed +* @param errorCallback {Function} Callback to be invoked upon error +* @param options {FileUploadOptions} Optional parameters such as file name and mimetype +* @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false +*/ +FileTransfer.prototype.upload = function(filePath, server, successCallback, errorCallback, options, trustAllHosts) { + argscheck.checkArgs('ssFFO*', 'FileTransfer.upload', arguments); + // check for options + var fileKey = null; + var fileName = null; + var mimeType = null; + var params = null; + var chunkedMode = true; + var headers = null; + var httpMethod = null; + var basicAuthHeader = getBasicAuthHeader(server); + if (basicAuthHeader) { + options = options || {}; + options.headers = options.headers || {}; + options.headers[basicAuthHeader.name] = basicAuthHeader.value; + } + + if (options) { + fileKey = options.fileKey; + fileName = options.fileName; + mimeType = options.mimeType; + headers = options.headers; + httpMethod = options.httpMethod || "POST"; + if (httpMethod.toUpperCase() == "PUT"){ + httpMethod = "PUT"; + } else { + httpMethod = "POST"; + } + if (options.chunkedMode !== null || typeof options.chunkedMode != "undefined") { + chunkedMode = options.chunkedMode; + } + if (options.params) { + params = options.params; + } + else { + params = {}; + } + } + + var fail = errorCallback && function(e) { + var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body); + errorCallback(error); + }; + + var self = this; + var win = function(result) { + if (typeof result.lengthComputable != "undefined") { + if (self.onprogress) { + self.onprogress(newProgressEvent(result)); + } + } else { + successCallback && successCallback(result); + } + }; + exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id, httpMethod]); +}; + +/** + * Downloads a file form a given URL and saves it to the specified directory. + * @param source {String} URL of the server to receive the file + * @param target {String} Full path of the file on the device + * @param successCallback (Function} Callback to be invoked when upload has completed + * @param errorCallback {Function} Callback to be invoked upon error + * @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false + * @param options {FileDownloadOptions} Optional parameters such as headers + */ +FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts, options) { + argscheck.checkArgs('ssFF*', 'FileTransfer.download', arguments); + var self = this; + + var basicAuthHeader = getBasicAuthHeader(source); + if (basicAuthHeader) { + options = options || {}; + options.headers = options.headers || {}; + options.headers[basicAuthHeader.name] = basicAuthHeader.value; + } + + var headers = null; + if (options) { + headers = options.headers || null; + } + + var win = function(result) { + if (typeof result.lengthComputable != "undefined") { + if (self.onprogress) { + return self.onprogress(newProgressEvent(result)); + } + } else if (successCallback) { + var entry = null; + if (result.isDirectory) { + entry = new (require('cordova/plugin/DirectoryEntry'))(); + } + else if (result.isFile) { + entry = new (require('cordova/plugin/FileEntry'))(); + } + entry.isDirectory = result.isDirectory; + entry.isFile = result.isFile; + entry.name = result.name; + entry.fullPath = result.fullPath; + successCallback(entry); + } + }; + + var fail = errorCallback && function(e) { + var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body); + errorCallback(error); + }; + + exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id, headers]); +}; + +/** + * Aborts the ongoing file transfer on this object. The original error + * callback for the file transfer will be called if necessary. + */ +FileTransfer.prototype.abort = function() { + exec(null, null, 'FileTransfer', 'abort', [this._id]); +}; + +module.exports = FileTransfer; + +}); + +// file: lib/common/plugin/FileTransferError.js +define("cordova/plugin/FileTransferError", function(require, exports, module) { + +/** + * FileTransferError + * @constructor + */ +var FileTransferError = function(code, source, target, status, body) { + this.code = code || null; + this.source = source || null; + this.target = target || null; + this.http_status = status || null; + this.body = body || null; +}; + +FileTransferError.FILE_NOT_FOUND_ERR = 1; +FileTransferError.INVALID_URL_ERR = 2; +FileTransferError.CONNECTION_ERR = 3; +FileTransferError.ABORT_ERR = 4; + +module.exports = FileTransferError; + +}); + +// file: lib/common/plugin/FileUploadOptions.js +define("cordova/plugin/FileUploadOptions", function(require, exports, module) { + +/** + * Options to customize the HTTP request used to upload files. + * @constructor + * @param fileKey {String} Name of file request parameter. + * @param fileName {String} Filename to be used by the server. Defaults to image.jpg. + * @param mimeType {String} Mimetype of the uploaded file. Defaults to image/jpeg. + * @param params {Object} Object with key: value params to send to the server. + * @param headers {Object} Keys are header names, values are header values. Multiple + * headers of the same name are not supported. + */ +var FileUploadOptions = function(fileKey, fileName, mimeType, params, headers, httpMethod) { + this.fileKey = fileKey || null; + this.fileName = fileName || null; + this.mimeType = mimeType || null; + this.params = params || null; + this.headers = headers || null; + this.httpMethod = httpMethod || null; +}; + +module.exports = FileUploadOptions; + +}); + +// file: lib/common/plugin/FileUploadResult.js +define("cordova/plugin/FileUploadResult", function(require, exports, module) { + +/** + * FileUploadResult + * @constructor + */ +var FileUploadResult = function() { + this.bytesSent = 0; + this.responseCode = null; + this.response = null; +}; + +module.exports = FileUploadResult; + +}); + +// file: lib/common/plugin/FileWriter.js +define("cordova/plugin/FileWriter", function(require, exports, module) { + +var exec = require('cordova/exec'), + FileError = require('cordova/plugin/FileError'), + ProgressEvent = require('cordova/plugin/ProgressEvent'); + +/** + * This class writes to the mobile device file system. + * + * For Android: + * The root directory is the root of the file system. + * To write to the SD card, the file name is "sdcard/my_file.txt" + * + * @constructor + * @param file {File} File object containing file properties + * @param append if true write to the end of the file, otherwise overwrite the file + */ +var FileWriter = function(file) { + this.fileName = ""; + this.length = 0; + if (file) { + this.fileName = file.fullPath || file; + this.length = file.size || 0; + } + // default is to write at the beginning of the file + this.position = 0; + + this.readyState = 0; // EMPTY + + this.result = null; + + // Error + this.error = null; + + // Event handlers + this.onwritestart = null; // When writing starts + this.onprogress = null; // While writing the file, and reporting partial file data + this.onwrite = null; // When the write has successfully completed. + this.onwriteend = null; // When the request has completed (either in success or failure). + this.onabort = null; // When the write has been aborted. For instance, by invoking the abort() method. + this.onerror = null; // When the write has failed (see errors). +}; + +// States +FileWriter.INIT = 0; +FileWriter.WRITING = 1; +FileWriter.DONE = 2; + +/** + * Abort writing file. + */ +FileWriter.prototype.abort = function() { + // check for invalid state + if (this.readyState === FileWriter.DONE || this.readyState === FileWriter.INIT) { + throw new FileError(FileError.INVALID_STATE_ERR); + } + + // set error + this.error = new FileError(FileError.ABORT_ERR); + + this.readyState = FileWriter.DONE; + + // If abort callback + if (typeof this.onabort === "function") { + this.onabort(new ProgressEvent("abort", {"target":this})); + } + + // If write end callback + if (typeof this.onwriteend === "function") { + this.onwriteend(new ProgressEvent("writeend", {"target":this})); + } +}; + +/** + * Writes data to the file + * + * @param data text or blob to be written + */ +FileWriter.prototype.write = function(data) { + + var isBinary = false; + + // If we don't have Blob or ArrayBuffer support, don't bother. + if (typeof window.Blob !== 'undefined' && typeof window.ArrayBuffer !== 'undefined') { + + // Check to see if the incoming data is a blob + if (data instanceof Blob) { + var that=this; + var fileReader = new FileReader(); + fileReader.onload = function() { + // Call this method again, with the arraybuffer as argument + FileWriter.prototype.write.call(that, this.result); + }; + fileReader.readAsArrayBuffer(data); + return; + } + + // Mark data type for safer transport over the binary bridge + isBinary = (data instanceof ArrayBuffer); + } + + // Throw an exception if we are already writing a file + if (this.readyState === FileWriter.WRITING) { + throw new FileError(FileError.INVALID_STATE_ERR); + } + + // WRITING state + this.readyState = FileWriter.WRITING; + + var me = this; + + // If onwritestart callback + if (typeof me.onwritestart === "function") { + me.onwritestart(new ProgressEvent("writestart", {"target":me})); + } + + // Write file + exec( + // Success callback + function(r) { + // If DONE (cancelled), then don't do anything + if (me.readyState === FileWriter.DONE) { + return; + } + + // position always increases by bytes written because file would be extended + me.position += r; + // The length of the file is now where we are done writing. + + me.length = me.position; + + // DONE state + me.readyState = FileWriter.DONE; + + // If onwrite callback + if (typeof me.onwrite === "function") { + me.onwrite(new ProgressEvent("write", {"target":me})); + } + + // If onwriteend callback + if (typeof me.onwriteend === "function") { + me.onwriteend(new ProgressEvent("writeend", {"target":me})); + } + }, + // Error callback + function(e) { + // If DONE (cancelled), then don't do anything + if (me.readyState === FileWriter.DONE) { + return; + } + + // DONE state + me.readyState = FileWriter.DONE; + + // Save error + me.error = new FileError(e); + + // If onerror callback + if (typeof me.onerror === "function") { + me.onerror(new ProgressEvent("error", {"target":me})); + } + + // If onwriteend callback + if (typeof me.onwriteend === "function") { + me.onwriteend(new ProgressEvent("writeend", {"target":me})); + } + }, "File", "write", [this.fileName, data, this.position, isBinary]); +}; + +/** + * Moves the file pointer to the location specified. + * + * If the offset is a negative number the position of the file + * pointer is rewound. If the offset is greater than the file + * size the position is set to the end of the file. + * + * @param offset is the location to move the file pointer to. + */ +FileWriter.prototype.seek = function(offset) { + // Throw an exception if we are already writing a file + if (this.readyState === FileWriter.WRITING) { + throw new FileError(FileError.INVALID_STATE_ERR); + } + + if (!offset && offset !== 0) { + return; + } + + // See back from end of file. + if (offset < 0) { + this.position = Math.max(offset + this.length, 0); + } + // Offset is bigger than file size so set position + // to the end of the file. + else if (offset > this.length) { + this.position = this.length; + } + // Offset is between 0 and file size so set the position + // to start writing. + else { + this.position = offset; + } +}; + +/** + * Truncates the file to the size specified. + * + * @param size to chop the file at. + */ +FileWriter.prototype.truncate = function(size) { + // Throw an exception if we are already writing a file + if (this.readyState === FileWriter.WRITING) { + throw new FileError(FileError.INVALID_STATE_ERR); + } + + // WRITING state + this.readyState = FileWriter.WRITING; + + var me = this; + + // If onwritestart callback + if (typeof me.onwritestart === "function") { + me.onwritestart(new ProgressEvent("writestart", {"target":this})); + } + + // Write file + exec( + // Success callback + function(r) { + // If DONE (cancelled), then don't do anything + if (me.readyState === FileWriter.DONE) { + return; + } + + // DONE state + me.readyState = FileWriter.DONE; + + // Update the length of the file + me.length = r; + me.position = Math.min(me.position, r); + + // If onwrite callback + if (typeof me.onwrite === "function") { + me.onwrite(new ProgressEvent("write", {"target":me})); + } + + // If onwriteend callback + if (typeof me.onwriteend === "function") { + me.onwriteend(new ProgressEvent("writeend", {"target":me})); + } + }, + // Error callback + function(e) { + // If DONE (cancelled), then don't do anything + if (me.readyState === FileWriter.DONE) { + return; + } + + // DONE state + me.readyState = FileWriter.DONE; + + // Save error + me.error = new FileError(e); + + // If onerror callback + if (typeof me.onerror === "function") { + me.onerror(new ProgressEvent("error", {"target":me})); + } + + // If onwriteend callback + if (typeof me.onwriteend === "function") { + me.onwriteend(new ProgressEvent("writeend", {"target":me})); + } + }, "File", "truncate", [this.fileName, size]); +}; + +module.exports = FileWriter; + +}); + +// file: lib/common/plugin/Flags.js +define("cordova/plugin/Flags", function(require, exports, module) { + +/** + * Supplies arguments to methods that lookup or create files and directories. + * + * @param create + * {boolean} file or directory if it doesn't exist + * @param exclusive + * {boolean} used with create; if true the command will fail if + * target path exists + */ +function Flags(create, exclusive) { + this.create = create || false; + this.exclusive = exclusive || false; +} + +module.exports = Flags; + +}); + +// file: lib/common/plugin/GlobalizationError.js +define("cordova/plugin/GlobalizationError", function(require, exports, module) { + + +/** + * Globalization error object + * + * @constructor + * @param code + * @param message + */ +var GlobalizationError = function(code, message) { + this.code = code || null; + this.message = message || ''; +}; + +// Globalization error codes +GlobalizationError.UNKNOWN_ERROR = 0; +GlobalizationError.FORMATTING_ERROR = 1; +GlobalizationError.PARSING_ERROR = 2; +GlobalizationError.PATTERN_ERROR = 3; + +module.exports = GlobalizationError; + +}); + +// file: lib/common/plugin/InAppBrowser.js +define("cordova/plugin/InAppBrowser", function(require, exports, module) { + +var exec = require('cordova/exec'); +var channel = require('cordova/channel'); +var modulemapper = require('cordova/modulemapper'); + +function InAppBrowser() { + this.channels = { + 'loadstart': channel.create('loadstart'), + 'loadstop' : channel.create('loadstop'), + 'loaderror' : channel.create('loaderror'), + 'exit' : channel.create('exit') + }; +} + +InAppBrowser.prototype = { + _eventHandler: function (event) { + if (event.type in this.channels) { + this.channels[event.type].fire(event); + } + }, + close: function (eventname) { + exec(null, null, "InAppBrowser", "close", []); + }, + show: function (eventname) { + exec(null, null, "InAppBrowser", "show", []); + }, + addEventListener: function (eventname,f) { + if (eventname in this.channels) { + this.channels[eventname].subscribe(f); + } + }, + removeEventListener: function(eventname, f) { + if (eventname in this.channels) { + this.channels[eventname].unsubscribe(f); + } + }, + + executeScript: function(injectDetails, cb) { + if (injectDetails.code) { + exec(cb, null, "InAppBrowser", "injectScriptCode", [injectDetails.code, !!cb]); + } else if (injectDetails.file) { + exec(cb, null, "InAppBrowser", "injectScriptFile", [injectDetails.file, !!cb]); + } else { + throw new Error('executeScript requires exactly one of code or file to be specified'); + } + }, + + insertCSS: function(injectDetails, cb) { + if (injectDetails.code) { + exec(cb, null, "InAppBrowser", "injectStyleCode", [injectDetails.code, !!cb]); + } else if (injectDetails.file) { + exec(cb, null, "InAppBrowser", "injectStyleFile", [injectDetails.file, !!cb]); + } else { + throw new Error('insertCSS requires exactly one of code or file to be specified'); + } + } +}; + +module.exports = function(strUrl, strWindowName, strWindowFeatures) { + var iab = new InAppBrowser(); + var cb = function(eventname) { + iab._eventHandler(eventname); + }; + + // Don't catch calls that write to existing frames (e.g. named iframes). + if (window.frames && window.frames[strWindowName]) { + var origOpenFunc = modulemapper.getOriginalSymbol(window, 'open'); + return origOpenFunc.apply(window, arguments); + } + + exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]); + return iab; +}; + + +}); + +// file: lib/common/plugin/LocalFileSystem.js +define("cordova/plugin/LocalFileSystem", function(require, exports, module) { + +var exec = require('cordova/exec'); + +/** + * Represents a local file system. + */ +var LocalFileSystem = function() { + +}; + +LocalFileSystem.TEMPORARY = 0; //temporary, with no guarantee of persistence +LocalFileSystem.PERSISTENT = 1; //persistent + +module.exports = LocalFileSystem; + +}); + +// file: lib/common/plugin/Media.js +define("cordova/plugin/Media", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + utils = require('cordova/utils'), + exec = require('cordova/exec'); + +var mediaObjects = {}; + +/** + * This class provides access to the device media, interfaces to both sound and video + * + * @constructor + * @param src The file name or url to play + * @param successCallback The callback to be called when the file is done playing or recording. + * successCallback() + * @param errorCallback The callback to be called if there is an error. + * errorCallback(int errorCode) - OPTIONAL + * @param statusCallback The callback to be called when media status has changed. + * statusCallback(int statusCode) - OPTIONAL + */ +var Media = function(src, successCallback, errorCallback, statusCallback) { + argscheck.checkArgs('SFFF', 'Media', arguments); + this.id = utils.createUUID(); + mediaObjects[this.id] = this; + this.src = src; + this.successCallback = successCallback; + this.errorCallback = errorCallback; + this.statusCallback = statusCallback; + this._duration = -1; + this._position = -1; + exec(null, this.errorCallback, "Media", "create", [this.id, this.src]); +}; + +// Media messages +Media.MEDIA_STATE = 1; +Media.MEDIA_DURATION = 2; +Media.MEDIA_POSITION = 3; +Media.MEDIA_ERROR = 9; + +// Media states +Media.MEDIA_NONE = 0; +Media.MEDIA_STARTING = 1; +Media.MEDIA_RUNNING = 2; +Media.MEDIA_PAUSED = 3; +Media.MEDIA_STOPPED = 4; +Media.MEDIA_MSG = ["None", "Starting", "Running", "Paused", "Stopped"]; + +// "static" function to return existing objs. +Media.get = function(id) { + return mediaObjects[id]; +}; + +/** + * Start or resume playing audio file. + */ +Media.prototype.play = function(options) { + exec(null, null, "Media", "startPlayingAudio", [this.id, this.src, options]); +}; + +/** + * Stop playing audio file. + */ +Media.prototype.stop = function() { + var me = this; + exec(function() { + me._position = 0; + }, this.errorCallback, "Media", "stopPlayingAudio", [this.id]); +}; + +/** + * Seek or jump to a new time in the track.. + */ +Media.prototype.seekTo = function(milliseconds) { + var me = this; + exec(function(p) { + me._position = p; + }, this.errorCallback, "Media", "seekToAudio", [this.id, milliseconds]); +}; + +/** + * Pause playing audio file. + */ +Media.prototype.pause = function() { + exec(null, this.errorCallback, "Media", "pausePlayingAudio", [this.id]); +}; + +/** + * Get duration of an audio file. + * The duration is only set for audio that is playing, paused or stopped. + * + * @return duration or -1 if not known. + */ +Media.prototype.getDuration = function() { + return this._duration; +}; + +/** + * Get position of audio. + */ +Media.prototype.getCurrentPosition = function(success, fail) { + var me = this; + exec(function(p) { + me._position = p; + success(p); + }, fail, "Media", "getCurrentPositionAudio", [this.id]); +}; + +/** + * Start recording audio file. + */ +Media.prototype.startRecord = function() { + exec(null, this.errorCallback, "Media", "startRecordingAudio", [this.id, this.src]); +}; + +/** + * Stop recording audio file. + */ +Media.prototype.stopRecord = function() { + exec(null, this.errorCallback, "Media", "stopRecordingAudio", [this.id]); +}; + +/** + * Release the resources. + */ +Media.prototype.release = function() { + exec(null, this.errorCallback, "Media", "release", [this.id]); +}; + +/** + * Adjust the volume. + */ +Media.prototype.setVolume = function(volume) { + exec(null, null, "Media", "setVolume", [this.id, volume]); +}; + +/** + * Audio has status update. + * PRIVATE + * + * @param id The media object id (string) + * @param msgType The 'type' of update this is + * @param value Use of value is determined by the msgType + */ +Media.onStatus = function(id, msgType, value) { + + var media = mediaObjects[id]; + + if(media) { + switch(msgType) { + case Media.MEDIA_STATE : + media.statusCallback && media.statusCallback(value); + if(value == Media.MEDIA_STOPPED) { + media.successCallback && media.successCallback(); + } + break; + case Media.MEDIA_DURATION : + media._duration = value; + break; + case Media.MEDIA_ERROR : + media.errorCallback && media.errorCallback(value); + break; + case Media.MEDIA_POSITION : + media._position = Number(value); + break; + default : + console.error && console.error("Unhandled Media.onStatus :: " + msgType); + break; + } + } + else { + console.error && console.error("Received Media.onStatus callback for unknown media :: " + id); + } + +}; + +module.exports = Media; + +}); + +// file: lib/common/plugin/MediaError.js +define("cordova/plugin/MediaError", function(require, exports, module) { + +/** + * This class contains information about any Media errors. +*/ +/* + According to :: http://dev.w3.org/html5/spec-author-view/video.html#mediaerror + We should never be creating these objects, we should just implement the interface + which has 1 property for an instance, 'code' + + instead of doing : + errorCallbackFunction( new MediaError(3,'msg') ); +we should simply use a literal : + errorCallbackFunction( {'code':3} ); + */ + + var _MediaError = window.MediaError; + + +if(!_MediaError) { + window.MediaError = _MediaError = function(code, msg) { + this.code = (typeof code != 'undefined') ? code : null; + this.message = msg || ""; // message is NON-standard! do not use! + }; +} + +_MediaError.MEDIA_ERR_NONE_ACTIVE = _MediaError.MEDIA_ERR_NONE_ACTIVE || 0; +_MediaError.MEDIA_ERR_ABORTED = _MediaError.MEDIA_ERR_ABORTED || 1; +_MediaError.MEDIA_ERR_NETWORK = _MediaError.MEDIA_ERR_NETWORK || 2; +_MediaError.MEDIA_ERR_DECODE = _MediaError.MEDIA_ERR_DECODE || 3; +_MediaError.MEDIA_ERR_NONE_SUPPORTED = _MediaError.MEDIA_ERR_NONE_SUPPORTED || 4; +// TODO: MediaError.MEDIA_ERR_NONE_SUPPORTED is legacy, the W3 spec now defines it as below. +// as defined by http://dev.w3.org/html5/spec-author-view/video.html#error-codes +_MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED = _MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED || 4; + +module.exports = _MediaError; + +}); + +// file: lib/common/plugin/MediaFile.js +define("cordova/plugin/MediaFile", function(require, exports, module) { + +var utils = require('cordova/utils'), + exec = require('cordova/exec'), + File = require('cordova/plugin/File'), + CaptureError = require('cordova/plugin/CaptureError'); +/** + * Represents a single file. + * + * name {DOMString} name of the file, without path information + * fullPath {DOMString} the full path of the file, including the name + * type {DOMString} mime type + * lastModifiedDate {Date} last modified date + * size {Number} size of the file in bytes + */ +var MediaFile = function(name, fullPath, type, lastModifiedDate, size){ + MediaFile.__super__.constructor.apply(this, arguments); +}; + +utils.extend(MediaFile, File); + +/** + * Request capture format data for a specific file and type + * + * @param {Function} successCB + * @param {Function} errorCB + */ +MediaFile.prototype.getFormatData = function(successCallback, errorCallback) { + if (typeof this.fullPath === "undefined" || this.fullPath === null) { + errorCallback(new CaptureError(CaptureError.CAPTURE_INVALID_ARGUMENT)); + } else { + exec(successCallback, errorCallback, "Capture", "getFormatData", [this.fullPath, this.type]); + } +}; + +module.exports = MediaFile; + +}); + +// file: lib/common/plugin/MediaFileData.js +define("cordova/plugin/MediaFileData", function(require, exports, module) { + +/** + * MediaFileData encapsulates format information of a media file. + * + * @param {DOMString} codecs + * @param {long} bitrate + * @param {long} height + * @param {long} width + * @param {float} duration + */ +var MediaFileData = function(codecs, bitrate, height, width, duration){ + this.codecs = codecs || null; + this.bitrate = bitrate || 0; + this.height = height || 0; + this.width = width || 0; + this.duration = duration || 0; +}; + +module.exports = MediaFileData; + +}); + +// file: lib/common/plugin/Metadata.js +define("cordova/plugin/Metadata", function(require, exports, module) { + +/** + * Information about the state of the file or directory + * + * {Date} modificationTime (readonly) + */ +var Metadata = function(time) { + this.modificationTime = (typeof time != 'undefined'?new Date(time):null); +}; + +module.exports = Metadata; + +}); + +// file: lib/common/plugin/Position.js +define("cordova/plugin/Position", function(require, exports, module) { + +var Coordinates = require('cordova/plugin/Coordinates'); + +var Position = function(coords, timestamp) { + if (coords) { + this.coords = new Coordinates(coords.latitude, coords.longitude, coords.altitude, coords.accuracy, coords.heading, coords.velocity, coords.altitudeAccuracy); + } else { + this.coords = new Coordinates(); + } + this.timestamp = (timestamp !== undefined) ? timestamp : new Date(); +}; + +module.exports = Position; + +}); + +// file: lib/common/plugin/PositionError.js +define("cordova/plugin/PositionError", function(require, exports, module) { + +/** + * Position error object + * + * @constructor + * @param code + * @param message + */ +var PositionError = function(code, message) { + this.code = code || null; + this.message = message || ''; +}; + +PositionError.PERMISSION_DENIED = 1; +PositionError.POSITION_UNAVAILABLE = 2; +PositionError.TIMEOUT = 3; + +module.exports = PositionError; + +}); + +// file: lib/common/plugin/ProgressEvent.js +define("cordova/plugin/ProgressEvent", function(require, exports, module) { + +// If ProgressEvent exists in global context, use it already, otherwise use our own polyfill +// Feature test: See if we can instantiate a native ProgressEvent; +// if so, use that approach, +// otherwise fill-in with our own implementation. +// +// NOTE: right now we always fill in with our own. Down the road would be nice if we can use whatever is native in the webview. +var ProgressEvent = (function() { + /* + var createEvent = function(data) { + var event = document.createEvent('Events'); + event.initEvent('ProgressEvent', false, false); + if (data) { + for (var i in data) { + if (data.hasOwnProperty(i)) { + event[i] = data[i]; + } + } + if (data.target) { + // TODO: cannot call .dispatchEvent + // need to first figure out how to implement EventTarget + } + } + return event; + }; + try { + var ev = createEvent({type:"abort",target:document}); + return function ProgressEvent(type, data) { + data.type = type; + return createEvent(data); + }; + } catch(e){ + */ + return function ProgressEvent(type, dict) { + this.type = type; + this.bubbles = false; + this.cancelBubble = false; + this.cancelable = false; + this.lengthComputable = false; + this.loaded = dict && dict.loaded ? dict.loaded : 0; + this.total = dict && dict.total ? dict.total : 0; + this.target = dict && dict.target ? dict.target : null; + }; + //} +})(); + +module.exports = ProgressEvent; + +}); + +// file: lib/common/plugin/accelerometer.js +define("cordova/plugin/accelerometer", function(require, exports, module) { + +/** + * This class provides access to device accelerometer data. + * @constructor + */ +var argscheck = require('cordova/argscheck'), + utils = require("cordova/utils"), + exec = require("cordova/exec"), + Acceleration = require('cordova/plugin/Acceleration'); + +// Is the accel sensor running? +var running = false; + +// Keeps reference to watchAcceleration calls. +var timers = {}; + +// Array of listeners; used to keep track of when we should call start and stop. +var listeners = []; + +// Last returned acceleration object from native +var accel = null; + +// Tells native to start. +function start() { + exec(function(a) { + var tempListeners = listeners.slice(0); + accel = new Acceleration(a.x, a.y, a.z, a.timestamp); + for (var i = 0, l = tempListeners.length; i < l; i++) { + tempListeners[i].win(accel); + } + }, function(e) { + var tempListeners = listeners.slice(0); + for (var i = 0, l = tempListeners.length; i < l; i++) { + tempListeners[i].fail(e); + } + }, "Accelerometer", "start", []); + running = true; +} + +// Tells native to stop. +function stop() { + exec(null, null, "Accelerometer", "stop", []); + running = false; +} + +// Adds a callback pair to the listeners array +function createCallbackPair(win, fail) { + return {win:win, fail:fail}; +} + +// Removes a win/fail listener pair from the listeners array +function removeListeners(l) { + var idx = listeners.indexOf(l); + if (idx > -1) { + listeners.splice(idx, 1); + if (listeners.length === 0) { + stop(); + } + } +} + +var accelerometer = { + /** + * Asynchronously acquires the current acceleration. + * + * @param {Function} successCallback The function to call when the acceleration data is available + * @param {Function} errorCallback The function to call when there is an error getting the acceleration data. (OPTIONAL) + * @param {AccelerationOptions} options The options for getting the accelerometer data such as timeout. (OPTIONAL) + */ + getCurrentAcceleration: function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'accelerometer.getCurrentAcceleration', arguments); + + var p; + var win = function(a) { + removeListeners(p); + successCallback(a); + }; + var fail = function(e) { + removeListeners(p); + errorCallback && errorCallback(e); + }; + + p = createCallbackPair(win, fail); + listeners.push(p); + + if (!running) { + start(); + } + }, + + /** + * Asynchronously acquires the acceleration repeatedly at a given interval. + * + * @param {Function} successCallback The function to call each time the acceleration data is available + * @param {Function} errorCallback The function to call when there is an error getting the acceleration data. (OPTIONAL) + * @param {AccelerationOptions} options The options for getting the accelerometer data such as timeout. (OPTIONAL) + * @return String The watch id that must be passed to #clearWatch to stop watching. + */ + watchAcceleration: function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'accelerometer.watchAcceleration', arguments); + // Default interval (10 sec) + var frequency = (options && options.frequency && typeof options.frequency == 'number') ? options.frequency : 10000; + + // Keep reference to watch id, and report accel readings as often as defined in frequency + var id = utils.createUUID(); + + var p = createCallbackPair(function(){}, function(e) { + removeListeners(p); + errorCallback && errorCallback(e); + }); + listeners.push(p); + + timers[id] = { + timer:window.setInterval(function() { + if (accel) { + successCallback(accel); + } + }, frequency), + listeners:p + }; + + if (running) { + // If we're already running then immediately invoke the success callback + // but only if we have retrieved a value, sample code does not check for null ... + if (accel) { + successCallback(accel); + } + } else { + start(); + } + + return id; + }, + + /** + * Clears the specified accelerometer watch. + * + * @param {String} id The id of the watch returned from #watchAcceleration. + */ + clearWatch: function(id) { + // Stop javascript timer & remove from timer list + if (id && timers[id]) { + window.clearInterval(timers[id].timer); + removeListeners(timers[id].listeners); + delete timers[id]; + } + } +}; + +module.exports = accelerometer; + +}); + +// file: lib/common/plugin/accelerometer/symbols.js +define("cordova/plugin/accelerometer/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.defaults('cordova/plugin/Acceleration', 'Acceleration'); +modulemapper.defaults('cordova/plugin/accelerometer', 'navigator.accelerometer'); + +}); + +// file: lib/android/plugin/android/app.js +define("cordova/plugin/android/app", function(require, exports, module) { + +var exec = require('cordova/exec'); + +module.exports = { + /** + * Clear the resource cache. + */ + clearCache:function() { + exec(null, null, "App", "clearCache", []); + }, + + /** + * Load the url into the webview or into new browser instance. + * + * @param url The URL to load + * @param props Properties that can be passed in to the activity: + * wait: int => wait msec before loading URL + * loadingDialog: "Title,Message" => display a native loading dialog + * loadUrlTimeoutValue: int => time in msec to wait before triggering a timeout error + * clearHistory: boolean => clear webview history (default=false) + * openExternal: boolean => open in a new browser (default=false) + * + * Example: + * navigator.app.loadUrl("http://server/myapp/index.html", {wait:2000, loadingDialog:"Wait,Loading App", loadUrlTimeoutValue: 60000}); + */ + loadUrl:function(url, props) { + exec(null, null, "App", "loadUrl", [url, props]); + }, + + /** + * Cancel loadUrl that is waiting to be loaded. + */ + cancelLoadUrl:function() { + exec(null, null, "App", "cancelLoadUrl", []); + }, + + /** + * Clear web history in this web view. + * Instead of BACK button loading the previous web page, it will exit the app. + */ + clearHistory:function() { + exec(null, null, "App", "clearHistory", []); + }, + + /** + * Go to previous page displayed. + * This is the same as pressing the backbutton on Android device. + */ + backHistory:function() { + exec(null, null, "App", "backHistory", []); + }, + + /** + * Override the default behavior of the Android back button. + * If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired. + * + * Note: The user should not have to call this method. Instead, when the user + * registers for the "backbutton" event, this is automatically done. + * + * @param override T=override, F=cancel override + */ + overrideBackbutton:function(override) { + exec(null, null, "App", "overrideBackbutton", [override]); + }, + + /** + * Exit and terminate the application. + */ + exitApp:function() { + return exec(null, null, "App", "exitApp", []); + } +}; + +}); + +// file: lib/android/plugin/android/device.js +define("cordova/plugin/android/device", function(require, exports, module) { + +var channel = require('cordova/channel'), + utils = require('cordova/utils'), + exec = require('cordova/exec'), + app = require('cordova/plugin/android/app'); + +module.exports = { + /* + * DEPRECATED + * This is only for Android. + * + * You must explicitly override the back button. + */ + overrideBackButton:function() { + console.log("Device.overrideBackButton() is deprecated. Use App.overrideBackbutton(true)."); + app.overrideBackbutton(true); + }, + + /* + * DEPRECATED + * This is only for Android. + * + * This resets the back button to the default behavior + */ + resetBackButton:function() { + console.log("Device.resetBackButton() is deprecated. Use App.overrideBackbutton(false)."); + app.overrideBackbutton(false); + }, + + /* + * DEPRECATED + * This is only for Android. + * + * This terminates the activity! + */ + exitApp:function() { + console.log("Device.exitApp() is deprecated. Use App.exitApp()."); + app.exitApp(); + } +}; + +}); + +// file: lib/android/plugin/android/nativeapiprovider.js +define("cordova/plugin/android/nativeapiprovider", function(require, exports, module) { + +/** + * Exports the ExposedJsApi.java object if available, otherwise exports the PromptBasedNativeApi. + */ + +var nativeApi = this._cordovaNative || require('cordova/plugin/android/promptbasednativeapi'); +var currentApi = nativeApi; + +module.exports = { + get: function() { return currentApi; }, + setPreferPrompt: function(value) { + currentApi = value ? require('cordova/plugin/android/promptbasednativeapi') : nativeApi; + }, + // Used only by tests. + set: function(value) { + currentApi = value; + } +}; + +}); + +// file: lib/android/plugin/android/notification.js +define("cordova/plugin/android/notification", function(require, exports, module) { + +var exec = require('cordova/exec'); + +/** + * Provides Android enhanced notification API. + */ +module.exports = { + activityStart : function(title, message) { + // If title and message not specified then mimic Android behavior of + // using default strings. + if (typeof title === "undefined" && typeof message == "undefined") { + title = "Busy"; + message = 'Please wait...'; + } + + exec(null, null, 'Notification', 'activityStart', [ title, message ]); + }, + + /** + * Close an activity dialog + */ + activityStop : function() { + exec(null, null, 'Notification', 'activityStop', []); + }, + + /** + * Display a progress dialog with progress bar that goes from 0 to 100. + * + * @param {String} + * title Title of the progress dialog. + * @param {String} + * message Message to display in the dialog. + */ + progressStart : function(title, message) { + exec(null, null, 'Notification', 'progressStart', [ title, message ]); + }, + + /** + * Close the progress dialog. + */ + progressStop : function() { + exec(null, null, 'Notification', 'progressStop', []); + }, + + /** + * Set the progress dialog value. + * + * @param {Number} + * value 0-100 + */ + progressValue : function(value) { + exec(null, null, 'Notification', 'progressValue', [ value ]); + } +}; + +}); + +// file: lib/android/plugin/android/promptbasednativeapi.js +define("cordova/plugin/android/promptbasednativeapi", function(require, exports, module) { + +/** + * Implements the API of ExposedJsApi.java, but uses prompt() to communicate. + * This is used only on the 2.3 simulator, where addJavascriptInterface() is broken. + */ + +module.exports = { + exec: function(service, action, callbackId, argsJson) { + return prompt(argsJson, 'gap:'+JSON.stringify([service, action, callbackId])); + }, + setNativeToJsBridgeMode: function(value) { + prompt(value, 'gap_bridge_mode:'); + }, + retrieveJsMessages: function() { + return prompt('', 'gap_poll:'); + } +}; + +}); + +// file: lib/android/plugin/android/storage.js +define("cordova/plugin/android/storage", function(require, exports, module) { + +var utils = require('cordova/utils'), + exec = require('cordova/exec'), + channel = require('cordova/channel'); + +var queryQueue = {}; + +/** + * SQL result set object + * PRIVATE METHOD + * @constructor + */ +var DroidDB_Rows = function() { + this.resultSet = []; // results array + this.length = 0; // number of rows +}; + +/** + * Get item from SQL result set + * + * @param row The row number to return + * @return The row object + */ +DroidDB_Rows.prototype.item = function(row) { + return this.resultSet[row]; +}; + +/** + * SQL result set that is returned to user. + * PRIVATE METHOD + * @constructor + */ +var DroidDB_Result = function() { + this.rows = new DroidDB_Rows(); +}; + +/** + * Callback from native code when query is complete. + * PRIVATE METHOD + * + * @param id Query id + */ +function completeQuery(id, data) { + var query = queryQueue[id]; + if (query) { + try { + delete queryQueue[id]; + + // Get transaction + var tx = query.tx; + + // If transaction hasn't failed + // Note: We ignore all query results if previous query + // in the same transaction failed. + if (tx && tx.queryList[id]) { + + // Save query results + var r = new DroidDB_Result(); + r.rows.resultSet = data; + r.rows.length = data.length; + try { + if (typeof query.successCallback === 'function') { + query.successCallback(query.tx, r); + } + } catch (ex) { + console.log("executeSql error calling user success callback: "+ex); + } + + tx.queryComplete(id); + } + } catch (e) { + console.log("executeSql error: "+e); + } + } +} + +/** + * Callback from native code when query fails + * PRIVATE METHOD + * + * @param reason Error message + * @param id Query id + */ +function failQuery(reason, id) { + var query = queryQueue[id]; + if (query) { + try { + delete queryQueue[id]; + + // Get transaction + var tx = query.tx; + + // If transaction hasn't failed + // Note: We ignore all query results if previous query + // in the same transaction failed. + if (tx && tx.queryList[id]) { + tx.queryList = {}; + + try { + if (typeof query.errorCallback === 'function') { + query.errorCallback(query.tx, reason); + } + } catch (ex) { + console.log("executeSql error calling user error callback: "+ex); + } + + tx.queryFailed(id, reason); + } + + } catch (e) { + console.log("executeSql error: "+e); + } + } +} + +/** + * SQL query object + * PRIVATE METHOD + * + * @constructor + * @param tx The transaction object that this query belongs to + */ +var DroidDB_Query = function(tx) { + + // Set the id of the query + this.id = utils.createUUID(); + + // Add this query to the queue + queryQueue[this.id] = this; + + // Init result + this.resultSet = []; + + // Set transaction that this query belongs to + this.tx = tx; + + // Add this query to transaction list + this.tx.queryList[this.id] = this; + + // Callbacks + this.successCallback = null; + this.errorCallback = null; + +}; + +/** + * Transaction object + * PRIVATE METHOD + * @constructor + */ +var DroidDB_Tx = function() { + + // Set the id of the transaction + this.id = utils.createUUID(); + + // Callbacks + this.successCallback = null; + this.errorCallback = null; + + // Query list + this.queryList = {}; +}; + +/** + * Mark query in transaction as complete. + * If all queries are complete, call the user's transaction success callback. + * + * @param id Query id + */ +DroidDB_Tx.prototype.queryComplete = function(id) { + delete this.queryList[id]; + + // If no more outstanding queries, then fire transaction success + if (this.successCallback) { + var count = 0; + var i; + for (i in this.queryList) { + if (this.queryList.hasOwnProperty(i)) { + count++; + } + } + if (count === 0) { + try { + this.successCallback(); + } catch(e) { + console.log("Transaction error calling user success callback: " + e); + } + } + } +}; + +/** + * Mark query in transaction as failed. + * + * @param id Query id + * @param reason Error message + */ +DroidDB_Tx.prototype.queryFailed = function(id, reason) { + + // The sql queries in this transaction have already been run, since + // we really don't have a real transaction implemented in native code. + // However, the user callbacks for the remaining sql queries in transaction + // will not be called. + this.queryList = {}; + + if (this.errorCallback) { + try { + this.errorCallback(reason); + } catch(e) { + console.log("Transaction error calling user error callback: " + e); + } + } +}; + +/** + * Execute SQL statement + * + * @param sql SQL statement to execute + * @param params Statement parameters + * @param successCallback Success callback + * @param errorCallback Error callback + */ +DroidDB_Tx.prototype.executeSql = function(sql, params, successCallback, errorCallback) { + + // Init params array + if (typeof params === 'undefined') { + params = []; + } + + // Create query and add to queue + var query = new DroidDB_Query(this); + queryQueue[query.id] = query; + + // Save callbacks + query.successCallback = successCallback; + query.errorCallback = errorCallback; + + // Call native code + exec(null, null, "Storage", "executeSql", [sql, params, query.id]); +}; + +var DatabaseShell = function() { +}; + +/** + * Start a transaction. + * Does not support rollback in event of failure. + * + * @param process {Function} The transaction function + * @param successCallback {Function} + * @param errorCallback {Function} + */ +DatabaseShell.prototype.transaction = function(process, errorCallback, successCallback) { + var tx = new DroidDB_Tx(); + tx.successCallback = successCallback; + tx.errorCallback = errorCallback; + try { + process(tx); + } catch (e) { + console.log("Transaction error: "+e); + if (tx.errorCallback) { + try { + tx.errorCallback(e); + } catch (ex) { + console.log("Transaction error calling user error callback: "+e); + } + } + } +}; + +/** + * Open database + * + * @param name Database name + * @param version Database version + * @param display_name Database display name + * @param size Database size in bytes + * @return Database object + */ +var DroidDB_openDatabase = function(name, version, display_name, size) { + exec(null, null, "Storage", "openDatabase", [name, version, display_name, size]); + var db = new DatabaseShell(); + return db; +}; + + +module.exports = { + openDatabase:DroidDB_openDatabase, + failQuery:failQuery, + completeQuery:completeQuery +}; + +}); + +// file: lib/android/plugin/android/storage/openDatabase.js +define("cordova/plugin/android/storage/openDatabase", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'), + storage = require('cordova/plugin/android/storage'); + +var originalOpenDatabase = modulemapper.getOriginalSymbol(window, 'openDatabase'); + +module.exports = function(name, version, desc, size) { + // First patch WebSQL if necessary + if (!originalOpenDatabase) { + // Not defined, create an openDatabase function for all to use! + return storage.openDatabase.apply(this, arguments); + } + + // Defined, but some Android devices will throw a SECURITY_ERR - + // so we wrap the whole thing in a try-catch and shim in our own + // if the device has Android bug 16175. + try { + return originalOpenDatabase(name, version, desc, size); + } catch (ex) { + if (ex.code !== 18) { + throw ex; + } + } + return storage.openDatabase(name, version, desc, size); +}; + + + +}); + +// file: lib/android/plugin/android/storage/symbols.js +define("cordova/plugin/android/storage/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/android/storage/openDatabase', 'openDatabase'); + + +}); + +// file: lib/common/plugin/battery.js +define("cordova/plugin/battery", function(require, exports, module) { + +/** + * This class contains information about the current battery status. + * @constructor + */ +var cordova = require('cordova'), + exec = require('cordova/exec'); + +function handlers() { + return battery.channels.batterystatus.numHandlers + + battery.channels.batterylow.numHandlers + + battery.channels.batterycritical.numHandlers; +} + +var Battery = function() { + this._level = null; + this._isPlugged = null; + // Create new event handlers on the window (returns a channel instance) + this.channels = { + batterystatus:cordova.addWindowEventHandler("batterystatus"), + batterylow:cordova.addWindowEventHandler("batterylow"), + batterycritical:cordova.addWindowEventHandler("batterycritical") + }; + for (var key in this.channels) { + this.channels[key].onHasSubscribersChange = Battery.onHasSubscribersChange; + } +}; +/** + * Event handlers for when callbacks get registered for the battery. + * Keep track of how many handlers we have so we can start and stop the native battery listener + * appropriately (and hopefully save on battery life!). + */ +Battery.onHasSubscribersChange = function() { + // If we just registered the first handler, make sure native listener is started. + if (this.numHandlers === 1 && handlers() === 1) { + exec(battery._status, battery._error, "Battery", "start", []); + } else if (handlers() === 0) { + exec(null, null, "Battery", "stop", []); + } +}; + +/** + * Callback for battery status + * + * @param {Object} info keys: level, isPlugged + */ +Battery.prototype._status = function(info) { + if (info) { + var me = battery; + var level = info.level; + if (me._level !== level || me._isPlugged !== info.isPlugged) { + // Fire batterystatus event + cordova.fireWindowEvent("batterystatus", info); + + // Fire low battery event + if (level === 20 || level === 5) { + if (level === 20) { + cordova.fireWindowEvent("batterylow", info); + } + else { + cordova.fireWindowEvent("batterycritical", info); + } + } + } + me._level = level; + me._isPlugged = info.isPlugged; + } +}; + +/** + * Error callback for battery start + */ +Battery.prototype._error = function(e) { + console.log("Error initializing Battery: " + e); +}; + +var battery = new Battery(); + +module.exports = battery; + +}); + +// file: lib/common/plugin/battery/symbols.js +define("cordova/plugin/battery/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.defaults('cordova/plugin/battery', 'navigator.battery'); + +}); + +// file: lib/common/plugin/camera/symbols.js +define("cordova/plugin/camera/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.defaults('cordova/plugin/Camera', 'navigator.camera'); +modulemapper.defaults('cordova/plugin/CameraConstants', 'Camera'); +modulemapper.defaults('cordova/plugin/CameraPopoverOptions', 'CameraPopoverOptions'); + +}); + +// file: lib/common/plugin/capture.js +define("cordova/plugin/capture", function(require, exports, module) { + +var exec = require('cordova/exec'), + MediaFile = require('cordova/plugin/MediaFile'); + +/** + * Launches a capture of different types. + * + * @param (DOMString} type + * @param {Function} successCB + * @param {Function} errorCB + * @param {CaptureVideoOptions} options + */ +function _capture(type, successCallback, errorCallback, options) { + var win = function(pluginResult) { + var mediaFiles = []; + var i; + for (i = 0; i < pluginResult.length; i++) { + var mediaFile = new MediaFile(); + mediaFile.name = pluginResult[i].name; + mediaFile.fullPath = pluginResult[i].fullPath; + mediaFile.type = pluginResult[i].type; + mediaFile.lastModifiedDate = pluginResult[i].lastModifiedDate; + mediaFile.size = pluginResult[i].size; + mediaFiles.push(mediaFile); + } + successCallback(mediaFiles); + }; + exec(win, errorCallback, "Capture", type, [options]); +} +/** + * The Capture interface exposes an interface to the camera and microphone of the hosting device. + */ +function Capture() { + this.supportedAudioModes = []; + this.supportedImageModes = []; + this.supportedVideoModes = []; +} + +/** + * Launch audio recorder application for recording audio clip(s). + * + * @param {Function} successCB + * @param {Function} errorCB + * @param {CaptureAudioOptions} options + */ +Capture.prototype.captureAudio = function(successCallback, errorCallback, options){ + _capture("captureAudio", successCallback, errorCallback, options); +}; + +/** + * Launch camera application for taking image(s). + * + * @param {Function} successCB + * @param {Function} errorCB + * @param {CaptureImageOptions} options + */ +Capture.prototype.captureImage = function(successCallback, errorCallback, options){ + _capture("captureImage", successCallback, errorCallback, options); +}; + +/** + * Launch device camera application for recording video(s). + * + * @param {Function} successCB + * @param {Function} errorCB + * @param {CaptureVideoOptions} options + */ +Capture.prototype.captureVideo = function(successCallback, errorCallback, options){ + _capture("captureVideo", successCallback, errorCallback, options); +}; + + +module.exports = new Capture(); + +}); + +// file: lib/common/plugin/capture/symbols.js +define("cordova/plugin/capture/symbols", function(require, exports, module) { + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/CaptureError', 'CaptureError'); +modulemapper.clobbers('cordova/plugin/CaptureAudioOptions', 'CaptureAudioOptions'); +modulemapper.clobbers('cordova/plugin/CaptureImageOptions', 'CaptureImageOptions'); +modulemapper.clobbers('cordova/plugin/CaptureVideoOptions', 'CaptureVideoOptions'); +modulemapper.clobbers('cordova/plugin/ConfigurationData', 'ConfigurationData'); +modulemapper.clobbers('cordova/plugin/MediaFile', 'MediaFile'); +modulemapper.clobbers('cordova/plugin/MediaFileData', 'MediaFileData'); +modulemapper.clobbers('cordova/plugin/capture', 'navigator.device.capture'); + +}); + +// file: lib/common/plugin/compass.js +define("cordova/plugin/compass", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), + utils = require('cordova/utils'), + CompassHeading = require('cordova/plugin/CompassHeading'), + CompassError = require('cordova/plugin/CompassError'), + timers = {}, + compass = { + /** + * Asynchronously acquires the current heading. + * @param {Function} successCallback The function to call when the heading + * data is available + * @param {Function} errorCallback The function to call when there is an error + * getting the heading data. + * @param {CompassOptions} options The options for getting the heading data (not used). + */ + getCurrentHeading:function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'compass.getCurrentHeading', arguments); + + var win = function(result) { + var ch = new CompassHeading(result.magneticHeading, result.trueHeading, result.headingAccuracy, result.timestamp); + successCallback(ch); + }; + var fail = errorCallback && function(code) { + var ce = new CompassError(code); + errorCallback(ce); + }; + + // Get heading + exec(win, fail, "Compass", "getHeading", [options]); + }, + + /** + * Asynchronously acquires the heading repeatedly at a given interval. + * @param {Function} successCallback The function to call each time the heading + * data is available + * @param {Function} errorCallback The function to call when there is an error + * getting the heading data. + * @param {HeadingOptions} options The options for getting the heading data + * such as timeout and the frequency of the watch. For iOS, filter parameter + * specifies to watch via a distance filter rather than time. + */ + watchHeading:function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'compass.watchHeading', arguments); + // Default interval (100 msec) + var frequency = (options !== undefined && options.frequency !== undefined) ? options.frequency : 100; + var filter = (options !== undefined && options.filter !== undefined) ? options.filter : 0; + + var id = utils.createUUID(); + if (filter > 0) { + // is an iOS request for watch by filter, no timer needed + timers[id] = "iOS"; + compass.getCurrentHeading(successCallback, errorCallback, options); + } else { + // Start watch timer to get headings + timers[id] = window.setInterval(function() { + compass.getCurrentHeading(successCallback, errorCallback); + }, frequency); + } + + return id; + }, + + /** + * Clears the specified heading watch. + * @param {String} watchId The ID of the watch returned from #watchHeading. + */ + clearWatch:function(id) { + // Stop javascript timer & remove from timer list + if (id && timers[id]) { + if (timers[id] != "iOS") { + clearInterval(timers[id]); + } else { + // is iOS watch by filter so call into device to stop + exec(null, null, "Compass", "stopHeading", []); + } + delete timers[id]; + } + } + }; + +module.exports = compass; + +}); + +// file: lib/common/plugin/compass/symbols.js +define("cordova/plugin/compass/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/CompassHeading', 'CompassHeading'); +modulemapper.clobbers('cordova/plugin/CompassError', 'CompassError'); +modulemapper.clobbers('cordova/plugin/compass', 'navigator.compass'); + +}); + +// file: lib/common/plugin/console-via-logger.js +define("cordova/plugin/console-via-logger", function(require, exports, module) { + +//------------------------------------------------------------------------------ + +var logger = require("cordova/plugin/logger"); +var utils = require("cordova/utils"); + +//------------------------------------------------------------------------------ +// object that we're exporting +//------------------------------------------------------------------------------ +var console = module.exports; + +//------------------------------------------------------------------------------ +// copy of the original console object +//------------------------------------------------------------------------------ +var WinConsole = window.console; + +//------------------------------------------------------------------------------ +// whether to use the logger +//------------------------------------------------------------------------------ +var UseLogger = false; + +//------------------------------------------------------------------------------ +// Timers +//------------------------------------------------------------------------------ +var Timers = {}; + +//------------------------------------------------------------------------------ +// used for unimplemented methods +//------------------------------------------------------------------------------ +function noop() {} + +//------------------------------------------------------------------------------ +// used for unimplemented methods +//------------------------------------------------------------------------------ +console.useLogger = function (value) { + if (arguments.length) UseLogger = !!value; + + if (UseLogger) { + if (logger.useConsole()) { + throw new Error("console and logger are too intertwingly"); + } + } + + return UseLogger; +}; + +//------------------------------------------------------------------------------ +console.log = function() { + if (logger.useConsole()) return; + logger.log.apply(logger, [].slice.call(arguments)); +}; + +//------------------------------------------------------------------------------ +console.error = function() { + if (logger.useConsole()) return; + logger.error.apply(logger, [].slice.call(arguments)); +}; + +//------------------------------------------------------------------------------ +console.warn = function() { + if (logger.useConsole()) return; + logger.warn.apply(logger, [].slice.call(arguments)); +}; + +//------------------------------------------------------------------------------ +console.info = function() { + if (logger.useConsole()) return; + logger.info.apply(logger, [].slice.call(arguments)); +}; + +//------------------------------------------------------------------------------ +console.debug = function() { + if (logger.useConsole()) return; + logger.debug.apply(logger, [].slice.call(arguments)); +}; + +//------------------------------------------------------------------------------ +console.assert = function(expression) { + if (expression) return; + + var message = logger.format.apply(logger.format, [].slice.call(arguments, 1)); + console.log("ASSERT: " + message); +}; + +//------------------------------------------------------------------------------ +console.clear = function() {}; + +//------------------------------------------------------------------------------ +console.dir = function(object) { + console.log("%o", object); +}; + +//------------------------------------------------------------------------------ +console.dirxml = function(node) { + console.log(node.innerHTML); +}; + +//------------------------------------------------------------------------------ +console.trace = noop; + +//------------------------------------------------------------------------------ +console.group = console.log; + +//------------------------------------------------------------------------------ +console.groupCollapsed = console.log; + +//------------------------------------------------------------------------------ +console.groupEnd = noop; + +//------------------------------------------------------------------------------ +console.time = function(name) { + Timers[name] = new Date().valueOf(); +}; + +//------------------------------------------------------------------------------ +console.timeEnd = function(name) { + var timeStart = Timers[name]; + if (!timeStart) { + console.warn("unknown timer: " + name); + return; + } + + var timeElapsed = new Date().valueOf() - timeStart; + console.log(name + ": " + timeElapsed + "ms"); +}; + +//------------------------------------------------------------------------------ +console.timeStamp = noop; + +//------------------------------------------------------------------------------ +console.profile = noop; + +//------------------------------------------------------------------------------ +console.profileEnd = noop; + +//------------------------------------------------------------------------------ +console.count = noop; + +//------------------------------------------------------------------------------ +console.exception = console.log; + +//------------------------------------------------------------------------------ +console.table = function(data, columns) { + console.log("%o", data); +}; + +//------------------------------------------------------------------------------ +// return a new function that calls both functions passed as args +//------------------------------------------------------------------------------ +function wrappedOrigCall(orgFunc, newFunc) { + return function() { + var args = [].slice.call(arguments); + try { orgFunc.apply(WinConsole, args); } catch (e) {} + try { newFunc.apply(console, args); } catch (e) {} + }; +} + +//------------------------------------------------------------------------------ +// For every function that exists in the original console object, that +// also exists in the new console object, wrap the new console method +// with one that calls both +//------------------------------------------------------------------------------ +for (var key in console) { + if (typeof WinConsole[key] == "function") { + console[key] = wrappedOrigCall(WinConsole[key], console[key]); + } +} + +}); + +// file: lib/common/plugin/contacts.js +define("cordova/plugin/contacts", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), + ContactError = require('cordova/plugin/ContactError'), + utils = require('cordova/utils'), + Contact = require('cordova/plugin/Contact'); + +/** +* Represents a group of Contacts. +* @constructor +*/ +var contacts = { + /** + * Returns an array of Contacts matching the search criteria. + * @param fields that should be searched + * @param successCB success callback + * @param errorCB error callback + * @param {ContactFindOptions} options that can be applied to contact searching + * @return array of Contacts matching search criteria + */ + find:function(fields, successCB, errorCB, options) { + argscheck.checkArgs('afFO', 'contacts.find', arguments); + if (!fields.length) { + errorCB && errorCB(new ContactError(ContactError.INVALID_ARGUMENT_ERROR)); + } else { + var win = function(result) { + var cs = []; + for (var i = 0, l = result.length; i < l; i++) { + cs.push(contacts.create(result[i])); + } + successCB(cs); + }; + exec(win, errorCB, "Contacts", "search", [fields, options]); + } + }, + + /** + * This function creates a new contact, but it does not persist the contact + * to device storage. To persist the contact to device storage, invoke + * contact.save(). + * @param properties an object whose properties will be examined to create a new Contact + * @returns new Contact object + */ + create:function(properties) { + argscheck.checkArgs('O', 'contacts.create', arguments); + var contact = new Contact(); + for (var i in properties) { + if (typeof contact[i] !== 'undefined' && properties.hasOwnProperty(i)) { + contact[i] = properties[i]; + } + } + return contact; + } +}; + +module.exports = contacts; + +}); + +// file: lib/common/plugin/contacts/symbols.js +define("cordova/plugin/contacts/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/contacts', 'navigator.contacts'); +modulemapper.clobbers('cordova/plugin/Contact', 'Contact'); +modulemapper.clobbers('cordova/plugin/ContactAddress', 'ContactAddress'); +modulemapper.clobbers('cordova/plugin/ContactError', 'ContactError'); +modulemapper.clobbers('cordova/plugin/ContactField', 'ContactField'); +modulemapper.clobbers('cordova/plugin/ContactFindOptions', 'ContactFindOptions'); +modulemapper.clobbers('cordova/plugin/ContactName', 'ContactName'); +modulemapper.clobbers('cordova/plugin/ContactOrganization', 'ContactOrganization'); + +}); + +// file: lib/common/plugin/device.js +define("cordova/plugin/device", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + channel = require('cordova/channel'), + utils = require('cordova/utils'), + exec = require('cordova/exec'); + +// Tell cordova channel to wait on the CordovaInfoReady event +channel.waitForInitialization('onCordovaInfoReady'); + +/** + * This represents the mobile device, and provides properties for inspecting the model, version, UUID of the + * phone, etc. + * @constructor + */ +function Device() { + this.available = false; + this.platform = null; + this.version = null; + this.uuid = null; + this.cordova = null; + this.model = null; + + var me = this; + + channel.onCordovaReady.subscribe(function() { + me.getInfo(function(info) { + var buildLabel = info.cordova; + if (buildLabel != CORDOVA_JS_BUILD_LABEL) { + buildLabel += ' JS=' + CORDOVA_JS_BUILD_LABEL; + } + me.available = true; + me.platform = info.platform; + me.version = info.version; + me.uuid = info.uuid; + me.cordova = buildLabel; + me.model = info.model; + channel.onCordovaInfoReady.fire(); + },function(e) { + me.available = false; + utils.alert("[ERROR] Error initializing Cordova: " + e); + }); + }); +} + +/** + * Get device info + * + * @param {Function} successCallback The function to call when the heading data is available + * @param {Function} errorCallback The function to call when there is an error getting the heading data. (OPTIONAL) + */ +Device.prototype.getInfo = function(successCallback, errorCallback) { + argscheck.checkArgs('fF', 'Device.getInfo', arguments); + exec(successCallback, errorCallback, "Device", "getDeviceInfo", []); +}; + +module.exports = new Device(); + +}); + +// file: lib/android/plugin/device/symbols.js +define("cordova/plugin/device/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/device', 'device'); +modulemapper.merges('cordova/plugin/android/device', 'device'); + +}); + +// file: lib/common/plugin/echo.js +define("cordova/plugin/echo", function(require, exports, module) { + +var exec = require('cordova/exec'), + utils = require('cordova/utils'); + +/** + * Sends the given message through exec() to the Echo plugin, which sends it back to the successCallback. + * @param successCallback invoked with a FileSystem object + * @param errorCallback invoked if error occurs retrieving file system + * @param message The string to be echoed. + * @param forceAsync Whether to force an async return value (for testing native->js bridge). + */ +module.exports = function(successCallback, errorCallback, message, forceAsync) { + var action = 'echo'; + var messageIsMultipart = (utils.typeName(message) == "Array"); + var args = messageIsMultipart ? message : [message]; + + if (utils.typeName(message) == 'ArrayBuffer') { + if (forceAsync) { + console.warn('Cannot echo ArrayBuffer with forced async, falling back to sync.'); + } + action += 'ArrayBuffer'; + } else if (messageIsMultipart) { + if (forceAsync) { + console.warn('Cannot echo MultiPart Array with forced async, falling back to sync.'); + } + action += 'MultiPart'; + } else if (forceAsync) { + action += 'Async'; + } + + exec(successCallback, errorCallback, "Echo", action, args); +}; + + +}); + +// file: lib/android/plugin/file/symbols.js +define("cordova/plugin/file/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'), + symbolshelper = require('cordova/plugin/file/symbolshelper'); + +symbolshelper(modulemapper.clobbers); + +}); + +// file: lib/common/plugin/file/symbolshelper.js +define("cordova/plugin/file/symbolshelper", function(require, exports, module) { + +module.exports = function(exportFunc) { + exportFunc('cordova/plugin/DirectoryEntry', 'DirectoryEntry'); + exportFunc('cordova/plugin/DirectoryReader', 'DirectoryReader'); + exportFunc('cordova/plugin/Entry', 'Entry'); + exportFunc('cordova/plugin/File', 'File'); + exportFunc('cordova/plugin/FileEntry', 'FileEntry'); + exportFunc('cordova/plugin/FileError', 'FileError'); + exportFunc('cordova/plugin/FileReader', 'FileReader'); + exportFunc('cordova/plugin/FileSystem', 'FileSystem'); + exportFunc('cordova/plugin/FileUploadOptions', 'FileUploadOptions'); + exportFunc('cordova/plugin/FileUploadResult', 'FileUploadResult'); + exportFunc('cordova/plugin/FileWriter', 'FileWriter'); + exportFunc('cordova/plugin/Flags', 'Flags'); + exportFunc('cordova/plugin/LocalFileSystem', 'LocalFileSystem'); + exportFunc('cordova/plugin/Metadata', 'Metadata'); + exportFunc('cordova/plugin/ProgressEvent', 'ProgressEvent'); + exportFunc('cordova/plugin/requestFileSystem', 'requestFileSystem'); + exportFunc('cordova/plugin/resolveLocalFileSystemURI', 'resolveLocalFileSystemURI'); +}; + +}); + +// file: lib/common/plugin/filetransfer/symbols.js +define("cordova/plugin/filetransfer/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/FileTransfer', 'FileTransfer'); +modulemapper.clobbers('cordova/plugin/FileTransferError', 'FileTransferError'); + +}); + +// file: lib/common/plugin/geolocation.js +define("cordova/plugin/geolocation", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + utils = require('cordova/utils'), + exec = require('cordova/exec'), + PositionError = require('cordova/plugin/PositionError'), + Position = require('cordova/plugin/Position'); + +var timers = {}; // list of timers in use + +// Returns default params, overrides if provided with values +function parseParameters(options) { + var opt = { + maximumAge: 0, + enableHighAccuracy: false, + timeout: Infinity + }; + + if (options) { + if (options.maximumAge !== undefined && !isNaN(options.maximumAge) && options.maximumAge > 0) { + opt.maximumAge = options.maximumAge; + } + if (options.enableHighAccuracy !== undefined) { + opt.enableHighAccuracy = options.enableHighAccuracy; + } + if (options.timeout !== undefined && !isNaN(options.timeout)) { + if (options.timeout < 0) { + opt.timeout = 0; + } else { + opt.timeout = options.timeout; + } + } + } + + return opt; +} + +// Returns a timeout failure, closed over a specified timeout value and error callback. +function createTimeout(errorCallback, timeout) { + var t = setTimeout(function() { + clearTimeout(t); + t = null; + errorCallback({ + code:PositionError.TIMEOUT, + message:"Position retrieval timed out." + }); + }, timeout); + return t; +} + +var geolocation = { + lastPosition:null, // reference to last known (cached) position returned + /** + * Asynchronously acquires the current position. + * + * @param {Function} successCallback The function to call when the position data is available + * @param {Function} errorCallback The function to call when there is an error getting the heading position. (OPTIONAL) + * @param {PositionOptions} options The options for getting the position data. (OPTIONAL) + */ + getCurrentPosition:function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'geolocation.getCurrentPosition', arguments); + options = parseParameters(options); + + // Timer var that will fire an error callback if no position is retrieved from native + // before the "timeout" param provided expires + var timeoutTimer = {timer:null}; + + var win = function(p) { + clearTimeout(timeoutTimer.timer); + if (!(timeoutTimer.timer)) { + // Timeout already happened, or native fired error callback for + // this geo request. + // Don't continue with success callback. + return; + } + var pos = new Position( + { + latitude:p.latitude, + longitude:p.longitude, + altitude:p.altitude, + accuracy:p.accuracy, + heading:p.heading, + velocity:p.velocity, + altitudeAccuracy:p.altitudeAccuracy + }, + (p.timestamp === undefined ? new Date() : ((p.timestamp instanceof Date) ? p.timestamp : new Date(p.timestamp))) + ); + geolocation.lastPosition = pos; + successCallback(pos); + }; + var fail = function(e) { + clearTimeout(timeoutTimer.timer); + timeoutTimer.timer = null; + var err = new PositionError(e.code, e.message); + if (errorCallback) { + errorCallback(err); + } + }; + + // Check our cached position, if its timestamp difference with current time is less than the maximumAge, then just + // fire the success callback with the cached position. + if (geolocation.lastPosition && options.maximumAge && (((new Date()).getTime() - geolocation.lastPosition.timestamp.getTime()) <= options.maximumAge)) { + successCallback(geolocation.lastPosition); + // If the cached position check failed and the timeout was set to 0, error out with a TIMEOUT error object. + } else if (options.timeout === 0) { + fail({ + code:PositionError.TIMEOUT, + message:"timeout value in PositionOptions set to 0 and no cached Position object available, or cached Position object's age exceeds provided PositionOptions' maximumAge parameter." + }); + // Otherwise we have to call into native to retrieve a position. + } else { + if (options.timeout !== Infinity) { + // If the timeout value was not set to Infinity (default), then + // set up a timeout function that will fire the error callback + // if no successful position was retrieved before timeout expired. + timeoutTimer.timer = createTimeout(fail, options.timeout); + } else { + // This is here so the check in the win function doesn't mess stuff up + // may seem weird but this guarantees timeoutTimer is + // always truthy before we call into native + timeoutTimer.timer = true; + } + exec(win, fail, "Geolocation", "getLocation", [options.enableHighAccuracy, options.maximumAge]); + } + return timeoutTimer; + }, + /** + * Asynchronously watches the geolocation for changes to geolocation. When a change occurs, + * the successCallback is called with the new location. + * + * @param {Function} successCallback The function to call each time the location data is available + * @param {Function} errorCallback The function to call when there is an error getting the location data. (OPTIONAL) + * @param {PositionOptions} options The options for getting the location data such as frequency. (OPTIONAL) + * @return String The watch id that must be passed to #clearWatch to stop watching. + */ + watchPosition:function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'geolocation.getCurrentPosition', arguments); + options = parseParameters(options); + + var id = utils.createUUID(); + + // Tell device to get a position ASAP, and also retrieve a reference to the timeout timer generated in getCurrentPosition + timers[id] = geolocation.getCurrentPosition(successCallback, errorCallback, options); + + var fail = function(e) { + clearTimeout(timers[id].timer); + var err = new PositionError(e.code, e.message); + if (errorCallback) { + errorCallback(err); + } + }; + + var win = function(p) { + clearTimeout(timers[id].timer); + if (options.timeout !== Infinity) { + timers[id].timer = createTimeout(fail, options.timeout); + } + var pos = new Position( + { + latitude:p.latitude, + longitude:p.longitude, + altitude:p.altitude, + accuracy:p.accuracy, + heading:p.heading, + velocity:p.velocity, + altitudeAccuracy:p.altitudeAccuracy + }, + (p.timestamp === undefined ? new Date() : ((p.timestamp instanceof Date) ? p.timestamp : new Date(p.timestamp))) + ); + geolocation.lastPosition = pos; + successCallback(pos); + }; + + exec(win, fail, "Geolocation", "addWatch", [id, options.enableHighAccuracy]); + + return id; + }, + /** + * Clears the specified heading watch. + * + * @param {String} id The ID of the watch returned from #watchPosition + */ + clearWatch:function(id) { + if (id && timers[id] !== undefined) { + clearTimeout(timers[id].timer); + timers[id].timer = false; + exec(null, null, "Geolocation", "clearWatch", [id]); + } + } +}; + +module.exports = geolocation; + +}); + +// file: lib/common/plugin/geolocation/symbols.js +define("cordova/plugin/geolocation/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.defaults('cordova/plugin/geolocation', 'navigator.geolocation'); +modulemapper.clobbers('cordova/plugin/PositionError', 'PositionError'); +modulemapper.clobbers('cordova/plugin/Position', 'Position'); +modulemapper.clobbers('cordova/plugin/Coordinates', 'Coordinates'); + +}); + +// file: lib/common/plugin/globalization.js +define("cordova/plugin/globalization", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), + GlobalizationError = require('cordova/plugin/GlobalizationError'); + +var globalization = { + +/** +* Returns the string identifier for the client's current language. +* It returns the language identifier string to the successCB callback with a +* properties object as a parameter. If there is an error getting the language, +* then the errorCB callback is invoked. +* +* @param {Function} successCB +* @param {Function} errorCB +* +* @return Object.value {String}: The language identifier +* +* @error GlobalizationError.UNKNOWN_ERROR +* +* Example +* globalization.getPreferredLanguage(function (language) {alert('language:' + language.value + '\n');}, +* function () {}); +*/ +getPreferredLanguage:function(successCB, failureCB) { + argscheck.checkArgs('fF', 'Globalization.getPreferredLanguage', arguments); + exec(successCB, failureCB, "Globalization","getPreferredLanguage", []); +}, + +/** +* Returns the string identifier for the client's current locale setting. +* It returns the locale identifier string to the successCB callback with a +* properties object as a parameter. If there is an error getting the locale, +* then the errorCB callback is invoked. +* +* @param {Function} successCB +* @param {Function} errorCB +* +* @return Object.value {String}: The locale identifier +* +* @error GlobalizationError.UNKNOWN_ERROR +* +* Example +* globalization.getLocaleName(function (locale) {alert('locale:' + locale.value + '\n');}, +* function () {}); +*/ +getLocaleName:function(successCB, failureCB) { + argscheck.checkArgs('fF', 'Globalization.getLocaleName', arguments); + exec(successCB, failureCB, "Globalization","getLocaleName", []); +}, + + +/** +* Returns a date formatted as a string according to the client's user preferences and +* calendar using the time zone of the client. It returns the formatted date string to the +* successCB callback with a properties object as a parameter. If there is an error +* formatting the date, then the errorCB callback is invoked. +* +* The defaults are: formatLenght="short" and selector="date and time" +* +* @param {Date} date +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* formatLength {String}: 'short', 'medium', 'long', or 'full' +* selector {String}: 'date', 'time', or 'date and time' +* +* @return Object.value {String}: The localized date string +* +* @error GlobalizationError.FORMATTING_ERROR +* +* Example +* globalization.dateToString(new Date(), +* function (date) {alert('date:' + date.value + '\n');}, +* function (errorCode) {alert(errorCode);}, +* {formatLength:'short'}); +*/ +dateToString:function(date, successCB, failureCB, options) { + argscheck.checkArgs('dfFO', 'Globalization.dateToString', arguments); + var dateValue = date.valueOf(); + exec(successCB, failureCB, "Globalization", "dateToString", [{"date": dateValue, "options": options}]); +}, + + +/** +* Parses a date formatted as a string according to the client's user +* preferences and calendar using the time zone of the client and returns +* the corresponding date object. It returns the date to the successCB +* callback with a properties object as a parameter. If there is an error +* parsing the date string, then the errorCB callback is invoked. +* +* The defaults are: formatLength="short" and selector="date and time" +* +* @param {String} dateString +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* formatLength {String}: 'short', 'medium', 'long', or 'full' +* selector {String}: 'date', 'time', or 'date and time' +* +* @return Object.year {Number}: The four digit year +* Object.month {Number}: The month from (0 - 11) +* Object.day {Number}: The day from (1 - 31) +* Object.hour {Number}: The hour from (0 - 23) +* Object.minute {Number}: The minute from (0 - 59) +* Object.second {Number}: The second from (0 - 59) +* Object.millisecond {Number}: The milliseconds (from 0 - 999), +* not available on all platforms +* +* @error GlobalizationError.PARSING_ERROR +* +* Example +* globalization.stringToDate('4/11/2011', +* function (date) { alert('Month:' + date.month + '\n' + +* 'Day:' + date.day + '\n' + +* 'Year:' + date.year + '\n');}, +* function (errorCode) {alert(errorCode);}, +* {selector:'date'}); +*/ +stringToDate:function(dateString, successCB, failureCB, options) { + argscheck.checkArgs('sfFO', 'Globalization.stringToDate', arguments); + exec(successCB, failureCB, "Globalization", "stringToDate", [{"dateString": dateString, "options": options}]); +}, + + +/** +* Returns a pattern string for formatting and parsing dates according to the client's +* user preferences. It returns the pattern to the successCB callback with a +* properties object as a parameter. If there is an error obtaining the pattern, +* then the errorCB callback is invoked. +* +* The defaults are: formatLength="short" and selector="date and time" +* +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* formatLength {String}: 'short', 'medium', 'long', or 'full' +* selector {String}: 'date', 'time', or 'date and time' +* +* @return Object.pattern {String}: The date and time pattern for formatting and parsing dates. +* The patterns follow Unicode Technical Standard #35 +* http://unicode.org/reports/tr35/tr35-4.html +* Object.timezone {String}: The abbreviated name of the time zone on the client +* Object.utc_offset {Number}: The current difference in seconds between the client's +* time zone and coordinated universal time. +* Object.dst_offset {Number}: The current daylight saving time offset in seconds +* between the client's non-daylight saving's time zone +* and the client's daylight saving's time zone. +* +* @error GlobalizationError.PATTERN_ERROR +* +* Example +* globalization.getDatePattern( +* function (date) {alert('pattern:' + date.pattern + '\n');}, +* function () {}, +* {formatLength:'short'}); +*/ +getDatePattern:function(successCB, failureCB, options) { + argscheck.checkArgs('fFO', 'Globalization.getDatePattern', arguments); + exec(successCB, failureCB, "Globalization", "getDatePattern", [{"options": options}]); +}, + + +/** +* Returns an array of either the names of the months or days of the week +* according to the client's user preferences and calendar. It returns the array of names to the +* successCB callback with a properties object as a parameter. If there is an error obtaining the +* names, then the errorCB callback is invoked. +* +* The defaults are: type="wide" and item="months" +* +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* type {String}: 'narrow' or 'wide' +* item {String}: 'months', or 'days' +* +* @return Object.value {Array{String}}: The array of names starting from either +* the first month in the year or the +* first day of the week. +* @error GlobalizationError.UNKNOWN_ERROR +* +* Example +* globalization.getDateNames(function (names) { +* for(var i = 0; i < names.value.length; i++) { +* alert('Month:' + names.value[i] + '\n');}}, +* function () {}); +*/ +getDateNames:function(successCB, failureCB, options) { + argscheck.checkArgs('fFO', 'Globalization.getDateNames', arguments); + exec(successCB, failureCB, "Globalization", "getDateNames", [{"options": options}]); +}, + +/** +* Returns whether daylight savings time is in effect for a given date using the client's +* time zone and calendar. It returns whether or not daylight savings time is in effect +* to the successCB callback with a properties object as a parameter. If there is an error +* reading the date, then the errorCB callback is invoked. +* +* @param {Date} date +* @param {Function} successCB +* @param {Function} errorCB +* +* @return Object.dst {Boolean}: The value "true" indicates that daylight savings time is +* in effect for the given date and "false" indicate that it is not. +* +* @error GlobalizationError.UNKNOWN_ERROR +* +* Example +* globalization.isDayLightSavingsTime(new Date(), +* function (date) {alert('dst:' + date.dst + '\n');} +* function () {}); +*/ +isDayLightSavingsTime:function(date, successCB, failureCB) { + argscheck.checkArgs('dfF', 'Globalization.isDayLightSavingsTime', arguments); + var dateValue = date.valueOf(); + exec(successCB, failureCB, "Globalization", "isDayLightSavingsTime", [{"date": dateValue}]); +}, + +/** +* Returns the first day of the week according to the client's user preferences and calendar. +* The days of the week are numbered starting from 1 where 1 is considered to be Sunday. +* It returns the day to the successCB callback with a properties object as a parameter. +* If there is an error obtaining the pattern, then the errorCB callback is invoked. +* +* @param {Function} successCB +* @param {Function} errorCB +* +* @return Object.value {Number}: The number of the first day of the week. +* +* @error GlobalizationError.UNKNOWN_ERROR +* +* Example +* globalization.getFirstDayOfWeek(function (day) +* { alert('Day:' + day.value + '\n');}, +* function () {}); +*/ +getFirstDayOfWeek:function(successCB, failureCB) { + argscheck.checkArgs('fF', 'Globalization.getFirstDayOfWeek', arguments); + exec(successCB, failureCB, "Globalization", "getFirstDayOfWeek", []); +}, + + +/** +* Returns a number formatted as a string according to the client's user preferences. +* It returns the formatted number string to the successCB callback with a properties object as a +* parameter. If there is an error formatting the number, then the errorCB callback is invoked. +* +* The defaults are: type="decimal" +* +* @param {Number} number +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* type {String}: 'decimal', "percent", or 'currency' +* +* @return Object.value {String}: The formatted number string. +* +* @error GlobalizationError.FORMATTING_ERROR +* +* Example +* globalization.numberToString(3.25, +* function (number) {alert('number:' + number.value + '\n');}, +* function () {}, +* {type:'decimal'}); +*/ +numberToString:function(number, successCB, failureCB, options) { + argscheck.checkArgs('nfFO', 'Globalization.numberToString', arguments); + exec(successCB, failureCB, "Globalization", "numberToString", [{"number": number, "options": options}]); +}, + +/** +* Parses a number formatted as a string according to the client's user preferences and +* returns the corresponding number. It returns the number to the successCB callback with a +* properties object as a parameter. If there is an error parsing the number string, then +* the errorCB callback is invoked. +* +* The defaults are: type="decimal" +* +* @param {String} numberString +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* type {String}: 'decimal', "percent", or 'currency' +* +* @return Object.value {Number}: The parsed number. +* +* @error GlobalizationError.PARSING_ERROR +* +* Example +* globalization.stringToNumber('1234.56', +* function (number) {alert('Number:' + number.value + '\n');}, +* function () { alert('Error parsing number');}); +*/ +stringToNumber:function(numberString, successCB, failureCB, options) { + argscheck.checkArgs('sfFO', 'Globalization.stringToNumber', arguments); + exec(successCB, failureCB, "Globalization", "stringToNumber", [{"numberString": numberString, "options": options}]); +}, + +/** +* Returns a pattern string for formatting and parsing numbers according to the client's user +* preferences. It returns the pattern to the successCB callback with a properties object as a +* parameter. If there is an error obtaining the pattern, then the errorCB callback is invoked. +* +* The defaults are: type="decimal" +* +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* type {String}: 'decimal', "percent", or 'currency' +* +* @return Object.pattern {String}: The number pattern for formatting and parsing numbers. +* The patterns follow Unicode Technical Standard #35. +* http://unicode.org/reports/tr35/tr35-4.html +* Object.symbol {String}: The symbol to be used when formatting and parsing +* e.g., percent or currency symbol. +* Object.fraction {Number}: The number of fractional digits to use when parsing and +* formatting numbers. +* Object.rounding {Number}: The rounding increment to use when parsing and formatting. +* Object.positive {String}: The symbol to use for positive numbers when parsing and formatting. +* Object.negative: {String}: The symbol to use for negative numbers when parsing and formatting. +* Object.decimal: {String}: The decimal symbol to use for parsing and formatting. +* Object.grouping: {String}: The grouping symbol to use for parsing and formatting. +* +* @error GlobalizationError.PATTERN_ERROR +* +* Example +* globalization.getNumberPattern( +* function (pattern) {alert('Pattern:' + pattern.pattern + '\n');}, +* function () {}); +*/ +getNumberPattern:function(successCB, failureCB, options) { + argscheck.checkArgs('fFO', 'Globalization.getNumberPattern', arguments); + exec(successCB, failureCB, "Globalization", "getNumberPattern", [{"options": options}]); +}, + +/** +* Returns a pattern string for formatting and parsing currency values according to the client's +* user preferences and ISO 4217 currency code. It returns the pattern to the successCB callback with a +* properties object as a parameter. If there is an error obtaining the pattern, then the errorCB +* callback is invoked. +* +* @param {String} currencyCode +* @param {Function} successCB +* @param {Function} errorCB +* +* @return Object.pattern {String}: The currency pattern for formatting and parsing currency values. +* The patterns follow Unicode Technical Standard #35 +* http://unicode.org/reports/tr35/tr35-4.html +* Object.code {String}: The ISO 4217 currency code for the pattern. +* Object.fraction {Number}: The number of fractional digits to use when parsing and +* formatting currency. +* Object.rounding {Number}: The rounding increment to use when parsing and formatting. +* Object.decimal: {String}: The decimal symbol to use for parsing and formatting. +* Object.grouping: {String}: The grouping symbol to use for parsing and formatting. +* +* @error GlobalizationError.FORMATTING_ERROR +* +* Example +* globalization.getCurrencyPattern('EUR', +* function (currency) {alert('Pattern:' + currency.pattern + '\n');} +* function () {}); +*/ +getCurrencyPattern:function(currencyCode, successCB, failureCB) { + argscheck.checkArgs('sfF', 'Globalization.getCurrencyPattern', arguments); + exec(successCB, failureCB, "Globalization", "getCurrencyPattern", [{"currencyCode": currencyCode}]); +} + +}; + +module.exports = globalization; + +}); + +// file: lib/common/plugin/globalization/symbols.js +define("cordova/plugin/globalization/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/globalization', 'navigator.globalization'); +modulemapper.clobbers('cordova/plugin/GlobalizationError', 'GlobalizationError'); + +}); + +// file: lib/android/plugin/inappbrowser/symbols.js +define("cordova/plugin/inappbrowser/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/InAppBrowser', 'open'); + +}); + +// file: lib/common/plugin/logger.js +define("cordova/plugin/logger", function(require, exports, module) { + +//------------------------------------------------------------------------------ +// The logger module exports the following properties/functions: +// +// LOG - constant for the level LOG +// ERROR - constant for the level ERROR +// WARN - constant for the level WARN +// INFO - constant for the level INFO +// DEBUG - constant for the level DEBUG +// logLevel() - returns current log level +// logLevel(value) - sets and returns a new log level +// useConsole() - returns whether logger is using console +// useConsole(value) - sets and returns whether logger is using console +// log(message,...) - logs a message at level LOG +// error(message,...) - logs a message at level ERROR +// warn(message,...) - logs a message at level WARN +// info(message,...) - logs a message at level INFO +// debug(message,...) - logs a message at level DEBUG +// logLevel(level,message,...) - logs a message specified level +// +//------------------------------------------------------------------------------ + +var logger = exports; + +var exec = require('cordova/exec'); +var utils = require('cordova/utils'); + +var UseConsole = true; +var UseLogger = true; +var Queued = []; +var DeviceReady = false; +var CurrentLevel; + +var originalConsole = console; + +/** + * Logging levels + */ + +var Levels = [ + "LOG", + "ERROR", + "WARN", + "INFO", + "DEBUG" +]; + +/* + * add the logging levels to the logger object and + * to a separate levelsMap object for testing + */ + +var LevelsMap = {}; +for (var i=0; i CurrentLevel) return; + + // queue the message if not yet at deviceready + if (!DeviceReady && !UseConsole) { + Queued.push([level, message]); + return; + } + + // Log using the native logger if that is enabled + if (UseLogger) { + exec(null, null, "Logger", "logLevel", [level, message]); + } + + // Log using the console if that is enabled + if (UseConsole) { + // make sure console is not using logger + if (console.__usingCordovaLogger) { + throw new Error("console and logger are too intertwingly"); + } + + // log to the console + switch (level) { + case logger.LOG: originalConsole.log(message); break; + case logger.ERROR: originalConsole.log("ERROR: " + message); break; + case logger.WARN: originalConsole.log("WARN: " + message); break; + case logger.INFO: originalConsole.log("INFO: " + message); break; + case logger.DEBUG: originalConsole.log("DEBUG: " + message); break; + } + } +}; + + +/** + * Formats a string and arguments following it ala console.log() + * + * Any remaining arguments will be appended to the formatted string. + * + * for rationale, see FireBug's Console API: + * http://getfirebug.com/wiki/index.php/Console_API + */ +logger.format = function(formatString, args) { + return __format(arguments[0], [].slice.call(arguments,1)).join(' '); +}; + + +//------------------------------------------------------------------------------ +/** + * Formats a string and arguments following it ala vsprintf() + * + * format chars: + * %j - format arg as JSON + * %o - format arg as JSON + * %c - format arg as '' + * %% - replace with '%' + * any other char following % will format it's + * arg via toString(). + * + * Returns an array containing the formatted string and any remaining + * arguments. + */ +function __format(formatString, args) { + if (formatString === null || formatString === undefined) return [""]; + if (arguments.length == 1) return [formatString.toString()]; + + if (typeof formatString != "string") + formatString = formatString.toString(); + + var pattern = /(.*?)%(.)(.*)/; + var rest = formatString; + var result = []; + + while (args.length) { + var match = pattern.exec(rest); + if (!match) break; + + var arg = args.shift(); + rest = match[3]; + result.push(match[1]); + + if (match[2] == '%') { + result.push('%'); + args.unshift(arg); + continue; + } + + result.push(__formatted(arg, match[2])); + } + + result.push(rest); + + var remainingArgs = [].slice.call(args); + remainingArgs.unshift(result.join('')); + return remainingArgs; +} + +function __formatted(object, formatChar) { + + try { + switch(formatChar) { + case 'j': + case 'o': return JSON.stringify(object); + case 'c': return ''; + } + } + catch (e) { + return "error JSON.stringify()ing argument: " + e; + } + + if ((object === null) || (object === undefined)) { + return Object.prototype.toString.call(object); + } + + return object.toString(); +} + + +//------------------------------------------------------------------------------ +// when deviceready fires, log queued messages +logger.__onDeviceReady = function() { + if (DeviceReady) return; + + DeviceReady = true; + + for (var i=0; i 3) { + fail(FileError.SYNTAX_ERR); + } else { + // if successful, return a FileSystem object + var success = function(file_system) { + if (file_system) { + if (successCallback) { + // grab the name and root from the file system object + var result = new FileSystem(file_system.name, file_system.root); + successCallback(result); + } + } + else { + // no FileSystem object returned + fail(FileError.NOT_FOUND_ERR); + } + }; + exec(success, fail, "File", "requestFileSystem", [type, size]); + } +}; + +module.exports = requestFileSystem; + +}); + +// file: lib/common/plugin/resolveLocalFileSystemURI.js +define("cordova/plugin/resolveLocalFileSystemURI", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + DirectoryEntry = require('cordova/plugin/DirectoryEntry'), + FileEntry = require('cordova/plugin/FileEntry'), + FileError = require('cordova/plugin/FileError'), + exec = require('cordova/exec'); + +/** + * Look up file system Entry referred to by local URI. + * @param {DOMString} uri URI referring to a local file or directory + * @param successCallback invoked with Entry object corresponding to URI + * @param errorCallback invoked if error occurs retrieving file system entry + */ +module.exports = function(uri, successCallback, errorCallback) { + argscheck.checkArgs('sFF', 'resolveLocalFileSystemURI', arguments); + // error callback + var fail = function(error) { + errorCallback && errorCallback(new FileError(error)); + }; + // sanity check for 'not:valid:filename' + if(!uri || uri.split(":").length > 2) { + setTimeout( function() { + fail(FileError.ENCODING_ERR); + },0); + return; + } + // if successful, return either a file or directory entry + var success = function(entry) { + var result; + if (entry) { + if (successCallback) { + // create appropriate Entry object + result = (entry.isDirectory) ? new DirectoryEntry(entry.name, entry.fullPath) : new FileEntry(entry.name, entry.fullPath); + successCallback(result); + } + } + else { + // no Entry object returned + fail(FileError.NOT_FOUND_ERR); + } + }; + + exec(success, fail, "File", "resolveLocalFileSystemURI", [uri]); +}; + +}); + +// file: lib/common/plugin/splashscreen.js +define("cordova/plugin/splashscreen", function(require, exports, module) { + +var exec = require('cordova/exec'); + +var splashscreen = { + show:function() { + exec(null, null, "SplashScreen", "show", []); + }, + hide:function() { + exec(null, null, "SplashScreen", "hide", []); + } +}; + +module.exports = splashscreen; + +}); + +// file: lib/common/plugin/splashscreen/symbols.js +define("cordova/plugin/splashscreen/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/splashscreen', 'navigator.splashscreen'); + +}); + +// file: lib/common/symbols.js +define("cordova/symbols", function(require, exports, module) { + +var modulemapper = require('cordova/modulemapper'); + +// Use merges here in case others symbols files depend on this running first, +// but fail to declare the dependency with a require(). +modulemapper.merges('cordova', 'cordova'); +modulemapper.clobbers('cordova/exec', 'cordova.exec'); +modulemapper.clobbers('cordova/exec', 'Cordova.exec'); + +}); + +// file: lib/common/utils.js +define("cordova/utils", function(require, exports, module) { + +var utils = exports; + +/** + * Defines a property getter / setter for obj[key]. + */ +utils.defineGetterSetter = function(obj, key, getFunc, opt_setFunc) { + if (Object.defineProperty) { + var desc = { + get: getFunc, + configurable: true + }; + if (opt_setFunc) { + desc.set = opt_setFunc; + } + Object.defineProperty(obj, key, desc); + } else { + obj.__defineGetter__(key, getFunc); + if (opt_setFunc) { + obj.__defineSetter__(key, opt_setFunc); + } + } +}; + +/** + * Defines a property getter for obj[key]. + */ +utils.defineGetter = utils.defineGetterSetter; + +utils.arrayIndexOf = function(a, item) { + if (a.indexOf) { + return a.indexOf(item); + } + var len = a.length; + for (var i = 0; i < len; ++i) { + if (a[i] == item) { + return i; + } + } + return -1; +}; + +/** + * Returns whether the item was found in the array. + */ +utils.arrayRemove = function(a, item) { + var index = utils.arrayIndexOf(a, item); + if (index != -1) { + a.splice(index, 1); + } + return index != -1; +}; + +utils.typeName = function(val) { + return Object.prototype.toString.call(val).slice(8, -1); +}; + +/** + * Returns an indication of whether the argument is an array or not + */ +utils.isArray = function(a) { + return utils.typeName(a) == 'Array'; +}; + +/** + * Returns an indication of whether the argument is a Date or not + */ +utils.isDate = function(d) { + return utils.typeName(d) == 'Date'; +}; + +/** + * Does a deep clone of the object. + */ +utils.clone = function(obj) { + if(!obj || typeof obj == 'function' || utils.isDate(obj) || typeof obj != 'object') { + return obj; + } + + var retVal, i; + + if(utils.isArray(obj)){ + retVal = []; + for(i = 0; i < obj.length; ++i){ + retVal.push(utils.clone(obj[i])); + } + return retVal; + } + + retVal = {}; + for(i in obj){ + if(!(i in retVal) || retVal[i] != obj[i]) { + retVal[i] = utils.clone(obj[i]); + } + } + return retVal; +}; + +/** + * Returns a wrapped version of the function + */ +utils.close = function(context, func, params) { + if (typeof params == 'undefined') { + return function() { + return func.apply(context, arguments); + }; + } else { + return function() { + return func.apply(context, params); + }; + } +}; + +/** + * Create a UUID + */ +utils.createUUID = function() { + return UUIDcreatePart(4) + '-' + + UUIDcreatePart(2) + '-' + + UUIDcreatePart(2) + '-' + + UUIDcreatePart(2) + '-' + + UUIDcreatePart(6); +}; + +/** + * Extends a child object from a parent object using classical inheritance + * pattern. + */ +utils.extend = (function() { + // proxy used to establish prototype chain + var F = function() {}; + // extend Child from Parent + return function(Child, Parent) { + F.prototype = Parent.prototype; + Child.prototype = new F(); + Child.__super__ = Parent.prototype; + Child.prototype.constructor = Child; + }; +}()); + +/** + * Alerts a message in any available way: alert or console.log. + */ +utils.alert = function(msg) { + if (window.alert) { + window.alert(msg); + } else if (console && console.log) { + console.log(msg); + } +}; + + +//------------------------------------------------------------------------------ +function UUIDcreatePart(length) { + var uuidpart = ""; + for (var i=0; i tag. + function injectScript(path) { + scriptCounter++; + var script = document.createElement("script"); + script.onload = scriptLoadedCallback; + script.onerror = scriptErrorCallback; + script.src = path; + document.head.appendChild(script); + } + + // Called when: + // * There are plugins defined and all plugins are finished loading. + // * There are no plugins to load. + function finishPluginLoading() { + context.cordova.require('cordova/channel').onPluginsReady.fire(); + } + + // Handler for the cordova_plugins.js content. + // See plugman's plugin_loader.js for the details of this object. + // This function is only called if the really is a plugins array that isn't empty. + // Otherwise the onerror response handler will just call finishPluginLoading(). + function handlePluginsObject(modules, path) { + // First create the callback for when all plugins are loaded. + var mapper = context.cordova.require('cordova/modulemapper'); + onScriptLoadingComplete = function() { + // Loop through all the plugins and then through their clobbers and merges. + for (var i = 0; i < modules.length; i++) { + var module = modules[i]; + if (module) { + try { + if (module.clobbers && module.clobbers.length) { + for (var j = 0; j < module.clobbers.length; j++) { + mapper.clobbers(module.id, module.clobbers[j]); + } + } + + if (module.merges && module.merges.length) { + for (var k = 0; k < module.merges.length; k++) { + mapper.merges(module.id, module.merges[k]); + } + } + + // Finally, if runs is truthy we want to simply require() the module. + // This can be skipped if it had any merges or clobbers, though, + // since the mapper will already have required the module. + if (module.runs && !(module.clobbers && module.clobbers.length) && !(module.merges && module.merges.length)) { + context.cordova.require(module.id); + } + } + catch(err) { + // error with module, most likely clobbers, should we continue? + } + } + } + + finishPluginLoading(); + }; + + // Now inject the scripts. + for (var i = 0; i < modules.length; i++) { + injectScript(path + modules[i].file); + } + } + + // Find the root of the app + var path = ''; + var scripts = document.getElementsByTagName('script'); + var term = 'cordova.js'; + for (var n = scripts.length-1; n>-1; n--) { + var src = scripts[n].src; + if (src.indexOf(term) == (src.length - term.length)) { + path = src.substring(0, src.length - term.length); + break; + } + } + + var plugins_json = path + 'cordova_plugins.json'; + var plugins_js = path + 'cordova_plugins.js'; + + // One some phones (Windows) this xhr.open throws an Access Denied exception + // So lets keep trying, but with a script tag injection technique instead of XHR + var injectPluginScript = function injectPluginScript() { + try { + var script = document.createElement("script"); + script.onload = function(){ + var list = cordova.require("cordova/plugin_list"); + handlePluginsObject(list,path); + }; + script.onerror = function() { + // Error loading cordova_plugins.js, file not found or something + // this is an acceptable error, pre-3.0.0, so we just move on. + finishPluginLoading(); + }; + script.src = plugins_js; + document.head.appendChild(script); + + } catch(err){ + finishPluginLoading(); + } + } + + + // Try to XHR the cordova_plugins.json file asynchronously. + var xhr = new XMLHttpRequest(); + xhr.onload = function() { + // If the response is a JSON string which composes an array, call handlePluginsObject. + // If the request fails, or the response is not a JSON array, just call finishPluginLoading. + var obj; + try { + obj = (this.status == 0 || this.status == 200) && this.responseText && JSON.parse(this.responseText); + } catch (err) { + // obj will be undefined. + } + if (Array.isArray(obj) && obj.length > 0) { + handlePluginsObject(obj, path); + } else { + finishPluginLoading(); + } + }; + xhr.onerror = function() { + // In this case, the json file was not present, but XHR was allowed, + // so we should still try the script injection technique with the js file + // in case that is there. + injectPluginScript(); + }; + try { // we commented we were going to try, so let us actually try and catch + xhr.open('GET', plugins_json, true); // Async + xhr.send(); + } catch(err){ + injectPluginScript(); + } +}(window)); + + +})();var PhoneGap = cordova; diff --git a/catapp/js/iscroll.js b/catapp/js/iscroll.js new file mode 100644 index 0000000..8222de0 --- /dev/null +++ b/catapp/js/iscroll.js @@ -0,0 +1,1104 @@ +/*! + * iScroll v4.2.5 ~ Copyright (c) 2012 Matteo Spinelli, http://cubiq.org + * Released under MIT license, http://cubiq.org/license + */ +(function(window, doc){ +var m = Math, + dummyStyle = doc.createElement('div').style, + vendor = (function () { + var vendors = 't,webkitT,MozT,msT,OT'.split(','), + t, + i = 0, + l = vendors.length; + + for ( ; i < l; i++ ) { + t = vendors[i] + 'ransform'; + if ( t in dummyStyle ) { + return vendors[i].substr(0, vendors[i].length - 1); + } + } + + return false; + })(), + cssVendor = vendor ? '-' + vendor.toLowerCase() + '-' : '', + + // Style properties + transform = prefixStyle('transform'), + transitionProperty = prefixStyle('transitionProperty'), + transitionDuration = prefixStyle('transitionDuration'), + transformOrigin = prefixStyle('transformOrigin'), + transitionTimingFunction = prefixStyle('transitionTimingFunction'), + transitionDelay = prefixStyle('transitionDelay'), + + // Browser capabilities + isAndroid = (/android/gi).test(navigator.appVersion), + isIDevice = (/iphone|ipad/gi).test(navigator.appVersion), + isTouchPad = (/hp-tablet/gi).test(navigator.appVersion), + + has3d = prefixStyle('perspective') in dummyStyle, + hasTouch = 'ontouchstart' in window && !isTouchPad, + hasTransform = vendor !== false, + hasTransitionEnd = prefixStyle('transition') in dummyStyle, + + RESIZE_EV = 'onorientationchange' in window ? 'orientationchange' : 'resize', + START_EV = hasTouch ? 'touchstart' : 'mousedown', + MOVE_EV = hasTouch ? 'touchmove' : 'mousemove', + END_EV = hasTouch ? 'touchend' : 'mouseup', + CANCEL_EV = hasTouch ? 'touchcancel' : 'mouseup', + TRNEND_EV = (function () { + if ( vendor === false ) return false; + + var transitionEnd = { + '' : 'transitionend', + 'webkit' : 'webkitTransitionEnd', + 'Moz' : 'transitionend', + 'O' : 'otransitionend', + 'ms' : 'MSTransitionEnd' + }; + + return transitionEnd[vendor]; + })(), + + nextFrame = (function() { + return window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function(callback) { return setTimeout(callback, 1); }; + })(), + cancelFrame = (function () { + return window.cancelRequestAnimationFrame || + window.webkitCancelAnimationFrame || + window.webkitCancelRequestAnimationFrame || + window.mozCancelRequestAnimationFrame || + window.oCancelRequestAnimationFrame || + window.msCancelRequestAnimationFrame || + clearTimeout; + })(), + + // Helpers + translateZ = has3d ? ' translateZ(0)' : '', + + // Constructor + iScroll = function (el, options) { + var that = this, + i; + + that.wrapper = typeof el == 'object' ? el : doc.getElementById(el); + that.wrapper.style.overflow = 'hidden'; + that.scroller = that.wrapper.children[0]; + + // Default options + that.options = { + hScroll: true, + vScroll: true, + x: 0, + y: 0, + bounce: true, + bounceLock: false, + momentum: true, + lockDirection: true, + useTransform: true, + useTransition: false, + topOffset: 0, + checkDOMChanges: false, // Experimental + handleClick: true, + + // Scrollbar + hScrollbar: true, + vScrollbar: true, + fixedScrollbar: isAndroid, + hideScrollbar: isIDevice, + fadeScrollbar: isIDevice && has3d, + scrollbarClass: '', + + // Zoom + zoom: false, + zoomMin: 1, + zoomMax: 4, + doubleTapZoom: 2, + wheelAction: 'scroll', + + // Snap + snap: false, + snapThreshold: 1, + + // Events + onRefresh: null, + onBeforeScrollStart: function (e) { e.preventDefault(); }, + onScrollStart: null, + onBeforeScrollMove: null, + onScrollMove: null, + onBeforeScrollEnd: null, + onScrollEnd: null, + onTouchEnd: null, + onDestroy: null, + onZoomStart: null, + onZoom: null, + onZoomEnd: null + }; + + // User defined options + for (i in options) that.options[i] = options[i]; + + // Set starting position + that.x = that.options.x; + that.y = that.options.y; + + // Normalize options + that.options.useTransform = hasTransform && that.options.useTransform; + that.options.hScrollbar = that.options.hScroll && that.options.hScrollbar; + that.options.vScrollbar = that.options.vScroll && that.options.vScrollbar; + that.options.zoom = that.options.useTransform && that.options.zoom; + that.options.useTransition = hasTransitionEnd && that.options.useTransition; + + // Helpers FIX ANDROID BUG! + // translate3d and scale doesn't work together! + // Ignoring 3d ONLY WHEN YOU SET that.options.zoom + if ( that.options.zoom && isAndroid ){ + translateZ = ''; + } + + // Set some default styles + that.scroller.style[transitionProperty] = that.options.useTransform ? cssVendor + 'transform' : 'top left'; + that.scroller.style[transitionDuration] = '0'; + that.scroller.style[transformOrigin] = '0 0'; + if (that.options.useTransition) that.scroller.style[transitionTimingFunction] = 'cubic-bezier(0.33,0.66,0.66,1)'; + + if (that.options.useTransform) that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px)' + translateZ; + else that.scroller.style.cssText += ';position:absolute;top:' + that.y + 'px;left:' + that.x + 'px'; + + if (that.options.useTransition) that.options.fixedScrollbar = true; + + that.refresh(); + + that._bind(RESIZE_EV, window); + that._bind(START_EV); + if (!hasTouch) { + if (that.options.wheelAction != 'none') { + that._bind('DOMMouseScroll'); + that._bind('mousewheel'); + } + } + + if (that.options.checkDOMChanges) that.checkDOMTime = setInterval(function () { + that._checkDOMChanges(); + }, 500); + }; + +// Prototype +iScroll.prototype = { + enabled: true, + x: 0, + y: 0, + steps: [], + scale: 1, + currPageX: 0, currPageY: 0, + pagesX: [], pagesY: [], + aniTime: null, + wheelZoomCount: 0, + + handleEvent: function (e) { + var that = this; + switch(e.type) { + case START_EV: + if (!hasTouch && e.button !== 0) return; + that._start(e); + break; + case MOVE_EV: that._move(e); break; + case END_EV: + case CANCEL_EV: that._end(e); break; + case RESIZE_EV: that._resize(); break; + case 'DOMMouseScroll': case 'mousewheel': that._wheel(e); break; + case TRNEND_EV: that._transitionEnd(e); break; + } + }, + + _checkDOMChanges: function () { + if (this.moved || this.zoomed || this.animating || + (this.scrollerW == this.scroller.offsetWidth * this.scale && this.scrollerH == this.scroller.offsetHeight * this.scale)) return; + + this.refresh(); + }, + + _scrollbar: function (dir) { + var that = this, + bar; + + if (!that[dir + 'Scrollbar']) { + if (that[dir + 'ScrollbarWrapper']) { + if (hasTransform) that[dir + 'ScrollbarIndicator'].style[transform] = ''; + that[dir + 'ScrollbarWrapper'].parentNode.removeChild(that[dir + 'ScrollbarWrapper']); + that[dir + 'ScrollbarWrapper'] = null; + that[dir + 'ScrollbarIndicator'] = null; + } + + return; + } + + if (!that[dir + 'ScrollbarWrapper']) { + // Create the scrollbar wrapper + bar = doc.createElement('div'); + + if (that.options.scrollbarClass) bar.className = that.options.scrollbarClass + dir.toUpperCase(); + else bar.style.cssText = 'position:absolute;z-index:100;' + (dir == 'h' ? 'height:7px;bottom:1px;left:2px;right:' + (that.vScrollbar ? '7' : '2') + 'px' : 'width:7px;bottom:' + (that.hScrollbar ? '7' : '2') + 'px;top:2px;right:1px'); + + bar.style.cssText += ';pointer-events:none;' + cssVendor + 'transition-property:opacity;' + cssVendor + 'transition-duration:' + (that.options.fadeScrollbar ? '350ms' : '0') + ';overflow:hidden;opacity:' + (that.options.hideScrollbar ? '0' : '1'); + + that.wrapper.appendChild(bar); + that[dir + 'ScrollbarWrapper'] = bar; + + // Create the scrollbar indicator + bar = doc.createElement('div'); + if (!that.options.scrollbarClass) { + bar.style.cssText = 'position:absolute;z-index:100;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);' + cssVendor + 'background-clip:padding-box;' + cssVendor + 'box-sizing:border-box;' + (dir == 'h' ? 'height:100%' : 'width:100%') + ';' + cssVendor + 'border-radius:3px;border-radius:3px'; + } + bar.style.cssText += ';pointer-events:none;' + cssVendor + 'transition-property:' + cssVendor + 'transform;' + cssVendor + 'transition-timing-function:cubic-bezier(0.33,0.66,0.66,1);' + cssVendor + 'transition-duration:0;' + cssVendor + 'transform: translate(0,0)' + translateZ; + if (that.options.useTransition) bar.style.cssText += ';' + cssVendor + 'transition-timing-function:cubic-bezier(0.33,0.66,0.66,1)'; + + that[dir + 'ScrollbarWrapper'].appendChild(bar); + that[dir + 'ScrollbarIndicator'] = bar; + } + + if (dir == 'h') { + that.hScrollbarSize = that.hScrollbarWrapper.clientWidth; + that.hScrollbarIndicatorSize = m.max(m.round(that.hScrollbarSize * that.hScrollbarSize / that.scrollerW), 8); + that.hScrollbarIndicator.style.width = that.hScrollbarIndicatorSize + 'px'; + that.hScrollbarMaxScroll = that.hScrollbarSize - that.hScrollbarIndicatorSize; + that.hScrollbarProp = that.hScrollbarMaxScroll / that.maxScrollX; + } else { + that.vScrollbarSize = that.vScrollbarWrapper.clientHeight; + that.vScrollbarIndicatorSize = m.max(m.round(that.vScrollbarSize * that.vScrollbarSize / that.scrollerH), 8); + that.vScrollbarIndicator.style.height = that.vScrollbarIndicatorSize + 'px'; + that.vScrollbarMaxScroll = that.vScrollbarSize - that.vScrollbarIndicatorSize; + that.vScrollbarProp = that.vScrollbarMaxScroll / that.maxScrollY; + } + + // Reset position + that._scrollbarPos(dir, true); + }, + + _resize: function () { + var that = this; + setTimeout(function () { that.refresh(); }, isAndroid ? 200 : 0); + }, + + _pos: function (x, y) { + if (this.zoomed) return; + + x = this.hScroll ? x : 0; + y = this.vScroll ? y : 0; + + if (this.options.useTransform) { + this.scroller.style[transform] = 'translate(' + x + 'px,' + y + 'px) scale(' + this.scale + ')' + translateZ; + } else { + x = m.round(x); + y = m.round(y); + this.scroller.style.left = x + 'px'; + this.scroller.style.top = y + 'px'; + } + + this.x = x; + this.y = y; + + this._scrollbarPos('h'); + this._scrollbarPos('v'); + }, + + _scrollbarPos: function (dir, hidden) { + var that = this, + pos = dir == 'h' ? that.x : that.y, + size; + + if (!that[dir + 'Scrollbar']) return; + + pos = that[dir + 'ScrollbarProp'] * pos; + + if (pos < 0) { + if (!that.options.fixedScrollbar) { + size = that[dir + 'ScrollbarIndicatorSize'] + m.round(pos * 3); + if (size < 8) size = 8; + that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px'; + } + pos = 0; + } else if (pos > that[dir + 'ScrollbarMaxScroll']) { + if (!that.options.fixedScrollbar) { + size = that[dir + 'ScrollbarIndicatorSize'] - m.round((pos - that[dir + 'ScrollbarMaxScroll']) * 3); + if (size < 8) size = 8; + that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px'; + pos = that[dir + 'ScrollbarMaxScroll'] + (that[dir + 'ScrollbarIndicatorSize'] - size); + } else { + pos = that[dir + 'ScrollbarMaxScroll']; + } + } + + that[dir + 'ScrollbarWrapper'].style[transitionDelay] = '0'; + that[dir + 'ScrollbarWrapper'].style.opacity = hidden && that.options.hideScrollbar ? '0' : '1'; + that[dir + 'ScrollbarIndicator'].style[transform] = 'translate(' + (dir == 'h' ? pos + 'px,0)' : '0,' + pos + 'px)') + translateZ; + }, + + _start: function (e) { + var that = this, + point = hasTouch ? e.touches[0] : e, + matrix, x, y, + c1, c2; + + if (!that.enabled) return; + + if (that.options.onBeforeScrollStart) that.options.onBeforeScrollStart.call(that, e); + + if (that.options.useTransition || that.options.zoom) that._transitionTime(0); + + that.moved = false; + that.animating = false; + that.zoomed = false; + that.distX = 0; + that.distY = 0; + that.absDistX = 0; + that.absDistY = 0; + that.dirX = 0; + that.dirY = 0; + + // Gesture start + if (that.options.zoom && hasTouch && e.touches.length > 1) { + c1 = m.abs(e.touches[0].pageX-e.touches[1].pageX); + c2 = m.abs(e.touches[0].pageY-e.touches[1].pageY); + that.touchesDistStart = m.sqrt(c1 * c1 + c2 * c2); + + that.originX = m.abs(e.touches[0].pageX + e.touches[1].pageX - that.wrapperOffsetLeft * 2) / 2 - that.x; + that.originY = m.abs(e.touches[0].pageY + e.touches[1].pageY - that.wrapperOffsetTop * 2) / 2 - that.y; + + if (that.options.onZoomStart) that.options.onZoomStart.call(that, e); + } + + if (that.options.momentum) { + if (that.options.useTransform) { + // Very lame general purpose alternative to CSSMatrix + matrix = getComputedStyle(that.scroller, null)[transform].replace(/[^0-9\-.,]/g, '').split(','); + x = +(matrix[12] || matrix[4]); + y = +(matrix[13] || matrix[5]); + } else { + x = +getComputedStyle(that.scroller, null).left.replace(/[^0-9-]/g, ''); + y = +getComputedStyle(that.scroller, null).top.replace(/[^0-9-]/g, ''); + } + + if (x != that.x || y != that.y) { + if (that.options.useTransition) that._unbind(TRNEND_EV); + else cancelFrame(that.aniTime); + that.steps = []; + that._pos(x, y); + if (that.options.onScrollEnd) that.options.onScrollEnd.call(that); + } + } + + that.absStartX = that.x; // Needed by snap threshold + that.absStartY = that.y; + + that.startX = that.x; + that.startY = that.y; + that.pointX = point.pageX; + that.pointY = point.pageY; + + that.startTime = e.timeStamp || Date.now(); + + if (that.options.onScrollStart) that.options.onScrollStart.call(that, e); + + that._bind(MOVE_EV, window); + that._bind(END_EV, window); + that._bind(CANCEL_EV, window); + }, + + _move: function (e) { + var that = this, + point = hasTouch ? e.touches[0] : e, + deltaX = point.pageX - that.pointX, + deltaY = point.pageY - that.pointY, + newX = that.x + deltaX, + newY = that.y + deltaY, + c1, c2, scale, + timestamp = e.timeStamp || Date.now(); + + if (that.options.onBeforeScrollMove) that.options.onBeforeScrollMove.call(that, e); + + // Zoom + if (that.options.zoom && hasTouch && e.touches.length > 1) { + c1 = m.abs(e.touches[0].pageX - e.touches[1].pageX); + c2 = m.abs(e.touches[0].pageY - e.touches[1].pageY); + that.touchesDist = m.sqrt(c1*c1+c2*c2); + + that.zoomed = true; + + scale = 1 / that.touchesDistStart * that.touchesDist * this.scale; + + if (scale < that.options.zoomMin) scale = 0.5 * that.options.zoomMin * Math.pow(2.0, scale / that.options.zoomMin); + else if (scale > that.options.zoomMax) scale = 2.0 * that.options.zoomMax * Math.pow(0.5, that.options.zoomMax / scale); + + that.lastScale = scale / this.scale; + + newX = this.originX - this.originX * that.lastScale + this.x; + newY = this.originY - this.originY * that.lastScale + this.y; + + this.scroller.style[transform] = 'translate(' + newX + 'px,' + newY + 'px) scale(' + scale + ')' + translateZ; + + if (that.options.onZoom) that.options.onZoom.call(that, e); + return; + } + + that.pointX = point.pageX; + that.pointY = point.pageY; + + // Slow down if outside of the boundaries + if (newX > 0 || newX < that.maxScrollX) { + newX = that.options.bounce ? that.x + (deltaX / 2) : newX >= 0 || that.maxScrollX >= 0 ? 0 : that.maxScrollX; + } + if (newY > that.minScrollY || newY < that.maxScrollY) { + newY = that.options.bounce ? that.y + (deltaY / 2) : newY >= that.minScrollY || that.maxScrollY >= 0 ? that.minScrollY : that.maxScrollY; + } + + that.distX += deltaX; + that.distY += deltaY; + that.absDistX = m.abs(that.distX); + that.absDistY = m.abs(that.distY); + + if (that.absDistX < 6 && that.absDistY < 6) { + return; + } + + // Lock direction + if (that.options.lockDirection) { + if (that.absDistX > that.absDistY + 5) { + newY = that.y; + deltaY = 0; + } else if (that.absDistY > that.absDistX + 5) { + newX = that.x; + deltaX = 0; + } + } + + that.moved = true; + that._pos(newX, newY); + that.dirX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0; + that.dirY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0; + + if (timestamp - that.startTime > 300) { + that.startTime = timestamp; + that.startX = that.x; + that.startY = that.y; + } + + if (that.options.onScrollMove) that.options.onScrollMove.call(that, e); + }, + + _end: function (e) { + if (hasTouch && e.touches.length !== 0) return; + + var that = this, + point = hasTouch ? e.changedTouches[0] : e, + target, ev, + momentumX = { dist:0, time:0 }, + momentumY = { dist:0, time:0 }, + duration = (e.timeStamp || Date.now()) - that.startTime, + newPosX = that.x, + newPosY = that.y, + distX, distY, + newDuration, + snap, + scale; + + that._unbind(MOVE_EV, window); + that._unbind(END_EV, window); + that._unbind(CANCEL_EV, window); + + if (that.options.onBeforeScrollEnd) that.options.onBeforeScrollEnd.call(that, e); + + if (that.zoomed) { + scale = that.scale * that.lastScale; + scale = Math.max(that.options.zoomMin, scale); + scale = Math.min(that.options.zoomMax, scale); + that.lastScale = scale / that.scale; + that.scale = scale; + + that.x = that.originX - that.originX * that.lastScale + that.x; + that.y = that.originY - that.originY * that.lastScale + that.y; + + that.scroller.style[transitionDuration] = '200ms'; + that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px) scale(' + that.scale + ')' + translateZ; + + that.zoomed = false; + that.refresh(); + + if (that.options.onZoomEnd) that.options.onZoomEnd.call(that, e); + return; + } + + if (!that.moved) { + if (hasTouch) { + if (that.doubleTapTimer && that.options.zoom) { + // Double tapped + clearTimeout(that.doubleTapTimer); + that.doubleTapTimer = null; + if (that.options.onZoomStart) that.options.onZoomStart.call(that, e); + that.zoom(that.pointX, that.pointY, that.scale == 1 ? that.options.doubleTapZoom : 1); + if (that.options.onZoomEnd) { + setTimeout(function() { + that.options.onZoomEnd.call(that, e); + }, 200); // 200 is default zoom duration + } + } else if (this.options.handleClick) { + that.doubleTapTimer = setTimeout(function () { + that.doubleTapTimer = null; + + // Find the last touched element + target = point.target; + while (target.nodeType != 1) target = target.parentNode; + + if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA') { + ev = doc.createEvent('MouseEvents'); + ev.initMouseEvent('click', true, true, e.view, 1, + point.screenX, point.screenY, point.clientX, point.clientY, + e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, + 0, null); + ev._fake = true; + target.dispatchEvent(ev); + } + }, that.options.zoom ? 250 : 0); + } + } + + that._resetPos(400); + + if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e); + return; + } + + if (duration < 300 && that.options.momentum) { + momentumX = newPosX ? that._momentum(newPosX - that.startX, duration, -that.x, that.scrollerW - that.wrapperW + that.x, that.options.bounce ? that.wrapperW : 0) : momentumX; + momentumY = newPosY ? that._momentum(newPosY - that.startY, duration, -that.y, (that.maxScrollY < 0 ? that.scrollerH - that.wrapperH + that.y - that.minScrollY : 0), that.options.bounce ? that.wrapperH : 0) : momentumY; + + newPosX = that.x + momentumX.dist; + newPosY = that.y + momentumY.dist; + + if ((that.x > 0 && newPosX > 0) || (that.x < that.maxScrollX && newPosX < that.maxScrollX)) momentumX = { dist:0, time:0 }; + if ((that.y > that.minScrollY && newPosY > that.minScrollY) || (that.y < that.maxScrollY && newPosY < that.maxScrollY)) momentumY = { dist:0, time:0 }; + } + + if (momentumX.dist || momentumY.dist) { + newDuration = m.max(m.max(momentumX.time, momentumY.time), 10); + + // Do we need to snap? + if (that.options.snap) { + distX = newPosX - that.absStartX; + distY = newPosY - that.absStartY; + if (m.abs(distX) < that.options.snapThreshold && m.abs(distY) < that.options.snapThreshold) { that.scrollTo(that.absStartX, that.absStartY, 200); } + else { + snap = that._snap(newPosX, newPosY); + newPosX = snap.x; + newPosY = snap.y; + newDuration = m.max(snap.time, newDuration); + } + } + + that.scrollTo(m.round(newPosX), m.round(newPosY), newDuration); + + if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e); + return; + } + + // Do we need to snap? + if (that.options.snap) { + distX = newPosX - that.absStartX; + distY = newPosY - that.absStartY; + if (m.abs(distX) < that.options.snapThreshold && m.abs(distY) < that.options.snapThreshold) that.scrollTo(that.absStartX, that.absStartY, 200); + else { + snap = that._snap(that.x, that.y); + if (snap.x != that.x || snap.y != that.y) that.scrollTo(snap.x, snap.y, snap.time); + } + + if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e); + return; + } + + that._resetPos(200); + if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e); + }, + + _resetPos: function (time) { + var that = this, + resetX = that.x >= 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x, + resetY = that.y >= that.minScrollY || that.maxScrollY > 0 ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y; + + if (resetX == that.x && resetY == that.y) { + if (that.moved) { + that.moved = false; + if (that.options.onScrollEnd) that.options.onScrollEnd.call(that); // Execute custom code on scroll end + } + + if (that.hScrollbar && that.options.hideScrollbar) { + if (vendor == 'webkit') that.hScrollbarWrapper.style[transitionDelay] = '300ms'; + that.hScrollbarWrapper.style.opacity = '0'; + } + if (that.vScrollbar && that.options.hideScrollbar) { + if (vendor == 'webkit') that.vScrollbarWrapper.style[transitionDelay] = '300ms'; + that.vScrollbarWrapper.style.opacity = '0'; + } + + return; + } + + that.scrollTo(resetX, resetY, time || 0); + }, + + _wheel: function (e) { + var that = this, + wheelDeltaX, wheelDeltaY, + deltaX, deltaY, + deltaScale; + + if ('wheelDeltaX' in e) { + wheelDeltaX = e.wheelDeltaX / 12; + wheelDeltaY = e.wheelDeltaY / 12; + } else if('wheelDelta' in e) { + wheelDeltaX = wheelDeltaY = e.wheelDelta / 12; + } else if ('detail' in e) { + wheelDeltaX = wheelDeltaY = -e.detail * 3; + } else { + return; + } + + if (that.options.wheelAction == 'zoom') { + deltaScale = that.scale * Math.pow(2, 1/3 * (wheelDeltaY ? wheelDeltaY / Math.abs(wheelDeltaY) : 0)); + if (deltaScale < that.options.zoomMin) deltaScale = that.options.zoomMin; + if (deltaScale > that.options.zoomMax) deltaScale = that.options.zoomMax; + + if (deltaScale != that.scale) { + if (!that.wheelZoomCount && that.options.onZoomStart) that.options.onZoomStart.call(that, e); + that.wheelZoomCount++; + + that.zoom(e.pageX, e.pageY, deltaScale, 400); + + setTimeout(function() { + that.wheelZoomCount--; + if (!that.wheelZoomCount && that.options.onZoomEnd) that.options.onZoomEnd.call(that, e); + }, 400); + } + + return; + } + + deltaX = that.x + wheelDeltaX; + deltaY = that.y + wheelDeltaY; + + if (deltaX > 0) deltaX = 0; + else if (deltaX < that.maxScrollX) deltaX = that.maxScrollX; + + if (deltaY > that.minScrollY) deltaY = that.minScrollY; + else if (deltaY < that.maxScrollY) deltaY = that.maxScrollY; + + if (that.maxScrollY < 0) { + that.scrollTo(deltaX, deltaY, 0); + } + }, + + _transitionEnd: function (e) { + var that = this; + + if (e.target != that.scroller) return; + + that._unbind(TRNEND_EV); + + that._startAni(); + }, + + + /** + * + * Utilities + * + */ + _startAni: function () { + var that = this, + startX = that.x, startY = that.y, + startTime = Date.now(), + step, easeOut, + animate; + + if (that.animating) return; + + if (!that.steps.length) { + that._resetPos(400); + return; + } + + step = that.steps.shift(); + + if (step.x == startX && step.y == startY) step.time = 0; + + that.animating = true; + that.moved = true; + + if (that.options.useTransition) { + that._transitionTime(step.time); + that._pos(step.x, step.y); + that.animating = false; + if (step.time) that._bind(TRNEND_EV); + else that._resetPos(0); + return; + } + + animate = function () { + var now = Date.now(), + newX, newY; + + if (now >= startTime + step.time) { + that._pos(step.x, step.y); + that.animating = false; + if (that.options.onAnimationEnd) that.options.onAnimationEnd.call(that); // Execute custom code on animation end + that._startAni(); + return; + } + + now = (now - startTime) / step.time - 1; + easeOut = m.sqrt(1 - now * now); + newX = (step.x - startX) * easeOut + startX; + newY = (step.y - startY) * easeOut + startY; + that._pos(newX, newY); + if (that.animating) that.aniTime = nextFrame(animate); + }; + + animate(); + }, + + _transitionTime: function (time) { + time += 'ms'; + this.scroller.style[transitionDuration] = time; + if (this.hScrollbar) this.hScrollbarIndicator.style[transitionDuration] = time; + if (this.vScrollbar) this.vScrollbarIndicator.style[transitionDuration] = time; + }, + + _momentum: function (dist, time, maxDistUpper, maxDistLower, size) { + var deceleration = 0.0006, + speed = m.abs(dist) / time, + newDist = (speed * speed) / (2 * deceleration), + newTime = 0, outsideDist = 0; + + // Proportinally reduce speed if we are outside of the boundaries + if (dist > 0 && newDist > maxDistUpper) { + outsideDist = size / (6 / (newDist / speed * deceleration)); + maxDistUpper = maxDistUpper + outsideDist; + speed = speed * maxDistUpper / newDist; + newDist = maxDistUpper; + } else if (dist < 0 && newDist > maxDistLower) { + outsideDist = size / (6 / (newDist / speed * deceleration)); + maxDistLower = maxDistLower + outsideDist; + speed = speed * maxDistLower / newDist; + newDist = maxDistLower; + } + + newDist = newDist * (dist < 0 ? -1 : 1); + newTime = speed / deceleration; + + return { dist: newDist, time: m.round(newTime) }; + }, + + _offset: function (el) { + var left = -el.offsetLeft, + top = -el.offsetTop; + + while (el = el.offsetParent) { + left -= el.offsetLeft; + top -= el.offsetTop; + } + + if (el != this.wrapper) { + left *= this.scale; + top *= this.scale; + } + + return { left: left, top: top }; + }, + + _snap: function (x, y) { + var that = this, + i, l, + page, time, + sizeX, sizeY; + + // Check page X + page = that.pagesX.length - 1; + for (i=0, l=that.pagesX.length; i= that.pagesX[i]) { + page = i; + break; + } + } + if (page == that.currPageX && page > 0 && that.dirX < 0) page--; + x = that.pagesX[page]; + sizeX = m.abs(x - that.pagesX[that.currPageX]); + sizeX = sizeX ? m.abs(that.x - x) / sizeX * 500 : 0; + that.currPageX = page; + + // Check page Y + page = that.pagesY.length-1; + for (i=0; i= that.pagesY[i]) { + page = i; + break; + } + } + if (page == that.currPageY && page > 0 && that.dirY < 0) page--; + y = that.pagesY[page]; + sizeY = m.abs(y - that.pagesY[that.currPageY]); + sizeY = sizeY ? m.abs(that.y - y) / sizeY * 500 : 0; + that.currPageY = page; + + // Snap with constant speed (proportional duration) + time = m.round(m.max(sizeX, sizeY)) || 200; + + return { x: x, y: y, time: time }; + }, + + _bind: function (type, el, bubble) { + (el || this.scroller).addEventListener(type, this, !!bubble); + }, + + _unbind: function (type, el, bubble) { + (el || this.scroller).removeEventListener(type, this, !!bubble); + }, + + + /** + * + * Public methods + * + */ + destroy: function () { + var that = this; + + that.scroller.style[transform] = ''; + + // Remove the scrollbars + that.hScrollbar = false; + that.vScrollbar = false; + that._scrollbar('h'); + that._scrollbar('v'); + + // Remove the event listeners + that._unbind(RESIZE_EV, window); + that._unbind(START_EV); + that._unbind(MOVE_EV, window); + that._unbind(END_EV, window); + that._unbind(CANCEL_EV, window); + + if (!that.options.hasTouch) { + that._unbind('DOMMouseScroll'); + that._unbind('mousewheel'); + } + + if (that.options.useTransition) that._unbind(TRNEND_EV); + + if (that.options.checkDOMChanges) clearInterval(that.checkDOMTime); + + if (that.options.onDestroy) that.options.onDestroy.call(that); + }, + + refresh: function () { + var that = this, + offset, + i, l, + els, + pos = 0, + page = 0; + + if (that.scale < that.options.zoomMin) that.scale = that.options.zoomMin; + that.wrapperW = that.wrapper.clientWidth || 1; + that.wrapperH = that.wrapper.clientHeight || 1; + + that.minScrollY = -that.options.topOffset || 0; + that.scrollerW = m.round(that.scroller.offsetWidth * that.scale); + that.scrollerH = m.round((that.scroller.offsetHeight + that.minScrollY) * that.scale); + that.maxScrollX = that.wrapperW - that.scrollerW; + that.maxScrollY = that.wrapperH - that.scrollerH + that.minScrollY; + that.dirX = 0; + that.dirY = 0; + + if (that.options.onRefresh) that.options.onRefresh.call(that); + + that.hScroll = that.options.hScroll && that.maxScrollX < 0; + that.vScroll = that.options.vScroll && (!that.options.bounceLock && !that.hScroll || that.scrollerH > that.wrapperH); + + that.hScrollbar = that.hScroll && that.options.hScrollbar; + that.vScrollbar = that.vScroll && that.options.vScrollbar && that.scrollerH > that.wrapperH; + + offset = that._offset(that.wrapper); + that.wrapperOffsetLeft = -offset.left; + that.wrapperOffsetTop = -offset.top; + + // Prepare snap + if (typeof that.options.snap == 'string') { + that.pagesX = []; + that.pagesY = []; + els = that.scroller.querySelectorAll(that.options.snap); + for (i=0, l=els.length; i= that.maxScrollX) { + that.pagesX[page] = pos; + pos = pos - that.wrapperW; + page++; + } + if (that.maxScrollX%that.wrapperW) that.pagesX[that.pagesX.length] = that.maxScrollX - that.pagesX[that.pagesX.length-1] + that.pagesX[that.pagesX.length-1]; + + pos = 0; + page = 0; + that.pagesY = []; + while (pos >= that.maxScrollY) { + that.pagesY[page] = pos; + pos = pos - that.wrapperH; + page++; + } + if (that.maxScrollY%that.wrapperH) that.pagesY[that.pagesY.length] = that.maxScrollY - that.pagesY[that.pagesY.length-1] + that.pagesY[that.pagesY.length-1]; + } + + // Prepare the scrollbars + that._scrollbar('h'); + that._scrollbar('v'); + + if (!that.zoomed) { + that.scroller.style[transitionDuration] = '0'; + that._resetPos(400); + } + }, + + scrollTo: function (x, y, time, relative) { + var that = this, + step = x, + i, l; + + that.stop(); + + if (!step.length) step = [{ x: x, y: y, time: time, relative: relative }]; + + for (i=0, l=step.length; i 0 ? 0 : pos.left < that.maxScrollX ? that.maxScrollX : pos.left; + pos.top = pos.top > that.minScrollY ? that.minScrollY : pos.top < that.maxScrollY ? that.maxScrollY : pos.top; + time = time === undefined ? m.max(m.abs(pos.left)*2, m.abs(pos.top)*2) : time; + + that.scrollTo(pos.left, pos.top, time); + }, + + scrollToPage: function (pageX, pageY, time) { + var that = this, x, y; + + time = time === undefined ? 400 : time; + + if (that.options.onScrollStart) that.options.onScrollStart.call(that); + + if (that.options.snap) { + pageX = pageX == 'next' ? that.currPageX+1 : pageX == 'prev' ? that.currPageX-1 : pageX; + pageY = pageY == 'next' ? that.currPageY+1 : pageY == 'prev' ? that.currPageY-1 : pageY; + + pageX = pageX < 0 ? 0 : pageX > that.pagesX.length-1 ? that.pagesX.length-1 : pageX; + pageY = pageY < 0 ? 0 : pageY > that.pagesY.length-1 ? that.pagesY.length-1 : pageY; + + that.currPageX = pageX; + that.currPageY = pageY; + x = that.pagesX[pageX]; + y = that.pagesY[pageY]; + } else { + x = -that.wrapperW * pageX; + y = -that.wrapperH * pageY; + if (x < that.maxScrollX) x = that.maxScrollX; + if (y < that.maxScrollY) y = that.maxScrollY; + } + + that.scrollTo(x, y, time); + }, + + disable: function () { + this.stop(); + this._resetPos(0); + this.enabled = false; + + // If disabled after touchstart we make sure that there are no left over events + this._unbind(MOVE_EV, window); + this._unbind(END_EV, window); + this._unbind(CANCEL_EV, window); + }, + + enable: function () { + this.enabled = true; + }, + + stop: function () { + if (this.options.useTransition) this._unbind(TRNEND_EV); + else cancelFrame(this.aniTime); + this.steps = []; + this.moved = false; + this.animating = false; + }, + + zoom: function (x, y, scale, time) { + var that = this, + relScale = scale / that.scale; + + if (!that.options.useTransform) return; + + that.zoomed = true; + time = time === undefined ? 200 : time; + x = x - that.wrapperOffsetLeft - that.x; + y = y - that.wrapperOffsetTop - that.y; + that.x = x - x * relScale + that.x; + that.y = y - y * relScale + that.y; + + that.scale = scale; + that.refresh(); + + that.x = that.x > 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x; + that.y = that.y > that.minScrollY ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y; + + that.scroller.style[transitionDuration] = time + 'ms'; + that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px) scale(' + scale + ')' + translateZ; + that.zoomed = false; + }, + + isReady: function () { + return !this.moved && !this.zoomed && !this.animating; + } +}; + +function prefixStyle (style) { + if ( vendor === '' ) return style; + + style = style.charAt(0).toUpperCase() + style.substr(1); + return vendor + style; +} + +dummyStyle = null; // for the sake of it + +if (typeof exports !== 'undefined') exports.iScroll = iScroll; +else window.iScroll = iScroll; + +})(window, document); diff --git a/catapp/js/main.js b/catapp/js/main.js new file mode 100644 index 0000000..0d79fe7 --- /dev/null +++ b/catapp/js/main.js @@ -0,0 +1,243 @@ +var App = (function() { + var pages = {}; + var run = function() { + $.each(pages, function(k, v) { + var sectionId = '#' + k + '_section'; + $('body').delegate(sectionId, 'pageinit', function() { + v.init && v.init.call(v); + }); + $('body').delegate(sectionId, 'pageshow', function(e, isBack) { + //页面加载的时候都会执行 + v.show && v.show.call(v); + //后退时不执行 + if (!isBack && v.load) { + v.load.call(v); + } + }); + }); + + J.Transition.add('flip', 'slideLeftOut', 'flipOut', 'slideRightOut', 'flipIn'); + Jingle.launch({ + showWelcome: false, + welcomeSlideChange: false, + showPageLoading: false, + remotePage: { + '#about_section': 'remote/about_section.html' + } + }); + + }; + var page = function(id, factory) { + return ((id && factory) ? _addPage : _getPage).call(this, id, factory); + } + var _addPage = function(id, factory) { + pages[id] = new factory(); + }; + var _getPage = function(id) { + return pages[id]; + } + + //动态计算chart canvas的高度,宽度,以适配终端界面 + var calcChartOffset = function() { + return { + height: $(document).height() - 44 - 30 - 60, + width: $(document).width() + } + + }; + return { + run: run, + page: page, + calcChartOffset: calcChartOffset + } +})(); + + + +//打开监控页面 +function AppMonitor() { + var $lineChart = null; + var $barChart = null; + var $delay = null; + var $request_c = null; + var $request_vs = null; + var $success_c = null; + var $success_vs = null; + var $request_A_c = null; + var $request_A_vs = null; + var $dely_c = null; + var $dely_vs = null; + + var renderChart = function(type, data, data3) { + if (type == 'request') { + $lineChart.show(); + $barChart.hide(); + $delay.hide(); + new JChart.Line(data, { + id: 'chart_drag_line_canvas', + smooth: false, + fill: false, + datasetGesture: true, + datasetOffsetNumber: 10 + }).draw(true); + $('#chartTitle_sp').text('请求数(个/每分钟)'); + $success_c.text('95.736%'); + $success_vs.text('95.484%'); + $request_c.text('93,984'); + $request_vs.text('202,242'); + $request_A_c.text('100.000%'); + $request_A_vs.text('215.188%'); + $dely_c.text('12,614'); + $dely_vs.text('8,605'); + + } + + if (type === 'success') { + $lineChart.hide(); + $delay.hide(); + $barChart.show(); + new JChart.Line(data, { + id: 'chart_drag_bar_canvas', + datasetGesture: true, + datasetOffsetNumber: 10 + }).draw(true); + $('#chartTitle_sp').text('成功率(%/每分钟)'); + $success_c.text('96.736%'); + $success_vs.text('95.34%'); + $request_c.text('91,984'); + $request_vs.text('102,242'); + $request_A_c.text('100.000%'); + $request_A_vs.text('165.188%'); + $dely_c.text('12,634'); + $dely_vs.text('8,905'); + } + + if (type === 'delay') { + $lineChart.hide(); + $barChart.hide(); + $delay.show(); + new JChart.Line(data3, { + id: 'chart_drag_delay_canvas', + datasetGesture: true, + datasetOffsetNumber: 10, + smooth: false, + fill: false + }).draw(true); + $('#chartTitle_sp').text('超时平均值(毫秒/每分钟)'); + $success_c.text('97.736%'); + $success_vs.text('99.34%'); + $request_c.text('92,984'); + $request_vs.text('109,242'); + $request_A_c.text('100.000%'); + $request_A_vs.text('195.188%'); + $dely_c.text('12,834'); + $dely_vs.text('9,905'); + } + }; + + (function() { + var wh = App.calcChartOffset(); + $lineChart = $('#chart_drag_line_canvas'); + $barChart = $('#chart_drag_bar_canvas'); + $delay = $('#chart_drag_delay_canvas'); + $success_c = $('#success_value_c'); + $success_vs = $('#success_value_vs'); + $request_c = $('#success_request_c'); + $request_vs = $('#success_request_vs'); + $request_A_c = $('#success_requestA_c'); + $request_A_vs = $('#success_requestA_vs'); + $dely_c = $('#success_delay_c'); + $dely_vs = $('#success_delay_c'); + + var LINE_HEIGHT = 200; + $lineChart.attr('width', wh.width).attr('height', wh.height - LINE_HEIGHT); + $barChart.attr('width', wh.width).attr('height', wh.height - LINE_HEIGHT); + $delay.attr('width', wh.width).attr('height', wh.height - LINE_HEIGHT); + + var data = { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], + datasets: [{ + name: '当前值', + color: "#368CE9", + pointColor: "#00C349", + pointBorderColor: "#fff", + data: [65, 59, 90, 81, 56, 55, 40, 20, 13, 20, 11, 60, 65, 59, 90, 81, 56, 55, 40, 20, 11, 20, 10, 60, 11, 60, 65] + }, { + name: '对比值', + color: "#FFBB00", + pointColor: "#00C349", + pointBorderColor: "#fff", + data: [28, 48, 40, 19, 96, 27, 100, 40, 40, 70, 11, 89, 28, 48, 40, 19, 96, 27, 100, 40, 40, 70, 10, 89, 28, 48, 40] + }] + }; + + var data3 = { + labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], + datasets: [{ + name: '当前值', + color: "#3C9BFD", + pointColor: "#00C349", + pointBorderColor: "#fff", + data: [165, 159, 90, 81, 56, 55, 40, 120, 13, 20, 11, 60, 165, 59, 390, 81, 56, 55, 840, 20, 11, 20, 10, 60, 11, 60, 65] + }, { + name: '对比值', + color: "#FACC02", + pointColor: "#00C349", + pointBorderColor: "#fff", + data: [28, 48, 140, 19, 96, 227, 100, 40, 40, 770, 11, 89, 28, 48, 40, 19, 96, 327, 100, 40, 40, 470, 10, 89, 28, 48, 40] + }] + }; + $('#changeDragChartType').on('change', function(e, el) { + $lineChart.attr('width', wh.width).attr('height', wh.height - LINE_HEIGHT); + $barChart.attr('width', wh.width).attr('height', wh.height - LINE_HEIGHT); + $delay.attr('width', wh.width).attr('height', wh.height - LINE_HEIGHT); + + renderChart(el.data('type'), data, data3); + + }) + renderChart('request', data); + })(); +} + + + +App.page('index', function() { + this.init = function() { + J.Scroll('#index_section nav.header-secondary', { + hScroll: true, + hScrollbar: false + }); + AppMonitor(); + $('#App_article').css('overflow', 'scroll'); + $('#index_section nav.header-secondary a').on('tap', function(e) { + if (!$(this).hasClass("active")) { + $(this).parent().find(".active").removeClass("active"); + $(this).addClass("active"); + } + + var text = $(this).text(); + var id = "#" + text + "_article"; + var noid = "#No_article"; + if ($(id).length) { + J.Router.showArticle(id, $(id)); + } else { + J.Router.showArticle(noid, $(noid)); + } + + + if ($(e.srcElement).text() === 'App') { + AppMonitor(); + $('#App_article').css('overflow', 'scroll'); + } + + }) + $('#index_section #btn_add_module').on('tap', function() { + J.Router.goTo('#add_module'); + }); + + } +}); + +$(function() { + App.run(); +}); \ No newline at end of file diff --git a/catapp/js/template.min.js b/catapp/js/template.min.js new file mode 100644 index 0000000..63c5a27 --- /dev/null +++ b/catapp/js/template.min.js @@ -0,0 +1 @@ +/*!artTemplate - Template Engine*/var template=function(a,b){return template["object"==typeof b?"render":"compile"].apply(template,arguments)};(function(a,b){"use strict";a.version="2.0.1",a.openTag="<%",a.closeTag="%>",a.isEscape=!0,a.isCompress=!1,a.parser=null,a.render=function(a,b){var c=d(a);return void 0===c?e({id:a,name:"Render Error",message:"No Template"}):c(b)},a.compile=function(b,d){function l(c){try{return new j(c)+""}catch(f){return h?(f.id=b||d,f.name="Render Error",f.source=d,e(f)):a.compile(b,d,!0)(c)}}var g=arguments,h=g[2],i="anonymous";"string"!=typeof d&&(h=g[1],d=g[0],b=i);try{var j=f(d,h)}catch(k){return k.id=b||d,k.name="Syntax Error",e(k)}return l.prototype=j.prototype,l.toString=function(){return""+j},b!==i&&(c[b]=l),l},a.helper=function(b,c){a.prototype[b]=c},a.onerror=function(a){var c="[template]:\n"+a.id+"\n\n[name]:\n"+a.name;a.message&&(c+="\n\n[message]:\n"+a.message),a.line&&(c+="\n\n[line]:\n"+a.line,c+="\n\n[source]:\n"+a.source.split(/\n/)[a.line-1].replace(/^[\s\t]+/,"")),a.temp&&(c+="\n\n[temp]:\n"+a.temp),b.console&&console.error(c)};var c={},d=function(d){var e=c[d];if(void 0===e&&"document"in b){var f=document.getElementById(d);if(f){var g=f.value||f.innerHTML;return a.compile(d,g.replace(/^\s*|\s*$/g,""))}}else if(c.hasOwnProperty(d))return e},e=function(b){function c(){return c+""}return a.onerror(b),c.toString=function(){return"{Template Error}"},c},f=function(){a.prototype={$render:a.render,$escape:function(a){return"string"==typeof a?a.replace(/&(?![\w#]+;)|[<>"']/g,function(a){return{"<":"<",">":">",'"':""","'":"'","&":"&"}[a]}):a},$string:function(a){return"string"==typeof a||"number"==typeof a?a:"function"==typeof a?a():""}};var b=Array.prototype.forEach||function(a,b){for(var c=this.length>>>0,d=0;c>d;d++)d in this&&a.call(b,this[d],d,this)},c=function(a,c){b.call(a,c)},d="break,case,catch,continue,debugger,default,delete,do,else,false,finally,for,function,if,in,instanceof,new,null,return,switch,this,throw,true,try,typeof,var,void,while,with,abstract,boolean,byte,char,class,const,double,enum,export,extends,final,float,goto,implements,import,int,interface,long,native,package,private,protected,public,short,static,super,synchronized,throws,transient,volatile,arguments,let,yield,undefined",e=/\/\*(?:.|\n)*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|'[^']*'|"[^"]*"|[\s\t\n]*\.[\s\t\n]*[$\w\.]+/g,f=/[^\w$]+/g,g=RegExp(["\\b"+d.replace(/,/g,"\\b|\\b")+"\\b"].join("|"),"g"),h=/\b\d[^,]*/g,i=/^,+|,+$/g,j=function(a){return a=a.replace(e,"").replace(f,",").replace(g,"").replace(h,"").replace(i,""),a=a?a.split(/,+/):[]};return function(b,d){function w(b){return k+=b.split(/\n/).length-1,a.isCompress&&(b=b.replace(/[\n\r\t\s]+/g," ")),b=b.replace(/('|\\)/g,"\\$1").replace(/\r/g,"\\r").replace(/\n/g,"\\n"),b=q[1]+"'"+b+"'"+q[2],b+"\n"}function x(b){var c=k;if(g?b=g(b):d&&(b=b.replace(/\n/g,function(){return k++,"$line="+k+";"})),0===b.indexOf("=")){var e=0!==b.indexOf("==");if(b=b.replace(/^=*|[\s;]*$/g,""),e&&a.isEscape){var f=b.replace(/\s*\([^\)]+\)/,"");m.hasOwnProperty(f)||/^(include|print)$/.test(f)||(b="$escape($string("+b+"))")}else b="$string("+b+")";b=q[1]+b+q[2]}return d&&(b="$line="+c+";"+b),y(b),b+"\n"}function y(a){a=j(a),c(a,function(a){l.hasOwnProperty(a)||(z(a),l[a]=!0)})}function z(a){var b;"print"===a?b=s:"include"===a?(n.$render=m.$render,b=t):(b="$data."+a,m.hasOwnProperty(a)&&(n[a]=m[a],b=0===a.indexOf("$")?"$helpers."+a:b+"===undefined?$helpers."+a+":"+b)),o+=a+"="+b+","}var e=a.openTag,f=a.closeTag,g=a.parser,h=b,i="",k=1,l={$data:!0,$helpers:!0,$out:!0,$line:!0},m=a.prototype,n={},o="var $helpers=this,"+(d?"$line=0,":""),p="".trim,q=p?["$out='';","$out+=",";","$out"]:["$out=[];","$out.push(",");","$out.join('')"],r=p?"if(content!==undefined){$out+=content;return content}":"$out.push(content);",s="function(content){"+r+"}",t="function(id,data){if(data===undefined){data=$data}var content=$helpers.$render(id,data);"+r+"}";c(h.split(e),function(a){a=a.split(f);var c=a[0],d=a[1];1===a.length?i+=w(c):(i+=x(c),d&&(i+=w(d)))}),h=i,d&&(h="try{"+h+"}catch(e){"+"e.line=$line;"+"throw e"+"}"),h="'use strict';"+o+q[0]+h+"return new String("+q[3]+")";try{var u=Function("$data",h);return u.prototype=n,u}catch(v){throw v.temp="function anonymous($data) {"+h+"}",v}}}()})(template,this),"function"==typeof define?define(function(a,b,c){c.exports=template}):"undefined"!=typeof exports&&(module.exports=template);(function(exports){exports.openTag="{";exports.closeTag="}";exports.parser=function(code){code=code.replace(/^\s/,"");var args=code.split(" ");var key=args.shift();var keywords=exports.keywords;var fuc=keywords[key];if(fuc&&keywords.hasOwnProperty(key)){args=args.join(" ");code=fuc.call(code,args)}else{if(exports.prototype.hasOwnProperty(key)){args=args.join(",");code="=="+key+"("+args+");"}else{code=code.replace(/[\s;]*$/,"");code="="+code}}return code};exports.keywords={"if":function(code){return"if("+code+"){"},"else":function(code){code=code.split(" ");if(code.shift()==="if"){code=" if("+code.join(" ")+")"}else{code=""}return"}else"+code+"{"},"/if":function(){return"}"},"each":function(code){code=code.split(" ");var object=code[0]||"$data";var as=code[1]||"as";var value=code[2]||"$value";var index=code[3]||"$index";var args=value+","+index;if(as!=="as"){object="[]"}return"$each("+object+",function("+args+"){"},"/each":function(){return"});"},"echo":function(code){return"print("+code+");"},"include":function(code){code=code.split(" ");var id=code[0];var data=code[1];var args=id+(data?(","+data):"");return"include("+args+");"}};exports.helper("$each",function(data,callback){var isArray=Array.isArray||function(obj){return Object.prototype.toString.call(obj)==="[object Array]"};if(isArray(data)){for(var i=0,len=data.length;i]*>/, + singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rootNodeRE = /^(?:body|html)$/i, + capitalRE = /([A-Z])/g, + + // special attributes that should be get/set via method calls + methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'], + + adjacencyOperators = [ 'after', 'prepend', 'before', 'append' ], + table = document.createElement('table'), + tableRow = document.createElement('tr'), + containers = { + 'tr': document.createElement('tbody'), + 'tbody': table, 'thead': table, 'tfoot': table, + 'td': tableRow, 'th': tableRow, + '*': document.createElement('div') + }, + readyRE = /complete|loaded|interactive/, + simpleSelectorRE = /^[\w-]*$/, + class2type = {}, + toString = class2type.toString, + zepto = {}, + camelize, uniq, + tempParent = document.createElement('div'), + propMap = { + 'tabindex': 'tabIndex', + 'readonly': 'readOnly', + 'for': 'htmlFor', + 'class': 'className', + 'maxlength': 'maxLength', + 'cellspacing': 'cellSpacing', + 'cellpadding': 'cellPadding', + 'rowspan': 'rowSpan', + 'colspan': 'colSpan', + 'usemap': 'useMap', + 'frameborder': 'frameBorder', + 'contenteditable': 'contentEditable' + }, + isArray = Array.isArray || + function(object){ return object instanceof Array } + + zepto.matches = function(element, selector) { + if (!selector || !element || element.nodeType !== 1) return false + var matchesSelector = element.webkitMatchesSelector || element.mozMatchesSelector || + element.oMatchesSelector || element.matchesSelector + if (matchesSelector) return matchesSelector.call(element, selector) + // fall back to performing a selector: + var match, parent = element.parentNode, temp = !parent + if (temp) (parent = tempParent).appendChild(element) + match = ~zepto.qsa(parent, selector).indexOf(element) + temp && tempParent.removeChild(element) + return match + } + + function type(obj) { + return obj == null ? String(obj) : + class2type[toString.call(obj)] || "object" + } + + function isFunction(value) { return type(value) == "function" } + function isWindow(obj) { return obj != null && obj == obj.window } + function isDocument(obj) { return obj != null && obj.nodeType == obj.DOCUMENT_NODE } + function isObject(obj) { return type(obj) == "object" } + function isPlainObject(obj) { + return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype + } + function likeArray(obj) { return typeof obj.length == 'number' } + + function compact(array) { return filter.call(array, function(item){ return item != null }) } + function flatten(array) { return array.length > 0 ? $.fn.concat.apply([], array) : array } + camelize = function(str){ return str.replace(/-+(.)?/g, function(match, chr){ return chr ? chr.toUpperCase() : '' }) } + function dasherize(str) { + return str.replace(/::/g, '/') + .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') + .replace(/([a-z\d])([A-Z])/g, '$1_$2') + .replace(/_/g, '-') + .toLowerCase() + } + uniq = function(array){ return filter.call(array, function(item, idx){ return array.indexOf(item) == idx }) } + + function classRE(name) { + return name in classCache ? + classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)')) + } + + function maybeAddPx(name, value) { + return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value + } + + function defaultDisplay(nodeName) { + var element, display + if (!elementDisplay[nodeName]) { + element = document.createElement(nodeName) + document.body.appendChild(element) + display = getComputedStyle(element, '').getPropertyValue("display") + element.parentNode.removeChild(element) + display == "none" && (display = "block") + elementDisplay[nodeName] = display + } + return elementDisplay[nodeName] + } + + function children(element) { + return 'children' in element ? + slice.call(element.children) : + $.map(element.childNodes, function(node){ if (node.nodeType == 1) return node }) + } + + // `$.zepto.fragment` takes a html string and an optional tag name + // to generate DOM nodes nodes from the given html string. + // The generated DOM nodes are returned as an array. + // This function can be overriden in plugins for example to make + // it compatible with browsers that don't support the DOM fully. + zepto.fragment = function(html, name, properties) { + var dom, nodes, container + + // A special case optimization for a single tag + if (singleTagRE.test(html)) dom = $(document.createElement(RegExp.$1)) + + if (!dom) { + if (html.replace) html = html.replace(tagExpanderRE, "<$1>") + if (name === undefined) name = fragmentRE.test(html) && RegExp.$1 + if (!(name in containers)) name = '*' + + container = containers[name] + container.innerHTML = '' + html + dom = $.each(slice.call(container.childNodes), function(){ + container.removeChild(this) + }) + } + + if (isPlainObject(properties)) { + nodes = $(dom) + $.each(properties, function(key, value) { + if (methodAttributes.indexOf(key) > -1) nodes[key](value) + else nodes.attr(key, value) + }) + } + + return dom + } + + // `$.zepto.Z` swaps out the prototype of the given `dom` array + // of nodes with `$.fn` and thus supplying all the Zepto functions + // to the array. Note that `__proto__` is not supported on Internet + // Explorer. This method can be overriden in plugins. + zepto.Z = function(dom, selector) { + dom = dom || [] + dom.__proto__ = $.fn + dom.selector = selector || '' + return dom + } + + // `$.zepto.isZ` should return `true` if the given object is a Zepto + // collection. This method can be overriden in plugins. + zepto.isZ = function(object) { + return object instanceof zepto.Z + } + + // `$.zepto.init` is Zepto's counterpart to jQuery's `$.fn.init` and + // takes a CSS selector and an optional context (and handles various + // special cases). + // This method can be overriden in plugins. + zepto.init = function(selector, context) { + var dom + // If nothing given, return an empty Zepto collection + if (!selector) return zepto.Z() + // Optimize for string selectors + else if (typeof selector == 'string') { + selector = selector.trim() + // If it's a html fragment, create nodes from it + // Note: In both Chrome 21 and Firefox 15, DOM error 12 + // is thrown if the fragment doesn't begin with < + if (selector[0] == '<' && fragmentRE.test(selector)) + dom = zepto.fragment(selector, RegExp.$1, context), selector = null + // If there's a context, create a collection on that context first, and select + // nodes from there + else if (context !== undefined) return $(context).find(selector) + // If it's a CSS selector, use it to select nodes. + else dom = zepto.qsa(document, selector) + } + // If a function is given, call it when the DOM is ready + else if (isFunction(selector)) return $(document).ready(selector) + // If a Zepto collection is given, just return it + else if (zepto.isZ(selector)) return selector + else { + // normalize array if an array of nodes is given + if (isArray(selector)) dom = compact(selector) + // Wrap DOM nodes. + else if (isObject(selector)) + dom = [selector], selector = null + // If it's a html fragment, create nodes from it + else if (fragmentRE.test(selector)) + dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null + // If there's a context, create a collection on that context first, and select + // nodes from there + else if (context !== undefined) return $(context).find(selector) + // And last but no least, if it's a CSS selector, use it to select nodes. + else dom = zepto.qsa(document, selector) + } + // create a new Zepto collection from the nodes found + return zepto.Z(dom, selector) + } + + // `$` will be the base `Zepto` object. When calling this + // function just call `$.zepto.init, which makes the implementation + // details of selecting nodes and creating Zepto collections + // patchable in plugins. + $ = function(selector, context){ + return zepto.init(selector, context) + } + + function extend(target, source, deep) { + for (key in source) + if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { + if (isPlainObject(source[key]) && !isPlainObject(target[key])) + target[key] = {} + if (isArray(source[key]) && !isArray(target[key])) + target[key] = [] + extend(target[key], source[key], deep) + } + else if (source[key] !== undefined) target[key] = source[key] + } + + // Copy all but undefined properties from one or more + // objects to the `target` object. + $.extend = function(target){ + var deep, args = slice.call(arguments, 1) + if (typeof target == 'boolean') { + deep = target + target = args.shift() + } + args.forEach(function(arg){ extend(target, arg, deep) }) + return target + } + + // `$.zepto.qsa` is Zepto's CSS selector implementation which + // uses `document.querySelectorAll` and optimizes for some special cases, like `#id`. + // This method can be overriden in plugins. + zepto.qsa = function(element, selector){ + var found, + maybeID = selector[0] == '#', + maybeClass = !maybeID && selector[0] == '.', + nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, // Ensure that a 1 char tag name still gets checked + isSimple = simpleSelectorRE.test(nameOnly) + return (isDocument(element) && isSimple && maybeID) ? + ( (found = element.getElementById(nameOnly)) ? [found] : [] ) : + (element.nodeType !== 1 && element.nodeType !== 9) ? [] : + slice.call( + isSimple && !maybeID ? + maybeClass ? element.getElementsByClassName(nameOnly) : // If it's simple, it could be a class + element.getElementsByTagName(selector) : // Or a tag + element.querySelectorAll(selector) // Or it's not simple, and we need to query all + ) + } + + function filtered(nodes, selector) { + return selector == null ? $(nodes) : $(nodes).filter(selector) + } + + $.contains = function(parent, node) { + return parent !== node && parent.contains(node) + } + + function funcArg(context, arg, idx, payload) { + return isFunction(arg) ? arg.call(context, idx, payload) : arg + } + + function setAttribute(node, name, value) { + value == null ? node.removeAttribute(name) : node.setAttribute(name, value) + } + + // access className property while respecting SVGAnimatedString + function className(node, value){ + var klass = node.className, + svg = klass && klass.baseVal !== undefined + + if (value === undefined) return svg ? klass.baseVal : klass + svg ? (klass.baseVal = value) : (node.className = value) + } + + // "true" => true + // "false" => false + // "null" => null + // "42" => 42 + // "42.5" => 42.5 + // "08" => "08" + // JSON => parse if valid + // String => self + function deserializeValue(value) { + var num + try { + return value ? + value == "true" || + ( value == "false" ? false : + value == "null" ? null : + !/^0/.test(value) && !isNaN(num = Number(value)) ? num : + /^[\[\{]/.test(value) ? $.parseJSON(value) : + value ) + : value + } catch(e) { + return value + } + } + + $.type = type + $.isFunction = isFunction + $.isWindow = isWindow + $.isArray = isArray + $.isPlainObject = isPlainObject + + $.isEmptyObject = function(obj) { + var name + for (name in obj) return false + return true + } + + $.inArray = function(elem, array, i){ + return emptyArray.indexOf.call(array, elem, i) + } + + $.camelCase = camelize + $.trim = function(str) { + return str == null ? "" : String.prototype.trim.call(str) + } + + // plugin compatibility + $.uuid = 0 + $.support = { } + $.expr = { } + + $.map = function(elements, callback){ + var value, values = [], i, key + if (likeArray(elements)) + for (i = 0; i < elements.length; i++) { + value = callback(elements[i], i) + if (value != null) values.push(value) + } + else + for (key in elements) { + value = callback(elements[key], key) + if (value != null) values.push(value) + } + return flatten(values) + } + + $.each = function(elements, callback){ + var i, key + if (likeArray(elements)) { + for (i = 0; i < elements.length; i++) + if (callback.call(elements[i], i, elements[i]) === false) return elements + } else { + for (key in elements) + if (callback.call(elements[key], key, elements[key]) === false) return elements + } + + return elements + } + + $.grep = function(elements, callback){ + return filter.call(elements, callback) + } + + if (window.JSON) $.parseJSON = JSON.parse + + // Populate the class2type map + $.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase() + }) + + // Define methods that will be available on all + // Zepto collections + $.fn = { + // Because a collection acts like an array + // copy over these useful array functions. + forEach: emptyArray.forEach, + reduce: emptyArray.reduce, + push: emptyArray.push, + sort: emptyArray.sort, + indexOf: emptyArray.indexOf, + concat: emptyArray.concat, + + // `map` and `slice` in the jQuery API work differently + // from their array counterparts + map: function(fn){ + return $($.map(this, function(el, i){ return fn.call(el, i, el) })) + }, + slice: function(){ + return $(slice.apply(this, arguments)) + }, + + ready: function(callback){ + // need to check if document.body exists for IE as that browser reports + // document ready when it hasn't yet created the body element + if (readyRE.test(document.readyState) && document.body) callback($) + else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false) + return this + }, + get: function(idx){ + return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length] + }, + toArray: function(){ return this.get() }, + size: function(){ + return this.length + }, + remove: function(){ + return this.each(function(){ + if (this.parentNode != null) + this.parentNode.removeChild(this) + }) + }, + each: function(callback){ + emptyArray.every.call(this, function(el, idx){ + return callback.call(el, idx, el) !== false + }) + return this + }, + filter: function(selector){ + if (isFunction(selector)) return this.not(this.not(selector)) + return $(filter.call(this, function(element){ + return zepto.matches(element, selector) + })) + }, + add: function(selector,context){ + return $(uniq(this.concat($(selector,context)))) + }, + is: function(selector){ + return this.length > 0 && zepto.matches(this[0], selector) + }, + not: function(selector){ + var nodes=[] + if (isFunction(selector) && selector.call !== undefined) + this.each(function(idx){ + if (!selector.call(this,idx)) nodes.push(this) + }) + else { + var excludes = typeof selector == 'string' ? this.filter(selector) : + (likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector) + this.forEach(function(el){ + if (excludes.indexOf(el) < 0) nodes.push(el) + }) + } + return $(nodes) + }, + has: function(selector){ + return this.filter(function(){ + return isObject(selector) ? + $.contains(this, selector) : + $(this).find(selector).size() + }) + }, + eq: function(idx){ + return idx === -1 ? this.slice(idx) : this.slice(idx, + idx + 1) + }, + first: function(){ + var el = this[0] + return el && !isObject(el) ? el : $(el) + }, + last: function(){ + var el = this[this.length - 1] + return el && !isObject(el) ? el : $(el) + }, + find: function(selector){ + var result, $this = this + if (typeof selector == 'object') + result = $(selector).filter(function(){ + var node = this + return emptyArray.some.call($this, function(parent){ + return $.contains(parent, node) + }) + }) + else if (this.length == 1) result = $(zepto.qsa(this[0], selector)) + else result = this.map(function(){ return zepto.qsa(this, selector) }) + return result + }, + closest: function(selector, context){ + var node = this[0], collection = false + if (typeof selector == 'object') collection = $(selector) + while (node && !(collection ? collection.indexOf(node) >= 0 : zepto.matches(node, selector))) + node = node !== context && !isDocument(node) && node.parentNode + return $(node) + }, + parents: function(selector){ + var ancestors = [], nodes = this + while (nodes.length > 0) + nodes = $.map(nodes, function(node){ + if ((node = node.parentNode) && !isDocument(node) && ancestors.indexOf(node) < 0) { + ancestors.push(node) + return node + } + }) + return filtered(ancestors, selector) + }, + parent: function(selector){ + return filtered(uniq(this.pluck('parentNode')), selector) + }, + children: function(selector){ + return filtered(this.map(function(){ return children(this) }), selector) + }, + contents: function() { + return this.map(function() { return slice.call(this.childNodes) }) + }, + siblings: function(selector){ + return filtered(this.map(function(i, el){ + return filter.call(children(el.parentNode), function(child){ return child!==el }) + }), selector) + }, + empty: function(){ + return this.each(function(){ this.innerHTML = '' }) + }, + // `pluck` is borrowed from Prototype.js + pluck: function(property){ + return $.map(this, function(el){ return el[property] }) + }, + show: function(){ + return this.each(function(){ + this.style.display == "none" && (this.style.display = '') + if (getComputedStyle(this, '').getPropertyValue("display") == "none") + this.style.display = defaultDisplay(this.nodeName) + }) + }, + replaceWith: function(newContent){ + return this.before(newContent).remove() + }, + wrap: function(structure){ + var func = isFunction(structure) + if (this[0] && !func) + var dom = $(structure).get(0), + clone = dom.parentNode || this.length > 1 + + return this.each(function(index){ + $(this).wrapAll( + func ? structure.call(this, index) : + clone ? dom.cloneNode(true) : dom + ) + }) + }, + wrapAll: function(structure){ + if (this[0]) { + $(this[0]).before(structure = $(structure)) + var children + // drill down to the inmost element + while ((children = structure.children()).length) structure = children.first() + $(structure).append(this) + } + return this + }, + wrapInner: function(structure){ + var func = isFunction(structure) + return this.each(function(index){ + var self = $(this), contents = self.contents(), + dom = func ? structure.call(this, index) : structure + contents.length ? contents.wrapAll(dom) : self.append(dom) + }) + }, + unwrap: function(){ + this.parent().each(function(){ + $(this).replaceWith($(this).children()) + }) + return this + }, + clone: function(){ + return this.map(function(){ return this.cloneNode(true) }) + }, + hide: function(){ + return this.css("display", "none") + }, + toggle: function(setting){ + return this.each(function(){ + var el = $(this) + ;(setting === undefined ? el.css("display") == "none" : setting) ? el.show() : el.hide() + }) + }, + prev: function(selector){ return $(this.pluck('previousElementSibling')).filter(selector || '*') }, + next: function(selector){ return $(this.pluck('nextElementSibling')).filter(selector || '*') }, + html: function(html){ + return arguments.length === 0 ? + (this.length > 0 ? this[0].innerHTML : null) : + this.each(function(idx){ + var originHtml = this.innerHTML + $(this).empty().append( funcArg(this, html, idx, originHtml) ) + }) + }, + text: function(text){ + return arguments.length === 0 ? + (this.length > 0 ? this[0].textContent : null) : + this.each(function(){ this.textContent = (text === undefined) ? '' : ''+text }) + }, + attr: function(name, value){ + var result + return (typeof name == 'string' && value === undefined) ? + (this.length == 0 || this[0].nodeType !== 1 ? undefined : + (name == 'value' && this[0].nodeName == 'INPUT') ? this.val() : + (!(result = this[0].getAttribute(name)) && name in this[0]) ? this[0][name] : result + ) : + this.each(function(idx){ + if (this.nodeType !== 1) return + if (isObject(name)) for (key in name) setAttribute(this, key, name[key]) + else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name))) + }) + }, + removeAttr: function(name){ + return this.each(function(){ this.nodeType === 1 && setAttribute(this, name) }) + }, + prop: function(name, value){ + name = propMap[name] || name + return (value === undefined) ? + (this[0] && this[0][name]) : + this.each(function(idx){ + this[name] = funcArg(this, value, idx, this[name]) + }) + }, + data: function(name, value){ + var data = this.attr('data-' + name.replace(capitalRE, '-$1').toLowerCase(), value) + return data !== null ? deserializeValue(data) : undefined + }, + val: function(value){ + return arguments.length === 0 ? + (this[0] && (this[0].multiple ? + $(this[0]).find('option').filter(function(){ return this.selected }).pluck('value') : + this[0].value) + ) : + this.each(function(idx){ + this.value = funcArg(this, value, idx, this.value) + }) + }, + offset: function(coordinates){ + if (coordinates) return this.each(function(index){ + var $this = $(this), + coords = funcArg(this, coordinates, index, $this.offset()), + parentOffset = $this.offsetParent().offset(), + props = { + top: coords.top - parentOffset.top, + left: coords.left - parentOffset.left + } + + if ($this.css('position') == 'static') props['position'] = 'relative' + $this.css(props) + }) + if (this.length==0) return null + var obj = this[0].getBoundingClientRect() + return { + left: obj.left + window.pageXOffset, + top: obj.top + window.pageYOffset, + width: Math.round(obj.width), + height: Math.round(obj.height) + } + }, + css: function(property, value){ + if (arguments.length < 2) { + var element = this[0], computedStyle = getComputedStyle(element, '') + if(!element) return + if (typeof property == 'string') + return element.style[camelize(property)] || computedStyle.getPropertyValue(property) + else if (isArray(property)) { + var props = {} + $.each(isArray(property) ? property: [property], function(_, prop){ + props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop)) + }) + return props + } + } + + var css = '' + if (type(property) == 'string') { + if (!value && value !== 0) + this.each(function(){ this.style.removeProperty(dasherize(property)) }) + else + css = dasherize(property) + ":" + maybeAddPx(property, value) + } else { + for (key in property) + if (!property[key] && property[key] !== 0) + this.each(function(){ this.style.removeProperty(dasherize(key)) }) + else + css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';' + } + + return this.each(function(){ this.style.cssText += ';' + css }) + }, + index: function(element){ + return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0]) + }, + hasClass: function(name){ + if (!name) return false + return emptyArray.some.call(this, function(el){ + return this.test(className(el)) + }, classRE(name)) + }, + addClass: function(name){ + if (!name) return this + return this.each(function(idx){ + classList = [] + var cls = className(this), newName = funcArg(this, name, idx, cls) + newName.split(/\s+/g).forEach(function(klass){ + if (!$(this).hasClass(klass)) classList.push(klass) + }, this) + classList.length && className(this, cls + (cls ? " " : "") + classList.join(" ")) + }) + }, + removeClass: function(name){ + return this.each(function(idx){ + if (name === undefined) return className(this, '') + classList = className(this) + funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass){ + classList = classList.replace(classRE(klass), " ") + }) + className(this, classList.trim()) + }) + }, + toggleClass: function(name, when){ + if (!name) return this + return this.each(function(idx){ + var $this = $(this), names = funcArg(this, name, idx, className(this)) + names.split(/\s+/g).forEach(function(klass){ + (when === undefined ? !$this.hasClass(klass) : when) ? + $this.addClass(klass) : $this.removeClass(klass) + }) + }) + }, + scrollTop: function(value){ + if (!this.length) return + var hasScrollTop = 'scrollTop' in this[0] + if (value === undefined) return hasScrollTop ? this[0].scrollTop : this[0].pageYOffset + return this.each(hasScrollTop ? + function(){ this.scrollTop = value } : + function(){ this.scrollTo(this.scrollX, value) }) + }, + scrollLeft: function(value){ + if (!this.length) return + var hasScrollLeft = 'scrollLeft' in this[0] + if (value === undefined) return hasScrollLeft ? this[0].scrollLeft : this[0].pageXOffset + return this.each(hasScrollLeft ? + function(){ this.scrollLeft = value } : + function(){ this.scrollTo(value, this.scrollY) }) + }, + position: function() { + if (!this.length) return + + var elem = this[0], + // Get *real* offsetParent + offsetParent = this.offsetParent(), + // Get correct offsets + offset = this.offset(), + parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset() + + // Subtract element margins + // note: when an element has margin: auto the offsetLeft and marginLeft + // are the same in Safari causing offset.left to incorrectly be 0 + offset.top -= parseFloat( $(elem).css('margin-top') ) || 0 + offset.left -= parseFloat( $(elem).css('margin-left') ) || 0 + + // Add offsetParent borders + parentOffset.top += parseFloat( $(offsetParent[0]).css('border-top-width') ) || 0 + parentOffset.left += parseFloat( $(offsetParent[0]).css('border-left-width') ) || 0 + + // Subtract the two offsets + return { + top: offset.top - parentOffset.top, + left: offset.left - parentOffset.left + } + }, + offsetParent: function() { + return this.map(function(){ + var parent = this.offsetParent || document.body + while (parent && !rootNodeRE.test(parent.nodeName) && $(parent).css("position") == "static") + parent = parent.offsetParent + return parent + }) + } + } + + // for now + $.fn.detach = $.fn.remove + + // Generate the `width` and `height` functions + ;['width', 'height'].forEach(function(dimension){ + var dimensionProperty = + dimension.replace(/./, function(m){ return m[0].toUpperCase() }) + + $.fn[dimension] = function(value){ + var offset, el = this[0] + if (value === undefined) return isWindow(el) ? el['inner' + dimensionProperty] : + isDocument(el) ? el.documentElement['scroll' + dimensionProperty] : + (offset = this.offset()) && offset[dimension] + else return this.each(function(idx){ + el = $(this) + el.css(dimension, funcArg(this, value, idx, el[dimension]())) + }) + } + }) + + function traverseNode(node, fun) { + fun(node) + for (var key in node.childNodes) traverseNode(node.childNodes[key], fun) + } + + // Generate the `after`, `prepend`, `before`, `append`, + // `insertAfter`, `insertBefore`, `appendTo`, and `prependTo` methods. + adjacencyOperators.forEach(function(operator, operatorIndex) { + var inside = operatorIndex % 2 //=> prepend, append + + $.fn[operator] = function(){ + // arguments can be nodes, arrays of nodes, Zepto objects and HTML strings + var argType, nodes = $.map(arguments, function(arg) { + argType = type(arg) + return argType == "object" || argType == "array" || arg == null ? + arg : zepto.fragment(arg) + }), + parent, copyByClone = this.length > 1 + if (nodes.length < 1) return this + + return this.each(function(_, target){ + parent = inside ? target : target.parentNode + + // convert all methods to a "before" operation + target = operatorIndex == 0 ? target.nextSibling : + operatorIndex == 1 ? target.firstChild : + operatorIndex == 2 ? target : + null + + nodes.forEach(function(node){ + if (copyByClone) node = node.cloneNode(true) + else if (!parent) return $(node).remove() + + traverseNode(parent.insertBefore(node, target), function(el){ + if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' && + (!el.type || el.type === 'text/javascript') && !el.src) + window['eval'].call(window, el.innerHTML) + }) + }) + }) + } + + // after => insertAfter + // prepend => prependTo + // before => insertBefore + // append => appendTo + $.fn[inside ? operator+'To' : 'insert'+(operatorIndex ? 'Before' : 'After')] = function(html){ + $(html)[operator](this) + return this + } + }) + + zepto.Z.prototype = $.fn + + // Export internal API functions in the `$.zepto` namespace + zepto.uniq = uniq + zepto.deserializeValue = deserializeValue + $.zepto = zepto + + return $ +})() + + +window.Zepto = Zepto +window.$ === undefined && (window.$ = Zepto) + + + + + +;(function($){ + var _zid = 1, undefined, + slice = Array.prototype.slice, + isFunction = $.isFunction, + isString = function(obj){ return typeof obj == 'string' }, + handlers = {}, + specialEvents={}, + focusinSupported = 'onfocusin' in window, + focus = { focus: 'focusin', blur: 'focusout' }, + hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' } + + specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents' + + function zid(element) { + return element._zid || (element._zid = _zid++) + } + function findHandlers(element, event, fn, selector) { + event = parse(event) + if (event.ns) var matcher = matcherFor(event.ns) + return (handlers[zid(element)] || []).filter(function(handler) { + return handler + && (!event.e || handler.e == event.e) + && (!event.ns || matcher.test(handler.ns)) + && (!fn || zid(handler.fn) === zid(fn)) + && (!selector || handler.sel == selector) + }) + } + function parse(event) { + var parts = ('' + event).split('.') + return {e: parts[0], ns: parts.slice(1).sort().join(' ')} + } + function matcherFor(ns) { + return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)') + } + + function eventCapture(handler, captureSetting) { + return handler.del && + (!focusinSupported && (handler.e in focus)) || + !!captureSetting + } + + function realEvent(type) { + return hover[type] || (focusinSupported && focus[type]) || type + } + + function add(element, events, fn, data, selector, delegator, capture){ + var id = zid(element), set = (handlers[id] || (handlers[id] = [])) + events.split(/\s/).forEach(function(event){ + if (event == 'ready') return $(document).ready(fn) + var handler = parse(event) + handler.fn = fn + handler.sel = selector + // emulate mouseenter, mouseleave + if (handler.e in hover) fn = function(e){ + var related = e.relatedTarget + if (!related || (related !== this && !$.contains(this, related))) + return handler.fn.apply(this, arguments) + } + handler.del = delegator + var callback = delegator || fn + handler.proxy = function(e){ + e = compatible(e) + if (e.isImmediatePropagationStopped()) return + e.data = data + var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args)) + if (result === false) e.preventDefault(), e.stopPropagation() + return result + } + handler.i = set.length + set.push(handler) + if ('addEventListener' in element) + element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + } + function remove(element, events, fn, selector, capture){ + var id = zid(element) + ;(events || '').split(/\s/).forEach(function(event){ + findHandlers(element, event, fn, selector).forEach(function(handler){ + delete handlers[id][handler.i] + if ('removeEventListener' in element) + element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + }) + } + + $.event = { add: add, remove: remove } + + $.proxy = function(fn, context) { + if (isFunction(fn)) { + var proxyFn = function(){ return fn.apply(context, arguments) } + proxyFn._zid = zid(fn) + return proxyFn + } else if (isString(context)) { + return $.proxy(fn[context], fn) + } else { + throw new TypeError("expected function") + } + } + + $.fn.bind = function(event, data, callback){ + return this.on(event, data, callback) + } + $.fn.unbind = function(event, callback){ + return this.off(event, callback) + } + $.fn.one = function(event, selector, data, callback){ + return this.on(event, selector, data, callback, 1) + } + + var returnTrue = function(){return true}, + returnFalse = function(){return false}, + ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$)/, + eventMethods = { + preventDefault: 'isDefaultPrevented', + stopImmediatePropagation: 'isImmediatePropagationStopped', + stopPropagation: 'isPropagationStopped' + } + + function compatible(event, source) { + if (source || !event.isDefaultPrevented) { + source || (source = event) + + $.each(eventMethods, function(name, predicate) { + var sourceMethod = source[name] + event[name] = function(){ + this[predicate] = returnTrue + return sourceMethod && sourceMethod.apply(source, arguments) + } + event[predicate] = returnFalse + }) + + if (source.defaultPrevented !== undefined ? source.defaultPrevented : + 'returnValue' in source ? source.returnValue === false : + source.getPreventDefault && source.getPreventDefault()) + event.isDefaultPrevented = returnTrue + } + return event + } + + function createProxy(event) { + var key, proxy = { originalEvent: event } + for (key in event) + if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key] + + return compatible(proxy, event) + } + + $.fn.delegate = function(selector, event, callback){ + return this.on(event, selector, callback) + } + $.fn.undelegate = function(selector, event, callback){ + return this.off(event, selector, callback) + } + + $.fn.live = function(event, callback){ + $(document.body).delegate(this.selector, event, callback) + return this + } + $.fn.die = function(event, callback){ + $(document.body).undelegate(this.selector, event, callback) + return this + } + + $.fn.on = function(event, selector, data, callback, one){ + var autoRemove, delegator, $this = this + if (event && !isString(event)) { + $.each(event, function(type, fn){ + $this.on(type, selector, data, fn, one) + }) + return $this + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = data, data = selector, selector = undefined + if (isFunction(data) || data === false) + callback = data, data = undefined + + if (callback === false) callback = returnFalse + + return $this.each(function(_, element){ + if (one) autoRemove = function(e){ + remove(element, e.type, callback) + return callback.apply(this, arguments) + } + + if (selector) delegator = function(e){ + var evt, match = $(e.target).closest(selector, element).get(0) + if (match && match !== element) { + evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element}) + return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1))) + } + } + + add(element, event, callback, data, selector, delegator || autoRemove) + }) + } + $.fn.off = function(event, selector, callback){ + var $this = this + if (event && !isString(event)) { + $.each(event, function(type, fn){ + $this.off(type, selector, fn) + }) + return $this + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = selector, selector = undefined + + if (callback === false) callback = returnFalse + + return $this.each(function(){ + remove(this, event, callback, selector) + }) + } + + $.fn.trigger = function(event, args){ + event = (isString(event) || $.isPlainObject(event)) ? $.Event(event) : compatible(event) + event._args = args + return this.each(function(){ + // items in the collection might not be DOM elements + if('dispatchEvent' in this) this.dispatchEvent(event) + else $(this).triggerHandler(event, args) + }) + } + + // triggers event handlers on current element just as if an event occurred, + // doesn't trigger an actual event, doesn't bubble + $.fn.triggerHandler = function(event, args){ + var e, result + this.each(function(i, element){ + e = createProxy(isString(event) ? $.Event(event) : event) + e._args = args + e.target = element + $.each(findHandlers(element, event.type || event), function(i, handler){ + result = handler.proxy(e) + if (e.isImmediatePropagationStopped()) return false + }) + }) + return result + } + + // shortcut methods for `.bind(event, fn)` for each event type + ;('focusin focusout load resize scroll unload click dblclick '+ + 'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave '+ + 'change select keydown keypress keyup error').split(' ').forEach(function(event) { + $.fn[event] = function(callback) { + return callback ? + this.bind(event, callback) : + this.trigger(event) + } + }) + + ;['focus', 'blur'].forEach(function(name) { + $.fn[name] = function(callback) { + if (callback) this.bind(name, callback) + else this.each(function(){ + try { this[name]() } + catch(e) {} + }) + return this + } + }) + + $.Event = function(type, props) { + if (!isString(type)) props = type, type = props.type + var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true + if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name]) + event.initEvent(type, bubbles, true) + return compatible(event) + } + +})(Zepto) + + + + + +;(function($){ + var jsonpID = 0, + document = window.document, + key, + name, + rscript = /)<[^<]*)*<\/script>/gi, + scriptTypeRE = /^(?:text|application)\/javascript/i, + xmlTypeRE = /^(?:text|application)\/xml/i, + jsonType = 'application/json', + htmlType = 'text/html', + blankRE = /^\s*$/ + + // trigger a custom event and return false if it was cancelled + function triggerAndReturn(context, eventName, data) { + var event = $.Event(eventName) + $(context).trigger(event, data) + return !event.isDefaultPrevented() + } + + // trigger an Ajax "global" event + function triggerGlobal(settings, context, eventName, data) { + if (settings.global) return triggerAndReturn(context || document, eventName, data) + } + + // Number of active Ajax requests + $.active = 0 + + function ajaxStart(settings) { + if (settings.global && $.active++ === 0) triggerGlobal(settings, null, 'ajaxStart') + } + function ajaxStop(settings) { + if (settings.global && !(--$.active)) triggerGlobal(settings, null, 'ajaxStop') + } + + // triggers an extra global event "ajaxBeforeSend" that's like "ajaxSend" but cancelable + function ajaxBeforeSend(xhr, settings) { + var context = settings.context + if (settings.beforeSend.call(context, xhr, settings) === false || + triggerGlobal(settings, context, 'ajaxBeforeSend', [xhr, settings]) === false) + return false + + triggerGlobal(settings, context, 'ajaxSend', [xhr, settings]) + } + function ajaxSuccess(data, xhr, settings, deferred) { + var context = settings.context, status = 'success' + settings.success.call(context, data, status, xhr) + if (deferred) deferred.resolveWith(context, [data, status, xhr]) + triggerGlobal(settings, context, 'ajaxSuccess', [xhr, settings, data]) + ajaxComplete(status, xhr, settings) + } + // type: "timeout", "error", "abort", "parsererror" + function ajaxError(error, type, xhr, settings, deferred) { + var context = settings.context + settings.error.call(context, xhr, type, error) + if (deferred) deferred.rejectWith(context, [xhr, type, error]) + triggerGlobal(settings, context, 'ajaxError', [xhr, settings, error || type]) + ajaxComplete(type, xhr, settings) + } + // status: "success", "notmodified", "error", "timeout", "abort", "parsererror" + function ajaxComplete(status, xhr, settings) { + var context = settings.context + settings.complete.call(context, xhr, status) + triggerGlobal(settings, context, 'ajaxComplete', [xhr, settings]) + ajaxStop(settings) + } + + // Empty function, used as default callback + function empty() {} + + $.ajaxJSONP = function(options, deferred){ + if (!('type' in options)) return $.ajax(options) + + var _callbackName = options.jsonpCallback, + callbackName = ($.isFunction(_callbackName) ? + _callbackName() : _callbackName) || ('jsonp' + (++jsonpID)), + script = document.createElement('script'), + originalCallback = window[callbackName], + responseData, + abort = function(errorType) { + $(script).triggerHandler('error', errorType || 'abort') + }, + xhr = { abort: abort }, abortTimeout + + if (deferred) deferred.promise(xhr) + + $(script).on('load error', function(e, errorType){ + clearTimeout(abortTimeout) + $(script).off().remove() + + if (e.type == 'error' || !responseData) { + ajaxError(null, errorType || 'error', xhr, options, deferred) + } else { + ajaxSuccess(responseData[0], xhr, options, deferred) + } + + window[callbackName] = originalCallback + if (responseData && $.isFunction(originalCallback)) + originalCallback(responseData[0]) + + originalCallback = responseData = undefined + }) + + if (ajaxBeforeSend(xhr, options) === false) { + abort('abort') + return xhr + } + + window[callbackName] = function(){ + responseData = arguments + } + + script.src = options.url.replace(/\?(.+)=\?/, '?$1=' + callbackName) + document.head.appendChild(script) + + if (options.timeout > 0) abortTimeout = setTimeout(function(){ + abort('timeout') + }, options.timeout) + + return xhr + } + + $.ajaxSettings = { + // Default type of request + type: 'GET', + // Callback that is executed before request + beforeSend: empty, + // Callback that is executed if the request succeeds + success: empty, + // Callback that is executed the the server drops error + error: empty, + // Callback that is executed on request complete (both: error and success) + complete: empty, + // The context for the callbacks + context: null, + // Whether to trigger "global" Ajax events + global: true, + // Transport + xhr: function () { + return new window.XMLHttpRequest() + }, + // MIME types mapping + // IIS returns Javascript as "application/x-javascript" + accepts: { + script: 'text/javascript, application/javascript, application/x-javascript', + json: jsonType, + xml: 'application/xml, text/xml', + html: htmlType, + text: 'text/plain' + }, + // Whether the request is to another domain + crossDomain: false, + // Default timeout + timeout: 0, + // Whether data should be serialized to string + processData: true, + // Whether the browser should be allowed to cache GET responses + cache: true + } + + function mimeToDataType(mime) { + if (mime) mime = mime.split(';', 2)[0] + return mime && ( mime == htmlType ? 'html' : + mime == jsonType ? 'json' : + scriptTypeRE.test(mime) ? 'script' : + xmlTypeRE.test(mime) && 'xml' ) || 'text' + } + + function appendQuery(url, query) { + if (query == '') return url + return (url + '&' + query).replace(/[&?]{1,2}/, '?') + } + + // serialize payload and append it to the URL for GET requests + function serializeData(options) { + if (options.processData && options.data && $.type(options.data) != "string") + options.data = $.param(options.data, options.traditional) + if (options.data && (!options.type || options.type.toUpperCase() == 'GET')) + options.url = appendQuery(options.url, options.data), options.data = undefined + } + + $.ajax = function(options){ + var settings = $.extend({}, options || {}), + deferred = $.Deferred && $.Deferred() + for (key in $.ajaxSettings) if (settings[key] === undefined) settings[key] = $.ajaxSettings[key] + + ajaxStart(settings) + + if (!settings.crossDomain) settings.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(settings.url) && + RegExp.$2 != window.location.host + + if (!settings.url) settings.url = window.location.toString() + serializeData(settings) + if (settings.cache === false) settings.url = appendQuery(settings.url, '_=' + Date.now()) + + var dataType = settings.dataType, hasPlaceholder = /\?.+=\?/.test(settings.url) + if (dataType == 'jsonp' || hasPlaceholder) { + if (!hasPlaceholder) + settings.url = appendQuery(settings.url, + settings.jsonp ? (settings.jsonp + '=?') : settings.jsonp === false ? '' : 'callback=?') + return $.ajaxJSONP(settings, deferred) + } + + var mime = settings.accepts[dataType], + headers = { }, + setHeader = function(name, value) { headers[name.toLowerCase()] = [name, value] }, + protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol, + xhr = settings.xhr(), + nativeSetHeader = xhr.setRequestHeader, + abortTimeout + + if (deferred) deferred.promise(xhr) + + if (!settings.crossDomain) setHeader('X-Requested-With', 'XMLHttpRequest') + setHeader('Accept', mime || '*/*') + if (mime = settings.mimeType || mime) { + if (mime.indexOf(',') > -1) mime = mime.split(',', 2)[0] + xhr.overrideMimeType && xhr.overrideMimeType(mime) + } + if (settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() != 'GET')) + setHeader('Content-Type', settings.contentType || 'application/x-www-form-urlencoded') + + if (settings.headers) for (name in settings.headers) setHeader(name, settings.headers[name]) + xhr.setRequestHeader = setHeader + + xhr.onreadystatechange = function(){ + if (xhr.readyState == 4) { + xhr.onreadystatechange = empty + clearTimeout(abortTimeout) + var result, error = false + if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || (xhr.status == 0 && protocol == 'file:')) { + dataType = dataType || mimeToDataType(settings.mimeType || xhr.getResponseHeader('content-type')) + result = xhr.responseText + + try { + // http://perfectionkills.com/global-eval-what-are-the-options/ + if (dataType == 'script') (1,eval)(result) + else if (dataType == 'xml') result = xhr.responseXML + else if (dataType == 'json') result = blankRE.test(result) ? null : $.parseJSON(result) + } catch (e) { error = e } + + if (error) ajaxError(error, 'parsererror', xhr, settings, deferred) + else ajaxSuccess(result, xhr, settings, deferred) + } else { + ajaxError(xhr.statusText || null, xhr.status ? 'error' : 'abort', xhr, settings, deferred) + } + } + } + + if (ajaxBeforeSend(xhr, settings) === false) { + xhr.abort() + ajaxError(null, 'abort', xhr, settings, deferred) + return xhr + } + + if (settings.xhrFields) for (name in settings.xhrFields) xhr[name] = settings.xhrFields[name] + + var async = 'async' in settings ? settings.async : true + xhr.open(settings.type, settings.url, async, settings.username, settings.password) + + for (name in headers) nativeSetHeader.apply(xhr, headers[name]) + + if (settings.timeout > 0) abortTimeout = setTimeout(function(){ + xhr.onreadystatechange = empty + xhr.abort() + ajaxError(null, 'timeout', xhr, settings, deferred) + }, settings.timeout) + + // avoid sending empty string (#319) + xhr.send(settings.data ? settings.data : null) + return xhr + } + + // handle optional data/success arguments + function parseArguments(url, data, success, dataType) { + if ($.isFunction(data)) dataType = success, success = data, data = undefined + if (!$.isFunction(success)) dataType = success, success = undefined + return { + url: url + , data: data + , success: success + , dataType: dataType + } + } + + $.get = function(/* url, data, success, dataType */){ + return $.ajax(parseArguments.apply(null, arguments)) + } + + $.post = function(/* url, data, success, dataType */){ + var options = parseArguments.apply(null, arguments) + options.type = 'POST' + return $.ajax(options) + } + + $.getJSON = function(/* url, data, success */){ + var options = parseArguments.apply(null, arguments) + options.dataType = 'json' + return $.ajax(options) + } + + $.fn.load = function(url, data, success){ + if (!this.length) return this + var self = this, parts = url.split(/\s/), selector, + options = parseArguments(url, data, success), + callback = options.success + if (parts.length > 1) options.url = parts[0], selector = parts[1] + options.success = function(response){ + self.html(selector ? + $('
    ').html(response.replace(rscript, "")).find(selector) + : response) + callback && callback.apply(self, arguments) + } + $.ajax(options) + return this + } + + var escape = encodeURIComponent + + function serialize(params, obj, traditional, scope){ + var type, array = $.isArray(obj), hash = $.isPlainObject(obj) + $.each(obj, function(key, value) { + type = $.type(value) + if (scope) key = traditional ? scope : + scope + '[' + (hash || type == 'object' || type == 'array' ? key : '') + ']' + // handle data in serializeArray() format + if (!scope && array) params.add(value.name, value.value) + // recurse into nested objects + else if (type == "array" || (!traditional && type == "object")) + serialize(params, value, traditional, key) + else params.add(key, value) + }) + } + + $.param = function(obj, traditional){ + var params = [] + params.add = function(k, v){ this.push(escape(k) + '=' + escape(v)) } + serialize(params, obj, traditional) + return params.join('&').replace(/%20/g, '+') + } +})(Zepto) + + + + + +;(function($){ + $.fn.serializeArray = function() { + var result = [], el + $([].slice.call(this.get(0).elements)).each(function(){ + el = $(this) + var type = el.attr('type') + if (this.nodeName.toLowerCase() != 'fieldset' && + !this.disabled && type != 'submit' && type != 'reset' && type != 'button' && + ((type != 'radio' && type != 'checkbox') || this.checked)) + result.push({ + name: el.attr('name'), + value: el.val() + }) + }) + return result + } + + $.fn.serialize = function(){ + var result = [] + this.serializeArray().forEach(function(elm){ + result.push(encodeURIComponent(elm.name) + '=' + encodeURIComponent(elm.value)) + }) + return result.join('&') + } + + $.fn.submit = function(callback) { + if (callback) this.bind('submit', callback) + else if (this.length) { + var event = $.Event('submit') + this.eq(0).trigger(event) + if (!event.isDefaultPrevented()) this.get(0).submit() + } + return this + } + +})(Zepto) + + + + + +;(function($){ + // __proto__ doesn't exist on IE<11, so redefine + // the Z function to use object extension instead + if (!('__proto__' in {})) { + $.extend($.zepto, { + Z: function(dom, selector){ + dom = dom || [] + $.extend(dom, $.fn) + dom.selector = selector || '' + dom.__Z = true + return dom + }, + // this is a kludge but works + isZ: function(object){ + return $.type(object) === 'array' && '__Z' in object + } + }) + } + + // getComputedStyle shouldn't freak out when called + // without a valid element as argument + try { + getComputedStyle(undefined) + } catch(e) { + var nativeGetComputedStyle = getComputedStyle; + window.getComputedStyle = function(element){ + try { + return nativeGetComputedStyle(element) + } catch(e) { + return null + } + } + } +})(Zepto) + + + + + +;(function($){ + function detect(ua){ + var os = this.os = {}, browser = this.browser = {}, + webkit = ua.match(/Web[kK]it[\/]{0,1}([\d.]+)/), + android = ua.match(/(Android);?[\s\/]+([\d.]+)?/), + osx = !!ua.match(/\(Macintosh\; Intel /), + ipad = ua.match(/(iPad).*OS\s([\d_]+)/), + ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/), + iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/), + webos = ua.match(/(webOS|hpwOS)[\s\/]([\d.]+)/), + wp = ua.match(/Windows Phone ([\d.]+)/), + touchpad = webos && ua.match(/TouchPad/), + kindle = ua.match(/Kindle\/([\d.]+)/), + silk = ua.match(/Silk\/([\d._]+)/), + blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/), + bb10 = ua.match(/(BB10).*Version\/([\d.]+)/), + rimtabletos = ua.match(/(RIM\sTablet\sOS)\s([\d.]+)/), + playbook = ua.match(/PlayBook/), + chrome = ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/), + firefox = ua.match(/Firefox\/([\d.]+)/), + ie = ua.match(/MSIE\s([\d.]+)/) || ua.match(/Trident\/[\d](?=[^\?]+).*rv:([0-9.].)/), + webview = !chrome && ua.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/), + safari = webview || ua.match(/Version\/([\d.]+)([^S](Safari)|[^M]*(Mobile)[^S]*(Safari))/) + + // Todo: clean this up with a better OS/browser seperation: + // - discern (more) between multiple browsers on android + // - decide if kindle fire in silk mode is android or not + // - Firefox on Android doesn't specify the Android version + // - possibly devide in os, device and browser hashes + + if (browser.webkit = !!webkit) browser.version = webkit[1] + + if (android) os.android = true, os.version = android[2] + if (iphone && !ipod) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.') + if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.') + if (ipod) os.ios = os.ipod = true, os.version = ipod[3] ? ipod[3].replace(/_/g, '.') : null + if (wp) os.wp = true, os.version = wp[1] + if (webos) os.webos = true, os.version = webos[2] + if (touchpad) os.touchpad = true + if (blackberry) os.blackberry = true, os.version = blackberry[2] + if (bb10) os.bb10 = true, os.version = bb10[2] + if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2] + if (playbook) browser.playbook = true + if (kindle) os.kindle = true, os.version = kindle[1] + if (silk) browser.silk = true, browser.version = silk[1] + if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true + if (chrome) browser.chrome = true, browser.version = chrome[1] + if (firefox) browser.firefox = true, browser.version = firefox[1] + if (ie) browser.ie = true, browser.version = ie[1] + if (safari && (osx || os.ios)) {browser.safari = true; if (osx) browser.version = safari[1]} + if (webview) browser.webview = true + + os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) || + (firefox && ua.match(/Tablet/)) || (ie && !ua.match(/Phone/) && ua.match(/Touch/))) + os.phone = !!(!os.tablet && !os.ipod && (android || iphone || webos || blackberry || bb10 || + (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\/([\d.]+)/)) || + (firefox && ua.match(/Mobile/)) || (ie && ua.match(/Touch/)))) + } + + detect.call($, navigator.userAgent) + // make available to unit tests + $.__detect = detect + +})(Zepto) + + + + + +;(function($, undefined){ + var prefix = '', eventPrefix, endEventName, endAnimationName, + vendors = { Webkit: 'webkit', Moz: '', O: 'o' }, + document = window.document, testEl = document.createElement('div'), + supportedTransforms = /^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i, + transform, + transitionProperty, transitionDuration, transitionTiming, transitionDelay, + animationName, animationDuration, animationTiming, animationDelay, + cssReset = {} + + function dasherize(str) { return str.replace(/([a-z])([A-Z])/, '$1-$2').toLowerCase() } + function normalizeEvent(name) { return eventPrefix ? eventPrefix + name : name.toLowerCase() } + + $.each(vendors, function(vendor, event){ + if (testEl.style[vendor + 'TransitionProperty'] !== undefined) { + prefix = '-' + vendor.toLowerCase() + '-' + eventPrefix = event + return false + } + }) + + transform = prefix + 'transform' + cssReset[transitionProperty = prefix + 'transition-property'] = + cssReset[transitionDuration = prefix + 'transition-duration'] = + cssReset[transitionDelay = prefix + 'transition-delay'] = + cssReset[transitionTiming = prefix + 'transition-timing-function'] = + cssReset[animationName = prefix + 'animation-name'] = + cssReset[animationDuration = prefix + 'animation-duration'] = + cssReset[animationDelay = prefix + 'animation-delay'] = + cssReset[animationTiming = prefix + 'animation-timing-function'] = '' + + $.fx = { + off: (eventPrefix === undefined && testEl.style.transitionProperty === undefined), + speeds: { _default: 400, fast: 200, slow: 600 }, + cssPrefix: prefix, + transitionEnd: normalizeEvent('TransitionEnd'), + animationEnd: normalizeEvent('AnimationEnd') + } + + $.fn.animate = function(properties, duration, ease, callback, delay){ + if ($.isFunction(duration)) + callback = duration, ease = undefined, duration = undefined + if ($.isFunction(ease)) + callback = ease, ease = undefined + if ($.isPlainObject(duration)) + ease = duration.easing, callback = duration.complete, delay = duration.delay, duration = duration.duration + if (duration) duration = (typeof duration == 'number' ? duration : + ($.fx.speeds[duration] || $.fx.speeds._default)) / 1000 + if (delay) delay = parseFloat(delay) / 1000 + return this.anim(properties, duration, ease, callback, delay) + } + + $.fn.anim = function(properties, duration, ease, callback, delay){ + var key, cssValues = {}, cssProperties, transforms = '', + that = this, wrappedCallback, endEvent = $.fx.transitionEnd, + fired = false + + if (duration === undefined) duration = $.fx.speeds._default / 1000 + if (delay === undefined) delay = 0 + if ($.fx.off) duration = 0 + + if (typeof properties == 'string') { + // keyframe animation + cssValues[animationName] = properties + cssValues[animationDuration] = duration + 's' + cssValues[animationDelay] = delay + 's' + cssValues[animationTiming] = (ease || 'linear') + endEvent = $.fx.animationEnd + } else { + cssProperties = [] + // CSS transitions + for (key in properties) + if (supportedTransforms.test(key)) transforms += key + '(' + properties[key] + ') ' + else cssValues[key] = properties[key], cssProperties.push(dasherize(key)) + + if (transforms) cssValues[transform] = transforms, cssProperties.push(transform) + if (duration > 0 && typeof properties === 'object') { + cssValues[transitionProperty] = cssProperties.join(', ') + cssValues[transitionDuration] = duration + 's' + cssValues[transitionDelay] = delay + 's' + cssValues[transitionTiming] = (ease || 'linear') + } + } + + wrappedCallback = function(event){ + if (typeof event !== 'undefined') { + if (event.target !== event.currentTarget) return // makes sure the event didn't bubble from "below" + $(event.target).unbind(endEvent, wrappedCallback) + } else + $(this).unbind(endEvent, wrappedCallback) // triggered by setTimeout + + fired = true + $(this).css(cssReset) + callback && callback.call(this) + } + if (duration > 0){ + this.bind(endEvent, wrappedCallback) + // transitionEnd is not always firing on older Android phones + // so make sure it gets fired + setTimeout(function(){ + if (fired) return + wrappedCallback.call(that) + }, (duration * 1000) + 25) + } + + // trigger page reflow so new elements can animate + this.size() && this.get(0).clientLeft + + this.css(cssValues) + + if (duration <= 0) setTimeout(function() { + that.each(function(){ wrappedCallback.call(this) }) + }, 0) + + return this + } + + testEl = null +})(Zepto) + + + + + +;(function($){ + var cache = [], timeout + + $.fn.remove = function(){ + return this.each(function(){ + if(this.parentNode){ + if(this.tagName === 'IMG'){ + cache.push(this) + this.src = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=' + if (timeout) clearTimeout(timeout) + timeout = setTimeout(function(){ cache = [] }, 60000) + } + this.parentNode.removeChild(this) + } + }) + } +})(Zepto) + + + + + + + +;(function($){ + var data = {}, dataAttr = $.fn.data, camelize = $.camelCase, + exp = $.expando = 'Zepto' + (+new Date()), emptyArray = [] + + // Get value from node: + // 1. first try key as given, + // 2. then try camelized key, + // 3. fall back to reading "data-*" attribute. + function getData(node, name) { + var id = node[exp], store = id && data[id] + if (name === undefined) return store || setData(node) + else { + if (store) { + if (name in store) return store[name] + var camelName = camelize(name) + if (camelName in store) return store[camelName] + } + return dataAttr.call($(node), name) + } + } + + // Store value under camelized key on node + function setData(node, name, value) { + var id = node[exp] || (node[exp] = ++$.uuid), + store = data[id] || (data[id] = attributeData(node)) + if (name !== undefined) store[camelize(name)] = value + return store + } + + // Read all "data-*" attributes from a node + function attributeData(node) { + var store = {} + $.each(node.attributes || emptyArray, function(i, attr){ + if (attr.name.indexOf('data-') == 0) + store[camelize(attr.name.replace('data-', ''))] = + $.zepto.deserializeValue(attr.value) + }) + return store + } + + $.fn.data = function(name, value) { + return value === undefined ? + // set multiple values via object + $.isPlainObject(name) ? + this.each(function(i, node){ + $.each(name, function(key, value){ setData(node, key, value) }) + }) : + // get value from first element + this.length == 0 ? undefined : getData(this[0], name) : + // set value on all elements + this.each(function(){ setData(this, name, value) }) + } + + $.fn.removeData = function(names) { + if (typeof names == 'string') names = names.split(/\s+/) + return this.each(function(){ + var id = this[exp], store = id && data[id] + if (store) $.each(names || store, function(key){ + delete store[names ? camelize(this) : key] + }) + }) + } + + // Generate extended `remove` and `empty` functions + ;['remove', 'empty'].forEach(function(methodName){ + var origFn = $.fn[methodName] + $.fn[methodName] = function() { + var elements = this.find('*') + if (methodName === 'remove') elements = elements.add(this) + elements.removeData() + return origFn.call(this) + } + }) +})(Zepto) + + + + + + + +;(function($){ + var slice = Array.prototype.slice + + function Deferred(func) { + var tuples = [ + // action, add listener, listener list, final state + [ "resolve", "done", $.Callbacks({once:1, memory:1}), "resolved" ], + [ "reject", "fail", $.Callbacks({once:1, memory:1}), "rejected" ], + [ "notify", "progress", $.Callbacks({memory:1}) ] + ], + state = "pending", + promise = { + state: function() { + return state + }, + always: function() { + deferred.done(arguments).fail(arguments) + return this + }, + then: function(/* fnDone [, fnFailed [, fnProgress]] */) { + var fns = arguments + return Deferred(function(defer){ + $.each(tuples, function(i, tuple){ + var fn = $.isFunction(fns[i]) && fns[i] + deferred[tuple[1]](function(){ + var returned = fn && fn.apply(this, arguments) + if (returned && $.isFunction(returned.promise)) { + returned.promise() + .done(defer.resolve) + .fail(defer.reject) + .progress(defer.notify) + } else { + var context = this === promise ? defer.promise() : this, + values = fn ? [returned] : arguments + defer[tuple[0] + "With"](context, values) + } + }) + }) + fns = null + }).promise() + }, + + promise: function(obj) { + return obj != null ? $.extend( obj, promise ) : promise + } + }, + deferred = {} + + $.each(tuples, function(i, tuple){ + var list = tuple[2], + stateString = tuple[3] + + promise[tuple[1]] = list.add + + if (stateString) { + list.add(function(){ + state = stateString + }, tuples[i^1][2].disable, tuples[2][2].lock) + } + + deferred[tuple[0]] = function(){ + deferred[tuple[0] + "With"](this === deferred ? promise : this, arguments) + return this + } + deferred[tuple[0] + "With"] = list.fireWith + }) + + promise.promise(deferred) + if (func) func.call(deferred, deferred) + return deferred + } + + $.when = function(sub) { + var resolveValues = slice.call(arguments), + len = resolveValues.length, + i = 0, + remain = len !== 1 || (sub && $.isFunction(sub.promise)) ? len : 0, + deferred = remain === 1 ? sub : Deferred(), + progressValues, progressContexts, resolveContexts, + updateFn = function(i, ctx, val){ + return function(value){ + ctx[i] = this + val[i] = arguments.length > 1 ? slice.call(arguments) : value + if (val === progressValues) { + deferred.notifyWith(ctx, val) + } else if (!(--remain)) { + deferred.resolveWith(ctx, val) + } + } + } + + if (len > 1) { + progressValues = new Array(len) + progressContexts = new Array(len) + resolveContexts = new Array(len) + for ( ; i < len; ++i ) { + if (resolveValues[i] && $.isFunction(resolveValues[i].promise)) { + resolveValues[i].promise() + .done(updateFn(i, resolveContexts, resolveValues)) + .fail(deferred.reject) + .progress(updateFn(i, progressContexts, progressValues)) + } else { + --remain + } + } + } + if (!remain) deferred.resolveWith(resolveContexts, resolveValues) + return deferred.promise() + } + + $.Deferred = Deferred +})(Zepto) + + + + + +;(function($){ + // Create a collection of callbacks to be fired in a sequence, with configurable behaviour + // Option flags: + // - once: Callbacks fired at most one time. + // - memory: Remember the most recent context and arguments + // - stopOnFalse: Cease iterating over callback list + // - unique: Permit adding at most one instance of the same callback + $.Callbacks = function(options) { + options = $.extend({}, options) + + var memory, // Last fire value (for non-forgettable lists) + fired, // Flag to know if list was already fired + firing, // Flag to know if list is currently firing + firingStart, // First callback to fire (used internally by add and fireWith) + firingLength, // End of the loop when firing + firingIndex, // Index of currently firing callback (modified by remove if needed) + list = [], // Actual callback list + stack = !options.once && [], // Stack of fire calls for repeatable lists + fire = function(data) { + memory = options.memory && data + fired = true + firingIndex = firingStart || 0 + firingStart = 0 + firingLength = list.length + firing = true + for ( ; list && firingIndex < firingLength ; ++firingIndex ) { + if (list[firingIndex].apply(data[0], data[1]) === false && options.stopOnFalse) { + memory = false + break + } + } + firing = false + if (list) { + if (stack) stack.length && fire(stack.shift()) + else if (memory) list.length = 0 + else Callbacks.disable() + } + }, + + Callbacks = { + add: function() { + if (list) { + var start = list.length, + add = function(args) { + $.each(args, function(_, arg){ + if (typeof arg === "function") { + if (!options.unique || !Callbacks.has(arg)) list.push(arg) + } + else if (arg && arg.length && typeof arg !== 'string') add(arg) + }) + } + add(arguments) + if (firing) firingLength = list.length + else if (memory) { + firingStart = start + fire(memory) + } + } + return this + }, + remove: function() { + if (list) { + $.each(arguments, function(_, arg){ + var index + while ((index = $.inArray(arg, list, index)) > -1) { + list.splice(index, 1) + // Handle firing indexes + if (firing) { + if (index <= firingLength) --firingLength + if (index <= firingIndex) --firingIndex + } + } + }) + } + return this + }, + has: function(fn) { + return !!(list && (fn ? $.inArray(fn, list) > -1 : list.length)) + }, + empty: function() { + firingLength = list.length = 0 + return this + }, + disable: function() { + list = stack = memory = undefined + return this + }, + disabled: function() { + return !list + }, + lock: function() { + stack = undefined; + if (!memory) Callbacks.disable() + return this + }, + locked: function() { + return !stack + }, + fireWith: function(context, args) { + if (list && (!fired || stack)) { + args = args || [] + args = [context, args.slice ? args.slice() : args] + if (firing) stack.push(args) + else fire(args) + } + return this + }, + fire: function() { + return Callbacks.fireWith(this, arguments) + }, + fired: function() { + return !!fired + } + } + + return Callbacks + } +})(Zepto) + + + + + +;(function($){ + var zepto = $.zepto, oldQsa = zepto.qsa, oldMatches = zepto.matches + + function visible(elem){ + elem = $(elem) + return !!(elem.width() || elem.height()) && elem.css("display") !== "none" + } + + // Implements a subset from: + // http://api.jquery.com/category/selectors/jquery-selector-extensions/ + // + // Each filter function receives the current index, all nodes in the + // considered set, and a value if there were parentheses. The value + // of `this` is the node currently being considered. The function returns the + // resulting node(s), null, or undefined. + // + // Complex selectors are not supported: + // li:has(label:contains("foo")) + li:has(label:contains("bar")) + // ul.inner:first > li + var filters = $.expr[':'] = { + visible: function(){ if (visible(this)) return this }, + hidden: function(){ if (!visible(this)) return this }, + selected: function(){ if (this.selected) return this }, + checked: function(){ if (this.checked) return this }, + parent: function(){ return this.parentNode }, + first: function(idx){ if (idx === 0) return this }, + last: function(idx, nodes){ if (idx === nodes.length - 1) return this }, + eq: function(idx, _, value){ if (idx === value) return this }, + contains: function(idx, _, text){ if ($(this).text().indexOf(text) > -1) return this }, + has: function(idx, _, sel){ if (zepto.qsa(this, sel).length) return this } + } + + var filterRe = new RegExp('(.*):(\\w+)(?:\\(([^)]+)\\))?$\\s*'), + childRe = /^\s*>/, + classTag = 'Zepto' + (+new Date()) + + function process(sel, fn) { + // quote the hash in `a[href^=#]` expression + sel = sel.replace(/=#\]/g, '="#"]') + var filter, arg, match = filterRe.exec(sel) + if (match && match[2] in filters) { + filter = filters[match[2]], arg = match[3] + sel = match[1] + if (arg) { + var num = Number(arg) + if (isNaN(num)) arg = arg.replace(/^["']|["']$/g, '') + else arg = num + } + } + return fn(sel, filter, arg) + } + + zepto.qsa = function(node, selector) { + return process(selector, function(sel, filter, arg){ + try { + var taggedParent + if (!sel && filter) sel = '*' + else if (childRe.test(sel)) + // support "> *" child queries by tagging the parent node with a + // unique class and prepending that classname onto the selector + taggedParent = $(node).addClass(classTag), sel = '.'+classTag+' '+sel + + var nodes = oldQsa(node, sel) + } catch(e) { + console.error('error performing selector: %o', selector) + throw e + } finally { + if (taggedParent) taggedParent.removeClass(classTag) + } + return !filter ? nodes : + zepto.uniq($.map(nodes, function(n, i){ return filter.call(n, i, nodes, arg) })) + }) + } + + zepto.matches = function(node, selector){ + return process(selector, function(sel, filter, arg){ + return (!sel || oldMatches(node, sel)) && + (!filter || filter.call(node, null, arg) === node) + }) + } +})(Zepto) + + + + + +;(function($){ + var touch = {}, + touchTimeout, tapTimeout, swipeTimeout, longTapTimeout, + longTapDelay = 750, + gesture + + function swipeDirection(x1, x2, y1, y2) { + return Math.abs(x1 - x2) >= + Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down') + } + + function longTap() { + longTapTimeout = null + if (touch.last) { + touch.el.trigger('longTap') + touch = {} + } + } + + function cancelLongTap() { + if (longTapTimeout) clearTimeout(longTapTimeout) + longTapTimeout = null + } + + function cancelAll() { + if (touchTimeout) clearTimeout(touchTimeout) + if (tapTimeout) clearTimeout(tapTimeout) + if (swipeTimeout) clearTimeout(swipeTimeout) + if (longTapTimeout) clearTimeout(longTapTimeout) + touchTimeout = tapTimeout = swipeTimeout = longTapTimeout = null + touch = {} + } + + function isPrimaryTouch(event){ + return (event.pointerType == 'touch' || + event.pointerType == event.MSPOINTER_TYPE_TOUCH) + && event.isPrimary + } + + function isPointerEventType(e, type){ + return (e.type == 'pointer'+type || + e.type.toLowerCase() == 'mspointer'+type) + } + + $(document).ready(function(){ + var now, delta, deltaX = 0, deltaY = 0, firstTouch, _isPointerType + + if ('MSGesture' in window) { + gesture = new MSGesture() + gesture.target = document.body + } + + $(document) + .bind('MSGestureEnd', function(e){ + var swipeDirectionFromVelocity = + e.velocityX > 1 ? 'Right' : e.velocityX < -1 ? 'Left' : e.velocityY > 1 ? 'Down' : e.velocityY < -1 ? 'Up' : null; + if (swipeDirectionFromVelocity) { + touch.el.trigger('swipe') + touch.el.trigger('swipe'+ swipeDirectionFromVelocity) + } + }) + .on('touchstart MSPointerDown pointerdown', function(e){ + if((_isPointerType = isPointerEventType(e, 'down')) && + !isPrimaryTouch(e)) return + firstTouch = _isPointerType ? e : e.touches[0] + if (e.touches && e.touches.length === 1 && touch.x2) { + // Clear out touch movement data if we have it sticking around + // This can occur if touchcancel doesn't fire due to preventDefault, etc. + touch.x2 = undefined + touch.y2 = undefined + } + now = Date.now() + delta = now - (touch.last || now) + touch.el = $('tagName' in firstTouch.target ? + firstTouch.target : firstTouch.target.parentNode) + touchTimeout && clearTimeout(touchTimeout) + touch.x1 = firstTouch.pageX + touch.y1 = firstTouch.pageY + if (delta > 0 && delta <= 250) touch.isDoubleTap = true + touch.last = now + longTapTimeout = setTimeout(longTap, longTapDelay) + // adds the current touch contact for IE gesture recognition + if (gesture && _isPointerType) gesture.addPointer(e.pointerId); + }) + .on('touchmove MSPointerMove pointermove', function(e){ + if(touch.last){ + if((_isPointerType = isPointerEventType(e, 'move')) && + !isPrimaryTouch(e)) return + firstTouch = _isPointerType ? e : e.touches[0] + cancelLongTap() + touch.x2 = firstTouch.pageX + touch.y2 = firstTouch.pageY + + deltaX += Math.abs(touch.x1 - touch.x2) + deltaY += Math.abs(touch.y1 - touch.y2) + } + }) + .on('touchend MSPointerUp pointerup', function(e){ + if((_isPointerType = isPointerEventType(e, 'up')) && + !isPrimaryTouch(e)) return + cancelLongTap() + + // swipe + if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > 30) || + (touch.y2 && Math.abs(touch.y1 - touch.y2) > 30)) + + swipeTimeout = setTimeout(function() { + touch.el.trigger('swipe') + touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2))) + touch = {} + }, 0) + + // normal tap + else if ('last' in touch) + // don't fire tap when delta position changed by more than 30 pixels, + // for instance when moving to a point and back to origin + if (deltaX < 30 && deltaY < 30) { + // delay by one tick so we can cancel the 'tap' event if 'scroll' fires + // ('tap' fires before 'scroll') + tapTimeout = setTimeout(function() { + + // trigger universal 'tap' with the option to cancelTouch() + // (cancelTouch cancels processing of single vs double taps for faster 'tap' response) + var event = $.Event('tap') + event.cancelTouch = cancelAll + touch.el.trigger(event) + + // trigger double tap immediately + if (touch.isDoubleTap) { + if (touch.el) touch.el.trigger('doubleTap') + touch = {} + } + + // trigger single tap after 250ms of inactivity + else { + touchTimeout = setTimeout(function(){ + touchTimeout = null + if (touch.el) touch.el.trigger('singleTap') + touch = {} + }, 250) + } + }, 0) + } else { + touch = {} + } + deltaX = deltaY = 0 + + }) + // when the browser window loses focus, + // for example when a modal dialog is shown, + // cancel all ongoing events + .on('touchcancel MSPointerCancel pointercancel', cancelAll) + + // scrolling the window indicates intention of the user + // to scroll, not tap or swipe, so cancel all ongoing events + $(window).on('scroll', cancelAll) + }) + + ;['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown', + 'doubleTap', 'tap', 'singleTap', 'longTap'].forEach(function(eventName){ + $.fn[eventName] = function(callback){ return this.on(eventName, callback) } + }) +})(Zepto) + + + + + +;(function($){ + if ($.os.ios) { + var gesture = {}, gestureTimeout + + function parentIfText(node){ + return 'tagName' in node ? node : node.parentNode + } + + $(document).bind('gesturestart', function(e){ + var now = Date.now(), delta = now - (gesture.last || now) + gesture.target = parentIfText(e.target) + gestureTimeout && clearTimeout(gestureTimeout) + gesture.e1 = e.scale + gesture.last = now + }).bind('gesturechange', function(e){ + gesture.e2 = e.scale + }).bind('gestureend', function(e){ + if (gesture.e2 > 0) { + Math.abs(gesture.e1 - gesture.e2) != 0 && $(gesture.target).trigger('pinch') && + $(gesture.target).trigger('pinch' + (gesture.e1 - gesture.e2 > 0 ? 'In' : 'Out')) + gesture.e1 = gesture.e2 = gesture.last = 0 + } else if ('last' in gesture) { + gesture = {} + } + }) + + ;['pinch', 'pinchIn', 'pinchOut'].forEach(function(m){ + $.fn[m] = function(callback){ return this.bind(m, callback) } + }) + } +})(Zepto) + + + + + +;(function($){ + $.fn.end = function(){ + return this.prevObject || $() + } + + $.fn.andSelf = function(){ + return this.add(this.prevObject || $()) + } + + 'filter,add,not,eq,first,last,find,closest,parents,parent,children,siblings'.split(',').forEach(function(property){ + var fn = $.fn[property] + $.fn[property] = function(){ + var ret = fn.apply(this, arguments) + ret.prevObject = this + return ret + } + }) +})(Zepto) diff --git a/catapp/js/zepto.touch2mouse.js b/catapp/js/zepto.touch2mouse.js new file mode 100644 index 0000000..9c0c352 --- /dev/null +++ b/catapp/js/zepto.touch2mouse.js @@ -0,0 +1,89 @@ +(function ($) { + /** + * If no touch events are available map touch events to corresponding mouse events. + **/ + if(!('ontouchstart' in window)){ + var _fakeCallbacks = {}; // store the faked callbacks so that they can be unbound + function touch2mouse(context,args){ + var type = args[0],//事件类型 + t = type ,matched = false; + if ((typeof type) == "object") { + return args; + } + if(type.indexOf('touchstart')>-1){ + matched = true; + t = t.replace('touchstart','mousedown'); + }else if(t.indexOf('touchend')>-1){ + matched = true; + t = t.replace('touchend','mouseup'); + }else if(t.indexOf('touchmove')>-1){ + matched = true; + t = t.replace('touchmove','mousemove'); + } + if(matched){//匹配到touch事件 + var ci = -1; + //找出callback,需要更换里面的event对象的属性 + for(var i =1;i -1){ + args[ci] = fakeTouches(type, args[ci] , context); + } + } + return args; + } + + function fakeTouches(type, callback, context) { + // wrap the callback with a function that adds a fake + // touches property to the event. + return _fakeCallbacks[callback] = function (event) { + if(event.liveFired)context = this;//if it is delegate event,change context to target element + if (event.button) { + return false; + } + event.touches = [{ + length: 1,// 1 mouse (finger) + clientX: event.clientX, + clientY: event.clientY, + pageX: event.pageX, + pageY: event.pageY, + screenX: event.screenX, + screenY: event.screenY, + target: event.target + }]; + event.touchType = type; + return callback.apply(context, [event]); + } + } + + var _trigger = $.fn.trigger; + $.fn.trigger = function(event, data){ + var args = Array.prototype.slice.call(arguments,0); + return _trigger.apply(this,touch2mouse(this,args)); + }; + var _triggerHandler = $.fn.triggerHandler; + $.fn.triggerHandler = function(event, data){ + var args = Array.prototype.slice.call(arguments,0); + return _triggerHandler.apply(this, touch2mouse(this,args)); + }; + var _on = $.fn.on; + $.fn.on = function(event, selector, data, callback, one){ + var args = Array.prototype.slice.call(arguments,0); + return _on.apply(this,touch2mouse(this,args)); + } + var _off = $.fn.off; + $.fn.off = function(event, selector, callback){ + var args = [event]; + if(typeof selector == 'string'){ + args.push(selector); + } + var result = touch2mouse(this,args).concat([_fakeCallbacks[callback]||callback]); + delete(_fakeCallbacks[callback]); + return _off.apply(this,result); + } + } +})(Zepto); \ No newline at end of file