From f049730567b8cebc65d1fb2e4155d58235add3c8 Mon Sep 17 00:00:00 2001 From: liaoxuezhi Date: Wed, 4 Jun 2014 10:53:38 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=BB=98=E8=AE=A4=E6=89=93?= =?UTF-8?q?=E5=8C=85=E8=B5=84=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 - Gruntfile.js | 8 +- dist/gmu.css | 1891 +++++ dist/gmu.js | 10101 ++++++++++++++++++++++++++ dist/gmu.min.js | 4 + dist/images/calendar-header.png | Bin 0 -> 682 bytes dist/images/cancel.png | Bin 0 -> 538 bytes dist/images/done.png | Bin 0 -> 767 bytes dist/images/icon.png | Bin 0 -> 396 bytes dist/images/icons-36-black.png | Bin 0 -> 3611 bytes dist/images/icons-36-white.png | Bin 0 -> 3648 bytes dist/images/r-flip.png | Bin 0 -> 1480 bytes dist/images/ui-add2desktop-iOS7.png | Bin 0 -> 429 bytes dist/images/ui-add2desktop-new.png | Bin 0 -> 563 bytes dist/images/ui-add2desktop-old.png | Bin 0 -> 264 bytes dist/images/ui-gotop-icon.png | Bin 0 -> 522 bytes dist/images/ui-loading.png | Bin 0 -> 3217 bytes dist/images/ui-slider-arrow.png | Bin 0 -> 524 bytes dist/images/ui-slider-imgbg.png | Bin 0 -> 2175 bytes dist/reset.css | 52 + dist/zepto.js | 1592 ++++ dist/zepto.min.js | 2 + 22 files changed, 13648 insertions(+), 3 deletions(-) create mode 100644 dist/gmu.css create mode 100644 dist/gmu.js create mode 100644 dist/gmu.min.js create mode 100644 dist/images/calendar-header.png create mode 100644 dist/images/cancel.png create mode 100644 dist/images/done.png create mode 100644 dist/images/icon.png create mode 100644 dist/images/icons-36-black.png create mode 100644 dist/images/icons-36-white.png create mode 100644 dist/images/r-flip.png create mode 100644 dist/images/ui-add2desktop-iOS7.png create mode 100644 dist/images/ui-add2desktop-new.png create mode 100644 dist/images/ui-add2desktop-old.png create mode 100644 dist/images/ui-gotop-icon.png create mode 100644 dist/images/ui-loading.png create mode 100644 dist/images/ui-slider-arrow.png create mode 100644 dist/images/ui-slider-imgbg.png create mode 100644 dist/reset.css create mode 100644 dist/zepto.js create mode 100644 dist/zepto.min.js diff --git a/.gitignore b/.gitignore index 94113aa1..43247e82 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ /.idea /gmu_webapp2.0.0.zip /node_modules -/dist /doc /test/report/report.html /test/report/report.xml diff --git a/Gruntfile.js b/Gruntfile.js index f4d0fbc6..0c28cbfb 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -40,8 +40,12 @@ module.exports = function(grunt) { src: [ 'widget/**/*.js', - // 所有的插件都默认不打包,要加的话在下面配。 - '!widget/**/$*.js' + // 过滤掉一些可能冲突的插件 + '!widget/gotop/$iscroll.js', + '!widget/refresh/$*.js', + 'widget/refresh/$iOS5.js', + '!widget/slider/$dynamic.js', + '!widget/slider/$multiview.js' ], dest: 'dist/gmu.js' diff --git a/dist/gmu.css b/dist/gmu.css new file mode 100644 index 00000000..eef1e02c --- /dev/null +++ b/dist/gmu.css @@ -0,0 +1,1891 @@ +/* Gmu v2.1.0 - widget/add2desktop/add2desktop.css, icons.default.css, widget/button/button.css, widget/button/button.default.css, widget/calendar/calendar.css, widget/calendar/calendar.default.css, widget/dialog/dialog.css, widget/dialog/dialog.default.css, widget/popover/popover.css, widget/popover/popover.default.css, widget/dropmenu/dropmenu.css, widget/dropmenu/dropmenu.default.css, widget/gotop/gotop.css, widget/historylist/historylist.css, widget/historylist/historylist.default.css, widget/navigator/navigator.css, widget/navigator/navigator.default.css, widget/panel/panel.css, widget/panel/panel.default.css, widget/progressbar/progressbar.css, widget/progressbar/progressbar.default.css, loading.default.css, widget/refresh/refresh.iscroll.default.css, widget/slider/slider.css, widget/slider/slider.default.css, widget/suggestion/suggestion.css, widget/suggestion/suggestion.default.css, transitions.css, loading.default.css, widget/tabs/tabs.css, widget/tabs/tabs.default.css, widget/toolbar/toolbar.css, widget/toolbar/toolbar.default.css */ + +@fontface { /* for iOS6 fix bug */ + font-family:"FixFont"; + src:url(); +} +.ui-add2desktop { + position: fixed; + bottom: 12px; + display: none; + left: 50%; + width:178px; + height: 55px; + padding: 7px 0 8px 9px; + margin-left: -92px; + z-index: 999; + color: #fff; + background: #494949; + border-radius: 2px; + box-shadow: 0 0 3px rgba(0, 0, 0, 0.8); + outline: 1px solid rgba(0,0,0,0); + font-family: "FixFont"; +} +.ui-add2desktop img { + display: block; + height: 55px; + width: 55px; + padding-right: 3px; + float: left; +} +.ui-add2desktop p{ + position: relative; + right: -3px; + padding: 0; + margin: 0; + font-size:13px; + width: 120px; + float: right; + line-height: 22px; + padding-top:6px; + font-weight: bold; +} + +.ui-add2desktop-icon-iOS7 { + margin:0 2px; + display: inline-block; + height: 24px; + width:18px; + background: url(./images/ui-add2desktop-iOS7.png) no-repeat; + -webkit-background-size:18px 24px; +} + +.ui-add2desktop-icon-new { + margin:0 2px; + display: inline-block; + height: 15px; + width:14px; + background: url(./images/ui-add2desktop-new.png) no-repeat; + -webkit-background-size:14px 15px; +} + +.ui-add2desktop-icon-old { + margin:0 2px; + display: inline-block; + height: 15px; + width:14px; + background: url(./images/ui-add2desktop-old.png) no-repeat; + -webkit-background-size:14px 15px; +} +.ui-add2desktop-close { + position: absolute; + right: 0; + top: 0; + height: 40px; + width: 40px; + cursor: pointer; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} +.ui-add2desktop-close b { + position: absolute; + display: inline-block; + right: 8px; + top: 10px; + height: 3px; + width: 12px; + background: #fff; + border-radius: 2px; + -webkit-transform: rotate(45deg); +} + +.ui-add2desktop-close b:after{ + content:''; + position: absolute; + display: inline-block; + height: 3px; + width: 12px; + background: #fff; + border-radius: 2px; + -webkit-transform: rotate(90deg); +} +.ui-add2desktop-arrow { + width:18px; + height: 10px; + overflow: hidden; + position: absolute; + bottom: -10px; + left:50%; + margin-left: -8px; +} +.ui-add2desktop-arrow b{ + display: inline-block; + position: absolute; + top:-5px; + left:3px; + width:10px; + height: 10px; + background: #494949; + box-shadow: 0 0 3px rgba(0, 0, 0, 0.8); + -webkit-transform: rotate(45deg); +} + +.ui-icon { + background-image: url(./images/icons-36-black.png); + -webkit-background-size: 776px 18px; + background-size: 776px 18px; + width:18px; + height: 18px; + display: inline-block; +} +.ui-icon.white { + background-image: url(./images/icons-36-white.png); +} + +/* plus minus */ +.ui-icon-plus { + background-position: -0 50%; +} +.ui-icon-minus { + background-position: -36px 50%; +} + +/* delete/close */ +.ui-icon-delete { + background-position: -72px 50%; +} + +/* arrows */ +.ui-icon-arrow-r { + background-position: -108px 50%; +} +.ui-icon-arrow-l { + background-position: -144px 50%; +} +.ui-icon-arrow-u { + background-position: -180px 50%; +} +.ui-icon-arrow-d { + background-position: -216px 50%; +} + +/* misc */ +.ui-icon-check { + background-position: -252px 50%; +} +.ui-icon-gear { + background-position: -288px 50%; +} +.ui-icon-refresh { + background-position: -324px 50%; +} +.ui-icon-forward { + background-position: -360px 50%; +} +.ui-icon-back { + background-position: -396px 50%; +} +.ui-icon-grid { + background-position: -432px 50%; +} +.ui-icon-star { + background-position: -468px 50%; +} +.ui-icon-alert { + background-position: -504px 50%; +} +.ui-icon-info { + background-position: -540px 50%; +} +.ui-icon-home { + background-position: -576px 50%; +} +.ui-icon-search { + background-position: -612px 50%; +} +.ui-icon-checkbox { + background-position: -684px 50%; +} +.ui-state-active .ui-icon-checkbox { + background-position: -648px 50%; +} +.ui-icon-checkbox-off { + background-position: -684px 50%; +} +.ui-icon-checkbox-on { + background-position: -648px 50%; +} +.ui-icon-radio { + background-position: -756px 50%; +} +.ui-state-active .ui-icon-radio { + background-position: -720px 50%; +} +.ui-icon-radio-off { + background-position: -756px 50%; +} +.ui-icon-radio-on { + background-position: -720px 50%; +} +.ui-btn{ + cursor:pointer; + -webkit-user-select: none; + -webkit-box-sizing:border-box; + -webkit-appearance:none; +} +.ui-btn.ui-state-disable, +.ui-btn.ui-state-disabled { + cursor: default; + pointer-events: none;/*此属性能屏蔽click事件*/ +} +.ui-btn-icon-only .ui-btn-text, +.ui-btn-icon-notext .ui-btn-text, +.ui-hidden { + display: none; +} +.ui-btn{ + display: inline-block; + padding: 0.5em 0.6em; + margin: 2px; + border: 1px solid #D2D2D2; + -webkit-border-radius: 2px; + border-radius: 2px; + background-color: #fff; + color: #333; + text-decoration: none; + font-size: 14px; + position: relative; +} + +.ui-btn-group { + margin: 2px; + position: relative; + display: inline-block; + font-size: 0; + white-space: nowrap; + vertical-align: middle; +} +.ui-btn-group .ui-btn { + margin: 0; + position: relative; + border-radius: 0; + margin-left: -1px; +} + +.ui-btn-group>.ui-btn:first-child { + border-bottom-left-radius: 4px; + border-top-left-radius: 4px; +} +.ui-btn-group>.ui-btn:last-child { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; +} + +@media all and (min-device-width:768px) and (max-device-width: 1024px){ + .ui-btn{ + font-size: 16px; + } +} +.ui-btn.ui-state-disable, +.ui-btn.ui-state-disabled { + color:#ababab; + background-color:#e6e6e6 ; + border-color: #d2d2d2; +} +.ui-btn.ui-state-active { + color:#fff; + background-color: #2d7ded; + border-color:#135cbe; +} +.ui-btn.ui-state-hover{ + background-color: #d9d9d9; + border-color: #B3B3B3; +} +.ui-btn-icon-left .ui-icon, +.ui-btn-icon-right .ui-icon, +.ui-btn-icon-bottom .ui-icon, +.ui-btn-icon-top .ui-icon{ + position: absolute; +} +.ui-btn-icon-left { + padding-left: 30px; +} +.ui-btn-icon-left .ui-icon { + left: 5px; + top: 50%; + margin-top: -9px; +} +.ui-btn-icon-right { + padding-right: 30px; +} +.ui-btn-icon-right .ui-icon { + right: 5px; + top: 50%; + margin-top: -9px; +} +.ui-btn-icon-top { + padding-top: 30px; +} +.ui-btn-icon-top .ui-icon { + top: 5px; + left: 50%; + margin-left: -9px; +} +.ui-btn-icon-bottom { + padding-bottom: 30px; +} +.ui-btn-icon-bottom .ui-icon { + bottom: 5px; + left: 50%; + margin-left: -9px; +} +.ui-btn-icon-only, +.ui-btn-icon-notext { + padding: 0.38em 0.5em; +} +.ui-holder { + position: absolute !important; + clip: rect(1px 1px 1px 1px); + left: -10000px; +} + +.ui-slideup { + position: absolute; + top: 100%; + width: 100%; + left: 0; +} +.ui-slideup-wrap { + position: absolute; + left: 0; + z-index: 1200; + width: 100%; + background: rgba(255, 255, 255, 0.4); + overflow: hidden; + -webkit-tap-highlight-color: rgba(255, 255, 255, 0); + -webkit-transform: translateZ(0); +} +.ui-calendar { + width: 100%; + line-height: 25px; + font-size: 14px; +} + +.ui-calendar-header { + color: #545454; + text-align: center; + padding: 3px 0; +} + +.ui-calendar-header a { + color: #545454; + text-decoration: none; + display: inline-block; + padding: 5px; + margin: 0 5px; + text-align: center; + border-radius: 3px; + line-height: 1.0; +} +.ui-calendar-header a.ui-state-hover { + background-color: #ccc; +} +.ui-calendar-header .ui-calendar-title { + text-align: center; + display: inline-block; +} + +.ui-calendar-calendar { + width: 100%; + border-collapse: collapse; +} + +.ui-calendar-calendar th, .ui-calendar-calendar td { + text-align: center; + color: #000; + background: #f5f5f5; + border: 1px solid #fff; + font-weight: normal; +} + +.ui-calendar-calendar thead tr { + border: 1px solid #fff; +} + +.ui-calendar-calendar thead th { + color: #fff; + background: #b6b6b6; +} + +.ui-calendar-calendar a { + text-decoration: none; + color:#000; + display: block; +} + +.ui-calendar-calendar tr.ui-calendar-gap td { + line-height: 5px; + font-size: 0; + border: none; + background: transparent; +} + +.ui-calendar-calendar td.ui-calendar-unSelectable { + color: #e1e1e1; +} + +.ui-calendar-calendar td.ui-calendar-today { + background: #FBF9EE; +} +.ui-calendar-calendar td.ui-calendar-current-day { + background: #b6b6b6; + font-weight: bold; + border-color: #fff; +} + +.ui-calendar-calendar td.ui-state-hover { + background: #ccc; +} + +.ui-slideup .header { + line-height: 43px; + height: 43px; + border-top: 1px solid black; + border-bottom: 1px solid black; + opacity: 0.9; + background: url(./images/calendar-header.png) repeat-x; + overflow: hidden; +} +.ui-slideup .ok-btn, .ui-slideup .no-btn { + position: absolute; + top: 7px; + height: 20px; + line-height: 20px; + padding: 0 5px; + margin: 0; + border-width: 5px; + font-size: 12px; + font-weight: bold; + text-shadow: rgba(0, 0, 0, 0.8) 0 -1px 0; + color: white; + text-decoration: none; + display: block; +} +.ui-slideup .ok-btn { + right: 7px; + float: right; + -webkit-border-image: url(./images/done.png) 5; +} +.ui-slideup .no-btn { + left: 7px; + float: left; + -webkit-border-image: url(./images/cancel.png) 5; +} +.ui-slideup .ok-btn.ui-state-hover, .ui-slideup .no-btn.ui-state-hover{ + opacity: 0.4; +} +.ui-slideup .frame { + background: #e1e1e1; + padding: 5px; +} + + +.ui-dialog{ + overflow: hidden; + margin: 0 auto; + z-index: 1002; + position:absolute; + left: 0; + top: -10000px; + display: none; + -webkit-tap-highlight-color: rgba(255, 255, 255, 0); + background-color: white; + -webkit-transform: translateZ(0); + -webkit-user-select: none; + -webkit-user-drag: none; +} +/** mask */ +.ui-mask{ + position: absolute; + top: 0; + left: 0; + background: #888; + opacity: 0.5; + display: none; + z-index: 1001; + -webkit-transform: translateZ(0); + -webkit-tap-highlight-color: rgba(255, 255, 255, 0); + -webkit-user-select: none; + -webkit-user-drag: none; +} +.ui-dialog .ui-dialog-title { + position: relative; +} + +.ui-dialog .ui-dialog-close{ + position: absolute; + top: 5px; + right: 5px; + cursor: pointer; +} +.ui-dialog-container { + position: relative; +} +.ui-dialog{ + background: #f5f5f5; + -webkit-box-shadow: 0px 1px 10px rgba(0, 0, 0, 0.6); + -webkit-border-radius: 3px; +} + +.ui-dialog .ui-dialog-title { + height: 50px; + line-height: 50px; + font-size: 16px; + text-align: center; + background: #373737; + color: #fff; + font-weight: 700; + -webkit-border-radius: 3px 3px 0 0; +} + +.ui-dialog .ui-dialog-close{ + cursor: pointer; + border-width: 0; + display: inline-block; + padding: 7px 9px; + margin: 2px; + line-height: 1; + -webkit-border-radius: 3px; +} + +.ui-dialog .ui-dialog-close .ui-icon { + background-image: url(./images/icons-36-white.png); +} + +.ui-dialog .ui-dialog-close-hover { + background-color: rgba(255, 255, 255, 0.4); +} + +.ui-dialog .ui-dialog-content{ + padding: 20px; + position: relative; +} + +.ui-dialog-btns { + table-layout: fixed; + display: table; + border-collapse: collapse; + margin: 19px 0 0 0; + width: 100%; +} +.ui-dialog-btns .ui-btn { + padding: 0; + font-size: 18px; + width: 100%; + display: table-cell; + float: none; + text-align: center; + height: 44px; + line-height: 44px; + color: #232323; + border: 1px solid #ddd; + background-color: #f7f7f7; + border-bottom: 0 none; + cursor: pointer; +} + +.ui-dialog-btns .ui-btn:first-child { + -webkit-border-bottom-left-radius: 3px; + border-left: 0 none; +} + +.ui-dialog-btns .ui-btn:last-child { + -webkit-border-bottom-right-radius: 3px; + border-right: 0 none; +} + +.ui-dialog-btns .ui-btn.ui-state-hover { + background-color: #e2e2e2; +} + +/*css for pad*/ +@media all and (min-device-width:768px) and (max-device-width: 1024px){ + .ui-dialog{ + min-width: 500px; + } + .ui-dialog .ui-dialog-title{ + min-height: 1.1em; + } +} +.ui-popover { + position: absolute; + display: none; + -webkit-user-select: none; + -webkit-box-sizing: border-box; + z-index: 10; +} + +.ui-popover.ui-in { + display: block; +} +.ui-popover { + background-color: #fff; + padding: 20px; + border-radius: 6px; + border: 1px solid rgba(0,0,0,0.2); +} + +.ui-popover .ui-arrow, .ui-popover .ui-arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border: 11px solid transparent; +} +.ui-popover .ui-arrow:after { + border-width: 10px; + content: ''; +} + +/* 剪头的默认位置 */ +.ui-popover.ui-pos-default { + margin-top: 10px; +} +.ui-popover.ui-pos-default .ui-arrow { + left: 30px; + margin-left: -11px; + top: -11px; + border-top-width: 0; + border-bottom-color: rgba(0, 0, 0, 0.2); +} +.ui-popover.ui-pos-default .ui-arrow:after { + border-top-width: 0; + border-bottom-color: white; + margin-left: -10px; + top: 1px; +} + +/* 剪头 下方 */ +.ui-popover.ui-pos-bottom .ui-arrow { + left: 50%; + margin-left: -11px; + top: -11px; + border-top-width: 0; + border-bottom-color: rgba(0, 0, 0, 0.2); +} +.ui-popover.ui-pos-bottom .ui-arrow:after { + border-top-width: 0; + border-bottom-color: white; + margin-left: -10px; + top: 1px; +} + +/* 剪头 上方 */ +.ui-popover.ui-pos-top .ui-arrow { + left: 50%; + margin-left: -11px; + bottom: -11px; + border-bottom-width: 0; + border-top-color: rgba(0, 0, 0, 0.2); +} +.ui-popover.ui-pos-top .ui-arrow:after { + border-bottom-width: 0; + border-top-color: white; + margin-left: -10px; + bottom: 1px; +} + +/* 剪头 左侧 */ +.ui-popover.ui-pos-left .ui-arrow { + top: 50%; + margin-top: -11px; + right: -11px; + border-right-width: 0; + border-left-color: rgba(0, 0, 0, 0.2); +} +.ui-popover.ui-pos-left .ui-arrow:after { + border-right-width: 0; + border-left-color: white; + bottom: -10px; + right: 1px; +} + +/* 剪头 右侧 */ +.ui-popover.ui-pos-right .ui-arrow { + top: 50%; + margin-top: -11px; + left: -11px; + border-left-width: 0; + border-right-color: rgba(0, 0, 0, 0.2); +} +.ui-popover.ui-pos-right .ui-arrow:after { + border-left-width: 0; + border-right-color: white; + bottom: -10px; + left: 1px; +} +.ui-dropmenu { + position: absolute; + display: none; + -webkit-user-select: none; + -webkit-box-sizing: border-box; + z-index: 10; +} + +.ui-dropmenu.ui-in { + display: block; +} + +.ui-dropmenu-items, .ui-dropmenu-items>li { + list-style: none; + white-space:nowrap;/*内容不换行*/ +} +.ui-dropmenu { + background-color: #fff; + padding: 5px 0; + border-radius: 6px; + border: 1px solid rgba(0,0,0,0.2); + -webkit-box-shadow: 0 5px 10px rgba(0,0,0,0.2); + min-width: 160px; +} + +.ui-dropmenu-items>li { + line-height: 20px; + display: list-item; +} + +.ui-dropmenu-items>li>a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 20px; + color: #333; + white-space: nowrap; + text-decoration: none; +} + +.ui-dropmenu-items>li.ui-state-hover>a, .ui-dropmenu-items>li.ui-state-active>a { + color: #fff; + text-decoration: none; + background-color: #0081c2; + background-image: -webkit-linear-gradient(top,#08c,#0077b3); + background-repeat: repeat-x; +} + +.ui-dropmenu-items .divider { + height: 1px; + margin: 9px 1px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #fff; +} + +.ui-dropmenu-items>li .ui-icon { + position: relative; + vertical-align: top; + left: -5px; + top: 1px; +} + +.ui-dropmenu-items>li.ui-state-active .ui-icon, .ui-dropmenu-items>li.ui-state-hover .ui-icon { + background-image: url(./images/icons-36-white.png); +} + +/* --------------------------------------- + * 剪头位置 + * ---------------------------------------*/ + +.ui-dropmenu .ui-arrow, .ui-dropmenu .ui-arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border: 11px solid transparent; +} +.ui-dropmenu .ui-arrow:after { + border-width: 10px; + content: ''; +} + +/* 剪头的默认位置 */ +.ui-dropmenu.ui-pos-default { + margin-top: 10px; +} +.ui-dropmenu.ui-pos-default .ui-arrow { + left: 30px; + margin-left: -11px; + top: -11px; + border-top-width: 0; + border-bottom-color: rgba(0, 0, 0, 0.2); +} +.ui-dropmenu.ui-pos-default .ui-arrow:after { + border-top-width: 0; + border-bottom-color: white; + margin-left: -10px; + top: 1px; +} + +.ui-dropmenu.ui-pos-bottom-left .ui-arrow, +.ui-dropmenu.ui-pos-bottom-center .ui-arrow, +.ui-dropmenu.ui-pos-bottom-right .ui-arrow { + top: -11px; + margin-left: -11px; + border-top-width: 0; + border-bottom-color: rgba(0, 0, 0, 0.2); +} + +.ui-dropmenu.ui-pos-bottom-left .ui-arrow:after, +.ui-dropmenu.ui-pos-bottom-center .ui-arrow:after, +.ui-dropmenu.ui-pos-bottom-right .ui-arrow:after { + border-top-width: 0; + border-bottom-color: white; + margin-left: -10px; + top: 1px; +} + +.ui-dropmenu.ui-pos-bottom-left .ui-arrow { + left: 20%; +} +.ui-dropmenu.ui-pos-bottom-center .ui-arrow { + left: 50%; +} +.ui-dropmenu.ui-pos-bottom-right .ui-arrow { + left: 80%; +} + +.ui-dropmenu.ui-pos-top-left .ui-arrow, +.ui-dropmenu.ui-pos-top-center .ui-arrow, +.ui-dropmenu.ui-pos-top-right .ui-arrow { + bottom: -11px; + margin-left: -11px; + border-bottom-width: 0; + border-top-color: rgba(0, 0, 0, 0.2); +} + +.ui-dropmenu.ui-pos-top-left .ui-arrow:after, +.ui-dropmenu.ui-pos-top-center .ui-arrow:after, +.ui-dropmenu.ui-pos-top-right .ui-arrow:after { + border-bottom-width: 0; + border-top-color: white; + margin-left: -10px; + bottom: 1px; +} + +.ui-dropmenu.ui-pos-top-left .ui-arrow { + left: 20%; +} +.ui-dropmenu.ui-pos-top-center .ui-arrow { + left: 50%; +} +.ui-dropmenu.ui-pos-top-right .ui-arrow { + left: 80%; +} + +/* --------------------------------------- + * 垂直排列 + * ---------------------------------------*/ + + .ui-dropmenu.ui-horizontal { + min-width: 50px; + } + .ui-dropmenu.ui-horizontal .ui-dropmenu-items { + padding: 0 10px; + } + .ui-dropmenu.ui-horizontal .ui-dropmenu-items>li { + display: inline-block; + } + .ui-dropmenu.ui-horizontal .ui-dropmenu-items>li.divider { + width: 2px; + margin: 0 5px; + height: auto; + padding: 0; + position: relative; + overflow: visible; + } + .ui-dropmenu.ui-horizontal .ui-dropmenu-items>li.divider:after { + content: ''; + display: block; + position: absolute; + width: 1px; + height: 30px; + top: -15px; + background-color: #e5e5e5; + border-right: 1px solid #fff; + } + + .ui-dropmenu.ui-horizontal .ui-dropmenu-items>li>a { + width: 30px; + height: 30px; + padding:0; + text-indent: -9999px; + overflow: hidden; + position: relative; + } + .ui-dropmenu.ui-horizontal .ui-dropmenu-items>li .ui-icon { + position: absolute; + left: 50%; + top: 50%; + margin-top: -9px; + margin-left: -9px; + } + +.ui-gotop { + position: fixed; + display: none; + width: 50px; + height: 50px; + bottom: 10px; + right: 10px; + z-index: 999; + cursor:pointer; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +.ui-gotop div { + margin: 5px; + width: 40px; + height: 40px; + border-radius: 2px; + -webkit-box-shadow: 0px 0px 5px #9c9c9c; + opacity: 0.9; + background:#454545 url(./images/ui-gotop-icon.png) no-repeat center center; + -webkit-background-size: 18px 15px; +} + +/*css for pad*/ +@media all and (min-device-width:768px) and (max-device-width: 1024px){ + .ui-gotop{ + width:60px; + height: 60px; + } + .ui-gotop div{ + width: 48px; + height: 48px; + -webkit-background-size: 22px 18px; + } +} +.ui-historylist { + overflow: hidden; +} +.ui-historylist-itemwrap { + line-height: 2.5em; + overflow: hidden; + white-space: nowrap; +} +.ui-historylist-item { + height: 100%; + display: block; +} +.ui-historylist-clear { + line-height: 2.5em; + text-align: center; +} +.ui-historylist { + padding-top: 1px; +} +.ui-historylist-itemwrap { + border: 1px solid #E1E1E1; + border-width: 1px 1px 0 1px; + background-color: #FFF; + margin-top: -1px; +} +.ui-historylist-item { + padding-left: 50px; + border-bottom: 1px solid #E1E1E1; + background: url(./images/icon.png) no-repeat 15px 11px; + background-size: 18px 18px; +} +.ui-historylist-clear { + border: 1px solid #E1E1E1; + background-color: #FFF; + margin-top: -1px; +} +.ui-historylist-itemwrap { + -webkit-transition-duration: 300ms; + -webkit-transition-property: -webkit-transform; +} +.ui-historylist-itemmoving { + -webkit-transition-duration: 0; +} +.ui-navigator-list, +.ui-navigator-list li { + list-style: none; +} +.ui-navigator-list li { + display: inline-block; + white-space:nowrap;/*内容不换行*/ +} +/** 一级导航样式 */ +.ui-navigator { + border-top: 1px solid #2468c9; + border-bottom: 1px solid #0145a5; + background:#2773dc; +} +.ui-navigator-list { + width: 100%; + display: -webkit-box; +} +.ui-navigator-list li { + line-height: 34px; + font-size: 16px; + font-weight: bold; + text-align: center; + -webkit-box-flex: 1; + display: -webkit-box; + -webkit-box-align: center; + -webkit-box-pack: center; +} +.ui-navigator-list li a { + text-decoration: none; + color: #ffffff; + display: block; + width: 100%; + -webkit-box-sizing:border-box; + padding: 0 15px; +} +.ui-navigator-list li.ui-state-hover, +.ui-navigator-list li.ui-state-active { + background: #0c4da8; +} + +.ui-scroller { + padding: 0; + margin: 0; + display: inline-block;/*重要,靠他让宽度由子节点撑开*/ +} +.ui-scroller .ui-navigator-list { + display: table; + table-layout: fixed;/*宽度可控*/ + white-space:nowrap;/*内容不换行*/ + width: auto; +} +.ui-scroller .ui-navigator-list:after { + content: ''; + clear: both; + display: inline-block; + width: 0; + height: 0; + overflow: hidden; +} +.ui-scroller .ui-navigator-list li { + display: inline-block; + /*float: left;*/ +} +.ui-panel{ + position: absolute; + display: block; +} + +.ui-panel-contentWrap{ + position: relative; + z-index: 1; +} + +.ui-panel.ui-panel-right{ + right: 0; +} + +.ui-panel.ui-panel-left{ + left: 0; +} + +.ui-panel.ui-panel-push{ + z-index: 999; +} +.ui-panel.ui-panel-overlay{ + z-index: 1001; +} +.ui-panel.ui-panel-reveal{ + z-index: 0; +} + +.ui-panel-animate{ + -webkit-transition: -webkit-transform 350ms ease; +} + +.ui-panel-dismiss{ + position: absolute; + z-index: 1000; + height: 100%; + top: 0; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} +.ui-panel{ + width: 15em; + height: 100%; + top: 0; + padding: 10px; + background: -webkit-gradient(linear, left top, left bottom, from(#444444), to(#222222)); + color: #ffffff; +} + +.ui-progressbar-bg { + border-radius: 5px; + position: relative; + -webkit-user-select:none; +} +.ui-progressbar-filled { + position: absolute; + border-radius: 5px; + -webkit-transform: translate3d(0, 0, 0); + -webkit-transition-duration: 0ms; + -webkit-user-select:none; + pointer-events:none; +} +.ui-progressbar-button { + position: absolute; + -webkit-transform: translate3d(0, 0, 0); + -webkit-transition-duration: 0ms; + -webkit-user-select:none; +} + +/* 横向样式 */ +.ui-progressbar-h .ui-progressbar-bg { + height: 5px; +} +.ui-progressbar-h .ui-progressbar-filled { + width:0; + height: 100%; +} + + +/* 竖向样式 */ + +.ui-progressbar-v .ui-progressbar-bg { + height:100%; + width: 5px; +} +.ui-progressbar-v .ui-progressbar-filled { + top: 100%; + height:0; + width: 100%; +} +.ui-progressbar-v .ui-progressbar-button { + top: 100%; +} + +.ui-progressbar-bg { + background: #5e5e5e; +} +.ui-progressbar-filled { + background: #2a94d9; +} +.ui-progressbar-button { + height: 30px; + width:30px; + border-radius: 15px; +} +.ui-progressbar-button div { + height: 18px; + width: 18px; + background: #efefef; + border-radius: 9px; + margin: 6px; + box-shadow:0 0 8px rgba(255, 255, 255, 0.4); +} +.ui-progressbar-button div b { + position: relative; + display: block; + width:8px; + height: 8px; + left:5px; + top:5px; + border-radius: 4px; + background: #64aef7; +} +.ui-progressbar-button-pressed div b{ + background: #036bd1; +} + +/* 横向样式 */ +.ui-progressbar-h .ui-progressbar-bg { + border: 1px solid #111; + border-bottom: 1px solid #3d3d3d; +} +.ui-progressbar-h .ui-progressbar-button { + top: -12px; + margin-left: -15px; +} + +/* 竖向样式 */ + +.ui-progressbar-v .ui-progressbar-bg { + border: 1px solid #111; + margin-top: -1px; + border-left: 1px solid #3d3d3d; +} + +.ui-progressbar-v .ui-progressbar-button { + margin-top: -15px; + margin-left: -13px; +} +.ui-loading { + width: 40px; + height: 40px; + text-indent: -10000px; + background: url(./images/ui-loading.png) 0 0 no-repeat; + -webkit-background-size: 40px 40px; + -webkit-animation-name: ui-loading-anim; + -webkit-animation-duration: 1s; + -webkit-animation-iteration-count: infinite; + -webkit-animation-timing-function: step-start; +} + +@-webkit-keyframes ui-loading-anim { + from { + -webkit-transform: rotate(0deg); + } + 8.32% { + -webkit-transform: rotate(0deg); + } + 8.33% { + -webkit-transform: rotate(30deg); + } + 16.65% { + -webkit-transform: rotate(30deg); + } + 16.66% { + -webkit-transform: rotate(60deg); + } + 24.99% { + -webkit-transform: rotate(60deg); + } + 25% { + -webkit-transform: rotate(90deg); + } + 33.32% { + -webkit-transform: rotate(90deg); + } + 33.33% { + -webkit-transform: rotate(120deg); + } + 41.65% { + -webkit-transform: rotate(120deg); + } + 41.66% { + -webkit-transform: rotate(150deg); + } + 49.99% { + -webkit-transform: rotate(150deg); + } + 50% { + -webkit-transform: rotate(180deg); + } + 58.32% { + -webkit-transform: rotate(180deg); + } + 58.33% { + -webkit-transform: rotate(210deg); + } + 66.65% { + -webkit-transform: rotate(210deg); + } + 66.66% { + -webkit-transform: rotate(240deg); + } + 74.99% { + -webkit-transform: rotate(240deg); + } + 75% { + -webkit-transform: rotate(270deg); + } + 83.32% { + -webkit-transform: rotate(270deg); + } + 83.33% { + -webkit-transform: rotate(300deg); + } + 91.65% { + -webkit-transform: rotate(300deg); + } + 91.66% { + -webkit-transform: rotate(330deg); + } + 99.99% { + -webkit-transform: rotate(330deg); + } + to { + -webkit-transform: rotate(360deg); + } +} + +.ui-refresh .ui-refresh-up .ui-refresh-icon, +.ui-refresh .ui-refresh-down .ui-refresh-icon{ + display: inline-block; + width: 25px; + height: 25px; + vertical-align: middle; + background: url(./images/r-flip.png) no-repeat; + -webkit-background-size: 25px 25px; + -webkit-transition-property: -webkit-transform; + -webkit-transition-duration: 400ms; + -webkit-transition-timing-function: ease-in-out; +} + +.ui-refresh .ui-refresh-down .ui-refresh-icon{ + -webkit-transform: rotate(180deg) translateZ(0); +} + +.ui-refresh .ui-refresh-up .ui-refresh-flip{ + -webkit-transform: rotate(180deg) translateZ(0); +} + +.ui-refresh .ui-refresh-down .ui-refresh-flip{ + -webkit-transform: rotate(0deg) translateZ(0); +} + + +.ui-refresh .ui-refresh-up .ui-loading, +.ui-refresh .ui-refresh-down .ui-loading{ + -webkit-transition-duration: 0ms; /*停止flip动画*/ +} +.ui-slider { + width: 100%; + overflow: hidden; + position: relative; + -webkit-user-select: none; + -webkit-touch-callout:none; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +.ui-slider-group { + overflow: hidden; + position: relative; + white-space:nowrap;/*内容不换行*/ + -webkit-transform: translateZ(0); +} + +.ui-slider-item { + background-color: #e3e3e3; + text-align: center; + position: relative; + float:left; + overflow: hidden; + -webkit-box-sizing:border-box; +} +.ui-slider-item { + height: 148px; +} + +.ui-slider-item img { + background:#E7E7E7 url(./images/ui-slider-imgbg.png) center center no-repeat; +} + +.ui-slider-item > a { + display: block; + text-decoration: none; + /*由于slide-item有3d属性,导致android上最后一个overflow:hidden无效,所以给子集也加个overflow:hidden;*/ + width: 100%; + overflow: hidden; +} + +.ui-slider-item > p { + position: absolute; + bottom: 0; + width: 100%; + text-align: left; + pointer-events: none; + overflow: hidden; + word-break: break-all; + white-space: nowrap; + text-overflow: ellipsis; + color: #fff; + background: rgba(0, 0, 0, 0.5); + padding: 6px 0; + text-indent: 10px; +} +.ui-slider-dots { + position: absolute; + bottom: 6px; + right: 0; + padding: 0 6px; + text-align: right; +} +.ui-slider-dots > b { + display: inline-block; + margin: 0 4px; + width: 6px; + height: 6px; + border-radius: 3px; + background: rgba(144, 144, 144, 0.8); +} + +.ui-slider-dots .ui-state-active { + background: #fff; +} + +.ui-slider-pre, .ui-slider-next { + position: absolute; + z-index: 99; + width: 50px; + height: 60px; + top:50%; + left: 0; + margin-top: -30px; + outline: none; +} +.ui-slider-next { + right: 0; + left: auto; +} +.ui-slider-pre:after, .ui-slider-next:after { + position: absolute; + width: 20px; + height: 40px; + background: rgba(0, 0, 0, 0.3) url(./images/ui-slider-arrow.png) no-repeat; + background-size: 35px 15px; + outline: none; + content: '\0020'; + display: inline-block; + background-position: 3px center; + left: 0; + top: 50%; + margin-top: -20px; + border-radius: 0 20px 20px 0; +} +.ui-slider-next:after { + background-position: -18px center; + right: 0; + left: auto; + border-radius: 20px 0 0 20px; +} + +/*css for pad*/ +@media all and (min-device-width:768px) and (max-device-width: 1024px){ + .ui-slider-item > p { + font-size: 16px; + padding: .5em 0; + text-indent: .8em; + } + .ui-slider-dots { + bottom:.5em; + padding-right: .5em; + } + + .ui-slider-dots b { + margin-right: .5em; + width: .5em; + height: .5em; + border-radius: .25em; + } +} + +.ui-suggestion-mask{ + position: relative; + z-index: 100; + display: -webkit-box; +} + +.ui-suggestion-mask input{ + -webkit-box-flex: 1; + display: block; +} +.ui-suggestion{ + position: absolute; + display: none; + z-index: 100; + width: 100%; + -webkit-box-sizing: border-box; +} + +.ui-suggestion ul li{ + position: relative; +} + +.ui-suggestion-button span{ + display: inline-block; +} + +.ui-suggestion-button span.ui-suggestion-clear{ + float: left; +} + +.ui-suggestion-button span.ui-suggestion-close{ + float: right; +} + +.ui-suggestion .ui-suggestion-plus{ + position: absolute; +} +.ui-suggestion{ + top: 0; + left: 0; + font-size: 16px; + border: 1px solid #b1b1b1; + background-color:#fff; +} + +.ui-suggestion ul{ + list-style: none; + background: #fff; +} + +.ui-suggestion ul li{ + border-bottom: 1px solid #e7e7e7; + padding: 0.5em 10px; +} + + +.ui-suggestion-highlight{ + background: #ededed; +} + +.ui-suggestion ul li span{ + color: #878787; +} + +.ui-suggestion .ui-suggestion-button{ + background: #f7f7f7; + height: 33px; + line-height: 33px; +} + +.ui-suggestion-button span{ + text-decoration: none; + text-align: center; + color: #4B4B4B; + font-size: 14px; + padding: 0 10px; + cursor: pointer; +} + +.ui-suggestion-button span.ui-suggestion-clear{ + border-right: 1px solid #e7e7e7; +} + +.ui-suggestion-button span.ui-suggestion-close{ + border-left: 1px solid #e7e7e7; +} + +.ui-suggestion .ui-suggestion-plus{ + right: 0; + top: 0; + bottom: 0; + width: 52px; + background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAI5JREFUSEtjZCACLF261J6RkbELpPT///9l0dHRB4nQRlgJ0ODny5Yt+w/CIDZhHUSqgBkKo4nURljZqMHwMBohQQFK/ECvnkT3LgX8kyAzGZATPwWGgTMPSiYCGvyEWgYiGfyEAcjxoKaroWZ5EM52QBUjJLkRExajQUH7Qgg5E4HYxMQLUWpgmYiUxA8AOdLMz+iDKvIAAAAASUVORK5CYII=") no-repeat scroll center center white; + -webkit-background-size: 11px 11px; +} + +@media all and (min-device-width: 768px) and (max-device-width: 1024px){ + .ui-suggestion{ + font-size: 18px; + } + .ui-suggestion .ui-suggestion-button{ + height: 40px; + line-height: 40px; + } +} +/*Transition*/ +.ui-viewport-transitioning .ui-panel { + width: 100%; + height: 100%; + overflow: hidden; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} +.ui-viewport-transitioning .ui-loading { + -webkit-animation-name: none; +} +.in { + -webkit-animation-timing-function: ease-out; + -webkit-animation-duration: 350ms; +} +.out { + -webkit-animation-timing-function: ease-in; + -webkit-animation-duration: 225ms; +} + +/* keyframes for slidein from sides */ +@-webkit-keyframes slideinfromright { + from { -webkit-transform: translateX(100%); } + to { -webkit-transform: translateX(0); } +} + +@-webkit-keyframes slideinfromleft { + from { -webkit-transform: translateX(-100%); } + to { -webkit-transform: translateX(0); } +} +/* keyframes for slideout to sides */ +@-webkit-keyframes slideouttoleft { + from { -webkit-transform: translateX(0); } + to { -webkit-transform: translateX(-100%); } +} + +@-webkit-keyframes slideouttoright { + from { -webkit-transform: translateX(0); } + to { -webkit-transform: translateX(100%); } +} +.slide.out, .slide.in { + -webkit-animation-timing-function: linear; + -webkit-animation-duration: 350ms; +} +.slide.out { + -webkit-animation-name: slideouttoleft; + -webkit-transform: translateX(-100%); +} + +.slide.in { + -webkit-animation-name: slideinfromright; + -webkit-transform: translateX(0); +} + +.slide.out.reverse { + -webkit-animation-name: slideouttoright; + -webkit-transform: translateX(100%); +} + +.slide.in.reverse { + -webkit-animation-name: slideinfromleft; + -webkit-transform: translateX(0); +} +.ui-loading { + width: 40px; + height: 40px; + text-indent: -10000px; + background: url(./images/ui-loading.png) 0 0 no-repeat; + -webkit-background-size: 40px 40px; + -webkit-animation-name: ui-loading-anim; + -webkit-animation-duration: 1s; + -webkit-animation-iteration-count: infinite; + -webkit-animation-timing-function: step-start; +} + +@-webkit-keyframes ui-loading-anim { + from { + -webkit-transform: rotate(0deg); + } + 8.32% { + -webkit-transform: rotate(0deg); + } + 8.33% { + -webkit-transform: rotate(30deg); + } + 16.65% { + -webkit-transform: rotate(30deg); + } + 16.66% { + -webkit-transform: rotate(60deg); + } + 24.99% { + -webkit-transform: rotate(60deg); + } + 25% { + -webkit-transform: rotate(90deg); + } + 33.32% { + -webkit-transform: rotate(90deg); + } + 33.33% { + -webkit-transform: rotate(120deg); + } + 41.65% { + -webkit-transform: rotate(120deg); + } + 41.66% { + -webkit-transform: rotate(150deg); + } + 49.99% { + -webkit-transform: rotate(150deg); + } + 50% { + -webkit-transform: rotate(180deg); + } + 58.32% { + -webkit-transform: rotate(180deg); + } + 58.33% { + -webkit-transform: rotate(210deg); + } + 66.65% { + -webkit-transform: rotate(210deg); + } + 66.66% { + -webkit-transform: rotate(240deg); + } + 74.99% { + -webkit-transform: rotate(240deg); + } + 75% { + -webkit-transform: rotate(270deg); + } + 83.32% { + -webkit-transform: rotate(270deg); + } + 83.33% { + -webkit-transform: rotate(300deg); + } + 91.65% { + -webkit-transform: rotate(300deg); + } + 91.66% { + -webkit-transform: rotate(330deg); + } + 99.99% { + -webkit-transform: rotate(330deg); + } + to { + -webkit-transform: rotate(360deg); + } +} + +.ui-tabs { + -webkit-tap-highlight-color: rgba(0,0,0,0); +} +.ui-tabs-nav { + list-style: none; + padding: 0; + margin: 0; + z-index: 11; + position: relative; +} +.ui-tabs-content { + position: relative; + min-height: 100px; + width: 100%; + -webkit-box-sizing: border-box; + overflow: hidden; + -webkit-transition: height 200ms ease-in-out; +} +.ui-tabs-content .ui-tabs-panel { + display: none; + position: absolute; + top:0; + left: 0; + width: 100%; + -webkit-box-sizing: border-box; + min-height: 100px; +} +.ui-tabs-panel { + -webkit-transform: translateZ(0); +} +.ui-tabs-content .ui-tabs-panel.ui-state-active, .ui-viewport-transitioning .ui-tabs-panel.out { + display: block; + z-index: 1; +} +.ui-tabs-content .ui-tabs-panel.ui-state-active { + z-index: 2; +} +.ui-tabs-nav { + display: -webkit-box; + width: 100%; +} +.ui-tabs-nav li { + border: solid #d4d4d4; + border-width: 1px 0 1px 1px; + -webkit-box-flex:1; + text-align: center; + color: #4a4a4a; + font-size: 16px; + background-color: #f4f4f4; + height: 35px; + line-height: 35px; + white-space:nowrap;/*内容不换行*/ + cursor: pointer; +} +.ui-tabs-nav li a { + text-decoration: none; + color: #4a4a4a; +} +.ui-tabs-nav li:last-child { + border-width: 1px; +} +.ui-tabs-nav li.ui-state-active{ + background-color: #fff; + border-bottom-color:#fff; +} +.ui-tabs-content { + border: solid #d4d4d4; + border-width: 0 1px 1px; +} +.ui-tabs-content .ui-tabs-panel { + padding: 1em; +} +.ui-tabs-panel .ui-loading { + position: absolute; + left: 50%; + top: 50px; + margin-top: -20px; + margin-left: -20px; +} +.ui-tabs-panel .ui-load-error { + color: red; + text-align: center; +} +.ui-toolbar { + width:100%; + z-index: 999 +} + +.ui-toolbar-wrap { + position: relative; +} + +.ui-toolbar-placeholder { + margin: 0; + padding: 0; + border: 0; + overflow: visible; + position: relative; +} + +.ui-toolbar-title { + height: 100%; +} + +.ui-toolbar-left, .ui-toolbar-right { + position: absolute; + top:0; + height: 100%; +} + +.ui-toolbar-left { + left: 0; +} +.ui-toolbar-right { + top:3px; + right: 0; +} +.ui-toolbar-left > * { + display: inline-block; + float: left; + margin-right:5px; + text-align: center; +} +.ui-toolbar-right > * { + display: inline-block; + float: right; + margin-right:10px; + text-align: center; +} + + + + +.ui-toolbar-wrap { + height: 40px; + border: #d2d2d2 solid 1px; + border-width: 1px 0; + background: #f4f4f4; +} + +.ui-toolbar-wrap a { + text-decoration: none; +} + +.ui-toolbar-title { + text-align: center; + line-height: 40px; +} +.ui-toolbar-button { + display: inline-block; + padding: 0.5em 0.6em; + margin: 2px; + border: 1px solid #D2D2D2; + -webkit-border-radius: 2px; + border-radius: 2px; + background-color: #FFF; + color: #333; + text-decoration: none; + font-size: 14px; +} + +/*css for pad*/ +@media all and (min-device-width:768px) and (max-device-width: 1024px){ + .ui-toolbar-wrap { + height: 48px; + } + .ui-toolbar-title { + font-size: 16px; + line-height: 48px; + } +} diff --git a/dist/gmu.js b/dist/gmu.js new file mode 100644 index 00000000..ceb0762b --- /dev/null +++ b/dist/gmu.js @@ -0,0 +1,10101 @@ +/* Gmu v2.1.0 - core/gmu.js, core/event.js, extend/parseTpl.js, core/widget.js, extend/throttle.js, extend/event.scrollStop.js, extend/matchMedia.js, extend/event.ortchange.js, extend/fix.js, widget/add2desktop/add2desktop.js, extend/highlight.js, widget/button/button.js, widget/button/$input.js, extend/touch.js, widget/calendar/calendar.js, widget/calendar/$picker.js, widget/dialog/dialog.js, extend/offset.js, extend/position.js, widget/dialog/$position.js, widget/popover/popover.js, widget/dropmenu/dropmenu.js, widget/dropmenu/horizontal.js, widget/dropmenu/placement.js, widget/gotop/gotop.js, widget/historylist/historylist.js, widget/navigator/navigator.js, extend/iscroll.js, widget/navigator/$scrollable.js, widget/navigator/evenness.js, widget/navigator/scrolltonext.js, widget/panel/panel.js, widget/popover/arrow.js, widget/popover/collision.js, widget/popover/dismissible.js, widget/popover/placement.js, widget/progressbar/progressbar.js, widget/refresh/refresh.js, widget/slider/slider.js, widget/slider/$autoplay.js, widget/slider/$lazyloadimg.js, widget/slider/$touch.js, widget/slider/arrow.js, widget/slider/dots.js, widget/slider/imgzoom.js, widget/suggestion/suggestion.js, widget/suggestion/$iscroll.js, widget/suggestion/$posadapt.js, widget/suggestion/$quickdelete.js, widget/suggestion/compatdata.js, widget/suggestion/renderlist.js, widget/suggestion/sendrequest.js, widget/tabs/tabs.js, widget/tabs/$ajax.js, widget/tabs/$swipe.js, widget/toolbar/toolbar.js, widget/toolbar/$position.js, widget/refresh/$iOS5.js */ +// Copyright (c) 2013, Baidu Inc. All rights reserved. +// +// Licensed under the BSD License +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://gmu.baidu.com/license.html +// +// 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. + +/** + * @file 声明gmu命名空间 + * @namespace gmu + * @import zepto.js +*/ + +/** + * GMU是基于zepto的轻量级mobile UI组件库,符合jquery ui使用规范,提供webapp、pad端简单易用的UI组件。为了减小代码量,提高性能,组件再插件化,兼容iOS3+ / android2.1+,支持国内主流移动端浏览器,如safari, chrome, UC, qq等。 + * GMU由百度GMU小组开发,基于开源BSD协议,支持商业和非商业用户的免费使用和任意修改,您可以通过[get started](http://gmu.baidu.com/getstarted)快速了解。 + * + * ###Quick Start### + * + **官网:**http://gmu.baidu.com/ + * + **API:**http://gmu.baidu.com/doc + * + * ###历史版本### + * + * ### 2.0.5 ### + * + **DEMO: ** http://gmu.baidu.com/demo/2.0.5 + * + **API:** http://gmu.baidu.com/doc/2.0.5 + * + **下载:** http://gmu.baidu.com/download/2.0.5 + * + * @module GMU + * @title GMU API 文档 + */ +var gmu = gmu || { + version: '@version', + $: window.Zepto, + + /** + * 调用此方法,可以减小重复实例化Zepto的开销。所有通过此方法调用的,都将公用一个Zepto实例, + * 如果想减少Zepto实例创建的开销,就用此方法。 + * @method staticCall + * @grammar gmu.staticCall( dom, fnName, args... ) + * @param {DOM} elem Dom对象 + * @param {String} fn Zepto方法名。 + * @param {*} * zepto中对应的方法参数。 + * @example + * // 复制dom的className给dom2, 调用的是zepto的方法,但是只会实例化一次Zepto类。 + * var dom = document.getElementById( '#test' ); + * + * var className = gmu.staticCall( dom, 'attr', 'class' ); + * console.log( className ); + * + * var dom2 = document.getElementById( '#test2' ); + * gmu.staticCall( dom, 'addClass', className ); + */ + staticCall: (function( $ ) { + var proto = $.fn, + slice = [].slice, + + // 公用此zepto实例 + instance = $(); + + instance.length = 1; + + return function( item, fn ) { + instance[ 0 ] = item; + return proto[ fn ].apply( instance, slice.call( arguments, 2 ) ); + }; + })( Zepto ) +}; +/** + * @file Event相关, 给widget提供事件行为。也可以给其他对象提供事件行为。 + * @import core/gmu.js + * @module GMU + */ +(function( gmu, $ ) { + var slice = [].slice, + separator = /\s+/, + + returnFalse = function() { + return false; + }, + + returnTrue = function() { + return true; + }; + + function eachEvent( events, callback, iterator ) { + + // 不支持对象,只支持多个event用空格隔开 + (events || '').split( separator ).forEach(function( type ) { + iterator( type, callback ); + }); + } + + // 生成匹配namespace正则 + function matcherFor( ns ) { + return new RegExp( '(?:^| )' + ns.replace( ' ', ' .* ?' ) + '(?: |$)' ); + } + + // 分离event name和event namespace + function parse( name ) { + var parts = ('' + name).split( '.' ); + + return { + e: parts[ 0 ], + ns: parts.slice( 1 ).sort().join( ' ' ) + }; + } + + function findHandlers( arr, name, callback, context ) { + var matcher, + obj; + + obj = parse( name ); + obj.ns && (matcher = matcherFor( obj.ns )); + return arr.filter(function( handler ) { + return handler && + (!obj.e || handler.e === obj.e) && + (!obj.ns || matcher.test( handler.ns )) && + (!callback || handler.cb === callback || + handler.cb._cb === callback) && + (!context || handler.ctx === context); + }); + } + + /** + * Event类,结合gmu.event一起使用, 可以使任何对象具有事件行为。包含基本`preventDefault()`, `stopPropagation()`方法。 + * 考虑到此事件没有Dom冒泡概念,所以没有`stopImmediatePropagation()`方法。而`stopProgapation()`的作用就是 + * 让之后的handler都不执行。 + * + * @class Event + * @constructor + * ```javascript + * var obj = {}; + * + * $.extend( obj, gmu.event ); + * + * var etv = gmu.Event( 'beforeshow' ); + * obj.trigger( etv ); + * + * if ( etv.isDefaultPrevented() ) { + * console.log( 'before show has been prevented!' ); + * } + * ``` + * @grammar new gmu.Event( name[, props]) => instance + * @param {String} type 事件名字 + * @param {Object} [props] 属性对象,将被复制进event对象。 + */ + function Event( type, props ) { + if ( !(this instanceof Event) ) { + return new Event( type, props ); + } + + props && $.extend( this, props ); + this.type = type; + + return this; + } + + Event.prototype = { + + /** + * @method isDefaultPrevented + * @grammar e.isDefaultPrevented() => Boolean + * @desc 判断此事件是否被阻止 + */ + isDefaultPrevented: returnFalse, + + /** + * @method isPropagationStopped + * @grammar e.isPropagationStopped() => Boolean + * @desc 判断此事件是否被停止蔓延 + */ + isPropagationStopped: returnFalse, + + /** + * @method preventDefault + * @grammar e.preventDefault() => undefined + * @desc 阻止事件默认行为 + */ + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + }, + + /** + * @method stopPropagation + * @grammar e.stopPropagation() => undefined + * @desc 阻止事件蔓延 + */ + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + } + }; + + /** + * @class event + * @static + * @description event对象,包含一套event操作方法。可以将此对象扩张到任意对象,来增加事件行为。 + * + * ```javascript + * var myobj = {}; + * + * $.extend( myobj, gmu.event ); + * + * myobj.on( 'eventname', function( e, var1, var2, var3 ) { + * console.log( 'event handler' ); + * console.log( var1, var2, var3 ); // =>1 2 3 + * } ); + * + * myobj.trigger( 'eventname', 1, 2, 3 ); + * ``` + */ + gmu.event = { + + /** + * 绑定事件。 + * @method on + * @grammar on( name, fn[, context] ) => self + * @param {String} name 事件名 + * @param {Function} callback 事件处理器 + * @param {Object} context 事件处理器的上下文。 + * @return {self} 返回自身,方便链式 + * @chainable + */ + on: function( name, callback, context ) { + var me = this, + set; + + if ( !callback ) { + return this; + } + + set = this._events || (this._events = []); + + eachEvent( name, callback, function( name, callback ) { + var handler = parse( name ); + + handler.cb = callback; + handler.ctx = context; + handler.ctx2 = context || me; + handler.id = set.length; + set.push( handler ); + } ); + + return this; + }, + + /** + * 绑定事件,且当handler执行完后,自动解除绑定。 + * @method one + * @grammar one( name, fn[, context] ) => self + * @param {String} name 事件名 + * @param {Function} callback 事件处理器 + * @param {Object} context 事件处理器的上下文。 + * @return {self} 返回自身,方便链式 + * @chainable + */ + one: function( name, callback, context ) { + var me = this; + + if ( !callback ) { + return this; + } + + eachEvent( name, callback, function( name, callback ) { + var once = function() { + me.off( name, once ); + return callback.apply( context || me, arguments ); + }; + + once._cb = callback; + me.on( name, once, context ); + } ); + + return this; + }, + + /** + * 解除事件绑定 + * @method off + * @grammar off( name[, fn[, context] ] ) => self + * @param {String} name 事件名 + * @param {Function} callback 事件处理器 + * @param {Object} context 事件处理器的上下文。 + * @return {self} 返回自身,方便链式 + * @chainable + */ + off: function( name, callback, context ) { + var events = this._events; + + if ( !events ) { + return this; + } + + if ( !name && !callback && !context ) { + this._events = []; + return this; + } + + eachEvent( name, callback, function( name, callback ) { + findHandlers( events, name, callback, context ) + .forEach(function( handler ) { + delete events[ handler.id ]; + }); + } ); + + return this; + }, + + /** + * 触发事件 + * @method trigger + * @grammar trigger( name[, ...] ) => self + * @param {String | Event } evt 事件名或gmu.Event对象实例 + * @param {*} * 任意参数 + * @return {self} 返回自身,方便链式 + * @chainable + */ + trigger: function( evt ) { + var i = -1, + args, + events, + stoped, + len, + ev; + + if ( !this._events || !evt ) { + return this; + } + + typeof evt === 'string' && (evt = new Event( evt )); + + args = slice.call( arguments, 1 ); + evt.args = args; // handler中可以直接通过e.args获取trigger数据 + args.unshift( evt ); + + events = findHandlers( this._events, evt.type ); + + if ( events ) { + len = events.length; + + while ( ++i < len ) { + if ( (stoped = evt.isPropagationStopped()) || false === + (ev = events[ i ]).cb.apply( ev.ctx2, args ) + ) { + + // 如果return false则相当于stopPropagation()和preventDefault(); + stoped || (evt.stopPropagation(), evt.preventDefault()); + break; + } + } + } + + return this; + } + }; + + // expose + gmu.Event = Event; +})( gmu, gmu.$ ); +/** + * @file 模板解析 + * @import zepto.js + * @module GMU + */ +(function( $, undefined ) { + + /** + * 解析模版tpl。当data未传入时返回编译结果函数;当某个template需要多次解析时,建议保存编译结果函数,然后调用此函数来得到结果。 + * + * @method $.parseTpl + * @grammar $.parseTpl(str, data) ⇒ string + * @grammar $.parseTpl(str) ⇒ Function + * @param {String} str 模板 + * @param {Object} data 数据 + * @example var str = "

<%=name%>

", + * obj = {name: 'ajean'}; + * console.log($.parseTpl(str, data)); // =>

ajean

+ */ + $.parseTpl = function( str, data ) { + var tmpl = 'var __p=[];' + 'with(obj||{}){__p.push(\'' + + str.replace( /\\/g, '\\\\' ) + .replace( /'/g, '\\\'' ) + .replace( /<%=([\s\S]+?)%>/g, function( match, code ) { + return '\',' + code.replace( /\\'/, '\'' ) + ',\''; + } ) + .replace( /<%([\s\S]+?)%>/g, function( match, code ) { + return '\');' + code.replace( /\\'/, '\'' ) + .replace( /[\r\n\t]/g, ' ' ) + '__p.push(\''; + } ) + .replace( /\r/g, '\\r' ) + .replace( /\n/g, '\\n' ) + .replace( /\t/g, '\\t' ) + + '\');}return __p.join("");', + + /* jsbint evil:true */ + func = new Function( 'obj', tmpl ); + + return data ? func( data ) : func; + }; +})( Zepto ); +/** + * @file gmu底层,定义了创建gmu组件的方法 + * @import core/gmu.js, core/event.js, extend/parseTpl.js + * @module GMU + */ + +(function( gmu, $, undefined ) { + var slice = [].slice, + toString = Object.prototype.toString, + blankFn = function() {}, + + // 挂到组件类上的属性、方法 + staticlist = [ 'options', 'template', 'tpl2html' ], + + // 存储和读取数据到指定对象,任何对象包括dom对象 + // 注意:数据不直接存储在object上,而是存在内部闭包中,通过_gid关联 + // record( object, key ) 获取object对应的key值 + // record( object, key, value ) 设置object对应的key值 + // record( object, key, null ) 删除数据 + record = (function() { + var data = {}, + id = 0, + ikey = '_gid'; // internal key. + + return function( obj, key, val ) { + var dkey = obj[ ikey ] || (obj[ ikey ] = ++id), + store = data[ dkey ] || (data[ dkey ] = {}); + + val !== undefined && (store[ key ] = val); + val === null && delete store[ key ]; + + return store[ key ]; + }; + })(), + + event = gmu.event; + + function isPlainObject( obj ) { + return toString.call( obj ) === '[object Object]'; + } + + // 遍历对象 + function eachObject( obj, iterator ) { + obj && Object.keys( obj ).forEach(function( key ) { + iterator( key, obj[ key ] ); + }); + } + + // 从某个元素上读取某个属性。 + function parseData( data ) { + try { // JSON.parse可能报错 + + // 当data===null表示,没有此属性 + data = data === 'true' ? true : + data === 'false' ? false : data === 'null' ? null : + + // 如果是数字类型,则将字符串类型转成数字类型 + +data + '' === data ? +data : + /(?:\{[\s\S]*\}|\[[\s\S]*\])$/.test( data ) ? + JSON.parse( data ) : data; + } catch ( ex ) { + data = undefined; + } + + return data; + } + + // 从DOM节点上获取配置项 + function getDomOptions( el ) { + var ret = {}, + attrs = el && el.attributes, + len = attrs && attrs.length, + key, + data; + + while ( len-- ) { + data = attrs[ len ]; + key = data.name; + + if ( key.substring(0, 5) !== 'data-' ) { + continue; + } + + key = key.substring( 5 ); + data = parseData( data.value ); + + data === undefined || (ret[ key ] = data); + } + + return ret; + } + + // 在$.fn上挂对应的组件方法呢 + // $('#btn').button( options );实例化组件 + // $('#btn').button( 'select' ); 调用实例方法 + // $('#btn').button( 'this' ); 取组件实例 + // 此方法遵循get first set all原则 + function zeptolize( name ) { + var key = name.substring( 0, 1 ).toLowerCase() + name.substring( 1 ), + old = $.fn[ key ]; + + $.fn[ key ] = function( opts ) { + var args = slice.call( arguments, 1 ), + method = typeof opts === 'string' && opts, + ret, + obj; + + $.each( this, function( i, el ) { + + // 从缓存中取,没有则创建一个 + obj = record( el, name ) || new gmu[ name ]( el, + isPlainObject( opts ) ? opts : undefined ); + + // 取实例 + if ( method === 'this' ) { + ret = obj; + return false; // 断开each循环 + } else if ( method ) { + + // 当取的方法不存在时,抛出错误信息 + if ( !$.isFunction( obj[ method ] ) ) { + throw new Error( '组件没有此方法:' + method ); + } + + ret = obj[ method ].apply( obj, args ); + + // 断定它是getter性质的方法,所以需要断开each循环,把结果返回 + if ( ret !== undefined && ret !== obj ) { + return false; + } + + // ret为obj时为无效值,为了不影响后面的返回 + ret = undefined; + } + } ); + + return ret !== undefined ? ret : this; + }; + + /* + * NO CONFLICT + * var gmuPanel = $.fn.panel.noConflict(); + * gmuPanel.call(test, 'fnname'); + */ + $.fn[ key ].noConflict = function() { + $.fn[ key ] = old; + return this; + }; + } + + // 加载注册的option + function loadOption( klass, opts ) { + var me = this; + + // 先加载父级的 + if ( klass.superClass ) { + loadOption.call( me, klass.superClass, opts ); + } + + eachObject( record( klass, 'options' ), function( key, option ) { + option.forEach(function( item ) { + var condition = item[ 0 ], + fn = item[ 1 ]; + + if ( condition === '*' || + ($.isFunction( condition ) && + condition.call( me, opts[ key ] )) || + condition === opts[ key ] ) { + + fn.call( me ); + } + }); + } ); + } + + // 加载注册的插件 + function loadPlugins( klass, opts ) { + var me = this; + + // 先加载父级的 + if ( klass.superClass ) { + loadPlugins.call( me, klass.superClass, opts ); + } + + eachObject( record( klass, 'plugins' ), function( opt, plugin ) { + + // 如果配置项关闭了,则不启用此插件 + if ( opts[ opt ] === false ) { + return; + } + + eachObject( plugin, function( key, val ) { + var oringFn; + + if ( $.isFunction( val ) && (oringFn = me[ key ]) ) { + me[ key ] = function() { + var origin = me.origin, + ret; + + me.origin = oringFn; + ret = val.apply( me, arguments ); + origin === undefined ? delete me.origin : + (me.origin = origin); + + return ret; + }; + } else { + me[ key ] = val; + } + } ); + + plugin._init.call( me ); + } ); + } + + // 合并对象 + function mergeObj() { + var args = slice.call( arguments ), + i = args.length, + last; + + while ( i-- ) { + last = last || args[ i ]; + isPlainObject( args[ i ] ) || args.splice( i, 1 ); + } + + return args.length ? + $.extend.apply( null, [ true, {} ].concat( args ) ) : last; // 深拷贝,options中某项为object时,用例中不能用==判断 + } + + // 初始化widget. 隐藏具体细节,因为如果放在构造器中的话,是可以看到方法体内容的 + // 同时此方法可以公用。 + function bootstrap( name, klass, uid, el, options ) { + var me = this, + opts; + + if ( isPlainObject( el ) ) { + options = el; + el = undefined; + } + + // options中存在el时,覆盖el + options && options.el && (el = $( options.el )); + el && (me.$el = $( el ), el = me.$el[ 0 ]); + + opts = me._options = mergeObj( klass.options, + getDomOptions( el ), options ); + + me.template = mergeObj( klass.template, opts.template ); + + me.tpl2html = mergeObj( klass.tpl2html, opts.tpl2html ); + + // 生成eventNs widgetName + me.widgetName = name.toLowerCase(); + me.eventNs = '.' + me.widgetName + uid; + + me._init( opts ); + + // 设置setup参数,只有传入的$el在DOM中,才认为是setup模式 + me._options.setup = (me.$el && me.$el.parent()[ 0 ]) ? true: false; + + loadOption.call( me, klass, opts ); + loadPlugins.call( me, klass, opts ); + + // 进行创建DOM等操作 + me._create(); + me.trigger( 'ready' ); + + el && record( el, name, me ) && me.on( 'destroy', function() { + record( el, name, null ); + } ); + + return me; + } + + /** + * @desc 创建一个类,构造函数默认为init方法, superClass默认为Base + * @name createClass + * @grammar createClass(object[, superClass]) => fn + */ + function createClass( name, object, superClass ) { + if ( typeof superClass !== 'function' ) { + superClass = gmu.Base; + } + + var uuid = 1, + suid = 1; + + function klass( el, options ) { + if ( name === 'Base' ) { + throw new Error( 'Base类不能直接实例化' ); + } + + if ( !(this instanceof klass) ) { + return new klass( el, options ); + } + + return bootstrap.call( this, name, klass, uuid++, el, options ); + } + + $.extend( klass, { + + /** + * @name register + * @grammar klass.register({}) + * @desc 注册插件 + */ + register: function( name, obj ) { + var plugins = record( klass, 'plugins' ) || + record( klass, 'plugins', {} ); + + obj._init = obj._init || blankFn; + + plugins[ name ] = obj; + return klass; + }, + + /** + * @name option + * @grammar klass.option(option, value, method) + * @desc 扩充组件的配置项 + */ + option: function( option, value, method ) { + var options = record( klass, 'options' ) || + record( klass, 'options', {} ); + + options[ option ] || (options[ option ] = []); + options[ option ].push([ value, method ]); + + return klass; + }, + + /** + * @name inherits + * @grammar klass.inherits({}) + * @desc 从该类继承出一个子类,不会被挂到gmu命名空间 + */ + inherits: function( obj ) { + + // 生成 Sub class + return createClass( name + 'Sub' + suid++, obj, klass ); + }, + + /** + * @name extend + * @grammar klass.extend({}) + * @desc 扩充现有组件 + */ + extend: function( obj ) { + var proto = klass.prototype, + superProto = superClass.prototype; + + staticlist.forEach(function( item ) { + obj[ item ] = mergeObj( superClass[ item ], obj[ item ] ); + obj[ item ] && (klass[ item ] = obj[ item ]); + delete obj[ item ]; + }); + + // todo 跟plugin的origin逻辑,公用一下 + eachObject( obj, function( key, val ) { + if ( typeof val === 'function' && superProto[ key ] ) { + proto[ key ] = function() { + var $super = this.$super, + ret; + + // todo 直接让this.$super = superProto[ key ]; + this.$super = function() { + var args = slice.call( arguments, 1 ); + return superProto[ key ].apply( this, args ); + }; + + ret = val.apply( this, arguments ); + + $super === undefined ? (delete this.$super) : + (this.$super = $super); + return ret; + }; + } else { + proto[ key ] = val; + } + } ); + } + } ); + + klass.superClass = superClass; + klass.prototype = Object.create( superClass.prototype ); + + + /*// 可以在方法中通过this.$super(name)方法调用父级方法。如:this.$super('enable'); + object.$super = function( name ) { + var fn = superClass.prototype[ name ]; + return $.isFunction( fn ) && fn.apply( this, + slice.call( arguments, 1 ) ); + };*/ + + klass.extend( object ); + + return klass; + } + + /** + * @method define + * @grammar gmu.define( name, object[, superClass] ) + * @class + * @param {String} name 组件名字标识符。 + * @param {Object} object + * @desc 定义一个gmu组件 + * @example + * ####组件定义 + * ```javascript + * gmu.define( 'Button', { + * _create: function() { + * var $el = this.getEl(); + * + * $el.addClass( 'ui-btn' ); + * }, + * + * show: function() { + * console.log( 'show' ); + * } + * } ); + * ``` + * + * ####组件使用 + * html部分 + * ```html + * 按钮 + * ``` + * + * javascript部分 + * ```javascript + * var btn = $('#btn').button(); + * + * btn.show(); // => show + * ``` + * + */ + gmu.define = function( name, object, superClass ) { + gmu[ name ] = createClass( name, object, superClass ); + zeptolize( name ); + }; + + /** + * @desc 判断object是不是 widget实例, klass不传时,默认为Base基类 + * @method isWidget + * @grammar gmu.isWidget( anything[, klass] ) => Boolean + * @param {*} anything 需要判断的对象 + * @param {String|Class} klass 字符串或者类。 + * @example + * var a = new gmu.Button(); + * + * console.log( gmu.isWidget( a ) ); // => true + * console.log( gmu.isWidget( a, 'Dropmenu' ) ); // => false + */ + gmu.isWidget = function( obj, klass ) { + + // 处理字符串的case + klass = typeof klass === 'string' ? gmu[ klass ] || blankFn : klass; + klass = klass || gmu.Base; + return obj instanceof klass; + }; + + /** + * @class Base + * @description widget基类。不能直接使用。 + */ + gmu.Base = createClass( 'Base', { + + /** + * @method _init + * @grammar instance._init() => instance + * @desc 组件的初始化方法,子类需要重写该方法 + */ + _init: blankFn, + + /** + * @override + * @method _create + * @grammar instance._create() => instance + * @desc 组件创建DOM的方法,子类需要重写该方法 + */ + _create: blankFn, + + + /** + * @method getEl + * @grammar instance.getEl() => $el + * @desc 返回组件的$el + */ + getEl: function() { + return this.$el; + }, + + /** + * @method on + * @grammar instance.on(name, callback, context) => self + * @desc 订阅事件 + */ + on: event.on, + + /** + * @method one + * @grammar instance.one(name, callback, context) => self + * @desc 订阅事件(只执行一次) + */ + one: event.one, + + /** + * @method off + * @grammar instance.off(name, callback, context) => self + * @desc 解除订阅事件 + */ + off: event.off, + + /** + * @method trigger + * @grammar instance.trigger( name ) => self + * @desc 派发事件, 此trigger会优先把options上的事件回调函数先执行 + * options上回调函数可以通过调用event.stopPropagation()来阻止事件系统继续派发, + * 或者调用event.preventDefault()阻止后续事件执行 + */ + trigger: function( name ) { + var evt = typeof name === 'string' ? new gmu.Event( name ) : name, + args = [ evt ].concat( slice.call( arguments, 1 ) ), + opEvent = this._options[ evt.type ], + + // 先存起来,否则在下面使用的时候,可能已经被destory给删除了。 + $el = this.getEl(); + + if ( opEvent && $.isFunction( opEvent ) ) { + + // 如果返回值是false,相当于执行stopPropagation()和preventDefault(); + false === opEvent.apply( this, args ) && + (evt.stopPropagation(), evt.preventDefault()); + } + + event.trigger.apply( this, args ); + + // triggerHandler不冒泡 + $el && $el.triggerHandler( evt, (args.shift(), args) ); + + return this; + }, + + /** + * @method tpl2html + * @grammar instance.tpl2html() => String + * @grammar instance.tpl2html( data ) => String + * @grammar instance.tpl2html( subpart, data ) => String + * @desc 将template输出成html字符串,当传入 data 时,html将通过$.parseTpl渲染。 + * template支持指定subpart, 当无subpart时,template本身将为模板,当有subpart时, + * template[subpart]将作为模板输出。 + */ + tpl2html: function( subpart, data ) { + var tpl = this.template; + + tpl = typeof subpart === 'string' ? tpl[ subpart ] : + ((data = subpart), tpl); + + return data || ~tpl.indexOf( '<%' ) ? $.parseTpl( tpl, data ) : tpl; + }, + + /** + * @method destroy + * @grammar instance.destroy() + * @desc 注销组件 + */ + destroy: function() { + + // 解绑element上的事件 + this.$el && this.$el.off( this.eventNs ); + + this.trigger( 'destroy' ); + // 解绑所有自定义事件 + this.off(); + + + this.destroyed = true; + } + + }, Object ); + + // 向下兼容 + $.ui = gmu; +})( gmu, gmu.$ ); +/** + * @file 减少对方法、事件的执行频率,多次调用,在指定的时间内只会执行一次 + * @import zepto.js + * @module GMU + */ + +(function ($) { + /** + * 减少执行频率, 多次调用,在指定的时间内,只会执行一次。 + * ``` + * ||||||||||||||||||||||||| (空闲) ||||||||||||||||||||||||| + * X X X X X X X X X X X X + * ``` + * + * @method $.throttle + * @grammar $.throttle(delay, fn) ⇒ function + * @param {Number} [delay=250] 延时时间 + * @param {Function} fn 被稀释的方法 + * @param {Boolean} [debounce_mode=false] 是否开启防震动模式, true:start, false:end + * @example var touchmoveHander = function(){ + * //.... + * } + * //绑定事件 + * $(document).bind('touchmove', $.throttle(250, touchmoveHander));//频繁滚动,每250ms,执行一次touchmoveHandler + * + * //解绑事件 + * $(document).unbind('touchmove', touchmoveHander);//注意这里面unbind还是touchmoveHander,而不是$.throttle返回的function, 当然unbind那个也是一样的效果 + * + */ + $.extend($, { + throttle: function(delay, fn, debounce_mode) { + var last = 0, + timeId; + + if (typeof fn !== 'function') { + debounce_mode = fn; + fn = delay; + delay = 250; + } + + function wrapper() { + var that = this, + period = Date.now() - last, + args = arguments; + + function exec() { + last = Date.now(); + fn.apply(that, args); + }; + + function clear() { + timeId = undefined; + }; + + if (debounce_mode && !timeId) { + // debounce模式 && 第一次调用 + exec(); + } + + timeId && clearTimeout(timeId); + if (debounce_mode === undefined && period > delay) { + // throttle, 执行到了delay时间 + exec(); + } else { + // debounce, 如果是start就clearTimeout + timeId = setTimeout(debounce_mode ? clear : exec, debounce_mode === undefined ? delay - period : delay); + } + }; + // for event bind | unbind + wrapper._zid = fn._zid = fn._zid || $.proxy(fn)._zid; + return wrapper; + }, + + /** + * @desc 减少执行频率, 在指定的时间内, 多次调用,只会执行一次。 + * **options:** + * - ***delay***: 延时时间 + * - ***fn***: 被稀释的方法 + * - ***t***: 指定是在开始处执行,还是结束是执行, true:start, false:end + * + * 非at_begin模式 + * ||||||||||||||||||||||||| (空闲) ||||||||||||||||||||||||| + * X X + * at_begin模式 + * ||||||||||||||||||||||||| (空闲) ||||||||||||||||||||||||| + * X X + * + * @grammar $.debounce(delay, fn[, at_begin]) ⇒ function + * @name $.debounce + * @example var touchmoveHander = function(){ + * //.... + * } + * //绑定事件 + * $(document).bind('touchmove', $.debounce(250, touchmoveHander));//频繁滚动,只要间隔时间不大于250ms, 在一系列移动后,只会执行一次 + * + * //解绑事件 + * $(document).unbind('touchmove', touchmoveHander);//注意这里面unbind还是touchmoveHander,而不是$.debounce返回的function, 当然unbind那个也是一样的效果 + */ + debounce: function(delay, fn, t) { + return fn === undefined ? $.throttle(250, delay, false) : $.throttle(delay, fn, t === undefined ? false : t !== false); + } + }); +})(Zepto); +/** + * @file 滚动停止事件 + * @name scrollStop + * @short scrollStop + * @desc 滚动停止事件 + * @import zepto.js, extend/throttle.js + */ +(function ($, win) { + /** + * @name scrollStop + * @desc 扩展的事件,滚动停止事件 + * - ***scrollStop*** : 在document上派生的scrollStop事件上,scroll停下来时触发, 考虑前进或者后退后scroll事件不触发情况。 + * @example $(document).on('scrollStop', function () { //scroll停下来时显示scrollStop + * console.log('scrollStop'); + * }); + */ + + function registerScrollStop() { + $(win).on('scroll', $.debounce(80, function () { + $(win).trigger('scrollStop'); + }, false)); + } + + function backEventOffHandler() { + //在离开页面,前进或后退回到页面后,重新绑定scroll, 需要off掉所有的scroll,否则scroll时间不触发 + $(win).off('scroll'); + registerScrollStop(); + } + registerScrollStop(); + + //todo 待统一解决后退事件触发问题 + $(win).on('pageshow', function (e) { + //如果是从bfcache中加载页面,为了防止多次注册,需要先off掉 + e.persisted && $(win).off('touchstart', backEventOffHandler).one('touchstart', backEventOffHandler); + }); + +})(Zepto, window); +/** + * @file 媒体查询 + * @import zepto.js + * @module GMU + */ + +(function ($) { + + /** + * 是原生的window.matchMedia方法的polyfill,对于不支持matchMedia的方法系统和浏览器,按照[w3c window.matchMedia](http://www.w3.org/TR/cssom-view/#dom-window-matchmedia)的接口 + * 定义,对matchMedia方法进行了封装。原理是用css media query及transitionEnd事件来完成的。在页面中插入media query样式及元素,当query条件满足时改变该元素样式,同时这个样式是transition作用的属性, + * 满足条件后即会触发transitionEnd,由此创建MediaQueryList的事件监听。由于transition的duration time为0.001ms,故若直接使用MediaQueryList对象的matches去判断当前是否与query匹配,会有部分延迟, + * 建议注册addListener的方式去监听query的改变。$.matchMedia的详细实现原理及采用该方法实现的转屏统一解决方案详见 + * [GMU Pages: 转屏解决方案($.matchMedia)](https://github.com/gmuteam/GMU/wiki/%E8%BD%AC%E5%B1%8F%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88$.matchMedia) + * + * 返回值MediaQueryList对象包含的属性
+ * - ***matches*** 是否满足query
+ * - ***query*** 查询的css query,类似\'screen and (orientation: portrait)\'
+ * - ***addListener*** 添加MediaQueryList对象监听器,接收回调函数,回调参数为MediaQueryList对象
+ * - ***removeListener*** 移除MediaQueryList对象监听器
+ * + * + * @method $.matchMedia + * @grammar $.matchMedia(query) ⇒ MediaQueryList + * @param {String} query 查询的css query,类似\'screen and (orientation: portrait)\' + * @return {Object} MediaQueryList + * @example + * $.matchMedia('screen and (orientation: portrait)').addListener(fn); + */ + $.matchMedia = (function() { + var mediaId = 0, + cls = 'gmu-media-detect', + transitionEnd = $.fx.transitionEnd, + cssPrefix = $.fx.cssPrefix, + $style = $('').append('.' + cls + '{' + cssPrefix + 'transition: width 0.001ms; width: 0; position: absolute; clip: rect(1px, 1px, 1px, 1px);}\n').appendTo('head'); + + return function (query) { + var id = cls + mediaId++, + $mediaElem, + listeners = [], + ret; + + $style.append('@media ' + query + ' { #' + id + ' { width: 1px; } }\n') ; //原生matchMedia也需要添加对应的@media才能生效 + + // 统一用模拟的,时机更好。 + // if ('matchMedia' in window) { + // return window.matchMedia(query); + // } + + $mediaElem = $('
') + .appendTo('body') + .on(transitionEnd, function() { + ret.matches = $mediaElem.width() === 1; + $.each(listeners, function (i,fn) { + $.isFunction(fn) && fn.call(ret, ret); + }); + }); + + ret = { + matches: $mediaElem.width() === 1 , + media: query, + addListener: function (callback) { + listeners.push(callback); + return this; + }, + removeListener: function (callback) { + var index = listeners.indexOf(callback); + ~index && listeners.splice(index, 1); + return this; + } + }; + + return ret; + }; + }()); +})(Zepto); + +/** + * @file 扩展转屏事件 + * @name ortchange + * @short ortchange + * @desc 扩展转屏事件orientation,解决原生转屏事件的兼容性问题 + * @import zepto.js, extend/matchMedia.js + */ + +$(function () { + /** + * @name ortchange + * @desc 扩展转屏事件orientation,解决原生转屏事件的兼容性问题 + * - ***ortchange*** : 当转屏的时候触发,兼容uc和其他不支持orientationchange的设备,利用css media query实现,解决了转屏延时及orientation事件的兼容性问题 + * $(window).on('ortchange', function () { //当转屏的时候触发 + * console.log('ortchange'); + * }); + */ + //扩展常用media query + $.mediaQuery = { + ortchange: 'screen and (width: ' + window.innerWidth + 'px)' + }; + //通过matchMedia派生转屏事件 + $.matchMedia($.mediaQuery.ortchange).addListener(function () { + $(window).trigger('ortchange'); + }); +}); +/** + * @file 实现了通用fix方法。 + * @name Fix + * @import zepto.js, extend/event.scrollStop.js, extend/event.ortchange.js + */ + +/** + * @name fix + * @grammar fix(options) => self + * @desc 固顶fix方法,对不支持position:fixed的设备上将元素position设为absolute, + * 在每次scrollstop时根据opts参数设置当前显示的位置,类似fix效果。 + * + * Options: + * - ''top'' {Number}: 距离顶部的px值 + * - ''left'' {Number}: 距离左侧的px值 + * - ''bottom'' {Number}: 距离底部的px值 + * - ''right'' {Number}: 距离右侧的px值 + * @example + * var div = $('div'); + * div.fix({top:0, left:0}); //将div固顶在左上角 + * div.fix({top:0, right:0}); //将div固顶在右上角 + * div.fix({bottom:0, left:0}); //将div固顶在左下角 + * div.fix({bottom:0, right:0}); //将div固顶在右下角 + * + */ + +(function ($, undefined) { + $.extend($.fn, { + fix: function(opts) { + var me = this; //如果一个集合中的第一元素已fix,则认为这个集合的所有元素已fix, + if(me.attr('isFixed')) return me; //这样在操作时就可以针对集合进行操作,不必单独绑事件去操作 + me.css(opts).css('position', 'fixed').attr('isFixed', true); + var buff = $('
').appendTo('body'), + top = buff[0].getBoundingClientRect().top, + checkFixed = function() { + if(window.pageYOffset > 0) { + if(buff[0].getBoundingClientRect().top !== top) { + me.css('position', 'absolute'); + doFixed(); + $(window).on('scrollStop', doFixed); + $(window).on('ortchange', doFixed); + } + $(window).off('scrollStop', checkFixed); + buff.remove(); + } + }, + doFixed = function() { + me.css({ + top: window.pageYOffset + (opts.bottom !== undefined ? window.innerHeight - me.height() - opts.bottom : (opts.top ||0)), + left: opts.right !== undefined ? document.body.offsetWidth - me.width() - opts.right : (opts.left || 0) + }); + opts.width == '100%' && me.css('width', document.body.offsetWidth); + }; + + $(window).on('scrollStop', checkFixed); + + return me; + } + }); +}(Zepto)); +/** + * @file 在iOS中将页面添加为桌面图标(不支持Android系统) + * @import core/widget.js, extend/fix.js + * @module GMU + */ +(function( gmu, $, undefined ) { + /** + * 在iOS中将页面添加为桌面图标(不支持Android系统) + * @class Add2desktop + * @constructor Html部分 + * + * javascript部分 + * ```javascript + * gmu.Add2desktop({icon:'../../../examples/assets/icon.png'}); + * ``` + * @param {dom | zepto | selector} [el] 用来初始化工具栏的元素 + * @param {Object} [options] 组件配置项。具体参数请查看[Options](#GMU:Toolbar:options) + * @grammar gmu.Add2desktop([el [,options]]) =>instance + * @grammar $(el).add2desktop(options) => zepto + */ + gmu.define('Add2desktop', { + options: { + /** + * @property {String} icon 产品线ICON的URL + * @namespace options + */ + icon: '', + /** + * @property {selector} [container=document.body] 组件容器 + * @namespace options + */ + container: '', + /** + * @property {String} [key='_gmu_adddesktop_key'] LocalStorage的key值 + * @namespace options + */ + key:'_gmu_adddesktop_key', + /** + * @property {Boolean} [useFix=true] 是否使用fix固顶效果 + * @namespace options + */ + useFix: true, + /** + * @property {Object} [position={bottom:12,left:50%}] 固顶时使用的位置参数 + * @namespace options + */ + position: { + bottom: 12, + left: '50%' + }, + /** + * @property {Function} [beforeshow=fn}] 显示前触发的事件,调用e.preventDefault()可以阻止显示 + * @namespace options + */ + beforeshow : function(e){ + this.key() && e.preventDefault() + }, + /** + * @property {Function} [afterhide=fn}] 隐藏后触发的事件,可以在这里写LocalStorage的值 + * @namespace options + */ + afterhide : function(){ + this.key(1) + }, + _isShow:false + }, + + _init: function() { + var me = this; + + me.on( 'ready', function(){ + me.$el.find('.ui-add2desktop-close').on('click',function () { + me.hide(); + }); + me._options['useFix'] && me.$el.fix(me._options['position']); + + me.show(); + } ); + + me.on( 'destroy', function(){ + me.$el.remove(); + } ); + }, + + _create: function() { + var me = this, + $el, + version = ($.os.version && $.os.version.substr(0, 3) > 4.1 ? 'new' :'old'); + + if($.os.version && $.os.version.substr(0, 3) >= 7.0) { + version = 'iOS7'; + } + + if( me._options.setup ) { + var src = me.$el.children('img').attr('src'); + src && (me._options['icon'] = src); + } + $el = me.$el || (me.$el = $('
')); + $el.addClass('ui-add2desktop').appendTo(me._options['container'] || (me.$el.parent().length ? '' : document.body)), + + $el.html('

先点击
再"添加到主屏幕"

'); + }, + + /** + * 存储/获取LocalStorage的键值 + * @method key + * @param {String} [value] LocalStorage的键值,不传表示取值 + * @return {self} LocalStorage的值 + */ + key : function(value){ + var ls = window.localStorage; + return value !== undefined ? ls.setItem(this._options['key'], value) : ls.getItem(this._options['key']); + }, + + /** + * 显示add2desktop + * @method show + * @return {self} 返回本身。 + */ + + /** + * @event beforeshow + * @param {Event} e gmu.Event对象 + * @description add2desktop显示前触发 + */ + show: function() { + var me = this; + + if( !me._options['_isShow'] ) { + if(!$.os.ios || $.browser.uc || $.browser.qq || $.browser.chrome) return me; //todo 添加iOS原生浏览器的判断 + var event = new gmu.Event('beforeshow'); + me.trigger(event); + if(event.isDefaultPrevented()) return me; + me.$el.css('display', 'block'); + me._options['_isShow'] = true; + } + + return me; + }, + + /** + * 隐藏add2desktop + * @method hide + * @return {self} 返回本身。 + */ + + /** + * @event afterhide + * @param {Event} e gmu.Event对象 + * @description add2desktop显示后触发 + */ + hide: function() { + var me = this; + + if(me._options['_isShow']) { + me.$el.css('display', 'none'); + me._options['_isShow'] = false; + me.trigger('afterhide'); + } + + return me; + } + + /** + * @event ready + * @param {Event} e gmu.Event对象 + * @description 当组件初始化完后触发。 + */ + + /** + * @event destroy + * @param {Event} e gmu.Event对象 + * @description 组件在销毁的时候触发 + */ + }); + +})( gmu, gmu.$ ); + +/** + * @file 实现了通用highlight方法。 + * @name Highlight + * @desc 点击高亮效果 + * @import zepto.js + */ +(function( $ ) { + var $doc = $( document ), + $el, // 当前按下的元素 + timer; // 考虑到滚动操作时不能高亮,所以用到了100ms延时 + + // 负责移除className. + function dismiss() { + var cls = $el.attr( 'hl-cls' ); + + clearTimeout( timer ); + $el.removeClass( cls ).removeAttr( 'hl-cls' ); + $el = null; + $doc.off( 'touchend touchmove touchcancel', dismiss ); + } + + /** + * @name highlight + * @desc 禁用掉系统的高亮,当手指移动到元素上时添加指定class,手指移开时,移除该class. + * 当不传入className是,此操作将解除事件绑定。 + * + * 此方法支持传入selector, 此方式将用到事件代理,允许dom后加载。 + * @grammar highlight(className, selector ) ⇒ self + * @grammar highlight(className ) ⇒ self + * @grammar highlight() ⇒ self + * @example var div = $('div'); + * div.highlight('div-hover'); + * + * $('a').highlight();// 把所有a的自带的高亮效果去掉。 + */ + $.fn.highlight = function( className, selector ) { + return this.each(function() { + var $this = $( this ); + + $this.css( '-webkit-tap-highlight-color', 'rgba(255,255,255,0)' ) + .off( 'touchstart.hl' ); + + className && $this.on( 'touchstart.hl', function( e ) { + var match; + + $el = selector ? (match = $( e.target ).closest( selector, + this )) && match.length && match : $this; + + // selctor可能找不到元素。 + if ( $el ) { + $el.attr( 'hl-cls', className ); + timer = setTimeout( function() { + $el.addClass( className ); + }, 100 ); + $doc.on( 'touchend touchmove touchcancel', dismiss ); + } + } ); + }); + }; +})( Zepto ); + +/** + * @file Button组件。 + * @module GMU + * @import core/widget.js, extend/highlight.js + * @importCss icons.css + */ +(function( gmu, $, undefined ) { + + /** + * Button组件。支持icon, icon位置设置。 + * + * [![Live Demo](qrcode:http://gmu.baidu.com/demo/widget/button/button.html)](http://gmu.baidu.com/demo/widget/button/button.html "Live Demo") + * + * @class Button + * @constructor + * html部分, 可以是以下任意dom实例化button + * ```html + * 按钮 + * 按钮 + * + * + * + * + * ``` + * + * Javascript部分 + * ```javascript + * $( '.btn' ).button(); + * ``` + * + * 如果希望支持checkbox radio按钮,请查看[input插件](#GMU:Button.input)。 + * @grammar new gmu.Button( el[, options]) => instance + * @grammar $( el ).button([ options ]) => zepto + */ + gmu.define( 'Button', { + options: { + + /** + * @property {String} [label] 按钮文字。 + * @namespace options + */ + + /** + * @property {String} [icon] 图标名称。系统提供以下图标。home, delete, plus, arrow-u, arrow-d, check, gear, grid, star, arrow-r, arrow-l, minus, refresh, forward, back, alert, info, search, + * @namespace options + */ + + /** + * @property {String} [iconpos] 图片位置。支持:left, right, top, bottom, notext. + * @namespace options + */ + iconpos: 'left' + + /** + * @property {String} [state] + * @description 设置初始状态。如果状态值为`disbaled`,按钮将不可点击。 + * @namespace options + */ + + /** + * @property {String} [{$state}Text] + * @description 设置对应状态文字,当button进入此状态时,按钮将显示对应的文字。 + * @namespace options + */ + }, + + template: { + icon: '', + text: '<%= text %>' + }, + + _getWrap: function( $el ) { + return $el; + }, + + _init: function(){ + var me = this; + + me.$el = me.$el === undefined ? $('').appendTo( document.body ) : me.$el; + }, + + _create: function() { + var me = this, + opts = me._options, + $wrap = me.$wrap = me._getWrap( me.getEl() ), + input = $wrap.is( 'input' ), + $label = $wrap.find( '.ui-btn-text' ), + $icon = $wrap.find( '.ui-icon' ); + + // 处理label + // 如果是空字符串,则表示dom中写了data-label="" + opts.label = opts.label === undefined ? $wrap[ input ? 'val' : 'text' ]() : opts.label; + input || opts.label === undefined || !$label.length && ($label = $( me.tpl2html( 'text', { + text: opts.label + } ) )).appendTo( $wrap.empty() ); + me.$label = $label.length && $label; + opts.resetText = opts.resetText || opts.label; + + // 如果传入了icon而dom中没有,则创建 + input || opts.icon && !$icon.length && ($icon = $( me.tpl2html( 'icon', { + name: opts.icon + } ) )).appendTo( $wrap ); + me.$icon = $icon.length && $icon; + + $wrap.addClass( 'ui-btn ' + (opts.label && opts.icon ? + 'ui-btn-icon-' + opts.iconpos : opts.label ? + 'ui-btn-text-only' : 'ui-btn-icon-only') ); + + opts.state && setTimeout( function(){ + me.state( opts.state ); + }, 0 ); + }, + + /** + * 设置或者获取按钮状态值。 + * + * 如果传入的state为"disabled", 此按钮将变成不可点击状态。 + * + * ```javascript + * // 初始化的时候可以给diabled状态设置Text + * var btn = $( '#btn' ).button({ + * disabledText: '不可点' + * }); + * + * // 按钮将变成不可点击状态。同时文字也变成了”不可点“ + * btn.button( 'state', 'disabled' ); + * + * // 还原按钮状态 + * // 文字也还原。 + * btn.button( 'state', 'reset' ); + * + * ``` + * @method state + * @grammar state( value ) => self + * @grammar state() => String + * @param {String} [state] 状态值。 + * @return {String} 当没有传入state值时,此方法行为为getter, 返回当前state值。 + * @return {self} 当传入了state值时,此方法行为为setter, 返回实例本身,方便链式调用。 + */ + state: function( state ) { + + // getter + if ( state === undefined ) { + return this._state; + } + + // setter + var me = this, + $wrap = me.$wrap, + input = $wrap.is( 'input' ), + text = me._options[ state + 'Text' ]; + + me.$wrap.removeClass( 'ui-state-' + me._state ) + .addClass( 'ui-state-' + state ); + + text === undefined || (input ? $wrap : me.$label)[ input ? + 'val' : 'text' ]( text ); + + me._state !== state && me.trigger( 'statechange', state, me._state ); + me._state = state; + return me; + }, + + /** + * 切换按钮选中状态 + * @method toggle + * @grammar toggle() => self + * @example + * var btn = $( '#btn' ); + * + * btn.on( 'click', function() { + * btn.button( 'toggle' ); + * } ); + */ + toggle: function() { + this.state( this._state === 'active' ? 'reset' : 'active' ); + return this; + } + + /** + * @event ready + * @param {Event} e gmu.Event对象 + * @description 当组件初始化完后触发。 + */ + + /** + * @event statechange + * @param {Event} e gmu.Event对象 + * @param {String} state 当前state值 + * @param {String} preState 前一次state的值 + * @description 当组件状态变化时触发。 + */ + + /** + * @event destroy + * @param {Event} e gmu.Event对象 + * @description 当组件被销毁的时候触发。 + */ + } ); + + // dom ready + $(function() { + + // 按下态。 + $( document.body ).highlight( 'ui-state-hover', '.ui-btn:not(.ui-state-disabled)' ); + }); +})( gmu, gmu.$ ); +/** + * @file Button input插件 + * @module GMU + * @import widget/button/button.js + */ +(function( gmu, $ ) { + var uid = 0; + + /** + * Button input插件,让button支持checkbox和radio来实例化。 + * + * 如: + * ```html + * + * + * ``` + * + * 且此类按钮,点击的时候回自动切换active状态,对应的input的checked值也会变化。 + * + * @class input + * @namespace Button + * @pluginfor Button + */ + gmu.Button.register( 'input', { + _getWrap: function( $el ) { + var id, el, $wrap; + + // 如果是表单元素。 + if ( $el.is( 'input[type="checkbox"], input[type="radio"]' ) ) { + el = $el.addClass( 'ui-hidden' )[ 0 ]; + (id = el.id) || (el.id = id = 'input_btn_' + uid++); + $wrap = $( 'label[for=' + id + ']', el.form || el.ownerDocument || undefined ); + $wrap.length || ($wrap = $( '' ).insertBefore( $el )); + + $el.prop( 'checked' ) && (this._options.state = 'active'); + return $wrap; + } + + return $el; + }, + + toggle: function() { + var $el = this.$el; + + if ( $el.is( 'input[type="radio"]' ) ) { + $radios = $( "[name='" + $el.attr('name') + "']", $el[ 0 ].form + || $el[ 0 ].ownerDocument || undefined ); + + $radios.button( 'state', 'reset' ); + } + return this.origin.apply( this, arguments ); + }, + + state: function( state ) { + var $el = this.$el; + + // 设置disabled状态 + if ( $el.is( 'input[type="checkbox"], input[type="radio"]' ) ) { + $el.prop( 'disabled', state === 'disabled' ); + } + + return this.origin.apply( this, arguments ); + } + } ); + + + // dom ready + $(function() { + $( document.body ).on( 'click.button', + 'label.ui-btn:not(.ui-state-disabled)', function() { + + $( '#' + this.getAttribute( 'for' ) ).button( 'toggle' ); + }); + }); +})( gmu, gmu.$ ); +/** + * @file 来自zepto/touch.js, zepto自1.0后,已不默认打包此文件。 + * @import zepto.js + */ +// Zepto.js +// (c) 2010-2012 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +;(function($){ + var touch = {}, + touchTimeout, tapTimeout, swipeTimeout, + longTapDelay = 750, longTapTimeout + + function parentIfText(node) { + return 'tagName' in node ? node : node.parentNode + } + + function swipeDirection(x1, x2, y1, y2) { + var xDelta = Math.abs(x1 - x2), yDelta = Math.abs(y1 - y2) + return xDelta >= yDelta ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down') + } + + function longTap() { + longTapTimeout = null + if (touch.last) { + touch.el.trigger('longTap') + touch = {} + } + } + + 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 = {} + } + + $(document).ready(function(){ + var now, delta + + $(document.body) + .bind('touchstart', function(e){ + now = Date.now() + delta = now - (touch.last || now) + touch.el = $(parentIfText(e.touches[0].target)) + touchTimeout && clearTimeout(touchTimeout) + touch.x1 = e.touches[0].pageX + touch.y1 = e.touches[0].pageY + if (delta > 0 && delta <= 250) touch.isDoubleTap = true + touch.last = now + longTapTimeout = setTimeout(longTap, longTapDelay) + }) + .bind('touchmove', function(e){ + cancelLongTap() + touch.x2 = e.touches[0].pageX + touch.y2 = e.touches[0].pageY + if (Math.abs(touch.x1 - touch.x2) > 10) + e.preventDefault() + }) + .bind('touchend', function(e){ + cancelLongTap() + + // swipe + if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > 30) || + (touch.y2 && Math.abs(touch.y1 - touch.y2) > 30)) + + swipeTimeout = setTimeout(function() { + touch.el.trigger('swipe') + touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2))) + touch = {} + }, 0) + + // normal tap + else if ('last' in touch) + + // delay by one tick so we can cancel the 'tap' event if 'scroll' fires + // ('tap' fires before 'scroll') + tapTimeout = setTimeout(function() { + + // trigger universal 'tap' with the option to cancelTouch() + // (cancelTouch cancels processing of single vs double taps for faster 'tap' response) + var event = $.Event('tap') + event.cancelTouch = cancelAll + touch.el.trigger(event) + + // trigger double tap immediately + if (touch.isDoubleTap) { + touch.el.trigger('doubleTap') + touch = {} + } + + // trigger single tap after 250ms of inactivity + else { + touchTimeout = setTimeout(function(){ + touchTimeout = null + touch.el.trigger('singleTap') + touch = {} + }, 250) + } + + }, 0) + + }) + .bind('touchcancel', cancelAll) + + $(window).bind('scroll', cancelAll) + }) + + ;['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown', 'doubleTap', 'tap', 'singleTap', 'longTap'].forEach(function(m){ + $.fn[m] = function(callback){ return this.bind(m, callback) } + }) +})(Zepto); + +/** + * @file 日历组件 + * @import extend/touch.js, core/widget.js, extend/highlight.js + * @module GMU + */ +(function( gmu, $, undefined ) { + var monthNames = ["01月", "02月", "03月", "04月", "05月", "06月", + "07月", "08月", "09月", "10月", "11月", "12月"], + + dayNames = ["日", "一", "二", "三", "四", "五", "六"], + offsetRE = /^(\+|\-)?(\d+)(M|Y)$/i, + + //获取月份的天数 + getDaysInMonth = function(year, month) { + return 32 - new Date(year, month, 32).getDate(); + }, + + //获取月份中的第一天是所在星期的第几天 + getFirstDayOfMonth = function(year, month) { + return new Date(year, month, 1).getDay(); + }, + + //格式化数字,不足补零. + formatNumber = function(val, len) { + var num = "" + val; + while (num.length < len) { + num = "0" + num; + } + return num; + }, + + getVal = function(elem) { + return elem.is('select, input') ? elem.val() : elem.attr('data-value'); + }, + + prototype; + + /** + * 日历组件 + * + * @class Calendar + * @constructor Html部分 + * ```html + *
+ * ``` + * + * javascript部分 + * ```javascript + * $('#calendar').calendar({ + * swipeable: true + * }); + * ``` + * @param {dom | zepto | selector} [el] 用来初始化日历的元素 + * @param {Object} [options] 组件配置项。具体参数请查看[Options](#GMU:Calendar:options) + * @grammar $( el ).calendar( options ) => zepto + * @grammar new gmu.Calendar( el, options ) => instance + */ + gmu.define( 'Calendar', { + options: { + /** + * @property {Date|String} [date=null] 初始化日期,默认今天 + * @namespace options + */ + date: null, + /** + * @property {Number} [firstDay=1] 设置新的一周从星期几开始,星期天用0表示, 星期一用1表示, 以此类推. + * @namespace options + */ + firstDay: 1, + /** + * @property {Date|String} [maxDate=null] 设置可以选择的最大日期 + * @namespace options + */ + maxDate: null, + /** + * @property {Date|String} [minDate=null] 设置可以选择的最小日期 + * @namespace options + */ + minDate: null, + /** + * @property {Boolean} [swipeable=false] 设置是否可以通过左右滑动手势来切换日历 + * @namespace options + */ + swipeable: false, + /** + * @property {Boolean} [monthChangeable=false] 设置是否让月份可选择 + * @namespace options + */ + monthChangeable: false, + /** + * @property {Boolean} [yearChangeable=false] 设置是否让年份可选择 + * @namespace options + */ + yearChangeable: false + }, + + _init: function() { + this.on('ready', function(){ + var opts = this._options, + el = this._container || this.$el, + eventHandler = $.proxy(this._eventHandler, this); + + this.minDate(opts.minDate) + .maxDate(opts.maxDate) + .date(opts.date || new Date()) + .refresh(); + + el.addClass('ui-calendar') + .on('click', eventHandler) + .highlight(); + + opts.swipeable && el.on('swipeLeft swipeRight', eventHandler); + }); + }, + + _create: function() { + var $el = this.$el; + + //如果没有指定el, 则创建一个空div + if( !$el ) { + $el = this.$el = $('
'); + } + $el.appendTo(this._options['container'] || ($el.parent().length ? '' : document.body)); + }, + + _eventHandler: function(e) { + var opts = this._options, + root = (this._container || this.$el).get(0), + match, + target, + cell, + date, + elems; + + switch (e.type) { + case 'swipeLeft': + case 'swipeRight': + return this.switchMonthTo((e.type == 'swipeRight' ? '-' : '+') + '1M'); + + case 'change': + elems = $('.ui-calendar-header .ui-calendar-year, ' + + '.ui-calendar-header .ui-calendar-month', this._el); + + return this.switchMonthTo(getVal(elems.eq(1)), getVal(elems.eq(0))); + + default: + //click + + target = e.target; + + if ((match = $(target).closest('.ui-calendar-calendar tbody a', root)) && match.length) { + + e.preventDefault(); + cell = match.parent(); + + this._option('selectedDate', + date = new Date(cell.attr('data-year'), cell.attr('data-month'), match.text())); + + this.trigger('select', date, $.calendar.formatDate(date), this); + this.refresh(); + } else if ((match = $(target).closest('.ui-calendar-prev, .ui-calendar-next', root)) && match.length) { + + e.preventDefault(); + this.switchMonthTo((match.is('.ui-calendar-prev') ? '-' : '+') + '1M'); + } + } + }, + + /** + * @ignore + * @name option + * @grammar option(key[, value]) ⇒ instance + * @desc 设置或获取Option,如果想要Option生效需要调用[Refresh](#calendar_refresh)方法。 + */ + _option: function(key, val) { + var opts = this._options, + date, minDate, maxDate; + + //如果是setter + if (val !== undefined) { + + switch (key) { + case 'minDate': + case 'maxDate': + opts[key] = val ? $.calendar.parseDate(val) : null; + break; + + case 'selectedDate': + minDate = opts.minDate; + maxDate = opts.maxDate; + val = $.calendar.parseDate(val); + val = minDate && minDate > val ? minDate : maxDate && maxDate < val ? maxDate : val; + opts._selectedYear = opts._drawYear = val.getFullYear(); + opts._selectedMonth = opts._drawMonth = val.getMonth(); + opts._selectedDay = val.getDate(); + break; + + case 'date': + this._option('selectedDate', val); + opts[key] = this._option('selectedDate'); + break; + + default: + opts[key] = val; + } + + //标记为true, 则表示下次refresh的时候要重绘所有内容。 + opts._invalid = true; + + //如果是setter则要返回instance + return this; + } + + return key == 'selectedDate' ? new Date(opts._selectedYear, opts._selectedMonth, opts._selectedDay) : opts[key]; + }, + + /** + * 切换到今天所在月份 + * @method switchToToday + */ + switchToToday: function() { + var today = new Date(); + return this.switchMonthTo(today.getMonth(), today.getFullYear()); + }, + + + /** + * 切换月份 + * @method switchMonthTo + * @param {String|Number} month 目标月份,值可以为+1M, +4M, -5Y, +1Y等等。+1M表示在显示的月的基础上显示下一个月,+4m表示下4个月,-5Y表示5年前 + * @param {String|Number} year 目标年份 + * @return {self} 返回本身 + */ + switchMonthTo: function(month, year) { + var opts = this._options, + minDate = this.minDate(), + maxDate = this.maxDate(), + offset, + period, + tmpDate; + + if (Object.prototype.toString.call(month) === '[object String]' && offsetRE.test(month)) { + offset = RegExp.$1 == '-' ? -parseInt(RegExp.$2, 10) : parseInt(RegExp.$2, 10); + period = RegExp.$3.toLowerCase(); + month = opts._drawMonth + (period == 'm' ? offset : 0); + year = opts._drawYear + (period == 'y' ? offset : 0); + } else { + month = parseInt(month, 10); + year = parseInt(year, 10); + } + + //Date有一定的容错能力,如果传入2012年13月,它会变成2013年1月 + tmpDate = new Date(year, month, 1); + + //不能跳到不可选的月份 + tmpDate = minDate && minDate > tmpDate ? minDate : maxDate && maxDate < tmpDate ? maxDate : tmpDate; + + month = tmpDate.getMonth(); + year = tmpDate.getFullYear(); + + if (month != opts._drawMonth || year != opts._drawYear) { + this.trigger('monthchange', opts._drawMonth = month, opts._drawYear = year, this); + + opts._invalid = true; + this.refresh(); + } + + return this; + }, + + /** + * 刷新日历,当修改option后需要调用此方法 + * @method refresh + * @return {self} 返回本身 + */ + refresh: function() { + var opts = this._options, + el = this._container || this.$el, + eventHandler = $.proxy(this._eventHandler, this); + + //如果数据没有变化厕不重绘了 + if (!opts._invalid) { + return; + } + + $('.ui-calendar-calendar td:not(.ui-state-disabled), .ui-calendar-header a', el).highlight(); + $('.ui-calendar-header select', el).off('change', eventHandler); + el.empty().append(this._generateHTML()); + $('.ui-calendar-calendar td:not(.ui-state-disabled), .ui-calendar-header a', el).highlight('ui-state-hover'); + $('.ui-calendar-header select', el).on('change', eventHandler); + opts._invalid = false; + return this; + }, + + /** + * 销毁组件 + * @method destroy + */ + destroy: function() { + var el = this._container || this.$el, + eventHandler = this._eventHandler; + + $('.ui-calendar-calendar td:not(.ui-state-disabled)', el).highlight(); + $('.ui-calendar-header select', el).off('change', eventHandler); + el.remove(); + return this.$super('destroy'); + }, + + /** + * 重绘表格 + */ + _generateHTML: function() { + var opts = this._options, + drawYear = opts._drawYear, + drawMonth = opts._drawMonth, + tempDate = new Date(), + today = new Date(tempDate.getFullYear(), tempDate.getMonth(), + tempDate.getDate()), + + minDate = this.minDate(), + maxDate = this.maxDate(), + selectedDate = this.selectedDate(), + html = '', + i, + j, + firstDay, + day, + leadDays, + daysInMonth, + rows, + printDate; + + firstDay = (isNaN(firstDay = parseInt(opts.firstDay, 10)) ? 0 : firstDay); + + html += this._renderHead(opts, drawYear, drawMonth, minDate, maxDate) + + ''; + + for (i = 0; i < 7; i++) { + day = (i + firstDay) % 7; + + html += '= 5 ? + + //如果是周末则加上ui-calendar-week-end的class给th + ' class="ui-calendar-week-end"' : '') + '>' + + '' + dayNames[day] + ''; + } + + //添加一个间隙,样式需求 + html += '' + + ''; + + daysInMonth = getDaysInMonth(drawYear, drawMonth); + leadDays = (getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; + rows = Math.ceil((leadDays + daysInMonth) / 7); + printDate = new Date(drawYear, drawMonth, 1 - leadDays); + + for (i = 0; i < rows; i++) { + html += ''; + + for (j = 0; j < 7; j++) { + html += this._renderDay(j, printDate, firstDay, drawMonth, selectedDate, today, minDate, maxDate); + printDate.setDate(printDate.getDate() + 1); + } + html += ''; + } + html += '
 
'; + return html; + }, + + _renderHead: function(data, drawYear, drawMonth, minDate, maxDate) { + var html = '
', + + //上一个月的最后一天 + lpd = new Date(drawYear, drawMonth, -1), + + //下一个月的第一天 + fnd = new Date(drawYear, drawMonth + 1, 1), + i, + max; + + html += '<<
'; + + if (data.yearChangeable) { + html += ''; + } else { + html += '' + drawYear + '年' + ''; + } + + if (data.monthChangeable) { + html += ''; + } else { + html += '' + monthNames[drawMonth] + ''; + } + + html += '
>>
'; + return html; + }, + + _renderDay: function(j, printDate, firstDay, drawMonth, selectedDate, today, minDate, maxDate) { + + var otherMonth = (printDate.getMonth() !== drawMonth), + unSelectable; + + unSelectable = otherMonth || (minDate && printDate < minDate) || (maxDate && printDate > maxDate); + + return "" + + + (otherMonth ? " " : (unSelectable ? "" + printDate.getDate() + "" : + "" + printDate.getDate() + "")) + ""; + } + }); + + prototype = gmu.Calendar.prototype; + + //添加更直接的option修改接口 + $.each(['maxDate', 'minDate', 'date', 'selectedDate'], function(i, name) { + prototype[name] = function(val) { + return this._option(name, val); + } + }); + + //补充注释 + + /** + * 设置或获取maxDate,如果想要Option生效需要调用[Refresh](#calendar_refresh)方法 + * @method maxDate + * @param {String|Date} value 最大日期的值 + * @return {self} 返回本身 + */ + + /** + * 设置或获取minDate,如果想要Option生效需要调用[Refresh](#calendar_refresh)方法 + * @method minDate + * @param {String|Date} value 最小日期的值 + * @return {self} 返回本身 + */ + + /** + * 设置或获取当前日期,如果想要Option生效需要调用[Refresh](#calendar_refresh)方法 + * @method date + * @param {String|Date} value 当前日期 + * @return {self} 返回本身 + */ + + /** + * 设置或获取当前选中的日期,如果想要Option生效需要调用[Refresh](#calendar_refresh)方法 + * @method selectedDate + * @param {String|Date} value 当前日期 + * @return {self} 返回本身 + */ + + + //@todo 支持各种格式 + //开放接口,如果现有格式不能满足需求,外部可以通过覆写一下两个方法 + $.calendar = { + + /** + * 解析字符串成日期格式对象。目前支持yyyy-mm-dd格式和yyyy/mm/dd格式。 + * @name $.calendar.parseDate + * @grammar $.calendar.parseDate( str ) ⇒ Date + */ + parseDate: function(obj) { + var dateRE = /^(\d{4})(?:\-|\/)(\d{1,2})(?:\-|\/)(\d{1,2})$/; + return Object.prototype.toString.call(obj) === '[object Date]' ? obj : dateRE.test(obj) ? new Date(parseInt(RegExp.$1, 10), parseInt(RegExp.$2, 10) - 1, parseInt(RegExp.$3, 10)) : null; + }, + + /** + * 格式化日期对象为字符串, 输出格式为yyy-mm-dd + * @name $.calendar.formatDate + * @grammar $.calendar.formatDate( date ) ⇒ String + */ + formatDate: function(date) { + return date.getFullYear() + '-' + formatNumber(date.getMonth() + 1, 2) + '-' + formatNumber(date.getDate(), 2); + } + } + + /** + * @event ready + * @param {Event} e gmu.Event对象 + * @description 当组件初始化完后触发。 + */ + + /** + * @event select + * @param {Event} e gmu.Event对象 + * @param {Date} date 当前选中的日期 + * @param {String} dateStr 当前选中日期的格式化字符串 + * @param {Instance} instance 当前日历的实例 + * @description 选中日期的时候触发 + */ + + /** + * @event monthchange + * @param {Event} e gmu.Event对象 + * @param {Date} month 当前月份 + * @param {String} year 当前年份 + * @param {Instance} instance 当前日历的实例 + * @description 前现实月份发生变化时触发 + */ + + /** + * @event destroy + * @param {Event} e gmu.Event对象 + * @description 组件在销毁的时候触发 + */ +})( gmu, gmu.$ ); + +/** + * @file Calendar Picker插件 + * @desc 默认的Calendar组件,只是在指定容器上生成日历功能,与表单元素的交互功能在此插件中体现. + * selector将会被认为是可赋值对象,当确认按钮点击后,所选的日期会赋值给selector。 + * @module GMU + * @import widget/calendar/calendar.js, extend/event.ortchange.js + */ +(function( gmu, $ ) { + function SlideUp(div, cb) { + var + //用来记录div的原始位置的 + holder = $(''), + + //dom + root = $('
' + + '
' + + '
' + + ' 确认' + + ' 取消' + + '
' + + '
' + + '
' + + '
'), + sDiv = $('.ui-slideup', root), + frame = $('.frame', sDiv), + + //对外只公开refresh和close方法 + obj = { + + /** + * 刷新日历显示,当屏幕旋转的时候时候需要外部调用 + */ + refresh: function( callback ){ + root.css({ + top: window.pageYOffset + 'px', + height: window.innerHeight + 'px' + }); + + sDiv.animate({ + translateY: '-' + sDiv.height() + 'px', + translateZ: '0' + }, 400, 'ease-out', function () { + callback && callback.call(obj); + }); + + }, + + /** + * 关闭日历 + */ + close: function( callback ){ + var count = SlideUp.count = SlideUp.count - 1; + + root.off('click.slideup' + id); + + sDiv + .animate({ + translateY: '0', + translateZ: '0' + }, 200, 'ease-out', function () { + callback && callback(); + + //还原div的位置 + holder.replaceWith(div); + + //销毁 + root.remove(); + count === 0 && $(document).off('touchmove.slideup'); + }) + .find('.ok-btn, .no-btn') + .highlight(); + + return obj; + } + }, + + //为了解绑事件用的 + id = SlideUp.id = ( SlideUp.id >>> 0 ) + 1, + + //记录当前弹出了多少次 + count; + + frame.append( div.replaceWith( holder ) ); + + count = SlideUp.count = ( SlideUp.count >>> 0 ) + 1; + + //弹出多个时,只会注册一次 + count === 1 && $(document).on('touchmove.slideup', function (e) { + + //禁用系统滚动 + e.preventDefault(); + }); + + root + .on('click.slideup' + id, '.ok-btn, .no-btn', function () { + cb.call(obj, $(this).is('.ok-btn')) !== false && obj.close(); + }) + .appendTo(document.body) + .find('.ok-btn, .no-btn') + .highlight('ui-state-hover'); + + obj.refresh(); + + return obj; + } + + /** + * Calendar Picker插件 + * + * 默认的Calendar组件,只是在指定容器上生成日历功能,与表单元素的交互功能在此插件中体现. + * selector将会被认为是可赋值对象,当确认按钮点击后,所选的日期会赋值给selector。 + * + * @class picker + * @namespace Calendar + * @pluginfor Calendar + */ + gmu.Calendar.register( 'picker', { + + _create: function () { + var el = this.$el; + + if( !el ) { + throw new Error("请指定日期选择器的赋值对象"); + } + }, + + _init: function(){ + var el = this.$el, + opts = this._options; + + this._container = $('
'); + + //如果有初始值,则把此值赋值给calendar + opts.date || (opts.date = el[el.is('select, input')?'val':'text']()); + + $(window).on('ortchange', $.proxy(this._eventHandler, this)); + this.on('commit', function(e, date){ + var str = $.calendar.formatDate(date); + + el[el.is('select, input')?'val':'text'](str); + }); + + this.on('destroy', function(){ + //解绑ortchange事件 + $(window).off('ortchange', this._eventHandler); + this._frame && this._frame.close(); + }); + }, + + _eventHandler: function(e){ + if(e.type === 'ortchange') { + this._frame && this._frame.refresh(); + }else { + this.origin( e ); + } + }, + + /** + * 显示组件 + * @method show + * @grammar show() ⇒ instance + * @param {Function} [callback] 刷新之后的回调函数 + * @for Calendar + * @uses Calendar.picker + */ + show: function(){ + var me = this, + el; + + if( this._visible ) { + return this; + } + + el = this._container; + + this._visible = true; + this.refresh(); + this._frame = SlideUp(el, function( confirm ){ + var date; + if( confirm) { + date = me._option('selectedDate'); + me.trigger('commit', date, $.calendar.formatDate(date), me); + me._option('date', date); + } else { + me._option('selectedDate', me._option('date')); + } + me.hide(); + return false; + }); + return this.trigger('show', this); + }, + + /** + * 隐藏组件 + * @method hide + * @grammar hide() ⇒ instance + * @param {Function} [callback] 刷新之后的回调函数 + * @for Calendar + * @uses Calendar.picker + */ + hide: function(){ + var me = this, + event; + + if (!this._visible) { + return this; + } + + event = new gmu.Event('beforehide'); + this.trigger(event, this); + + //如果外部阻止了此事件,则停止往下执行 + if(event.isDefaultPrevented()){ + return this; + } + + this._visible = false; + + this._frame.close(function(){ + me.trigger && me.trigger('hide'); + }); + + this._frame = null; + + return this; + } + + /** + * @event show + * @param {Event} e gmu.Event对象 + * @param {Calendar} ui widget实例 + * @description 当组件显示后触发 + * @for Calendar + * @uses Calendar.picker + */ + + /** + * @event hide + * @param {Event} e gmu.Event对象 + * @param {Calendar} ui widget实例 + * @description 当组件隐藏后触发 + * @for Calendar + * @uses Calendar.picker + */ + + /** + * @event beforehide + * @param {Event} e gmu.Event对象 + * @param {Calendar} ui widget实例 + * @description 组件隐藏之前触发,可以通过e.preventDefault()来阻止 + * @for Calendar + * @uses Calendar.picker + */ + + /** + * @event commit + * @param {Event} e gmu.Event对象 + * @param {Date} date 选中的日期 + * @param {String} dateStr 选中的日期字符格式 + * @param {Calendar} ui widget实例 + * @description 但确认选择某个日期的时候触发 + * @for Calendar + * @uses Calendar.picker + */ + } ); + +})( gmu, gmu.$ ); + +/** + * @file 弹出框组件 + * @import core/widget.js, extend/highlight.js, extend/parseTpl.js, extend/event.ortchange.js + * @module GMU + */ +(function( gmu, $, undefined ) { + var tpl = { + close: '', + mask: '
', + title: '
'+ + '

<%=title%>

'+ + '
', + wrap: '
'+ + '
'+ + '<% if(btns){ %>'+ + '
'+ + '<% for(var i=0, length=btns.length; i'+ + '<%=item.text%>'+ + '<% } %>'+ + '
'+ + '<% } %>' + + '
' + }; + + /** + * 弹出框组件 + * + * @class Dialog + * @constructor Html部分 + * ```html + *
+ *

请使用百度账号登录后, 获得更多个性化特色功能

+ *
+ * ``` + * + * javascript部分 + * ```javascript + * $('#dialog1').dialog({ + * autoOpen: false, + * closeBtn: false, + * buttons: { + * '取消': function(){ + * this.close(); + * }, + * '确定': function(){ + * this.close(); + * $('#dialog2').dialog('open'); + * } + * } + * }); + * ``` + * @param {dom | zepto | selector} [el] 用来初始化对话框的元素 + * @param {Object} [options] 组件配置项。具体参数请查看[Options](#GMU:Dialog:options) + * @grammar $( el ).dialog( options ) => zepto + * @grammar new gmu.Dialog( el, options ) => instance + */ + gmu.define( 'Dialog', { + options: { + /** + * @property {Boolean} [autoOpen=true] 初始化后是否自动弹出 + * @namespace options + */ + autoOpen: true, + /** + * @property {Array} [buttons=null] 弹出框上的按钮 + * @namespace options + */ + buttons: null, + /** + * @property {Boolean} [closeBtn=true] 是否显示关闭按钮 + * @namespace options + */ + closeBtn: true, + /** + * @property {Boolean} [mask=true] 是否有遮罩层 + * @namespace options + */ + mask: true, + /** + * @property {Number} [width=300] 弹出框宽度 + * @namespace options + */ + width: 300, + /** + * @property {Number|String} [height='auto'] 弹出框高度 + * @namespace options + */ + height: 'auto', + /** + * @property {String} [title=null] 弹出框标题 + * @namespace options + */ + title: null, + /** + * @property {String} [content=null] 弹出框内容 + * @namespace options + */ + content: null, + /** + * @property {Boolean} [scrollMove=true] 是否禁用掉scroll,在弹出的时候 + * @namespace options + */ + scrollMove: true, + /** + * @property {Element} [container=null] 弹出框容器 + * @namespace options + */ + container: null, + /** + * @property {Function} [maskClick=null] 在遮罩上点击时触发的事件 + * @namespace options + */ + maskClick: null, + position: null //需要dialog.position插件才能用 + }, + + /** + * 获取最外层的节点 + * @method getWrap + * @return {Element} 最外层的节点 + */ + getWrap: function(){ + return this._options._wrap; + }, + + _init: function(){ + var me = this, opts = me._options, btns, + i= 0, eventHanlder = $.proxy(me._eventHandler, me), vars = {}; + + me.on( 'ready', function() { + opts._container = $(opts.container || document.body); + (opts._cIsBody = opts._container.is('body')) || opts._container.addClass('ui-dialog-container'); + vars.btns = btns= []; + opts.buttons && $.each(opts.buttons, function(key){ + btns.push({ + index: ++i, + text: key, + key: key + }); + }); + opts._mask = opts.mask ? $(tpl.mask).appendTo(opts._container) : null; + opts._wrap = $($.parseTpl(tpl.wrap, vars)).appendTo(opts._container); + opts._content = $('.ui-dialog-content', opts._wrap); + + opts._title = $(tpl.title); + opts._close = opts.closeBtn && $(tpl.close).highlight('ui-dialog-close-hover'); + me.$el = me.$el || opts._content;//如果不需要支持render模式,此句要删除 + + me.title(opts.title); + me.content(opts.content); + + btns.length && $('.ui-dialog-btns .ui-btn', opts._wrap).highlight('ui-state-hover'); + opts._wrap.css({ + width: opts.width, + height: opts.height + }); + + //bind events绑定事件 + $(window).on('ortchange', eventHanlder); + opts._wrap.on('click', eventHanlder); + opts._mask && opts._mask.on('click', eventHanlder); + opts.autoOpen && me.open(); + } ); + }, + + _create: function(){ + var opts = this._options; + + if( this._options.setup ){ + opts.content = opts.content || this.$el.show(); + opts.title = opts.title || this.$el.attr('title'); + } + }, + + _eventHandler: function(e){ + var me = this, match, wrap, opts = me._options, fn; + switch(e.type){ + case 'ortchange': + this.refresh(); + break; + case 'touchmove': + opts.scrollMove && e.preventDefault(); + break; + case 'click': + if(opts._mask && ($.contains(opts._mask[0], e.target) || opts._mask[0] === e.target )){ + return me.trigger('maskClick'); + } + wrap = opts._wrap.get(0); + if( (match = $(e.target).closest('.ui-dialog-close', wrap)) && match.length ){ + me.close(); + } else if( (match = $(e.target).closest('.ui-dialog-btns .ui-btn', wrap)) && match.length ) { + fn = opts.buttons[match.attr('data-key')]; + fn && fn.apply(me, arguments); + } + } + }, + + _calculate: function(){ + var me = this, opts = me._options, size, $win, root = document.body, + ret = {}, isBody = opts._cIsBody, round = Math.round; + + opts.mask && (ret.mask = isBody ? { + width: '100%', + height: Math.max(root.scrollHeight, root.clientHeight)-1//不减1的话uc浏览器再旋转的时候不触发resize.奇葩! + }:{ + width: '100%', + height: '100%' + }); + + size = opts._wrap.offset(); + $win = $(window); + ret.wrap = { + left: '50%', + marginLeft: -round(size.width/2) +'px', + top: isBody?round($win.height() / 2) + window.pageYOffset:'50%', + marginTop: -round(size.height/2) +'px' + } + return ret; + }, + + /** + * 用来更新弹出框位置和mask大小。如父容器大小发生变化时,可能弹出框位置不对,可以外部调用refresh来修正。 + * @method refresh + * @return {self} 返回本身 + */ + refresh: function(){ + var me = this, opts = me._options, ret, action; + if(opts._isOpen) { + + action = function(){ + ret = me._calculate(); + ret.mask && opts._mask.css(ret.mask); + opts._wrap.css(ret.wrap); + } + + //如果有键盘在,需要多加延时 + if( $.os.ios && + document.activeElement && + /input|textarea|select/i.test(document.activeElement.tagName)){ + + document.body.scrollLeft = 0; + setTimeout(action, 200);//do it later in 200ms. + + } else { + action();//do it now + } + } + return me; + }, + + /** + * 弹出弹出框,如果设置了位置,内部会数值转给[position](widget/dialog.js#position)来处理。 + * @method open + * @param {String|Number} [x] X轴位置 + * @param {String|Number} [y] Y轴位置 + * @return {self} 返回本身 + */ + open: function(x, y){ + var opts = this._options; + opts._isOpen = true; + + opts._wrap.css('display', 'block'); + opts._mask && opts._mask.css('display', 'block'); + + x !== undefined && this.position ? this.position(x, y) : this.refresh(); + + $(document).on('touchmove', $.proxy(this._eventHandler, this)); + return this.trigger('open'); + }, + + /** + * 关闭弹出框 + * @method close + * @return {self} 返回本身 + */ + close: function(){ + var eventData, opts = this._options; + + eventData = $.Event('beforeClose'); + this.trigger(eventData); + if(eventData.defaultPrevented)return this; + + opts._isOpen = false; + opts._wrap.css('display', 'none'); + opts._mask && opts._mask.css('display', 'none'); + + $(document).off('touchmove', this._eventHandler); + return this.trigger('close'); + }, + + /** + * 设置或者获取弹出框标题。value接受带html标签字符串 + * @method title + * @param {String} [value] 弹出框标题 + * @return {self} 返回本身 + */ + title: function(value) { + var opts = this._options, setter = value !== undefined; + if(setter){ + value = (opts.title = value) ? '

'+value+'

' : value; + opts._title.html(value)[value?'prependTo':'remove'](opts._wrap); + opts._close && opts._close.prependTo(opts.title? opts._title : opts._wrap); + } + return setter ? this : opts.title; + }, + + /** + * 设置或者获取弹出框内容。value接受带html标签字符串和zepto对象。 + * @method content + * @param {String|Element} [val] 弹出框内容 + * @return {self} 返回本身 + */ + content: function(val) { + var opts = this._options, setter = val!==undefined; + setter && opts._content.empty().append(opts.content = val); + return setter ? this: opts.content; + }, + + /** + * @desc 销毁组件。 + * @name destroy + */ + destroy: function(){ + var opts = this._options, _eventHander = this._eventHandler; + $(window).off('ortchange', _eventHander); + $(document).off('touchmove', _eventHander); + opts._wrap.off('click', _eventHander).remove(); + opts._mask && opts._mask.off('click', _eventHander).remove(); + opts._close && opts._close.highlight(); + return this.$super('destroy'); + } + + /** + * @event ready + * @param {Event} e gmu.Event对象 + * @description 当组件初始化完后触发。 + */ + + /** + * @event open + * @param {Event} e gmu.Event对象 + * @description 当弹出框弹出后触发 + */ + + /** + * @event beforeClose + * @param {Event} e gmu.Event对象 + * @description 在弹出框关闭之前触发,可以通过e.preventDefault()来阻止 + */ + + /** + * @event close + * @param {Event} e gmu.Event对象 + * @description 在弹出框关闭之后触发 + */ + + /** + * @event destroy + * @param {Event} e gmu.Event对象 + * @description 组件在销毁的时候触发 + */ + }); +})( gmu, gmu.$ ); + +/** + * @file 修复Zepto中offset setter bug + * 比如 被定位元素满足以下条件时,会定位不正确 + * 1. 被定位元素不是第一个节点,且prev兄弟节点中有非absolute或者fixed定位的元素 + * 2. 被定位元素为非absolute或者fixed定位。 + * issue: https://github.com/gmuteam/GMU/issues/101 + * @import zepto.js + * @module GMU + */ + +(function( $ ) { + var _offset = $.fn.offset, + round = Math.round; + + // zepto的offset bug的主要问题是当position:relative的时候,没有考虑元素的初始值。 + // 初始值,是指positon:relative; top: 0; left: 0; bottom:0; right:0; 的时候 + // 该元素的位置,zepto中的offset是假定了这个值就是{left:0, top: 0}; 实际上前面有兄弟 + // 节点且不为postion: absolute|fixed 定位时时,该元素的初始位置并不是{left:0, top: 0} + // 会根据前面兄弟节点的内容大小而不一样。 + function setter( coord ) { + return this.each(function( idx ) { + var $el = $( this ), + coords = $.isFunction( coord ) ? coord.call( this, idx, + $el.offset() ) : coord, + + position = $el.css( 'position' ), + + // position为absolute或者fixed定位的元素,跟元素的初始位置没有关系 + // 所以不需要取初始位置 + pos = position === 'absolute' || position === 'fixed' || + $el.position(); + + // 如果是position为relative, 且存在 top, right, bottom, left值 + // position值还不能代表初始值,需要还原一下 + // 比如 top: 1px, 那要让position取得的值减去1px才是该元素的初始位置 + // 但是如果是top:auto, bottom: 1px; 则是要加1px, 所以下面的代码要乘以个-1 + if ( position === 'relative' ) { + pos.top -= parseFloat( $el.css( 'top' ) ) || + parseFloat( $el.css( 'bottom' ) ) * -1 || 0; + pos.left -= parseFloat( $el.css( 'left' ) ) || + parseFloat( $el.css( 'right' ) ) * -1 || 0; + } + + parentOffset = $el.offsetParent().offset(), + + // 迫于无赖,chrome下如果offset设置的top,left不是整型,会导致popOver中arrow样式有问题。 + props = { + top: round( coords.top - (pos.top || 0) - parentOffset.top ), + left: round( coords.left - (pos.left || 0) - parentOffset.left ) + } + + if ( position == 'static' ){ + props['position'] = 'relative'; + } + + // 可以考虑改用animate方法。 + if ( coords.using ) { + coords.using.call( this, props, idx ); + } else { + $el.css( props ); + } + }); + } + + $.fn.offset = function( corrd ) { + return corrd ? setter.call( this, corrd ): _offset.call( this ); + } +})( Zepto ); +/** + * @file 基于Zepto的位置设置获取组件 + * @import zepto.js, extend/offset.js + * @module GMU + */ + +(function ($, undefined) { + var _position = $.fn.position, + round = Math.round, + rhorizontal = /^(left|center|right)([\+\-]\d+%?)?$/, + rvertical = /^(top|center|bottom)([\+\-]\d+%?)?$/, + rpercent = /%$/; + + function str2int( persent, totol ) { + return (parseInt( persent, 10 ) || 0) * (rpercent.test( persent ) ? + totol / 100 : 1); + } + + function getOffsets( pos, offset, width, height ) { + return [ + pos[ 0 ] === 'right' ? width : pos[ 0 ] === 'center' ? + width / 2 : 0, + + pos[ 1 ] === 'bottom' ? height : pos[ 1 ] === 'center' ? + height / 2 : 0, + + str2int( offset[ 0 ], width ), + + str2int( offset[ 1 ], height ) + ]; + } + + function getDimensions( elem ) { + var raw = elem[ 0 ], + isEvent = raw.preventDefault; + + raw = raw.touches && raw.touches[ 0 ] || raw; + + // 特殊处理document, window和event对象 + if ( raw.nodeType === 9 || raw === window || isEvent ) { + return { + width: isEvent ? 0 : elem.width(), + height: isEvent ? 0 : elem.height(), + top: raw.pageYOffset || raw.pageY || 0, + left: raw.pageXOffset || raw.pageX || 0 + }; + } + + return elem.offset(); + } + + function getWithinInfo( el ) { + var $el = $( el = (el || window) ), + dim = getDimensions( $el ); + + el = $el[ 0 ]; + + return { + $el: $el, + width: dim.width, + height: dim.height, + scrollLeft: el.pageXOffset || el.scrollLeft, + scrollTop: el.pageYOffset || el.scrollTop + }; + } + + // 参数检测纠错 + function filterOpts( opts, offsets ) { + [ 'my', 'at' ].forEach(function( key ) { + var pos = ( opts[ key ] || '' ).split( ' ' ), + opt = opts[ key ] = [ 'center', 'center' ], + offset = offsets[ key ] = [ 0, 0 ]; + + pos.length === 1 && pos[ rvertical.test( pos[ 0 ] ) ? 'unshift' : + 'push' ]( 'center' ); + + rhorizontal.test( pos[ 0 ] ) && (opt[ 0 ] = RegExp.$1) && + (offset[ 0 ] = RegExp.$2); + + rvertical.test( pos[ 1 ] ) && (opt[ 1 ] = RegExp.$1) && + (offset[ 1 ] = RegExp.$2); + }); + } + + /** + * 获取元素相对于相对父级元素(父级最近为position为relative|abosolute|fixed的元素)的坐标位置。 + * @method $.fn.position + * @grammar position() ⇒ array + * @grammar position(opts) ⇒ self + * @param {String} [my=center] 设置中心点。可以为'left top', 'center bottom', 'right center'...同时还可以设置偏移量;如 'left+5 center-20%' + * @param {String} [at=center] 设置定位到目标元素的什么位置。参数格式同my参数一致 + * @param {Object} [of=null] 设置目标元素 + * @param {Function} [collision=null] 碰撞检测回调方法 + * @param {Object} [within=window] 碰撞检测对象 + * @example + * var position = $('#target').position(); + * $('#target').position({ + * my: 'center', + * at: 'center', + * of: document.body + * }); + */ + $.fn.position = function ( opts ) { + if ( !opts || !opts.of ) { + return _position.call( this ); + } + + opts = $.extend( {}, opts ); + + var target = $( opts.of ), + collision = opts.collision, + within = collision && getWithinInfo( opts.within ), + ofses = {}, + dim = getDimensions( target ), + bPos = { + left: dim.left, + top: dim.top + }, + atOfs; + + target[ 0 ].preventDefault && (opts.at = 'left top'); + filterOpts( opts, ofses ); // 参数检测纠错 + + atOfs = getOffsets( opts.at, ofses.at, dim.width, dim.height ); + bPos.left += atOfs[ 0 ] + atOfs[ 2 ]; + bPos.top += atOfs[ 1 ] + atOfs[ 3 ]; + + return this.each(function() { + var $el = $( this ), + ofs = $el.offset(), + pos = $.extend( {}, bPos ), + myOfs = getOffsets( opts.my, ofses.my, ofs.width, ofs.height ); + + pos.left = round( pos.left + myOfs[ 2 ] - myOfs[ 0 ] ); + pos.top = round( pos.top + myOfs[ 3 ] - myOfs[ 1 ] ); + + collision && collision.call( this, pos, { + of: dim, + offset: ofs, + my: opts.my, + at: opts.at, + within: within, + $el : $el + } ); + + pos.using = opts.using; + $el.offset( pos ); + }); + } +})( Zepto ); +/** + * @file Dialog - 父容器插件 + * @module GMU + * @import widget/dialog/dialog.js, extend/position.js + */ +(function( gmu, $, undefined ) { + /** + * @name dialog.position + * @desc 用zepto.position来定位dialog + */ + /** + * 用zepto.position来定位dialog + * + * @class position + * @namespace Dialog + * @pluginfor Dialog + */ + gmu.Dialog.register( 'position', { + + _init: function(){ + var opts = this._options; + + opts.position = opts.position || {of: opts.container || window, at: 'center', my: 'center'}; + }, + + /** + * 用来设置弹出框的位置,如果不另外设置,组件默认为上下左右居中对齐。位置参数接受,数值,百分比,带单位的数值,或者'center'。 + * 如: 100, 100px, 100em, 10%, center;暂时不支持 left, right, top, bottom. + * @method position + * @param {String|Number} [x] X轴位置 + * @param {String|Number} [y] Y轴位置 + * @for Dialog + * @uses Dialog.position + * @return {self} 返回本身。 + */ + position: function(x, y){ + var opts = this._options; + if(!$.isPlainObject(x)){//兼容老格式! + opts.position.at = 'left'+(x>0?'+'+x: x)+' top'+(y>0?'+'+y: y); + } else $.extend(opts.position, x); + return this.refresh(); + }, + + _calculate:function () { + var me = this, + opts = me._options, + position = opts.position, + ret = me.origin(); + + opts._wrap.position($.extend(position, { + using: function(position){ + ret.wrap = position; + } + })); + + return ret; + } + } ); +})( gmu, gmu.$); + +/** + * @file 弹出层组件, 基础版本。 + * @import core/widget.js + * @module GMU + */ +(function( gmu, $, undefined ) { + + /** + * 弹出层组件,具有点击按钮在周围弹出层的交互效果。至于弹出层内容,可以通过`content`直接设置内容, + * 也可以通过`container`设置容器节点。按钮和弹出层之间没有位置依赖。 + * + * 基础版本只有简单的点击显示,再点击隐藏功能。像用更多的功能请参看[插件介绍](#GMU:Popover:plugins)部分. + * + * @class Popover + * @constructor Html部分 + * ```html + * 按钮 + * ``` + * + * javascript部分 + * ```javascript + * $('#btn').popover({ + * content: 'Hello world' + * }); + * ``` + * @param {dom | zepto | selector} [el] 按钮节点 + * @param {Object} [options] 组件配置项。具体参数请查看[Options](#GMU:Popover:options) + * @grammar $( el ).popover( options ) => zepto + * @grammar new gmu.Popover( el, options ) => instance + */ + gmu.define( 'Popover', { + + // 默认配置项。 + options: { + + /** + * @property {Zepto | Selector} [container] 指定容器,如果不传入,组件将在el的后面自动创建一个。 + * @namespace options + */ + container: null, + + /** + * @property {String | Zepto | Selector } [content] 弹出框的内容。 + * @namespace options + */ + content: null, + + /** + * @property {String} [event="click"] 交互事件名, 可能你会设置成tap。 + * @namespace options + */ + event: 'click' + }, + + template: { + frame: '
' + }, + + /** + * @event ready + * @param {Event} e gmu.Event对象 + * @description 当组件初始化完后触发。 + */ + +  // 负责dom的创建。 + _create: function() { + var me = this, + opts = me._options, + $el = opts.target && $( opts.target ) || me.getEl(), + $root = opts.container && $( opts.container ); + + // 没传 或者 就算传入了选择器,但是没有找到节点,还是得创建一个。 + $root && $root.length || ($root = $( me.tpl2html( 'frame' ) ) + .addClass( 'ui-mark-temp' )); + me.$root = $root; + + // 如果传入了content, 则作为内容插入到container中 + opts.content && me.setContent( opts.content ); + me.trigger( 'done.dom', $root.addClass( 'ui-' + me.widgetName ), + opts ); + + // 如果节点是动态创建的,则不在文档树中,就把节点插入到$el后面。 + $root.parent().length || $el.after( $root ); + + me.target( $el ); + }, + + // 删除标记为组件临时的dom + _checkTemp: function( $el ) { + $el.is( '.ui-mark-temp' ) && $el.off( this.eventNs ) && + $el.remove(); + }, + + /** + * @event beforeshow + * @param {Event} e gmu.Event对象 + * @description 但弹出层打算显示时触发,可以通过`e.preventDefault()`来阻止。 + */ + + + /** + * @event show + * @param {Event} e gmu.Event对象 + * @description 当弹出层显示后触发。 + */ + + + /** + * 显示弹出层。 + * @method show + * @chainable + * @return {self} 返回本身。 + */ + show: function() { + var me = this, + evt = gmu.Event( 'beforeshow' ); + + me.trigger( evt ); + + // 如果外部阻止了关闭,则什么也不做。 + if ( evt.isDefaultPrevented() ) { + return; + } + + me.trigger( 'placement', me.$root.addClass( 'ui-in' ), me.$target ); + me._visible = true; + return me.trigger( 'show' ); + }, + + /** + * @event beforehide + * @param {Event} e gmu.Event对象 + * @description 但弹出层打算隐藏时触发,可以通过`e.preventDefault()`来阻止。 + */ + + + /** + * @event hide + * @param {Event} e gmu.Event对象 + * @description 当弹出层隐藏后触发。 + */ + + /** + * 隐藏弹出层。 + * @method hide + * @chainable + * @return {self} 返回本身。 + */ + hide: function() { + var me = this, + evt = new gmu.Event( 'beforehide' ); + + me.trigger( evt ); + + // 如果外部阻止了关闭,则什么也不做。 + if ( evt.isDefaultPrevented() ) { + return; + } + + me.$root.removeClass( 'ui-in' ); + me._visible = false; + return me.trigger( 'hide' ); + }, + + /** + * 切换弹出层的显示和隐藏。 + * @method toggle + * @chainable + * @return {self} 返回本身。 + */ + toggle: function() { + var me = this; + return me[ me._visible ? 'hide' : 'show' ].apply( me, arguments ); + }, + + /** + * 设置或者获取当前`按钮`(被点击的对象)。 + * @method target + * @param {dom | selector | zepto} [el] target新值。 + * @chainable + * @return {self} 当传入了el时,此方法为setter, 返回值为self. + * @return {dom} 当没有传入el时,为getter, 返回当前target值。 + */ + target: function( el ) { + + // getter + if ( el === undefined ) { + return this.$target; + } + + // setter + var me = this, + $el = $( el ), + orig = me.$target, + click = me._options.event + me.eventNs; + + orig && orig.off( click ); + + // 绑定事件 + me.$target = $el.on( click, function( e ) { + e.preventDefault(); + me.toggle(); + } ); + + return me; + }, + + /** + * 设置当前容器内容。 + * @method setContent + * @param {dom | selector | zepto} [value] 容器内容 + * @chainable + * @return {self} 组件本身。 + */ + setContent: function( val ) { + var container = this.$root; + container.empty().append( val ); + return this; + }, + + /** + * 销毁组件,包括事件销毁和删除自动创建的dom. + * @method destroy + * @chainable + * @return {self} 组件本身。 + */ + destroy: function() { + var me = this; + + me.$target.off( me.eventNs ); + me._checkTemp( me.$root ); + return me.$super( 'destroy' ); + } + } ); +})( gmu, gmu.$ ); +/** + * @file 附近弹出组件 + * @import core/widget.js, widget/popover/popover.js, extend/highlight.js + * @module GMU + */ +(function( gmu, $ ) { + + /** + * 附近弹出组件 + * + * @class Dropmenu + * @constructor Html部分 + * ```html + * Dropmenu + * ``` + * + * javascript部分 + * ```javascript + * $('#btn1').dropmenu({ + * content: [ + * + * 'Action', + * + * 'Another Action', + * + * 'Someone else here', + * + * 'divider', + * + * { + * text: 'Open Baidu', + * icon: 'grid', + * href: 'http://www.baidu.com' + * }, + * ] + * }) + * ``` + * @param {dom | zepto | selector} [el] 用来初始化组件的元素 + * @param {Object} [options] 组件配置项。具体参数请查看[Options](#GMU:Dropmenu:options) + * @grammar $( el ).dropmenu( options ) => zepto + * @grammar new gmu.Dropmenu( el, options ) => instance + */ + gmu.define( 'Dropmenu', { + options: { + + // 注意: 以前是叫items, 为了与其他组件统一,所以改名叫content + /** + * @property {Array} [content=null] 弹出的内容,每条记录为一个Object,属性有 {text:'', icon: '', href:'' } + * @namespace options + */ + content: null + }, + + template: { + + item: '
  • href="<%= href %>"<% } %>>' + + '<% if ( icon ) { %><% } %><%= text %>
  • ', + + divider: '
  • ', + + wrap: '
      ' + }, + + _init: function() { + var me = this; + + // 存储ul + me.on( 'done.dom', function( e, $root ) { + me.$list = $root.find( 'ul' ).first() + .addClass( 'ui-dropmenu-items' ) + .highlight( 'ui-state-hover', + '.ui-dropmenu-items>li:not(.divider)' ); + } ); + }, + + _create: function() { + var me = this, + opts = me._options, + content = ''; + + // 根据opts.content创建ul>li + if ( $.type( opts.content ) === 'array' ) { + + opts.content.forEach(function( item ) { + + item = $.extend( { + href: '', + icon: '', + text: '' + }, typeof item === 'string' ? { + text: item + } : item ); + + content += me.tpl2html( item.text === 'divider' ? + 'divider' : 'item', item ); + }); + opts.content = $( me.tpl2html( 'wrap' ) ).append( content ); + } + + me.$super( '_create' ); + me.$list.on( 'click' + me.eventNs, '.ui-dropmenu-items>li:not(' + + '.ui-state-disable):not(.divider)', function( e ) { + + var evt = gmu.Event( 'itemclick', e ); + me.trigger( evt, this ); + + if ( evt.isDefaultPrevented() ) { + return; + } + + me.hide(); + } ); + } + + /** + * @event ready + * @param {Event} e gmu.Event对象 + * @description 当组件初始化完后触发。 + */ + + /** + * @event itemclick + * @param {Event} e gmu.Event对象 + * @param {Element} item 当前点击的条目 + * @description 某个条目被点击时触发 + */ + + /** + * @event destroy + * @param {Event} e gmu.Event对象 + * @description 组件在销毁的时候触发 + */ + }, gmu.Popover ); + +})( gmu, gmu.$ ); +/** + * @file Dropmenu 支持水平排列插件 + * @module GMU + * @import widget/dropmenu/dropmenu.js + */ +(function( gmu ) { + + gmu.Dropmenu.options.horizontal = true; + + /** + * Dropmenu 支持水平排列插件 + * + * @class horizontal + * @namespace Dropmenu + * @pluginfor Dropmenu + */ + gmu.Dropmenu.option( 'horizontal', true, function() { + var me = this; + + me.on( 'done.dom', function( e, $root ) { + $root.addClass( 'ui-horizontal' ); + } ); + } ); +})( gmu, gmu.$ ); +/** + * @file Dropmenu 简单版定位 + * @module GMU + * @import widget/dropmenu/dropmenu.js, extend/offset.js + */ +(function( gmu, $ ) { + + // 设置默认Options + $.extend( gmu.Dropmenu.options, { + /** + * @property {String} [placement='bottom'] 默认让其在下方显示 + * @namespace options + * @for Dropmenu + * @uses Dropmenu.placement + */ + placement: 'bottom', + + /** + * @property {String} [align='center'] 默认居中对齐 + * @namespace options + * @for Dropmenu + * @uses Dropmenu.placement + */ + align: 'center', + + /** + * @property {Object} [offset=null] 偏移量 + * @namespace options + * @for Dropmenu + * @uses Dropmenu.placement + */ + offset: null + } ); + + /** + * Dropmenu 简单版定位 + * + * @class placement + * @namespace Dropmenu + * @pluginfor Dropmenu + */ + gmu.Dropmenu.option( 'placement', function( val ) { + return ~[ 'top', 'bottom' ].indexOf( val ); + }, function() { + var config = { + 'top_center': 'center top center bottom', + 'top_left': 'left top left bottom', + 'top_right': 'right top right bottom', + 'bottom_center': 'center bottom center top', + 'bottom_right': 'right bottom right top', + 'bottom_left': 'left bottom left top' + }, + presets = {}, // 支持的定位方式。 + + info; + + $.each( config, function( preset, args ) { + args = args.split( /\s/g ); + args.unshift( preset ); + presets[ preset ] = function() { + return placement.apply( null, args ); + }; + } ); + + function getPos( pos, len ) { + return pos === 'right' || pos === 'bottom' ? len : + pos === 'center' ? len / 2 : 0; + } + + // 暂时用简单的方式实现,以后考虑采用position.js + function placement( preset, atH, atV, myH, myV ) { + var of = info.of, + coord = info.coord, + offset = info.offset, + top = of.top, + left = of.left; + + left += getPos( atH, of.width ) - getPos( myH, coord.width ); + top += getPos( atV, of.height ) - getPos( myV, coord.height ); + + // offset可以是fn + offset = typeof offset === 'function' ? offset.call( null, { + left: left, + top: top + }, preset ) : offset || {}; + + return { + left: left + (offset.left || 0), + top: top + (offset.top || 0) + }; + } + + this.on( 'placement', function( e, $el, $of ) { + var me = this, + opts = me._options, + placement = opts.placement, + align = opts.align, + coord; + + info = { + coord: $el.offset(), + of: $of.offset(), + placement: placement, + align: align, + $el: $el, + $of: $of, + offset: opts.offset + }; + + // 设置初始值 + coord = presets[ placement + '_' + align ](); + + // 提供机会在设置之前修改位置 + me.trigger( 'before.placement', coord, info, presets ); + + if ( /^(\w+)_(\w+)$/.test( info.preset ) ) { + info.placement = RegExp.$1; + info.align = RegExp.$2; + } + + $el.offset( coord ); + + // 提供给arrow位置定位用 + me.trigger( 'after.placement', coord, info ); + } ); + } ); +})( gmu, gmu.$ ); +/** + * @file 返回顶部组件 + * @import core/widget.js, extend/fix.js, extend/throttle.js, extend/event.scrollStop.js, extend/event.ortchange.js + * @module GMU + */ +(function( gmu, $, undefined ) { + + /** + * 返回顶部组件 + * + * @class Gotop + * @constructor Html部分 + * ```html + *
      + * ``` + * + * javascript部分 + * ```javascript + * $('#gotop').gotop(); + * ``` + * @param {dom | zepto | selector} [el] 用来初始化组件的元素 + * @param {Object} [options] 组件配置项。具体参数请查看[Options](#GMU:Gotop:options) + * @grammar $( el ).gotop( options ) => zepto + * @grammar new gmu.Gotop( el, options ) => instance + */ + gmu.define( 'Gotop', { + options: { + /** + * @property {selector} [container=document.body] 组件容器 + * @namespace options + */ + container: '', + /** + * @property {Boolean} [useFix=true] 是否使用固顶效果 + * @namespace options + */ + useFix: true, + /** + * @property {Boolean} [useHide=true] 是否在touchmove的时候隐藏gotop图标 + * @namespace options + */ + useHide: true, + /** + * @property {Boolean} [useAnimation=false] 返回顶部时是否使用动画,在使用iScroll时,返回顶部的动作由iScroll实例执行,此参数无效 + * @namespace options + */ + useAnimation: false, + /** + * @property {Object} [position={bottom:10,right:10}] 使用fix效果时,要用的位置参数 + * @namespace options + */ + position: {bottom: 10, right: 10}, + /** + * @property {Function} [afterScroll=null] 返回顶部后执行的回调函数 + * @namespace options + */ + afterScroll: null + }, + + _init: function() { + var me = this, + $el, + _opts = me._options, + _eventHandler; + + if($.os.version && $.os.version.substr(0, 3) >= 7.0) { + _opts.position.bottom = 40; + } + + me.on( 'ready', function(){ + $el = me.$el; + _eventHandler = $.proxy(me._eventHandler, me); + + _opts['useHide'] && $(document).on('touchmove', _eventHandler); + $(window).on('touchend touchcancel scrollStop', _eventHandler); + $(window).on('scroll ortchange', _eventHandler); + $el.on('click', _eventHandler); + me.on('destroy', function() { + $(window).off('touchend touchcancel scrollStop', _eventHandler); + $(document).off('touchmove', _eventHandler); + $(window).off('scroll ortchange', _eventHandler); + }); + _opts['useFix'] && $el.fix(_opts['position']); + _opts['root'] = $el[0]; + } ); + + // 不管是哪种模式创建的,destroy时都将元素移除 + me.on( 'destroy', function() { + me.$el.remove(); + } ); + }, + + _create: function() { + var me = this; + + if( !me.$el ) { + me.$el = $('
      '); + } + me.$el.addClass('ui-gotop').append('
      ').appendTo(me._options['container'] || (me.$el.parent().length ? '' : document.body)); + + return me; + }, + + /** + * 事件处理中心 + */ + _eventHandler: function(e) { + var me = this; + + switch (e.type) { + case 'touchmove': + me.hide(); + break; + case 'scroll': + clearTimeout(me._options['_TID']); + break; + case 'touchend': + case 'touchcancel': + clearTimeout(me._options['_TID']); + me._options['_TID'] = setTimeout(function(){ + me._check.call(me); + }, 300); + break; + case 'scrollStop': + me._check(); + break; + case 'ortchange': + me._check.call(me); + break; + case 'click': + me._scrollTo(); + break; + } + }, + + /** + * 判断是否显示gotop + */ + _check: function(position) { + var me = this; + + (position !== undefined ? position : window.pageYOffset) > document.documentElement.clientHeight ? me.show() : me.hide(); + + return me; + }, + + /** + * 滚动到顶部或指定节点位置 + */ + _scrollTo: function() { + var me = this, + from = window.pageYOffset; + + me.hide(); + clearTimeout(me._options['_TID']); + if (!me._options['useAnimation']) { + window.scrollTo(0, 1); + me.trigger('afterScroll'); + } else { + me._options['moveToTop'] = setInterval(function() { + if (from > 1) { + window.scrollBy(0, -Math.min(150,from - 1)); + from -= 150; + } else { + clearInterval(me._options['moveToTop']); + me.trigger('afterScroll'); + } + }, 25, true); + } + return me; + }, + + /** + * 显示gotop + * @method show + * @return {self} 返回本身 + */ + show: function() { + this._options.root.style.display = 'block'; + + return this; + }, + + /** + * 隐藏gotop + * @method hide + * @chainable + * @return {self} 返回本身 + */ + hide: function() { + this._options.root.style.display = 'none'; + + return this; + } + + /** + * @event ready + * @param {Event} e gmu.Event对象 + * @description 当组件初始化完后触发 + */ + + /** + * @event afterScroll + * @param {Event} e gmu.Event对象 + * @description 返回顶部后触发的事件 + */ + + /** + * @event destroy + * @param {Event} e gmu.Event对象 + * @description 组件在销毁的时候触发 + */ + }); +})( gmu, gmu.$ ); + +/** + * @file 历史记录组件 + * @import core/widget.js, extend/touch.js, widget/dialog.js + * @module GMU + */ + + // TODO 列表区域支持iScroll +(function( gmu, $ ) { + + /** + * 历史记录组件 + * + * @class Historylist + * @constructor Html部分 + * ```html + *
      + *

      + *
      + *
      + * ``` + * + * javascript部分 + * ```javascript + * var instance = new gmu.Historylist({ + * container: $('#J_historyWrap'), // 页面上需要有一个已经存在的容器来存放组件 + * items: [ + * {'value': 'global', 'context': 'global adj. 全球的;综合的'}, + * 'google', + * {'value': 'visual', 'context': 'visual adj. 视觉的'}, + * 'alibaba', + * 'taobao' + * ], // 历史记录的列表 + * itemTouch: function(e, data) { // 某条记录被点击后的响应事件 + * console.log( 'item touched: ' + data.item ); // data.item是某条记录的内容 + * $('#J_input').val(data.item); + * }, + * itemDelete: function(e, data) { // 某条记录被删除后的响应事件 + * console.log( 'item delete:' + data.item ); // data.item是某条记录的内容 + * }, + * clear: function() { // 用户确认清空搜索历史后的响应事件 + * // 在这里删除localstorage里面存的历史数据 + * console.log( 'clear triggered' ); + * } + * }); + * ``` + * @param {dom | zepto | selector} [el] 用来初始化组件的元素 + * @param {Object} [options] 组件配置项。具体参数请查看[Options](#GMU:Historylist:options) + * @grammar $( el ).historylist( options ) => zepto + * @grammar new gmu.Historylist( el, options ) => instance + */ + gmu.define( 'Historylist', { + + options: { + + /** + * @property {Zepto | Selector | Element} [container=document.body] 容器,默认为 document.body + * @namespace options + */ + container: document.body, + + /** + * @property {Boolean} [deleteSupport=true] 是否支持滑动删除记录,默认支持 + * @namespace options + */ + deleteSupport: true, + + /** + * @property {Array} [items=Array()] 历史记录的数据 + * @namespace options + */ + items: [] + }, + + template: { + wrap: '
        ', + item: '
      • <%=context%>

      • ', + clear: '

        清空搜索历史

        ' + }, + + _init: function() { + var me = this, + opts = me._options; + + // js不一定放在页面尾部,所以在init中要重新赋值 + me.$el = opts.container = opts.container || document.body; + + me.items = []; + + me.on( 'ready', function() { + me._bindUI(); + } ); + + me.on( 'itemDelete', function() { + // 历史记录为空时,隐藏 + if( me.items.length === 0 ) { + me.hide(); + } + } ); + }, + + _create: function() { + var me = this, + opts = me._options; + + me.$el.hide(); + me.$wrap = $( me.tpl2html( 'wrap' ) ).appendTo( opts.container ); + + me.$clear = $( me.tpl2html( 'clear' ) ).appendTo( opts.container ); + !me._options.deleteSupport && me.$clear.hide(); + + me.addItems( opts.items ); + + me.show(); + }, + + _filterItemsById: function( id, callback ) { + var me = this; + + me.items.forEach( function( _item, index ) { + if ( _item.id === id ) { + callback.call( me, _item, index ); + + return; + } + } ); + }, + + _bindUI: function() { + var me = this, + touch, + $target, + itemId, + startTimestamp, + endTimestamp, + wantDelete = false, + timeout, + touchstartX, + currentX, + touchstartY, + currentY, + velocity, + movedPercentage, + moved, + movedDistance; + + me.$clear.on( 'tap' + me.eventNs, function( ev ) { + // 防止穿透 + setTimeout( function() { + gmu.Dialog({ + closeBtn: false, + buttons: { + '清空': function(){ + me.clear(); + this.destroy(); + }, + '取消': function(){ + this.destroy(); + } + }, + title: '清空历史', + content: '

        是否清空搜索历史?

        ', + open: function(){ + this._options._wrap.addClass( 'ui-historylist-dialog' ); + } + }); + }, 10 ); + + ev.preventDefault(); + ev.stopPropagation(); + } ); + + me.$wrap.on( 'tap' + me.eventNs, function(ev) { + if( me._options.deleteSupport ) { + return; + } + + $target = $( ev.target ); + + if( !$target.hasClass( 'ui-historylist-itemwrap' ) && + !($target = $target.parents( '.ui-historylist-itemwrap' )).length ) { + $target = null; + return; + } + + itemId = $target.parent().attr( 'data-id' ); + me._filterItemsById( itemId, function( _item ) { + me.trigger( 'itemTouch', {'item': _item.value} ); + }); + + } ); + + me.$wrap.on( 'touchstart' + me.eventNs, function(ev) { + + if( !me._options.deleteSupport ) { + return; + } + touch = ev.touches[0]; + $target = $( touch.target ); + startTimestamp = ev.timeStamp; + currentX = touchstartX = parseInt( touch.pageX ); + currentY = touchstartY = parseInt( touch.pageY ); + moved = false; + wantDelete = false; + + if( !$target.hasClass( 'ui-historylist-itemwrap' ) && + !($target = $target.parents( '.ui-historylist-itemwrap' )).length ) { + $target = null; + return; + } + + $target.addClass( 'ui-historylist-ontap' ); + + // TODO 用了-webkit-box,就不需要去动态设置width了 + $target.css( 'width', $target.width() - parseInt( $target.css( 'border-left-width' ) ) - parseInt( $target.css( 'border-right-width' ) )); + } ); + + me.$wrap.on( 'touchmove' + me.eventNs, function(ev) { + if( !$target ) { + return; + } + + currentX = ev.touches[0].pageX; + currentY = ev.touches[0].pageY; + timeout === undefined && (timeout = setTimeout( function() { + // 竖向移动的距离大于横向移动距离的一半时,认为用户是企图滚动,而不是删除 + if( Math.abs( currentY - touchstartY ) > Math.abs (currentX - touchstartX )/2 ){ + wantDelete = false; + }else{ + wantDelete = true; + } + + }, 10 )); + + moved = moved || ((currentX - touchstartX >= 3 || currentY - touchstartY >= 3) ? true : false); + if( !wantDelete ) { + setTimeout( function() { + $target && $target.removeClass( 'ui-historylist-ontap' ); + }, 150 ); // 延时长一点,这样不会因为class改变太快,导致闪 + return; + } + + movedPercentage = (currentX - touchstartX)/me.$wrap.width(); + + // TODO 有些设备上有点卡,需要优化 + $target.addClass( 'ui-historylist-itemmoving' ); + $target.removeClass( 'ui-historylist-ontap' ); + $target.css( '-webkit-transform', 'translate3d(' + (currentX - touchstartX) + 'px, 0, 0)' ); + $target.css( 'opacity', 1 - movedPercentage ); + + ev.preventDefault(); + ev.stopPropagation(); + } ); + + me.$wrap.on( 'touchend' + me.eventNs + ' touchcancel' + me.eventNs, function(ev) { + if( !$target) { + return; + } + + clearTimeout(timeout); + timeout = undefined; + + itemId = $target.parent().attr( 'data-id' ); + endTimestamp = ev.timeStamp; + velocity = (currentX - touchstartX) / (endTimestamp - startTimestamp); + movedDistance = Math.abs( currentX - touchstartX ); + + $target.removeClass( 'ui-historylist-ontap' ); + $target.removeClass( 'ui-historylist-itemmoving' ); + + // 当移动的距离小于 1/3 时,速度快则删除,速度慢则还原 + if( ((movedDistance < me.$wrap.width()/3 && Math.abs( velocity ) > 0.1) && wantDelete) || + (movedDistance >= me.$wrap.width()/3 && wantDelete) ) { + me.removeItem( itemId, $target ); + } else { + $target.css( 'width', 'auto' ); + $target.css( '-webkit-transform', 'translate3d(0, 0, 0)' ); + $target.css( 'opacity', 1 ); + + // 移动小于3个像素时,则认为是点击,派发 itemTouch 事件 + // 如果移出3像素外,再移到3像素内,认为不是点击 + !moved && movedDistance < 3 && me._filterItemsById( itemId, function( _item ) { + me.trigger( 'itemTouch', {'item': _item.value} ); + }); + } + + $target = null; + } ); + }, + + /** + * 显示Historylist + * @method show + * @return {self} 返回本身。 + */ + show: function() { + var me = this; + + // 没有历史记录时,不显示 + if( me.items.length === 0 ) { + return; + } + + if( me.sync === false ) { + me.$wrap.html( '' ); + me.addItems( me.syncitems ); + me.sync = true; + } + me.$el.show(); + me.isShow = true; + + return me; + }, + + /** + * 隐藏Historylist + * @method hide + * @return {self} 返回本身。 + */ + hide: function() { + var me = this; + + me.$el.hide(); + me.isShow = false; + + return me; + }, + + _getItemId: function() { + var me = this; + + me._itemId === undefined ? (me._itemId = 1) : ++me._itemId; + + return '__dd__' + me._itemId; + }, + + _getFormatItem: function( item ) { + var me = this; + + if( Object.prototype.toString.call( item ) === '[object String]' ) { + return { + 'context': item, + 'value': item, + 'id': me._getItemId() + } + } else { + return { + 'context': item.context || item.value, + 'value': item.value || item.context, + 'id': me._getItemId() + } + } + }, + + /** + * 添加一条历史记录 + * @method addBtns + * @param {String|Object} item 历史记录,可以是字符串,也可以是标准格式的对象(包含context和value) + * @return {self} 返回本身 + */ + addItem: function( item ) { + var me = this, + item = me._getFormatItem( item ); + + // 检查me.items中是否已存在该项 + me.items.forEach( function( _item, index ) { + if ( _item.value === item.value ) { + me.items.splice( index, 1); + $( me.$wrap.children()[index] ).remove(); + + return; + } + } ); + + me.$wrap.children().length === 0 ? + me.$wrap.append( me.tpl2html( 'item', item ) ) : + $( me.tpl2html( 'item', item ) ).insertBefore( me.$wrap.children()[0] ); + + me.items.unshift( item ); + + return me; + }, + + /** + * 添加多条历史记录 + * @method addBtns + * @param {Array} item 历史记录 + * @return {self} 返回本身 + */ + addItems: function( items ) { + var me = this; + + items.forEach( function( item ) { + me.addItem( item ); + } ); + + return me; + }, + + /** + * 更新数据,重新渲染列表 + * @method update + * @param {Array} item 新的历史记录 + * @return {self} 返回本身 + */ + update: function( items ) { + var me = this; + + + if( me.isShow ) { + me.$wrap.html( '' ); + me.addItems( items ); + me.sync = true; + } else { + me.syncitems = items; + me.sync = false; + } + + return me; + }, + + removeItem: function( itemId, $itemTarget ) { + var me = this, + distance, + transform, + x; + + // 根据当前位移的正负,判断是从右滑出还是从左滑出 + transform = $itemTarget.css( '-webkit-transform'); + x = /translate3d\((.*?),.*/.test(transform) ? RegExp.$1: 0; + distance = parseInt( x, 10) >= 0 ? $itemTarget.width() : -$itemTarget.width(); + $itemTarget.css( '-webkit-transform', 'translate3d(' + distance + 'px, 0, 0)' ); + + // TODO 根据位移改变透明度,感觉不出来,没必要加 + + $itemTarget.on( 'transitionEnd' + me.eventNs + ' webkitTransitionEnd' + me.eventNs, function() { + $itemTarget.parent().remove(); + + me._filterItemsById( itemId, function( _item, index ) { + me.items.splice( index, 1); + me.trigger( 'itemDelete', {'item': _item.value} ); + }); + } ); + + }, + + /** + * 清空历史记录 + * @method clear + * @return {self} 返回本身 + */ + clear: function() { + var me = this; + + me.$wrap.html( '' ); + me.items = []; + me.sync = true; + me.hide(); + me.trigger( 'clear' ); + + return me; + }, + + /** + * 禁用删除功能 + * @method disableDelete + * @return {self} 返回本身 + */ + disableDelete: function() { + var me = this; + + me._options.deleteSupport = false; + me.$clear.hide(); + + return me; + }, + + /** + * 启用删除功能 + * @method enableDelete + * @return {self} 返回本身 + */ + enableDelete: function() { + var me = this; + + me._options.deleteSupport = true; + me.$clear.show(); + + return me; + }, + + /** + * 销毁组件 + * @method destroy + */ + destroy: function() { + var me = this; + + me.$wrap.off( me.eventNs ); + me.$clear.off( me.eventNs ); + + me.$wrap.remove(); + me.$clear.remove(); + + return me.$super( 'destroy' ); + } + + /** + * @event ready + * @param {Event} e gmu.Event对象 + * @description 当组件初始化完后触发。 + */ + + /** + * @event itemTouch + * @param {Event} e gmu.Event对象 + * @param {String} item 被点击的记录的value + * @description 点击某条历史记录时触发 + */ + + /** + * @event itemDelete + * @param {Event} e gmu.Event对象 + * @param {String} item 被删除的记录的value + * @description 删除某条历史记录时触发 + */ + + /** + * @event clear + * @param {Event} e gmu.Event对象 + * @description 清除历史记录时触发 + */ + + /** + * @event destroy + * @param {Event} e gmu.Event对象 + * @description 组件在销毁的时候触发 + */ + } ); +})( gmu, gmu.$ ); + + +/** + * @file 导航栏组件 + * @import core/widget.js, extend/highlight.js + * @module GMU + */ +(function( gmu, $, undefined ) { + + /** + * 导航栏组件 + * + * @class Navigator + * @constructor Html部分 + * ```html + * + * ``` + * + * javascript部分 + * ```javascript + * + * ``` + * @param {dom | zepto | selector} [el] 用来初始化导航栏的元素 + * @param {Object} [options] 组件配置项。具体参数请查看[Options](#GMU:Navigator:options) + * @grammar $( el ).navigator( options ) => zepto + * @grammar new gmu.Navigator( el, options ) => instance + */ + gmu.define( 'Navigator', { + options: { + + /** + * @property {Array} [content=null] 菜单数组 + * @namespace options + */ + content: null, + + /** + * @property {String} [event='click'] 交互事件名 + * @namespace options + */ + event: 'click' + }, + + template: { + list: '
          ', + item: '
        • href="<%= href %>"<% } %>>' + + '<%= text %>
        • ' + }, + + _create: function() { + var me = this, + opts = me._options, + $el = me.getEl(), + $list = $el.find( 'ul' ).first(), + name = 'ui-' + me.widgetName, + renderer, + html; + + // 如果没有包含ul节点,则说明通过指定content来create + // 建议把create模式给拆出去。很多时候都是先写好在dom中了。 + if ( !$list.length && opts.content ) { + $list = $( me.tpl2html( 'list' ) ); + renderer = me.tpl2html( 'item' ); + + html = ''; + opts.content.forEach(function( item ) { + + // 如果不提供默认值,然后同时某些key没有传值,parseTpl会报错 + item = $.extend( { + href: '', + text: '' + }, typeof item === 'string' ? { + text: item + } : item ); + + html += renderer( item ); + }); + + $list.append( html ).appendTo( $el ); + } else { + + // 处理直接通过ul初始化的情况 + if ( $el.is( 'ul, ol' ) ) { + $list = $el.wrap( '
          ' ); + $el = $el.parent(); + } + + if ( opts.index === undefined ) { + + // 如果opts中没有指定index, 则尝试从dom中查看是否有比较为ui-state-active的 + opts.index = $list.find( '.ui-state-active' ).index(); + + // 没找到还是赋值为0 + ~opts.index || (opts.index = 0); + } + } + + me.$list = $list.addClass( name + '-list' ); + me.trigger( 'done.dom', $el.addClass( name ), opts ); + + // bind Events + $list.highlight( 'ui-state-hover', 'li' ); + $list.on( opts.event + me.eventNs, + 'li:not(.ui-state-disable)>a', function( e ) { + me._switchTo( $( this ).parent().index(), e ); + } ); + + me.index = -1; + me.switchTo( opts.index ); + }, + + _switchTo: function( to, e ) { + if ( to === this.index ) { + return; + } + + var me = this, + list = me.$list.children(), + evt = gmu.Event( 'beforeselect', e ), + cur; + + me.trigger( evt, list.get( to ) ); + + if ( evt.isDefaultPrevented() ) { + return; + } + + cur = list.removeClass( 'ui-state-active' ) + .eq( to ) + .addClass( 'ui-state-active' ); + + me.index = to; + return me.trigger( 'select', to, cur[ 0 ] ); + }, + + /** + * 切换到导航栏的某一项 + * @param {Number} to 序号 + * @method switchTo + */ + switchTo: function( to ) { + return this._switchTo( ~~to ); + }, + + /** + * 取消选择 + * @method unselect + */ + unselect: function() { + this.index = -1; + this.$list.children().removeClass( 'ui-state-active' ); + }, + + /** + * 获取当前选中的序号 + * @method getIndex + */ + getIndex: function() { + return this.index; + } + + /** + * @event ready + * @param {Event} e gmu.Event对象 + * @description 当组件初始化完后触发。 + */ + + /** + * @event beforeselect + * @param {Event} e gmu.Event对象 + * @param {Element} 目标元素 + * @description 当选择的序号发生切换前触发 + */ + + /** + * @event select + * @param {Event} e gmu.Event对象 + * @param {Event} 当前选择的序号 + * @param {Element} 上一次选择的元素 + * @description 当选择的序号发生切换后触发 + */ + + /** + * @event destroy + * @param {Event} e gmu.Event对象 + * @description 组件在销毁的时候触发 + */ + } ); +})( gmu, gmu.$ ); +/*! + * iScroll v4.2.2 ~ Copyright (c) 2012 Matteo Spinelli, http://cubiq.org + * Released under MIT license, http://cubiq.org/license + */ +(function(window, doc){ + var m = Math,_bindArr = [], + dummyStyle = doc.createElement('div').style, + vendor = (function () { + var vendors = 'webkitT,MozT,msT,OT,t'.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), + isTouchPad = (/hp-tablet/gi).test(navigator.appVersion), + + has3d = prefixStyle('perspective') in dummyStyle, + hasTouch = 'ontouchstart' in window && !isTouchPad, + hasTransform = !!vendor, + 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]; + + that.translateZ = translateZ; + // 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, + + + // Events + onRefresh: null, + onBeforeScrollStart: function (e) { e.preventDefault(); }, + onScrollStart: null, + onBeforeScrollMove: null, + onScrollMove: null, + onBeforeScrollEnd: null, + onScrollEnd: null, + onTouchEnd: null, + onDestroy: 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.useTransition = hasTransitionEnd && that.options.useTransition; + + + + // 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'; + + + + that.refresh(); + + that._bind(RESIZE_EV, window); + that._bind(START_EV); + + + 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, + isStopScrollAction:false, + + 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 TRNEND_EV: that._transitionEnd(e); break; + } + }, + + _checkDOMChanges: function () { + if (this.moved || this.animating || + (this.scrollerW == this.scroller.offsetWidth * this.scale && this.scrollerH == this.scroller.offsetHeight * this.scale)) return; + + this.refresh(); + }, + + _resize: function () { + var that = this; + setTimeout(function () { that.refresh(); }, isAndroid ? 200 : 0); + }, + + _pos: function (x, y) { + 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; + + }, + + + + _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._transitionTime(0); + + that.moved = false; + that.animating = false; + + that.distX = 0; + that.distY = 0; + that.absDistX = 0; + that.absDistY = 0; + that.dirX = 0; + that.dirY = 0; + that.isStopScrollAction = false; + + 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[4]; + y = +matrix[5]; + } else { + x = +getComputedStyle(that.scroller, null).left.replace(/[^0-9-]/g, ''); + y = +getComputedStyle(that.scroller, null).top.replace(/[^0-9-]/g, ''); + } + + if (m.round(x) != m.round(that.x) || m.round(y) != m.round(that.y)) { + that.isStopScrollAction = true; + 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.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, + + timestamp = e.timeStamp || Date.now(); + + if (that.options.onBeforeScrollMove) that.options.onBeforeScrollMove.call(that, e); + + 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; + + // internal for header scroll + + that._beforePos ? that._beforePos(newY, deltaY) && that._pos(newX, newY) : 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, + newDuration; + + + 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.moved) { + + if (hasTouch && this.options.handleClick && !that.isStopScrollAction) { + 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); + } + }, 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); + + + + that.scrollTo(m.round(newPosX), m.round(newPosY), newDuration); + + 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._afterPos) that._afterPos(); + } + + return; + } + + that.scrollTo(resetX, resetY, time || 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; + + }, + + _momentum: function (dist, time, maxDistUpper, maxDistLower, size) { + var deceleration = 0.0006, + speed = m.abs(dist) * (this.options.speedScale||1) / 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 }; + }, + + + + _bind: function (type, el, bubble) { + _bindArr.concat([el || this.scroller, type, this]); + (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 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.useTransition) that._unbind(TRNEND_EV); + + if (that.options.checkDOMChanges) clearInterval(that.checkDOMTime); + + if (that.options.onDestroy) that.options.onDestroy.call(that); + + //清除所有绑定的事件 + for (var i = 0, l = _bindArr.length; i < l;) { + _bindArr[i].removeEventListener(_bindArr[i + 1], _bindArr[i + 2]); + _bindArr[i] = null; + i = i + 3 + } + _bindArr = []; + + //干掉外边的容器内容 + /*var div = doc.createElement('div'); + div.appendChild(this.wrapper); + div.innerHTML = ''; + that.wrapper = that.scroller = div = null;*/ + }, + + refresh: function () { + var that = this, + offset; + + + + 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); + + + offset = that._offset(that.wrapper); + that.wrapperOffsetLeft = -offset.left; + that.wrapperOffsetTop = -offset.top; + + + 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); + + + 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; + }, + + isReady: function () { + return !this.moved && !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; + + // 给$.fn上挂iScroll方法 + (function( $, ns, undefined ){ + if(!$)return; + + var _iScroll = ns.iScroll, + + slice = [].slice, + + record = (function() { + var data = {}, + id = 0, + ikey = '_sid'; // internal key. + + return function( obj, val ) { + var key = obj[ ikey ] || (obj[ ikey ] = ++id); + + val !== undefined && (data[ key ] = val); + val === null && delete data[ key ]; + + return data[ key ]; + }; + })(), + + iScroll; + + ns.iScroll = iScroll = function( el, options ){ + var args = [].slice.call( arguments, 0 ), + ins = new _iScroll( el, options ); + + record( el, ins ); + return ins; + }; + iScroll.prototype = _iScroll.prototype; + + + $.fn.iScroll = function( opts ) { + var args = slice.call( arguments, 1 ), + method = typeof opts === 'string' && opts, + ret, + obj; + + $.each( this, function( i, el ) { + + // 从缓存中取,没有则创建一个 + obj = record( el ) || iScroll( el, $.isPlainObject( opts ) ? + opts : undefined ); + + // 取实例 + if ( method === 'this' ) { + ret = obj; + return false; // 断开each循环 + } else if ( method ) { + + // 当取的方法不存在时,抛出错误信息 + if ( !$.isFunction( obj[ method ] ) ) { + throw new Error( 'iScroll没有此方法:' + method ); + } + + ret = obj[ method ].apply( obj, args ); + + // 断定它是getter性质的方法,所以需要断开each循环,把结果返回 + if ( ret !== undefined && ret !== obj ) { + return false; + } + + // ret为obj时为无效值,为了不影响后面的返回 + ret = undefined; + } + } ); + + return ret !== undefined ? ret : this; + }; + + })( window.Zepto || null, window ); +})(window, document); +/** + * Change list + * 修改记录 + * + * 1. 2012-08-14 解决滑动中按住停止滚动,松开后被点元素触发点击事件。 + * + * 具体修改: + * a. 202行 添加isStopScrollAction: false 给iScroll的原型上添加变量 + * b. 365行 _start方法里面添加that.isStopScrollAction = false; 默认让这个值为false + * c. 390行 if (x != that.x || y != that.y)条件语句里面 添加了 that.isStopScrollAction = true; 当目标值与实际值不一致,说明还在滚动动画中 + * d. 554行 that.isStopScrollAction || (that.doubleTapTimer = setTimeout(function () { + * ...... + * ...... + * }, that.options.zoom ? 250 : 0)); + * 如果isStopScrollAction为true就不派送click事件 + * + * + * 2. 2012-08-14 给options里面添加speedScale属性,提供外部控制冲量滚动速度 + * + * 具体修改 + * a. 108行 添加speedScale: 1, 给options里面添加speedScale属性,默认为1 + * b. 798行 speed = m.abs(dist) * this.options.speedScale / time, 在原来速度的基础上*speedScale来改变速度 + * + * 3. 2012-08-21 修改部分代码,给iscroll_plugin墙用的 + * + * 具体修改 + * a. 517行 在_pos之前,调用_beforePos,如果里面不返回true, 将不会调用_pos + * // internal for header scroll + * if (that._beforePos) + * that._beforePos(newY, deltaY) && that._pos(newX, newY); + * else + * that._pos(newX, newY); + * + * b. 680行 在滚动结束后调用 _afterPos. + * // internal for header scroll + * if (that._afterPos) that._afterPos(); + * + * c. 106行构造器里面添加以下代码 + * // add var to this for header scroll + * that.translateZ = translateZ; + * + * 为处理溢出 + * _bind 方法 + * destroy 方法 + * 最开头的 _bindArr = [] + * + */ +/** + * @file GMU定制版iscroll,基于[iScroll 4.2.2](http://cubiq.org/iscroll-4), 去除zoom, pc兼容,snap, scrollbar等功能。同时把iscroll扩展到了Zepto的原型中。 + * @name iScroll + * @import zepto.js + * @desc GMU定制版iscroll,基于{@link[http://cubiq.org/iscroll-4] iScroll 4.2.2}, 去除zoom, pc兼容,snap, scrollbar等功能。同时把iscroll扩展到了***Zepto***的原型中。 + */ + +/** + * @name iScroll + * @grammar new iScroll(el,[options]) ⇒ self + * @grammar $('selecotr').iScroll([options]) ⇒ zepto实例 + * @desc 将iScroll加入到了***$.fn***中,方便用Zepto的方式调用iScroll。 + * **el** + * - ***el {String/ElementNode}*** iscroll容器节点 + * + * **Options** + * - ***hScroll*** {Boolean}: (可选, 默认: true)横向是否可以滚动 + * - ***vScroll*** {Boolean}: (可选, 默认: true)竖向是否可以滚动 + * - ***momentum*** {Boolean}: (可选, 默认: true)是否带有滚动效果 + * - ***checkDOMChanges*** {Boolean, 默认: false}: (可选)每个500毫秒判断一下滚动区域的容器是否有新追加的内容,如果有就调用refresh重新渲染一次 + * - ***useTransition*** {Boolean, 默认: false}: (可选)是否使用css3来来实现动画,默认是false,建议开启 + * - ***topOffset*** {Number}: (可选, 默认: 0)可滚动区域头部缩紧多少高度,默认是0, ***主要用于头部下拉加载更多时,收起头部的提示按钮*** + * @example + * $('div').iscroll().find('selector').atrr({'name':'aaa'}) //保持链式调用 + * $('div').iScroll('refresh');//调用iScroll的方法 + * $('div').iScroll('scrollTo', 0, 0, 200);//调用iScroll的方法, 200ms内滚动到顶部 + */ + + +/** + * @name destroy + * @desc 销毁iScroll实例,在原iScroll的destroy的基础上对创建的dom元素进行了销毁 + * @grammar destroy() ⇒ undefined + */ + +/** + * @name refresh + * @desc 更新iScroll实例,在滚动的内容增减时,或者可滚动区域发生变化时需要调用***refresh***方法来纠正。 + * @grammar refresh() ⇒ undefined + */ + +/** + * @name scrollTo + * @desc 使iScroll实例,在指定时间内滚动到指定的位置, 如果relative为true, 说明x, y的值是相对与当前位置的。 + * @grammar scrollTo(x, y, time, relative) ⇒ undefined + */ +/** + * @name scrollToElement + * @desc 滚动到指定内部元素 + * @grammar scrollToElement(element, time) ⇒ undefined + * @grammar scrollToElement(selector, time) ⇒ undefined + */ +/** + * @name scrollToPage + * @desc 跟scrollTo很像,这里传入的是百分比。 + * @grammar scrollToPage(pageX, pageY, time) ⇒ undefined + */ +/** + * @name disable + * @desc 禁用iScroll + * @grammar disable() ⇒ undefined + */ +/** + * @name enable + * @desc 启用iScroll + * @grammar enable() ⇒ undefined + */ +/** + * @name stop + * @desc 定制iscroll滚动 + * @grammar stop() ⇒ undefined + */ + + +/** + * @file Navigator的可滚插件, 采用iScroll来实现。 + * @module GMU + * @import widget/navigator/navigator.js, extend/iscroll.js, extend/event.ortchange.js + */ +(function( gmu, $, undefined ) { + + /** + * @property {Object} [iScroll={}] iScroll配置 + * @namespace options + * @for Navigator + * @uses Navigator.scrollable + */ + gmu.Navigator.options.iScroll = { + hScroll: true, + vScroll: false, + hScrollbar: false, + vScrollbar: false + }; + + /** + * Navigator的可滚插件, 采用iScroll来实现。 + * + * @class scrollable + * @namespace Navigator + * @pluginfor Navigator + */ + gmu.Navigator.register( 'scrollable', { + + _init: function() { + var me = this, + opts = me._options; + + me.on( 'done.dom', function() { + me.$list.wrap( '
          ' ); + + me.trigger( 'init.iScroll' ); + me.$el.iScroll( $.extend( {}, opts.iScroll ) ); + } ); + + $( window ).on( 'ortchange' + me.eventNs, + $.proxy( me.refresh, me ) ); + + me.on('destroy', function(){ + me.$el.iScroll( 'destroy' ); + $( window ).off( 'ortchange' + me.eventNs ); + } ); + }, + + /** + * 刷新iscroll + * @method refresh + * @for Navigator + * @uses Navigator.scrollable + */ + refresh: function() { + this.trigger( 'refresh.iScroll' ).$el.iScroll( 'refresh' ); + } + + /** + * @event refresh.iScroll + * @param {Event} e gmu.Event对象 + * @description iscroll刷新前触发 + */ + } ); +})( gmu, gmu.$ ); +/** + * @file 平均分配按钮,根据传入的visibleCount, 来平均分配宽度, 此插件主要用来加强 + * scrollable, 如果内容不可滚,用纯样式就能实现这块。 + * @import widget/navigator/navigator.js, widget/navigator/$scrollable.js + */ +(function( gmu, $, undefined ) { + gmu.Navigator.options.visibleCount = 4; + + /** + * 平均分配按钮,根据传入的visibleCount, 来平均分配宽度, 此插件主要用来加强 + * scrollable, 如果内容不可滚,用纯样式就能实现这块。 + * @class visibleCount + * @namespace Navigator + * @pluginfor Navigator + */ + gmu.Navigator.option( 'visibleCount', '*', function() { + var me = this, + opts = me._options, + counts = $.type( opts.visibleCount ) === 'number' ? { + portrait: opts.visibleCount, + landscape: Math.floor( opts.visibleCount * 3 / 2 ) + } : opts.visibleCount; + + me.on( 'init.iScroll refresh.iScroll', arrage ); + + function arrage( e ) { + + // todo 采用一种更精准的方法来获取横竖屏 + var ort = window.innerWidth > window.innerHeight ? + 'landscape' : 'portrait', + count = counts[ ort ], + $el = me.$el; + + //TODO 横竖屏切换时,不能自动调整宽度 + me.$list.children().width( $el.width() / count ); + me.$list.width($el.width() / count * me.$list.children().length); + } + } ); +})( gmu, gmu.$ ); +/** + * @file 当滚动到边缘的时候,自动把下一个滚出来 + * @import widget/navigator/navigator.js, widget/navigator/$scrollable.js + */ +(function( gmu, $, undefined ) { + gmu.Navigator.options.isScrollToNext = true; + + /** + * 当滚动到边缘的时候,自动把下一个滚出来 + * @class isScrollToNext + * @namespace Navigator + * @pluginfor Navigator + */ + gmu.Navigator.option( 'isScrollToNext', true, function() { + var me = this, + prevIndex; + + me.on( 'select', function( e, to, el ) { + + // 第一调用的时候没有prevIndex, 固根据this.index来控制方向。 + if ( prevIndex === undefined ) { + prevIndex = me.index ? 0 : 1; + } + + var dir = to > prevIndex, + + // 如果是想左则找prev否则找next + target = $( el )[ dir ? 'next' : 'prev' ](), + + // 如果没有相邻的,自己的位置也需要检测。存在这种情况 + // 被点击的按钮,只显示了一半 + offset = target.offset() || $( el ).offset(), + within = me.$el.offset(), + listOffset; + + if ( dir ? offset.left + offset.width > within.left + + within.width : offset.left < within.left ) { + listOffset = me.$list.offset(); + + me.$el.iScroll( 'scrollTo', dir ? within.width - + offset.left + listOffset.left - offset.width : + listOffset.left - offset.left, 0, 400 ); + } + + prevIndex = to; + } ); + } ); +})( gmu, gmu.$ ); +/** + * @file panel组件 + * @import extend/touch.js, core/widget.js, extend/throttle.js, extend/event.scrollStop.js, extend/event.ortchange.js + * @module GMU + */ +(function( gmu, $, undefined ) { + + var cssPrefix = $.fx.cssPrefix, + transitionEnd = $.fx.transitionEnd; + /** + * panel组件 + * + * @class Panel + * @constructor Html部分 + * ```html + *
          + *
          panel内容
          + *
          + * ``` + * + * javascript部分 + * ```javascript + * $('.panel').panel({ + * contentWrap: $('.cont') + * }); + * ``` + * @param {dom | zepto | selector} [el] 用来初始化Panel的元素 + * @param {Object} [options] 组件配置项。具体参数请查看[Options](#GMU:Panel:options) + * @grammar $( el ).panel( options ) => zepto + * @grammar new gmu.Panel( el, options ) => instance + */ + + gmu.define( 'Panel', { + options: { + + /** + * @property {Dom | Zepto | selector} [contentWrap=''] 主体内容dom,若不传,则默认为panel的next节点 + * @namespace options + */ + contentWrap: '', + + /** + * @property {String} [scrollMode='follow'] Panel滑动方式,follow表示跟随页面滑动,hide表示页面滑动时panel消失, fix表示panel固定在页面中 + * @namespace options + */ + scrollMode: 'follow', + + /** + * @property {String} [display='push'] 可选值:('overlay' | 'reveal' | 'push') Panel出现模式,overlay表示浮层reveal表示在content下边展示,push表示panel将content推出 + * @namespace options + */ + display: 'push', + + /** + * @property {String} [position='right'] 可选值:('left' | 'right') 在右边或左边 + * @namespace options + */ + position: 'right', + + /** + * @property {Boolean} [dismissible=true] (render模式下必填)是否在内容区域点击后,panel消失 + * @namespace options + */ + dismissible: true, + + /** + * @property {Boolean} [swipeClose=true] 在panel上滑动,panel是否关闭 + * @namespace options + */ + swipeClose: true + }, + + _init: function () { + var me = this, + opts = me._options; + + me.on( 'ready', function(){ + me.displayFn = me._setDisplay(); + me.$contentWrap.addClass('ui-panel-animate'); + me.$el.on(transitionEnd, $.proxy(me._eventHandler, me)).hide(); //初始状态隐藏panel + opts.dismissible && me.$panelMask.hide().on('click', $.proxy(me._eventHandler, me)); //绑定mask上的关闭事件 + opts.scrollMode !== 'follow' && $(window).on('scrollStop', $.proxy(me._eventHandler, me)); + $(window).on('ortchange', $.proxy(me._eventHandler, me)); + } ); + }, + + _create: function () { + if(this._options.setup){ + var me = this, + opts = me._options, + $el = me.$el.addClass('ui-panel ui-panel-'+ opts.position); + + me.panelWidth = $el.width() || 0; + me.$contentWrap = $(opts.contentWrap || $el.next()); + opts.dismissible && ( me.$panelMask = $('
          ').width(document.body.clientWidth - $el.width()).appendTo('body') || null); + }else{ + throw new Error('panel组件不支持create模式,请使用setup模式'); + } + }, + + /** + * 生成display模式函数 + * */ + _setDisplay: function () { + var me = this, + $panel = me.$el, + $contentWrap = me.$contentWrap, + transform = cssPrefix + 'transform', + posData = me._transDisplayToPos(), + obj = {}, panelPos, contPos; + + $.each(['push', 'overlay', 'reveal'], function (i,display) { + obj[display] = function (isOpen, pos, isClear) { //isOpen:是打开还是关闭操作,pos:从右或从左打开关闭,isClear:是否是初始化操作 + panelPos = posData[display].panel, contPos = posData[display].cont; + $panel.css(transform, 'translate3d(' + me._transDirectionToPos(pos, panelPos[isOpen]) + 'px,0,0)'); + if (!isClear) { + $contentWrap.css(transform, 'translate3d(' + me._transDirectionToPos(pos, contPos[isOpen]) + 'px,0,0)'); + me.maskTimer = setTimeout(function () { //防止外界注册tap穿透,故做了延迟 + me.$panelMask && me.$panelMask.css(pos, $panel.width()).toggle(isOpen); + }, 400); //改变mask left/right值 + } + return me; + } + }); + return obj; + }, + /** + * 初始化panel位置,每次打开之前由于位置可能不同,所以均需重置 + * */ + _initPanelPos: function (dis, pos) { + this.displayFn[dis](0, pos, true); + this.$el.get(0).clientLeft; //触发页面reflow,使得ui-panel-animate样式不生效 + return this; + }, + /** + * 将位置(左或右)转化为数值 + * */ + _transDirectionToPos: function (pos, val) { + return pos === 'left' ? val : -val; + }, + /** + * 将打开模式(push,overlay,reveal)转化为数值 + * */ + _transDisplayToPos: function () { + var me = this, + panelWidth = me.panelWidth; + return { + push: { + panel: [-panelWidth, 0], //[from, to] for panel + cont: [0, panelWidth] //[from, to] for contentWrap + }, + overlay: { + panel: [-panelWidth, 0], + cont: [0, 0] + }, + reveal: { + panel: [0, 0], + cont: [0, panelWidth] + } + } + }, + /** + * 设置显示或关闭,关闭时的操作,包括模式、方向与需与打开时相同 + * */ + _setShow: function (isOpen, dis, pos) { + var me = this, + opts = me._options, + eventName = isOpen ? 'open' : 'close', + beforeEvent = $.Event('before' + eventName), + changed = isOpen !== me.state(), + _eventBinder = isOpen ? 'on' : 'off', + _eventHandler = isOpen ? $.proxy(me._eventHandler, me) : me._eventHandler, + _dis = dis || opts.display, + _pos = pos || opts.position; + + me.trigger(beforeEvent, [dis, pos]); + if (beforeEvent.isDefaultPrevented()) return me; + if (changed) { + me._dealState(isOpen, _dis, _pos); //关闭或显示时,重置状态 + me.displayFn[_dis](me.isOpen = Number(isOpen), _pos); //根据模式和打开方向,操作panel + opts.swipeClose && me.$el[_eventBinder]($.camelCase('swipe-' + _pos), _eventHandler); //滑动panel关闭 + opts.display = _dis, opts.position = _pos; + } + return me; + }, + /** + * 打开或关闭前的状态重置操作,包括样式,位置等 + * */ + _dealState: function (isOpen, dis, pos) { + var me = this, + opts = me._options, + $panel = me.$el, + $contentWrap = me.$contentWrap, + addCls = 'ui-panel-' + dis + ' ui-panel-' + pos, + removeCls = 'ui-panel-' + opts.display + ' ui-panel-' + opts.position + ' ui-panel-animate'; + + if (isOpen) { + $panel.removeClass(removeCls).addClass(addCls).show(); + opts.scrollMode === 'fix' && $panel.css('top', $(window).scrollTop()); //fix模式下 + me._initPanelPos(dis, pos); //panel及contentWrap位置初始化 + if (dis === 'reveal') { + $contentWrap.addClass('ui-panel-contentWrap').on(transitionEnd, $.proxy(me._eventHandler, me)); //reveal模式下panel不触发transitionEnd; + } else { + $contentWrap.removeClass('ui-panel-contentWrap').off(transitionEnd, $.proxy(me._eventHandler, me)); + $panel.addClass('ui-panel-animate'); + } + me.$panelMask && me.$panelMask.css({ //panel mask状态初始化 + 'left': 'auto', + 'right': 'auto', + 'height': document.body.clientHeight + }); + } + return me; + }, + + _eventHandler: function (e) { + var me = this, + opts = me._options, + scrollMode = opts.scrollMode, + eventName = me.state() ? 'open' : 'close'; + + switch (e.type) { + case 'click': + case 'swipeLeft': + case 'swipeRight': + me.close(); + break; + case 'scrollStop': + scrollMode === 'fix' ? me.$el.css('top', $(window).scrollTop()) : me.close(); + break; + case transitionEnd: + me.trigger(eventName, [opts.display, opts.position]); + break; + case 'ortchange': //增加转屏时对mask的处理 + me.$panelMask && me.$panelMask.css('height', document.body.clientHeight); + scrollMode === 'fix' && me.$el.css('top', $(window).scrollTop()); //转并重设top值 + break; + } + }, + + /** + * 打开panel + * @method open + * @param {String} [display] 可选值:('overlay' | 'reveal' | 'push'),默认为初始化时设置的值,Panel出现模式,overlay表示浮层reveal表示在content下边展示,push表示panel将content推出 + * @param {String} position 可选值:('left' | 'right'),默认为初始化时设置的值,在右边或左边 + * @chainable + * @return {self} 返回本身。 + */ + open: function (display, position) { + return this._setShow(true, display, position); + }, + + /** + * 关闭panel + * @method close + * @chainable + * @return {self} 返回本身。 + */ + close: function () { + return this._setShow(false); + }, + + /** + * 切换panel的打开或关闭状态 + * @method toggle + * @param {String} [display] 可选值:('overlay' | 'reveal' | 'push'),默认为初始化时设置的值,Panel出现模式,overlay表示浮层reveal表示在content下边展示,push表示panel将content推出 + * @param {String} position 可选值:('left' | 'right'),默认为初始化时设置的值,在右边或左边 + * @chainable + * @return {self} 返回本身。 + */ + toggle: function (display, position) { + return this[this.isOpen ? 'close' : 'open'](display, position); + }, + + /** + * 获取当前panel状态,打开为true,关闭为false + * @method state + * @chainable + * @return {self} 返回本身。 + */ + state: function () { + return !!this.isOpen; + }, + + /** + * 销毁组件 + * @method destroy + */ + destroy:function () { + this.$panelMask && this.$panelMask.off().remove(); + this.maskTimer && clearTimeout(this.maskTimer); + this.$contentWrap.removeClass('ui-panel-animate'); + $(window).off('scrollStop', this._eventHandler); + $(window).off('ortchange', this._eventHandler); + return this.$super('destroy'); + } + + /** + * @event ready + * @param {Event} e gmu.Event对象 + * @description 当组件初始化完后触发。 + */ + + /** + * @event beforeopen + * @param {Event} e gmu.Event对象 + * @description panel打开前触发,可以通过e.preventDefault()来阻止 + */ + + /** + * @event open + * @param {Event} e gmu.Event对象 + * @description panel打开后触发 + */ + + /** + * @event beforeclose + * @param {Event} e gmu.Event对象 + * @description panel关闭前触发,可以通过e.preventDefault()来阻止 + */ + + /** + * @event close + * @param {Event} e gmu.Event对象 + * @description panel关闭后触发 + */ + + /** + * @event destroy + * @param {Event} e gmu.Event对象 + * @description 组件在销毁的时候触发 + */ + }); + +})( gmu, gmu.$ ); + +/** + * @file 是否现实剪头 + * @import widget/popover/popover.js + */ +(function( gmu ) { + var Popover = gmu.Popover; + + Popover.template.arrow = ''; + + /** + * @property {Boolean} [arrow=true] 是否显示剪头 + * @namespace options + * @for Popover + * @uses Popover.arrow + */ + Popover.options.arrow = true; // 默认开启arrow + + /** + * 扩展Popover显示剪头功能。当此文件引入后,Popover实例将自动开启显示剪头。 + * 剪头的位置会根据不同的placement显示在不同的位置。 + * @class arrow + * @namespace Popover + * @pluginfor Popover + */ + Popover.option( 'arrow', true, function() { + var me = this, + opts = me._options; + + // 在没有传入offset的时候,默认有arrow就会多10px偏移 + opts.offset = opts.offset || function( coord, placement ) { + placement = placement.split( '_' )[ 0 ]; + return { + left: (placement === 'left' ? -1 : + placement === 'right' ? 1 : 0) * 15, + top: (placement === 'top' ? -1 : + placement === 'bottom' ? 1 : 0) * 15 + }; + }; + + me.on( 'done.dom', function( e, $root ) { + $root.append( me.tpl2html( 'arrow' ) ).addClass( 'ui-pos-default' ); + } ); + + me.on( 'after.placement', function( e, coord, info ) { + var root = this.$root[ 0 ], + cls = root.className, + placement = info.placement, + align = info.align || ''; + + root.className = cls.replace( /(?:\s|^)ui-pos-[^\s$]+/g, '' ) + + ' ui-pos-' + placement + (align ? '-' + align : ''); + } ); + } ); +})( gmu ); +/** + * @file 碰撞检测,根据指定的容器,做最优位置显示 + * @import widget/popover/popover.js + */ +(function( gmu, $ ) { + + /** + * @property {Boolean} [collision=true] 开启碰撞检测。 + * @namespace options + * @uses Popover.collision + * @for Popover + */ + gmu.Popover.options.collision = true; + + /** + * 碰撞检测,依赖于placement插件,根据是否能完全显示内容的策略,挑选最合适的placement. + * @class collision + * @namespace Popover + * @pluginfor Popover + */ + gmu.Popover.option( 'collision', true, function() { + var me = this, + opts = me._options; + + // 获取within坐标信息 + // 可以是window, document或者element. + // within为碰撞检测的容器。 + function getWithinInfo( raw ) { + var $el = $( raw ); + + raw = $el[ 0 ]; + + if ( raw !== window && raw.nodeType !== 9 ) { + return $el.offset(); + } + + return { + width: $el.width(), + height: $el.height(), + top: raw.pageYOffset || raw.scrollTop || 0, + left: raw.pageXOffset || raw.scrollLeft || 0 + }; + } + + // 判断是否没被挡住 + function isInside( coord, width, height, within ) { + return coord.left >= within.left && + coord.left + width <= within.left + within.width && + coord.top >= within.top && + coord.top + height <= within.top + within.height; + } + + // 此事件来源于placement.js, 主要用来修改定位最终值。 + me.on( 'before.placement', function( e, coord, info, presets ) { + var within = getWithinInfo( opts.within || window ), + now = info.placement, + orig = info.coord, + aviable = Object.keys( presets ), + idx = aviable.indexOf( now ) + 1, + swap = aviable.splice( idx, aviable.length - idx ); + + // 从当前placement的下一个开始,最多尝试一圈。 + // 如果有完全没有被挡住的位置,则跳出循环 + // 如果尝试一圈都没有合适的位置,还是用原来的初始位置定位 + aviable = swap.concat( aviable ); + + while ( aviable.length && !isInside( coord, orig.width, + orig.height, within ) ) { + now = aviable.shift(); + $.extend( coord, presets[ now ]() ); + } + info.preset = now; + } ); + } ); +})( gmu, gmu.$ ); +/** + * @file 是否点击其他区域,关闭自己 + * @import widget/popover/popover.js + */ +(function( gmu, $ ) { + var Popover = gmu.Popover; + + /** + * @property {Boolean} [dismissible=true] 是否点击其他区域,关闭自己. + * @namespace options + * @uses Popover.dismissible + * @for Popover + */ + Popover.options.dismissible = true; + + /** + * 用来实现自动关闭功能,在弹出层打开的条件下,点击其他位置,将自动关闭此弹出层。 + * 此功能包括多个实例间的互斥功能。 + * @class dismissible + * @namespace Popover + * @pluginfor Popover + */ + Popover.option( 'dismissible', true, function() { + var me = this, + $doc = $( document ), + click = 'click' + me.eventNs; + + function isFromSelf( target ) { + var doms = me.$target.add( me.$root ).get(), + i = doms.length; + + while ( i-- ) { + if ( doms[ i ] === target || + $.contains( doms[ i ], target ) ) { + return true; + } + } + return false; + } + + me.on( 'show', function() { + $doc.off( click ).on( click, function( e ) { + isFromSelf( e.target ) || me.hide(); + } ); + } ); + + me.on( 'hide', function() { + $doc.off( click ); + } ); + } ); +})( gmu, gmu.$ ); +/** + * @file 简单版定位 + * @import widget/popover/popover.js, extend/offset.js + */ +(function( gmu, $ ) { + + /** + * @property {String} [placement="bottom"] 设置定位位置。 + * @namespace options + * @uses Popover.placement + * @for Popover + */ + + /** + * @property {Object|Function} [offset=null] 设置偏移量。 + * @namespace options + * @for Popover + * @uses Popover.placement + */ + $.extend( gmu.Popover.options, { + placement: 'bottom', // 默认让其在下方显示 + offset: null + } ); + + /** + * 支持弹出层相对于按钮上下左右定位。 + * @class placement + * @namespace Popover + * @pluginfor Popover + */ + gmu.Popover.option( 'placement', function( val ) { + return ~[ 'top', 'bottom', 'left', 'right' ].indexOf( val ); + }, function() { + + var me = this, + + // 第一个值:相对于目标位置的水平位置 + // 第二个值:相对于目标位置的垂直位置 + // 第三个值:中心点的水平位置 + // 第四个值:中心点的垂直位置 + config = { + 'top': 'center top center bottom', + 'right': 'right center left center', + 'bottom': 'center bottom center top', + 'left': 'left center right center' + }, + presets = {}, // 支持的定位方式。 + + info; + + // 根据配置项生成方法。 + $.each( config, function( preset, args ) { + args = args.split( /\s/g ); + args.unshift( preset ); + presets[ preset ] = function() { + return placement.apply( null, args ); + }; + } ); + + function getPos( pos, len ) { + return pos === 'right' || pos === 'bottom' ? len : + pos === 'center' ? len / 2 : 0; + } + + // 暂时用简单的方式实现,以后考虑采用position.js + function placement( preset, atH, atV, myH, myV ) { + var of = info.of, + coord = info.coord, + offset = info.offset, + top = of.top, + left = of.left; + + left += getPos( atH, of.width ) - getPos( myH, coord.width ); + top += getPos( atV, of.height ) - getPos( myV, coord.height ); + + // offset可以是fn + offset = typeof offset === 'function' ? offset.call( null, { + left: left, + top: top + }, preset ) : offset || {}; + + return { + left: left + (offset.left || 0), + top: top + (offset.top || 0) + }; + } + + // 此事件在 + this.on( 'placement', function( e, $el, $of ) { + var me = this, + opts = me._options, + placement = opts.placement, + coord; + + info = { + coord: $el.offset(), + of: $of.offset(), + placement: placement, + $el: $el, + $of: $of, + offset: opts.offset + }; + + // 设置初始值 + coord = presets[ placement ](); + + // 提供机会在设置之前修改位置 + me.trigger( 'before.placement', coord, info, presets ); + info.preset && (info.placement = info.preset); + $el.offset( coord ); + + // 提供给arrow位置定位用 + me.trigger( 'after.placement', coord, info ); + } ); + + // 当屏幕旋转的时候需要需要重新计算。 + $( window ).on( 'ortchange', function() { + me._visible && me.trigger( 'placement', me.$target, me.$root ); + } ); + } ); +})( gmu, gmu.$ ); +/** + * @file 进度条组件 + * @import extend/touch.js, core/widget.js + * @module GMU + */ +(function( gmu, $, undefined ) { + + /** + * 进度条组件 + * + * @class Progressbar + * @constructor Html部分 + * ```html + *
          + * ``` + * + * javascript部分 + * ```javascript + * $('#progressbar').progressbar(); + * ``` + * @param {dom | zepto | selector} [el] 用来初始化进度条的元素 + * @param {Object} [options] 组件配置项。具体参数请查看[Options](#GMU:Progressbar:options) + * @grammar $( el ).progressbar( options ) => zepto + * @grammar new gmu.Progressbar( el, options ) => instance + */ + gmu.define('Progressbar', { + + options: { + + /** + * @property {Nubmer} [initValue=0] 初始时进度的百分比,不要百分号 + * @namespace options + */ + initValue: 0, + + /** + * @property {Boolean} [horizontal=true] 组件是否为横向(若设为false,则为竖向) + * @namespace options + */ + horizontal: true, + + /** + * @property {Number} [transitionDuration=300] 按钮滑动时动画效果持续的时间,单位为ms,设为0则无动画 + * @namespace options + */ + transitionDuration: 300, + _isShow: true, + _current: 0, + _percent: 0 + }, + + _init: function() { + var me = this, + $el, + _eventHandler, + _button, + _background, + _offset; + + me.on( 'ready', function(){ + $el = me.$el, + _eventHandler = $.proxy(me._eventHandler, me), + _button = $el.find('.ui-progressbar-button'), + _background = $el.find('.ui-progressbar-bg'), + _offset = $el.offset(); + + _button.on('touchstart touchmove touchend touchcancel', _eventHandler); + _background.on('touchstart', _eventHandler); + $.extend( me._options, { + _button: _button[0], + $_background: _background, + _filled: $el.find('.ui-progressbar-filled')[0], + _width: _offset.width, + _height: _offset.height + }); + me._options['horizontal'] && _offset.width && $el.width(_offset.width); + me._options['initValue'] > 0 && me.value( me._options['initValue']); + } ); + + me.on( 'destroy', function() { + if ( !me._options.setup ) { + me.$el.remove(); + } + } ); + }, + + _create: function() { + var me = this, + direction = me._options['horizontal'] ? 'h' : 'v'; + + if ( !me.$el ) { + me.$el = $('
          '); + } + me.$el.addClass('ui-progressbar-' + direction).appendTo(me._options['container'] || (me.$el.parent().length ? '' : document.body)).html( + ('
          ')); + }, + + _eventHandler: function(e) { + var me = this; + + switch (e.type) { + case 'touchmove': + me._touchMove(e); + break; + case 'touchstart': + $(e.target).hasClass('ui-progressbar-bg') ? me._click(e) : me._touchStart(e); + break; + case 'touchcancel': + case 'touchend': + me._touchEnd(); + break; + case 'tap': + me._click(e); + break; + } + }, + + _touchStart: function(e) { + var me = this, + opts = me._options; + + $.extend( me._options, { + pageX: e.touches[0].pageX, + pageY: e.touches[0].pageY, + S: false, //isScrolling + T: false, //isTested + X: 0, //horizontal moved + Y: 0 //vertical moved + }); + + opts._button.style.webkitTransitionDuration = '0ms'; + opts._filled.style.webkitTransitionDuration = '0ms'; + $(opts._button).addClass('ui-progressbar-button-pressed'); + me.trigger('dragStart'); + }, + + _touchMove: function(e) { + var me = this, + opts = me._options, + touch = e.touches[0], + X = touch.pageX - opts.pageX, + Y = touch.pageY - opts.pageY, + _percent; + + if(!opts.T) { + var S = Math.abs(X) < Math.abs(touch.pageY - opts.pageY); + opts.T = true; + opts.S = S; + } + if(opts.horizontal) { + if(!opts.S) { + e.stopPropagation(); + e.preventDefault(); + _percent = (X + opts._current) / opts._width * 100; + if(_percent <= 100 && _percent >= 0) { + opts._percent = _percent; + opts.X = X; + opts._button.style.webkitTransform = 'translate3d(' + (opts.X + opts._current) + 'px,0,0)'; + opts._filled.style.width = _percent + '%'; + me.trigger('valueChange'); + } + me.trigger('dragMove'); + } + } else { + if(opts.S) { + e.stopPropagation(); + e.preventDefault(); + _percent = -(opts._current + Y) / opts._height * 100; + if(_percent <= 100 && _percent >= 0) { + opts._percent = _percent; + opts.Y = Y; + opts._button.style.webkitTransform = 'translate3d(0,' + (Y + opts._current) + 'px,0)'; + opts._filled.style.cssText += 'height:' + _percent + '%;top:' + (opts._height + Y + opts._current) + 'px'; + me.trigger('valueChange'); + } + me.trigger('dragMove'); + } + } + }, + + _touchEnd: function() { + var me = this, + opts = me._options; + + opts._current += opts.horizontal ? opts.X : opts.Y; + $(opts._button).removeClass('ui-progressbar-button-pressed'); + me.trigger('dragEnd'); + }, + + _click: function(e) { + var me = this, + opts = me._options, + rect = opts.$_background.offset(), + touch = e.touches[0]; + + opts.horizontal ? + me.value((touch.pageX - rect.left) / opts._width * 100) : + me.value((opts._height - touch.pageY + rect.top) / opts._height * 100); + }, + + /** + * 获取/设置progressbar的值 + * @method value + * @param {Number} [opts] 要设置的值,不传表示取值 + * @chainable + * @return {self} 返回本身。 + */ + value: function(value) { + var me = this, + opts = me._options, + _current, duration; + + if(value === undefined) { + return opts._percent; + } else { + value = parseFloat(value); + if(isNaN(value)) return me; + value = value > 100 ? 100 : value < 0 ? 0 : value; + opts._percent = value; + duration = ';-webkit-transition-duration:' + opts.transitionDuration + 'ms'; + if(opts.horizontal) { + _current = opts._current = opts._width * value / 100; + opts._button.style.cssText += '-webkit-transform:translate3d(' + _current + 'px,0,0)' + duration; + opts._filled.style.cssText += 'width:'+ value + '%' + duration; + } else { + _current = opts._current = opts._height * value / -100; + opts._button.style.cssText += '-webkit-transform:translate3d(0,' + _current + 'px,0)' + duration; + opts._filled.style.cssText += 'height:' + value + '%;top:' + (opts._height + _current) + 'px' + duration; + } + me.trigger('valueChange'); + return me; + } + }, + + /** + * 显示progressbar + * @method show + * @chainable + * @return {self} 返回本身。 + */ + show: function() { + var me = this; + + if(!me._options['_isShow']){ + me.$el.css('display', 'block'); + me._options['_isShow'] = true; + } + + return me; + }, + + /** + * 隐藏progressbar + * @method hide + * @chainable + * @return {self} 返回本身。 + */ + hide: function() { + var me = this; + + if(me._options['_isShow']) { + me.$el.css('display', 'none'); + me._options['_isShow'] = false; + } + + return me; + } + + /** + * @event ready + * @param {Event} e gmu.Event对象 + * @description 当组件初始化完后触发。 + */ + + /** + * @event dragStart + * @param {Event} e gmu.Event对象 + * @description 拖动进度条开始时触发的事件 + */ + + /** + * @event dragMove + * @param {Event} e gmu.Event对象 + * @description 拖动进度条过程中触发的事件 + */ + + /** + * @event dragEnd + * @param {Event} e gmu.Event对象 + * @description 拖动进度条结束时触发的事件 + */ + + /** + * @event valueChange + * @param {Event} e gmu.Event对象 + * @description progressbar的值有变化时触发(拖动progressbar时,值不一定会变化) + */ + + /** + * @event destroy + * @param {Event} e gmu.Event对象 + * @description 组件在销毁的时候触发 + */ + }); +})( gmu, gmu.$ ); + +/** + * @file 加载更多组件 + * @import core/widget.js + * @importCSS loading.css + * @module GMU + */ + +(function( gmu, $, undefined ) { + + /** + * 加载更多组件 + * + * @class Refresh + * @constructor Html部分 + * ```html + *
          + *
            ...
          + *
          + *
          + + * ``` + * + * javascript部分 + * ```javascript + * $('.ui-refresh').refresh({ + * load: function (dir, type) { + * var me = this; + * $.getJSON('../../data/refresh.php', function (data) { + * var $list = $('.data-list'), + * html = (function (data) { //数据渲染 + * var liArr = []; + * $.each(data, function () { + * liArr.push(this.html); + * }); + * return liArr.join(''); + * })(data); + * $list[dir == 'up' ? 'prepend' : 'append'](html); + * me.afterDataLoading(); //数据加载完成后改变状态 + * }); + * } + * }); + * ``` + * @param {dom | zepto | selector} [el] 用来初始化Refresh的元素 + * @param {Object} [options] 组件配置项。具体参数请查看[Options](#GMU:Refresh:options) + * @grammar $( el ).refresh( options ) => zepto + * @grammar new gmu.Refresh( el, options ) => instance + */ + gmu.define( 'Refresh', { + options: { + + /** + * @property {Function} load 当点击按钮,或者滑动达到可加载内容条件时,此方法会被调用。需要在此方法里面进行ajax内容请求,并在请求完后,调用afterDataLoading(),通知refresh组件,改变状态。 + * @namespace options + */ + load: null, + + /** + * @property {Function} [statechange=null] 样式改变时触发,该事件可以被阻止,阻止后可以自定义加载样式,回调参数:event(事件对象), elem(refresh按钮元素), state(状态), dir(方向) + * @namespace options + */ + statechange: null + }, + + _init: function() { + var me = this, + opts = me._options; + + me.on( 'ready', function(){ + $.each(['up', 'down'], function (i, dir) { + var $elem = opts['$' + dir + 'Elem'], + elem = $elem.get(0); + + if ($elem.length) { + me._status(dir, true); //初始设置加载状态为可用 + if (!elem.childNodes.length || ($elem.find('.ui-refresh-icon').length && $elem.find('.ui-refresh-label').length)) { //若内容为空则创建,若不满足icon和label的要求,则不做处理 + !elem.childNodes.length && me._createBtn(dir); + opts.refreshInfo || (opts.refreshInfo = {}); + opts.refreshInfo[dir] = { + $icon: $elem.find('.ui-refresh-icon'), + $label: $elem.find('.ui-refresh-label'), + text: $elem.find('.ui-refresh-label').html() + } + } + $elem.on('click', function () { + if (!me._status(dir) || opts._actDir) return; //检查是否处于可用状态,同一方向上的仍在加载中,或者不同方向的还未加载完成 traceID:FEBASE-569 + me._setStyle(dir, 'loading'); + me._loadingAction(dir, 'click'); + }); + } + }); + } ); + + me.on( 'destroy', function(){ + me.$el.remove(); + } ); + }, + + _create: function(){ + var me = this, + opts = me._options, + $el = me.$el; + + if( me._options.setup ) { + // 值支持setup模式,所以直接从DOM中取元素 + opts.$upElem = $el.find('.ui-refresh-up'); + opts.$downElem = $el.find('.ui-refresh-down'); + $el.addClass('ui-refresh'); + } + }, + + _createBtn: function (dir) { + this._options['$' + dir + 'Elem'].html('加载更多'); + + return this; + }, + + _setStyle: function (dir, state) { + var me = this, + stateChange = $.Event('statechange'); + + me.trigger(stateChange, me._options['$' + dir + 'Elem'], state, dir); + if ( stateChange.defaultPrevented ) { + return me; + } + + return me._changeStyle(dir, state); + }, + + _changeStyle: function (dir, state) { + var opts = this._options, + refreshInfo = opts.refreshInfo[dir]; + + switch (state) { + case 'loaded': + refreshInfo['$label'].html(refreshInfo['text']); + refreshInfo['$icon'].removeClass(); + opts._actDir = ''; + break; + case 'loading': + refreshInfo['$label'].html('加载中...'); + refreshInfo['$icon'].addClass('ui-loading'); + opts._actDir = dir; + break; + case 'disable': + refreshInfo['$label'].html('没有更多内容了'); + break; + } + + return this; + }, + + _loadingAction: function (dir, type) { + var me = this, + opts = me._options, + loadFn = opts.load; + + $.isFunction(loadFn) && loadFn.call(me, dir, type); + me._status(dir, false); + + return me; + }, + + /** + * 当组件调用load,在load中通过ajax请求内容回来后,需要调用此方法,来改变refresh状态。 + * @method afterDataLoading + * @param {String} dir 加载的方向('up' | 'down') + * @chainable + * @return {self} 返回本身。 + */ + afterDataLoading: function (dir) { + var me = this, + dir = dir || me._options._actDir; + + me._setStyle(dir, 'loaded'); + me._status(dir, true); + + return me; + }, + + /** + * 用来设置加载是否可用,分方向的。 + * @param {String} dir 加载的方向('up' | 'down') + * @param {String} status 状态(true | false) + */ + _status: function(dir, status) { + var opts = this._options; + + return status === undefined ? opts['_' + dir + 'Open'] : opts['_' + dir + 'Open'] = !!status; + }, + + _setable: function (able, dir, hide) { + var me = this, + opts = me._options, + dirArr = dir ? [dir] : ['up', 'down']; + + $.each(dirArr, function (i, dir) { + var $elem = opts['$' + dir + 'Elem']; + if (!$elem.length) return; + //若是enable操作,直接显示,disable则根据text是否是true来确定是否隐藏 + able ? $elem.show() : (hide ? $elem.hide() : me._setStyle(dir, 'disable')); + me._status(dir, able); + }); + + return me; + }, + + /** + * 如果已无类容可加载时,可以调用此方法来,禁用Refresh。 + * @method disable + * @param {String} dir 加载的方向('up' | 'down') + * @param {Boolean} hide 是否隐藏按钮。如果此属性为false,将只有文字变化。 + * @chainable + * @return {self} 返回本身。 + */ + disable: function (dir, hide) { + return this._setable(false, dir, hide); + }, + + /** + * 启用组件 + * @method enable + * @param {String} dir 加载的方向('up' | 'down') + * @chainable + * @return {self} 返回本身。 + */ + enable: function (dir) { + return this._setable(true, dir); + } + + /** + * @event ready + * @param {Event} e gmu.Event对象 + * @description 当组件初始化完后触发。 + */ + + /** + * @event statechange + * @param {Event} e gmu.Event对象 + * @param {Zepto} elem 按钮元素 + * @param {String} state 当前组件的状态('loaded':默认状态;'loading':加载中状态;'disabled':禁用状态,表示无内容加载了;'beforeload':在手没有松开前满足加载的条件状态。 需要引入插件才有此状态,lite,iscroll,或者iOS5) + * @param {String} dir 加载的方向('up' | 'down') + * @description 组件发生状态变化时会触发 + */ + + /** + * @event destroy + * @param {Event} e gmu.Event对象 + * @description 组件在销毁的时候触发 + */ + + } ); +})( gmu, gmu.$ ); + +/** + * @file 图片轮播组件 + * @import extend/touch.js, extend/event.ortchange.js, core/widget.js + * @module GMU + */ +(function( gmu, $, undefined ) { + var cssPrefix = $.fx.cssPrefix, + transitionEnd = $.fx.transitionEnd, + + // todo 检测3d是否支持。 + translateZ = ' translateZ(0)'; + + /** + * 图片轮播组件 + * + * @class Slider + * @constructor Html部分 + * ```html + *
          + *
          + * + *

          1,让Coron的太阳把自己晒黑—小天

          + *
          + *
          + * + *

          2,让Coron的太阳把自己晒黑—小天

          + *
          + *
          + * + *

          3,让Coron的太阳把自己晒黑—小天

          + *
          + *
          + * + *

          4,让Coron的太阳把自己晒黑—小天

          + *
          + *
          + * ``` + * + * javascript部分 + * ```javascript + * $('#slider').slider(); + * ``` + * @param {dom | zepto | selector} [el] 用来初始化Slider的元素 + * @param {Object} [options] 组件配置项。具体参数请查看[Options](#GMU:Slider:options) + * @grammar $( el ).slider( options ) => zepto + * @grammar new gmu.Slider( el, options ) => instance + */ + gmu.define( 'Slider', { + + options: { + + /** + * @property {Boolean} [loop=false] 是否连续滑动 + * @namespace options + */ + loop: false, + + /** + * @property {Number} [speed=400] 动画执行速度 + * @namespace options + */ + speed: 400, + + /** + * @property {Number} [index=0] 初始位置 + * @namespace options + */ + index: 0, + + /** + * @property {Object} [selector={container:'.ui-slider-group'}] 内部结构选择器定义 + * @namespace options + */ + selector: { + container: '.ui-slider-group' // 容器的选择器 + } + }, + + template: { + item: '
          ' + + '' + + '<% if( title ) { %>

          <%= title %>

          <% } %>' + + '
          ' + }, + + _create: function() { + var me = this, + $el = me.getEl(), + opts = me._options; + + me.index = opts.index; + + // 初始dom结构 + me._initDom( $el, opts ); + + // 更新width + me._initWidth( $el, me.index ); + me._container.on( transitionEnd + me.eventNs, + $.proxy( me._tansitionEnd, me ) ); + + // 转屏事件检测 + $( window ).on( 'ortchange' + me.eventNs, function() { + me._initWidth( $el, me.index ); + } ); + }, + + _initDom: function( $el, opts ) { + var selector = opts.selector, + viewNum = opts.viewNum || 1, + items, + container; + + // 检测容器节点是否指定 + container = $el.find( selector.container ); + + // 没有指定容器则创建容器 + if ( !container.length ) { + container = $( '
          ' ); + + // 如果没有传入content, 则将root的孩子作为可滚动item + if ( !opts.content ) { + + // 特殊处理直接用ul初始化slider的case + if ( $el.is( 'ul' ) ) { + this.$el = container.insertAfter( $el ); + container = $el; + $el = this.$el; + } else { + container.append( $el.children() ); + } + } else { + this._createItems( container, opts.content ); + } + + container.appendTo( $el ); + } + + // 检测是否构成循环条件 + if ( (items = container.children()).length < viewNum + 1 ) { + opts.loop = false; + } + + // 如果节点少了,需要复制几份 + while ( opts.loop && container.children().length < 3 * viewNum ) { + container.append( items.clone() ); + } + + this.length = container.children().length; + + this._items = (this._container = container) + .addClass( 'ui-slider-group' ) + .children() + .addClass( 'ui-slider-item' ) + .toArray(); + + this.trigger( 'done.dom', $el.addClass( 'ui-slider' ), opts ); + }, + + // 根据items里面的数据挨个render插入到container中 + _createItems: function( container, items ) { + var i = 0, + len = items.length; + + for ( ; i < len; i++ ) { + container.append( this.tpl2html( 'item', items[ i ] ) ); + } + }, + + _initWidth: function( $el, index, force ) { + var me = this, + width; + + // width没有变化不需要重排 + if ( !force && (width = $el.width()) === me.width ) { + return; + } + + me.width = width; + me._arrange( width, index ); + me.height = $el.height(); + me.trigger( 'width.change' ); + }, + + // 重排items + _arrange: function( width, index ) { + var items = this._items, + i = 0, + item, + len; + + this._slidePos = new Array( items.length ); + + for ( len = items.length; i < len; i++ ) { + item = items[ i ]; + + item.style.cssText += 'width:' + width + 'px;' + + 'left:' + (i * -width) + 'px;'; + item.setAttribute( 'data-index', i ); + + this._move( i, i < index ? -width : i > index ? width : 0, 0 ); + } + + this._container.css( 'width', width * len ); + }, + + _move: function( index, dist, speed, immediate ) { + var slidePos = this._slidePos, + items = this._items; + + if ( slidePos[ index ] === dist || !items[ index ] ) { + return; + } + + this._translate( index, dist, speed ); + slidePos[ index ] = dist; // 记录目标位置 + + // 强制一个reflow + immediate && items[ index ].clientLeft; + }, + + _translate: function( index, dist, speed ) { + var slide = this._items[ index ], + style = slide && slide.style; + + if ( !style ) { + return false; + } + + style.cssText += cssPrefix + 'transition-duration:' + speed + + 'ms;' + cssPrefix + 'transform: translate(' + + dist + 'px, 0)' + translateZ + ';'; + }, + + _circle: function( index, arr ) { + var len; + + arr = arr || this._items; + len = arr.length; + + return (index % len + len) % arr.length; + }, + + _tansitionEnd: function( e ) { + + // ~~用来类型转换,等价于parseInt( str, 10 ); + if ( ~~e.target.getAttribute( 'data-index' ) !== this.index ) { + return; + } + + this.trigger( 'slideend', this.index ); + }, + + _slide: function( from, diff, dir, width, speed, opts ) { + var me = this, + to; + + to = me._circle( from - dir * diff ); + + // 如果不是loop模式,以实际位置的方向为准 + if ( !opts.loop ) { + dir = Math.abs( from - to ) / (from - to); + } + + // 调整初始位置,如果已经在位置上不会重复处理 + this._move( to, -dir * width, 0, true ); + + this._move( from, width * dir, speed ); + this._move( to, 0, speed ); + + this.index = to; + return this.trigger( 'slide', to, from ); + }, + + /** + * 切换到第几个slide + * @method slideTo + * @chainable + * @param {Number} to 目标slide的序号 + * @param {Number} [speed] 切换的速度 + * @return {self} 返回本身 + */ + slideTo: function( to, speed ) { + if ( this.index === to || this.index === this._circle( to ) ) { + return this; + } + + var opts = this._options, + index = this.index, + diff = Math.abs( index - to ), + + // 1向左,-1向右 + dir = diff / (index - to), + width = this.width; + + speed = speed || opts.speed; + + return this._slide( index, diff, dir, width, speed, opts ); + }, + + /** + * 切换到上一个slide + * @method prev + * @chainable + * @return {self} 返回本身 + */ + prev: function() { + + if ( this._options.loop || this.index > 0 ) { + this.slideTo( this.index - 1 ); + } + + return this; + }, + + /** + * 切换到下一个slide + * @method next + * @chainable + * @return {self} 返回本身 + */ + next: function() { + + if ( this._options.loop || this.index + 1 < this.length ) { + this.slideTo( this.index + 1 ); + } + + return this; + }, + + /** + * 返回当前显示的第几个slide + * @method getIndex + * @chainable + * @return {Number} 当前的silde序号 + */ + getIndex: function() { + return this.index; + }, + + /** + * 销毁组件 + * @method destroy + */ + destroy: function() { + this._container.off( this.eventNs ); + $( window ).off( 'ortchange' + this.eventNs ); + return this.$super( 'destroy' ); + } + + /** + * @event ready + * @param {Event} e gmu.Event对象 + * @description 当组件初始化完后触发。 + */ + + /** + * @event done.dom + * @param {Event} e gmu.Event对象 + * @param {Zepto} $el slider元素 + * @param {Object} opts 组件初始化时的配置项 + * @description DOM创建完成后触发 + */ + + /** + * @event width.change + * @param {Event} e gmu.Event对象 + * @description slider容器宽度发生变化时触发 + */ + + /** + * @event slideend + * @param {Event} e gmu.Event对象 + * @param {Number} index 当前slide的序号 + * @description slide切换完成后触发 + */ + + /** + * @event slide + * @param {Event} e gmu.Event对象 + * @param {Number} to 目标slide的序号 + * @param {Number} from 当前slide的序号 + * @description slide切换时触发(如果切换时有动画,此事件触发时,slide不一定已经完成切换) + */ + + /** + * @event destroy + * @param {Event} e gmu.Event对象 + * @description 组件在销毁的时候触发 + */ + } ); + +})( gmu, gmu.$ ); +/** + * @file 自动播放插件 + * @import widget/slider/slider.js + */ +(function( gmu, $ ) { + $.extend( true, gmu.Slider, { + options: { + /** + * @property {Boolean} [autoPlay=true] 是否开启自动播放 + * @namespace options + * @for Slider + * @uses Slider.autoplay + */ + autoPlay: true, + /** + * @property {Number} [interval=4000] 自动播放的间隔时间(毫秒) + * @namespace options + * @for Slider + * @uses Slider.autoplay + */ + interval: 4000 + } + } ); + + /** + * 自动播放插件 + * @class autoplay + * @namespace Slider + * @pluginfor Slider + */ + gmu.Slider.register( 'autoplay', { + _init: function() { + var me = this; + me.on( 'slideend ready', me.resume ) + + // 清除timer + .on( 'destory', me.stop ); + + // 避免滑动时,自动切换 + me.getEl() + .on( 'touchstart' + me.eventNs, $.proxy( me.stop, me ) ) + .on( 'touchend' + me.eventNs, $.proxy( me.resume, me ) ); + }, + + /** + * 恢复自动播放。 + * @method resume + * @chainable + * @return {self} 返回本身 + * @for Slider + * @uses Slider.autoplay + */ + resume: function() { + var me = this, + opts = me._options; + + if ( opts.autoPlay && !me._timer ) { + me._timer = setTimeout( function() { + me.slideTo( me.index + 1 ); + me._timer = null; + }, opts.interval ); + } + return me; + }, + + /** + * 停止自动播放 + * @method stop + * @chainable + * @return {self} 返回本身 + * @for Slider + * @uses Slider.autoplay + */ + stop: function() { + var me = this; + + if ( me._timer ) { + clearTimeout( me._timer ); + me._timer = null; + } + return me; + } + } ); +})( gmu, gmu.$ ); +/** + * @file 图片懒加载插件 + * @import widget/slider/slider.js + */ +(function( gmu ) { + + gmu.Slider.template.item = '
          ' + + '' + + '' + + '<% if( title ) { %>

          <%= title %>

          <% } %>' + + '
          '; + + /** + * 图片懒加载插件 + * @class lazyloadimg + * @namespace Slider + * @pluginfor Slider + */ + gmu.Slider.register( 'lazyloadimg', { + _init: function() { + this.on( 'ready slide', this._loadItems ); + }, + + _loadItems: function() { + var opts = this._options, + loop = opts.loop, + viewNum = opts.viewNum || 1, + index = this.index, + i, + len; + + for ( i = index - viewNum, len = index + 2 * viewNum; i < len; + i++ ) { + + this.loadImage( loop ? this._circle( i ) : i ); + } + }, + + /** + * 加载指定item中的图片 + * @method loadImage + * @param {Number} index 要加载的图片的序号 + * @for Slider + * @uses Slider.lazyloadimg + */ + loadImage: function( index ) { + var item = this._items[ index ], + images; + + if ( !item || !(images = gmu.staticCall( item, 'find', + 'img[lazyload]' ), images.length) ) { + + return this; + } + + images.each(function() { + this.src = this.getAttribute( 'lazyload' ); + this.removeAttribute( 'lazyload' ); + }); + } + } ); +})( gmu ); +/** + * @file 图片轮播手指跟随插件 + * @import widget/slider/slider.js + */ +(function( gmu, $, undefined ) { + + var map = { + touchstart: '_onStart', + touchmove: '_onMove', + touchend: '_onEnd', + touchcancel: '_onEnd', + click: '_onClick' + }, + + isScrolling, + start, + delta, + moved; + + // 提供默认options + $.extend( gmu.Slider.options, { + + /** + * @property {Boolean} [stopPropagation=false] 是否阻止事件冒泡 + * @namespace options + * @for Slider + * @uses Slider.touch + */ + stopPropagation: false, + + /** + * @property {Boolean} [disableScroll=false] 是否阻止滚动 + * @namespace options + * @for Slider + * @uses Slider.touch + */ + disableScroll: false + } ); + + /** + * 图片轮播手指跟随插件 + * @class touch + * @namespace Slider + * @pluginfor Slider + */ + gmu.Slider.register( 'touch', { + _init: function() { + var me = this, + $el = me.getEl(); + + me._handler = function( e ) { + me._options.stopPropagation && e.stopPropagation(); + return map[ e.type ] && me[ map[ e.type ] ].call( me, e ); + }; + + me.on( 'ready', function() { + + // 绑定手势 + $el.on( 'touchstart' + me.eventNs, me._handler ); + + // 阻止误点击, 犹豫touchmove被preventDefault了,导致长按也会触发click + me._container.on( 'click' + me.eventNs, me._handler ); + } ); + }, + + _onClick: function() { + return !moved; + }, + + _onStart: function( e ) { + + // 不处理多指 + if ( e.touches.length > 1 ) { + return false; + } + + var me = this, + touche = e.touches[ 0 ], + opts = me._options, + eventNs = me.eventNs, + num; + + start = { + x: touche.pageX, + y: touche.pageY, + time: +new Date() + }; + + delta = {}; + moved = false; + isScrolling = undefined; + + num = opts.viewNum || 1; + me._move( opts.loop ? me._circle( me.index - num ) : + me.index - num, -me.width, 0, true ); + me._move( opts.loop ? me._circle( me.index + num ) : + me.index + num, me.width, 0, true ); + + me.$el.on( 'touchmove' + eventNs + ' touchend' + eventNs + + ' touchcancel' + eventNs, me._handler ); + }, + + _onMove: function( e ) { + + // 多指或缩放不处理 + if ( e.touches.length > 1 || e.scale && + e.scale !== 1 ) { + return false; + } + + var opts = this._options, + viewNum = opts.viewNum || 1, + touche = e.touches[ 0 ], + index = this.index, + i, + len, + pos, + slidePos; + + opts.disableScroll && e.preventDefault(); + + delta.x = touche.pageX - start.x; + delta.y = touche.pageY - start.y; + + if ( typeof isScrolling === 'undefined' ) { + isScrolling = Math.abs( delta.x ) < + Math.abs( delta.y ); + } + + if ( !isScrolling ) { + e.preventDefault(); + + if ( !opts.loop ) { + + // 如果左边已经到头 + delta.x /= (!index && delta.x > 0 || + + // 如果右边到头 + index === this._items.length - 1 && + delta.x < 0) ? + + // 则来一定的减速 + (Math.abs( delta.x ) / this.width + 1) : 1; + } + + slidePos = this._slidePos; + + for ( i = index - viewNum, len = index + 2 * viewNum; + i < len; i++ ) { + + pos = opts.loop ? this._circle( i ) : i; + this._translate( pos, delta.x + slidePos[ pos ], 0 ); + } + + moved = true; + } + }, + + _onEnd: function() { + + // 解除事件 + this.$el.off( 'touchmove' + this.eventNs + ' touchend' + + this.eventNs + ' touchcancel' + this.eventNs, + this._handler ); + + if ( !moved ) { + return; + } + + var me = this, + opts = me._options, + viewNum = opts.viewNum || 1, + index = me.index, + slidePos = me._slidePos, + duration = +new Date() - start.time, + absDeltaX = Math.abs( delta.x ), + + // 是否滑出边界 + isPastBounds = !opts.loop && (!index && delta.x > 0 || + index === slidePos.length - viewNum && delta.x < 0), + + // -1 向右 1 向左 + dir = delta.x > 0 ? 1 : -1, + speed, + diff, + i, + len, + pos; + + if ( duration < 250 ) { + + // 如果滑动速度比较快,偏移量跟根据速度来算 + speed = absDeltaX / duration; + diff = Math.min( Math.round( speed * viewNum * 1.2 ), + viewNum ); + } else { + diff = Math.round( absDeltaX / (me.perWidth || me.width) ); + } + + if ( diff && !isPastBounds ) { + me._slide( index, diff, dir, me.width, opts.speed, + opts, true ); + + // 在以下情况,需要多移动一张 + if ( viewNum > 1 && duration >= 250 && + Math.ceil( absDeltaX / me.perWidth ) !== diff ) { + + me.index < index ? me._move( me.index - 1, -me.perWidth, + opts.speed ) : me._move( me.index + viewNum, + me.width, opts.speed ); + } + } else { + + // 滑回去 + for ( i = index - viewNum, len = index + 2 * viewNum; + i < len; i++ ) { + + pos = opts.loop ? me._circle( i ) : i; + me._translate( pos, slidePos[ pos ], + opts.speed ); + } + } + } + } ); +})( gmu, gmu.$ ); +/** + * @file 图片轮播剪头按钮 + * @import widget/slider/slider.js + */ +(function( gmu, $, undefined ) { + $.extend( true, gmu.Slider, { + + template: { + prev: '', + next: '' + }, + + options: { + /** + * @property {Boolean} [arrow=true] 是否显示点 + * @namespace options + * @for Slider + * @uses Slider.arrow + */ + arrow: true, + + /** + * @property {Object} [select={prev:'.ui-slider-pre',next:'.ui-slider-next'}] 上一张和下一张按钮的选择器 + * @namespace options + * @for Slider + * @uses Slider.arrow + */ + select: { + prev: '.ui-slider-pre', // 上一张按钮选择器 + next: '.ui-slider-next' // 下一张按钮选择器 + } + } + } ); + + /** + * 图片轮播剪头按钮 + * @class arrow + * @namespace Slider + * @pluginfor Slider + */ + gmu.Slider.option( 'arrow', true, function() { + var me = this, + arr = [ 'prev', 'next' ]; + + this.on( 'done.dom', function( e, $el, opts ) { + var selector = opts.selector; + + arr.forEach(function( name ) { + var item = $el.find( selector[ name ] ); + item.length || $el.append( item = $( me.tpl2html( name ) ) ); + me[ '_' + name ] = item; + }); + } ); + + this.on( 'ready', function() { + arr.forEach(function( name ) { + me[ '_' + name ].on( 'tap' + me.eventNs, function() { + me[ name ].call( me ); + } ); + }); + } ); + + this.on( 'destroy', function() { + me._prev.off( me.eventNs ); + me._next.off( me.eventNs ); + } ); + } ); +})( gmu, gmu.$ ); +/** + * @file 图片轮播显示点功能 + * @import widget/slider/slider.js + */ +(function( gmu, $, undefined ) { + $.extend( true, gmu.Slider, { + + template: { + dots: '

          <%= new Array( len + 1 )' + + '.join("") %>

          ' + }, + + options: { + + /** + * @property {Boolean} [dots=true] 是否显示点 + * @namespace options + * @for Slider + * @uses Slider.dots + */ + dots: true, + + /** + * @property {Object} [selector={dots:'.ui-slider-dots'}] 所有点父级的选择器 + * @namespace options + * @for Slider + * @uses Slider.dots + */ + selector: { + dots: '.ui-slider-dots' + } + } + } ); + + /** + * 图片轮播显示点功能 + * @class dots + * @namespace Slider + * @pluginfor Slider + */ + gmu.Slider.option( 'dots', true, function() { + + var updateDots = function( to, from ) { + var dots = this._dots; + + typeof from === 'undefined' || gmu.staticCall( dots[ + from % this.length ], 'removeClass', 'ui-state-active' ); + + gmu.staticCall( dots[ to % this.length ], 'addClass', + 'ui-state-active' ); + }; + + this.on( 'done.dom', function( e, $el, opts ) { + var dots = $el.find( opts.selector.dots ); + + if ( !dots.length ) { + dots = this.tpl2html( 'dots', { + len: this.length + } ); + + dots = $( dots ).appendTo( $el ); + } + + this._dots = dots.children().toArray(); + } ); + + this.on( 'slide', function( e, to, from ) { + updateDots.call( this, to, from ); + } ); + + this.on( 'ready', function() { + updateDots.call( this, this.index ); + } ); + } ); +})( gmu, gmu.$ ); +/** + * @file 图片自动适应功能 + * @import widget/slider/slider.js + */ +(function( gmu ) { + + /** + * @property {Boolean} [imgZoom=true] 是否开启图片自适应 + * @namespace options + * @for Slider + * @uses Slider.dots + */ + gmu.Slider.options.imgZoom = true; + + /** + * 图片自动适应功能 + * @class imgZoom + * @namespace Slider + * @pluginfor Slider + */ + gmu.Slider.option( 'imgZoom', function() { + return !!this._options.imgZoom; + }, function() { + var me = this, + selector = me._options.imgZoom, + watches; + + selector = typeof selector === 'string' ? selector : 'img'; + + function unWatch() { + watches && watches.off( 'load' + me.eventNs, imgZoom ); + } + + function watch() { + unWatch(); + watches = me._container.find( selector ) + .on( 'load' + me.eventNs, imgZoom ); + } + + function imgZoom( e ) { + var img = e.target || this, + + // 只缩放,不拉伸 + scale = Math.min( 1, me.width / img.naturalWidth, + me.height / img.naturalHeight ); + + img.style.width = scale * img.naturalWidth + 'px'; + } + + me.on( 'ready dom.change', watch ); + me.on( 'width.change', function() { + watches && watches.each( imgZoom ); + } ); + me.on( 'destroy', unWatch ); + } ); +})( gmu ); +/** + * @file 搜索建议组件 + * @import core/widget.js, extend/touch.js, extend/highlight.js + */ +(function( $, win ) { + + /** + * 搜索建议组件 + * + * @class Suggestion + * @constructor Html部分 + * ```html + *
          + * + *
          + * ``` + * + * javascript部分 + * ```javascript + * $('#input').suggestion({ + * source: "../../data/suggestion.php" + * }); + * ``` + * @param {dom | zepto | selector} [el] 用来初始化Suggestion的元素 + * @param {Object} [options] 组件配置项。具体参数请查看[Options](#GMU:Suggestion:options) + * @grammar $( el ).suggestion( options ) => zepto + * @grammar new gmu.Suggestion( el, options ) => instance + */ + + var guid = 0; + + gmu.define( 'Suggestion', { + + // 默认options + options: { + + /** + * @property {Element | Zepto | Selector} container 父元素,若为render模式,则为必选 + * @namespace options + */ + + /** + * @property {String} source 请求数据的url,若不自定义sendRequest,则为必选 + * @namespace options + */ + + /** + * @property {String} [param=''] url附加参数 + * @namespace options + */ + + /** + * @property {String | Element} [form] 提交搜索的表单,默认为包含input框的第一个父级form + * @namespace options + */ + + /** + * @property {Boolean | String} [historyShare=true] 多个sug之间是否共享历史记录,可传入指定的key值。若传默认传true,则使用默认key:'SUG-Sharing-History',若传false,即表示不共享history;若传string,则为该值+'-SUG-Sharing-History'作为key值 + * @namespace options + */ + historyShare: true, + + /** + * @property {Boolean} [confirmClearHistory=true] 删除历史记录时是否确认 + * @namespace options + */ + confirmClearHistory: true, + + /** + * @property {Boolean} [autoClose=true] 点击input之外自动关闭 + * @namespace options + */ + autoClose: false + }, + + template: { + + // ui-suggestion的class必须有 + // ontent, button, clear, close这几个div必须有,其他的可以更改 + wrapper: '
          ' + + '
          ' + + '
          ' + + '清除历史记录' + + '关闭' + + '
          ' + }, + + _initDom: function() { + var me = this, + $input = me.getEl().attr( 'autocomplete', 'off'), + $parent = $input.parent('.ui-suggestion-mask'); + + $parent.length ? me.$mask = $parent : + $input.wrap( me.$mask = + $( '
          ' ) ); + + // 考采用template的wrapper项渲染列表 + me.$mask.append( me.tpl2html( 'wrapper' ) ); + + me.$wrapper = me.$mask.find( '.ui-suggestion' ) + .prop('id', 'ui-suggestion-' + (guid++)); + me.$content = me.$wrapper + .css( 'top', $input.height() + (me.wrapperTop = + parseInt( me.$wrapper.css( 'top' ), 10 ) || 0) ) + .find( '.ui-suggestion-content' ); + + me.$btn = me.$wrapper.find( '.ui-suggestion-button' ); + me.$clearBtn = me.$btn.find( '.ui-suggestion-clear' ); + me.$closeBtn = me.$btn.find( '.ui-suggestion-close' ); + + return me.trigger('initdom'); + }, + + _bindEvent: function() { + var me = this, + $el = me.getEl(), + ns = me.eventNs; + + me._options.autoClose && $( document ).on( 'tap' + ns, function( e ) { + + // 若点击是的sug外边则关闭sug + !$.contains( me.$mask.get( 0 ), e.target ) && me.hide(); + } ); + + $el.on( 'focus' + ns, function() { + + // 当sug已经处于显示状态时,不需要次showlist + !me.isShow && me._showList().trigger( 'open' ); + } ); + + $el.on( 'input' + ns, function() { + + // 考虑到在手机上输入比较慢,故未进行稀释处理 + me._showList(); + } ); + + me.$clearBtn.on( 'click' + ns, function() { + + //清除历史记录 + me.history( null ); + } ).highlight( 'ui-suggestion-highlight' ); + + me.$closeBtn.on( 'click' + ns, function() { + + // 隐藏sug + me.getEl().blur(); + me.hide().trigger( 'close' ); + } ).highlight( 'ui-suggestion-highlight' ); + + return me; + }, + + _create: function() { + var me = this, + opts = me._options, + hs = opts.historyShare; + + opts.container && (me.$el = $(opts.container)); + + // 若传默认传true,则使用默认key:'SUG-Sharing-History' + // 若传false,即表示不共享history,以该sug的id作为key值 + // 若传string,则在此基础上加上'SUG-Sharing-History' + me.key = hs ? + (($.type( hs ) === 'boolean' ? '' : hs + '-') + + 'SUG-Sharing-History') : + me.getEl().attr( 'id' ) || ('ui-suggestion-' + (guid++)); + + // localStorage中数据分隔符 + me.separator = encodeURIComponent( ',' ); + + // 创建dom,绑定事件 + me._initDom()._bindEvent(); + + return me; + }, + + /** + * 展示suglist,分为query存在和不存在 + * @private + */ + _showList: function() { + var me = this, + query = me.value(), + data; + + if ( query ) { + + // 当query不为空,即input或focus时,input有值 + // 用户自己发送请求或直接本地数据处理,可以在sendrequest中处理 + me.trigger( 'sendrequest', query, $.proxy( me._render, me ), + $.proxy( me._cacheData, me )); + + } else { + + // query为空,即刚开始focus时,读取localstorage中的数据渲染 + (data = me._localStorage()) ? + me._render( query, data.split( me.separator ) ) : + me.hide(); + } + + return me; + }, + + _render: function( query, data ) { + + this.trigger( 'renderlist', data, query, $.proxy( this._fillWrapper, this ) ); + }, + + /** + * 根据数据填充sug wrapper + * @listHtml 填充的sug片段,默认为'
          • ...
          • ...
          ' + * @private + */ + _fillWrapper: function( listHtml ) { + + // 数据不是来自历史记录时隐藏清除历史记录按钮 + this.$clearBtn[ this.value() ? 'hide' : 'show' ](); + listHtml ? (this.$content.html( listHtml ), this.show()) : + this.hide(); + + return this; + }, + + _localStorage: function( value ) { + var me = this, + key = me.key, + separator = me.separator, + localStorage, + data; + + try { + + localStorage = win.localStorage; + + if ( value === undefined ) { // geter + return localStorage[ key ]; + + } else if ( value === null ) { // setter clear + localStorage[ key ] = ''; + + } else if ( value ) { // setter + data = localStorage[ key ] ? + localStorage[ key ].split( separator ) : []; + + // 数据去重处理 + // todo 对于兼容老格式的数据中有一项会带有\u001e,暂未做判断 + if ( !~$.inArray( value, data ) ) { + data.unshift( value ); + localStorage[ key ] = data.join( separator ); + } + } + + } catch ( ex ) { + console.log( ex.message ); + } + + return me; + }, + + _cacheData: function( key, value ) { + this.cacheData || (this.cacheData = {}); + + return value !== undefined ? + this.cacheData[ key ] = value : this.cacheData[ key ]; + }, + + /** + * 获取input值 + * @method value + * @return {String} input中的值 + */ + value: function() { + return this.getEl().val(); + }, + + /** + * 设置|获取|清空历史记录 + * @method history + * @param {String} [value] 不传value表示清除sug历史记录,传value表示存值 + */ + history: function( value ) { + var me = this, + clearHistory = value !== null || function() { + return me._localStorage( null).hide(); + }; + + return value === null ? (me._options.confirmClearHistory ? + win.confirm( '清除全部查询历史记录?' ) && clearHistory() : + clearHistory()) : me._localStorage( value ) + }, + + /** + * 显示sug + * @method show + */ + show: function() { + + if ( !this.isShow ) { + this.$wrapper.show(); + this.isShow = true; + return this.trigger( 'show' ); + }else{ + return this; + } + + }, + + /** + * 隐藏sug + * @method hide + */ + hide: function() { + + if ( this.isShow ) { + this.$wrapper.hide(); + this.isShow = false; + return this.trigger( 'hide' ); + }else{ + return this; + } + + }, + + /** + * 销毁组件 + * @method destroy + */ + destroy: function() { + var me = this, + $el = me.getEl(), + ns = me.ns; + + // 先执行父级destroy,保证插件或option中的destroy先执行 + me.trigger( 'destroy' ); + + $el.off( ns ); + me.$mask.replaceWith( $el ); + me.$clearBtn.off( ns ); + me.$closeBtn.off( ns ); + me.$wrapper.children().off().remove(); + me.$wrapper.remove(); + me._options.autoClose && $( document ).off( ns ); + + this.destroyed = true; + + return me; + } + + /** + * @event ready + * @param {Event} e gmu.Event对象 + * @description 当组件初始化完后触发。 + */ + + /** + * @event initdom + * @param {Event} e gmu.Event对象 + * @param {Zepto} $el slider元素 + * @description DOM创建完成后触发 + */ + + /** + * @event show + * @param {Event} e gmu.Event对象 + * @description 显示sug时触发 + */ + + /** + * @event hide + * @param {Event} e gmu.Event对象 + * @param {Number} index 当前slide的序号 + * @description 隐藏sug时触发 + */ + + /** + * @event sendrequest + * @param {Event} e gmu.Event对象 + * @param {String} query 用户输入查询串 + * @param {Function} render 数据请求完成后的渲染回调函数,其参数为query,data + * @param {Function} cacheData 缓存query的回调函数,其参数为query, data + * @description 发送请求时触发 + */ + + /** + * @event renderlist + * @param {Event} e gmu.Event对象 + * @param {Array} data 渲染的数据 + * @param {String} query 用户输入的查询串 + * @param {Function} fillWrapper 列表渲染完成后的回调函数,参数为listHtml片段 + * @description 渲染sug list时触发 + */ + + /** + * @event destroy + * @param {Event} e gmu.Event对象 + * @description 组件在销毁的时候触发 + */ + } ); +})( gmu.$, window ); + +/** + * @file iScroll插件,sug列表使用iScroll展示 + * @import widget/suggestion/suggestion.js, extend/iscroll.js + */ +(function( gmu, $ ) { + + /** + * iScroll插件,sug列表使用iScroll展示 + * @class iscroll + * @namespace Suggestion + * @pluginfor Suggestion + */ + gmu.Suggestion.register( 'iscroll', { + + _init: function() { + var me = this; + + me.on( 'ready', function() { + + // 增加一层scroller结构 + me.$scroller = + $( '
          ' ); + + // 初始化iScroll,若需要设置wrapper高度,可在样式中设max-height + me.$content + .wrapInner( me.$scroller ) + .iScroll({ + + hScroll: false, + + onRefresh: function() { + + // 更新iScroll时滚回顶部 + this.y && this.scrollTo( 0, 0 ); + } + }); + + // 调用iscroll的destroy + me.on( 'destroy', function() { + me.$content.iScroll('destroy'); + } ); + } ); + + return me; + }, + + /** + * 复写_fillWrapper方法,数据及按钮调整顺序 + * */ + _fillWrapper: function( listHtml ) { + + // 数据不是来自历史记录时隐藏清除历史记录按钮 + this.$clearBtn[ this.value() ? 'hide' : 'show' ](); + + if ( listHtml ) { + this.show().$scroller.html( listHtml ); + this.$content.iScroll( 'refresh' ); + + } else { + this.hide(); + } + + return this; + } + } ); + +})( gmu, gmu.$ ); +/** + * @file 位置自适应插件 + * @import widget/suggestion/suggestion.js, extend/event.ortchange.js + */ +(function( $, win ) { + var reverse = Array.prototype.reverse; + + // 指明sug list的item项selector,用于item项的反转 + // 基于list最外层的$content元素进行查找的 + gmu.Suggestion.options.listSelector = 'li'; + + /** + * 位置自适应插件,主要需求用于当sug放在页面底部时,需将sug翻转到上面来显示 + * @class posadapt + * @namespace Suggestion + * @pluginfor Suggestion + */ + gmu.Suggestion.register( 'posadapt', { + + _init: function() { + var me = this, + $list; + + me.on( 'show ortchange', function() { + + if ( me._checkPos() ) { + + me.$wrapper.css( 'top', - me.$wrapper.height()- me.wrapperTop ); + + // sug list反转 + reverse.call( $list = + me.$content.find( me._options.listSelector ) ); + $list.appendTo( $list.parent() ); + + // 调整按钮位置 + me.$btn.prependTo( me.$wrapper ); + } + + } ); + }, + + _checkPos: function() { + var sugH = this._options.height || 66, + upDis = this.getEl().offset().top - win.pageYOffset; + + // 当下边的高度小于sug的高度并且上边的高度大于sug的高度 + return $( win ).height() - upDis < sugH && upDis >= sugH; + } + + } ); +})( gmu.$, window ); +/** + * @file quickdelete插件 + * @import widget/suggestion/suggestion.js + */ +(function( gmu, $ ) { + + /** + * quickdelete插件 + * @class quickdelete + * @namespace Suggestion + * @pluginfor Suggestion + */ + gmu.Suggestion.register( 'quickdelete', { + + _init: function() { + var me = this, + $input, + ns; + + me.on( 'ready', function() { + $input = me.getEl(); + ns = me.eventNs; + + me.$mask.append( me.$quickDel = + $( '
          ' ) ); + + $input.on('focus' + ns + ' input' + ns, function() { + me[ '_quickDel' + + ($.trim( $input.val() ) ? 'Show' : 'Hide') ](); + }); + + $input.on( 'blur' + ns, function() { + me._quickDelHide(); + }); + + // 绑tap事件,touchend会失焦点,键盘收起,故绑touchstart并阻止默认行为 + me.$quickDel.on( 'touchstart' + ns, function( e ) { + e.preventDefault(); // 阻止默认事件,否则会触发blur,键盘收起 + e.formDelete = true; // suggestion解决删除问题 + $input.val(''); + me.trigger('delete').trigger('input')._quickDelHide(); + + // 中文输入时,focus失效 trace:FEBASE-779 + $input.blur().focus(); + } ); + + me.on( 'destroy', function() { + me.$quickDel.off().remove(); + } ); + } ); + }, + + _quickDelShow: function() { + + if ( !this.quickDelShow ) { + + gmu.staticCall( this.$quickDel.get(0), + 'css', 'visibility', 'visible' ); + + this.quickDelShow = true + } + }, + + _quickDelHide: function() { + + if ( this.quickDelShow ) { + + gmu.staticCall( this.$quickDel.get(0), + 'css', 'visibility', 'hidden' ); + + this.quickDelShow = false + } + } + } ); + +})( gmu, gmu.$ ); +/** + * @file compatData + * @import widget/suggestion/suggestion.js + */ +(function( $, win ) { + + // 是否兼容1.x版本中的历史数据 + gmu.Suggestion.options.compatdata = true; + + + /** + * compatdata插件,兼容用户历史localstorge,gmu 1.x版本用户搜索历史通过','分隔数据,为了解决','不能被存入的问题,现在采用encodeURIComponent(',')来存入数据,故需要兼容老的历史数据。该配置项为true,则开启数据兼容处理 + * @class compatdata + * @namespace Suggestion + * @pluginfor Suggestion + */ + gmu.Suggestion.option( 'compatdata', true, function() { + + this.on( 'ready', function() { + var key = this.key, + flagKey = 'SUG-History-DATATRANS', + localdata, + dataArr; + + try { + localdata = win.localStorage[ key ]; + + // 兼容老数据,以前以“,”分隔localstorage中的数据,现在改为encodeURIComponent(',')分隔 + if ( localdata && !win.localStorage[ flagKey ] ) { + + // 存储是否转换过历史数据的标记 + win.localStorage[ flagKey ] = '\u001e'; + + dataArr = localdata.split( ',' ); + win.localStorage[ key ] = dataArr.join( this.separator ); + } + + }catch ( e ) { + console.log( e.message ); + } + } ) + } ); +})( gmu.$, window ); +/** + * @file renderList + * @import widget/suggestion/suggestion.js, extend/highlight.js + */ +(function( $ ) { + + $.extend( gmu.Suggestion.options, { + + /** + * @property {Boolean} [isHistory=true] 是否在localstorage中存储用户查询记录,相当于2.0.5以前版本中的isStorage + * @namespace options + * @for Suggestion + * @uses Suggestion.renderlist + */ + isHistory: true, + + /** + * @property {Boolean} [usePlus=false] 是否使用+来使sug item进入input框 + * @namespace options + * @for Suggestion + * @uses Suggestion.renderlist + */ + usePlus: false, + + /** + * @property {Number} [listCount=5] sug列表条数 + * @namespace options + * @for Suggestion + * @uses Suggestion.renderlist + */ + listCount: 5, + + /** + * @property {Function} [renderlist=null] 自定义渲染列表函数,可以覆盖默认渲染列表的方法 + * @namespace options + * @for Suggestion + * @uses Suggestion.renderlist + */ + renderlist: null + } ); + + /** + * renderList,提供默认列表渲染,若需要自己渲染sug列表,即renderList为Function类型,则不需要使用此插件
          + * 默认以jsonp发送请求,当用户在option中配置了renderList时,需要调用用e.preventDefault来阻默认请求数据方法 + * @class renderlist + * @namespace Suggestion + * @pluginfor Suggestion + */ + gmu.Suggestion.option( 'renderlist', function() { + + // 当renderList不是Function类型时,该option操作生效 + return $.type( this._options.renderlist ) !== 'function'; + + }, function() { + + var me = this, + $xssElem = $( '
          '), + _xssFilter = function( str ) { + return $xssElem.text( str ).html(); + }, + + // 渲染sug list列表,返回list array + _createList = function( query, sugs ) { + var opts = me._options, + html = [], + str = '', + sug, + len, + i; + + if ( !sugs || !sugs.length ) { + me.hide(); + return html; + } + + sugs = sugs.slice( 0, opts.listCount ); + + // 防止xss注入,通过text()方法转换一下 + query = _xssFilter( query || '' ); + + // sug列表渲染比较频繁,故不采用模板来解析 + for ( i = 0, len = sugs.length; i < len; i++ ) { + str = _xssFilter( sug = sugs[ i ] ); + + // 若是query为空则不需要进行替换 + query && (str = $.trim( sug ) + .replace( query, '' + query + '' )); + + opts.usePlus && + (str += '
          '); + + html.push( '
        • ' + str + '
        • ' ); + } + + return html; + }; + + me.on( 'ready', function() { + var me = this, + ns = me.eventNs, + $form = $( me._options.form || me.getEl().closest( 'form' )); + + // 绑定form的submit事件 + $form.size() && (me.$form = $form .on( 'submit' + ns, + function( e ) { + var submitEvent = gmu.Event('submit'); + + me._options.isHistory && + me._localStorage( me.value() ); + + me.trigger( submitEvent ); + + // 阻止表单默认提交事件 + submitEvent.isDefaultPrevented() && e.preventDefault(); + })); + + // todo 待验证,新闻页面不会有该bug,待排查原因,中文输入不跳转的bug + me.$content.on( 'touchstart' + ns, function(e) { + e.preventDefault(); + }); + + // 注册tap事件由于中文输入法时,touch事件不能submit + me.$content.on( 'tap' + ns, function(e) { + var $input = me.getEl(), + $elem = $( e.target ); + + // 点击加号,input值上框 + if ( $elem.hasClass( 'ui-suggestion-plus' ) ) { + $input.val( $elem.attr( 'data-item' ) ); + } else if ( $.contains( me.$content.get( 0 ), + $elem.get( 0 ) ) ) { + + // 点击sug item, 防止使用tap造成穿透 + setTimeout( function() { + $input.val( $elem.text() ); + me.trigger( 'select', $elem ) + .hide().$form.submit(); + }, 400 ); + } + }).highlight( 'ui-suggestion-highlight' ); + + me.on( 'destroy', function() { + $form.size() && $form.off( ns ); + me.$content.off(); + } ); + } ); + + me.on( 'renderlist', function( e, data, query, callback ) { + var ret = _createList( query, data ); + + // 回调渲染suglist + return callback( ret.length ? + '
            ' + ret.join( ' ' ) + '
          ' : '' ); + } ); + } ); + +})( gmu.$ ); +/** + * @file sendRequest + * @import widget/suggestion/suggestion.js + */ + +(function( $, win ) { + + $.extend( gmu.Suggestion.options, { + + /** + * @property {Boolean} [isCache=true] 发送请求返回数据后是否缓存query请求结果 + * @namespace options + * @for Suggestion + * @uses Suggestion.sendrequest + */ + isCache: true, + + /** + * @property {String} [queryKey='wd'] 发送请求时query的key值 + * @namespace options + * @for Suggestion + * @uses Suggestion.sendrequest + */ + + queryKey: 'wd', + + /** + * @property {String} [cbKey='cb'] 发送请求时callback的name + * @namespace options + * @for Suggestion + * @uses Suggestion.sendrequest + */ + cbKey: 'cb', + + /** + * @property {Function} [sendrequest=null] 自定义发送请求函数,可以覆盖默认发送请求的方法 + * @namespace options + * @for Suggestion + * @uses Suggestion.sendrequest + */ + sendrequest: null + } ); + + /** + * sendRequest,默认sendRequest为jsonp方式取数据,若用户自己用数据填充sug,即该option为Function类型,则不需要使用此插件
          + * 默认以jsonp发送请求,当用户在option中配置了sendRequest时,需要调用用e.preventDefault来阻默认请求数据方法 + * @class sendrequest + * @namespace Suggestion + * @pluginfor Suggestion + */ + gmu.Suggestion.option( 'sendrequest', function() { + + // 当sendRequest不是Function类型时,该option操作生效 + return $.type( this._options.sendrequest ) !== 'function'; + + }, function() { + var me = this, + opts = me._options, + queryKey = opts.queryKey, + cbKey = opts.cbKey, + param = opts.param, + isCache = opts.isCache, + cdata; + + this.on( 'sendrequest', function( e, query, callback, cacheData ) { + + var url = opts.source, + + // 以date作为后缀,应该不会重复,故不作origin + cb = 'suggestion_' + (+new Date()); + + // 若缓存中存数请求的query数据,则不发送请求 + if ( isCache && (cdata = cacheData( query )) ) { + callback( query, cdata ); + return me; + + } + + // 替换url后第一个参数的连接符?&或&为? + url = (url + '&' + queryKey + '=' + encodeURIComponent( query )) + .replace( /[&?]{1,2}/, '?' ); + + !~url.indexOf( '&' + cbKey ) && (url += '&' + cbKey + '=' + cb); + + param && (url += '&' + param); + + win[ cb ] = function( data ) { + + /* + * 渲染数据并缓存请求数据 + * 返回的数据格式如下: + * { + * q: "a", + * p: false, + * s: ["angelababy", "akb48", "after school", + * "android", "angel beats!", "a pink", "app"] + * } + */ + callback( query, data.s ); + + // 缓存请求的query + isCache && cacheData( query, data.s ); + + delete win[ cb ]; + }; + + // 以jsonp形式发送请求 + $.ajax({ + url: url, + dataType: 'jsonp' + }); + + return me; + } ); + + } ); +})( gmu.$, window ); +/** + * @file 选项卡组件 + * @import extend/touch.js, core/widget.js, extend/highlight.js, extend/event.ortchange.js + * @importCSS transitions.css, loading.css + * @module GMU + */ + +(function( gmu, $, undefined ) { + var _uid = 1, + uid = function(){ + return _uid++; + }, + idRE = /^#(.+)$/; + + /** + * 选项卡组件 + * + * @class Tabs + * @constructor Html部分 + * ```html + *
          + * + *
          content1
          + *
          + *
          content3
          + *
          + * ``` + * + * javascript部分 + * ```javascript + * $('#tabs').tabs(); + * ``` + * @param {dom | zepto | selector} [el] 用来初始化Tab的元素 + * @param {Object} [options] 组件配置项。具体参数请查看[Options](#GMU:Tabs:options) + * @grammar $( el ).tabs( options ) => zepto + * @grammar new gmu.Tabs( el, options ) => instance + */ + gmu.define( 'Tabs', { + options: { + + /** + * @property {Number} [active=0] 初始时哪个为选中状态,如果时setup模式,如果第2个li上加了ui-state-active样式时,active值为1 + * @namespace options + */ + active: 0, + + /** + * @property {Array} [items=null] 在render模式下需要必须设置 格式为\[{title:\'\', content:\'\', href:\'\'}\], href可以不设,可以用来设置ajax内容 + * @namespace options + */ + items:null, + + /** + * @property {String} [transition='slide'] 设置切换动画,目前只支持slide动画,或无动画 + * @namespace options + */ + transition: 'slide' + }, + + template: { + nav:'
            '+ + '<% var item; for(var i=0, length=items.length; i'+ + ' class="ui-state-active"<% } %>><%=item.title%>'+ + '<% } %>
          ', + content:'
          ' + + '<% var item; for(var i=0, length=items.length; i'+ + ' id="<%=item.id%>"<% } %> class="ui-tabs-panel <%=transition%><% if(i==active){ %> ui-state-active<% } %>"><%=item.content%>
          '+ + '<% } %>
          ' + }, + + _init:function () { + var me = this, _opts = me._options, $el, eventHandler = $.proxy(me._eventHandler, me); + + me.on( 'ready', function(){ + $el = me.$el; + $el.addClass('ui-tabs'); + _opts._nav.on('tap', eventHandler).children().highlight('ui-state-hover'); + } ); + + $(window).on('ortchange', eventHandler); + }, + + _create:function () { + var me = this, _opts = me._options; + + if( me._options.setup && me.$el.children().length > 0 ) { + me._prepareDom('setup', _opts); + } else { + _opts.setup = false; + me.$el = me.$el || $('
          '); + me._prepareDom('create', _opts); + } + }, + + _prepareDom:function (mode, _opts) { + var me = this, content, $el = me.$el, items, nav, contents, id; + switch (mode) { + case 'setup': + _opts._nav = me._findElement('ul').first(); + if(_opts._nav) { + _opts._content = me._findElement('div.ui-tabs-content'); + _opts._content = ((_opts._content && _opts._content.first()) || $('
          ').appendTo($el)).addClass('ui-viewport ui-tabs-content'); + items = []; + _opts._nav.addClass('ui-tabs-nav').children().each(function(){ + var $a = me._findElement('a', this), href = $a?$a.attr('href'):$(this).attr('data-url'), id, $content; + id = idRE.test(href)? RegExp.$1: 'tabs_'+uid(); + ($content = me._findElement('#'+id) || $('
          ')) + .addClass('ui-tabs-panel'+(_opts.transition?' '+_opts.transition:'')) + .appendTo(_opts._content); + items.push({ + id: id, + href: href, + title: $a?$a.attr('href', 'javascript:;').text():$(this).text(),//如果href不删除的话,地址栏会出现,然后一会又消失。 + content: $content + }); + }); + _opts.items = items; + _opts.active = Math.max(0, Math.min(items.length-1, _opts.active || $('.ui-state-active', _opts._nav).index()||0)); + me._getPanel().add(_opts._nav.children().eq(_opts.active)).addClass('ui-state-active'); + break; + } //if cannot find the ul, switch this to create mode. Doing this by remove the break centence. + default: + items = _opts.items = _opts.items || []; + nav = []; + contents = []; + _opts.active = Math.max(0, Math.min(items.length-1, _opts.active)); + $.each(items, function(key, val){ + id = 'tabs_'+uid(); + nav.push({ + href: val.href || '#'+id, + title: val.title + }); + contents.push({ + content: val.content || '', + id: id + }); + items[key].id = id; + }); + _opts._nav = $( this.tpl2html( 'nav', {items: nav, active: _opts.active} ) ).prependTo($el); + _opts._content = $( this.tpl2html( 'content', {items: contents, active: _opts.active, transition: _opts.transition} ) ).appendTo($el); + _opts.container = _opts.container || ($el.parent().length ? null : 'body'); + } + _opts.container && $el.appendTo(_opts.container); + me._fitToContent(me._getPanel()); + }, + + _getPanel: function(index){ + var _opts = this._options; + return $('#' + _opts.items[index === undefined ? _opts.active : index].id); + }, + + _findElement:function (selector, el) { + var ret = $(el || this.$el).find(selector); + return ret.length ? ret : null; + }, + + _eventHandler:function (e) { + var match, _opts = this._options; + switch(e.type) { + case 'ortchange': + this.refresh(); + break; + default: + if((match = $(e.target).closest('li', _opts._nav.get(0))) && match.length) { + e.preventDefault(); + this.switchTo(match.index()); + } + } + }, + + _fitToContent: function(div) { + var _opts = this._options, $content = _opts._content; + _opts._plus === undefined && (_opts._plus = parseFloat($content.css('border-top-width'))+parseFloat($content.css('border-bottom-width'))) + $content.height( div.height() + _opts._plus); + return this; + }, + + /** + * 切换到某个Tab + * @method switchTo + * @param {Number} index Tab编号 + * @chainable + * @return {self} 返回本身。 + */ + switchTo: function(index) { + var me = this, _opts = me._options, items = _opts.items, eventData, to, from, reverse, endEvent; + if(!_opts._buzy && _opts.active != (index = Math.max(0, Math.min(items.length-1, index)))) { + to = $.extend({}, items[index]);//copy it. + to.div = me._getPanel(index); + to.index = index; + + from = $.extend({}, items[_opts.active]);//copy it. + from.div = me._getPanel(); + from.index = _opts.active; + + eventData = gmu.Event('beforeActivate'); + me.trigger(eventData, to, from); + if(eventData.isDefaultPrevented()) return me; + + _opts._content.children().removeClass('ui-state-active'); + to.div.addClass('ui-state-active'); + _opts._nav.children().removeClass('ui-state-active').eq(to.index).addClass('ui-state-active'); + if(_opts.transition) { //use transition + _opts._buzy = true; + endEvent = $.fx.animationEnd + '.tabs'; + reverse = index>_opts.active?'':' reverse'; + _opts._content.addClass('ui-viewport-transitioning'); + from.div.addClass('out'+reverse); + to.div.addClass('in'+reverse).on(endEvent, function(e){ + if (e.target != e.currentTarget) return //如果是冒泡上来的,则不操作 + to.div.off(endEvent, arguments.callee);//解除绑定 + _opts._buzy = false; + from.div.removeClass('out reverse'); + to.div.removeClass('in reverse'); + _opts._content.removeClass('ui-viewport-transitioning'); + me.trigger('animateComplete', to, from); + me._fitToContent(to.div); + }); + } + _opts.active = index; + me.trigger('activate', to, from); + _opts.transition || me._fitToContent(to.div); + } + return me; + }, + + /** + * 当外部修改tabs内容好,需要调用refresh让tabs自动更新高度 + * @method refresh + * @chainable + * @return {self} 返回本身。 + */ + refresh: function(){ + return this._fitToContent(this._getPanel()); + }, + + /** + * 销毁组件 + * @method destroy + */ + destroy:function () { + var _opts = this._options, eventHandler = this._eventHandler; + _opts._nav.off('tap', eventHandler).children().highlight(); + _opts.swipe && _opts._content.off('swipeLeft swipeRight', eventHandler); + + if( !_opts.setup ) { + this.$el.remove(); + } + return this.$super('destroy'); + } + + /** + * @event ready + * @param {Event} e gmu.Event对象 + * @description 当组件初始化完后触发。 + */ + + /** + * @event beforeActivate + * @param {Event} e gmu.Event对象 + * @param {Object} to 包含如下属性:div(内容div), index(位置), title(标题), content(内容), href(链接) + * @param {Object} from 包含如下属性:div(内容div), index(位置), title(标题), content(内容), href(链接) + * @description 内容切换之前触发,可以通过e.preventDefault()来阻止 + */ + + /** + * @event activate + * @param {Event} e gmu.Event对象 + * @param {Object} to 包含如下属性:div(内容div), index(位置), title(标题), content(内容), href(链接) + * @param {Object} from 包含如下属性:div(内容div), index(位置), title(标题), content(内容), href(链接) + * @description 内容切换之后触发 + */ + + /** + * @event animateComplete + * @param {Event} e gmu.Event对象 + * @param {Object} to 包含如下属性:div(内容div), index(位置), title(标题), content(内容), href(链接) + * @param {Object} from 包含如下属性:div(内容div), index(位置), title(标题), content(内容), href(链接) + * @description 动画完成后执行,如果没有设置动画,此时间不会触发 + */ + + /** + * @event destroy + * @param {Event} e gmu.Event对象 + * @description 组件在销毁的时候触发 + */ + }); +})( gmu, gmu.$ ); +/** + * @file ajax插件 + * @import widget/tabs/tabs.js + */ +(function ($, undefined) { + var idRE = /^#.+$/, + loaded = {}, + tpl = { + loading: '
          Loading
          ', + error: '

          内容加载失败!

          ' + }; + + /** + * 在a上面href设置的是地址,而不是id,则组件认为这个为ajax类型的。在options上传入ajax对象可以配置[ajax选项](#$.ajax) + * @class ajax + * @namespace Tabs + * @pluginfor Tabs + */ + gmu.Tabs.register( 'ajax', { + _init:function () { + var _opts = this._options, items, i, length; + + this.on( 'ready', function(){ + items = _opts.items; + for (i = 0, length = items.length; i < length; i++) { + items[i].href && !idRE.test(items[i].href) && (items[i].isAjax = true); + } + this.on('activate', this._onActivate); + items[_opts.active].isAjax && this.load(_opts.active);//如果当前是ajax + } ); + }, + + destroy:function () { + this.off('activate', this._onActivate); + this.xhr && this.xhr.abort(); + return this.origin(); + }, + + _fitToContent: function(div) { + var _opts = this._options; + + if(!_opts._fitLock)return this.origin(div); + }, + + _onActivate:function (e, to) { + to.isAjax && this.load(to.index); + }, + + /** + * 加载内容,指定的tab必须是ajax类型。加载的内容会缓存起来,如果要强行再次加载,第二个参数传入true + * @method load + * @param {Number} index Tab编号 + * @param {Boolean} [force=false] 是否强制重新加载 + * @for Tabs + * @uses Tabs.ajax + * @return {self} 返回本身。 + */ + load:function (index, force) { + var me = this, _opts = me._options, items = _opts.items, item, $panel, prevXHR; + + if (index < 0 || + index > items.length - 1 || + !(item = items[index]) || //如果范围错误 + !item.isAjax || //如果不是ajax类型的 + ( ( $panel = me._getPanel(index)).text() && !force && loaded[index] ) //如果没有加载过,并且tab内容为空 + )return this; + + (prevXHR = me.xhr) && setTimeout(function(){//把切出去没有加载玩的xhr abort了 + prevXHR.abort(); + }, 400); + + _opts._loadingTimer = setTimeout(function () {//如果加载在50ms内完成了,就没必要再去显示 loading了 + $panel.html(tpl.loading); + }, 50); + + _opts._fitLock = true; + + me.xhr = $.ajax($.extend(_opts.ajax || {}, { + url:item.href, + context:me.$el.get(0), + beforeSend:function (xhr, settings) { + var eventData = gmu.Event('beforeLoad'); + me.trigger(eventData, xhr, settings); + if (eventData.isDefaultPrevented())return false; + }, + success:function (response, xhr) { + var eventData = gmu.Event('beforeRender'); + clearTimeout(_opts._loadingTimer);//清除显示loading的计时器 + me.trigger(eventData, response, $panel, index, xhr)//外部可以修改data,或者直接把pannel修改了 + if (!eventData.isDefaultPrevented()) { + $panel.html(response); + } + _opts._fitLock = false; + loaded[index] = true; + me.trigger('load', $panel); + delete me.xhr; + me._fitToContent($panel); + }, + error:function () { + var eventData = gmu.Event('loadError'); + clearTimeout(_opts._loadingTimer);//清除显示loading的计时器 + loaded[index] = false; + me.trigger(eventData, $panel); + if(!eventData.isDefaultPrevented()){ + $panel.html(tpl.error); + } + delete me.xhr; + } + })); + } + + /** + * @event beforeLoad + * @param {Event} e gmu.Event对象 + * @param {Object} xhr xhr对象 + * @param {Object} settings ajax请求的参数 + * @description 在请求前触发,可以通过e.preventDefault()来取消此次ajax请求 + * @for Tabs + * @uses Tabs.ajax + */ + + /** + * @event beforeRender + * @param {Event} e gmu.Event对象 + * @param {Object} response 返回值 + * @param {Object} panel 对应的Tab内容的容器 + * @param {Number} index Tab的序号 + * @param {Object} xhr xhr对象 + * @description ajax请求进来数据,在render到div上之前触发,对于json数据,可以通过此方来自行写render,然后通过e.preventDefault()来阻止,将response输出在div上 + * @for Tabs + * @uses Tabs.ajax + */ + + /** + * @event load + * @param {Event} e gmu.Event对象 + * @param {Zepto} panel 对应的Tab内容的容器 + * @description 当ajax请求到的内容过来后,平已经Render到div上了后触发 + * @for Tabs + * @uses Tabs.ajax + */ + + /** + * @event loadError + * @param {Event} e gmu.Event对象 + * @param {Zepto} panel 对应的Tab内容的容器 + * @description 当ajax请求内容失败时触发,如果此事件被preventDefault了,则不会把自带的错误信息Render到div上 + * @for Tabs + * @uses Tabs.ajax + */ + } ); +})(Zepto); + +/** + * @file 左右滑动手势插件 + * @import widget/tabs/tabs.js + */ + +(function ($, undefined) { + var durationThreshold = 1000, // 时间大于1s就不算。 + horizontalDistanceThreshold = 30, // x方向必须大于30 + verticalDistanceThreshold = 70, // y方向上只要大于70就不算 + scrollSupressionThreshold = 30, //如果x方向移动大于这个直就禁掉滚动 + tabs = [], + eventBinded = false, + isFromTabs = function (target) { + for (var i = tabs.length; i--;) { + if ($.contains(tabs[i], target)) return true; + } + return false; + } + + function tabsSwipeEvents() { + $(document).on('touchstart.tabs', function (e) { + var point = e.touches ? e.touches[0] : e, start, stop; + + start = { + x:point.clientX, + y:point.clientY, + time:Date.now(), + el:$(e.target) + } + + $(document).on('touchmove.tabs',function (e) { + var point = e.touches ? e.touches[0] : e, xDelta; + if (!start)return; + stop = { + x:point.clientX, + y:point.clientY, + time:Date.now() + } + if ((xDelta = Math.abs(start.x - stop.x)) > scrollSupressionThreshold || + xDelta > Math.abs(start.y - stop.y)) { + isFromTabs(e.target) && e.preventDefault(); + } else {//如果系统滚动开始了,就不触发swipe事件 + $(document).off('touchmove.tabs touchend.tabs'); + } + }).one('touchend.tabs', function () { + $(document).off('touchmove.tabs'); + if (start && stop) { + if (stop.time - start.time < durationThreshold && + Math.abs(start.x - stop.x) > horizontalDistanceThreshold && + Math.abs(start.y - stop.y) < verticalDistanceThreshold) { + start.el.trigger(start.x > stop.x ? "tabsSwipeLeft" : "tabsSwipeRight"); + } + } + start = stop = undefined; + }); + }); + } + + /** + * 添加 swipe功能,zepto的swipeLeft, swipeRight不太准,所以在这另外实现了一套。 + * @class swipe + * @namespace Tabs + * @pluginfor Tabs + */ + gmu.Tabs.register( 'swipe', { + _init:function () { + var _opts = this._options; + + this.on( 'ready', function(){ + tabs.push(_opts._content.get(0)); + eventBinded = eventBinded || (tabsSwipeEvents(), true); + this.$el.on('tabsSwipeLeft tabsSwipeRight', $.proxy(this._eventHandler, this)); + } ); + }, + _eventHandler:function (e) { + var _opts = this._options, items, index; + switch (e.type) { + case 'tabsSwipeLeft': + case 'tabsSwipeRight': + items = _opts.items; + if (e.type == 'tabsSwipeLeft' && _opts.active < items.length - 1) { + index = _opts.active + 1; + } else if (e.type == 'tabsSwipeRight' && _opts.active > 0) { + index = _opts.active - 1; + } + index !== undefined && (e.stopPropagation(), this.switchTo(index)); + break; + default://tap + return this.origin(e); + } + }, + destroy: function(){ + var _opts = this._options, idx; + ~(idx = $.inArray(_opts._content.get(0), tabs)) && tabs.splice(idx, 1); + this.$el.off('tabsSwipeLeft tabsSwipeRight', this._eventHandler); + tabs.length || ($(document).off('touchstart.tabs'), eventBinded = false); + return this.origin(); + } + } ); +})(Zepto); +/** + * @file 工具栏组件 + * @import core/widget.js + * @module GMU + */ +(function( gmu, $ ) { + /** + * 工具栏组件 + * + * @class Toolbar + * @constructor Html部分 + * ```html + *
          + * 返回 + *

          工具栏

          + * 百科 + * 知道 + *
          + * ``` + * + * javascript部分 + * ```javascript + * $('#J_toolbar').toolbar({}); + * ``` + * @param {dom | zepto | selector} [el] 用来初始化工具栏的元素 + * @param {Object} [options] 组件配置项。具体参数请查看[Options](#GMU:Toolbar:options) + * @grammar $( el ).toolbar( options ) => zepto + * @grammar new gmu.Toolbar( el, options ) => instance + */ + gmu.define( 'Toolbar', { + + options: { + + /** + * @property {Zepto | Selector | Element} [container=document.body] toolbar的最外层元素 + * @namespace options + */ + container: document.body, + + /** + * @property {String} [title='标题'] toolbar的标题 + * @namespace options + */ + title: '标题', + + /** + * @property {Array} [leftBtns] 标题左侧的按钮组,支持html、gmu button实例 + * @namespace options + */ + leftBtns: [], + + /** + * @property {Array} [rightBtns] 标题右侧的按钮组,支持html、gmu button实例 + * @namespace options + */ + rightBtns: [], + + /** + * @property {Boolean} [fixed=false] toolbar是否固定位置 + * @namespace options + */ + fixed: false + }, + + _init: function() { + var me = this, + opts = me._options, + $el; + + // 设置container的默认值 + if( !opts.container ) { + opts.container = document.body; + } + + me.on( 'ready', function() { + $el = me.$el; + + if( opts.fixed ) { + // TODO 元素id的处理 + var placeholder = $( '
          ' ).height( $el.offset().height ). + insertBefore( $el ).append( $el ).append( $el.clone().css({'z-index': 1, position: 'absolute',top: 0}) ), + top = $el.offset().top, + check = function() { + document.body.scrollTop > top ? $el.css({position:'fixed', top: 0}) : $el.css('position', 'absolute'); + }, + offHandle; + + $(window).on( 'touchmove touchend touchcancel scroll scrollStop', check ); + $(document).on( 'touchend touchcancel', offHandle = function() { + setTimeout( function() { + check(); + }, 200 ); + } ); + me.on( 'destroy', function() { + $(window).off('touchmove touchend touchcancel scroll scrollStop', check); + $(document).off('touchend touchcancel', offHandle); + + // 删除placeholder,保留原来的Toolbar节点 + $el.insertBefore(placeholder); + placeholder.remove(); + me._removeDom(); + } ); + + check(); + } + } ); + + me.on( 'destroy', function() { + me._removeDom(); + } ); + }, + + _create: function() { + var me = this, + opts = me._options, + $el = me.getEl(), + container = $( opts.container ), + children = [], + btnGroups = me.btnGroups = { + left: [], + right: [] + }, + currentGroup = btnGroups['left']; + + // render方式,需要先创建Toolbar节点 + if( !opts.setup ) { + ($el && $el.length > 0) ? + $el.appendTo(container) : // 如果el是一个HTML片段,将其插入container中 + ($el = me.$el = $('
          ').appendTo( container )); // 否则,创建一个空div,将其插入container中 + } + + // 从DOM中取出按钮组 + children = $el.children(); + $toolbarWrap = $el.find('.ui-toolbar-wrap'); + if( $toolbarWrap.length === 0 ){ + $toolbarWrap = $('
          ').appendTo($el); + }else{ + children = $toolbarWrap.children(); + } + + children.forEach( function( child ) { + $toolbarWrap.append(child); + + /^[hH]/.test( child.tagName ) ? + (currentGroup = btnGroups['right'], me.title = child) : + currentGroup.push( child ); + } ); + + // 创建左侧按钮组的容器 + var leftBtnContainer = $toolbarWrap.find('.ui-toolbar-left'); + var rightBtnContainer = $toolbarWrap.find('.ui-toolbar-right'); + if( leftBtnContainer.length === 0 ) { + leftBtnContainer = children.length ? $('
          ').insertBefore(children[0]) : $('
          ').appendTo($toolbarWrap); + btnGroups['left'].forEach( function( btn ) { + $(btn).addClass('ui-toolbar-button'); + leftBtnContainer.append( btn ); + } ); + + // 没有左侧容器,则认为也没有右侧容器,不需要再判断是否存在右侧容器 + rightBtnContainer = $('
          ').appendTo($toolbarWrap); + btnGroups['right'].forEach( function( btn ) { + $(btn).addClass('ui-toolbar-button'); + rightBtnContainer.append( btn ); + } ); + } + + $el.addClass( 'ui-toolbar' ); + $(me.title).length ? $(me.title).addClass( 'ui-toolbar-title' ) : $('

          ' + opts.title + '

          ').insertAfter(leftBtnContainer);; + + me.btnContainer = { + 'left': leftBtnContainer, + 'right': rightBtnContainer + }; + + me.addBtns( 'left', opts.leftBtns ); + me.addBtns( 'right', opts.rightBtns ); + }, + + _addBtn: function( container, btn ) { + var me = this; + + $( btn ).appendTo( container ).addClass('ui-toolbar-button'); + }, + + /** + * 添加按钮组 + * @method addBtns + * @param {String} [position=right] 按钮添加的位置,left或者right + * @param {Array} btns 要添加的按钮组,每个按钮可以是一个gmu Button实例,或者元素,或者HTML片段 + * @return {self} 返回本身 + */ + addBtns: function( position, btns ) { + var me = this, + btnContainer = me.btnContainer[position], + toString = Object.prototype.toString; + + // 向下兼容:如果没有传position,认为在右侧添加按钮 + if( toString.call(position) != '[object String]' ) { + btns = position; + btnContainer = me.btnContainer['right']; + } + + btns.forEach( function( btn, index ) { + // 如果是gmu组件实例,取实例的$el + if( btn instanceof gmu.Base ) { + btn = btn.getEl(); + } + me._addBtn( btnContainer, btn ); + }); + + return me; + }, + + /** + * 显示Toolbar + * @method show + * @return {self} 返回本身。 + */ + + /** + * @event show + * @param {Event} e gmu.Event对象 + * @description Toolbar显示时触发 + */ + show: function() { + var me = this; + + me.$el.show(); + me.trigger( 'show' ); + me.isShowing = true; + + return me; + }, + + /** + * 隐藏Toolbar + * @method hide + * @return {self} 返回本身。 + */ + + /** + * @event hide + * @param {Event} e gmu.Event对象 + * @description Toolbar隐藏时触发 + */ + hide: function() { + var me = this; + + me.$el.hide(); + me.trigger( 'hide' ); + me.isShowing = false; + + return me; + }, + + /** + * 交换Toolbar(显示/隐藏)状态 + * @method toggle + * @return {self} 返回本身。 + */ + toggle: function() { + var me = this; + + me.isShowing === false ? + me.show() : me.hide(); + + return me; + }, + + _removeDom: function(){ + var me = this, + $el = me.$el; + + if( me._options.setup === false ) { // 如果是通过render模式创建,移除节点 + $el.remove(); + } else { // 如果是通过setup模式创建,保留节点 + $el.css('position', 'static').css('top', 'auto'); + } + } + + + /** + * @event ready + * @param {Event} e gmu.Event对象 + * @description 当组件初始化完后触发。 + */ + + /** + * @event destroy + * @param {Event} e gmu.Event对象 + * @description 组件在销毁的时候触发 + */ + } ); +})( gmu, gmu.$ ); + +/** + * @file Toolbar fix插件 + * @module GMU + * @import widget/toolbar/toolbar.js, extend/fix.js + */ +(function( gmu, $ ) { + /** + * Toolbar position插件,调用position方法可以将Toolbar固定在某个位置。 + * + * @class position + * @namespace Toolbar + * @pluginfor Toolbar + */ + gmu.Toolbar.register( 'position', { + /** + * 定位Toolbar + * @method position + * @param {Object} opts 定位参数,格式与$.fn.fix参数格式相同 + * @for Toolbar + * @uses Toolbar.position + * @return {self} 返回本身。 + */ + position: function( opts ) { + this.$el.fix( opts ); + + return this; + } + } ); +})( gmu, gmu.$ ); +/** + * @file iOS5插件,适用于iOS5及以上 + * @import widget/refresh/refresh.js,extend/throttle.js + */ +(function( gmu, $, undefined ) { + + /** + * iOS5插件,支持iOS5和以上设备,使用系统自带的内滚功能 + * @class iOS5 + * @namespace Refresh + * @pluginfor Refresh + */ + /** + * @property {Number} [threshold=5] 加载的阀值,默认向上或向下拉动距离超过5px,即可触发拉动操作,该值只能为正值,若该值是10,则需要拉动距离大于15px才可触发加载操作 + * @namespace options + * @for Refresh + * @uses Refresh.iOS5 + */ + /** + * @property {Number} [topOffset=0] 上边缩进的距离,默认为refresh按钮的高度,建议不要修改 + * @namespace options + * @for Refresh + * @uses Refresh.iOS5 + */ + gmu.Refresh.register( 'iOS5', { + _init: function () { + var me = this, + opts = me._options, + $el = me.$el; + + $el.css({ + 'overflow': 'scroll', + '-webkit-overflow-scrolling': 'touch' + }); + opts.topOffset = opts['$upElem'] ? opts['$upElem'].height() : 0; + opts.iScroll = me._getiScroll(); + $el.get(0).scrollTop = opts.topOffset; + $el.on('touchstart touchmove touchend', $.proxy(me._eventHandler, me)); + }, + _changeStyle: function (dir, state) { + var me = this, + opts = me._options, + refreshInfo = opts.refreshInfo[dir]; + + me.origin(dir, state); + switch (state) { + case 'loaded': + refreshInfo['$icon'].addClass('ui-refresh-icon'); + opts._actDir = ''; + break; + case 'beforeload': + refreshInfo['$label'].html('松开立即加载'); + refreshInfo['$icon'].addClass('ui-refresh-flip'); + break; + case 'loading': + refreshInfo['$icon'].removeClass().addClass('ui-loading'); + break; + } + return me; + }, + + _scrollStart: function (e) { + var me = this, + opts = me._options, + topOffset = opts.topOffset, + $upElem = opts.$upElem, + wrapper = me.$el.get(0), + _scrollFn = function () { + clearTimeout(opts.topOffsetTimer); + if ($upElem && $upElem.length && wrapper.scrollTop <= topOffset && !opts['_upRefreshed']) { + + wrapper.scrollTop = topOffset; + } + }; + + me.trigger('scrollstart', e); + me._enableScroll()._bindScrollStop(wrapper, _scrollFn); //保证wrapper不会滑到最底部或最顶部,使其处于可滑动状态 + opts.maxScrollY = wrapper.offsetHeight - wrapper.scrollHeight; + opts._scrollFn = _scrollFn; + + return me; + }, + + _scrollMove: function () { + var me = this, + opts = me._options, + up = opts.$upElem && opts.$upElem.length , + down = opts.$downElem && opts.$downElem.length, + wrapper = me.$el.get(0), + threshold = opts.threshold || 5; + + me._scrollMove = function (e) { + var maxScrollY = opts.maxScrollY, + scrollY = wrapper.scrollTop, + lastMoveY = opts.lastMoveY || scrollY, + upRefreshed = opts['_upRefreshed'], + downRefreshed = opts['_downRefreshed'], + upStatus = me._status('up'), + downStatus = me._status('down'); + + if (up && !upStatus || down && !downStatus) return; //处于数据正在加载中,即上次加载还未完成,直接返回, 增加上下按钮的同时加载处理 traceID:FEBASE-569, trace:FEBASE-775 + opts.iScroll.deltaY = scrollY - lastMoveY; //每次在touchmove时更新偏移量的值 + if (downStatus && down && !downRefreshed && -scrollY < (maxScrollY - threshold)) { //下边按钮,上拉加载 + me._setMoveState('down', 'beforeload', 'pull'); + } else if (downStatus && down && downRefreshed && -scrollY > (maxScrollY - threshold) && -scrollY !== maxScrollY) { //下边按钮,上拉恢复 -scrollY !== maxScrollY for trace784 + me._setMoveState('down', 'loaded', 'restore'); + } else if (upStatus && up && !upRefreshed && -scrollY > threshold ) { //上边按钮,下拉加载 + me._setMoveState('up', 'beforeload', 'pull'); + } else if (upStatus && up && upRefreshed && -scrollY < threshold && scrollY) { //上边按钮,下拉恢复,scrollY !== 0 for trace784 + me._setMoveState('up', 'loaded', 'restore'); + } + + opts.lastMoveY = scrollY; + opts._moved = true; + return me.trigger('scrollmove', e, scrollY, scrollY - lastMoveY); + }; + me._scrollMove.apply(me, arguments); + }, + + _scrollEnd: function (e) { + var me = this, + opts = me._options, + wrapper = me.$el.get(0), + topOffset = opts.topOffset, + actDir = opts._actDir, + restoreDir = opts._restoreDir; + + /*上边的铵钮隐藏,隐藏条件分以下几种 + 1.上边按钮复原操作: restoreDir == 'up',延迟200ms + 2.上边按钮向下拉,小距离,未触发加载: scrollTop <= topOffset,延迟800ms + 3.上边按钮向下拉,小距离,未触发加载,惯性回弹:scrollTop <= topOffset,延迟800ms + 4.上边按钮向下拉,大距离,再回向上拉,惯性回弹scrollTop <= topOffset不触发,走touchstart时的绑定的scroll事件 + 5.上边按钮向下拉,触发加载,走action中的回弹 + */ + if ((restoreDir == 'up' || wrapper.scrollTop <= topOffset) && !actDir && opts._moved) { + me._options['topOffsetTimer'] = setTimeout( function () { + $(wrapper).off('scroll', opts._scrollFn); //scroll事件不需要再触发 + wrapper.scrollTop = topOffset; + }, 800); + } + + if (actDir && me._status(actDir)) { + me._setStyle(actDir, 'loading'); + me._loadingAction(actDir, 'pull'); + } + + opts._moved = false; + return me.trigger('scrollend', e); + }, + + _enableScroll: function () { + var me = this, + wrapper = me.$el.get(0), + scrollY = wrapper.scrollTop; + + scrollY <= 0 && (wrapper.scrollTop = 1); //滑动到最上方 + if (scrollY + wrapper.offsetHeight >= wrapper.scrollHeight) { //滑动到最下方 + wrapper.scrollTop = wrapper.scrollHeight - wrapper.offsetHeight - 1; + } + + return me; + }, + + _bindScrollStop: function (elem, fn) { + var me = this, + $elem = $(elem); + + $elem.off('scroll', me._options._scrollFn).on('scroll', $.debounce(100, function(){ + $elem.off('scroll', arguments.callee).one('scroll', fn); + }, false)); + + return me; + }, + + _getiScroll: function () { + var me = this, + $wrapper = me.$el, + wrapper = $wrapper[0]; + return { + el: wrapper, + deltaY: 0, + scrollTo: function (y, time, relative) { + if (relative) { + y = wrapper.scrollTop + y; + } + $wrapper.css({ + '-webkit-transition-property':'scrollTop', + '-webkit-transition-duration':y + 'ms' + }); + wrapper.scrollTop = y; + }, + + disable: function (destroy) { + destroy && me.destroy(); + $wrapper.css('overflow', 'hidden'); + }, + + enable:function () { + $wrapper.css('overflow', 'scroll'); + } + } + }, + + _setMoveState: function (dir, state, actType) { + var me = this, + opts = me._options; + + me._setStyle(dir, state); + opts['_' + dir + 'Refreshed'] = actType == 'pull'; + opts['_actDir'] = actType == 'pull' ? dir : ''; + opts['_restoreDir'] = dir == 'up' && actType == 'restore' ? dir : '' + return me; + }, + + _eventHandler: function (e) { + var me = this; + switch(e.type) { + case 'touchstart': + me._scrollStart(e); + break; + case 'touchmove': + me._scrollMove(e); + break; + case 'touchend': + me._scrollEnd(e); + break; + } + }, + afterDataLoading: function (dir) { + var me = this, + opts = me._options, + dir = dir || opts._actDir; + + opts['_' + dir + 'Refreshed'] = false; + dir == 'up' && (me.$el.get(0).scrollTop = opts.topOffset); + return me.origin(dir); + } + } ); +})( gmu, gmu.$ ); \ No newline at end of file diff --git a/dist/gmu.min.js b/dist/gmu.min.js new file mode 100644 index 00000000..1f341b3b --- /dev/null +++ b/dist/gmu.min.js @@ -0,0 +1,4 @@ +/* Gmu v2.1.0 */ +var gmu=gmu||{version:"@version",$:window.Zepto,staticCall:function(a){var b=a.fn,c=[].slice,d=a();return d.length=1,function(a,e){return d[0]=a,b[e].apply(d,c.call(arguments,2))}}(Zepto)};!function(a,b){function c(a,b,c){(a||"").split(i).forEach(function(a){c(a,b)})}function d(a){return new RegExp("(?:^| )"+a.replace(" "," .* ?")+"(?: |$)")}function e(a){var b=(""+a).split(".");return{e:b[0],ns:b.slice(1).sort().join(" ")}}function f(a,b,c,f){var g,h;return h=e(b),h.ns&&(g=d(h.ns)),a.filter(function(a){return!(!a||h.e&&a.e!==h.e||h.ns&&!g.test(a.ns)||c&&a.cb!==c&&a.cb._cb!==c||f&&a.ctx!==f)})}function g(a,c){return this instanceof g?(c&&b.extend(this,c),this.type=a,this):new g(a,c)}var h=[].slice,i=/\s+/,j=function(){return!1},k=function(){return!0};g.prototype={isDefaultPrevented:j,isPropagationStopped:j,preventDefault:function(){this.isDefaultPrevented=k},stopPropagation:function(){this.isPropagationStopped=k}},a.event={on:function(a,b,d){var f,g=this;return b?(f=this._events||(this._events=[]),c(a,b,function(a,b){var c=e(a);c.cb=b,c.ctx=d,c.ctx2=d||g,c.id=f.length,f.push(c)}),this):this},one:function(a,b,d){var e=this;return b?(c(a,b,function(a,b){var c=function(){return e.off(a,c),b.apply(d||e,arguments)};c._cb=b,e.on(a,c,d)}),this):this},off:function(a,b,d){var e=this._events;return e?a||b||d?(c(a,b,function(a,b){f(e,a,b,d).forEach(function(a){delete e[a.id]})}),this):(this._events=[],this):this},trigger:function(a){var b,c,d,e,i,j=-1;if(!this._events||!a)return this;if("string"==typeof a&&(a=new g(a)),b=h.call(arguments,1),a.args=b,b.unshift(a),c=f(this._events,a.type))for(e=c.length;++j/g,function(a,b){return"',"+b.replace(/\\'/,"'")+",'"}).replace(/<%([\s\S]+?)%>/g,function(a,b){return"');"+b.replace(/\\'/,"'").replace(/[\r\n\t]/g," ")+"__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+'\');}return __p.join("");',d=new Function("obj",c);return b?d(b):d}}(Zepto),function(a,b,c){function d(a){return"[object Object]"===o.call(a)}function e(a,b){a&&Object.keys(a).forEach(function(c){b(c,a[c])})}function f(a){try{a="true"===a?!0:"false"===a?!1:"null"===a?null:+a+""===a?+a:/(?:\{[\s\S]*\}|\[[\s\S]*\])$/.test(a)?JSON.parse(a):a}catch(b){a=c}return a}function g(a){for(var b,d,e={},g=a&&a.attributes,h=g&&g.length;h--;)d=g[h],b=d.name,"data-"===b.substring(0,5)&&(b=b.substring(5),d=f(d.value),d===c||(e[b]=d));return e}function h(e){var f=e.substring(0,1).toLowerCase()+e.substring(1),g=b.fn[f];b.fn[f]=function(f){var g,h,i=n.call(arguments,1),j="string"==typeof f&&f;return b.each(this,function(k,l){if(h=r(l,e)||new a[e](l,d(f)?f:c),"this"===j)return g=h,!1;if(j){if(!b.isFunction(h[j]))throw new Error("组件没有此方法:"+j);if(g=h[j].apply(h,i),g!==c&&g!==h)return!1;g=c}}),g!==c?g:this},b.fn[f].noConflict=function(){return b.fn[f]=g,this}}function i(a,c){var d=this;a.superClass&&i.call(d,a.superClass,c),e(r(a,"options"),function(a,e){e.forEach(function(e){var f=e[0],g=e[1];("*"===f||b.isFunction(f)&&f.call(d,c[a])||f===c[a])&&g.call(d)})})}function j(a,d){var f=this;a.superClass&&j.call(f,a.superClass,d),e(r(a,"plugins"),function(a,g){d[a]!==!1&&(e(g,function(a,d){var e;f[a]=b.isFunction(d)&&(e=f[a])?function(){var a,b=f.origin;return f.origin=e,a=d.apply(f,arguments),b===c?delete f.origin:f.origin=b,a}:d}),g._init.call(f))})}function k(){for(var a,c=n.call(arguments),e=c.length;e--;)a=a||c[e],d(c[e])||c.splice(e,1);return c.length?b.extend.apply(null,[!0,{}].concat(c)):a}function l(a,e,f,h,l){var m,n=this;return d(h)&&(l=h,h=c),l&&l.el&&(h=b(l.el)),h&&(n.$el=b(h),h=n.$el[0]),m=n._options=k(e.options,g(h),l),n.template=k(e.template,m.template),n.tpl2html=k(e.tpl2html,m.tpl2html),n.widgetName=a.toLowerCase(),n.eventNs="."+n.widgetName+f,n._init(m),n._options.setup=n.$el&&n.$el.parent()[0]?!0:!1,i.call(n,e,m),j.call(n,e,m),n._create(),n.trigger("ready"),h&&r(h,a,n)&&n.on("destroy",function(){r(h,a,null)}),n}function m(d,f,g){function h(a,b){if("Base"===d)throw new Error("Base类不能直接实例化");return this instanceof h?l.call(this,d,h,i++,a,b):new h(a,b)}"function"!=typeof g&&(g=a.Base);var i=1,j=1;return b.extend(h,{register:function(a,b){var c=r(h,"plugins")||r(h,"plugins",{});return b._init=b._init||p,c[a]=b,h},option:function(a,b,c){var d=r(h,"options")||r(h,"options",{});return d[a]||(d[a]=[]),d[a].push([b,c]),h},inherits:function(a){return m(d+"Sub"+j++,a,h)},extend:function(a){var b=h.prototype,d=g.prototype;q.forEach(function(b){a[b]=k(g[b],a[b]),a[b]&&(h[b]=a[b]),delete a[b]}),e(a,function(a,e){b[a]="function"==typeof e&&d[a]?function(){var b,f=this.$super;return this.$super=function(){var b=n.call(arguments,1);return d[a].apply(this,b)},b=e.apply(this,arguments),f===c?delete this.$super:this.$super=f,b}:e})}}),h.superClass=g,h.prototype=Object.create(g.prototype),h.extend(f),h}var n=[].slice,o=Object.prototype.toString,p=function(){},q=["options","template","tpl2html"],r=function(){var a={},b=0,d="_gid";return function(e,f,g){var h=e[d]||(e[d]=++b),i=a[h]||(a[h]={});return g!==c&&(i[f]=g),null===g&&delete i[f],i[f]}}(),s=a.event;a.define=function(b,c,d){a[b]=m(b,c,d),h(b)},a.isWidget=function(b,c){return c="string"==typeof c?a[c]||p:c,c=c||a.Base,b instanceof c},a.Base=m("Base",{_init:p,_create:p,getEl:function(){return this.$el},on:s.on,one:s.one,off:s.off,trigger:function(c){var d="string"==typeof c?new a.Event(c):c,e=[d].concat(n.call(arguments,1)),f=this._options[d.type],g=this.getEl();return f&&b.isFunction(f)&&!1===f.apply(this,e)&&(d.stopPropagation(),d.preventDefault()),s.trigger.apply(this,e),g&&g.triggerHandler(d,(e.shift(),e)),this},tpl2html:function(a,c){var d=this.template;return d="string"==typeof a?d[a]:(c=a,d),c||~d.indexOf("<%")?b.parseTpl(d,c):d},destroy:function(){this.$el&&this.$el.off(this.eventNs),this.trigger("destroy"),this.off(),this.destroyed=!0}},Object),b.ui=a}(gmu,gmu.$),function(a){a.extend(a,{throttle:function(b,c,d){function e(){function a(){g=Date.now(),c.apply(h,j)}function e(){f=void 0}var h=this,i=Date.now()-g,j=arguments;d&&!f&&a(),f&&clearTimeout(f),void 0===d&&i>b?a():f=setTimeout(d?e:a,void 0===d?b-i:b)}var f,g=0;return"function"!=typeof c&&(d=c,c=b,b=250),e._zid=c._zid=c._zid||a.proxy(c)._zid,e},debounce:function(b,c,d){return void 0===c?a.throttle(250,b,!1):a.throttle(b,c,void 0===d?!1:d!==!1)}})}(Zepto),function(a,b){function c(){a(b).on("scroll",a.debounce(80,function(){a(b).trigger("scrollStop")},!1))}function d(){a(b).off("scroll"),c()}c(),a(b).on("pageshow",function(c){c.persisted&&a(b).off("touchstart",d).one("touchstart",d)})}(Zepto,window),function(a){a.matchMedia=function(){var b=0,c="gmu-media-detect",d=a.fx.transitionEnd,e=a.fx.cssPrefix,f=a("").append("."+c+"{"+e+"transition: width 0.001ms; width: 0; position: absolute; clip: rect(1px, 1px, 1px, 1px);}\n").appendTo("head");return function(e){var g,h,i=c+b++,j=[];return f.append("@media "+e+" { #"+i+" { width: 1px; } }\n"),g=a('
          ').appendTo("body").on(d,function(){h.matches=1===g.width(),a.each(j,function(b,c){a.isFunction(c)&&c.call(h,h)})}),h={matches:1===g.width(),media:e,addListener:function(a){return j.push(a),this},removeListener:function(a){var b=j.indexOf(a);return~b&&j.splice(b,1),this}}}}()}(Zepto),$(function(){$.mediaQuery={ortchange:"screen and (width: "+window.innerWidth+"px)"},$.matchMedia($.mediaQuery.ortchange).addListener(function(){$(window).trigger("ortchange")})}),function(a,b){a.extend(a.fn,{fix:function(c){var d=this;if(d.attr("isFixed"))return d;d.css(c).css("position","fixed").attr("isFixed",!0);var e=a('
          ').appendTo("body"),f=e[0].getBoundingClientRect().top,g=function(){window.pageYOffset>0&&(e[0].getBoundingClientRect().top!==f&&(d.css("position","absolute"),h(),a(window).on("scrollStop",h),a(window).on("ortchange",h)),a(window).off("scrollStop",g),e.remove())},h=function(){d.css({top:window.pageYOffset+(c.bottom!==b?window.innerHeight-d.height()-c.bottom:c.top||0),left:c.right!==b?document.body.offsetWidth-d.width()-c.right:c.left||0}),"100%"==c.width&&d.css("width",document.body.offsetWidth)};return a(window).on("scrollStop",g),d}})}(Zepto),function(a,b,c){a.define("Add2desktop",{options:{icon:"",container:"",key:"_gmu_adddesktop_key",useFix:!0,position:{bottom:12,left:"50%"},beforeshow:function(a){this.key()&&a.preventDefault()},afterhide:function(){this.key(1)},_isShow:!1},_init:function(){var a=this;a.on("ready",function(){a.$el.find(".ui-add2desktop-close").on("click",function(){a.hide()}),a._options.useFix&&a.$el.fix(a._options.position),a.show()}),a.on("destroy",function(){a.$el.remove()})},_create:function(){var a,c=this,d=b.os.version&&b.os.version.substr(0,3)>4.1?"new":"old";if(b.os.version&&b.os.version.substr(0,3)>=7&&(d="iOS7"),c._options.setup){var e=c.$el.children("img").attr("src");e&&(c._options.icon=e)}a=c.$el||(c.$el=b("
          ")),a.addClass("ui-add2desktop").appendTo(c._options.container||(c.$el.parent().length?"":document.body)),a.html('

          先点击
          再"添加到主屏幕"

          ')},key:function(a){var b=window.localStorage;return a!==c?b.setItem(this._options.key,a):b.getItem(this._options.key)},show:function(){var c=this;if(!c._options._isShow){if(!b.os.ios||b.browser.uc||b.browser.qq||b.browser.chrome)return c;var d=new a.Event("beforeshow");if(c.trigger(d),d.isDefaultPrevented())return c;c.$el.css("display","block"),c._options._isShow=!0}return c},hide:function(){var a=this;return a._options._isShow&&(a.$el.css("display","none"),a._options._isShow=!1,a.trigger("afterhide")),a}})}(gmu,gmu.$),function(a){function b(){var a=c.attr("hl-cls");clearTimeout(d),c.removeClass(a).removeAttr("hl-cls"),c=null,e.off("touchend touchmove touchcancel",b)}var c,d,e=a(document);a.fn.highlight=function(f,g){return this.each(function(){var h=a(this);h.css("-webkit-tap-highlight-color","rgba(255,255,255,0)").off("touchstart.hl"),f&&h.on("touchstart.hl",function(i){var j;c=g?(j=a(i.target).closest(g,this))&&j.length&&j:h,c&&(c.attr("hl-cls",f),d=setTimeout(function(){c.addClass(f)},100),e.on("touchend touchmove touchcancel",b))})})}}(Zepto),function(a,b,c){a.define("Button",{options:{iconpos:"left"},template:{icon:'',text:'<%= text %>'},_getWrap:function(a){return a},_init:function(){var a=this;a.$el=a.$el===c?b("").appendTo(document.body):a.$el},_create:function(){var a=this,d=a._options,e=a.$wrap=a._getWrap(a.getEl()),f=e.is("input"),g=e.find(".ui-btn-text"),h=e.find(".ui-icon");d.label=d.label===c?e[f?"val":"text"]():d.label,f||d.label===c||!g.length&&(g=b(a.tpl2html("text",{text:d.label}))).appendTo(e.empty()),a.$label=g.length&&g,d.resetText=d.resetText||d.label,f||d.icon&&!h.length&&(h=b(a.tpl2html("icon",{name:d.icon}))).appendTo(e),a.$icon=h.length&&h,e.addClass("ui-btn "+(d.label&&d.icon?"ui-btn-icon-"+d.iconpos:d.label?"ui-btn-text-only":"ui-btn-icon-only")),d.state&&setTimeout(function(){a.state(d.state)},0)},state:function(a){if(a===c)return this._state;var b=this,d=b.$wrap,e=d.is("input"),f=b._options[a+"Text"];return b.$wrap.removeClass("ui-state-"+b._state).addClass("ui-state-"+a),f===c||(e?d:b.$label)[e?"val":"text"](f),b._state!==a&&b.trigger("statechange",a,b._state),b._state=a,b},toggle:function(){return this.state("active"===this._state?"reset":"active"),this}}),b(function(){b(document.body).highlight("ui-state-hover",".ui-btn:not(.ui-state-disabled)")})}(gmu,gmu.$),function(a,b){var c=0;a.Button.register("input",{_getWrap:function(a){var d,e,f;return a.is('input[type="checkbox"], input[type="radio"]')?(e=a.addClass("ui-hidden")[0],(d=e.id)||(e.id=d="input_btn_"+c++),f=b("label[for="+d+"]",e.form||e.ownerDocument||void 0),f.length||(f=b('').insertBefore(a)),a.prop("checked")&&(this._options.state="active"),f):a},toggle:function(){var a=this.$el;return a.is('input[type="radio"]')&&($radios=b("[name='"+a.attr("name")+"']",a[0].form||a[0].ownerDocument||void 0),$radios.button("state","reset")),this.origin.apply(this,arguments)},state:function(a){var b=this.$el;return b.is('input[type="checkbox"], input[type="radio"]')&&b.prop("disabled","disabled"===a),this.origin.apply(this,arguments)}}),b(function(){b(document.body).on("click.button","label.ui-btn:not(.ui-state-disabled)",function(){b("#"+this.getAttribute("for")).button("toggle")})})}(gmu,gmu.$),function(a){function b(a){return"tagName"in a?a:a.parentNode}function c(a,b,c,d){var e=Math.abs(a-b),f=Math.abs(c-d);return e>=f?a-b>0?"Left":"Right":c-d>0?"Up":"Down"}function d(){j=null,k.last&&(k.el.trigger("longTap"),k={})}function e(){j&&clearTimeout(j),j=null}function f(){g&&clearTimeout(g),h&&clearTimeout(h),i&&clearTimeout(i),j&&clearTimeout(j),g=h=i=j=null,k={}}var g,h,i,j,k={},l=750;a(document).ready(function(){var m,n;a(document.body).bind("touchstart",function(c){m=Date.now(),n=m-(k.last||m),k.el=a(b(c.touches[0].target)),g&&clearTimeout(g),k.x1=c.touches[0].pageX,k.y1=c.touches[0].pageY,n>0&&250>=n&&(k.isDoubleTap=!0),k.last=m,j=setTimeout(d,l)}).bind("touchmove",function(a){e(),k.x2=a.touches[0].pageX,k.y2=a.touches[0].pageY,Math.abs(k.x1-k.x2)>10&&a.preventDefault()}).bind("touchend",function(){e(),k.x2&&Math.abs(k.x1-k.x2)>30||k.y2&&Math.abs(k.y1-k.y2)>30?i=setTimeout(function(){k.el.trigger("swipe"),k.el.trigger("swipe"+c(k.x1,k.x2,k.y1,k.y2)),k={}},0):"last"in k&&(h=setTimeout(function(){var b=a.Event("tap");b.cancelTouch=f,k.el.trigger(b),k.isDoubleTap?(k.el.trigger("doubleTap"),k={}):g=setTimeout(function(){g=null,k.el.trigger("singleTap"),k={}},250)},0))}).bind("touchcancel",f),a(window).bind("scroll",f)}),["swipe","swipeLeft","swipeRight","swipeUp","swipeDown","doubleTap","tap","singleTap","longTap"].forEach(function(b){a.fn[b]=function(a){return this.bind(b,a)}})}(Zepto),function(a,b,c){var d,e=["01月","02月","03月","04月","05月","06月","07月","08月","09月","10月","11月","12月"],f=["日","一","二","三","四","五","六"],g=/^(\+|\-)?(\d+)(M|Y)$/i,h=function(a,b){return 32-new Date(a,b,32).getDate()},i=function(a,b){return new Date(a,b,1).getDay()},j=function(a,b){for(var c=""+a;c.length")),a.appendTo(this._options.container||(a.parent().length?"":document.body))},_eventHandler:function(a){var c,d,e,f,g,h=(this._options,(this._container||this.$el).get(0));switch(a.type){case"swipeLeft":case"swipeRight":return this.switchMonthTo(("swipeRight"==a.type?"-":"+")+"1M");case"change":return g=b(".ui-calendar-header .ui-calendar-year, .ui-calendar-header .ui-calendar-month",this._el),this.switchMonthTo(k(g.eq(1)),k(g.eq(0)));default:d=a.target,(c=b(d).closest(".ui-calendar-calendar tbody a",h))&&c.length?(a.preventDefault(),e=c.parent(),this._option("selectedDate",f=new Date(e.attr("data-year"),e.attr("data-month"),c.text())),this.trigger("select",f,b.calendar.formatDate(f),this),this.refresh()):(c=b(d).closest(".ui-calendar-prev, .ui-calendar-next",h))&&c.length&&(a.preventDefault(),this.switchMonthTo((c.is(".ui-calendar-prev")?"-":"+")+"1M"))}},_option:function(a,d){var e,f,g=this._options;if(d!==c){switch(a){case"minDate":case"maxDate":g[a]=d?b.calendar.parseDate(d):null;break;case"selectedDate":e=g.minDate,f=g.maxDate,d=b.calendar.parseDate(d),d=e&&e>d?e:f&&d>f?f:d,g._selectedYear=g._drawYear=d.getFullYear(),g._selectedMonth=g._drawMonth=d.getMonth(),g._selectedDay=d.getDate();break;case"date":this._option("selectedDate",d),g[a]=this._option("selectedDate");break;default:g[a]=d}return g._invalid=!0,this}return"selectedDate"==a?new Date(g._selectedYear,g._selectedMonth,g._selectedDay):g[a]},switchToToday:function(){var a=new Date;return this.switchMonthTo(a.getMonth(),a.getFullYear())},switchMonthTo:function(a,b){var c,d,e,f=this._options,h=this.minDate(),i=this.maxDate();return"[object String]"===Object.prototype.toString.call(a)&&g.test(a)?(c="-"==RegExp.$1?-parseInt(RegExp.$2,10):parseInt(RegExp.$2,10),d=RegExp.$3.toLowerCase(),a=f._drawMonth+("m"==d?c:0),b=f._drawYear+("y"==d?c:0)):(a=parseInt(a,10),b=parseInt(b,10)),e=new Date(b,a,1),e=h&&h>e?h:i&&e>i?i:e,a=e.getMonth(),b=e.getFullYear(),(a!=f._drawMonth||b!=f._drawYear)&&(this.trigger("monthchange",f._drawMonth=a,f._drawYear=b,this),f._invalid=!0,this.refresh()),this},refresh:function(){var a=this._options,c=this._container||this.$el,d=b.proxy(this._eventHandler,this);if(a._invalid)return b(".ui-calendar-calendar td:not(.ui-state-disabled), .ui-calendar-header a",c).highlight(),b(".ui-calendar-header select",c).off("change",d),c.empty().append(this._generateHTML()),b(".ui-calendar-calendar td:not(.ui-state-disabled), .ui-calendar-header a",c).highlight("ui-state-hover"),b(".ui-calendar-header select",c).on("change",d),a._invalid=!1,this},destroy:function(){var a=this._container||this.$el,c=this._eventHandler;return b(".ui-calendar-calendar td:not(.ui-state-disabled)",a).highlight(),b(".ui-calendar-header select",a).off("change",c),a.remove(),this.$super("destroy")},_generateHTML:function(){var a,b,c,d,e,g,j,k,l=this._options,m=l._drawYear,n=l._drawMonth,o=new Date,p=new Date(o.getFullYear(),o.getMonth(),o.getDate()),q=this.minDate(),r=this.maxDate(),s=this.selectedDate(),t="";for(c=isNaN(c=parseInt(l.firstDay,10))?0:c,t+=this._renderHead(l,m,n,q,r)+'',a=0;7>a;a++)d=(a+c)%7,t+="=5?' class="ui-calendar-week-end"':"")+">"+f[d]+"";for(t+='',g=h(m,n),e=(i(m,n)-c+7)%7,j=Math.ceil((e+g)/7),k=new Date(m,n,1-e),a=0;j>a;a++){for(t+="",b=0;7>b;b++)t+=this._renderDay(b,k,c,n,s,p,q,r),k.setDate(k.getDate()+1);t+=""}return t+="
           
          "},_renderHead:function(a,b,c,d,f){var g,h,i='
          ',j=new Date(b,c,-1),k=new Date(b,c+1,1);if(i+='<<
          ',a.yearChangeable){for(i+='"}else i+=''+b+"年";if(a.monthChangeable){for(i+='"}else i+=''+e[c]+"";return i+='
          >>
          '},_renderDay:function(a,b,c,d,e,f,g,h){var i,j=b.getMonth()!==d;return i=j||g&&g>b||h&&b>h,""+(j?" ":i?""+b.getDate()+"":""+b.getDate()+"")+""}}),d=a.Calendar.prototype,b.each(["maxDate","minDate","date","selectedDate"],function(a,b){d[b]=function(a){return this._option(b,a)}}),b.calendar={parseDate:function(a){var b=/^(\d{4})(?:\-|\/)(\d{1,2})(?:\-|\/)(\d{1,2})$/;return"[object Date]"===Object.prototype.toString.call(a)?a:b.test(a)?new Date(parseInt(RegExp.$1,10),parseInt(RegExp.$2,10)-1,parseInt(RegExp.$3,10)):null},formatDate:function(a){return a.getFullYear()+"-"+j(a.getMonth()+1,2)+"-"+j(a.getDate(),2)}}}(gmu,gmu.$),function(a,b){function c(a,d){var e,f=b(''),g=b('
          确认 取消
          '),h=b(".ui-slideup",g),i=b(".frame",h),j={refresh:function(a){g.css({top:window.pageYOffset+"px",height:window.innerHeight+"px"}),h.animate({translateY:"-"+h.height()+"px",translateZ:"0"},400,"ease-out",function(){a&&a.call(j)})},close:function(d){var e=c.count=c.count-1;return g.off("click.slideup"+k),h.animate({translateY:"0",translateZ:"0"},200,"ease-out",function(){d&&d(),f.replaceWith(a),g.remove(),0===e&&b(document).off("touchmove.slideup")}).find(".ok-btn, .no-btn").highlight(),j}},k=c.id=(c.id>>>0)+1;return i.append(a.replaceWith(f)),e=c.count=(c.count>>>0)+1,1===e&&b(document).on("touchmove.slideup",function(a){a.preventDefault()}),g.on("click.slideup"+k,".ok-btn, .no-btn",function(){d.call(j,b(this).is(".ok-btn"))!==!1&&j.close()}).appendTo(document.body).find(".ok-btn, .no-btn").highlight("ui-state-hover"),j.refresh(),j}a.Calendar.register("picker",{_create:function(){var a=this.$el;if(!a)throw new Error("请指定日期选择器的赋值对象")},_init:function(){var a=this.$el,c=this._options;this._container=b("
          "),c.date||(c.date=a[a.is("select, input")?"val":"text"]()),b(window).on("ortchange",b.proxy(this._eventHandler,this)),this.on("commit",function(c,d){var e=b.calendar.formatDate(d);a[a.is("select, input")?"val":"text"](e)}),this.on("destroy",function(){b(window).off("ortchange",this._eventHandler),this._frame&&this._frame.close()})},_eventHandler:function(a){"ortchange"===a.type?this._frame&&this._frame.refresh():this.origin(a)},show:function(){var a,d=this;return this._visible?this:(a=this._container,this._visible=!0,this.refresh(),this._frame=c(a,function(a){var c;return a?(c=d._option("selectedDate"),d.trigger("commit",c,b.calendar.formatDate(c),d),d._option("date",c)):d._option("selectedDate",d._option("date")),d.hide(),!1}),this.trigger("show",this))},hide:function(){var b,c=this;return this._visible?(b=new a.Event("beforehide"),this.trigger(b,this),b.isDefaultPrevented()?this:(this._visible=!1,this._frame.close(function(){c.trigger&&c.trigger("hide")}),this._frame=null,this)):this}})}(gmu,gmu.$),function(a,b,c){var d={close:'',mask:'
          ',title:'

          <%=title%>

          ',wrap:'
          <% if(btns){ %>
          <% for(var i=0, length=btns.length; i<%=item.text%><% } %>
          <% } %>
          '};a.define("Dialog",{options:{autoOpen:!0,buttons:null,closeBtn:!0,mask:!0,width:300,height:"auto",title:null,content:null,scrollMove:!0,container:null,maskClick:null,position:null},getWrap:function(){return this._options._wrap},_init:function(){var a,c=this,e=c._options,f=0,g=b.proxy(c._eventHandler,c),h={};c.on("ready",function(){e._container=b(e.container||document.body),(e._cIsBody=e._container.is("body"))||e._container.addClass("ui-dialog-container"),h.btns=a=[],e.buttons&&b.each(e.buttons,function(b){a.push({index:++f,text:b,key:b})}),e._mask=e.mask?b(d.mask).appendTo(e._container):null,e._wrap=b(b.parseTpl(d.wrap,h)).appendTo(e._container),e._content=b(".ui-dialog-content",e._wrap),e._title=b(d.title),e._close=e.closeBtn&&b(d.close).highlight("ui-dialog-close-hover"),c.$el=c.$el||e._content,c.title(e.title),c.content(e.content),a.length&&b(".ui-dialog-btns .ui-btn",e._wrap).highlight("ui-state-hover"),e._wrap.css({width:e.width,height:e.height}),b(window).on("ortchange",g),e._wrap.on("click",g),e._mask&&e._mask.on("click",g),e.autoOpen&&c.open()})},_create:function(){var a=this._options;this._options.setup&&(a.content=a.content||this.$el.show(),a.title=a.title||this.$el.attr("title"))},_eventHandler:function(a){var c,d,e,f=this,g=f._options;switch(a.type){case"ortchange":this.refresh();break;case"touchmove":g.scrollMove&&a.preventDefault();break;case"click":if(g._mask&&(b.contains(g._mask[0],a.target)||g._mask[0]===a.target))return f.trigger("maskClick");d=g._wrap.get(0),(c=b(a.target).closest(".ui-dialog-close",d))&&c.length?f.close():(c=b(a.target).closest(".ui-dialog-btns .ui-btn",d))&&c.length&&(e=g.buttons[c.attr("data-key")],e&&e.apply(f,arguments))}},_calculate:function(){var a,c,d=this,e=d._options,f=document.body,g={},h=e._cIsBody,i=Math.round;return e.mask&&(g.mask=h?{width:"100%",height:Math.max(f.scrollHeight,f.clientHeight)-1}:{width:"100%",height:"100%"}),a=e._wrap.offset(),c=b(window),g.wrap={left:"50%",marginLeft:-i(a.width/2)+"px",top:h?i(c.height()/2)+window.pageYOffset:"50%",marginTop:-i(a.height/2)+"px"},g},refresh:function(){var a,c,d=this,e=d._options;return e._isOpen&&(c=function(){a=d._calculate(),a.mask&&e._mask.css(a.mask),e._wrap.css(a.wrap)},b.os.ios&&document.activeElement&&/input|textarea|select/i.test(document.activeElement.tagName)?(document.body.scrollLeft=0,setTimeout(c,200)):c()),d},open:function(a,d){var e=this._options;return e._isOpen=!0,e._wrap.css("display","block"),e._mask&&e._mask.css("display","block"),a!==c&&this.position?this.position(a,d):this.refresh(),b(document).on("touchmove",b.proxy(this._eventHandler,this)),this.trigger("open")},close:function(){var a,c=this._options;return a=b.Event("beforeClose"),this.trigger(a),a.defaultPrevented?this:(c._isOpen=!1,c._wrap.css("display","none"),c._mask&&c._mask.css("display","none"),b(document).off("touchmove",this._eventHandler),this.trigger("close"))},title:function(a){var b=this._options,d=a!==c;return d&&(a=(b.title=a)?"

          "+a+"

          ":a,b._title.html(a)[a?"prependTo":"remove"](b._wrap),b._close&&b._close.prependTo(b.title?b._title:b._wrap)),d?this:b.title},content:function(a){var b=this._options,d=a!==c;return d&&b._content.empty().append(b.content=a),d?this:b.content},destroy:function(){var a=this._options,c=this._eventHandler;return b(window).off("ortchange",c),b(document).off("touchmove",c),a._wrap.off("click",c).remove(),a._mask&&a._mask.off("click",c).remove(),a._close&&a._close.highlight(),this.$super("destroy")}})}(gmu,gmu.$),function(a){function b(b){return this.each(function(c){var e=a(this),f=a.isFunction(b)?b.call(this,c,e.offset()):b,g=e.css("position"),h="absolute"===g||"fixed"===g||e.position();"relative"===g&&(h.top-=parseFloat(e.css("top"))||-1*parseFloat(e.css("bottom"))||0,h.left-=parseFloat(e.css("left"))||-1*parseFloat(e.css("right"))||0),parentOffset=e.offsetParent().offset(),props={top:d(f.top-(h.top||0)-parentOffset.top),left:d(f.left-(h.left||0)-parentOffset.left)},"static"==g&&(props.position="relative"),f.using?f.using.call(this,props,c):e.css(props)})}var c=a.fn.offset,d=Math.round;a.fn.offset=function(a){return a?b.call(this,a):c.call(this)}}(Zepto),function(a){function b(a,b){return(parseInt(a,10)||0)*(k.test(a)?b/100:1)}function c(a,c,d,e){return["right"===a[0]?d:"center"===a[0]?d/2:0,"bottom"===a[1]?e:"center"===a[1]?e/2:0,b(c[0],d),b(c[1],e)]}function d(a){var b=a[0],c=b.preventDefault;return b=b.touches&&b.touches[0]||b,9===b.nodeType||b===window||c?{width:c?0:a.width(),height:c?0:a.height(),top:b.pageYOffset||b.pageY||0,left:b.pageXOffset||b.pageX||0}:a.offset()}function e(b){var c=a(b=b||window),e=d(c);return b=c[0],{$el:c,width:e.width,height:e.height,scrollLeft:b.pageXOffset||b.scrollLeft,scrollTop:b.pageYOffset||b.scrollTop}}function f(a,b){["my","at"].forEach(function(c){var d=(a[c]||"").split(" "),e=a[c]=["center","center"],f=b[c]=[0,0];1===d.length&&d[j.test(d[0])?"unshift":"push"]("center"),i.test(d[0])&&(e[0]=RegExp.$1)&&(f[0]=RegExp.$2),j.test(d[1])&&(e[1]=RegExp.$1)&&(f[1]=RegExp.$2)})}var g=a.fn.position,h=Math.round,i=/^(left|center|right)([\+\-]\d+%?)?$/,j=/^(top|center|bottom)([\+\-]\d+%?)?$/,k=/%$/;a.fn.position=function(b){if(!b||!b.of)return g.call(this);b=a.extend({},b);var i,j=a(b.of),k=b.collision,l=k&&e(b.within),m={},n=d(j),o={left:n.left,top:n.top};return j[0].preventDefault&&(b.at="left top"),f(b,m),i=c(b.at,m.at,n.width,n.height),o.left+=i[0]+i[2],o.top+=i[1]+i[3],this.each(function(){var d=a(this),e=d.offset(),f=a.extend({},o),g=c(b.my,m.my,e.width,e.height);f.left=h(f.left+g[2]-g[0]),f.top=h(f.top+g[3]-g[1]),k&&k.call(this,f,{of:n,offset:e,my:b.my,at:b.at,within:l,$el:d}),f.using=b.using,d.offset(f)})}}(Zepto),function(a,b){a.Dialog.register("position",{_init:function(){var a=this._options;a.position=a.position||{of:a.container||window,at:"center",my:"center"}},position:function(a,c){var d=this._options;return b.isPlainObject(a)?b.extend(d.position,a):d.position.at="left"+(a>0?"+"+a:a)+" top"+(c>0?"+"+c:c),this.refresh()},_calculate:function(){var a=this,c=a._options,d=c.position,e=a.origin();return c._wrap.position(b.extend(d,{using:function(a){e.wrap=a}})),e}})}(gmu,gmu.$),function(a,b,c){a.define("Popover",{options:{container:null,content:null,event:"click"},template:{frame:"
          "},_create:function(){var a=this,c=a._options,d=c.target&&b(c.target)||a.getEl(),e=c.container&&b(c.container);e&&e.length||(e=b(a.tpl2html("frame")).addClass("ui-mark-temp")),a.$root=e,c.content&&a.setContent(c.content),a.trigger("done.dom",e.addClass("ui-"+a.widgetName),c),e.parent().length||d.after(e),a.target(d)},_checkTemp:function(a){a.is(".ui-mark-temp")&&a.off(this.eventNs)&&a.remove()},show:function(){var b=this,c=a.Event("beforeshow");return b.trigger(c),c.isDefaultPrevented()?void 0:(b.trigger("placement",b.$root.addClass("ui-in"),b.$target),b._visible=!0,b.trigger("show"))},hide:function(){var b=this,c=new a.Event("beforehide");return b.trigger(c),c.isDefaultPrevented()?void 0:(b.$root.removeClass("ui-in"),b._visible=!1,b.trigger("hide"))},toggle:function(){var a=this;return a[a._visible?"hide":"show"].apply(a,arguments)},target:function(a){if(a===c)return this.$target;var d=this,e=b(a),f=d.$target,g=d._options.event+d.eventNs;return f&&f.off(g),d.$target=e.on(g,function(a){a.preventDefault(),d.toggle()}),d},setContent:function(a){var b=this.$root;return b.empty().append(a),this},destroy:function(){var a=this;return a.$target.off(a.eventNs),a._checkTemp(a.$root),a.$super("destroy")}})}(gmu,gmu.$),function(a,b){a.define("Dropmenu",{options:{content:null},template:{item:'
        • href="<%= href %>"<% } %>><% if ( icon ) { %><% } %><%= text %>
        • ',divider:'
        • ',wrap:"
            "},_init:function(){var a=this;a.on("done.dom",function(b,c){a.$list=c.find("ul").first().addClass("ui-dropmenu-items").highlight("ui-state-hover",".ui-dropmenu-items>li:not(.divider)")})},_create:function(){var c=this,d=c._options,e="";"array"===b.type(d.content)&&(d.content.forEach(function(a){a=b.extend({href:"",icon:"",text:""},"string"==typeof a?{text:a}:a),e+=c.tpl2html("divider"===a.text?"divider":"item",a)}),d.content=b(c.tpl2html("wrap")).append(e)),c.$super("_create"),c.$list.on("click"+c.eventNs,".ui-dropmenu-items>li:not(.ui-state-disable):not(.divider)",function(b){var d=a.Event("itemclick",b);c.trigger(d,this),d.isDefaultPrevented()||c.hide()})}},a.Popover)}(gmu,gmu.$),function(a){a.Dropmenu.options.horizontal=!0,a.Dropmenu.option("horizontal",!0,function(){var a=this; +a.on("done.dom",function(a,b){b.addClass("ui-horizontal")})})}(gmu,gmu.$),function(a,b){b.extend(a.Dropmenu.options,{placement:"bottom",align:"center",offset:null}),a.Dropmenu.option("placement",function(a){return~["top","bottom"].indexOf(a)},function(){function a(a,b){return"right"===a||"bottom"===a?b:"center"===a?b/2:0}function c(b,c,e,f,g){var h=d.of,i=d.coord,j=d.offset,k=h.top,l=h.left;return l+=a(c,h.width)-a(f,i.width),k+=a(e,h.height)-a(g,i.height),j="function"==typeof j?j.call(null,{left:l,top:k},b):j||{},{left:l+(j.left||0),top:k+(j.top||0)}}var d,e={top_center:"center top center bottom",top_left:"left top left bottom",top_right:"right top right bottom",bottom_center:"center bottom center top",bottom_right:"right bottom right top",bottom_left:"left bottom left top"},f={};b.each(e,function(a,b){b=b.split(/\s/g),b.unshift(a),f[a]=function(){return c.apply(null,b)}}),this.on("placement",function(a,b,c){var e,g=this,h=g._options,i=h.placement,j=h.align;d={coord:b.offset(),of:c.offset(),placement:i,align:j,$el:b,$of:c,offset:h.offset},e=f[i+"_"+j](),g.trigger("before.placement",e,d,f),/^(\w+)_(\w+)$/.test(d.preset)&&(d.placement=RegExp.$1,d.align=RegExp.$2),b.offset(e),g.trigger("after.placement",e,d)})})}(gmu,gmu.$),function(a,b,c){a.define("Gotop",{options:{container:"",useFix:!0,useHide:!0,useAnimation:!1,position:{bottom:10,right:10},afterScroll:null},_init:function(){var a,c,d=this,e=d._options;b.os.version&&b.os.version.substr(0,3)>=7&&(e.position.bottom=40),d.on("ready",function(){a=d.$el,c=b.proxy(d._eventHandler,d),e.useHide&&b(document).on("touchmove",c),b(window).on("touchend touchcancel scrollStop",c),b(window).on("scroll ortchange",c),a.on("click",c),d.on("destroy",function(){b(window).off("touchend touchcancel scrollStop",c),b(document).off("touchmove",c),b(window).off("scroll ortchange",c)}),e.useFix&&a.fix(e.position),e.root=a[0]}),d.on("destroy",function(){d.$el.remove()})},_create:function(){var a=this;return a.$el||(a.$el=b("
            ")),a.$el.addClass("ui-gotop").append("
            ").appendTo(a._options.container||(a.$el.parent().length?"":document.body)),a},_eventHandler:function(a){var b=this;switch(a.type){case"touchmove":b.hide();break;case"scroll":clearTimeout(b._options._TID);break;case"touchend":case"touchcancel":clearTimeout(b._options._TID),b._options._TID=setTimeout(function(){b._check.call(b)},300);break;case"scrollStop":b._check();break;case"ortchange":b._check.call(b);break;case"click":b._scrollTo()}},_check:function(a){var b=this;return(a!==c?a:window.pageYOffset)>document.documentElement.clientHeight?b.show():b.hide(),b},_scrollTo:function(){var a=this,b=window.pageYOffset;return a.hide(),clearTimeout(a._options._TID),a._options.useAnimation?a._options.moveToTop=setInterval(function(){b>1?(window.scrollBy(0,-Math.min(150,b-1)),b-=150):(clearInterval(a._options.moveToTop),a.trigger("afterScroll"))},25,!0):(window.scrollTo(0,1),a.trigger("afterScroll")),a},show:function(){return this._options.root.style.display="block",this},hide:function(){return this._options.root.style.display="none",this}})}(gmu,gmu.$),function(a,b){a.define("Historylist",{options:{container:document.body,deleteSupport:!0,items:[]},template:{wrap:'
              ',item:'
            • <%=context%>

            • ',clear:'

              清空搜索历史

              '},_init:function(){var a=this,b=a._options;a.$el=b.container=b.container||document.body,a.items=[],a.on("ready",function(){a._bindUI()}),a.on("itemDelete",function(){0===a.items.length&&a.hide()})},_create:function(){var a=this,c=a._options;a.$el.hide(),a.$wrap=b(a.tpl2html("wrap")).appendTo(c.container),a.$clear=b(a.tpl2html("clear")).appendTo(c.container),!a._options.deleteSupport&&a.$clear.hide(),a.addItems(c.items),a.show()},_filterItemsById:function(a,b){var c=this;c.items.forEach(function(d,e){return d.id===a?(b.call(c,d,e),void 0):void 0})},_bindUI:function(){var c,d,e,f,g,h,i,j,k,l,m,n,o,p,q=this,r=!1;q.$clear.on("tap"+q.eventNs,function(b){setTimeout(function(){a.Dialog({closeBtn:!1,buttons:{"清空":function(){q.clear(),this.destroy()},"取消":function(){this.destroy()}},title:"清空历史",content:"

              是否清空搜索历史?

              ",open:function(){this._options._wrap.addClass("ui-historylist-dialog")}})},10),b.preventDefault(),b.stopPropagation()}),q.$wrap.on("tap"+q.eventNs,function(a){if(!q._options.deleteSupport){if(d=b(a.target),!d.hasClass("ui-historylist-itemwrap")&&!(d=d.parents(".ui-historylist-itemwrap")).length)return d=null,void 0;e=d.parent().attr("data-id"),q._filterItemsById(e,function(a){q.trigger("itemTouch",{item:a.value})})}}),q.$wrap.on("touchstart"+q.eventNs,function(a){if(q._options.deleteSupport){if(c=a.touches[0],d=b(c.target),f=a.timeStamp,j=i=parseInt(c.pageX),l=k=parseInt(c.pageY),o=!1,r=!1,!d.hasClass("ui-historylist-itemwrap")&&!(d=d.parents(".ui-historylist-itemwrap")).length)return d=null,void 0;d.addClass("ui-historylist-ontap"),d.css("width",d.width()-parseInt(d.css("border-left-width"))-parseInt(d.css("border-right-width")))}}),q.$wrap.on("touchmove"+q.eventNs,function(a){if(d){if(j=a.touches[0].pageX,l=a.touches[0].pageY,void 0===h&&(h=setTimeout(function(){r=Math.abs(l-k)>Math.abs(j-i)/2?!1:!0},10)),o=o||(j-i>=3||l-k>=3?!0:!1),!r)return setTimeout(function(){d&&d.removeClass("ui-historylist-ontap")},150),void 0;n=(j-i)/q.$wrap.width(),d.addClass("ui-historylist-itemmoving"),d.removeClass("ui-historylist-ontap"),d.css("-webkit-transform","translate3d("+(j-i)+"px, 0, 0)"),d.css("opacity",1-n),a.preventDefault(),a.stopPropagation()}}),q.$wrap.on("touchend"+q.eventNs+" touchcancel"+q.eventNs,function(a){d&&(clearTimeout(h),h=void 0,e=d.parent().attr("data-id"),g=a.timeStamp,m=(j-i)/(g-f),p=Math.abs(j-i),d.removeClass("ui-historylist-ontap"),d.removeClass("ui-historylist-itemmoving"),p.1&&r||p>=q.$wrap.width()/3&&r?q.removeItem(e,d):(d.css("width","auto"),d.css("-webkit-transform","translate3d(0, 0, 0)"),d.css("opacity",1),!o&&3>p&&q._filterItemsById(e,function(a){q.trigger("itemTouch",{item:a.value})})),d=null)})},show:function(){var a=this;if(0!==a.items.length)return a.sync===!1&&(a.$wrap.html(""),a.addItems(a.syncitems),a.sync=!0),a.$el.show(),a.isShow=!0,a},hide:function(){var a=this;return a.$el.hide(),a.isShow=!1,a},_getItemId:function(){var a=this;return void 0===a._itemId?a._itemId=1:++a._itemId,"__dd__"+a._itemId},_getFormatItem:function(a){var b=this;return"[object String]"===Object.prototype.toString.call(a)?{context:a,value:a,id:b._getItemId()}:{context:a.context||a.value,value:a.value||a.context,id:b._getItemId()}},addItem:function(a){var c=this,a=c._getFormatItem(a);return c.items.forEach(function(d,e){return d.value===a.value?(c.items.splice(e,1),b(c.$wrap.children()[e]).remove(),void 0):void 0}),0===c.$wrap.children().length?c.$wrap.append(c.tpl2html("item",a)):b(c.tpl2html("item",a)).insertBefore(c.$wrap.children()[0]),c.items.unshift(a),c},addItems:function(a){var b=this;return a.forEach(function(a){b.addItem(a)}),b},update:function(a){var b=this;return b.isShow?(b.$wrap.html(""),b.addItems(a),b.sync=!0):(b.syncitems=a,b.sync=!1),b},removeItem:function(a,b){var c,d,e,f=this;d=b.css("-webkit-transform"),e=/translate3d\((.*?),.*/.test(d)?RegExp.$1:0,c=parseInt(e,10)>=0?b.width():-b.width(),b.css("-webkit-transform","translate3d("+c+"px, 0, 0)"),b.on("transitionEnd"+f.eventNs+" webkitTransitionEnd"+f.eventNs,function(){b.parent().remove(),f._filterItemsById(a,function(a,b){f.items.splice(b,1),f.trigger("itemDelete",{item:a.value})})})},clear:function(){var a=this;return a.$wrap.html(""),a.items=[],a.sync=!0,a.hide(),a.trigger("clear"),a},disableDelete:function(){var a=this;return a._options.deleteSupport=!1,a.$clear.hide(),a},enableDelete:function(){var a=this;return a._options.deleteSupport=!0,a.$clear.show(),a},destroy:function(){var a=this;return a.$wrap.off(a.eventNs),a.$clear.off(a.eventNs),a.$wrap.remove(),a.$clear.remove(),a.$super("destroy")}})}(gmu,gmu.$),function(a,b,c){a.define("Navigator",{options:{content:null,event:"click"},template:{list:"
                ",item:'
              • href="<%= href %>"<% } %>><%= text %>
              • '},_create:function(){var a,d,e=this,f=e._options,g=e.getEl(),h=g.find("ul").first(),i="ui-"+e.widgetName;!h.length&&f.content?(h=b(e.tpl2html("list")),a=e.tpl2html("item"),d="",f.content.forEach(function(c){c=b.extend({href:"",text:""},"string"==typeof c?{text:c}:c),d+=a(c)}),h.append(d).appendTo(g)):(g.is("ul, ol")&&(h=g.wrap("
                "),g=g.parent()),f.index===c&&(f.index=h.find(".ui-state-active").index(),~f.index||(f.index=0))),e.$list=h.addClass(i+"-list"),e.trigger("done.dom",g.addClass(i),f),h.highlight("ui-state-hover","li"),h.on(f.event+e.eventNs,"li:not(.ui-state-disable)>a",function(a){e._switchTo(b(this).parent().index(),a)}),e.index=-1,e.switchTo(f.index)},_switchTo:function(b,c){if(b!==this.index){var d,e=this,f=e.$list.children(),g=a.Event("beforeselect",c);if(e.trigger(g,f.get(b)),!g.isDefaultPrevented())return d=f.removeClass("ui-state-active").eq(b).addClass("ui-state-active"),e.index=b,e.trigger("select",b,d[0])}},switchTo:function(a){return this._switchTo(~~a)},unselect:function(){this.index=-1,this.$list.children().removeClass("ui-state-active")},getIndex:function(){return this.index}})}(gmu,gmu.$),function(a,b){function c(a){return""===g?a:(a=a.charAt(0).toUpperCase()+a.substr(1),g+a)}var d=Math,e=[],f=b.createElement("div").style,g=function(){for(var a,b="webkitT,MozT,msT,OT,t".split(","),c=0,d=b.length;d>c;c++)if(a=b[c]+"ransform",a in f)return b[c].substr(0,b[c].length-1);return!1}(),h=g?"-"+g.toLowerCase()+"-":"",i=c("transform"),j=c("transitionProperty"),k=c("transitionDuration"),l=c("transformOrigin"),m=c("transitionTimingFunction"),n=(c("transitionDelay"),/android/gi.test(navigator.appVersion)),o=/hp-tablet/gi.test(navigator.appVersion),p=c("perspective")in f,q="ontouchstart"in a&&!o,r=!!g,s=c("transition")in f,t="onorientationchange"in a?"orientationchange":"resize",u=q?"touchstart":"mousedown",v=q?"touchmove":"mousemove",w=q?"touchend":"mouseup",x=q?"touchcancel":"mouseup",y=function(){if(g===!1)return!1;var a={"":"transitionend",webkit:"webkitTransitionEnd",Moz:"transitionend",O:"otransitionend",ms:"MSTransitionEnd"};return a[g]}(),z=function(){return a.requestAnimationFrame||a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame||a.msRequestAnimationFrame||function(a){return setTimeout(a,1)}}(),A=function(){return a.cancelRequestAnimationFrame||a.webkitCancelAnimationFrame||a.webkitCancelRequestAnimationFrame||a.mozCancelRequestAnimationFrame||a.oCancelRequestAnimationFrame||a.msCancelRequestAnimationFrame||clearTimeout}(),B=p?" translateZ(0)":"",C=function(c,d){var e,f=this;f.wrapper="object"==typeof c?c:b.getElementById(c),f.wrapper.style.overflow="hidden",f.scroller=f.wrapper.children[0],f.translateZ=B,f.options={hScroll:!0,vScroll:!0,x:0,y:0,bounce:!0,bounceLock:!1,momentum:!0,lockDirection:!0,useTransform:!0,useTransition:!1,topOffset:0,checkDOMChanges:!1,handleClick:!0,onRefresh:null,onBeforeScrollStart:function(a){a.preventDefault()},onScrollStart:null,onBeforeScrollMove:null,onScrollMove:null,onBeforeScrollEnd:null,onScrollEnd:null,onTouchEnd:null,onDestroy:null};for(e in d)f.options[e]=d[e];f.x=f.options.x,f.y=f.options.y,f.options.useTransform=r&&f.options.useTransform,f.options.useTransition=s&&f.options.useTransition,f.scroller.style[j]=f.options.useTransform?h+"transform":"top left",f.scroller.style[k]="0",f.scroller.style[l]="0 0",f.options.useTransition&&(f.scroller.style[m]="cubic-bezier(0.33,0.66,0.66,1)"),f.options.useTransform?f.scroller.style[i]="translate("+f.x+"px,"+f.y+"px)"+B:f.scroller.style.cssText+=";position:absolute;top:"+f.y+"px;left:"+f.x+"px",f.refresh(),f._bind(t,a),f._bind(u),f.options.checkDOMChanges&&(f.checkDOMTime=setInterval(function(){f._checkDOMChanges()},500))};C.prototype={enabled:!0,x:0,y:0,steps:[],scale:1,currPageX:0,currPageY:0,pagesX:[],pagesY:[],aniTime:null,isStopScrollAction:!1,handleEvent:function(a){var b=this;switch(a.type){case u:if(!q&&0!==a.button)return;b._start(a);break;case v:b._move(a);break;case w:case x:b._end(a);break;case t:b._resize();break;case y:b._transitionEnd(a)}},_checkDOMChanges:function(){this.moved||this.animating||this.scrollerW==this.scroller.offsetWidth*this.scale&&this.scrollerH==this.scroller.offsetHeight*this.scale||this.refresh()},_resize:function(){var a=this;setTimeout(function(){a.refresh()},n?200:0)},_pos:function(a,b){a=this.hScroll?a:0,b=this.vScroll?b:0,this.options.useTransform?this.scroller.style[i]="translate("+a+"px,"+b+"px) scale("+this.scale+")"+B:(a=d.round(a),b=d.round(b),this.scroller.style.left=a+"px",this.scroller.style.top=b+"px"),this.x=a,this.y=b},_start:function(b){var c,e,f,g=this,h=q?b.touches[0]:b;g.enabled&&(g.options.onBeforeScrollStart&&g.options.onBeforeScrollStart.call(g,b),g.options.useTransition&&g._transitionTime(0),g.moved=!1,g.animating=!1,g.distX=0,g.distY=0,g.absDistX=0,g.absDistY=0,g.dirX=0,g.dirY=0,g.isStopScrollAction=!1,g.options.momentum&&(g.options.useTransform?(c=getComputedStyle(g.scroller,null)[i].replace(/[^0-9\-.,]/g,"").split(","),e=+c[4],f=+c[5]):(e=+getComputedStyle(g.scroller,null).left.replace(/[^0-9-]/g,""),f=+getComputedStyle(g.scroller,null).top.replace(/[^0-9-]/g,"")),(d.round(e)!=d.round(g.x)||d.round(f)!=d.round(g.y))&&(g.isStopScrollAction=!0,g.options.useTransition?g._unbind(y):A(g.aniTime),g.steps=[],g._pos(e,f),g.options.onScrollEnd&&g.options.onScrollEnd.call(g))),g.startX=g.x,g.startY=g.y,g.pointX=h.pageX,g.pointY=h.pageY,g.startTime=b.timeStamp||Date.now(),g.options.onScrollStart&&g.options.onScrollStart.call(g,b),g._bind(v,a),g._bind(w,a),g._bind(x,a))},_move:function(a){var b=this,c=q?a.touches[0]:a,e=c.pageX-b.pointX,f=c.pageY-b.pointY,g=b.x+e,h=b.y+f,i=a.timeStamp||Date.now();b.options.onBeforeScrollMove&&b.options.onBeforeScrollMove.call(b,a),b.pointX=c.pageX,b.pointY=c.pageY,(g>0||g=0||b.maxScrollX>=0?0:b.maxScrollX),(h>b.minScrollY||h=b.minScrollY||b.maxScrollY>=0?b.minScrollY:b.maxScrollY),b.distX+=e,b.distY+=f,b.absDistX=d.abs(b.distX),b.absDistY=d.abs(b.distY),b.absDistX<6&&b.absDistY<6||(b.options.lockDirection&&(b.absDistX>b.absDistY+5?(h=b.y,f=0):b.absDistY>b.absDistX+5&&(g=b.x,e=0)),b.moved=!0,b._beforePos?b._beforePos(h,f)&&b._pos(g,h):b._pos(g,h),b.dirX=e>0?-1:0>e?1:0,b.dirY=f>0?-1:0>f?1:0,i-b.startTime>300&&(b.startTime=i,b.startX=b.x,b.startY=b.y),b.options.onScrollMove&&b.options.onScrollMove.call(b,a))},_end:function(c){if(!q||0===c.touches.length){var e,f,g,h=this,i=q?c.changedTouches[0]:c,j={dist:0,time:0},k={dist:0,time:0},l=(c.timeStamp||Date.now())-h.startTime,m=h.x,n=h.y;if(h._unbind(v,a),h._unbind(w,a),h._unbind(x,a),h.options.onBeforeScrollEnd&&h.options.onBeforeScrollEnd.call(h,c),!h.moved)return q&&this.options.handleClick&&!h.isStopScrollAction&&(h.doubleTapTimer=setTimeout(function(){for(h.doubleTapTimer=null,e=i.target;1!=e.nodeType;)e=e.parentNode;"SELECT"!=e.tagName&&"INPUT"!=e.tagName&&"TEXTAREA"!=e.tagName&&(f=b.createEvent("MouseEvents"),f.initMouseEvent("click",!0,!0,c.view,1,i.screenX,i.screenY,i.clientX,i.clientY,c.ctrlKey,c.altKey,c.shiftKey,c.metaKey,0,null),f._fake=!0,e.dispatchEvent(f))},0)),h._resetPos(400),h.options.onTouchEnd&&h.options.onTouchEnd.call(h,c),void 0;if(300>l&&h.options.momentum&&(j=m?h._momentum(m-h.startX,l,-h.x,h.scrollerW-h.wrapperW+h.x,h.options.bounce?h.wrapperW:0):j,k=n?h._momentum(n-h.startY,l,-h.y,h.maxScrollY<0?h.scrollerH-h.wrapperH+h.y-h.minScrollY:0,h.options.bounce?h.wrapperH:0):k,m=h.x+j.dist,n=h.y+k.dist,(h.x>0&&m>0||h.xh.minScrollY&&n>h.minScrollY||h.y=0?0:b.x=b.minScrollY||b.maxScrollY>0?b.minScrollY:b.y=h+a.time?(e._pos(a.x,a.y),e.animating=!1,e.options.onAnimationEnd&&e.options.onAnimationEnd.call(e),e._startAni(),void 0):(k=(k-h)/a.time-1,b=d.sqrt(1-k*k),i=(a.x-f)*b+f,j=(a.y-g)*b+g,e._pos(i,j),e.animating&&(e.aniTime=z(c)),void 0)},c()}},_transitionTime:function(a){a+="ms",this.scroller.style[k]=a},_momentum:function(a,b,c,e,f){var g=6e-4,h=d.abs(a)*(this.options.speedScale||1)/b,i=h*h/(2*g),j=0,k=0;return a>0&&i>c?(k=f/(6/(i/h*g)),c+=k,h=h*c/i,i=c):0>a&&i>e&&(k=f/(6/(i/h*g)),e+=k,h=h*e/i,i=e),i*=0>a?-1:1,j=h/g,{dist:i,time:d.round(j)}},_offset:function(a){for(var b=-a.offsetLeft,c=-a.offsetTop;a=a.offsetParent;)b-=a.offsetLeft,c-=a.offsetTop;return a!=this.wrapper&&(b*=this.scale,c*=this.scale),{left:b,top:c}},_bind:function(a,b,c){e.concat([b||this.scroller,a,this]),(b||this.scroller).addEventListener(a,this,!!c)},_unbind:function(a,b,c){(b||this.scroller).removeEventListener(a,this,!!c)},destroy:function(){var b=this;b.scroller.style[i]="",b._unbind(t,a),b._unbind(u),b._unbind(v,a),b._unbind(w,a),b._unbind(x,a),b.options.useTransition&&b._unbind(y),b.options.checkDOMChanges&&clearInterval(b.checkDOMTime),b.options.onDestroy&&b.options.onDestroy.call(b);for(var c=0,d=e.length;d>c;)e[c].removeEventListener(e[c+1],e[c+2]),e[c]=null,c+=3;e=[]},refresh:function(){var a,b=this;b.wrapperW=b.wrapper.clientWidth||1,b.wrapperH=b.wrapper.clientHeight||1,b.minScrollY=-b.options.topOffset||0,b.scrollerW=d.round(b.scroller.offsetWidth*b.scale),b.scrollerH=d.round((b.scroller.offsetHeight+b.minScrollY)*b.scale),b.maxScrollX=b.wrapperW-b.scrollerW,b.maxScrollY=b.wrapperH-b.scrollerH+b.minScrollY,b.dirX=0,b.dirY=0,b.options.onRefresh&&b.options.onRefresh.call(b),b.hScroll=b.options.hScroll&&b.maxScrollX<0,b.vScroll=b.options.vScroll&&(!b.options.bounceLock&&!b.hScroll||b.scrollerH>b.wrapperH),a=b._offset(b.wrapper),b.wrapperOffsetLeft=-a.left,b.wrapperOffsetTop=-a.top,b.scroller.style[k]="0",b._resetPos(400)},scrollTo:function(a,b,c,d){var e,f,g=this,h=a;for(g.stop(),h.length||(h=[{x:a,y:b,time:c,relative:d}]),e=0,f=h.length;f>e;e++)h[e].relative&&(h[e].x=g.x-h[e].x,h[e].y=g.y-h[e].y),g.steps.push({x:h[e].x,y:h[e].y,time:h[e].time||0});g._startAni()},scrollToElement:function(a,b){var c,e=this;a=a.nodeType?a:e.scroller.querySelector(a),a&&(c=e._offset(a),c.left+=e.wrapperOffsetLeft,c.top+=e.wrapperOffsetTop,c.left=c.left>0?0:c.lefte.minScrollY?e.minScrollY:c.top
                '),a.trigger("init.iScroll"),a.$el.iScroll(b.extend({},c.iScroll))}),b(window).on("ortchange"+a.eventNs,b.proxy(a.refresh,a)),a.on("destroy",function(){a.$el.iScroll("destroy"),b(window).off("ortchange"+a.eventNs)})},refresh:function(){this.trigger("refresh.iScroll").$el.iScroll("refresh")}})}(gmu,gmu.$),function(a,b){a.Navigator.options.visibleCount=4,a.Navigator.option("visibleCount","*",function(){function a(){var a=window.innerWidth>window.innerHeight?"landscape":"portrait",b=e[a],d=c.$el;c.$list.children().width(d.width()/b),c.$list.width(d.width()/b*c.$list.children().length)}var c=this,d=c._options,e="number"===b.type(d.visibleCount)?{portrait:d.visibleCount,landscape:Math.floor(3*d.visibleCount/2)}:d.visibleCount;c.on("init.iScroll refresh.iScroll",a)})}(gmu,gmu.$),function(a,b,c){a.Navigator.options.isScrollToNext=!0,a.Navigator.option("isScrollToNext",!0,function(){var a,d=this;d.on("select",function(e,f,g){a===c&&(a=d.index?0:1);var h,i=f>a,j=b(g)[i?"next":"prev"](),k=j.offset()||b(g).offset(),l=d.$el.offset();(i?k.left+k.width>l.left+l.width:k.left
          ').width(document.body.clientWidth-d.width()).appendTo("body")||null)},_setDisplay:function(){var a,d,e=this,f=e.$el,g=e.$contentWrap,h=c+"transform",i=e._transDisplayToPos(),j={};return b.each(["push","overlay","reveal"],function(b,c){j[c]=function(b,j,k){return a=i[c].panel,d=i[c].cont,f.css(h,"translate3d("+e._transDirectionToPos(j,a[b])+"px,0,0)"),k||(g.css(h,"translate3d("+e._transDirectionToPos(j,d[b])+"px,0,0)"),e.maskTimer=setTimeout(function(){e.$panelMask&&e.$panelMask.css(j,f.width()).toggle(b)},400)),e}}),j},_initPanelPos:function(a,b){return this.displayFn[a](0,b,!0),this.$el.get(0).clientLeft,this},_transDirectionToPos:function(a,b){return"left"===a?b:-b},_transDisplayToPos:function(){var a=this,b=a.panelWidth;return{push:{panel:[-b,0],cont:[0,b]},overlay:{panel:[-b,0],cont:[0,0]},reveal:{panel:[0,0],cont:[0,b]}}},_setShow:function(a,c,d){var e=this,f=e._options,g=a?"open":"close",h=b.Event("before"+g),i=a!==e.state(),j=a?"on":"off",k=a?b.proxy(e._eventHandler,e):e._eventHandler,l=c||f.display,m=d||f.position;return e.trigger(h,[c,d]),h.isDefaultPrevented()?e:(i&&(e._dealState(a,l,m),e.displayFn[l](e.isOpen=Number(a),m),f.swipeClose&&e.$el[j](b.camelCase("swipe-"+m),k),f.display=l,f.position=m),e)},_dealState:function(a,c,e){var f=this,g=f._options,h=f.$el,i=f.$contentWrap,j="ui-panel-"+c+" ui-panel-"+e,k="ui-panel-"+g.display+" ui-panel-"+g.position+" ui-panel-animate";return a&&(h.removeClass(k).addClass(j).show(),"fix"===g.scrollMode&&h.css("top",b(window).scrollTop()),f._initPanelPos(c,e),"reveal"===c?i.addClass("ui-panel-contentWrap").on(d,b.proxy(f._eventHandler,f)):(i.removeClass("ui-panel-contentWrap").off(d,b.proxy(f._eventHandler,f)),h.addClass("ui-panel-animate")),f.$panelMask&&f.$panelMask.css({left:"auto",right:"auto",height:document.body.clientHeight})),f},_eventHandler:function(a){var c=this,e=c._options,f=e.scrollMode,g=c.state()?"open":"close";switch(a.type){case"click":case"swipeLeft":case"swipeRight":c.close();break;case"scrollStop":"fix"===f?c.$el.css("top",b(window).scrollTop()):c.close();break;case d:c.trigger(g,[e.display,e.position]);break;case"ortchange":c.$panelMask&&c.$panelMask.css("height",document.body.clientHeight),"fix"===f&&c.$el.css("top",b(window).scrollTop())}},open:function(a,b){return this._setShow(!0,a,b)},close:function(){return this._setShow(!1)},toggle:function(a,b){return this[this.isOpen?"close":"open"](a,b)},state:function(){return!!this.isOpen},destroy:function(){return this.$panelMask&&this.$panelMask.off().remove(),this.maskTimer&&clearTimeout(this.maskTimer),this.$contentWrap.removeClass("ui-panel-animate"),b(window).off("scrollStop",this._eventHandler),b(window).off("ortchange",this._eventHandler),this.$super("destroy")}})}(gmu,gmu.$),function(a){var b=a.Popover;b.template.arrow='',b.options.arrow=!0,b.option("arrow",!0,function(){var a=this,b=a._options;b.offset=b.offset||function(a,b){return b=b.split("_")[0],{left:15*("left"===b?-1:"right"===b?1:0),top:15*("top"===b?-1:"bottom"===b?1:0)}},a.on("done.dom",function(b,c){c.append(a.tpl2html("arrow")).addClass("ui-pos-default")}),a.on("after.placement",function(a,b,c){var d=this.$root[0],e=d.className,f=c.placement,g=c.align||"";d.className=e.replace(/(?:\s|^)ui-pos-[^\s$]+/g,"")+" ui-pos-"+f+(g?"-"+g:"")})})}(gmu),function(a,b){a.Popover.options.collision=!0,a.Popover.option("collision",!0,function(){function a(a){var c=b(a);return a=c[0],a!==window&&9!==a.nodeType?c.offset():{width:c.width(),height:c.height(),top:a.pageYOffset||a.scrollTop||0,left:a.pageXOffset||a.scrollLeft||0}}function c(a,b,c,d){return a.left>=d.left&&a.left+b<=d.left+d.width&&a.top>=d.top&&a.top+c<=d.top+d.height}var d=this,e=d._options;d.on("before.placement",function(d,f,g,h){var i=a(e.within||window),j=g.placement,k=g.coord,l=Object.keys(h),m=l.indexOf(j)+1,n=l.splice(m,l.length-m);for(l=n.concat(l);l.length&&!c(f,k.width,k.height,i);)j=l.shift(),b.extend(f,h[j]());g.preset=j})})}(gmu,gmu.$),function(a,b){var c=a.Popover;c.options.dismissible=!0,c.option("dismissible",!0,function(){function a(a){for(var d=c.$target.add(c.$root).get(),e=d.length;e--;)if(d[e]===a||b.contains(d[e],a))return!0;return!1}var c=this,d=b(document),e="click"+c.eventNs;c.on("show",function(){d.off(e).on(e,function(b){a(b.target)||c.hide()})}),c.on("hide",function(){d.off(e)})})}(gmu,gmu.$),function(a,b){b.extend(a.Popover.options,{placement:"bottom",offset:null}),a.Popover.option("placement",function(a){return~["top","bottom","left","right"].indexOf(a)},function(){function a(a,b){return"right"===a||"bottom"===a?b:"center"===a?b/2:0}function c(b,c,e,f,g){var h=d.of,i=d.coord,j=d.offset,k=h.top,l=h.left;return l+=a(c,h.width)-a(f,i.width),k+=a(e,h.height)-a(g,i.height),j="function"==typeof j?j.call(null,{left:l,top:k},b):j||{},{left:l+(j.left||0),top:k+(j.top||0)}}var d,e=this,f={top:"center top center bottom",right:"right center left center",bottom:"center bottom center top",left:"left center right center"},g={};b.each(f,function(a,b){b=b.split(/\s/g),b.unshift(a),g[a]=function(){return c.apply(null,b)}}),this.on("placement",function(a,b,c){var e,f=this,h=f._options,i=h.placement;d={coord:b.offset(),of:c.offset(),placement:i,$el:b,$of:c,offset:h.offset},e=g[i](),f.trigger("before.placement",e,d,g),d.preset&&(d.placement=d.preset),b.offset(e),f.trigger("after.placement",e,d)}),b(window).on("ortchange",function(){e._visible&&e.trigger("placement",e.$target,e.$root)})})}(gmu,gmu.$),function(a,b,c){a.define("Progressbar",{options:{initValue:0,horizontal:!0,transitionDuration:300,_isShow:!0,_current:0,_percent:0},_init:function(){var a,c,d,e,f,g=this;g.on("ready",function(){a=g.$el,c=b.proxy(g._eventHandler,g),d=a.find(".ui-progressbar-button"),e=a.find(".ui-progressbar-bg"),f=a.offset(),d.on("touchstart touchmove touchend touchcancel",c),e.on("touchstart",c),b.extend(g._options,{_button:d[0],$_background:e,_filled:a.find(".ui-progressbar-filled")[0],_width:f.width,_height:f.height}),g._options.horizontal&&f.width&&a.width(f.width),g._options.initValue>0&&g.value(g._options.initValue)}),g.on("destroy",function(){g._options.setup||g.$el.remove()})},_create:function(){var a=this,c=a._options.horizontal?"h":"v";a.$el||(a.$el=b("
          ")),a.$el.addClass("ui-progressbar-"+c).appendTo(a._options.container||(a.$el.parent().length?"":document.body)).html('
          ')},_eventHandler:function(a){var c=this;switch(a.type){case"touchmove":c._touchMove(a);break;case"touchstart":b(a.target).hasClass("ui-progressbar-bg")?c._click(a):c._touchStart(a);break;case"touchcancel":case"touchend":c._touchEnd();break;case"tap":c._click(a)}},_touchStart:function(a){var c=this,d=c._options;b.extend(c._options,{pageX:a.touches[0].pageX,pageY:a.touches[0].pageY,S:!1,T:!1,X:0,Y:0}),d._button.style.webkitTransitionDuration="0ms",d._filled.style.webkitTransitionDuration="0ms",b(d._button).addClass("ui-progressbar-button-pressed"),c.trigger("dragStart")},_touchMove:function(a){var b,c=this,d=c._options,e=a.touches[0],f=e.pageX-d.pageX,g=e.pageY-d.pageY;if(!d.T){var h=Math.abs(f)=b&&b>=0&&(d._percent=b,d.X=f,d._button.style.webkitTransform="translate3d("+(d.X+d._current)+"px,0,0)",d._filled.style.width=b+"%",c.trigger("valueChange")),c.trigger("dragMove")):d.S&&(a.stopPropagation(),a.preventDefault(),b=-(d._current+g)/d._height*100,100>=b&&b>=0&&(d._percent=b,d.Y=g,d._button.style.webkitTransform="translate3d(0,"+(g+d._current)+"px,0)",d._filled.style.cssText+="height:"+b+"%;top:"+(d._height+g+d._current)+"px",c.trigger("valueChange")),c.trigger("dragMove"))},_touchEnd:function(){var a=this,c=a._options;c._current+=c.horizontal?c.X:c.Y,b(c._button).removeClass("ui-progressbar-button-pressed"),a.trigger("dragEnd")},_click:function(a){var b=this,c=b._options,d=c.$_background.offset(),e=a.touches[0];c.horizontal?b.value((e.pageX-d.left)/c._width*100):b.value((c._height-e.pageY+d.top)/c._height*100)},value:function(a){var b,d,e=this,f=e._options;return a===c?f._percent:(a=parseFloat(a),isNaN(a)?e:(a=a>100?100:0>a?0:a,f._percent=a,d=";-webkit-transition-duration:"+f.transitionDuration+"ms",f.horizontal?(b=f._current=f._width*a/100,f._button.style.cssText+="-webkit-transform:translate3d("+b+"px,0,0)"+d,f._filled.style.cssText+="width:"+a+"%"+d):(b=f._current=f._height*a/-100,f._button.style.cssText+="-webkit-transform:translate3d(0,"+b+"px,0)"+d,f._filled.style.cssText+="height:"+a+"%;top:"+(f._height+b)+"px"+d),e.trigger("valueChange"),e))},show:function(){var a=this;return a._options._isShow||(a.$el.css("display","block"),a._options._isShow=!0),a},hide:function(){var a=this;return a._options._isShow&&(a.$el.css("display","none"),a._options._isShow=!1),a}})}(gmu,gmu.$),function(a,b,c){a.define("Refresh",{options:{load:null,statechange:null},_init:function(){var a=this,c=a._options; +a.on("ready",function(){b.each(["up","down"],function(b,d){var e=c["$"+d+"Elem"],f=e.get(0);e.length&&(a._status(d,!0),(!f.childNodes.length||e.find(".ui-refresh-icon").length&&e.find(".ui-refresh-label").length)&&(!f.childNodes.length&&a._createBtn(d),c.refreshInfo||(c.refreshInfo={}),c.refreshInfo[d]={$icon:e.find(".ui-refresh-icon"),$label:e.find(".ui-refresh-label"),text:e.find(".ui-refresh-label").html()}),e.on("click",function(){a._status(d)&&!c._actDir&&(a._setStyle(d,"loading"),a._loadingAction(d,"click"))}))})}),a.on("destroy",function(){a.$el.remove()})},_create:function(){var a=this,b=a._options,c=a.$el;a._options.setup&&(b.$upElem=c.find(".ui-refresh-up"),b.$downElem=c.find(".ui-refresh-down"),c.addClass("ui-refresh"))},_createBtn:function(a){return this._options["$"+a+"Elem"].html('加载更多'),this},_setStyle:function(a,c){var d=this,e=b.Event("statechange");return d.trigger(e,d._options["$"+a+"Elem"],c,a),e.defaultPrevented?d:d._changeStyle(a,c)},_changeStyle:function(a,b){var c=this._options,d=c.refreshInfo[a];switch(b){case"loaded":d.$label.html(d.text),d.$icon.removeClass(),c._actDir="";break;case"loading":d.$label.html("加载中..."),d.$icon.addClass("ui-loading"),c._actDir=a;break;case"disable":d.$label.html("没有更多内容了")}return this},_loadingAction:function(a,c){var d=this,e=d._options,f=e.load;return b.isFunction(f)&&f.call(d,a,c),d._status(a,!1),d},afterDataLoading:function(a){var b=this,a=a||b._options._actDir;return b._setStyle(a,"loaded"),b._status(a,!0),b},_status:function(a,b){var d=this._options;return b===c?d["_"+a+"Open"]:d["_"+a+"Open"]=!!b},_setable:function(a,c,d){var e=this,f=e._options,g=c?[c]:["up","down"];return b.each(g,function(b,c){var g=f["$"+c+"Elem"];g.length&&(a?g.show():d?g.hide():e._setStyle(c,"disable"),e._status(c,a))}),e},disable:function(a,b){return this._setable(!1,a,b)},enable:function(a){return this._setable(!0,a)}})}(gmu,gmu.$),function(a,b){var c=b.fx.cssPrefix,d=b.fx.transitionEnd,e=" translateZ(0)";a.define("Slider",{options:{loop:!1,speed:400,index:0,selector:{container:".ui-slider-group"}},template:{item:'
          <% if( title ) { %>

          <%= title %>

          <% } %>
          '},_create:function(){var a=this,c=a.getEl(),e=a._options;a.index=e.index,a._initDom(c,e),a._initWidth(c,a.index),a._container.on(d+a.eventNs,b.proxy(a._tansitionEnd,a)),b(window).on("ortchange"+a.eventNs,function(){a._initWidth(c,a.index)})},_initDom:function(a,c){var d,e,f=c.selector,g=c.viewNum||1;for(e=a.find(f.container),e.length||(e=b("
          "),c.content?this._createItems(e,c.content):a.is("ul")?(this.$el=e.insertAfter(a),e=a,a=this.$el):e.append(a.children()),e.appendTo(a)),(d=e.children()).lengthc;c++)a.append(this.tpl2html("item",b[c]))},_initWidth:function(a,b,c){var d,e=this;(c||(d=a.width())!==e.width)&&(e.width=d,e._arrange(d,b),e.height=a.height(),e.trigger("width.change"))},_arrange:function(a,b){var c,d,e=this._items,f=0;for(this._slidePos=new Array(e.length),d=e.length;d>f;f++)c=e[f],c.style.cssText+="width:"+a+"px;left:"+f*-a+"px;",c.setAttribute("data-index",f),this._move(f,b>f?-a:f>b?a:0,0);this._container.css("width",a*d)},_move:function(a,b,c,d){var e=this._slidePos,f=this._items;e[a]!==b&&f[a]&&(this._translate(a,b,c),e[a]=b,d&&f[a].clientLeft)},_translate:function(a,b,d){var f=this._items[a],g=f&&f.style;return g?(g.cssText+=c+"transition-duration:"+d+"ms;"+c+"transform: translate("+b+"px, 0)"+e+";",void 0):!1},_circle:function(a,b){var c;return b=b||this._items,c=b.length,(a%c+c)%b.length},_tansitionEnd:function(a){~~a.target.getAttribute("data-index")===this.index&&this.trigger("slideend",this.index)},_slide:function(a,b,c,d,e,f){var g,h=this;return g=h._circle(a-c*b),f.loop||(c=Math.abs(a-g)/(a-g)),this._move(g,-c*d,0,!0),this._move(a,d*c,e),this._move(g,0,e),this.index=g,this.trigger("slide",g,a)},slideTo:function(a,b){if(this.index===a||this.index===this._circle(a))return this;var c=this._options,d=this.index,e=Math.abs(d-a),f=e/(d-a),g=this.width;return b=b||c.speed,this._slide(d,e,f,g,b,c)},prev:function(){return(this._options.loop||this.index>0)&&this.slideTo(this.index-1),this},next:function(){return(this._options.loop||this.index+1<% if( title ) { %>

          <%= title %>

          <% } %>
          ',a.Slider.register("lazyloadimg",{_init:function(){this.on("ready slide",this._loadItems)},_loadItems:function(){var a,b,c=this._options,d=c.loop,e=c.viewNum||1,f=this.index;for(a=f-e,b=f+2*e;b>a;a++)this.loadImage(d?this._circle(a):a)},loadImage:function(b){var c,d=this._items[b];return d&&(c=a.staticCall(d,"find","img[lazyload]"),c.length)?(c.each(function(){this.src=this.getAttribute("lazyload"),this.removeAttribute("lazyload")}),void 0):this}})}(gmu),function(a,b,c){var d,e,f,g,h={touchstart:"_onStart",touchmove:"_onMove",touchend:"_onEnd",touchcancel:"_onEnd",click:"_onClick"};b.extend(a.Slider.options,{stopPropagation:!1,disableScroll:!1}),a.Slider.register("touch",{_init:function(){var a=this,b=a.getEl();a._handler=function(b){return a._options.stopPropagation&&b.stopPropagation(),h[b.type]&&a[h[b.type]].call(a,b)},a.on("ready",function(){b.on("touchstart"+a.eventNs,a._handler),a._container.on("click"+a.eventNs,a._handler)})},_onClick:function(){return!g},_onStart:function(a){if(a.touches.length>1)return!1;var b,h=this,i=a.touches[0],j=h._options,k=h.eventNs;e={x:i.pageX,y:i.pageY,time:+new Date},f={},g=!1,d=c,b=j.viewNum||1,h._move(j.loop?h._circle(h.index-b):h.index-b,-h.width,0,!0),h._move(j.loop?h._circle(h.index+b):h.index+b,h.width,0,!0),h.$el.on("touchmove"+k+" touchend"+k+" touchcancel"+k,h._handler)},_onMove:function(a){if(a.touches.length>1||a.scale&&1!==a.scale)return!1;var b,c,h,i,j=this._options,k=j.viewNum||1,l=a.touches[0],m=this.index;if(j.disableScroll&&a.preventDefault(),f.x=l.pageX-e.x,f.y=l.pageY-e.y,"undefined"==typeof d&&(d=Math.abs(f.x)0||m===this._items.length-1&&f.x<0?Math.abs(f.x)/this.width+1:1),i=this._slidePos,b=m-k,c=m+2*k;c>b;b++)h=j.loop?this._circle(b):b,this._translate(h,f.x+i[h],0);g=!0}},_onEnd:function(){if(this.$el.off("touchmove"+this.eventNs+" touchend"+this.eventNs+" touchcancel"+this.eventNs,this._handler),g){var a,b,c,d,h,i=this,j=i._options,k=j.viewNum||1,l=i.index,m=i._slidePos,n=+new Date-e.time,o=Math.abs(f.x),p=!j.loop&&(!l&&f.x>0||l===m.length-k&&f.x<0),q=f.x>0?1:-1;if(250>n?(a=o/n,b=Math.min(Math.round(a*k*1.2),k)):b=Math.round(o/(i.perWidth||i.width)),b&&!p)i._slide(l,b,q,i.width,j.speed,j,!0),k>1&&n>=250&&Math.ceil(o/i.perWidth)!==b&&(i.indexc;c++)h=j.loop?i._circle(c):c,i._translate(h,m[h],j.speed)}}})}(gmu,gmu.$),function(a,b){b.extend(!0,a.Slider,{template:{prev:'',next:''},options:{arrow:!0,select:{prev:".ui-slider-pre",next:".ui-slider-next"}}}),a.Slider.option("arrow",!0,function(){var a=this,c=["prev","next"];this.on("done.dom",function(d,e,f){var g=f.selector;c.forEach(function(c){var d=e.find(g[c]);d.length||e.append(d=b(a.tpl2html(c))),a["_"+c]=d})}),this.on("ready",function(){c.forEach(function(b){a["_"+b].on("tap"+a.eventNs,function(){a[b].call(a)})})}),this.on("destroy",function(){a._prev.off(a.eventNs),a._next.off(a.eventNs)})})}(gmu,gmu.$),function(a,b){b.extend(!0,a.Slider,{template:{dots:'

          <%= new Array( len + 1 ).join("") %>

          '},options:{dots:!0,selector:{dots:".ui-slider-dots"}}}),a.Slider.option("dots",!0,function(){var c=function(b,c){var d=this._dots;"undefined"==typeof c||a.staticCall(d[c%this.length],"removeClass","ui-state-active"),a.staticCall(d[b%this.length],"addClass","ui-state-active")};this.on("done.dom",function(a,c,d){var e=c.find(d.selector.dots);e.length||(e=this.tpl2html("dots",{len:this.length}),e=b(e).appendTo(c)),this._dots=e.children().toArray()}),this.on("slide",function(a,b,d){c.call(this,b,d)}),this.on("ready",function(){c.call(this,this.index)})})}(gmu,gmu.$),function(a){a.Slider.options.imgZoom=!0,a.Slider.option("imgZoom",function(){return!!this._options.imgZoom},function(){function a(){d&&d.off("load"+e.eventNs,c)}function b(){a(),d=e._container.find(f).on("load"+e.eventNs,c)}function c(a){var b=a.target||this,c=Math.min(1,e.width/b.naturalWidth,e.height/b.naturalHeight);b.style.width=c*b.naturalWidth+"px"}var d,e=this,f=e._options.imgZoom;f="string"==typeof f?f:"img",e.on("ready dom.change",b),e.on("width.change",function(){d&&d.each(c)}),e.on("destroy",a)})}(gmu),function(a,b){var c=0;gmu.define("Suggestion",{options:{historyShare:!0,confirmClearHistory:!0,autoClose:!1},template:{wrapper:'
          清除历史记录关闭
          '},_initDom:function(){var b=this,d=b.getEl().attr("autocomplete","off"),e=d.parent(".ui-suggestion-mask");return e.length?b.$mask=e:d.wrap(b.$mask=a('
          ')),b.$mask.append(b.tpl2html("wrapper")),b.$wrapper=b.$mask.find(".ui-suggestion").prop("id","ui-suggestion-"+c++),b.$content=b.$wrapper.css("top",d.height()+(b.wrapperTop=parseInt(b.$wrapper.css("top"),10)||0)).find(".ui-suggestion-content"),b.$btn=b.$wrapper.find(".ui-suggestion-button"),b.$clearBtn=b.$btn.find(".ui-suggestion-clear"),b.$closeBtn=b.$btn.find(".ui-suggestion-close"),b.trigger("initdom")},_bindEvent:function(){var b=this,c=b.getEl(),d=b.eventNs;return b._options.autoClose&&a(document).on("tap"+d,function(c){!a.contains(b.$mask.get(0),c.target)&&b.hide()}),c.on("focus"+d,function(){!b.isShow&&b._showList().trigger("open")}),c.on("input"+d,function(){b._showList()}),b.$clearBtn.on("click"+d,function(){b.history(null)}).highlight("ui-suggestion-highlight"),b.$closeBtn.on("click"+d,function(){b.getEl().blur(),b.hide().trigger("close")}).highlight("ui-suggestion-highlight"),b},_create:function(){var b=this,d=b._options,e=d.historyShare;return d.container&&(b.$el=a(d.container)),b.key=e?("boolean"===a.type(e)?"":e+"-")+"SUG-Sharing-History":b.getEl().attr("id")||"ui-suggestion-"+c++,b.separator=encodeURIComponent(","),b._initDom()._bindEvent(),b},_showList:function(){var b,c=this,d=c.value();return d?c.trigger("sendrequest",d,a.proxy(c._render,c),a.proxy(c._cacheData,c)):(b=c._localStorage())?c._render(d,b.split(c.separator)):c.hide(),c},_render:function(b,c){this.trigger("renderlist",c,b,a.proxy(this._fillWrapper,this))},_fillWrapper:function(a){return this.$clearBtn[this.value()?"hide":"show"](),a?(this.$content.html(a),this.show()):this.hide(),this},_localStorage:function(c){var d,e,f=this,g=f.key,h=f.separator;try{if(d=b.localStorage,void 0===c)return d[g];null===c?d[g]="":c&&(e=d[g]?d[g].split(h):[],~a.inArray(c,e)||(e.unshift(c),d[g]=e.join(h)))}catch(i){console.log(i.message)}return f},_cacheData:function(a,b){return this.cacheData||(this.cacheData={}),void 0!==b?this.cacheData[a]=b:this.cacheData[a]},value:function(){return this.getEl().val()},history:function(a){var c=this,d=null!==a||function(){return c._localStorage(null).hide()};return null===a?c._options.confirmClearHistory?b.confirm("清除全部查询历史记录?")&&d():d():c._localStorage(a)},show:function(){return this.isShow?this:(this.$wrapper.show(),this.isShow=!0,this.trigger("show"))},hide:function(){return this.isShow?(this.$wrapper.hide(),this.isShow=!1,this.trigger("hide")):this},destroy:function(){var b=this,c=b.getEl(),d=b.ns;return b.trigger("destroy"),c.off(d),b.$mask.replaceWith(c),b.$clearBtn.off(d),b.$closeBtn.off(d),b.$wrapper.children().off().remove(),b.$wrapper.remove(),b._options.autoClose&&a(document).off(d),this.destroyed=!0,b}})}(gmu.$,window),function(a,b){a.Suggestion.register("iscroll",{_init:function(){var a=this;return a.on("ready",function(){a.$scroller=b('
          '),a.$content.wrapInner(a.$scroller).iScroll({hScroll:!1,onRefresh:function(){this.y&&this.scrollTo(0,0)}}),a.on("destroy",function(){a.$content.iScroll("destroy")})}),a},_fillWrapper:function(a){return this.$clearBtn[this.value()?"hide":"show"](),a?(this.show().$scroller.html(a),this.$content.iScroll("refresh")):this.hide(),this}})}(gmu,gmu.$),function(a,b){var c=Array.prototype.reverse;gmu.Suggestion.options.listSelector="li",gmu.Suggestion.register("posadapt",{_init:function(){var a,b=this;b.on("show ortchange",function(){b._checkPos()&&(b.$wrapper.css("top",-b.$wrapper.height()-b.wrapperTop),c.call(a=b.$content.find(b._options.listSelector)),a.appendTo(a.parent()),b.$btn.prependTo(b.$wrapper))})},_checkPos:function(){var c=this._options.height||66,d=this.getEl().offset().top-b.pageYOffset;return a(b).height()-d=c}})}(gmu.$,window),function(a,b){a.Suggestion.register("quickdelete",{_init:function(){var a,c,d=this;d.on("ready",function(){a=d.getEl(),c=d.eventNs,d.$mask.append(d.$quickDel=b('
          ')),a.on("focus"+c+" input"+c,function(){d["_quickDel"+(b.trim(a.val())?"Show":"Hide")]()}),a.on("blur"+c,function(){d._quickDelHide()}),d.$quickDel.on("touchstart"+c,function(b){b.preventDefault(),b.formDelete=!0,a.val(""),d.trigger("delete").trigger("input")._quickDelHide(),a.blur().focus()}),d.on("destroy",function(){d.$quickDel.off().remove()})})},_quickDelShow:function(){this.quickDelShow||(a.staticCall(this.$quickDel.get(0),"css","visibility","visible"),this.quickDelShow=!0)},_quickDelHide:function(){this.quickDelShow&&(a.staticCall(this.$quickDel.get(0),"css","visibility","hidden"),this.quickDelShow=!1)}})}(gmu,gmu.$),function(a,b){gmu.Suggestion.options.compatdata=!0,gmu.Suggestion.option("compatdata",!0,function(){this.on("ready",function(){var a,c,d=this.key,e="SUG-History-DATATRANS";try{a=b.localStorage[d],a&&!b.localStorage[e]&&(b.localStorage[e]="",c=a.split(","),b.localStorage[d]=c.join(this.separator))}catch(f){console.log(f.message)}})})}(gmu.$,window),function(a){a.extend(gmu.Suggestion.options,{isHistory:!0,usePlus:!1,listCount:5,renderlist:null}),gmu.Suggestion.option("renderlist",function(){return"function"!==a.type(this._options.renderlist)},function(){var b=this,c=a("
          "),d=function(a){return c.text(a).html()},e=function(c,e){var f,g,h,i=b._options,j=[],k="";if(!e||!e.length)return b.hide(),j;for(e=e.slice(0,i.listCount),c=d(c||""),h=0,g=e.length;g>h;h++)k=d(f=e[h]),c&&(k=a.trim(f).replace(c,""+c+"")),i.usePlus&&(k+='
          '),j.push("
        • "+k+"
        • ");return j};b.on("ready",function(){var b=this,c=b.eventNs,d=a(b._options.form||b.getEl().closest("form"));d.size()&&(b.$form=d.on("submit"+c,function(a){var c=gmu.Event("submit");b._options.isHistory&&b._localStorage(b.value()),b.trigger(c),c.isDefaultPrevented()&&a.preventDefault()})),b.$content.on("touchstart"+c,function(a){a.preventDefault()}),b.$content.on("tap"+c,function(c){var d=b.getEl(),e=a(c.target);e.hasClass("ui-suggestion-plus")?d.val(e.attr("data-item")):a.contains(b.$content.get(0),e.get(0))&&setTimeout(function(){d.val(e.text()),b.trigger("select",e).hide().$form.submit()},400)}).highlight("ui-suggestion-highlight"),b.on("destroy",function(){d.size()&&d.off(c),b.$content.off()})}),b.on("renderlist",function(a,b,c,d){var f=e(c,b);return d(f.length?"
            "+f.join(" ")+"
          ":"")})})}(gmu.$),function(a,b){a.extend(gmu.Suggestion.options,{isCache:!0,queryKey:"wd",cbKey:"cb",sendrequest:null}),gmu.Suggestion.option("sendrequest",function(){return"function"!==a.type(this._options.sendrequest)},function(){var c,d=this,e=d._options,f=e.queryKey,g=e.cbKey,h=e.param,i=e.isCache;this.on("sendrequest",function(j,k,l,m){var n=e.source,o="suggestion_"+ +new Date;return i&&(c=m(k))?(l(k,c),d):(n=(n+"&"+f+"="+encodeURIComponent(k)).replace(/[&?]{1,2}/,"?"),!~n.indexOf("&"+g)&&(n+="&"+g+"="+o),h&&(n+="&"+h),b[o]=function(a){l(k,a.s),i&&m(k,a.s),delete b[o]},a.ajax({url:n,dataType:"jsonp"}),d)})})}(gmu.$,window),function(a,b,c){var d=1,e=function(){return d++},f=/^#(.+)$/;a.define("Tabs",{options:{active:0,items:null,transition:"slide"},template:{nav:'
            <% var item; for(var i=0, length=items.length; i class="ui-state-active"<% } %>><%=item.title%><% } %>
          ',content:'
          <% var item; for(var i=0, length=items.length; i id="<%=item.id%>"<% } %> class="ui-tabs-panel <%=transition%><% if(i==active){ %> ui-state-active<% } %>"><%=item.content%>
          <% } %>
          '},_init:function(){var a,c=this,d=c._options,e=b.proxy(c._eventHandler,c);c.on("ready",function(){a=c.$el,a.addClass("ui-tabs"),d._nav.on("tap",e).children().highlight("ui-state-hover")}),b(window).on("ortchange",e)},_create:function(){var a=this,c=a._options;a._options.setup&&a.$el.children().length>0?a._prepareDom("setup",c):(c.setup=!1,a.$el=a.$el||b("
          "),a._prepareDom("create",c))},_prepareDom:function(a,c){var d,g,h,i,j=this,k=j.$el;switch(a){case"setup":if(c._nav=j._findElement("ul").first(),c._nav){c._content=j._findElement("div.ui-tabs-content"),c._content=(c._content&&c._content.first()||b("
          ").appendTo(k)).addClass("ui-viewport ui-tabs-content"),d=[],c._nav.addClass("ui-tabs-nav").children().each(function(){var a,g,h=j._findElement("a",this),i=h?h.attr("href"):b(this).attr("data-url");a=f.test(i)?RegExp.$1:"tabs_"+e(),(g=j._findElement("#"+a)||b('
          ')).addClass("ui-tabs-panel"+(c.transition?" "+c.transition:"")).appendTo(c._content),d.push({id:a,href:i,title:h?h.attr("href","javascript:;").text():b(this).text(),content:g})}),c.items=d,c.active=Math.max(0,Math.min(d.length-1,c.active||b(".ui-state-active",c._nav).index()||0)),j._getPanel().add(c._nav.children().eq(c.active)).addClass("ui-state-active");break}default:d=c.items=c.items||[],g=[],h=[],c.active=Math.max(0,Math.min(d.length-1,c.active)),b.each(d,function(a,b){i="tabs_"+e(),g.push({href:b.href||"#"+i,title:b.title}),h.push({content:b.content||"",id:i}),d[a].id=i}),c._nav=b(this.tpl2html("nav",{items:g,active:c.active})).prependTo(k),c._content=b(this.tpl2html("content",{items:h,active:c.active,transition:c.transition})).appendTo(k),c.container=c.container||(k.parent().length?null:"body")}c.container&&k.appendTo(c.container),j._fitToContent(j._getPanel())},_getPanel:function(a){var d=this._options;return b("#"+d.items[a===c?d.active:a].id)},_findElement:function(a,c){var d=b(c||this.$el).find(a);return d.length?d:null},_eventHandler:function(a){var c,d=this._options;switch(a.type){case"ortchange":this.refresh();break;default:(c=b(a.target).closest("li",d._nav.get(0)))&&c.length&&(a.preventDefault(),this.switchTo(c.index()))}},_fitToContent:function(a){var b=this._options,d=b._content;return b._plus===c&&(b._plus=parseFloat(d.css("border-top-width"))+parseFloat(d.css("border-bottom-width"))),d.height(a.height()+b._plus),this},switchTo:function(c){var d,e,f,g,h,i=this,j=i._options,k=j.items;if(!j._buzy&&j.active!=(c=Math.max(0,Math.min(k.length-1,c)))){if(e=b.extend({},k[c]),e.div=i._getPanel(c),e.index=c,f=b.extend({},k[j.active]),f.div=i._getPanel(),f.index=j.active,d=a.Event("beforeActivate"),i.trigger(d,e,f),d.isDefaultPrevented())return i;j._content.children().removeClass("ui-state-active"),e.div.addClass("ui-state-active"),j._nav.children().removeClass("ui-state-active").eq(e.index).addClass("ui-state-active"),j.transition&&(j._buzy=!0,h=b.fx.animationEnd+".tabs",g=c>j.active?"":" reverse",j._content.addClass("ui-viewport-transitioning"),f.div.addClass("out"+g),e.div.addClass("in"+g).on(h,function(a){a.target==a.currentTarget&&(e.div.off(h,arguments.callee),j._buzy=!1,f.div.removeClass("out reverse"),e.div.removeClass("in reverse"),j._content.removeClass("ui-viewport-transitioning"),i.trigger("animateComplete",e,f),i._fitToContent(e.div))})),j.active=c,i.trigger("activate",e,f),j.transition||i._fitToContent(e.div)}return i},refresh:function(){return this._fitToContent(this._getPanel())},destroy:function(){var a=this._options,b=this._eventHandler;return a._nav.off("tap",b).children().highlight(),a.swipe&&a._content.off("swipeLeft swipeRight",b),a.setup||this.$el.remove(),this.$super("destroy")}})}(gmu,gmu.$),function(a){var b=/^#.+$/,c={},d={loading:'
          Loading
          ',error:'

          内容加载失败!

          '};gmu.Tabs.register("ajax",{_init:function(){var a,c,d,e=this._options;this.on("ready",function(){for(a=e.items,c=0,d=a.length;d>c;c++)a[c].href&&!b.test(a[c].href)&&(a[c].isAjax=!0);this.on("activate",this._onActivate),a[e.active].isAjax&&this.load(e.active)})},destroy:function(){return this.off("activate",this._onActivate),this.xhr&&this.xhr.abort(),this.origin()},_fitToContent:function(a){var b=this._options;return b._fitLock?void 0:this.origin(a)},_onActivate:function(a,b){b.isAjax&&this.load(b.index)},load:function(b,e){var f,g,h,i=this,j=i._options,k=j.items;return 0>b||b>k.length-1||!(f=k[b])||!f.isAjax||(g=i._getPanel(b)).text()&&!e&&c[b]?this:((h=i.xhr)&&setTimeout(function(){h.abort()},400),j._loadingTimer=setTimeout(function(){g.html(d.loading)},50),j._fitLock=!0,i.xhr=a.ajax(a.extend(j.ajax||{},{url:f.href,context:i.$el.get(0),beforeSend:function(a,b){var c=gmu.Event("beforeLoad");return i.trigger(c,a,b),c.isDefaultPrevented()?!1:void 0},success:function(a,d){var e=gmu.Event("beforeRender");clearTimeout(j._loadingTimer),i.trigger(e,a,g,b,d),e.isDefaultPrevented()||g.html(a),j._fitLock=!1,c[b]=!0,i.trigger("load",g),delete i.xhr,i._fitToContent(g)},error:function(){var a=gmu.Event("loadError");clearTimeout(j._loadingTimer),c[b]=!1,i.trigger(a,g),a.isDefaultPrevented()||g.html(d.error),delete i.xhr}})),void 0)}})}(Zepto),function(a,b){function c(){a(document).on("touchstart.tabs",function(c){var h,i,k=c.touches?c.touches[0]:c;h={x:k.clientX,y:k.clientY,time:Date.now(),el:a(c.target)},a(document).on("touchmove.tabs",function(b){var c,d=b.touches?b.touches[0]:b;h&&(i={x:d.clientX,y:d.clientY,time:Date.now()},(c=Math.abs(h.x-i.x))>g||c>Math.abs(h.y-i.y)?j(b.target)&&b.preventDefault():a(document).off("touchmove.tabs touchend.tabs"))}).one("touchend.tabs",function(){a(document).off("touchmove.tabs"),h&&i&&i.time-h.timee&&Math.abs(h.y-i.y)i.x?"tabsSwipeLeft":"tabsSwipeRight"),h=i=b})})}var d=1e3,e=30,f=70,g=30,h=[],i=!1,j=function(b){for(var c=h.length;c--;)if(a.contains(h[c],b))return!0;return!1};gmu.Tabs.register("swipe",{_init:function(){var b=this._options;this.on("ready",function(){h.push(b._content.get(0)),i=i||(c(),!0),this.$el.on("tabsSwipeLeft tabsSwipeRight",a.proxy(this._eventHandler,this))})},_eventHandler:function(a){var c,d,e=this._options;switch(a.type){case"tabsSwipeLeft":case"tabsSwipeRight":c=e.items,"tabsSwipeLeft"==a.type&&e.active0&&(d=e.active-1),d!==b&&(a.stopPropagation(),this.switchTo(d));break;default:return this.origin(a)}},destroy:function(){var b,c=this._options;return~(b=a.inArray(c._content.get(0),h))&&h.splice(b,1),this.$el.off("tabsSwipeLeft tabsSwipeRight",this._eventHandler),h.length||(a(document).off("touchstart.tabs"),i=!1),this.origin()}})}(Zepto),function(a,b){a.define("Toolbar",{options:{container:document.body,title:"标题",leftBtns:[],rightBtns:[],fixed:!1},_init:function(){var a,c=this,d=c._options;d.container||(d.container=document.body),c.on("ready",function(){if(a=c.$el,d.fixed){var e,f=b('
          ').height(a.offset().height).insertBefore(a).append(a).append(a.clone().css({"z-index":1,position:"absolute",top:0})),g=a.offset().top,h=function(){document.body.scrollTop>g?a.css({position:"fixed",top:0}):a.css("position","absolute")};b(window).on("touchmove touchend touchcancel scroll scrollStop",h),b(document).on("touchend touchcancel",e=function(){setTimeout(function(){h()},200)}),c.on("destroy",function(){b(window).off("touchmove touchend touchcancel scroll scrollStop",h),b(document).off("touchend touchcancel",e),a.insertBefore(f),f.remove(),c._removeDom()}),h()}}),c.on("destroy",function(){c._removeDom()})},_create:function(){var a=this,c=a._options,d=a.getEl(),e=b(c.container),f=[],g=a.btnGroups={left:[],right:[]},h=g.left;c.setup||(d&&d.length>0?d.appendTo(e):d=a.$el=b("
          ").appendTo(e)),f=d.children(),$toolbarWrap=d.find(".ui-toolbar-wrap"),0===$toolbarWrap.length?$toolbarWrap=b('
          ').appendTo(d):f=$toolbarWrap.children(),f.forEach(function(b){$toolbarWrap.append(b),/^[hH]/.test(b.tagName)?(h=g.right,a.title=b):h.push(b)});var i=$toolbarWrap.find(".ui-toolbar-left"),j=$toolbarWrap.find(".ui-toolbar-right");0===i.length&&(i=f.length?b('
          ').insertBefore(f[0]):b('
          ').appendTo($toolbarWrap),g.left.forEach(function(a){b(a).addClass("ui-toolbar-button"),i.append(a)}),j=b('
          ').appendTo($toolbarWrap),g.right.forEach(function(a){b(a).addClass("ui-toolbar-button"),j.append(a)})),d.addClass("ui-toolbar"),b(a.title).length?b(a.title).addClass("ui-toolbar-title"):b('

          '+c.title+"

          ").insertAfter(i),a.btnContainer={left:i,right:j},a.addBtns("left",c.leftBtns),a.addBtns("right",c.rightBtns)},_addBtn:function(a,c){b(c).appendTo(a).addClass("ui-toolbar-button")},addBtns:function(b,c){var d=this,e=d.btnContainer[b],f=Object.prototype.toString;return"[object String]"!=f.call(b)&&(c=b,e=d.btnContainer.right),c.forEach(function(b){b instanceof a.Base&&(b=b.getEl()),d._addBtn(e,b)}),d},show:function(){var a=this;return a.$el.show(),a.trigger("show"),a.isShowing=!0,a},hide:function(){var a=this;return a.$el.hide(),a.trigger("hide"),a.isShowing=!1,a},toggle:function(){var a=this;return a.isShowing===!1?a.show():a.hide(),a},_removeDom:function(){var a=this,b=a.$el;a._options.setup===!1?b.remove():b.css("position","static").css("top","auto")}})}(gmu,gmu.$),function(a){a.Toolbar.register("position",{position:function(a){return this.$el.fix(a),this}})}(gmu,gmu.$),function(a,b){a.Refresh.register("iOS5",{_init:function(){var a=this,c=a._options,d=a.$el;d.css({overflow:"scroll","-webkit-overflow-scrolling":"touch"}),c.topOffset=c.$upElem?c.$upElem.height():0,c.iScroll=a._getiScroll(),d.get(0).scrollTop=c.topOffset,d.on("touchstart touchmove touchend",b.proxy(a._eventHandler,a))},_changeStyle:function(a,b){var c=this,d=c._options,e=d.refreshInfo[a];switch(c.origin(a,b),b){case"loaded":e.$icon.addClass("ui-refresh-icon"),d._actDir="";break;case"beforeload":e.$label.html("松开立即加载"),e.$icon.addClass("ui-refresh-flip");break;case"loading":e.$icon.removeClass().addClass("ui-loading")}return c},_scrollStart:function(a){var b=this,c=b._options,d=c.topOffset,e=c.$upElem,f=b.$el.get(0),g=function(){clearTimeout(c.topOffsetTimer),e&&e.length&&f.scrollTop<=d&&!c._upRefreshed&&(f.scrollTop=d)};return b.trigger("scrollstart",a),b._enableScroll()._bindScrollStop(f,g),c.maxScrollY=f.offsetHeight-f.scrollHeight,c._scrollFn=g,b},_scrollMove:function(){var a=this,b=a._options,c=b.$upElem&&b.$upElem.length,d=b.$downElem&&b.$downElem.length,e=a.$el.get(0),f=b.threshold||5;a._scrollMove=function(g){var h=b.maxScrollY,i=e.scrollTop,j=b.lastMoveY||i,k=b._upRefreshed,l=b._downRefreshed,m=a._status("up"),n=a._status("down");if(!(c&&!m||d&&!n))return b.iScroll.deltaY=i-j,n&&d&&!l&&h-f>-i?a._setMoveState("down","beforeload","pull"):n&&d&&l&&-i>h-f&&-i!==h?a._setMoveState("down","loaded","restore"):m&&c&&!k&&-i>f?a._setMoveState("up","beforeload","pull"):m&&c&&k&&f>-i&&i&&a._setMoveState("up","loaded","restore"),b.lastMoveY=i,b._moved=!0,a.trigger("scrollmove",g,i,i-j)},a._scrollMove.apply(a,arguments)},_scrollEnd:function(a){var c=this,d=c._options,e=c.$el.get(0),f=d.topOffset,g=d._actDir,h=d._restoreDir;return("up"==h||e.scrollTop<=f)&&!g&&d._moved&&(c._options.topOffsetTimer=setTimeout(function(){b(e).off("scroll",d._scrollFn),e.scrollTop=f},800)),g&&c._status(g)&&(c._setStyle(g,"loading"),c._loadingAction(g,"pull")),d._moved=!1,c.trigger("scrollend",a)},_enableScroll:function(){var a=this,b=a.$el.get(0),c=b.scrollTop;return 0>=c&&(b.scrollTop=1),c+b.offsetHeight>=b.scrollHeight&&(b.scrollTop=b.scrollHeight-b.offsetHeight-1),a},_bindScrollStop:function(a,c){var d=this,e=b(a);return e.off("scroll",d._options._scrollFn).on("scroll",b.debounce(100,function(){e.off("scroll",arguments.callee).one("scroll",c)},!1)),d},_getiScroll:function(){var a=this,b=a.$el,c=b[0];return{el:c,deltaY:0,scrollTo:function(a,d,e){e&&(a=c.scrollTop+a),b.css({"-webkit-transition-property":"scrollTop","-webkit-transition-duration":a+"ms"}),c.scrollTop=a},disable:function(c){c&&a.destroy(),b.css("overflow","hidden")},enable:function(){b.css("overflow","scroll")}}},_setMoveState:function(a,b,c){var d=this,e=d._options;return d._setStyle(a,b),e["_"+a+"Refreshed"]="pull"==c,e._actDir="pull"==c?a:"",e._restoreDir="up"==a&&"restore"==c?a:"",d},_eventHandler:function(a){var b=this;switch(a.type){case"touchstart":b._scrollStart(a);break;case"touchmove":b._scrollMove(a);break;case"touchend":b._scrollEnd(a)}},afterDataLoading:function(a){var b=this,c=b._options,a=a||c._actDir;return c["_"+a+"Refreshed"]=!1,"up"==a&&(b.$el.get(0).scrollTop=c.topOffset),b.origin(a)}})}(gmu,gmu.$); \ No newline at end of file diff --git a/dist/images/calendar-header.png b/dist/images/calendar-header.png new file mode 100644 index 0000000000000000000000000000000000000000..db4ec279a18d342112b00985b69bc539487a7bbd GIT binary patch literal 682 zcmV;b0#*HqP)o%AsrnZBO@ay zC@5Q7TO}nWJ3Bk0qoWxa859&07Z(>C92^=N8W zE=^5M6%`d89v(I}HdR$sA0Hn-KR;7bQ!OnmFfcG)US2&tJxfbVLPA0>FE3zVU_(Pg zR#sL?Nl8aXM>jV&VPRoKMMY6jQC(eKL_|bNN=hIgATu*FJUl!sEG#}gK2lOrG&D3+ zR8&k%Oe-rZI5;?0S67WnzCi#00fR|IK~#9!Y|-m-qCgY`;5MMkE-N5c1r#+A?{`En zX5as@_RJZ9q>8V)s(a4g!Jk&xFWG*%XG{6UY0ggb6PwF7ezn3nj@R*;#jpKu9V3b3 zBuKT|O?12DY2ccC%$P7!_8B!|Jf2 z$QEeeyjYwUXG+rqlRKN-C*Rz0d#~NzZ;S?hx57?}c2V>deNiHsJ48`5hz2!!h@i}} zGAqkLDbLv;6OhhWI!oD1z7YgL8l;rqJ52L@non6??;LnO@dSIr8%6XJe_LVnlQ;4x zBY2+I_xg-R1^tHAw-^mrx^C$fMYcc#rmma1NoktEHfy$NznHL%nr&2P1BR*^syx%E zAXL>*4Jl2F^LRWC$04O@0_A#Du1bv_0u~-wg3PC literal 0 HcmV?d00001 diff --git a/dist/images/cancel.png b/dist/images/cancel.png new file mode 100644 index 0000000000000000000000000000000000000000..cea9e385042e50f0438bc61ab004ede850f9700c GIT binary patch literal 538 zcmV+#0_FXQP)ccdjO;G1u%jVv4*m&^GYS3)5`uAM^FP3_@FO86P1wqhdf!WHDz>rIy75ik zz02M8bML(#M=cB#~*F!h4C&8Hq$$Nbu5ASC7oSh9a z9F0aNj8B|0#zYz}_4<~+-G_IR#W`bq!69}7bo(JcHFd7D`UlJ|c96)tHevu8hT#k9 z7P)f`{A#r#)YP?}K_#HhNPm-8q)vgyK>kaluIZ!k8>#Q~cY%5xF=wZV zv;nDyq81cQFU5jV1&>v7QZI^sKoJircoET)h!;T+j{&jx7eqm!UTS+NN)<5_#L}WM zX<`#&c6WR;+f6o`O}c3_;pHte^S<}J_h#NMfsHYB{pS6-g-@4CrQ!fL3_o}rgwlVJ zh`N$II+A|$@WCxPC;n0wuV(Va%Ea(U687#(KwwAED<)L`mSJ`IJAC>00d}ca)v6d~NE-9)aLIRM2MfRNe`*{`4XFkj!!!B8ZM-njJGLdBx%fx5u) z1=Ixd2P0u13^d)4UWK`3Vm*^K`Q*+$h~p2dAx5YV!@!Ucv=>9*F~P8=8J?nbuGbmc z=5#C^6S>rT#8QIl96@y*^Qn7`&4sF?XyS-54Vh}&WNP=LVJex(f!53Lxdp0u1a&)O zj&mprB@(+;rs6&k{8?J&R2B-6t?Ju1Z8?0w^!M62(A-+jaw_r6RFOJ;()Ln%AIu)E zGe2H(+FDBj%+Ai4)6JZ?&5Ql4epH0wL_SO1!LZXYGnsbkbG7XQ~h-hwu5;7+eKhE`DQ9;3$OTXdP{cS?zM}*xe;r!Ro;O^NgsqvXpW64*z xwn!Qd`2eaRlqibQO}9fSpkxtnMNIq`U;u;zQKbchSo#0}002ovPDHLkV1lg2X)*u+ literal 0 HcmV?d00001 diff --git a/dist/images/icon.png b/dist/images/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..44edcad2039cfcff00728439c9f972a174caa3e1 GIT binary patch literal 396 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv=3*z$5DpHG+YkL80J;1DJ|V9E z|NqzSI1fiBvUA0NQmiFGe!&caO2#fz?z+?f1vm>lB8wRqxITa|qthCb89+gq64!{5 z;QX|b^2DN42FH~Aq*MjB%%art{G#k)1?ONBwoR880M*_0ba4#PnCKhW&D&zYvGf%~ zl~u!Zi-tH!2i@Q2OFk^PdQ75n4}Xx7wY->Sd{(;HoWp8aD8<8k7ja3w`szv0KW<9ea=1ibMEV!vy(LvE(;eB5J1}65RV85 z0Ej)@wfhP#Gmy^TOz@g>b;n&Lm9ObYZdgS?g0Ef`793E(^K(2U#a*o>x~G) zPGk!PFYlJOw~TE&h0=^5<>xKGXZr@kOqE2Mj8MB$$ATv{K9QH6{fLeX#n>rITq9yr zZT`Q&ex_7_?Q3rEgcD58{zzKLUpIJ19ecq3%jO|1k^_G&zi<984Pc%UmQV{wNoWI z+^B#Jv;$lq0cJXA#suiF^HXTvm*mF^B%1XQm$m~*ZpMiRJC<oyc4QEr%cc1r5~?!E8Q5%-G%^e> znqkD+Sj;?1W5{yp*)Zho-)}4Is|rpLaO8Z>){OO|S8Ml->M!KXUnO;$Jzrm4$n7~y zoFT%LPq)%Bnk$~;P4;P`96gz)Y_0IuFxX+?i=F- z9S4=(rhI`D80+~ZQMKCA)PUwI8Pqr!azWlP{`{$s9f|T1cNApQZ3rTmyJc>|#EuH8 z_#0cHWn)E6{*CBo)l7}50$MC3c8X#-+ULtoTH7fADL)iU1XJph#6-R2YGNdK7w#00 zwR@3%A3V&issXwqEbeFG*1Ka^k~u40cVAWW ztO|GC@cu5N{ud|5;6^f~g*cBu9sh z*O)4sxQ+MjmA$E1z_S*{bQDqP0O|@ORAs6=bMO|jW8T%>uwaDG%ix<(|?Rj{Cz9aaEw(Gy6_oRY{ z>E+y5WcYC!Ip6)+OJS$?YML(}(Fudw7jn89u9ub0N9@=wcdo=tA9Gh!qwf?q)LXK6 zSUV`V_hZ_+5q&TX*f&sql%al8+E9rs2BX82$lHOS z6{y0c6-s+Zz$Ga{QQY}fif-9axY3l%1$$ERrn)%_6sVZ$7h3c|Xj*;fAzpF2|3ov0 zZB&HFfJRpOt8Cm7s-`sx)CHvl)#lj@WFO3ZbZ&G5hA0;VEjKS-PBimdH8)Gl9kC9D z#9XdAuGbl&0|$~v-Zb&rE;-G+u!}0PDw6_hG(~}PCc1n1+64z>M>-0o?u^8ua!wW3qpT_e(Gv_|_E>L%A^L6`5i;aCcv|FUYH( za>$0*L;KMM0Oe69ghxC#4^&*b?{p3>oOyU$waki}FW~KIBM-Euz+&?Wk*CFP9U^&% zAdIDn2cvEo502M(Ef@?m&isDu>$d*gV{sCqPu1LbMWWT|?#66Hb1NUp^;>*CE6k-8 z2{#`Q52UgOS?-`>f*KLRVls~=UI{WUh3!2B8d0>cIM31+etoBs*q?r})xDtwxcDXuC zZ+wpojT>~8z(}9r#&n-h{cN1zATlsYo3&x2>1rvkBu^YO;&5)EMd(IeT zrnZ%Qz+s&66YXH+ei&pe-sftEFytke$WD%prNro*Hs0fXJ3yvr>Mc`DXu#n@HS-&T5^JYkN}>+g(6p zCTnqC7^k{v3F0xj)?h_%+{d&`G7Ff|k?x7@(ZpS+8ysG>yY&VWiCaw3pD^$k5Wg1I|fDkRag8Q_TzvWct zy_)fDs<#jUW}D%~aMEkzeOpV$PXqz!CgSvqTCC%YRVfUO#Q2yfWl862Dwun!s#MeV zAQ3AjXfc#}+r`>+!&ubLj%H2zlf}3dDjn1M04caz_xSJB34@+{8 z4njrN4!l&pRn+NXFz{VN!TL z$-HL*E90F!R}hjRzE?T~g1Ed(qi>+3q6>sF4Onlrh~|5py|W>inR8KxVGx}l<$kisNU@!wIO-8y-A9rsebH;;8m;(@pSAy1v9nY%^%;N9xx$>)3 z8l;I=QFKNc=!;l*DffgfouEuIFZzXLZ}`n`sgr3W8nVh{Ww!N-bc9UmFb2c>(kF}` zYJb`#2e+!8uo}$tV;e6U%w!1zSO{$R%=M#?ci&@@aN&vKyJTJI>9wB}`@muNvZ3DY z%?&I@u{>(S?M!-Vtbbbro{UpX8B!$Oq^dekOSusm^?r_w*ZSwa95Hv=YK1<~6S7`f ze)mbczu0PLXd}?@taHu!hDW%Of8CkvVQ(~*QmyUfCu=Q->hAGOg01l}<-LcIWw4c| z@yyv@B=eC2fpcvXowSX!x(WDcg6UxD=&7AwP(;kavxow)lsS%n^J~M z24k_I8gzS(ckrZbu6Mx^l-fB*ep`SDAq;}*6RC?dP-v@(T&Awq1yyR`3z3(9Zi(}kU&Ny{y7K%@ zWj|~{nSx{@z3p-jic5c%5%6L8t-^m8WKuRiOyZ08Ipe9ljP{tanp$TTha-az>SeFCnqcU`!aom@$6~Ma8kXJ<=c=NWL8VcP=ROPg>sC?x!h1Me_S7 zO_6^LnK9RB?KFjOtRat{>Z_7mnQ}z4g9q{NFgln=630C`nt$MRpF`;x84DEIxn7UNU_ z6tT*gS-ldTlExL>hU)bG11B2YvhUhQ{qjshLpABhRI9D#W+8k*r*r_uQ{Zrz{4aV zlr@VmZ-646-rD`G^w%od=hofo=(z$;GT6o88_PLroV5hYPjMAS5nrDuz7Y%k^5NrM z9ZZYvxYDqN=?c}-DH;DdhFwRTxNR^ku{+%yRi)EhCZ3JSkcJg+_RPvDpL32?9R~|@ z*&Sc>Rb?fka$fIKPgucI2?VfZV}w(Gh;ua=Lx@gl;AGW!{4}f+jHXKOV@zN@U;JK@ za=yz_*qZEI@Mu`7-5Y_#3JB8f{Uw{ojV(8pz|1TYeCT9F4M4AUjz5KM$w=l25sYxr z_sc!A{!?PlEf&sQS$Rne7@Q!Z*2`%z;p`TfLj>@$dP|fkr`&Y8uzq^4*wgbtd)a*%a8~kzL&b z#Hg6&D7OxIX`%a)swjeE#!zLnqvh%E^KML#qSn}Y#%-ziAeU1$BE3A~FSyae*=*cTSWDO58VS@rhGEgg2Y}bC06fiuclI z#o2-pZCeg0iV^g=^#ro`myOz0l2ne>W*L^l)h>(%z=a(=E}m=n5H0>&#q4Cq*AI|I zkBk(*O)3A6?)=2Q21t|7OygjB8NQe=y-NMPCx8FfonB$m3Dk8}xIXJeauC@ZLOt1_ zoJ6oeMzQmMm(Afhmx3CkHx6bLz+qg(uh$FdG|lWdyfqpzzXWq-wKKpn#y{_V(aiZV z0Vmb^x&WxQ2JYpWn{Q{F>E$pRi6GNeCGqh!rZ?V5J$O$BqD!nSD%#HL>Bb@b!4)Qo z0hEKU8dFS$H`9N;I`NhbSoDZgV}D%xoL%}dPpPYCSTvkVWr;V`S;E785yG0yd~TeT z-$UHRX((=f+f3R-eQGJQRMr~ze{g}+tnTDGW_e3bV`QX+=0L{Yw_i6Uf@MJpN)1L@R$^ZVTFTW?Up6Z*N&=Td;1kT^#6ZYd8io<9! zFLMoOSi6SUw67H=+=Q-JAGu14+p9Q)KLl&0zS_4_i{%Qm+rt#?S8JvjjyHZ*hm+#N zZ(m6`k$4MwZ5mnJ-=46yUNUovM1>rVN61ok>gIVJo$B83KHZ%pb(Jmg7O66$4(|6y z5uE@u>t0N!rul9y=MyX*=5jwIFuhki#vdi45vhvC(SS)YF$3yBC9u3N~)dXvyJaHl{B;>$v2 zMI(ei)pg|f-CS4G*sOjO6U190q}Dk%Zl5)=aWMI5_~xX0bZwanR+SLl{-d{_aR$zG z=Q=*)qZpiYec1J0*xHLaa<{I**3xTNMYT1DgLz{^XpQq#2)H~Sg)dnG6%NMNp05(pk5N0TwPGYisyl!OOc z>!+Chs%vh7`)mqvq`F(8&7lvS%o4J>CB*>T1AKasmVoXfLTkH`&~RWaUWb^T2*<80 zQOkhk$3KLaq^3meE7`WHuWDYgrUl8MB%fTJ`4I{u6?x6?l$MNa+B7Fuc|=@9wN>Cu zU6sV)<7-Y742(3QM((~PH&s!adV6Rs^`Wg8WzIL)fMeb=gag~z>5h)lPs$aLRzW#* z`qmh}xB)Gt!lTO!6bL&PczNE{scVum>Qu;E{g!?S-TTTJC0R7UV{qTpX^|@m`lArCv&uZ z?bu?#r2=nVY;FWC+q)xWleBpGhLnt4JEq45m~Tig@l3u78eSGGCaB5*wu*QvU3lws zY-xhVrwe%46mnr*TM&yKA;-WyF&tVVL?ziX>;+8}4RV>=#eKYwKJUxplaZjbFHhYm zcA`I54%XdIt4_-wO)-b!RTw|_v71-1obV(aQN24?p$F4ljaquqgj8&e1A(To|Gve2 zZ1T^_NI@JAP2oCApa4GVgp=$!IW($B47l_P`b4mR#ql*Ssp!a#r1LC!LlJ7%$cAo< z9D2c_L<;i`?zf729`GtNESFD+xKH|L9Xon`4#(+j2#MUclblK3v*6_T==xCc!e&`^ z;T29PmIxIpacBLM6Tg<8;nTZ}+5D%9!%~=Zu+R$g&z~A>tFSqOSh=mdB`hLv^&8^8 z{=z-u3;G-aJfcEn!&!v|)D*=hN%UV_NiN0Qd&vua-gi(61OF{LZi`U$ymSKr6@ndB zBi7vnR*3|{J8=mm+j! zuNKo=V0f9RW5L!)?_IBOy;)_bbfchDsH;mqroCGeV6LE#Lh}Wx?q6&wBzJF7ZjO)Q ze7x+>qLC`I3m3m5R^M%Y2~}@-wg4kp+yo{^9c(m|5j&6Oc#obTt6pJ>weBNivnC!K zXc%%ZEBihY)SdweXCIy^u}u^YsHk)9uT_dWl~^85%&UaFvanU~e0ij*QQO0v{U}g$ z)hxlOn+J`Q#3bRBy~k(2#@@2Ua*VrK^)hYuMw-rAPa(;e2f)m#ymmy0O=mK>*+CG$ zeT2(rgG=JT!eD#Y6J~pRn9W(QXS^nPs$esPK-{`v!+18kiBoJdIOi| zImTWZxC}*PgaydUTvcIst1KJUSw>YE8gk_HG*w5+%6v$QhCYiQ5`KyL*_1YCJLk@a7=|a<3Fxw7liQNo6AM$gy-T&;Z1^KM%~7!gDOnB zY|g~RnB6=XpcF8BHk4ZdY)c)&9qByc=T){#vwcU5U&Uajy8K;EYY*^YhYn+JRS~i+ zF-jhVrgj|jB-I2&CdSWtKVjELrZ)213;Kim2eS8|krIBznUcH?zmM7%Q=Uxn7!;I% zE4&_eea~-ZtXWn4^MSE%9hJz@fSlXuOo_i9&cr;pbJF_5*{`XlYkR5Gu(zUs<@K|i zMR&ChCF!LOMBYuFiPP1X!W&(( zuJauxEO0sA{k@Aw<<3Z65wA$p;sz=KyhGC#s?qhM_am7*O}md1Zu9J>NY2DM1+scy z>zGrjPCCw*>KwyJn|14jR4Rbsda_aQRxtb`??2Vs%Eupqmq}e;6IeOyd}_5f1_<_z zo?5NmX~FNs|I0XJM7j`S+Ye*uq~ A8~^|S literal 0 HcmV?d00001 diff --git a/dist/images/r-flip.png b/dist/images/r-flip.png new file mode 100644 index 0000000000000000000000000000000000000000..ea3a91a5d5d2fbceb4416dfdfe7b70ddbc2f21a8 GIT binary patch literal 1480 zcmeAS@N?(olHy`uVBq!ia0vp^0U*r51|<6gKdl8)k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+m=!WZB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPAEg{v+u2}(t{7puX=A(aKG z`a!A1`K3k4z=%sz23b{L2gXBV%(zLsugUb7M0{Lq}Ij6DLDw z7Yjp}UYGpj(%jU%5}4i;gkEQydO-;xw*Y9fOKMSOS!#+~QGTuh*uz$txZPrj(>$o& z6x?oc#Hm*w=oo!av?4__ObD2EKuma|1#;lYJ~a=R){8)ix^>$Z1_mZOPZ!6Kid%1P z@AhJLlwf^uH{(N7MdvjqDQ>|_H*R;#?d4yPkgS=swD$+czJ}HZ$~QXJ&h>Su>0Hpk z5@;y-|6pW9n{0WR@pO3`cD^;iDvzI^d6VR!)#5SXmnS2K0|S#l0|x_$p~S$Vz`)qS zAkYA0Fo7kmUb=aw^lQ-LD`^LRH2iw{h<8_c_&K#xhQX_<_N~;PqjpNNU|qr=;fAuA z%g&uvZksjN@YAokw_Plm^;Tss{19<&y7mK}ty7y%8?haDrEPF_tqY^WZ_yng8(P^J zw!}BCZTiU1aEnu?DeBsSRrXxf9xNE&I0O zJ5SyD&{tevBhRLvko+)Z*WBMf8>@s~vRzmp7hGPH+YM%c8qCSu z_wk&G%}mo*`%aq|?k)9=)=)`m+a6jt?;>Nh>hl1OBSw2%=CGSFfR!_A! zb;`T;@lUody%M>%+gQG|o?y}!S&;2wR-woktGMY9H*W;%MV2eiTEv+zh;8(1dVG{g zhBZ*)*rEqVS=MyVkYZT;;3!+k#<}f=A1xUAnj~cVxf5hv#46@6tX9}`@G)CP^9ing z8~1pdp40j`3U_H|49fy!1- LS3j3^P6u1geQY^(zo*^7SP{WbZ0pxQQctjR6 zFmMZjFyp1Wb$@_@G9|7NCBgY=CFO}lsSJ)O`AMk?Zka`?<@rU~#R|^BCTyE7F950& z1F3T^N=+=u%+FH@$;?egnPb64Cnh#zo#H2Z5G{jS&s1 z0bC^soLdrHFLh3F&@9_v*YMHh!tC9OJKO&XFA|8|FC)b{b*5v;ejC27MD?QrXI4aS zuut(f*?ed1_V>T;>~vqCVj-HvHP2qeLiCl)oA|H`Ds#A6A4KeyIelnlK(<6tq1F{K z9d7aNtbYr>B}DId)**V^`EOI}ju)b<&!p6Qu6LAeFf5OlYyDt_%(1ZKe|bxCa-XED zoYgNodg%2=?S{^Z{5RRwNoovt8vSpu96VpMc*)G8^Ss(OTK1ex%;8HemY99`hRm^L zy9(L&=yS~MK6`h{hCqwecYPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0mw;2K~zXf-IUKq zL{SvShiDZ;M5~Ba(W+Iei0BV!HLGY9ZCgd#wh?WIwnM8{L$n z?+7|EUe!ymcZh0eKF}NnVd5Y?SBO>bt;Yy8&6^AeUBmwqXACxbnmAk%6-kY+N;L!~ zduA)l6bq^?WZ25kb>5kIVtg;KRWq~V@Fjm7AN7V5q1%oeCc|k*%e300 zktZ-=wvzrlGU>6%xK=j;b!{zT-eJk-{{x+KFCulWWTAFR5%u*s8NvB>5slJTnBF_| z4ezFVe+#4xS<{op=p??G;U0_6G2*&D5*ORofnQyha_%!KMPdK|002ovPDHLkV1l7{ B^`Za( literal 0 HcmV?d00001 diff --git a/dist/images/ui-add2desktop-old.png b/dist/images/ui-add2desktop-old.png new file mode 100644 index 0000000000000000000000000000000000000000..1d3a988014985efa7911330584230acc398212c0 GIT binary patch literal 264 zcmeAS@N?(olHy`uVBq!ia0vp^vOp}u!3HGfp5L+xNHG=%xjQkeJ16rJ$YDu$^mSxl z*x1kgCy^D%=PdAuEM{QfI}E~%$MaXDfHZo#IEHw5zn$jI)nLHmQk;;lz>ybQ>Bk@N zV%aQ?yQZz`bz*80d}Y(JjC#5nw3g~rFaA=)YQnSX$xXqtJ)8@oo4)c~Fv#e*#d6~e zgVizV$E9x+Ba>9W3{sN&Ms5g%giUW z@BUR*V(L54e?YyiaN~c&Nz>z=Pk+2J=+n)ghv#=bWBmR-PeO5~-%OxG89ZJ6T-G@y GGywn|3uB=G literal 0 HcmV?d00001 diff --git a/dist/images/ui-gotop-icon.png b/dist/images/ui-gotop-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a2e03aba9a563190bf699aca0ab4b4fd051e582d GIT binary patch literal 522 zcmV+l0`>igP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0iQ`kK~z{r?Up@D z!%!4J1A^crbP`+z!By}F2tvWhso>N}@COu}oCHB|5(=)aPOd_KfZ*gL1e}CIA#M7V zHf_@DxegMm)+Xj99Soch9`D_I?oD12YciP>p&>aQnqNIEPA@rne56(nD-1)I3&|Vx zSS*plJm)E+`PIYvKTLIi7ME!8weS07Q#s~}I~t8Dh)9I9xfZ59 z34wjO5g;T{7%QcnYi7LRaJU67iDeqbJ><4C5#mi-E-*3h^OXqVgKZ zZwv;52j(vu6Y@OoiX;+)8zVCPe*Xv=NkAo4Av&>(jGsV6SQqg86jKpGWP^YW(7;J? z+wJz|pM;vt<|qyD0A-7}qP+kjf`_9rCr}3+$OXr78sxrs0|vzgA^klGl&tfzlCWH z019x9hmY8Y>O!RRxu~Ee8k^TKbeR_ zY!IJ=@}cg8llej>+yaF$rDH5Ha7!!-Yi5qe<4xc=3>JgN;Luo{DHcyO!x1qU_?HI( zdJ{5&iEj3eUwnZ*8w6V{77)?s@bGX{xEYEsWTCNER#r=+abyA>i*>-+I@sZ? z@OGAVwitpX-puYR)}Buf<1%^TuUN*vSiA3HmxRC-fS&D{Le2pu!%@iR!apTUVJCVM6i)VdH9brhB)1ArCE6nk3_ zN&kzzeW|JeTD9S-u!cYra&R+zIdmg!=;}|e2xx!%k=uucx4fKe`|C%rotEfavhhH9 z>f_#&@)>z}?RydND*thDS+T5GrXQB>Di?c8A1%su*Z%FXz2Ic?rrI8+1_KEGT+$(# zkcm@6b%(qyI*KnoNbtLUfa+HzbXb_5b*ikaEGpQZkyLx|{aqIYva`2$1~iqjINFq| zwAk)K$gh#Ss-GR49q;%^1r9CDor{c&M9h~5)cq1M7-#fRM0)w4bkF45>4APNQB|&Q z1>*>t&0hYjN#Od(`oo9!^2yiF?v32bK-0SNDYVy5TPntY#*AyCao5F}ive{>W~}x^ z>0jP|RaaLx)@oFK7`_$v?xQVn^X7B+_w`qDDhgfZy8ql^w=L_C273ey;@!%%Yi6z8 z4H}wTPW&`GT&^8(Bl7aw=;2F24JrVp)i?V6ThrA%`NVyLe_lRmsOfMy?~$Ps69-jG z2NROBHJ3I1Gxg9QpyTp-%O}6S&Fa6~VHVt4)P{6v*M0hsp1$KONlL<@d{B@b`5}>q zJ2J6!Ag_c1yqC|QS1a`?;|OzycOBV(+zKJc-5lP&{kOQZowQJcBk#R=-hH}|GGA7xQy{Q46J$1>c$<7Xd7b>2 z2d}4SS4CA--{?vs*i_LE50(348&vg^wN1NF`IEq=$UJ0~cVlT!oU(e4d}fH8wQ=?C zX=SQ^;&_x?7JGH=-niB>AQZqw&j~s#Zp{z`nZC(4v7)h74`Y0q*=okR+!u8R-)sNk za#R=ZdilzgB+|imbEwGSo3X-?#v_xm$Jb$6FU?~T$IHr4wr8KE7EC=$Wo{jB%Nf64 zyFCMCMYRbXo{-7BSRH4iL(009`=rKL$;-ejofxEQP4s-l&Boyx${M9Xen^Nr#=CA7 zqKQ;xshB9%jQ1+7)NbzkoAvX%v$W>p8_$HKk4;VW#>ScNP%M2iQ#ILh!F{AYVP)h8 zjgpU`4rupInWnk5IU9zapt&Ev76(7!h1}Mc8|)VlfM&I27eGd*;B*d$v)|t=;~r(5 zq~yM$N9+)}60J?RR12#52q=*#gna7Z#nT0qTV4Jr+|2M&xokBs)9XQh(Od323S=Kl zQQts9nrNkIHr*~Y?=HM>-YFHK8B(XbW|O1SykRq~*pcM-X^X{`~uZSq@ zSV*Q(wENEEMpyF!_m4EL$P69shd(u}e5)CdQbXFk@Ak6ARUYxJI1T5dlFmCGKzwrV zji{@r3-ejV`QQ$tJ*iKiEiTNLKXz_W^7Qc2&_N#Nq}Yp}0+6Ko!ew2#r{L8%Nnu~M z-D>}Cy^<}S`Z_1M<`x!4om#KcBF?a~DZYoPm9e7_k>#ZUb^b^7ZK_Qkz)v8F^&jEQ zg2wZ=CkO4*3!>edHG9CcXH$@G8$uqGtadMSF`9xg(mnT_F?KeSWQvok^kWUj+E3>+ z6B(B0d=;dbsyAImoPthXOl(`%se!nUG?7e(zgVSlP*+#iK_n7+swzCLiC8lqkuTaw zk#ApV07)dtno>6ypkdakQr(k<#w!K~Z$zzxEtILT%J!`#H5O8Hv>-1&DG?v^wIC-GD)RqDUx!M&Wev((c>Pm_S!8svO?qWF%284!g}J7xeMvazwL zz8_z!Y`pPzBr<;^Qyyzy9oC6uWrL?5o6DuDZG97^{sSQ|=Pj4ZrS(-X5f@fSDsu|6)xm5BLpA-%Lrur@vKwa&X=<5AdoKmW>0oK`CB|#+2s8{!11nI&t*x8X zo^V!(6`zm@)a(04f8FX;A$+zi0qR!8>o;1lb(w45W-dt-sl3MVgtZ#5t8r_bp00`} zSCg5~nlL!evgV;EXL;{zcJA~0t>{cZVJ?J6a*bOut9IvyzD~C;J>J!DzsmmJj z+g`1j-CW{#-K%8JRaBQRBEgY;)K5;|@|&LOGWGhj{=L^IQF{}P#&oC{o7grXV#37Y z=IMc}A^sEijx~kRo)zkiy^2o$1eU5{dY|@V3zu`W*s)5IJ|-e5w+niVwR~P@Amfkz zX>vwV*|U+`$&=v4p<`{_d9y7C?{p@WQVLV}lb8Ji8dljb2+aAO2^}8gYOY#rdD8;Z zTcrd%YAL5Ty~%~Q!X63QbFH4MuS=lLboP|rilc{T*;GD)LYw;M%`1|X zL(G+;TT>_JWF?-a2e{^`(19lS%{MUM12J;BbHP59_HfUpZWGO)RN#cOdQ2R%1JyXx&B<||bVbtW=SPOseAS(LAB7|{?$n#>-4B5R`=otWaqz_*4bHNdj& z@Y^>*^VSnu$1nAd!&*$C)lIK!q{GFS;-+A$pG)^_Dz1Qa=lqzH(gL)8E}IlE3YQ$8 cZGk`m(dmwqg`92NrJn?fgR6a+UEtyW07M9k0ssI2 literal 0 HcmV?d00001 diff --git a/dist/images/ui-slider-arrow.png b/dist/images/ui-slider-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..ffdb24767371bdc8e07eec002395fa6f4cfb2580 GIT binary patch literal 524 zcmV+n0`vWeP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0ij7mK~!i%<(XZI z!Y~wtyMTF`S3wYF4T1}B0mAHK)-b#5tKh3p5QG7#bIweZ7@C?U_ZE``E|%CN=YF~Q zZPP@izVF{*i^$^Y#i)%M)f=)KK!cyK^A!od-?KIz&=@rtZD(o?D3bn)fpTHPR$8Xl zEK>tCEp1`Y`=btL2nzC!5b`GDR(dVeVl>_PsKW6?N{9S)x;wHpP!p(h>XDNZlpA7o zI5|R5hm$iDH8>+sHnKBwYogr=adX38cq#RCc~)-N-!Ki z*}>ei4|lZLtv*xNH~Q$Ab9T+ZAEz3i*pUN&PtKvZYmnJGnY>E)no2*{_v!0^|1H6M z!1gu5@j%&=$zMm~VO1NP5h$yN=&uP*FcfPdDn4>1L#Y9d2g-q?C1~+5!|G7dgq#e; ziJT(fh(Rd{jyRMO;HW{#8IC#>3l4Y4SjQ2uwc(#aej9^mj~4ttqz*wo_Q7O+F_ z+k9y#zR2Op6gKb2^AYE$g_>?#jai^LaCj=`z0Fpu6JqP7CZny5jg()S80nwr)I0b9 O0000?8kG0>6{?WD$6)0h;xGJS4p}UEi`q6-)e8^Y73E~wh$?53+XgHfK3P?==FL{594U?JP%YvxTuC< z=m35aec#7~P*Ed6e*rKOdEdu|kT9WP7~cT61n^e?CnE0on5k9N4Ke>#=Y1p(sYO&N zX0vb=HL5*&4dBl_`z=ElhG2}rah%i)hN39w_xn&)6@;{NN5@6fNX$zB-}C6NDwbuz zw(Zm$V~p#%a9tOcWkJ(442MI3BNW44qE-=8RaHED_6#3Ce%$BQ4+z5$^Z6XU@0a?{ z&CLxQ$HDped8=k^B~cB-c!fJLr$xV`sw#%VAv&E->atjsFbpx9&2ndF9=`8mHk)BO zowi2UQljoFW*yAu^U8w8#4~*|nQ$6avlM#LhbSg+XG6;@xq0}$56iMzVPlIv@izdp zT^A8TpzAtRRjpM_;BI!=w#~Iq+qR+W`q3}LMMwW8w-Z7z91by^PB9n^Y8Mm$7-M@c zyGi2h(6O_(sGDMn{D(V^b5#9`q>u`f(lvm8r+wDcCZ4AUEuvqMlu_d{tyA3wzk2!XcMJGrIfw{@V{jHdcEfEiAt(d#lyKu zHiTg)+-p=6<*51$)&algpp9u&9P%ya4d? zuIof^Z+IlQ2_ZN?Kj$=}@-W7*SS+~h_X|CZ$d0~Cwm*IPbn9Bt!3aVKrqgNV8Qbl4 z8%>ZemrE>{ORjwu{UvXaNWBq4aCUZ-wx6D! z-fz-1P1_PRPGAoP1AZedNbD7B+RmJQV=%_BTCHm9Kl85|+0nPj_I|(r;DITMk{X5i z^yw3)A+`(8^J*0o$hWEQkg%h@UJs+u_SvSiy=febkbET!LoAoe+T-M@q8f(r2Eexu zE+hn_(J0jpWz{6fTw&1z!KSO^MVhAV40QMV{nS~^GmKZ2FbwabU7qJPa(~`?(L9oC=GJ~xQ52k>p6=`@ zD;DdzE`lHsQen8s=C&ryhIPALD2f7I*J~e}2s^sT{jV_$;|d8o+UayM0}N^Cx}G{S zEz3%EuNZ=EH5{``5V4SH7UN<`?;^E{ZQ ziPdUVdR8#TV47wvHc#ZT8$+T%eQNDdm3(DZrlU?L!Sg&U7K^<+%h>Mm6v48rMvC$X zfN!!sbR4Jj!|HT8sZLd0bxg6Ky!vL0aS^tTV{BVFYf9-0WE`&m?jj;ZA7tI3L!QSNvxrZcm!*oc#*;1AmQwl(z~8gJP&7-Q6*}Z0 zY7hj%f*NI4gLr@3B&qwAs0{Qw!4wQ5})ng!q(s5n(;gYh(+PBy$s5 z#Lg}ji(K206*}A}9xS@J4Y&(b%;)pm)hS-V4uRarLK!=o+IbW@O!E2j=aR$xN>j09 z-}hmf=GNZR^E_N%UkeWf=20jvMk#$|7{;&2s3v5L!S{WP$K$P;nH4&$Lep8F_%%I; zkfg|?%u&WS0RDs=J3E`rwmedvRqyNdnoB=zr^>0f7s#=*X)#n@Mbfg8q8L>UNWI5h z1S-?cCS#~sp~EuN@#2oQQmIBVa-d!T_-EENj4^!p@ZnyFeXINAEG^Dng|9{ItZAC? zeIJUVRIZ|L+Ce%t_O51*?Cb?H>}(JOn9t{6j6v7+O800wLUU|zDN&CC6&FZ((FgD~ zSLu0PrRoCd^_GL%xr4~gz69`N)-|?m5GiU4IVhWYdwYBEHMNICRvPo5L=A#K zzI%xSa`|l`Qq&eAMQtHc)E3f|qx2p*Rfm%O_&=5U2@93i>nZ>M002ovPDHLkV1j>> 0, k = 0, accumulator + if(typeof fun != 'function') throw new TypeError() + if(len == 0 && arguments.length == 1) throw new TypeError() + + if(arguments.length >= 2) + accumulator = arguments[1] + else + do{ + if(k in t){ + accumulator = t[k++] + break + } + if(++k >= len) throw new TypeError() + } while (true) + + while (k < len){ + if(k in t) accumulator = fun.call(undefined, accumulator, t[k], k, t) + k++ + } + return accumulator + } + +})() + +// Zepto.js +// (c) 2010-2012 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +var Zepto = (function() { + var undefined, key, $, classList, emptyArray = [], slice = emptyArray.slice, filter = emptyArray.filter, + document = window.document, + elementDisplay = {}, classCache = {}, + getComputedStyle = document.defaultView.getComputedStyle, + cssNumber = { 'column-count': 1, 'columns': 1, 'font-weight': 1, 'line-height': 1,'opacity': 1, 'z-index': 1, 'zoom': 1 }, + fragmentRE = /^\s*<(\w+|!)[^>]*>/, + tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rootNodeRE = /^(?:body|html)$/i, + + // 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/, + classSelectorRE = /^\.([\w-]+)$/, + idSelectorRE = /^#([\w-]*)$/, + tagSelectorRE = /^[\w-]+$/, + class2type = {}, + toString = class2type.toString, + zepto = {}, + camelize, uniq, + tempParent = document.createElement('div') + + zepto.matches = function(element, selector) { + if (!element || element.nodeType !== 1) return false + var matchesSelector = element.webkitMatchesSelector || element.mozMatchesSelector || + element.oMatchesSelector || element.matchesSelector + if (matchesSelector) return matchesSelector.call(element, selector) + // fall back to performing a selector: + var match, parent = element.parentNode, temp = !parent + if (temp) (parent = tempParent).appendChild(element) + match = ~zepto.qsa(parent, selector).indexOf(element) + temp && tempParent.removeChild(element) + return match + } + + function type(obj) { + return obj == null ? String(obj) : + class2type[toString.call(obj)] || "object" + } + + function isFunction(value) { return type(value) == "function" } + function isWindow(obj) { return obj != null && obj == obj.window } + function isDocument(obj) { return obj != null && obj.nodeType == obj.DOCUMENT_NODE } + function isObject(obj) { return type(obj) == "object" } + function isPlainObject(obj) { + return isObject(obj) && !isWindow(obj) && obj.__proto__ == Object.prototype + } + function isArray(value) { return value instanceof Array } + function likeArray(obj) { return typeof obj.length == 'number' } + + function compact(array) { return 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) { + if (html.replace) html = html.replace(tagExpanderRE, "<$1>") + if (name === undefined) name = fragmentRE.test(html) && RegExp.$1 + if (!(name in containers)) name = '*' + + var nodes, dom, container = containers[name] + container.innerHTML = '' + html + dom = $.each(slice.call(container.childNodes), function(){ + container.removeChild(this) + }) + if (isPlainObject(properties)) { + nodes = $(dom) + $.each(properties, function(key, value) { + if (methodAttributes.indexOf(key) > -1) nodes[key](value) + else nodes.attr(key, value) + }) + } + return dom + } + + // `$.zepto.Z` swaps out the prototype of the given `dom` array + // of nodes with `$.fn` and thus supplying all the Zepto functions + // to the array. Note that `__proto__` is not supported on Internet + // Explorer. This method can be overriden in plugins. + zepto.Z = function(dom, selector) { + dom = dom || [] + dom.__proto__ = $.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) { + // If nothing given, return an empty Zepto collection + if (!selector) return zepto.Z() + // If a function is given, call it when the DOM is ready + else if (isFunction(selector)) return $(document).ready(selector) + // If a Zepto collection is given, juts return it + else if (zepto.isZ(selector)) return selector + else { + var dom + // normalize array if an array of nodes is given + if (isArray(selector)) dom = compact(selector) + // Wrap DOM nodes. If a plain object is given, duplicate it. + else if (isObject(selector)) + dom = [isPlainObject(selector) ? $.extend({}, selector) : selector], selector = null + // If it's a html fragment, create nodes from it + else if (fragmentRE.test(selector)) + dom = 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 + return (isDocument(element) && idSelectorRE.test(selector)) ? + ( (found = element.getElementById(RegExp.$1)) ? [found] : [] ) : + (element.nodeType !== 1 && element.nodeType !== 9) ? [] : + slice.call( + classSelectorRE.test(selector) ? element.getElementsByClassName(RegExp.$1) : + tagSelectorRE.test(selector) ? element.getElementsByTagName(selector) : + element.querySelectorAll(selector) + ) + } + + function filtered(nodes, selector) { + return selector === undefined ? $(nodes) : $(nodes).filter(selector) + } + + $.contains = function(parent, node) { + return parent !== node && parent.contains(node) + } + + function funcArg(context, arg, idx, payload) { + return isFunction(arg) ? arg.call(context, idx, payload) : arg + } + + function setAttribute(node, name, value) { + value == null ? node.removeAttribute(name) : node.setAttribute(name, value) + } + + // access className property while respecting SVGAnimatedString + function className(node, value){ + var klass = node.className, + svg = klass && klass.baseVal !== undefined + + if (value === undefined) return svg ? klass.baseVal : klass + svg ? (klass.baseVal = value) : (node.className = value) + } + + // "true" => true + // "false" => false + // "null" => null + // "42" => 42 + // "42.5" => 42.5 + // JSON => parse if valid + // String => self + function deserializeValue(value) { + var num + try { + return value ? + value == "true" || + ( value == "false" ? false : + value == "null" ? null : + !isNaN(num = Number(value)) ? num : + /^[\[\{]/.test(value) ? $.parseJSON(value) : + value ) + : value + } catch(e) { + return value + } + } + + $.type = type + $.isFunction = isFunction + $.isWindow = isWindow + $.isArray = isArray + $.isPlainObject = isPlainObject + + $.isEmptyObject = function(obj) { + var name + for (name in obj) return false + return true + } + + $.inArray = function(elem, array, i){ + return emptyArray.indexOf.call(array, elem, i) + } + + $.camelCase = camelize + $.trim = function(str) { return str.trim() } + + // plugin compatibility + $.uuid = 0 + $.support = { } + $.expr = { } + + $.map = function(elements, callback){ + var value, values = [], i, key + if (likeArray(elements)) + for (i = 0; i < elements.length; i++) { + 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){ + if (readyRE.test(document.readyState)) callback($) + else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false) + return this + }, + get: function(idx){ + return idx === undefined ? slice.call(this) : this[idx >= 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 = null) + 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 html === undefined ? + (this.length > 0 ? this[0].innerHTML : null) : + this.each(function(idx){ + var originHtml = this.innerHTML + $(this).empty().append( funcArg(this, html, idx, originHtml) ) + }) + }, + text: function(text){ + return text === undefined ? + (this.length > 0 ? this[0].textContent : null) : + this.each(function(){ this.textContent = 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){ + 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-' + dasherize(name), value) + return data !== null ? deserializeValue(data) : undefined + }, + val: function(value){ + return (value === undefined) ? + (this[0] && (this[0].multiple ? + $(this[0]).find('option').filter(function(o){ return this.selected }).pluck('value') : + this[0].value) + ) : + this.each(function(idx){ + this.value = funcArg(this, value, idx, this.value) + }) + }, + offset: function(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 && typeof property == 'string') + return this[0] && (this[0].style[camelize(property)] || getComputedStyle(this[0], '').getPropertyValue(property)) + + 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){ + return emptyArray.some.call(this, function(el){ + return this.test(className(el)) + }, classRE(name)) + }, + addClass: function(name){ + return this.each(function(idx){ + classList = [] + var cls = 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){ + 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(){ + if (!this.length) return + return ('scrollTop' in this[0]) ? this[0].scrollTop : this[0].scrollY + }, + position: function() { + if (!this.length) return + + var elem = this[0], + // Get *real* offsetParent + offsetParent = this.offsetParent(), + // Get correct offsets + offset = this.offset(), + parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset() + + // Subtract element margins + // note: when an element has margin: auto the offsetLeft and marginLeft + // are the same in Safari causing offset.left to incorrectly be 0 + offset.top -= parseFloat( $(elem).css('margin-top') ) || 0 + offset.left -= parseFloat( $(elem).css('margin-left') ) || 0 + + // Add offsetParent borders + parentOffset.top += parseFloat( $(offsetParent[0]).css('border-top-width') ) || 0 + parentOffset.left += parseFloat( $(offsetParent[0]).css('border-left-width') ) || 0 + + // Subtract the two offsets + return { + top: offset.top - parentOffset.top, + left: offset.left - parentOffset.left + } + }, + offsetParent: function() { + return this.map(function(){ + var parent = this.offsetParent || document.body + while (parent && !rootNodeRE.test(parent.nodeName) && $(parent).css("position") == "static") + parent = parent.offsetParent + return parent + }) + } + } + + // for now + $.fn.detach = $.fn.remove + + // Generate the `width` and `height` functions + ;['width', 'height'].forEach(function(dimension){ + $.fn[dimension] = function(value){ + var offset, el = this[0], + Dimension = dimension.replace(/./, function(m){ return m[0].toUpperCase() }) + if (value === undefined) return isWindow(el) ? el['inner' + Dimension] : + isDocument(el) ? el.documentElement['offset' + Dimension] : + (offset = this.offset()) && offset[dimension] + else return this.each(function(idx){ + 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 $ +})() + +// If `$` is not yet defined, point it to `Zepto` +window.Zepto = Zepto +'$' in window || (window.$ = Zepto) + +// Zepto.js +// (c) 2010-2012 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +;(function($){ + function detect(ua){ + var os = this.os = {}, browser = this.browser = {}, + webkit = ua.match(/WebKit\/([\d.]+)/), + android = ua.match(/(Android)\s+([\d.]+)/), + ipad = ua.match(/(iPad).*OS\s([\d_]+)/), + iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/), + webos = ua.match(/(webOS|hpwOS)[\s\/]([\d.]+)/), + touchpad = webos && ua.match(/TouchPad/), + kindle = ua.match(/Kindle\/([\d.]+)/), + silk = ua.match(/Silk\/([\d._]+)/), + blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/), + bb10 = ua.match(/(BB10).*Version\/([\d.]+)/), + rimtabletos = ua.match(/(RIM\sTablet\sOS)\s([\d.]+)/), + playbook = ua.match(/PlayBook/), + chrome = ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/), + firefox = ua.match(/Firefox\/([\d.]+)/) + + // Todo: clean this up with a better OS/browser seperation: + // - discern (more) between multiple browsers on android + // - decide if kindle fire in silk mode is android or not + // - Firefox on Android doesn't specify the Android version + // - possibly devide in os, device and browser hashes + + if (browser.webkit = !!webkit) browser.version = webkit[1] + + if (android) os.android = true, os.version = android[2] + if (iphone) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.') + if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.') + if (webos) os.webos = true, os.version = webos[2] + if (touchpad) os.touchpad = true + if (blackberry) os.blackberry = true, os.version = blackberry[2] + if (bb10) os.bb10 = true, os.version = bb10[2] + if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2] + if (playbook) browser.playbook = true + if (kindle) os.kindle = true, os.version = kindle[1] + if (silk) browser.silk = true, browser.version = silk[1] + if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true + if (chrome) browser.chrome = true, browser.version = chrome[1] + if (firefox) browser.firefox = true, browser.version = firefox[1] + + os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) || (firefox && ua.match(/Tablet/))) + os.phone = !!(!os.tablet && (android || iphone || webos || blackberry || bb10 || + (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\/([\d.]+)/)) || (firefox && ua.match(/Mobile/)))) + } + + detect.call($, navigator.userAgent) + // make available to unit tests + $.__detect = detect + +})(Zepto) + +// Zepto.js +// (c) 2010-2012 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +;(function($){ + var $$ = $.zepto.qsa, handlers = {}, _zid = 1, specialEvents={}, + hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' } + + specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents' + + function zid(element) { + return element._zid || (element._zid = _zid++) + } + 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 eachEvent(events, fn, iterator){ + if ($.type(events) != "string") $.each(events, iterator) + else events.split(/\s/).forEach(function(type){ iterator(type, fn) }) + } + + function eventCapture(handler, captureSetting) { + return handler.del && + (handler.e == 'focus' || handler.e == 'blur') || + !!captureSetting + } + + function realEvent(type) { + return hover[type] || type + } + + function add(element, events, fn, selector, getDelegate, capture){ + var id = zid(element), set = (handlers[id] || (handlers[id] = [])) + eachEvent(events, fn, function(event, 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 = getDelegate && getDelegate(fn, event) + var callback = handler.del || fn + handler.proxy = function (e) { + var result = callback.apply(element, [e].concat(e.data)) + if (result === false) e.preventDefault(), e.stopPropagation() + return result + } + handler.i = set.length + set.push(handler) + element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + } + function remove(element, events, fn, selector, capture){ + var id = zid(element) + eachEvent(events || '', fn, function(event, fn){ + findHandlers(element, event, fn, selector).forEach(function(handler){ + delete handlers[id][handler.i] + element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + }) + } + + $.event = { add: add, remove: remove } + + $.proxy = function(fn, context) { + if ($.isFunction(fn)) { + var proxyFn = function(){ return fn.apply(context, arguments) } + proxyFn._zid = zid(fn) + return proxyFn + } else if (typeof context == 'string') { + return $.proxy(fn[context], fn) + } else { + throw new TypeError("expected function") + } + } + + $.fn.bind = function(event, callback){ + return this.each(function(){ + add(this, event, callback) + }) + } + $.fn.unbind = function(event, callback){ + return this.each(function(){ + remove(this, event, callback) + }) + } + $.fn.one = function(event, callback){ + return this.each(function(i, element){ + add(this, event, callback, null, function(fn, type){ + return function(){ + var result = fn.apply(element, arguments) + remove(element, type, fn) + return result + } + }) + }) + } + + var returnTrue = function(){return true}, + returnFalse = function(){return false}, + ignoreProperties = /^([A-Z]|layer[XY]$)/, + eventMethods = { + preventDefault: 'isDefaultPrevented', + stopImmediatePropagation: 'isImmediatePropagationStopped', + stopPropagation: 'isPropagationStopped' + } + function createProxy(event) { + var key, proxy = { originalEvent: event } + for (key in event) + if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key] + + $.each(eventMethods, function(name, predicate) { + proxy[name] = function(){ + this[predicate] = returnTrue + return event[name].apply(event, arguments) + } + proxy[predicate] = returnFalse + }) + return proxy + } + + // emulates the 'defaultPrevented' property for browsers that have none + function fix(event) { + if (!('defaultPrevented' in event)) { + event.defaultPrevented = false + var prevent = event.preventDefault + event.preventDefault = function() { + this.defaultPrevented = true + prevent.call(this) + } + } + } + + $.fn.delegate = function(selector, event, callback){ + return this.each(function(i, element){ + add(element, event, callback, selector, function(fn){ + return function(e){ + var evt, match = $(e.target).closest(selector, element).get(0) + if (match) { + evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element}) + return fn.apply(match, [evt].concat([].slice.call(arguments, 1))) + } + } + }) + }) + } + $.fn.undelegate = function(selector, event, callback){ + return this.each(function(){ + remove(this, event, callback, selector) + }) + } + + $.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, callback){ + return !selector || $.isFunction(selector) ? + this.bind(event, selector || callback) : this.delegate(selector, event, callback) + } + $.fn.off = function(event, selector, callback){ + return !selector || $.isFunction(selector) ? + this.unbind(event, selector || callback) : this.undelegate(selector, event, callback) + } + + $.fn.trigger = function(event, data){ + if (typeof event == 'string' || $.isPlainObject(event)) event = $.Event(event) + fix(event) + event.data = data + return this.each(function(){ + // items in the collection might not be DOM elements + // (todo: possibly support events on plain old objects) + if('dispatchEvent' in this) this.dispatchEvent(event) + }) + } + + // triggers event handlers on current element just as if an event occurred, + // doesn't trigger an actual event, doesn't bubble + $.fn.triggerHandler = function(event, data){ + var e, result + this.each(function(i, element){ + e = createProxy(typeof event == 'string' ? $.Event(event) : event) + e.data = data + e.target = element + $.each(findHandlers(element, event.type || event), function(i, handler){ + result = handler.proxy(e) + if (e.isImmediatePropagationStopped()) return false + }) + }) + return result + } + + // 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 (typeof type != 'string') props = type, type = props.type + var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true + if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name]) + event.initEvent(type, bubbles, true, null, null, null, null, null, null, null, null, null, null, null, null) + event.isDefaultPrevented = function(){ return this.defaultPrevented } + return event + } + +})(Zepto) + +// Zepto.js +// (c) 2010-2012 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +;(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.defaultPrevented + } + + // 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) { + var context = settings.context, status = 'success' + settings.success.call(context, data, status, xhr) + triggerGlobal(settings, context, 'ajaxSuccess', [xhr, settings, data]) + ajaxComplete(status, xhr, settings) + } + // type: "timeout", "error", "abort", "parsererror" + function ajaxError(error, type, xhr, settings) { + var context = settings.context + settings.error.call(context, xhr, type, error) + triggerGlobal(settings, context, 'ajaxError', [xhr, settings, error]) + ajaxComplete(type, xhr, settings) + } + // 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){ + if (!('type' in options)) return $.ajax(options) + + var callbackName = 'jsonp' + (++jsonpID), + script = document.createElement('script'), + cleanup = function() { + clearTimeout(abortTimeout) + $(script).remove() + delete window[callbackName] + }, + abort = function(type){ + cleanup() + // In case of manual abort or timeout, keep an empty function as callback + // so that the SCRIPT tag that eventually loads won't result in an error. + if (!type || type == 'timeout') window[callbackName] = empty + ajaxError(null, type || 'abort', xhr, options) + }, + xhr = { abort: abort }, abortTimeout + + if (ajaxBeforeSend(xhr, options) === false) { + abort('abort') + return false + } + + window[callbackName] = function(data){ + cleanup() + ajaxSuccess(data, xhr, options) + } + + script.onerror = function() { abort('error') } + + script.src = options.url.replace(/=\?/, '=' + callbackName) + $('head').append(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 + accepts: { + script: 'text/javascript, application/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) { + 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) + } + + $.ajax = function(options){ + var settings = $.extend({}, options || {}) + 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, 'callback=?') + return $.ajaxJSONP(settings) + } + + var mime = settings.accepts[dataType], + baseHeaders = { }, + protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol, + xhr = settings.xhr(), abortTimeout + + if (!settings.crossDomain) baseHeaders['X-Requested-With'] = 'XMLHttpRequest' + if (mime) { + baseHeaders['Accept'] = mime + if (mime.indexOf(',') > -1) mime = mime.split(',', 2)[0] + xhr.overrideMimeType && xhr.overrideMimeType(mime) + } + if (settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() != 'GET')) + baseHeaders['Content-Type'] = (settings.contentType || 'application/x-www-form-urlencoded') + settings.headers = $.extend(baseHeaders, settings.headers || {}) + + xhr.onreadystatechange = function(){ + if (xhr.readyState == 4) { + xhr.onreadystatechange = empty; + clearTimeout(abortTimeout) + var result, error = false + if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || (xhr.status == 0 && protocol == 'file:')) { + dataType = dataType || mimeToDataType(xhr.getResponseHeader('content-type')) + result = xhr.responseText + + try { + // http://perfectionkills.com/global-eval-what-are-the-options/ + if (dataType == 'script') (1,eval)(result) + else if (dataType == 'xml') result = xhr.responseXML + else if (dataType == 'json') result = blankRE.test(result) ? null : $.parseJSON(result) + } catch (e) { error = e } + + if (error) ajaxError(error, 'parsererror', xhr, settings) + else ajaxSuccess(result, xhr, settings) + } else { + ajaxError(null, xhr.status ? 'error' : 'abort', xhr, settings) + } + } + } + + var async = 'async' in settings ? settings.async : true + xhr.open(settings.type, settings.url, async) + + for (name in settings.headers) xhr.setRequestHeader(name, settings.headers[name]) + + if (ajaxBeforeSend(xhr, settings) === false) { + xhr.abort() + return false + } + + if (settings.timeout > 0) abortTimeout = setTimeout(function(){ + xhr.onreadystatechange = empty + xhr.abort() + ajaxError(null, 'timeout', xhr, settings) + }, settings.timeout) + + // avoid sending empty string (#319) + xhr.send(settings.data ? settings.data : null) + return xhr + } + + // handle optional data/success arguments + function parseArguments(url, data, success, dataType) { + var hasData = !$.isFunction(data) + return { + url: url, + data: hasData ? data : undefined, + success: !hasData ? data : $.isFunction(success) ? success : undefined, + dataType: hasData ? dataType || success : success + } + } + + $.get = function(url, data, success, dataType){ + return $.ajax(parseArguments.apply(null, arguments)) + } + + $.post = function(url, data, success, dataType){ + 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) + $.each(obj, function(key, value) { + type = $.type(value) + if (scope) key = traditional ? scope : scope + '[' + (array ? '' : key) + ']' + // handle data in serializeArray() format + if (!scope && array) params.add(value.name, value.value) + // recurse into nested objects + else if (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) + +// Zepto.js +// (c) 2010-2012 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +;(function ($) { + $.fn.serializeArray = function () { + var result = [], el + $( Array.prototype.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.defaultPrevented) this.get(0).submit() + } + return this + } + +})(Zepto) + +// Zepto.js +// (c) 2010-2012 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +;(function($, undefined){ + var prefix = '', eventPrefix, endEventName, endAnimationName, + vendors = { Webkit: 'webkit', Moz: '', O: 'o', ms: 'MS' }, + document = window.document, testEl = document.createElement('div'), + supportedTransforms = /^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i, + transform, + transitionProperty, transitionDuration, transitionTiming, + animationName, animationDuration, animationTiming, + cssReset = {} + + function dasherize(str) { return downcase(str.replace(/([a-z])([A-Z])/, '$1-$2')) } + function downcase(str) { return str.toLowerCase() } + function normalizeEvent(name) { return eventPrefix ? eventPrefix + name : downcase(name) } + + $.each(vendors, function(vendor, event){ + if (testEl.style[vendor + 'TransitionProperty'] !== undefined) { + prefix = '-' + downcase(vendor) + '-' + eventPrefix = event + return false + } + }) + + transform = prefix + 'transform' + cssReset[transitionProperty = prefix + 'transition-property'] = + cssReset[transitionDuration = prefix + 'transition-duration'] = + cssReset[transitionTiming = prefix + 'transition-timing-function'] = + cssReset[animationName = prefix + 'animation-name'] = + cssReset[animationDuration = prefix + 'animation-duration'] = + cssReset[animationTiming = prefix + 'animation-timing-function'] = '' + + $.fx = { + off: (eventPrefix === undefined && testEl.style.transitionProperty === undefined), + speeds: { _default: 400, fast: 200, slow: 600 }, + cssPrefix: prefix, + transitionEnd: normalizeEvent('TransitionEnd'), + animationEnd: normalizeEvent('AnimationEnd') + } + + $.fn.animate = function(properties, duration, ease, callback){ + if ($.isPlainObject(duration)) + ease = duration.easing, callback = duration.complete, duration = duration.duration + if (duration) duration = (typeof duration == 'number' ? duration : + ($.fx.speeds[duration] || $.fx.speeds._default)) / 1000 + return this.anim(properties, duration, ease, callback) + } + + $.fn.anim = function(properties, duration, ease, callback){ + var key, cssValues = {}, cssProperties, transforms = '', + that = this, wrappedCallback, endEvent = $.fx.transitionEnd + + if (duration === undefined) duration = 0.4 + if ($.fx.off) duration = 0 + + if (typeof properties == 'string') { + // keyframe animation + cssValues[animationName] = properties + cssValues[animationDuration] = duration + 's' + cssValues[animationTiming] = (ease || 'linear') + endEvent = $.fx.animationEnd + } else { + cssProperties = [] + // CSS transitions + for (key in properties) + if (supportedTransforms.test(key)) transforms += key + '(' + properties[key] + ') ' + else cssValues[key] = properties[key], cssProperties.push(dasherize(key)) + + if (transforms) cssValues[transform] = transforms, cssProperties.push(transform) + if (duration > 0 && typeof properties === 'object') { + cssValues[transitionProperty] = cssProperties.join(', ') + cssValues[transitionDuration] = duration + 's' + cssValues[transitionTiming] = (ease || 'linear') + } + } + + wrappedCallback = function(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) + } + $(this).css(cssReset) + callback && callback.call(this) + } + if (duration > 0) this.bind(endEvent, wrappedCallback) + + // 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) diff --git a/dist/zepto.min.js b/dist/zepto.min.js new file mode 100644 index 00000000..f170cabb --- /dev/null +++ b/dist/zepto.min.js @@ -0,0 +1,2 @@ +/* Zepto v1.0 - polyfill zepto detect event ajax form fx - zeptojs.com/license */ +!function(a){String.prototype.trim===a&&(String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"")}),Array.prototype.reduce===a&&(Array.prototype.reduce=function(b){if(void 0===this||null===this)throw new TypeError;var c,d=Object(this),e=d.length>>>0,f=0;if("function"!=typeof b)throw new TypeError;if(0==e&&1==arguments.length)throw new TypeError;if(arguments.length>=2)c=arguments[1];else for(;;){if(f in d){c=d[f++];break}if(++f>=e)throw new TypeError}for(;e>f;)f in d&&(c=b.call(a,c,d[f],f,d)),f++;return c})}();var Zepto=function(){function a(a){return null==a?String(a):W[X.call(a)]||"object"}function b(b){return"function"==a(b)}function c(a){return null!=a&&a==a.window}function d(a){return null!=a&&a.nodeType==a.DOCUMENT_NODE}function e(b){return"object"==a(b)}function f(a){return e(a)&&!c(a)&&a.__proto__==Object.prototype}function g(a){return a instanceof Array}function h(a){return"number"==typeof a.length}function i(a){return E.call(a,function(a){return null!=a})}function j(a){return a.length>0?y.fn.concat.apply([],a):a}function k(a){return a.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()}function l(a){return a in H?H[a]:H[a]=new RegExp("(^|\\s)"+a+"(\\s|$)")}function m(a,b){return"number"!=typeof b||J[k(a)]?b:b+"px"}function n(a){var b,c;return G[a]||(b=F.createElement(a),F.body.appendChild(b),c=I(b,"").getPropertyValue("display"),b.parentNode.removeChild(b),"none"==c&&(c="block"),G[a]=c),G[a]}function o(a){return"children"in a?D.call(a.children):y.map(a.childNodes,function(a){return 1==a.nodeType?a:void 0})}function p(a,b,c){for(x in b)c&&(f(b[x])||g(b[x]))?(f(b[x])&&!f(a[x])&&(a[x]={}),g(b[x])&&!g(a[x])&&(a[x]=[]),p(a[x],b[x],c)):b[x]!==w&&(a[x]=b[x])}function q(a,b){return b===w?y(a):y(a).filter(b)}function r(a,c,d,e){return b(c)?c.call(a,d,e):c}function s(a,b,c){null==c?a.removeAttribute(b):a.setAttribute(b,c)}function t(a,b){var c=a.className,d=c&&c.baseVal!==w;return b===w?d?c.baseVal:c:(d?c.baseVal=b:a.className=b,void 0)}function u(a){var b;try{return a?"true"==a||("false"==a?!1:"null"==a?null:isNaN(b=Number(a))?/^[\[\{]/.test(a)?y.parseJSON(a):a:b):a}catch(c){return a}}function v(a,b){b(a);for(var c in a.childNodes)v(a.childNodes[c],b)}var w,x,y,z,A,B,C=[],D=C.slice,E=C.filter,F=window.document,G={},H={},I=F.defaultView.getComputedStyle,J={"column-count":1,columns:1,"font-weight":1,"line-height":1,opacity:1,"z-index":1,zoom:1},K=/^\s*<(\w+|!)[^>]*>/,L=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,M=/^(?:body|html)$/i,N=["val","css","html","text","data","width","height","offset"],O=["after","prepend","before","append"],P=F.createElement("table"),Q=F.createElement("tr"),R={tr:F.createElement("tbody"),tbody:P,thead:P,tfoot:P,td:Q,th:Q,"*":F.createElement("div")},S=/complete|loaded|interactive/,T=/^\.([\w-]+)$/,U=/^#([\w-]*)$/,V=/^[\w-]+$/,W={},X=W.toString,Y={},Z=F.createElement("div");return Y.matches=function(a,b){if(!a||1!==a.nodeType)return!1;var c=a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.matchesSelector;if(c)return c.call(a,b);var d,e=a.parentNode,f=!e;return f&&(e=Z).appendChild(a),d=~Y.qsa(e,b).indexOf(a),f&&Z.removeChild(a),d},A=function(a){return a.replace(/-+(.)?/g,function(a,b){return b?b.toUpperCase():""})},B=function(a){return E.call(a,function(b,c){return a.indexOf(b)==c})},Y.fragment=function(a,b,c){a.replace&&(a=a.replace(L,"<$1>")),b===w&&(b=K.test(a)&&RegExp.$1),b in R||(b="*");var d,e,g=R[b];return g.innerHTML=""+a,e=y.each(D.call(g.childNodes),function(){g.removeChild(this)}),f(c)&&(d=y(e),y.each(c,function(a,b){N.indexOf(a)>-1?d[a](b):d.attr(a,b)})),e},Y.Z=function(a,b){return a=a||[],a.__proto__=y.fn,a.selector=b||"",a},Y.isZ=function(a){return a instanceof Y.Z},Y.init=function(a,c){if(a){if(b(a))return y(F).ready(a);if(Y.isZ(a))return a;var d;if(g(a))d=i(a);else if(e(a))d=[f(a)?y.extend({},a):a],a=null;else if(K.test(a))d=Y.fragment(a.trim(),RegExp.$1,c),a=null;else{if(c!==w)return y(c).find(a);d=Y.qsa(F,a)}return Y.Z(d,a)}return Y.Z()},y=function(a,b){return Y.init(a,b)},y.extend=function(a){var b,c=D.call(arguments,1);return"boolean"==typeof a&&(b=a,a=c.shift()),c.forEach(function(c){p(a,c,b)}),a},Y.qsa=function(a,b){var c;return d(a)&&U.test(b)?(c=a.getElementById(RegExp.$1))?[c]:[]:1!==a.nodeType&&9!==a.nodeType?[]:D.call(T.test(b)?a.getElementsByClassName(RegExp.$1):V.test(b)?a.getElementsByTagName(b):a.querySelectorAll(b))},y.contains=function(a,b){return a!==b&&a.contains(b)},y.type=a,y.isFunction=b,y.isWindow=c,y.isArray=g,y.isPlainObject=f,y.isEmptyObject=function(a){var b;for(b in a)return!1;return!0},y.inArray=function(a,b,c){return C.indexOf.call(b,a,c)},y.camelCase=A,y.trim=function(a){return a.trim()},y.uuid=0,y.support={},y.expr={},y.map=function(a,b){var c,d,e,f=[];if(h(a))for(d=0;d=0?a:a+this.length]},toArray:function(){return this.get()},size:function(){return this.length},remove:function(){return this.each(function(){null!=this.parentNode&&this.parentNode.removeChild(this)})},each:function(a){return C.every.call(this,function(b,c){return a.call(b,c,b)!==!1}),this},filter:function(a){return b(a)?this.not(this.not(a)):y(E.call(this,function(b){return Y.matches(b,a)}))},add:function(a,b){return y(B(this.concat(y(a,b))))},is:function(a){return this.length>0&&Y.matches(this[0],a)},not:function(a){var c=[];if(b(a)&&a.call!==w)this.each(function(b){a.call(this,b)||c.push(this)});else{var d="string"==typeof a?this.filter(a):h(a)&&b(a.item)?D.call(a):y(a);this.forEach(function(a){d.indexOf(a)<0&&c.push(a)})}return y(c)},has:function(a){return this.filter(function(){return e(a)?y.contains(this,a):y(this).find(a).size()})},eq:function(a){return-1===a?this.slice(a):this.slice(a,+a+1)},first:function(){var a=this[0];return a&&!e(a)?a:y(a)},last:function(){var a=this[this.length-1];return a&&!e(a)?a:y(a)},find:function(a){var b,c=this;return b="object"==typeof a?y(a).filter(function(){var a=this;return C.some.call(c,function(b){return y.contains(b,a)})}):1==this.length?y(Y.qsa(this[0],a)):this.map(function(){return Y.qsa(this,a)})},closest:function(a,b){var c=this[0],e=!1;for("object"==typeof a&&(e=y(a));c&&!(e?e.indexOf(c)>=0:Y.matches(c,a));)c=c!==b&&!d(c)&&c.parentNode;return y(c)},parents:function(a){for(var b=[],c=this;c.length>0;)c=y.map(c,function(a){return(a=a.parentNode)&&!d(a)&&b.indexOf(a)<0?(b.push(a),a):void 0});return q(b,a)},parent:function(a){return q(B(this.pluck("parentNode")),a)},children:function(a){return q(this.map(function(){return o(this)}),a)},contents:function(){return this.map(function(){return D.call(this.childNodes)})},siblings:function(a){return q(this.map(function(a,b){return E.call(o(b.parentNode),function(a){return a!==b})}),a)},empty:function(){return this.each(function(){this.innerHTML=""})},pluck:function(a){return y.map(this,function(b){return b[a]})},show:function(){return this.each(function(){"none"==this.style.display&&(this.style.display=null),"none"==I(this,"").getPropertyValue("display")&&(this.style.display=n(this.nodeName))})},replaceWith:function(a){return this.before(a).remove()},wrap:function(a){var c=b(a);if(this[0]&&!c)var d=y(a).get(0),e=d.parentNode||this.length>1;return this.each(function(b){y(this).wrapAll(c?a.call(this,b):e?d.cloneNode(!0):d)})},wrapAll:function(a){if(this[0]){y(this[0]).before(a=y(a));for(var b;(b=a.children()).length;)a=b.first();y(a).append(this)}return this},wrapInner:function(a){var c=b(a);return this.each(function(b){var d=y(this),e=d.contents(),f=c?a.call(this,b):a;e.length?e.wrapAll(f):d.append(f)})},unwrap:function(){return this.parent().each(function(){y(this).replaceWith(y(this).children())}),this},clone:function(){return this.map(function(){return this.cloneNode(!0)})},hide:function(){return this.css("display","none")},toggle:function(a){return this.each(function(){var b=y(this);(a===w?"none"==b.css("display"):a)?b.show():b.hide()})},prev:function(a){return y(this.pluck("previousElementSibling")).filter(a||"*")},next:function(a){return y(this.pluck("nextElementSibling")).filter(a||"*")},html:function(a){return a===w?this.length>0?this[0].innerHTML:null:this.each(function(b){var c=this.innerHTML;y(this).empty().append(r(this,a,b,c))})},text:function(a){return a===w?this.length>0?this[0].textContent:null:this.each(function(){this.textContent=a})},attr:function(a,b){var c;return"string"==typeof a&&b===w?0==this.length||1!==this[0].nodeType?w:"value"==a&&"INPUT"==this[0].nodeName?this.val():!(c=this[0].getAttribute(a))&&a in this[0]?this[0][a]:c:this.each(function(c){if(1===this.nodeType)if(e(a))for(x in a)s(this,x,a[x]);else s(this,a,r(this,b,c,this.getAttribute(a)))})},removeAttr:function(a){return this.each(function(){1===this.nodeType&&s(this,a)})},prop:function(a,b){return b===w?this[0]&&this[0][a]:this.each(function(c){this[a]=r(this,b,c,this[a])})},data:function(a,b){var c=this.attr("data-"+k(a),b);return null!==c?u(c):w},val:function(a){return a===w?this[0]&&(this[0].multiple?y(this[0]).find("option").filter(function(){return this.selected}).pluck("value"):this[0].value):this.each(function(b){this.value=r(this,a,b,this.value)})},offset:function(a){if(a)return this.each(function(b){var c=y(this),d=r(this,a,b,c.offset()),e=c.offsetParent().offset(),f={top:d.top-e.top,left:d.left-e.left};"static"==c.css("position")&&(f.position="relative"),c.css(f)});if(0==this.length)return null;var b=this[0].getBoundingClientRect();return{left:b.left+window.pageXOffset,top:b.top+window.pageYOffset,width:Math.round(b.width),height:Math.round(b.height)}},css:function(b,c){if(arguments.length<2&&"string"==typeof b)return this[0]&&(this[0].style[A(b)]||I(this[0],"").getPropertyValue(b));var d="";if("string"==a(b))c||0===c?d=k(b)+":"+m(b,c):this.each(function(){this.style.removeProperty(k(b))});else for(x in b)b[x]||0===b[x]?d+=k(x)+":"+m(x,b[x])+";":this.each(function(){this.style.removeProperty(k(x))});return this.each(function(){this.style.cssText+=";"+d})},index:function(a){return a?this.indexOf(y(a)[0]):this.parent().children().indexOf(this[0])},hasClass:function(a){return C.some.call(this,function(a){return this.test(t(a))},l(a))},addClass:function(a){return this.each(function(b){z=[];var c=t(this),d=r(this,a,b,c);d.split(/\s+/g).forEach(function(a){y(this).hasClass(a)||z.push(a)},this),z.length&&t(this,c+(c?" ":"")+z.join(" "))})},removeClass:function(a){return this.each(function(b){return a===w?t(this,""):(z=t(this),r(this,a,b,z).split(/\s+/g).forEach(function(a){z=z.replace(l(a)," ")}),t(this,z.trim()),void 0)})},toggleClass:function(a,b){return this.each(function(c){var d=y(this),e=r(this,a,c,t(this));e.split(/\s+/g).forEach(function(a){(b===w?!d.hasClass(a):b)?d.addClass(a):d.removeClass(a)})})},scrollTop:function(){return this.length?"scrollTop"in this[0]?this[0].scrollTop:this[0].scrollY:void 0},position:function(){if(this.length){var a=this[0],b=this.offsetParent(),c=this.offset(),d=M.test(b[0].nodeName)?{top:0,left:0}:b.offset();return c.top-=parseFloat(y(a).css("margin-top"))||0,c.left-=parseFloat(y(a).css("margin-left"))||0,d.top+=parseFloat(y(b[0]).css("border-top-width"))||0,d.left+=parseFloat(y(b[0]).css("border-left-width"))||0,{top:c.top-d.top,left:c.left-d.left}}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||F.body;a&&!M.test(a.nodeName)&&"static"==y(a).css("position");)a=a.offsetParent;return a})}},y.fn.detach=y.fn.remove,["width","height"].forEach(function(a){y.fn[a]=function(b){var e,f=this[0],g=a.replace(/./,function(a){return a[0].toUpperCase()});return b===w?c(f)?f["inner"+g]:d(f)?f.documentElement["offset"+g]:(e=this.offset())&&e[a]:this.each(function(c){f=y(this),f.css(a,r(this,b,c,f[a]()))})}}),O.forEach(function(b,c){var d=c%2;y.fn[b]=function(){var b,e,f=y.map(arguments,function(c){return b=a(c),"object"==b||"array"==b||null==c?c:Y.fragment(c)}),g=this.length>1;return f.length<1?this:this.each(function(a,b){e=d?b:b.parentNode,b=0==c?b.nextSibling:1==c?b.firstChild:2==c?b:null,f.forEach(function(a){if(g)a=a.cloneNode(!0);else if(!e)return y(a).remove();v(e.insertBefore(a,b),function(a){null==a.nodeName||"SCRIPT"!==a.nodeName.toUpperCase()||a.type&&"text/javascript"!==a.type||a.src||window.eval.call(window,a.innerHTML)})})})},y.fn[d?b+"To":"insert"+(c?"Before":"After")]=function(a){return y(a)[b](this),this}}),Y.Z.prototype=y.fn,Y.uniq=B,Y.deserializeValue=u,y.zepto=Y,y}();window.Zepto=Zepto,"$"in window||(window.$=Zepto),function(a){function b(a){var b=this.os={},c=this.browser={},d=a.match(/WebKit\/([\d.]+)/),e=a.match(/(Android)\s+([\d.]+)/),f=a.match(/(iPad).*OS\s([\d_]+)/),g=!f&&a.match(/(iPhone\sOS)\s([\d_]+)/),h=a.match(/(webOS|hpwOS)[\s\/]([\d.]+)/),i=h&&a.match(/TouchPad/),j=a.match(/Kindle\/([\d.]+)/),k=a.match(/Silk\/([\d._]+)/),l=a.match(/(BlackBerry).*Version\/([\d.]+)/),m=a.match(/(BB10).*Version\/([\d.]+)/),n=a.match(/(RIM\sTablet\sOS)\s([\d.]+)/),o=a.match(/PlayBook/),p=a.match(/Chrome\/([\d.]+)/)||a.match(/CriOS\/([\d.]+)/),q=a.match(/Firefox\/([\d.]+)/);(c.webkit=!!d)&&(c.version=d[1]),e&&(b.android=!0,b.version=e[2]),g&&(b.ios=b.iphone=!0,b.version=g[2].replace(/_/g,".")),f&&(b.ios=b.ipad=!0,b.version=f[2].replace(/_/g,".")),h&&(b.webos=!0,b.version=h[2]),i&&(b.touchpad=!0),l&&(b.blackberry=!0,b.version=l[2]),m&&(b.bb10=!0,b.version=m[2]),n&&(b.rimtabletos=!0,b.version=n[2]),o&&(c.playbook=!0),j&&(b.kindle=!0,b.version=j[1]),k&&(c.silk=!0,c.version=k[1]),!k&&b.android&&a.match(/Kindle Fire/)&&(c.silk=!0),p&&(c.chrome=!0,c.version=p[1]),q&&(c.firefox=!0,c.version=q[1]),b.tablet=!!(f||o||e&&!a.match(/Mobile/)||q&&a.match(/Tablet/)),b.phone=!(b.tablet||!(e||g||h||l||m||p&&a.match(/Android/)||p&&a.match(/CriOS\/([\d.]+)/)||q&&a.match(/Mobile/)))}b.call(a,navigator.userAgent),a.__detect=b}(Zepto),function(a){function b(a){return a._zid||(a._zid=n++)}function c(a,c,f,g){if(c=d(c),c.ns)var h=e(c.ns);return(m[b(a)]||[]).filter(function(a){return!(!a||c.e&&a.e!=c.e||c.ns&&!h.test(a.ns)||f&&b(a.fn)!==b(f)||g&&a.sel!=g)})}function d(a){var b=(""+a).split(".");return{e:b[0],ns:b.slice(1).sort().join(" ")}}function e(a){return new RegExp("(?:^| )"+a.replace(" "," .* ?")+"(?: |$)")}function f(b,c,d){"string"!=a.type(b)?a.each(b,d):b.split(/\s/).forEach(function(a){d(a,c)})}function g(a,b){return a.del&&("focus"==a.e||"blur"==a.e)||!!b}function h(a){return p[a]||a}function i(c,e,i,j,k,l){var n=b(c),o=m[n]||(m[n]=[]);f(e,i,function(b,e){var f=d(b);f.fn=e,f.sel=j,f.e in p&&(e=function(b){var c=b.relatedTarget;return!c||c!==this&&!a.contains(this,c)?f.fn.apply(this,arguments):void 0}),f.del=k&&k(e,b);var i=f.del||e;f.proxy=function(a){var b=i.apply(c,[a].concat(a.data));return b===!1&&(a.preventDefault(),a.stopPropagation()),b},f.i=o.length,o.push(f),c.addEventListener(h(f.e),f.proxy,g(f,l))})}function j(a,d,e,i,j){var k=b(a);f(d||"",e,function(b,d){c(a,b,d,i).forEach(function(b){delete m[k][b.i],a.removeEventListener(h(b.e),b.proxy,g(b,j))})})}function k(b){var c,d={originalEvent:b};for(c in b)s.test(c)||void 0===b[c]||(d[c]=b[c]);return a.each(t,function(a,c){d[a]=function(){return this[c]=q,b[a].apply(b,arguments)},d[c]=r}),d}function l(a){if(!("defaultPrevented"in a)){a.defaultPrevented=!1;var b=a.preventDefault;a.preventDefault=function(){this.defaultPrevented=!0,b.call(this)}}}var m=(a.zepto.qsa,{}),n=1,o={},p={mouseenter:"mouseover",mouseleave:"mouseout"};o.click=o.mousedown=o.mouseup=o.mousemove="MouseEvents",a.event={add:i,remove:j},a.proxy=function(c,d){if(a.isFunction(c)){var e=function(){return c.apply(d,arguments)};return e._zid=b(c),e}if("string"==typeof d)return a.proxy(c[d],c);throw new TypeError("expected function")},a.fn.bind=function(a,b){return this.each(function(){i(this,a,b)})},a.fn.unbind=function(a,b){return this.each(function(){j(this,a,b)})},a.fn.one=function(a,b){return this.each(function(c,d){i(this,a,b,null,function(a,b){return function(){var c=a.apply(d,arguments);return j(d,b,a),c}})})};var q=function(){return!0},r=function(){return!1},s=/^([A-Z]|layer[XY]$)/,t={preventDefault:"isDefaultPrevented",stopImmediatePropagation:"isImmediatePropagationStopped",stopPropagation:"isPropagationStopped"};a.fn.delegate=function(b,c,d){return this.each(function(e,f){i(f,c,d,b,function(c){return function(d){var e,g=a(d.target).closest(b,f).get(0);return g?(e=a.extend(k(d),{currentTarget:g,liveFired:f}),c.apply(g,[e].concat([].slice.call(arguments,1)))):void 0}})})},a.fn.undelegate=function(a,b,c){return this.each(function(){j(this,b,c,a)})},a.fn.live=function(b,c){return a(document.body).delegate(this.selector,b,c),this},a.fn.die=function(b,c){return a(document.body).undelegate(this.selector,b,c),this},a.fn.on=function(b,c,d){return!c||a.isFunction(c)?this.bind(b,c||d):this.delegate(c,b,d)},a.fn.off=function(b,c,d){return!c||a.isFunction(c)?this.unbind(b,c||d):this.undelegate(c,b,d)},a.fn.trigger=function(b,c){return("string"==typeof b||a.isPlainObject(b))&&(b=a.Event(b)),l(b),b.data=c,this.each(function(){"dispatchEvent"in this&&this.dispatchEvent(b)})},a.fn.triggerHandler=function(b,d){var e,f;return this.each(function(g,h){e=k("string"==typeof b?a.Event(b):b),e.data=d,e.target=h,a.each(c(h,b.type||b),function(a,b){return f=b.proxy(e),e.isImmediatePropagationStopped()?!1:void 0})}),f},"focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select keydown keypress keyup error".split(" ").forEach(function(b){a.fn[b]=function(a){return a?this.bind(b,a):this.trigger(b)}}),["focus","blur"].forEach(function(b){a.fn[b]=function(a){return a?this.bind(b,a):this.each(function(){try{this[b]()}catch(a){}}),this}}),a.Event=function(a,b){"string"!=typeof a&&(b=a,a=b.type);var c=document.createEvent(o[a]||"Events"),d=!0;if(b)for(var e in b)"bubbles"==e?d=!!b[e]:c[e]=b[e];return c.initEvent(a,d,!0,null,null,null,null,null,null,null,null,null,null,null,null),c.isDefaultPrevented=function(){return this.defaultPrevented},c}}(Zepto),function(a){function b(b,c,d){var e=a.Event(c);return a(b).trigger(e,d),!e.defaultPrevented}function c(a,c,d,e){return a.global?b(c||s,d,e):void 0}function d(b){b.global&&0===a.active++&&c(b,null,"ajaxStart")}function e(b){b.global&&!--a.active&&c(b,null,"ajaxStop")}function f(a,b){var d=b.context;return b.beforeSend.call(d,a,b)===!1||c(b,d,"ajaxBeforeSend",[a,b])===!1?!1:(c(b,d,"ajaxSend",[a,b]),void 0)}function g(a,b,d){var e=d.context,f="success";d.success.call(e,a,f,b),c(d,e,"ajaxSuccess",[b,d,a]),i(f,b,d)}function h(a,b,d,e){var f=e.context;e.error.call(f,d,b,a),c(e,f,"ajaxError",[d,e,a]),i(b,d,e)}function i(a,b,d){var f=d.context;d.complete.call(f,b,a),c(d,f,"ajaxComplete",[b,d]),e(d)}function j(){}function k(a){return a&&(a=a.split(";",2)[0]),a&&(a==x?"html":a==w?"json":u.test(a)?"script":v.test(a)&&"xml")||"text"}function l(a,b){return(a+"&"+b).replace(/[&?]{1,2}/,"?")}function m(b){b.processData&&b.data&&"string"!=a.type(b.data)&&(b.data=a.param(b.data,b.traditional)),!b.data||b.type&&"GET"!=b.type.toUpperCase()||(b.url=l(b.url,b.data))}function n(b,c,d,e){var f=!a.isFunction(c);return{url:b,data:f?c:void 0,success:f?a.isFunction(d)?d:void 0:c,dataType:f?e||d:d}}function o(b,c,d,e){var f,g=a.isArray(c);a.each(c,function(c,h){f=a.type(h),e&&(c=d?e:e+"["+(g?"":c)+"]"),!e&&g?b.add(h.name,h.value):"array"==f||!d&&"object"==f?o(b,h,d,c):b.add(c,h)})}var p,q,r=0,s=window.document,t=/)<[^<]*)*<\/script>/gi,u=/^(?:text|application)\/javascript/i,v=/^(?:text|application)\/xml/i,w="application/json",x="text/html",y=/^\s*$/;a.active=0,a.ajaxJSONP=function(b){if(!("type"in b))return a.ajax(b);var c,d="jsonp"+ ++r,e=s.createElement("script"),i=function(){clearTimeout(c),a(e).remove(),delete window[d]},k=function(a){i(),a&&"timeout"!=a||(window[d]=j),h(null,a||"abort",l,b)},l={abort:k};return f(l,b)===!1?(k("abort"),!1):(window[d]=function(a){i(),g(a,l,b)},e.onerror=function(){k("error")},e.src=b.url.replace(/=\?/,"="+d),a("head").append(e),b.timeout>0&&(c=setTimeout(function(){k("timeout")},b.timeout)),l)},a.ajaxSettings={type:"GET",beforeSend:j,success:j,error:j,complete:j,context:null,global:!0,xhr:function(){return new window.XMLHttpRequest},accepts:{script:"text/javascript, application/javascript",json:w,xml:"application/xml, text/xml",html:x,text:"text/plain"},crossDomain:!1,timeout:0,processData:!0,cache:!0},a.ajax=function(b){var c=a.extend({},b||{});for(p in a.ajaxSettings)void 0===c[p]&&(c[p]=a.ajaxSettings[p]);d(c),c.crossDomain||(c.crossDomain=/^([\w-]+:)?\/\/([^\/]+)/.test(c.url)&&RegExp.$2!=window.location.host),c.url||(c.url=window.location.toString()),m(c),c.cache===!1&&(c.url=l(c.url,"_="+Date.now()));var e=c.dataType,i=/=\?/.test(c.url);if("jsonp"==e||i)return i||(c.url=l(c.url,"callback=?")),a.ajaxJSONP(c);var n,o=c.accepts[e],r={},s=/^([\w-]+:)\/\//.test(c.url)?RegExp.$1:window.location.protocol,t=c.xhr();c.crossDomain||(r["X-Requested-With"]="XMLHttpRequest"),o&&(r.Accept=o,o.indexOf(",")>-1&&(o=o.split(",",2)[0]),t.overrideMimeType&&t.overrideMimeType(o)),(c.contentType||c.contentType!==!1&&c.data&&"GET"!=c.type.toUpperCase())&&(r["Content-Type"]=c.contentType||"application/x-www-form-urlencoded"),c.headers=a.extend(r,c.headers||{}),t.onreadystatechange=function(){if(4==t.readyState){t.onreadystatechange=j,clearTimeout(n);var b,d=!1;if(t.status>=200&&t.status<300||304==t.status||0==t.status&&"file:"==s){e=e||k(t.getResponseHeader("content-type")),b=t.responseText;try{"script"==e?(1,eval)(b):"xml"==e?b=t.responseXML:"json"==e&&(b=y.test(b)?null:a.parseJSON(b))}catch(f){d=f}d?h(d,"parsererror",t,c):g(b,t,c)}else h(null,t.status?"error":"abort",t,c)}};var u="async"in c?c.async:!0;t.open(c.type,c.url,u);for(q in c.headers)t.setRequestHeader(q,c.headers[q]);return f(t,c)===!1?(t.abort(),!1):(c.timeout>0&&(n=setTimeout(function(){t.onreadystatechange=j,t.abort(),h(null,"timeout",t,c)},c.timeout)),t.send(c.data?c.data:null),t)},a.get=function(){return a.ajax(n.apply(null,arguments))},a.post=function(){var b=n.apply(null,arguments);return b.type="POST",a.ajax(b)},a.getJSON=function(){var b=n.apply(null,arguments);return b.dataType="json",a.ajax(b)},a.fn.load=function(b,c,d){if(!this.length)return this;var e,f=this,g=b.split(/\s/),h=n(b,c,d),i=h.success;return g.length>1&&(h.url=g[0],e=g[1]),h.success=function(b){f.html(e?a("
          ").html(b.replace(t,"")).find(e):b),i&&i.apply(f,arguments)},a.ajax(h),this};var z=encodeURIComponent;a.param=function(a,b){var c=[];return c.add=function(a,b){this.push(z(a)+"="+z(b))},o(c,a,b),c.join("&").replace(/%20/g,"+")}}(Zepto),function(a){a.fn.serializeArray=function(){var b,c=[];return a(Array.prototype.slice.call(this.get(0).elements)).each(function(){b=a(this);var d=b.attr("type");"fieldset"!=this.nodeName.toLowerCase()&&!this.disabled&&"submit"!=d&&"reset"!=d&&"button"!=d&&("radio"!=d&&"checkbox"!=d||this.checked)&&c.push({name:b.attr("name"),value:b.val()})}),c},a.fn.serialize=function(){var a=[];return this.serializeArray().forEach(function(b){a.push(encodeURIComponent(b.name)+"="+encodeURIComponent(b.value))}),a.join("&")},a.fn.submit=function(b){if(b)this.bind("submit",b);else if(this.length){var c=a.Event("submit");this.eq(0).trigger(c),c.defaultPrevented||this.get(0).submit()}return this}}(Zepto),function(a,b){function c(a){return d(a.replace(/([a-z])([A-Z])/,"$1-$2"))}function d(a){return a.toLowerCase()}function e(a){return f?f+a:d(a)}var f,g,h,i,j,k,l,m,n="",o={Webkit:"webkit",Moz:"",O:"o",ms:"MS"},p=window.document,q=p.createElement("div"),r=/^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i,s={};a.each(o,function(a,c){return q.style[a+"TransitionProperty"]!==b?(n="-"+d(a)+"-",f=c,!1):void 0}),g=n+"transform",s[h=n+"transition-property"]=s[i=n+"transition-duration"]=s[j=n+"transition-timing-function"]=s[k=n+"animation-name"]=s[l=n+"animation-duration"]=s[m=n+"animation-timing-function"]="",a.fx={off:f===b&&q.style.transitionProperty===b,speeds:{_default:400,fast:200,slow:600},cssPrefix:n,transitionEnd:e("TransitionEnd"),animationEnd:e("AnimationEnd")},a.fn.animate=function(b,c,d,e){return a.isPlainObject(c)&&(d=c.easing,e=c.complete,c=c.duration),c&&(c=("number"==typeof c?c:a.fx.speeds[c]||a.fx.speeds._default)/1e3),this.anim(b,c,d,e)},a.fn.anim=function(d,e,f,n){var o,p,q,t={},u="",v=this,w=a.fx.transitionEnd;if(e===b&&(e=.4),a.fx.off&&(e=0),"string"==typeof d)t[k]=d,t[l]=e+"s",t[m]=f||"linear",w=a.fx.animationEnd;else{p=[];for(o in d)r.test(o)?u+=o+"("+d[o]+") ":(t[o]=d[o],p.push(c(o)));u&&(t[g]=u,p.push(g)),e>0&&"object"==typeof d&&(t[h]=p.join(", "),t[i]=e+"s",t[j]=f||"linear")}return q=function(b){if("undefined"!=typeof b){if(b.target!==b.currentTarget)return;a(b.target).unbind(w,q)}a(this).css(s),n&&n.call(this)},e>0&&this.bind(w,q),this.size()&&this.get(0).clientLeft,this.css(t),0>=e&&setTimeout(function(){v.each(function(){q.call(this)})},0),this},q=null}(Zepto); \ No newline at end of file