├── .gitignore ├── Modfile.js ├── README.md ├── bower.json ├── css └── pro.css ├── demo ├── index.html ├── js │ └── demo.js └── vendor │ └── ionicons │ ├── css │ └── ionicons.css │ └── fonts │ ├── ionicons.eot │ ├── ionicons.svg │ ├── ionicons.ttf │ └── ionicons.woff ├── doc ├── css │ └── doc.css ├── img │ └── iphone.png ├── index.html ├── js │ └── doc.js ├── md │ └── getting-started.md └── vendor │ ├── fingerblast │ └── fingerblast.js │ ├── prettify │ ├── prettify.css │ └── prettify.js │ └── zepto │ └── dimensions.js ├── img └── icon-search.png ├── js ├── ajax.js ├── carousel.js ├── countable.js ├── data.js ├── debounce.js ├── deletable.js ├── dialog.js ├── event.js ├── fixed.js ├── lazyload.js ├── os.js ├── pro.js ├── requestAnimationFrame.js ├── scrollfix.js ├── spinner.js ├── tab.js ├── tmpl.js ├── touch.js ├── transition.js └── zepto.js ├── package.json ├── task └── amdify.js └── vendor └── requirejs └── require.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Files to ignore 2 | .DS_Store 3 | .localized 4 | Thumbs.db 5 | *.log 6 | *.sass-cache 7 | 8 | # Folders to ignore 9 | .idea 10 | .hg 11 | .svn 12 | .CVS 13 | .cache 14 | tmp 15 | node_modules 16 | -------------------------------------------------------------------------------- /Modfile.js: -------------------------------------------------------------------------------- 1 | // More info about Modfile at https://github.com/modulejs/modjs/ 2 | 3 | module.exports = { 4 | version: ">=0.4.3", 5 | plugins: { 6 | amdify: './task/amdify' 7 | }, 8 | tasks: { 9 | server: { 10 | port: 3000 11 | }, 12 | download: { 13 | options: { 14 | dest: "js/" 15 | }, 16 | zepto: { 17 | src: "http://rawgithub.com/madrobby/zepto/master/src/zepto.js" 18 | }, 19 | event: { 20 | src: "http://rawgithub.com/madrobby/zepto/master/src/event.js" 21 | }, 22 | ajax: { 23 | src: "http://rawgithub.com/madrobby/zepto/master/src/ajax.js" 24 | }, 25 | data: { 26 | src: "http://rawgithub.com/madrobby/zepto/master/src/data.js" 27 | }, 28 | touch: { 29 | src: "http://rawgithub.com/madrobby/zepto/master/src/touch.js" 30 | }, 31 | requirejs: { 32 | src: "http://requirejs.org/docs/release/2.1.10/comments/require.js", 33 | dest: 'vendor/requirejs/' 34 | }, 35 | 'requirejs-tmpl': { 36 | src: "http://rawgithub.com/modulejs/requirejs-tmpl/master/tmpl.js" 37 | } 38 | }, 39 | amdify: { 40 | src: "js/{zepto,event,ajax,data,touch}.js" 41 | } 42 | }, 43 | targets: { 44 | vendor: ["download", "amdify"] 45 | } 46 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Pro 2 | === 3 | > Framework for mobile platform. 4 | 5 | ## Features 6 | * Mobile Only 7 | * High performance 8 | * Accessibility Support 9 | * Custom build support 10 | 11 | ## Screenshot 12 | 13 | ![screenshot1](https://f.cloud.github.com/assets/677114/2280325/a3db2e1e-9f87-11e3-85bd-6ca4e58a433e.png) 14 | 15 | ![screenshot2](https://f.cloud.github.com/assets/677114/2280329/a796fb1e-9f87-11e3-86fe-9f88657827c1.png) 16 | 17 | ## Demo 18 | 19 | Scan below QR code or visit [http://url.cn/NDKvRr](http://url.cn/NDKvRr) on your handset. 20 | 21 | ![qrcode](https://f.cloud.github.com/assets/677114/2168855/86661b22-954c-11e3-951d-ffe40ad41d16.png) 22 | 23 | ## Basic template 24 | 25 | Copy the HTML below to begin working with a minimal PRO document. 26 | 27 | ```html 28 | 29 | 30 | 31 | 32 | PRO Template 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
42 | PRO Template 43 |
44 | 45 | 51 | 52 | 53 |
54 |
55 |

Hello, world!

56 |
57 |
58 | 59 | 60 | 61 | 62 | 63 | ``` 64 | ## Platform support 65 | 66 | Current version have been tested on the below platforms: 67 | 68 | * iOS 4.0-7.0 69 | * iOS 4.3 (iPad 1) 70 | * iOS 5.1 (iPhone 4) 71 | * iOS 6.1 (iPhone 4S) 72 | * iOS 7.0 (iPhone 5) 73 | * Android 2.3-4.4 74 | * Android 2.3 (ZTE) 75 | * Android 4.0 (HTC Rhyme S510B) 76 | * Android 4.1 (LG Optimus G) 77 | * Android 4.2 (Sony Xperia Z) 78 | * Android 4.3 (Nexus 4) 79 | * Android 4.4 (Nexus 4) 80 | 81 | ## Built with Pro 82 | 83 | * Mobile QQ 84 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pro", 3 | "version": "0.0.0", 4 | "homepage": "https://github.com/AlloyTeam/Pro", 5 | "authors": [ 6 | "yuanyan " 7 | ], 8 | "description": "Framework for mobile platform.", 9 | "keywords": [ 10 | "mobile" 11 | ], 12 | "license": "MIT", 13 | "ignore": [ 14 | "**/.*", 15 | "node_modules", 16 | "bower_components", 17 | "doc", 18 | "demo", 19 | "task", 20 | "vendor", 21 | "package.json", 22 | "Modfile.js", 23 | "*.md" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PRO DEMO 6 | 7 | 8 | 9 | 10 | 11 | 82 | 83 | 84 | 85 |
86 |
87 |
    88 | 89 | 90 |
91 |
92 |
93 |
    94 | 95 | 96 |
97 |
98 |
99 |
    100 | 101 | 102 | 103 | 104 |
105 |
106 |
107 |
    108 | 109 | 110 | 111 | 112 |
113 |
114 |
115 |
    116 | 117 | 118 |
119 |
120 |
121 | 122 | 146 | 147 | 148 |
149 | 150 |
151 | 152 | 153 |
154 | 155 |

156 | 你已累计消费 157 | 0000 158 | 159 |

160 | 161 | 175 | 176 | 179 | 180 | 183 | 184 | 188 | 189 |
190 | 191 |
192 | 193 | 212 |
213 | 214 |
215 |
216 | 217 |
218 | 219 |
220 |
221 |

按钮

222 |

223 | 224 | 225 | 226 | 227 |

228 | 229 |

块级按钮

230 |

231 | 232 | 233 | 234 | 235 |

236 |
237 | 238 |
239 |

图标按钮

240 |

241 | 242 | 243 | 244 |

245 |
246 | 247 |
248 |
249 | 250 |
251 | 252 |
253 | 254 |
255 | 256 |

Dark

257 |

258 | 259 |

260 | 261 |

Light

262 |

263 | 264 |

265 | 266 |

Trigger

267 |

268 | 271 | 272 | 275 |

276 | 277 |
278 | 279 |
280 | 302 |
303 | 304 |
305 |

CountUp

306 |
307 | 0 308 |
309 | 310 |

CountDown

311 |
312 | 9521 313 |
314 |
315 | 316 | 359 | 360 |
361 | 362 |
363 | 364 |
365 | 366 |
367 | 368 |
369 | 370 |

Blue

371 |
372 |
    373 |
  • 列表 1123
  • 374 |
  • 列表 2
  • 375 |
  • 列表 32
  • 376 |
377 |
378 | 379 |

Gray

380 |
381 |
    382 |
  • 列表 1
  • 383 |
  • 列表 2
  • 384 |
  • 列表 31
  • 385 |
386 |
387 | 388 |
389 | 390 |
391 | 392 |

Notify

393 |

394 | 397 |

398 |
399 | 400 |
401 | 402 |

Alert

403 |

404 | 407 | 408 | 411 | 412 | 415 | 416 | 419 | 420 | 423 | 424 | 427 |

428 | 429 |
430 | 431 |
432 |

Action Sheet

433 |

434 | 437 |

438 |
439 | 440 |
441 |
442 | 443 |
444 | 445 |
446 | 447 |
448 | 449 |

Normal

450 | 451 | 458 | 459 |
460 | 461 |
462 | 463 |

Nature

464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 |

Technics

475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 |
485 | 486 |
487 |
488 | 489 | 490 | 491 | 496 | 497 | 502 | 503 | 514 | 515 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | -------------------------------------------------------------------------------- /demo/js/demo.js: -------------------------------------------------------------------------------- 1 | require([ 2 | '../../js/pro' 3 | ], function(){ 4 | 5 | // CountUp 6 | $('#countup').countable('start'); 7 | 8 | // Spinner 9 | $('[data-spinner]').each(function () { 10 | var $this = $(this); 11 | $this.spinner('show') 12 | }); 13 | 14 | $('#show-body-spinner').on('tap', function(){ 15 | //var $this = $(this); 16 | //var delay = $this.data('delay') || 6000; 17 | 18 | $('body').spinner('show'); 19 | //setTimeout(function(){ 20 | // $('body').spinner('hide'); 21 | //}, delay); 22 | }); 23 | 24 | $('#hide-body-spinner').on('tap', function(){ 25 | $('body').spinner('hide'); 26 | }); 27 | 28 | function initSearch(){ 29 | var $search = $('#my-search'); 30 | var $input = $('#my-search-input'); 31 | $input.on('focus', function(){ 32 | $search.addClass('js-focus') 33 | }).on('input', function(){ 34 | if($input[0].value){ 35 | $search.addClass('js-input') 36 | }else{ 37 | $search.removeClass('js-input') 38 | } 39 | }); 40 | 41 | $('#my-search-reset').on('tap', function(){ 42 | $input[0].value = ''; 43 | $search.removeClass('js-input'); 44 | $input[0].focus(); 45 | }); 46 | 47 | $('#my-search-cancel').on('touchstart', function(evt){ 48 | $input[0].value = ''; 49 | $search.removeClass('js-input'); 50 | $search.removeClass('js-focus'); 51 | 52 | document.activeElement.blur(); 53 | $input[0].blur(); 54 | 55 | evt.stopPropagation(); 56 | evt.preventDefault(); 57 | }); 58 | } 59 | 60 | initSearch(); 61 | 62 | // Tab 63 | $('[data-toggle="tab"]').on('shown:tab', function (e) { 64 | 65 | var target = e.target // activated tab 66 | var relatedTarget = e.relatedTarget // previous tab 67 | 68 | var tab = target.innerText.trim().toLowerCase(); 69 | 70 | if(target.inited) return; 71 | 72 | if(tab == 'counter'){ 73 | 74 | $('[data-countable]').each(function () { 75 | var $this = $(this); 76 | $this.countable('start') 77 | }); 78 | 79 | }else if(tab == 'spinner'){ 80 | 81 | 82 | }else if(tab == 'carousel'){ 83 | 84 | $('[data-ride="carousel"]').each(function () { 85 | var $this = $(this); 86 | $this.carousel($this.data()) 87 | }); 88 | }else if(tab == 'deleter'){ 89 | 90 | $('.my-deletable').deletable() 91 | 92 | }else if(tab == 'lazyload'){ 93 | $('[data-lazy]').lazyload({ 94 | container: $.os.ios > 5? $('#page5-container'): window 95 | }); 96 | } 97 | 98 | target.inited = true; 99 | 100 | }); 101 | 102 | }); 103 | -------------------------------------------------------------------------------- /demo/vendor/ionicons/fonts/ionicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeamDev/Pro/fc9641dde9689276c5b9e625697cbef411e7040a/demo/vendor/ionicons/fonts/ionicons.eot -------------------------------------------------------------------------------- /demo/vendor/ionicons/fonts/ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeamDev/Pro/fc9641dde9689276c5b9e625697cbef411e7040a/demo/vendor/ionicons/fonts/ionicons.ttf -------------------------------------------------------------------------------- /demo/vendor/ionicons/fonts/ionicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeamDev/Pro/fc9641dde9689276c5b9e625697cbef411e7040a/demo/vendor/ionicons/fonts/ionicons.woff -------------------------------------------------------------------------------- /doc/css/doc.css: -------------------------------------------------------------------------------- 1 | /* Base styles 2 | -------------------------------------------------- */ 3 | 4 | body { 5 | font-family: "Helvetica Neue", Helvetica, STHeiTi, sans-serif; 6 | font-size: 14px; 7 | line-height: 1.6; 8 | color: #333; 9 | background-color: #fff; 10 | -webkit-font-smoothing: antialiased; /* Fix for webkit rendering */ 11 | -webkit-text-size-adjust: 100%; 12 | 13 | /* Overrides the none user select of body in Pro */ 14 | -webkit-user-select: text; 15 | } 16 | 17 | /* Typography 18 | -------------------------------------------------- */ 19 | 20 | hr { 21 | height: 0; 22 | margin: 10px 0 30px; 23 | border: solid #ddd; 24 | border-width: 1px 0 0; 25 | clear: both; 26 | } 27 | 28 | h1, 29 | h2, 30 | h3, 31 | h4, 32 | h5, 33 | h6 { 34 | margin: 0; 35 | text-rendering: optimizeLegibility; 36 | } 37 | 38 | b { 39 | color: green; 40 | } 41 | 42 | a { 43 | color: grey; 44 | text-decoration: none; 45 | } 46 | 47 | p, pre, pre.prettyprint, blockquote { 48 | margin: 0 0 15px 49 | } 50 | 51 | hr { 52 | margin: 30px 0 53 | } 54 | 55 | code, pre { 56 | font-family: Menlo, Consolas, "Courier New", monospace; 57 | font-size: 12px !important 58 | } 59 | 60 | /* Doc structural styles 61 | -------------------------------------------------- */ 62 | 63 | .outer-wrapper { 64 | position: relative; 65 | } 66 | 67 | .inner-wrapper { 68 | width: 1000px; 69 | margin: 0 auto; 70 | position: relative; 71 | padding-top: 5px; 72 | } 73 | 74 | /* Navigation 75 | -------------------------------------------------- */ 76 | 77 | .nav { 78 | position: fixed; 79 | top: 0; 80 | right: 0; 81 | left: 0; 82 | z-index: 100; 83 | padding: 10px 0; 84 | background-color: rgba(0,0,0, 1); 85 | border-bottom: 1px solid #ddd; 86 | box-shadow: 0 0 5px rgba(0,0,0,.1); 87 | color: #fff; 88 | } 89 | 90 | .nav .inner-wrapper { 91 | line-height: 40px; 92 | } 93 | 94 | .nav-title { 95 | font-weight: 600; 96 | font-size: 20px; 97 | text-transform: uppercase; 98 | letter-spacing: 5px; 99 | } 100 | 101 | .nav-list { 102 | float: right; 103 | font-size: 15px; 104 | } 105 | 106 | .nav-item { 107 | position: relative; 108 | float: left; 109 | margin-right: 30px; 110 | list-style: none; 111 | } 112 | 113 | .nav-item:last-child { 114 | margin-right: 0; 115 | } 116 | 117 | .nav-item a { 118 | color: #fff; 119 | position: relative; 120 | text-decoration: none; 121 | } 122 | 123 | /* iPhone previewer 124 | -------------------------------------------------- */ 125 | 126 | .iphone { 127 | position: relative; 128 | top: 50px; 129 | float: right; 130 | width: 375px; 131 | height: 806px; 132 | font-family: "Helvetica Neue", sans-serif; 133 | background-image: url("../img/iphone.png"); 134 | } 135 | 136 | .iphone-fixed, 137 | .iphone-bottom { 138 | left: 50%; 139 | margin-left: 125px; 140 | } 141 | 142 | .iphone-fixed { 143 | position: fixed; 144 | top: 30px; 145 | } 146 | 147 | .iphone-bottom { 148 | position: absolute; 149 | top: auto; 150 | bottom: 130px; 151 | } 152 | 153 | .iphone .iphone-content { 154 | position: absolute; 155 | top: 147px; 156 | left: 27px; 157 | width: 320px; 158 | height: 548px; 159 | overflow: hidden; 160 | } 161 | 162 | .iphone .content, 163 | .component-example .content { 164 | position: absolute; 165 | top: 0; 166 | left: 0; 167 | right: 0; 168 | bottom: 0; 169 | } 170 | 171 | .component-example .content { 172 | position: relative; 173 | } 174 | 175 | /* Content layout 176 | -------------------------------------------------- */ 177 | 178 | .content-section { 179 | position: relative; 180 | padding-top: 80px; 181 | } 182 | 183 | /* Section header 184 | -------------------------------------------------- */ 185 | 186 | .section-header { 187 | border-bottom: 1px solid #ddd; 188 | } 189 | 190 | .section-title { 191 | margin: 10px 0; 192 | font-size: 50px; 193 | font-weight: 600; 194 | line-height: 1; 195 | color: #333; 196 | } 197 | 198 | .section-description { 199 | margin: 10px 0; 200 | font-weight: 300; 201 | font-size: 24px; 202 | color: #777; 203 | } 204 | 205 | .section-informational { 206 | border-top: 1px solid #ddd; 207 | border-bottom: 1px solid #ddd; 208 | background-color: #fafafa; 209 | padding-bottom: 70px; 210 | padding-top: 141px;/* 80+61 px*/ 211 | } 212 | 213 | .section-performance { 214 | border-top: 1px solid #ddd; 215 | border-bottom: 1px solid #ddd; 216 | background-color: #fafafa; 217 | padding-bottom: 70px; 218 | } 219 | 220 | .article-title { 221 | margin: 30px 0 15px 0; 222 | font-size: 30px; 223 | font-weight: 600; 224 | line-height: 1; 225 | color: #333; 226 | } 227 | 228 | 229 | /* Getting started & page setup 230 | -------------------------------------------------- */ 231 | 232 | .steps { 233 | overflow: hidden; 234 | padding-top: 40px; 235 | } 236 | 237 | .steps .step { 238 | float: left; 239 | width: 306px; 240 | margin-right: 10px; 241 | margin-left: 10px; 242 | list-style: none; 243 | } 244 | 245 | .step-title { 246 | font-size: 18px; 247 | font-weight: 700; 248 | } 249 | 250 | .step-description { 251 | margin-left: 10px; 252 | margin-bottom: 10px; 253 | margin-top: 15px; 254 | color: #333; 255 | 256 | } 257 | 258 | .steps .step:last-child { 259 | margin-right: 0; 260 | } 261 | 262 | .steps ul{ 263 | padding-top: 8px; 264 | padding-bottom: 8px; 265 | padding-left: 15px; 266 | } 267 | 268 | /* Components 269 | -------------------------------------------------- */ 270 | 271 | .section-components { 272 | background-color: #fff; 273 | } 274 | 275 | .component { 276 | position: relative; 277 | padding-top: 80px; 278 | width: 550px; 279 | margin-top: 1px; 280 | font-family: "proxima-nova", "HelveticaNeue-Light", "Helvetica Neue Light", Helvetica, Arial, sans-serif; 281 | font-weight: 300; 282 | opacity: .3; /* Fade content back until the user scrolls to it. */ 283 | -webkit-transition: opacity .2s ease-in-out; 284 | } 285 | 286 | .component:last-child { 287 | margin-bottom: 320px; 288 | } 289 | 290 | /* Active class applied when the specific component is in focus */ 291 | .component.active { 292 | opacity: 1; 293 | } 294 | 295 | .component-title { 296 | font-size: 28px; 297 | font-weight: 300; 298 | line-height: 35px; 299 | } 300 | 301 | .component-title a { 302 | font-size: 16px; 303 | float: right; 304 | } 305 | 306 | .component-description { 307 | margin-bottom: 13px; 308 | color: #777; 309 | font-size: 18px; 310 | line-height: 26px; 311 | font-weight: 300; 312 | } 313 | 314 | .component-note { 315 | margin-top: 10px; 316 | color: #999; 317 | font-size: 14px; 318 | line-height: 18px; 319 | font-style: italic; 320 | } 321 | 322 | .component-title + .component-example { 323 | margin-top: 13px; 324 | } 325 | 326 | .content-section .prettyprint, 327 | .content-section .instruction-code { 328 | overflow-x: auto; 329 | font-size: 13px; 330 | font-family: monaco, menlo, monospace; 331 | color: #777; 332 | background-color: #fafafa; 333 | 334 | border: 0 solid rgba(102, 128, 153, 0.075); 335 | border-left: 10px solid rgba(102, 128, 153, 0.075); 336 | border-radius: 0; 337 | border-top-right-radius: 5px; 338 | border-bottom-right-radius: 5px; 339 | padding: 10px 15px; 340 | margin: 0 0 15px; 341 | } 342 | 343 | .prettyprint + .component-description, 344 | .component-note + .component-description { 345 | margin-top: 36px; 346 | } 347 | 348 | /* Content specific styles 349 | -------------------------------------------------- */ 350 | 351 | /* Component examples on mobile */ 352 | .component-example { 353 | position: relative; 354 | display: none; 355 | margin-bottom: 20px; 356 | font-family: "Helvetica Neue", sans-serif; 357 | font-weight: normal; 358 | } 359 | 360 | .component-example-fullbleed { 361 | margin-right: -20px; 362 | margin-left: -20px; 363 | } 364 | 365 | /* Footer 366 | -------------------------------------------------- */ 367 | 368 | .footer { 369 | overflow: hidden; 370 | background-color: #fff; 371 | } 372 | 373 | .footer .inner-wrapper { 374 | text-align: center 375 | } 376 | 377 | .footer p, .footer a { 378 | font-size: 14px; 379 | margin: 6px; 380 | color: #0079FF; 381 | } 382 | 383 | /* Banner for Mozilla and IE about component rendering poorly 384 | ------------------------------------------------------------- */ 385 | .notice-banner { 386 | cursor: pointer; 387 | height: 0; 388 | opacity: 0; 389 | padding: 0; 390 | color: #333; 391 | font-size: 16px; 392 | text-align: center; 393 | background-color: #fff9c4; /* Old browsers */ 394 | background-image: linear-gradient(to bottom, #fff9c4 0%,#fff38d 100%); /* W3C */ 395 | box-shadow: inset 0 -1px 0 rgba(0,0,0,.1); 396 | } 397 | 398 | /* Media queries 399 | -------------------------------------------------- */ 400 | 401 | @media only screen and (max-width: 1039px) { 402 | .inner-wrapper { 403 | width: 920px; 404 | } 405 | 406 | .steps .step { 407 | width: 280px; 408 | } 409 | 410 | .component { 411 | width: 500px; 412 | } 413 | 414 | .iphone-fixed, 415 | .iphone-bottom { 416 | margin-left: 85px; 417 | } 418 | } 419 | @media only screen and (min-width: 768px) and (max-width: 959px) { 420 | .header-text, 421 | .inner-wrapper { 422 | width: 700px; 423 | } 424 | 425 | .component { 426 | width: 300px; 427 | } 428 | 429 | .iphone-fixed, 430 | .iphone-bottom { 431 | margin-left: -25px; 432 | } 433 | } 434 | @media only screen and (max-width: 767px) { 435 | .outer-wrapper, 436 | .inner-wrapper, 437 | .header-text, 438 | .content, 439 | .component { 440 | width: auto; 441 | } 442 | 443 | .inner-wrapper { 444 | padding-right: 20px; 445 | padding-left: 20px; 446 | } 447 | 448 | /* Have the nav scroll away instead of being fixed */ 449 | .nav { 450 | position: absolute; 451 | padding: 2px 0 1px; 452 | } 453 | 454 | .nav-title { 455 | font-size: 18px; 456 | text-align: center; 457 | } 458 | 459 | /* Hide the navigation on mobile. Scroll away! */ 460 | .navigation { 461 | display: none; 462 | } 463 | 464 | .content-section { 465 | padding-top: 50px; 466 | } 467 | 468 | .section-header { 469 | padding-bottom: 5px; 470 | } 471 | 472 | .section-title { 473 | margin-bottom: 5px; 474 | font-size: 40px; 475 | } 476 | 477 | .section-description { 478 | font-size: 18px; 479 | line-height: 24px; 480 | } 481 | 482 | .section-components { 483 | padding-bottom: 0px; 484 | } 485 | 486 | .section-informational { 487 | padding-bottom: 70px; 488 | padding-top: 94px; /* 50+44 px*/ 489 | } 490 | 491 | .steps .step { 492 | float: none; 493 | width: auto; 494 | margin: 0 0 30px 0; 495 | } 496 | 497 | .steps .step:last-child { 498 | margin: 0; 499 | } 500 | 501 | .notice-banner { 502 | position: relative; 503 | top: 0; 504 | font-size: 14px; 505 | line-height: 18px; 506 | } 507 | 508 | .notice-banner:after { 509 | display: none; 510 | } 511 | 512 | .component { 513 | padding: 50px 20px; 514 | margin-left: -20px; 515 | margin-right: -20px; 516 | opacity: 1; 517 | border-bottom: 1px solid #ddd; 518 | } 519 | 520 | .component:last-child { 521 | margin-bottom: 80px; 522 | } 523 | 524 | .component-example { 525 | display: block; 526 | } 527 | 528 | /* Hide the iPhone on mobile */ 529 | .iphone { 530 | display: none; 531 | } 532 | 533 | } 534 | -------------------------------------------------------------------------------- /doc/img/iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeamDev/Pro/fc9641dde9689276c5b9e625697cbef411e7040a/doc/img/iphone.png -------------------------------------------------------------------------------- /doc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Pro - Framework for mobile platform 6 | 7 | 8 | 9 | 10 | 11 | 12 | 92 | 93 | 94 | 95 | 96 | 106 | 107 | 113 | 114 | 115 |
116 |
117 | 118 |
119 |

Getting started

120 |

An overview of Pro, how to download and use, basic templates.

121 |
122 | 123 |

Download

124 | 125 |

Pro has a few easy ways to quickly get started, each one appealing to a different skill level and use case. Read through to see what suits your particular needs.

126 | 127 |

Download Pro

128 | 129 |

Download Pro Compiled and minified CSS, JavaScript.

130 | 131 |

Download Source Source CSS, JavaScript.

132 | 133 |

Install with Bower

134 | 135 |

Install and manage Pro’s CSS, JavaScript, using Bower.

136 | 137 |
bower install pro
138 | 139 |

Setup

140 | 141 |

3 steps for structuring your Pro application

142 | 143 |
    144 |
  1. 145 |

    Set viewport meta

    146 |

    <name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">

    147 |
  2. 148 |
  3. 149 |

    Set fixed bars

    150 |

    All fixed bars (.ui-top-bar, .ui-bottom-bar) should always be the first thing in the body of the page. This is really important!

    151 |
  4. 152 |
  5. 153 |

    Put content into .ui-page

    154 |

    Anything that’s not a -bar should be put in a div with the class ui-page. Put this div after the bars in the body tag.

    155 |
  6. 156 |
157 | 158 |

Basic template

159 | 160 |

Start with this basic HTML template, or modify it, adapting them to suit your needs.

161 | 162 |

Copy the HTML below to begin working with a minimal Pro document.

163 | 164 |
<!DOCTYPE html>
165 | <html>
166 | <head>
167 |     <meta charset='utf-8'>
168 |     <title>Pro Template</title>
169 |     <meta charset="utf-8">
170 |     <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
171 | 
172 |     <!-- Pro CSS -->
173 |     <link rel="stylesheet" type="text/css" href="css/pro.css">
174 | </head>
175 | <body class="ui-app">
176 | 
177 |     <div class="ui-top-bar js-no-bounce">
178 |         PRO Template
179 |     </div>
180 | 
181 |     <div class="ui-bottom-bar js-no-bounce" role="toolbar" tabindex="0">
182 |         <button class="ui-bottom-bar-button js-active" data-toggle="tab" data-target="#page1">
183 |             <span class="ui-icon"></span>
184 |             <span class="ui-label">CSS</span>
185 |         </button>
186 |         </div>
187 |     </div>
188 | 
189 |     <div id="page1" class="ui-page js-active">
190 |         <div class="ui-page-content">
191 |              <h1>Hello, world!</h1>
192 |         </div>
193 |     </div>
194 | 
195 |     <!-- Pro JS -->
196 |     <script src="js/pro.js"></script>
197 |   </body>
198 | </html>
199 | 200 |
201 |
202 | 203 | 204 |
205 |
206 | 207 |
208 |

Components

209 | 210 |

Bring Pro's components to life with over a dozen custom Zepto plugins. Easily include them all, or one by one.

211 |
212 | 213 |
214 |
215 |
216 | 217 |

按钮

218 |

219 | 220 | 221 | 222 | 223 |

224 | 225 |

块级按钮

226 |

227 | 228 | 229 | 230 | 231 |

232 |
233 |
234 |
235 | 236 | 237 |
238 |

Buttons

239 | 240 |

Buttons 包含三种状态:正常态、激活态、不可用态

241 | 242 |
243 | 244 |

按钮

245 |

246 | 247 | 248 | 249 | 250 |

251 | 252 |

块级按钮

253 |

254 | 255 | 256 | 257 | 258 |

259 | 260 |
261 |
262 | 263 | 282 | 283 | 284 | 310 | 311 |
312 |

Spinner

313 |
314 | 315 | 316 |

Trigger

317 |

318 | 321 | 324 |

325 | 326 |
327 |
328 | 329 | 358 | 359 |
360 |

Counter

361 |
362 | 363 |

CountUp

364 |
365 | 0 366 |
367 | 368 |

CountDown

369 |
370 | 9521 371 |
372 | 373 |
374 |
375 | 376 |
377 |

Deleter

378 | 423 |
424 | 425 |
426 |

Tab

427 |
428 | 429 |

Blue

430 |
431 |
    432 |
  • 列表 1123
  • 433 |
  • 列表 2
  • 434 |
  • 列表 32
  • 435 |
436 |
437 | 438 |

Gray

439 |
440 |
    441 |
  • 列表 1
  • 442 |
  • 列表 2
  • 443 |
  • 列表 31
  • 444 |
445 |
446 | 447 |
448 |
449 | 450 |
451 |

Notify

452 |
453 | 454 |

Notify

455 |

456 | 459 |

460 | 461 | 466 | 467 |
468 |
469 | 470 |
471 |

Alert

472 |
473 | 474 |

Alert

475 |

476 | 479 | 480 | 483 | 484 | 487 | 488 | 491 | 492 | 495 | 496 | 499 |

500 | 501 | 512 | 513 |
514 |
515 | 516 |
517 |

Action Sheet

518 |
519 | 520 |

Action Sheet

521 |

522 | 525 |

526 | 527 | 536 | 537 |
538 |
539 | 540 |
541 |
542 | 543 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | -------------------------------------------------------------------------------- /doc/js/doc.js: -------------------------------------------------------------------------------- 1 | require([ 2 | '../vendor/zepto/dimensions' 3 | ], function(){ 4 | 5 | var windowWidth; 6 | var windowHeight; 7 | var pageHeight; 8 | var contentPadding; 9 | var footerHeight; 10 | var noticeBanner; 11 | var componentsList; 12 | var navComponentLinks; 13 | var contentSection; 14 | var currentActive; 15 | var topCache; 16 | var eventListeners; 17 | 18 | var $doc = $(document); 19 | var $win = $(window); 20 | var $body = $(document.body); 21 | var $iphone = $('.iphone'); 22 | 23 | (function main(){ 24 | prettyPrintExample(); 25 | 26 | $win.on('ready resize', initialize); 27 | 28 | // TODO FingerBlast会导致checkbox无法点击 29 | $win.on('ready', function () { 30 | new FingerBlast('.iphone-content'); 31 | }); 32 | 33 | // Spinner 34 | $doc.on('tap', '[data-toggle="spinner"]', function () { 35 | var $this = $('.ui-app'); 36 | $this.spinner('toggle') 37 | }); 38 | 39 | })(); 40 | 41 | function prettyPrintExample(){ 42 | var componentExample = $('.component-example'); 43 | 44 | componentExample.each(function(index, node){ 45 | var $node = $(node); 46 | var preStart = '
';
 47 |             var preEnd = '
'; 48 | var preContent = $node.html().replace(/&/g, '&').replace(//g, ">").replace(/"/g, """).replace(/'/g, "'").trim(); 49 | $node.after( preStart + preContent + preEnd); 50 | }); 51 | 52 | prettyPrint(); 53 | } 54 | 55 | function initialize() { 56 | currentActive = 0; 57 | topCache = []; 58 | noticeBanner = $('.notice-banner'); 59 | navComponentLinks = $('.nav-components-link'); 60 | componentsList = $('.components-list'); 61 | contentSection = $('.component'); 62 | topCache = contentSection.map(function () { return $(this).offset().top }); 63 | windowHeight = $(window).height() / 3; 64 | pageHeight = $(document).height(); 65 | contentPadding = parseInt($('.doc-content').css('padding-bottom')); 66 | footerHeight = $('.doc-footer').outerHeight(false); 67 | 68 | $iphone.initialLeft = $iphone.offset().left; 69 | $iphone.initialTop = $iphone.initialTop || $iphone.offset().top; 70 | $iphone.dockingOffset = ($(window).height() + 20 + $('.doc-masthead').height() - $iphone.height())/2; 71 | 72 | checkDesktopContent(); 73 | calculateScroll(); 74 | 75 | if (!eventListeners) addEventListeners(); 76 | } 77 | 78 | function addEventListeners() { 79 | eventListeners = true; 80 | 81 | noticeBanner.on('click', function () { 82 | $(this).hide(); 83 | }); 84 | 85 | // TODO 会导致checkbox无法点击 86 | $iphone.on('click', function (e) { 87 | e.preventDefault(); 88 | }); 89 | 90 | navComponentLinks.click(function(e) { 91 | e.stopPropagation(); 92 | e.preventDefault(); 93 | // componentsList.toggleClass('active'); 94 | componentsList.removeClass('active'); 95 | $(e.target.parentNode.children[1]).toggleClass('active'); 96 | }); 97 | 98 | $doc.on('click', function () { 99 | componentsList.removeClass('active'); 100 | }); 101 | 102 | $win.on('scroll', calculateScroll); 103 | 104 | } 105 | 106 | function checkDesktopContent() { 107 | windowWidth = $(window).width(); 108 | if (windowWidth <= 768) { 109 | var content = $('.content'); 110 | if (content.length > 1) { 111 | $(content[0]).remove() 112 | } 113 | } 114 | } 115 | 116 | function calculateScroll() { 117 | // if small screen don't worry about this 118 | if (windowWidth <= 768) return 119 | 120 | // Save scrollTop value 121 | var contentSectionItem; 122 | var currentTop = $win.scrollTop(); 123 | 124 | // If page is scrolled to bottom near footers 125 | if(pageHeight - currentTop < footerHeight + contentPadding + 1400) { 126 | $iphone[0].className = "iphone iphone-bottom"; 127 | $iphone[0].setAttribute('style','') 128 | } else if(($iphone.initialTop - currentTop) <= $iphone.dockingOffset) { 129 | $iphone[0].className = "iphone iphone-fixed"; 130 | $iphone.css({top: $iphone.dockingOffset}) 131 | } else { 132 | $iphone[0].className = "iphone"; 133 | $iphone[0].setAttribute('style','') 134 | } 135 | 136 | // Injection of components into phone 137 | for (var l = contentSection.length; l--;) { 138 | if ((topCache[l] - currentTop) < windowHeight) { 139 | if (currentActive == l) return; 140 | currentActive = l; 141 | $body.find('.component.active').removeClass('active'); 142 | contentSectionItem = $(contentSection[l]); 143 | contentSectionItem.addClass('active'); 144 | if(contentSectionItem.attr('id')) { 145 | $iphone.attr("id", contentSectionItem.attr('id') + "InPhone"); 146 | } else { 147 | $iphone.attr("id", "") 148 | } 149 | if (!contentSectionItem.hasClass('informational')) { 150 | updateContent(contentSectionItem.find('.prettyprint').not('.js').text()) 151 | } 152 | break 153 | } 154 | } 155 | 156 | function updateContent(content) { 157 | $('#iwindow').html(content); 158 | } 159 | } 160 | 161 | }); 162 | -------------------------------------------------------------------------------- /doc/md/getting-started.md: -------------------------------------------------------------------------------- 1 |
2 |

Getting started

3 |

An overview of Pro, how to download and use, basic templates.

4 |
5 | 6 |

Download

7 | 8 |

Pro has a few easy ways to quickly get started, each one appealing to a different skill level and use case. Read through to see what suits your particular needs.

9 | 10 |

Download Pro

11 |

Download Pro Compiled and minified CSS, JavaScript.

12 | 13 |

Download Source Source CSS, JavaScript.

14 | 15 |

Install with Bower

16 |

Install and manage Pro's CSS, JavaScript, using Bower.

17 | 18 | ```bash 19 | bower install pro 20 | ``` 21 | 22 |

Setup

23 | 24 | 3 steps for structuring your Pro application 25 | 26 |
    27 |
  1. 28 |

    Set viewport meta

    29 |

    <name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">

    30 |
  2. 31 |
  3. 32 |

    Set fixed bars

    33 |

    All fixed bars (.ui-top-bar, .ui-bottom-bar) should always be the first thing in the body of the page. This is really important!

    34 |
  4. 35 |
  5. 36 |

    Put content into .ui-page

    37 |

    Anything that's not a -bar should be put in a div with the class ui-page. Put this div after the bars in the body tag.

    38 |
  6. 39 |
40 | 41 |

Basic template

42 | 43 | Start with this basic HTML template, or modify it, adapting them to suit your needs. 44 | 45 | Copy the HTML below to begin working with a minimal Pro document. 46 | 47 | ```html 48 | 49 | 50 | 51 | 52 | Pro Template 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 |
62 | PRO Template 63 |
64 | 65 | 71 | 72 | 73 |
74 |
75 |

Hello, world!

76 |
77 |
78 | 79 | 80 | 81 | 82 | 83 | ``` 84 | 85 | -------------------------------------------------------------------------------- /doc/vendor/fingerblast/fingerblast.js: -------------------------------------------------------------------------------- 1 | // FINGERBLAST.js 2 | // -------------- 3 | // Adapted from phantom limb by brian cartensen 4 | 5 | function FingerBlast(element) { 6 | this.element = typeof element == 'string' ? document.querySelector(element) : element; 7 | this.listen(); 8 | } 9 | 10 | FingerBlast.prototype = { 11 | x: NaN, 12 | y: NaN, 13 | 14 | startDistance: NaN, 15 | startAngle: NaN, 16 | 17 | mouseIsDown: false, 18 | 19 | listen: function () { 20 | 21 | var activate = this.activate.bind(this); 22 | var deactivate = this.deactivate.bind(this); 23 | 24 | function contains (element, ancestor) { 25 | var descendants, index, descendant; 26 | if ("compareDocumentPosition" in ancestor) { 27 | return !!(ancestor.compareDocumentPosition(element) & 16); 28 | } else if ("contains" in ancestor) { 29 | return ancestor != element && ancestor.contains(element); 30 | } else { 31 | for (descendants = ancestor.getElementsByTagName("*"), index = 0; descendant = descendants[index++];) { 32 | if (descendant == element) return true; 33 | } 34 | return false; 35 | } 36 | } 37 | 38 | this.element.addEventListener('mouseover', function (e) { 39 | var target = e.relatedTarget; 40 | if (target != this && !contains(target, this)) activate(); 41 | }); 42 | 43 | this.element.addEventListener("mouseout", function (e) { 44 | var target = e.relatedTarget; 45 | if (target != this && !contains(target, this)) deactivate(e); 46 | }); 47 | }, 48 | 49 | activate: function () { 50 | if (this.active) return; 51 | this.element.addEventListener('mousedown', (this.touchStart = this.touchStart.bind(this)), true); 52 | this.element.addEventListener('mousemove', (this.touchMove = this.touchMove.bind(this)), true); 53 | this.element.addEventListener('mouseup', (this.touchEnd = this.touchEnd.bind(this)), true); 54 | this.element.addEventListener('click', (this.click = this.click.bind(this)), true); 55 | this.active = true; 56 | }, 57 | 58 | deactivate: function (e) { 59 | this.active = false; 60 | if (this.mouseIsDown) this.touchEnd(e); 61 | this.element.removeEventListener('mousedown', this.touchStart, true); 62 | this.element.removeEventListener('mousemove', this.touchMove, true); 63 | this.element.removeEventListener('mouseup', this.touchEnd, true); 64 | this.element.removeEventListener('click', this.click, true); 65 | }, 66 | 67 | click: function (e) { 68 | if (e.synthetic) return; 69 | e.preventDefault(); 70 | e.stopPropagation(); 71 | }, 72 | 73 | touchStart: function (e) { 74 | if (e.synthetic || /input|textarea/.test(e.target.tagName.toLowerCase())) return; 75 | 76 | this.mouseIsDown = true; 77 | 78 | e.preventDefault(); 79 | e.stopPropagation(); 80 | 81 | this.fireTouchEvents('touchstart', e); 82 | }, 83 | 84 | touchMove: function (e) { 85 | if (e.synthetic) return; 86 | 87 | e.preventDefault(); 88 | e.stopPropagation(); 89 | 90 | this.move(e.clientX, e.clientY); 91 | 92 | if (this.mouseIsDown) this.fireTouchEvents('touchmove', e); 93 | }, 94 | 95 | touchEnd: function (e) { 96 | if (e.synthetic) return; 97 | 98 | this.mouseIsDown = false; 99 | 100 | e.preventDefault(); 101 | e.stopPropagation(); 102 | 103 | this.fireTouchEvents('touchend', e); 104 | 105 | if (!this.target) return; 106 | 107 | // Mobile Safari moves all the mouse events to fire after the touchend event. 108 | this.target.dispatchEvent(this.createMouseEvent('mouseover', e)); 109 | this.target.dispatchEvent(this.createMouseEvent('mousemove', e)); 110 | this.target.dispatchEvent(this.createMouseEvent('mousedown', e)); 111 | }, 112 | 113 | fireTouchEvents: function (eventName, originalEvent) { 114 | var events = []; 115 | var gestures = []; 116 | 117 | if (!this.target) return; 118 | 119 | // Convert "ontouch*" properties and attributes to listeners. 120 | var onEventName = 'on' + eventName; 121 | 122 | if (onEventName in this.target) { 123 | console.warn('Converting `' + onEventName + '` property to event listener.', this.target); 124 | this.target.addEventListener(eventName, this.target[onEventName], false); 125 | delete this.target[onEventName]; 126 | } 127 | 128 | if (this.target.hasAttribute(onEventName)) { 129 | console.warn('Converting `' + onEventName + '` attribute to event listener.', this.target); 130 | var handler = new GLOBAL.Function('event', this.target.getAttribute(onEventName)); 131 | this.target.addEventListener(eventName, handler, false); 132 | this.target.removeAttribute(onEventName); 133 | } 134 | 135 | // Set up a new event with the coordinates of the finger. 136 | var touch = this.createMouseEvent(eventName, originalEvent); 137 | 138 | events.push(touch); 139 | 140 | // Figure out scale and rotation. 141 | if (events.length > 1) { 142 | var x = events[0].pageX - events[1].pageX; 143 | var y = events[0].pageY - events[1].pageY; 144 | 145 | var distance = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); 146 | var angle = Math.atan2(x, y) * (180 / Math.PI); 147 | 148 | var gestureName = 'gesturechange'; 149 | 150 | if (eventName === 'touchstart') { 151 | gestureName = 'gesturestart'; 152 | this.startDistance = distance; 153 | this.startAngle = angle; 154 | } 155 | 156 | if (eventName === 'touchend') gestureName = 'gestureend'; 157 | 158 | events.forEach(function(event) { 159 | var gesture = this.createMouseEvent.call(event._finger, gestureName, event); 160 | gestures.push(gesture); 161 | }.bind(this)); 162 | 163 | events.concat(gestures).forEach(function(event) { 164 | event.scale = distance / this.startDistance; 165 | event.rotation = this.startAngle - angle; 166 | }); 167 | } 168 | 169 | // Loop through the events array and fill in each touch array. 170 | events.forEach(function(touch) { 171 | touch.touches = events.filter(function(e) { 172 | return ~e.type.indexOf('touch') && e.type !== 'touchend'; 173 | }); 174 | 175 | touch.changedTouches = events.filter(function(e) { 176 | return ~e.type.indexOf('touch') && e._finger.target === touch._finger.target; 177 | }); 178 | 179 | touch.targetTouches = touch.changedTouches.filter(function(e) { 180 | return ~e.type.indexOf('touch') && e.type !== 'touchend'; 181 | }); 182 | }); 183 | 184 | // Then fire the events. 185 | events.concat(gestures).forEach(function(event, i) { 186 | event.identifier = i; 187 | event._finger.target.dispatchEvent(event); 188 | }); 189 | }, 190 | 191 | createMouseEvent: function (eventName, originalEvent) { 192 | var e = document.createEvent('MouseEvent'); 193 | 194 | e.initMouseEvent(eventName, true, true, 195 | originalEvent.view, originalEvent.detail, 196 | this.x || originalEvent.screenX, this.y || originalEvent.screenY, 197 | this.x || originalEvent.clientX, this.y || originalEvent.clientY, 198 | originalEvent.ctrlKey, originalEvent.shiftKey, 199 | originalEvent.altKey, originalEvent.metaKey, 200 | originalEvent.button, this.target || originalEvent.relatedTarget 201 | ); 202 | 203 | e.synthetic = true; 204 | e._finger = this; 205 | 206 | return e; 207 | }, 208 | 209 | move: function (x, y) { 210 | if (isNaN(x) || isNaN(y)) { 211 | this.target = null; 212 | } else { 213 | this.x = x; 214 | this.y = y; 215 | 216 | if (!this.mouseIsDown) { 217 | this.target = document.elementFromPoint(x, y); 218 | } 219 | } 220 | } 221 | }; -------------------------------------------------------------------------------- /doc/vendor/prettify/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#999}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:teal}.atv{color:#d14}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} -------------------------------------------------------------------------------- /doc/vendor/prettify/prettify.js: -------------------------------------------------------------------------------- 1 | var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; 2 | (function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= 3 | [],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), 9 | l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, 10 | q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, 11 | q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, 12 | "");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), 13 | a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} 14 | for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], 18 | "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], 19 | H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], 20 | J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ 21 | I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), 22 | ["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", 23 | /^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), 24 | ["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", 25 | hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= 26 | !k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p)<[^<]*)*<\/script>/gi, 12 | scriptTypeRE = /^(?:text|application)\/javascript/i, 13 | xmlTypeRE = /^(?:text|application)\/xml/i, 14 | jsonType = 'application/json', 15 | htmlType = 'text/html', 16 | blankRE = /^\s*$/ 17 | 18 | // trigger a custom event and return false if it was cancelled 19 | function triggerAndReturn(context, eventName, data) { 20 | var event = $.Event(eventName) 21 | $(context).trigger(event, data) 22 | return !event.isDefaultPrevented() 23 | } 24 | 25 | // trigger an Ajax "global" event 26 | function triggerGlobal(settings, context, eventName, data) { 27 | if (settings.global) return triggerAndReturn(context || document, eventName, data) 28 | } 29 | 30 | // Number of active Ajax requests 31 | $.active = 0 32 | 33 | function ajaxStart(settings) { 34 | if (settings.global && $.active++ === 0) triggerGlobal(settings, null, 'ajaxStart') 35 | } 36 | function ajaxStop(settings) { 37 | if (settings.global && !(--$.active)) triggerGlobal(settings, null, 'ajaxStop') 38 | } 39 | 40 | // triggers an extra global event "ajaxBeforeSend" that's like "ajaxSend" but cancelable 41 | function ajaxBeforeSend(xhr, settings) { 42 | var context = settings.context 43 | if (settings.beforeSend.call(context, xhr, settings) === false || 44 | triggerGlobal(settings, context, 'ajaxBeforeSend', [xhr, settings]) === false) 45 | return false 46 | 47 | triggerGlobal(settings, context, 'ajaxSend', [xhr, settings]) 48 | } 49 | function ajaxSuccess(data, xhr, settings, deferred) { 50 | var context = settings.context, status = 'success' 51 | settings.success.call(context, data, status, xhr) 52 | if (deferred) deferred.resolveWith(context, [data, status, xhr]) 53 | triggerGlobal(settings, context, 'ajaxSuccess', [xhr, settings, data]) 54 | ajaxComplete(status, xhr, settings) 55 | } 56 | // type: "timeout", "error", "abort", "parsererror" 57 | function ajaxError(error, type, xhr, settings, deferred) { 58 | var context = settings.context 59 | settings.error.call(context, xhr, type, error) 60 | if (deferred) deferred.rejectWith(context, [xhr, type, error]) 61 | triggerGlobal(settings, context, 'ajaxError', [xhr, settings, error || type]) 62 | ajaxComplete(type, xhr, settings) 63 | } 64 | // status: "success", "notmodified", "error", "timeout", "abort", "parsererror" 65 | function ajaxComplete(status, xhr, settings) { 66 | var context = settings.context 67 | settings.complete.call(context, xhr, status) 68 | triggerGlobal(settings, context, 'ajaxComplete', [xhr, settings]) 69 | ajaxStop(settings) 70 | } 71 | 72 | // Empty function, used as default callback 73 | function empty() {} 74 | 75 | $.ajaxJSONP = function(options, deferred){ 76 | if (!('type' in options)) return $.ajax(options) 77 | 78 | var _callbackName = options.jsonpCallback, 79 | callbackName = ($.isFunction(_callbackName) ? 80 | _callbackName() : _callbackName) || ('jsonp' + (++jsonpID)), 81 | script = document.createElement('script'), 82 | originalCallback = window[callbackName], 83 | responseData, 84 | abort = function(errorType) { 85 | $(script).triggerHandler('error', errorType || 'abort') 86 | }, 87 | xhr = { abort: abort }, abortTimeout 88 | 89 | if (deferred) deferred.promise(xhr) 90 | 91 | $(script).on('load error', function(e, errorType){ 92 | clearTimeout(abortTimeout) 93 | $(script).off().remove() 94 | 95 | if (e.type == 'error' || !responseData) { 96 | ajaxError(null, errorType || 'error', xhr, options, deferred) 97 | } else { 98 | ajaxSuccess(responseData[0], xhr, options, deferred) 99 | } 100 | 101 | window[callbackName] = originalCallback 102 | if (responseData && $.isFunction(originalCallback)) 103 | originalCallback(responseData[0]) 104 | 105 | originalCallback = responseData = undefined 106 | }) 107 | 108 | if (ajaxBeforeSend(xhr, options) === false) { 109 | abort('abort') 110 | return xhr 111 | } 112 | 113 | window[callbackName] = function(){ 114 | responseData = arguments 115 | } 116 | 117 | script.src = options.url.replace(/\?(.+)=\?/, '?$1=' + callbackName) 118 | document.head.appendChild(script) 119 | 120 | if (options.timeout > 0) abortTimeout = setTimeout(function(){ 121 | abort('timeout') 122 | }, options.timeout) 123 | 124 | return xhr 125 | } 126 | 127 | $.ajaxSettings = { 128 | // Default type of request 129 | type: 'GET', 130 | // Callback that is executed before request 131 | beforeSend: empty, 132 | // Callback that is executed if the request succeeds 133 | success: empty, 134 | // Callback that is executed the the server drops error 135 | error: empty, 136 | // Callback that is executed on request complete (both: error and success) 137 | complete: empty, 138 | // The context for the callbacks 139 | context: null, 140 | // Whether to trigger "global" Ajax events 141 | global: true, 142 | // Transport 143 | xhr: function () { 144 | return new window.XMLHttpRequest() 145 | }, 146 | // MIME types mapping 147 | // IIS returns Javascript as "application/x-javascript" 148 | accepts: { 149 | script: 'text/javascript, application/javascript, application/x-javascript', 150 | json: jsonType, 151 | xml: 'application/xml, text/xml', 152 | html: htmlType, 153 | text: 'text/plain' 154 | }, 155 | // Whether the request is to another domain 156 | crossDomain: false, 157 | // Default timeout 158 | timeout: 0, 159 | // Whether data should be serialized to string 160 | processData: true, 161 | // Whether the browser should be allowed to cache GET responses 162 | cache: true 163 | } 164 | 165 | function mimeToDataType(mime) { 166 | if (mime) mime = mime.split(';', 2)[0] 167 | return mime && ( mime == htmlType ? 'html' : 168 | mime == jsonType ? 'json' : 169 | scriptTypeRE.test(mime) ? 'script' : 170 | xmlTypeRE.test(mime) && 'xml' ) || 'text' 171 | } 172 | 173 | function appendQuery(url, query) { 174 | if (query == '') return url 175 | return (url + '&' + query).replace(/[&?]{1,2}/, '?') 176 | } 177 | 178 | // serialize payload and append it to the URL for GET requests 179 | function serializeData(options) { 180 | if (options.processData && options.data && $.type(options.data) != "string") 181 | options.data = $.param(options.data, options.traditional) 182 | if (options.data && (!options.type || options.type.toUpperCase() == 'GET')) 183 | options.url = appendQuery(options.url, options.data), options.data = undefined 184 | } 185 | 186 | $.ajax = function(options){ 187 | var settings = $.extend({}, options || {}), 188 | deferred = $.Deferred && $.Deferred() 189 | for (key in $.ajaxSettings) if (settings[key] === undefined) settings[key] = $.ajaxSettings[key] 190 | 191 | ajaxStart(settings) 192 | 193 | if (!settings.crossDomain) settings.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(settings.url) && 194 | RegExp.$2 != window.location.host 195 | 196 | if (!settings.url) settings.url = window.location.toString() 197 | serializeData(settings) 198 | if (settings.cache === false) settings.url = appendQuery(settings.url, '_=' + Date.now()) 199 | 200 | var dataType = settings.dataType, hasPlaceholder = /\?.+=\?/.test(settings.url) 201 | if (dataType == 'jsonp' || hasPlaceholder) { 202 | if (!hasPlaceholder) 203 | settings.url = appendQuery(settings.url, 204 | settings.jsonp ? (settings.jsonp + '=?') : settings.jsonp === false ? '' : 'callback=?') 205 | return $.ajaxJSONP(settings, deferred) 206 | } 207 | 208 | var mime = settings.accepts[dataType], 209 | headers = { }, 210 | setHeader = function(name, value) { headers[name.toLowerCase()] = [name, value] }, 211 | protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol, 212 | xhr = settings.xhr(), 213 | nativeSetHeader = xhr.setRequestHeader, 214 | abortTimeout 215 | 216 | if (deferred) deferred.promise(xhr) 217 | 218 | if (!settings.crossDomain) setHeader('X-Requested-With', 'XMLHttpRequest') 219 | setHeader('Accept', mime || '*/*') 220 | if (mime = settings.mimeType || mime) { 221 | if (mime.indexOf(',') > -1) mime = mime.split(',', 2)[0] 222 | xhr.overrideMimeType && xhr.overrideMimeType(mime) 223 | } 224 | if (settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() != 'GET')) 225 | setHeader('Content-Type', settings.contentType || 'application/x-www-form-urlencoded') 226 | 227 | if (settings.headers) for (name in settings.headers) setHeader(name, settings.headers[name]) 228 | xhr.setRequestHeader = setHeader 229 | 230 | xhr.onreadystatechange = function(){ 231 | if (xhr.readyState == 4) { 232 | xhr.onreadystatechange = empty 233 | clearTimeout(abortTimeout) 234 | var result, error = false 235 | if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || (xhr.status == 0 && protocol == 'file:')) { 236 | dataType = dataType || mimeToDataType(settings.mimeType || xhr.getResponseHeader('content-type')) 237 | result = xhr.responseText 238 | 239 | try { 240 | // http://perfectionkills.com/global-eval-what-are-the-options/ 241 | if (dataType == 'script') (1,eval)(result) 242 | else if (dataType == 'xml') result = xhr.responseXML 243 | else if (dataType == 'json') result = blankRE.test(result) ? null : $.parseJSON(result) 244 | } catch (e) { error = e } 245 | 246 | if (error) ajaxError(error, 'parsererror', xhr, settings, deferred) 247 | else ajaxSuccess(result, xhr, settings, deferred) 248 | } else { 249 | ajaxError(xhr.statusText || null, xhr.status ? 'error' : 'abort', xhr, settings, deferred) 250 | } 251 | } 252 | } 253 | 254 | if (ajaxBeforeSend(xhr, settings) === false) { 255 | xhr.abort() 256 | ajaxError(null, 'abort', xhr, settings, deferred) 257 | return xhr 258 | } 259 | 260 | if (settings.xhrFields) for (name in settings.xhrFields) xhr[name] = settings.xhrFields[name] 261 | 262 | var async = 'async' in settings ? settings.async : true 263 | xhr.open(settings.type, settings.url, async, settings.username, settings.password) 264 | 265 | for (name in headers) nativeSetHeader.apply(xhr, headers[name]) 266 | 267 | if (settings.timeout > 0) abortTimeout = setTimeout(function(){ 268 | xhr.onreadystatechange = empty 269 | xhr.abort() 270 | ajaxError(null, 'timeout', xhr, settings, deferred) 271 | }, settings.timeout) 272 | 273 | // avoid sending empty string (#319) 274 | xhr.send(settings.data ? settings.data : null) 275 | return xhr 276 | } 277 | 278 | // handle optional data/success arguments 279 | function parseArguments(url, data, success, dataType) { 280 | if ($.isFunction(data)) dataType = success, success = data, data = undefined 281 | if (!$.isFunction(success)) dataType = success, success = undefined 282 | return { 283 | url: url 284 | , data: data 285 | , success: success 286 | , dataType: dataType 287 | } 288 | } 289 | 290 | $.get = function(/* url, data, success, dataType */){ 291 | return $.ajax(parseArguments.apply(null, arguments)) 292 | } 293 | 294 | $.post = function(/* url, data, success, dataType */){ 295 | var options = parseArguments.apply(null, arguments) 296 | options.type = 'POST' 297 | return $.ajax(options) 298 | } 299 | 300 | $.getJSON = function(/* url, data, success */){ 301 | var options = parseArguments.apply(null, arguments) 302 | options.dataType = 'json' 303 | return $.ajax(options) 304 | } 305 | 306 | $.fn.load = function(url, data, success){ 307 | if (!this.length) return this 308 | var self = this, parts = url.split(/\s/), selector, 309 | options = parseArguments(url, data, success), 310 | callback = options.success 311 | if (parts.length > 1) options.url = parts[0], selector = parts[1] 312 | options.success = function(response){ 313 | self.html(selector ? 314 | $('
').html(response.replace(rscript, "")).find(selector) 315 | : response) 316 | callback && callback.apply(self, arguments) 317 | } 318 | $.ajax(options) 319 | return this 320 | } 321 | 322 | var escape = encodeURIComponent 323 | 324 | function serialize(params, obj, traditional, scope){ 325 | var type, array = $.isArray(obj), hash = $.isPlainObject(obj) 326 | $.each(obj, function(key, value) { 327 | type = $.type(value) 328 | if (scope) key = traditional ? scope : 329 | scope + '[' + (hash || type == 'object' || type == 'array' ? key : '') + ']' 330 | // handle data in serializeArray() format 331 | if (!scope && array) params.add(value.name, value.value) 332 | // recurse into nested objects 333 | else if (type == "array" || (!traditional && type == "object")) 334 | serialize(params, value, traditional, key) 335 | else params.add(key, value) 336 | }) 337 | } 338 | 339 | $.param = function(obj, traditional){ 340 | var params = [] 341 | params.add = function(k, v){ this.push(escape(k) + '=' + escape(v)) } 342 | serialize(params, obj, traditional) 343 | return params.join('&').replace(/%20/g, '+') 344 | } 345 | })(Zepto) 346 | 347 | }); 348 | -------------------------------------------------------------------------------- /js/carousel.js: -------------------------------------------------------------------------------- 1 | define(['./event', './data', './touch', './transition', './requestAnimationFrame'], function(){ 2 | 3 | var activeClass = 'js-active'; 4 | var slidEvent = 'slid:carousel'; 5 | 6 | function Carousel(element, options) { 7 | this.$element = $(element); 8 | this.$indicators = this.$element.find('.ui-carousel-indicators'); 9 | this.options = options; 10 | this.paused = 11 | this.sliding = 12 | this.interval = 13 | this.$active = 14 | this.$items = null; 15 | 16 | // TODO when only one item, do not need init swiping 17 | this.swipeable() 18 | } 19 | 20 | Carousel.DEFAULTS = { 21 | interval: 5000, 22 | wrap: true 23 | }; 24 | 25 | Carousel.prototype.cycle = function (e) { 26 | e || (this.paused = false); 27 | 28 | this.interval && clearInterval(this.interval); 29 | 30 | this.options.interval 31 | && !this.paused 32 | && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)); 33 | 34 | return this 35 | }; 36 | 37 | Carousel.prototype.getActiveIndex = function () { 38 | this.$active = this.$element.find('.ui-carousel-item.'+ activeClass); 39 | this.$items = this.$active.parent().children(); 40 | 41 | return this.$items.index(this.$active); 42 | }; 43 | 44 | Carousel.prototype.to = function (pos) { 45 | var that = this; 46 | var activeIndex = this.getActiveIndex(); 47 | 48 | if (pos > (this.$items.length - 1) || pos < 0) return; 49 | 50 | if (this.sliding) return this.$element.one(slidEvent, function () { that.to(pos) }); 51 | if (activeIndex == pos) return this.pause().cycle(); 52 | 53 | return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])); 54 | }; 55 | 56 | Carousel.prototype.pause = function (e) { 57 | e || (this.paused = true); 58 | 59 | if (this.$element.find('.js-next, .js-prev').length && $.support.transition) { 60 | this.$element.trigger($.support.transition.end); 61 | this.cycle(true) 62 | } 63 | 64 | this.interval = clearInterval(this.interval); 65 | 66 | return this 67 | }; 68 | 69 | Carousel.prototype.next = function () { 70 | if (this.sliding) return; 71 | return this.slide('next') 72 | }; 73 | 74 | Carousel.prototype.prev = function () { 75 | if (this.sliding) return; 76 | return this.slide('prev') 77 | }; 78 | 79 | Carousel.prototype.slide = function (type, next) { 80 | var $active = this.$element.find('.ui-carousel-item.'+ activeClass); 81 | var $next = next || $active[type](); 82 | var direction = type == 'next' ? 'left' : 'right'; 83 | var fallback = type == 'next' ? 'first' : 'last'; 84 | var that = this; 85 | 86 | if (!$next.length) { 87 | if (!this.options.wrap) return; 88 | $next = this.$element.find('.ui-carousel-item')[fallback]() 89 | } 90 | 91 | if ($next.hasClass(activeClass)) return this.sliding = false; 92 | 93 | var e = $.Event(slidEvent, { relatedTarget: $next[0], direction: direction }); 94 | this.$element.trigger(e); 95 | if (e.isDefaultPrevented()) return; 96 | 97 | this.sliding = true; 98 | this.pause(); 99 | 100 | if (this.$indicators.length) { 101 | this.$indicators.find('.'+ activeClass).removeClass(activeClass); 102 | this.$element.one(slidEvent, function () { 103 | var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]); 104 | $nextIndicator && $nextIndicator.addClass(activeClass) 105 | }) 106 | } 107 | 108 | if ($.support.transition && this.$element.hasClass('js-slide') && !this.swiping) { 109 | // js related class 110 | var directionClass = 'js-' + direction; 111 | var typeClass = 'js-' + type; 112 | $next.addClass(typeClass); 113 | $next[0].offsetWidth; // force reflow 114 | $active.addClass(directionClass); 115 | $next.addClass(directionClass); 116 | $active 117 | .one($.support.transition.end, function () { 118 | $next.removeClass([typeClass, directionClass].join(' ')).addClass(activeClass); 119 | $active.removeClass([activeClass, directionClass].join(' ')); 120 | that.sliding = false; 121 | setTimeout(function () { that.$element.trigger(slidEvent) }, 0) 122 | }) 123 | .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000) 124 | } else { 125 | $active.removeClass(activeClass); 126 | $next.addClass(activeClass); 127 | this.sliding = false; 128 | this.$element.trigger(slidEvent); 129 | } 130 | 131 | this.cycle(); 132 | 133 | // reset swipe refs 134 | this.$center = $next; 135 | var $item = (function(){ 136 | var $item = $next[type](); 137 | if (!$item.length) { 138 | if (!that.options.wrap) return; 139 | $item = that.$element.find('.ui-carousel-item')[fallback]() 140 | } 141 | return $item; 142 | })(); 143 | 144 | this.$left = type == 'next'? $active: $item; 145 | this.$right = type == 'next'? $item: $active; 146 | 147 | return this 148 | } 149 | 150 | Carousel.prototype.swipeable = function(){ 151 | // init swipe refs 152 | // TODO when not start from first item 153 | var $active = this.$element.find('.ui-carousel-item.'+ activeClass); 154 | this.$center = $active; 155 | this.$left = this.$element.find('.ui-carousel-item').last(); 156 | this.$right = $active.next(); 157 | 158 | var offset = 0, 159 | width = window.innerWidth, 160 | pressed = false, 161 | timeConstant = 125, 162 | xform= 'webkitTransform'; 163 | 164 | var reference, 165 | amplitude, 166 | target, 167 | velocity, 168 | frame, 169 | timestamp, 170 | ticker; 171 | 172 | var slide = false; 173 | var type = ''; // next or prev 174 | var that = this; 175 | 176 | this.$element.on('touchstart', function touchstart(e) { 177 | 178 | if(!that.sliding){ 179 | pressed = true; 180 | reference = xpos(e); 181 | 182 | velocity = amplitude = 0; 183 | frame = offset; 184 | timestamp = Date.now(); 185 | clearInterval(ticker); 186 | ticker = setInterval(track, 100); 187 | 188 | that.pause(); 189 | that.$left.addClass('js-show'); 190 | that.$right.addClass('js-show'); 191 | } 192 | 193 | e.preventDefault(); 194 | e.stopPropagation(); 195 | return false; 196 | }); 197 | 198 | this.$element.on('touchmove', function touchmove(e) { 199 | var x, delta; 200 | if (pressed) { 201 | x = xpos(e); 202 | delta = reference - x; 203 | if (delta > 2 || delta < -2) { 204 | reference = x; 205 | scroll(offset + delta); 206 | } 207 | } 208 | 209 | e.preventDefault(); 210 | e.stopPropagation(); 211 | return false; 212 | }); 213 | 214 | this.$element.on('touchend', function touchend(e) { 215 | 216 | if(!that.sliding){ 217 | pressed = false; 218 | 219 | clearInterval(ticker); 220 | target = offset; 221 | if (velocity > 10 || velocity < -10) { 222 | amplitude = 1.2 * velocity; 223 | target = offset + amplitude; 224 | } 225 | target = Math.round(target / width) * width; 226 | target = (target < -width) ? -width : (target > width) ? width : target; 227 | amplitude = target - offset; 228 | timestamp = Date.now(); 229 | 230 | that.swiping = true; 231 | slide = target !== 0; 232 | type = offset > 0? 'next': 'prev'; 233 | autoScroll(); 234 | } 235 | 236 | e.preventDefault(); 237 | e.stopPropagation(); 238 | return false; 239 | }); 240 | 241 | function xpos(e) { 242 | // touch event 243 | if (e.targetTouches && (e.targetTouches.length >= 1)) { 244 | return e.targetTouches[0].clientX; 245 | } 246 | 247 | // mouse event 248 | return e.clientX; 249 | } 250 | 251 | function track() { 252 | var now, elapsed, delta, v; 253 | 254 | now = Date.now(); 255 | elapsed = now - timestamp; 256 | timestamp = now; 257 | delta = offset - frame; 258 | frame = offset; 259 | 260 | v = 800 * delta / (1 + elapsed); 261 | velocity = 0.8 * v + 0.2 * velocity; 262 | } 263 | 264 | function scroll(x) { 265 | offset = x; 266 | x = -Math.round(x); 267 | if(Math.abs(x) > width){ 268 | x = x < 0? -width: width; 269 | } 270 | 271 | that.$left[0].style[xform] = 'translate3d(' + (x - width) + 'px, 0, 0)'; 272 | that.$center[0].style[xform] = 'translate3d(' + x + 'px, 0, 0)'; 273 | that.$right[0].style[xform] = 'translate3d(' + (x + width) + 'px, 0, 0)'; 274 | } 275 | 276 | function autoScroll() { 277 | var elapsed, delta; 278 | 279 | if (amplitude) { 280 | elapsed = Date.now() - timestamp; 281 | delta = amplitude * Math.exp(-elapsed / timeConstant); 282 | if (delta > 10 || delta < -10) { 283 | scroll(target - delta); 284 | return requestAnimationFrame(autoScroll); 285 | } else { 286 | scroll(0); 287 | that.cycle(); 288 | 289 | [that.$left, that.$right].forEach(function($el){ 290 | $el[0].style[xform] = 'translate3d(0, 0, 0)'; 291 | $el.removeClass('js-show'); 292 | }) 293 | 294 | if(slide) that.slide(type); 295 | that.swiping = false; 296 | } 297 | } 298 | } 299 | 300 | }; 301 | 302 | $.Carousel = Carousel; 303 | 304 | $.fn.carousel = function (option) { 305 | return this.each(function () { 306 | var $this = $(this); 307 | var data = $this.data('carousel'); 308 | var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option); 309 | var action = typeof option == 'string' ? option : options.slide; 310 | 311 | if (!data) $this.data('carousel', (data = new Carousel(this, options))); 312 | if (typeof option == 'number') data.to(option); 313 | else if (action) data[action](); 314 | else if (options.interval) data.pause().cycle() 315 | }) 316 | } 317 | 318 | }); 319 | -------------------------------------------------------------------------------- /js/countable.js: -------------------------------------------------------------------------------- 1 | define(['./data', './requestAnimationFrame'], function(){ 2 | 3 | function Counter(element, options) { 4 | 5 | this.$element = $(element); 6 | this.options = options; 7 | 8 | this.frameVal = this.from = Number(options.from); 9 | this.to = Number(options.to); 10 | this.duration = options.duration; 11 | this.decimals = Math.max(0, options.decimals); 12 | this.dec = Math.pow(10, options.decimals); 13 | this.startTime = null; 14 | 15 | var self = this; 16 | 17 | this.count = function(timestamp) { 18 | var from = self.from; 19 | var to = self.to; 20 | var duration = self.duration; 21 | var countDown = from > to; 22 | 23 | if (self.startTime === null) self.startTime = timestamp; 24 | 25 | var progress = timestamp - self.startTime; 26 | 27 | // to ease or not to ease 28 | if (countDown) { 29 | var i = self.easeOutExpo(progress, 0, from - to, duration); 30 | self.frameVal = from - i; 31 | } else { 32 | self.frameVal = self.easeOutExpo(progress, from, to - from, duration); 33 | } 34 | 35 | // decimal 36 | self.frameVal = Math.round(self.frameVal*self.dec)/self.dec; 37 | 38 | // don't go past endVal since progress can exceed duration in the last frame 39 | if (countDown) { 40 | self.frameVal = (self.frameVal < to) ? to : self.frameVal; 41 | } else { 42 | self.frameVal = (self.frameVal > to) ? to : self.frameVal; 43 | } 44 | 45 | // format and print value 46 | var val = self.frameVal.toFixed(self.decimals) 47 | if(self.options.commas){ 48 | val = self.addCommas(val) 49 | } 50 | self.$element.html(val); 51 | 52 | // whether to continue 53 | if (progress < duration) { 54 | requestAnimationFrame(self.count); 55 | } else { 56 | if (self.onComplete != null) self.onComplete(); 57 | } 58 | } 59 | } 60 | 61 | Counter.DEFAULTS = { 62 | commas: false, 63 | decimals: 0, // number of decimal places in number, default 0 64 | duration: 1000 // duration in ms 65 | }; 66 | 67 | Counter.prototype.start = function(callback) { 68 | this.onComplete = callback; 69 | // make sure values are valid 70 | if (!isNaN(this.to) && !isNaN(this.from)) { 71 | requestAnimationFrame(this.count); 72 | } else { 73 | this.$element.html('--'); 74 | console.log('Error: from or to is not a number'); 75 | } 76 | return false; 77 | }; 78 | 79 | // Robert Penner's easeOutExpo 80 | Counter.prototype.easeOutExpo = function(t, b, c, d) { 81 | return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b; 82 | }; 83 | 84 | Counter.prototype.reset = function(){ 85 | this.$element.html(0); 86 | }; 87 | 88 | Counter.prototype.addCommas = function(nStr) { 89 | nStr += ''; 90 | var x, x1, x2, rgx; 91 | x = nStr.split('.'); 92 | x1 = x[0]; 93 | x2 = x.length > 1 ? '.' + x[1] : ''; 94 | rgx = /(\d+)(\d{3})/; 95 | while (rgx.test(x1)) { 96 | x1 = x1.replace(rgx, '$1' + ',' + '$2'); 97 | } 98 | return x1 + x2; 99 | }; 100 | 101 | $.Counter = Counter; 102 | 103 | $.fn.countable = function (option) { 104 | 105 | return $(this).each(function () { 106 | var $this = $(this); 107 | var data = $this.data('counter'); 108 | var options = $.extend({}, Counter.DEFAULTS, $this.data(), typeof option == 'object' && option); 109 | 110 | if (!data) { 111 | data = new Counter(this, options); 112 | $this.data('counter', data) 113 | } 114 | if (typeof option == 'string') data[option](); 115 | else if (options.show) data.show() 116 | }); 117 | }; 118 | 119 | }); 120 | -------------------------------------------------------------------------------- /js/data.js: -------------------------------------------------------------------------------- 1 | define(['./zepto'], function(){ 2 | // Zepto.js 3 | // (c) 2010-2014 Thomas Fuchs 4 | // Zepto.js may be freely distributed under the MIT license. 5 | 6 | // The following code is heavily inspired by jQuery's $.fn.data() 7 | 8 | ;(function($){ 9 | var data = {}, dataAttr = $.fn.data, camelize = $.camelCase, 10 | exp = $.expando = 'Zepto' + (+new Date()), emptyArray = [] 11 | 12 | // Get value from node: 13 | // 1. first try key as given, 14 | // 2. then try camelized key, 15 | // 3. fall back to reading "data-*" attribute. 16 | function getData(node, name) { 17 | var id = node[exp], store = id && data[id] 18 | if (name === undefined) return store || setData(node) 19 | else { 20 | if (store) { 21 | if (name in store) return store[name] 22 | var camelName = camelize(name) 23 | if (camelName in store) return store[camelName] 24 | } 25 | return dataAttr.call($(node), name) 26 | } 27 | } 28 | 29 | // Store value under camelized key on node 30 | function setData(node, name, value) { 31 | var id = node[exp] || (node[exp] = ++$.uuid), 32 | store = data[id] || (data[id] = attributeData(node)) 33 | if (name !== undefined) store[camelize(name)] = value 34 | return store 35 | } 36 | 37 | // Read all "data-*" attributes from a node 38 | function attributeData(node) { 39 | var store = {} 40 | $.each(node.attributes || emptyArray, function(i, attr){ 41 | if (attr.name.indexOf('data-') == 0) 42 | store[camelize(attr.name.replace('data-', ''))] = 43 | $.zepto.deserializeValue(attr.value) 44 | }) 45 | return store 46 | } 47 | 48 | $.fn.data = function(name, value) { 49 | return value === undefined ? 50 | // set multiple values via object 51 | $.isPlainObject(name) ? 52 | this.each(function(i, node){ 53 | $.each(name, function(key, value){ setData(node, key, value) }) 54 | }) : 55 | // get value from first element 56 | this.length == 0 ? undefined : getData(this[0], name) : 57 | // set value on all elements 58 | this.each(function(){ setData(this, name, value) }) 59 | } 60 | 61 | $.fn.removeData = function(names) { 62 | if (typeof names == 'string') names = names.split(/\s+/) 63 | return this.each(function(){ 64 | var id = this[exp], store = id && data[id] 65 | if (store) $.each(names || store, function(key){ 66 | delete store[names ? camelize(this) : key] 67 | }) 68 | }) 69 | } 70 | 71 | // Generate extended `remove` and `empty` functions 72 | ;['remove', 'empty'].forEach(function(methodName){ 73 | var origFn = $.fn[methodName] 74 | $.fn[methodName] = function() { 75 | var elements = this.find('*') 76 | if (methodName === 'remove') elements = elements.add(this) 77 | elements.removeData() 78 | return origFn.call(this) 79 | } 80 | }) 81 | })(Zepto) 82 | 83 | }); 84 | -------------------------------------------------------------------------------- /js/debounce.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Debounces a function by the given threshold. 3 | * @method debounce(fn, wait, [ immediate || true ]) 4 | * @param {Function} function to wrap 5 | * @param {Number} timeout in ms (`100`) 6 | * @param {Boolean} whether to execute at the beginning (`true`) 7 | * @example 8 | * 9 | * window.onresize = debounce(resize, 200); 10 | * function resize(e) { 11 | * console.log('height', window.innerHeight); 12 | * console.log('width', window.innerWidth); 13 | * } 14 | * 15 | */ 16 | define(['./zepto'], function(){ 17 | 18 | $.debounce = function (func, threshold, execAsap){ 19 | var timeout; 20 | if (false !== execAsap) execAsap = true; 21 | 22 | return function debounced(){ 23 | var obj = this, args = arguments; 24 | 25 | function delayed () { 26 | if (!execAsap) { 27 | func.apply(obj, args); 28 | } 29 | timeout = null; 30 | } 31 | 32 | if (timeout) { 33 | clearTimeout(timeout); 34 | } else if (execAsap) { 35 | func.apply(obj, args); 36 | } 37 | 38 | timeout = setTimeout(delayed, threshold || 100); 39 | }; 40 | } 41 | }); 42 | -------------------------------------------------------------------------------- /js/deletable.js: -------------------------------------------------------------------------------- 1 | define(['./event', './data', './requestAnimationFrame'], function () { 2 | 3 | var getTime = Date.now; 4 | 5 | function pos(e) { 6 | // touch event 7 | var touches = e.targetTouches; 8 | if (touches && (touches.length >= 1)) { 9 | return { 10 | x: touches[0].clientX, 11 | y: touches[0].clientY 12 | }; 13 | } 14 | } 15 | 16 | function Deleter(element, options){ 17 | this.$element = $(element); 18 | this.options = options; 19 | // 0 is init state 20 | // 1 is tap state 21 | // 2 is snap left 22 | // 3 is snap right 23 | this._state = 0; 24 | this._pre = {}; // pre position 25 | this._opened = false; 26 | this._offset = 0; 27 | } 28 | 29 | Deleter.DEFAULTS = { 30 | init: true, 31 | // left/right snap value 32 | left: 60, //px 33 | right: 0, 34 | timeConstant: 125 // ms 35 | }; 36 | 37 | Deleter.prototype.init = function(){ 38 | this.$element.on('touchstart', $.proxy(this.start, this)); 39 | this.$element.on('touchmove', $.proxy(this.move, this)); 40 | this.$element.on('touchend', $.proxy(this.end, this)); 41 | this.autoTranslate = $.proxy(this.autoTranslate, this); 42 | }; 43 | 44 | Deleter.prototype.translate = function (x) { 45 | var move = -Math.round(x); 46 | if(move <= -this.options.right) this.$element.css('-webkit-transform', 'translate3d(' + move + 'px, 0, 0)'); 47 | // make the latest offset value 48 | this._offset = x; 49 | }; 50 | 51 | Deleter.prototype.track = function () { 52 | var now = getTime(); 53 | var elapsed = now - this._timestamp; 54 | this._timestamp = now; 55 | 56 | var delta = this._offset - this._frame; 57 | this._frame = this._offset; 58 | 59 | var v = 1000 * delta / (1 + elapsed); 60 | this._speed = 0.8 * v + 0.2 * this._speed; 61 | }; 62 | 63 | Deleter.prototype.autoTranslate = function () { 64 | 65 | var amplitude = this._amplitude; 66 | var target = this._target; 67 | var options = this.options; 68 | var left = options.left; 69 | var right = options.right; 70 | var timeConstant = options.timeConstant; 71 | 72 | var elapsed, delta; 73 | 74 | if (amplitude) { 75 | elapsed = getTime() - this._timestamp; 76 | delta = amplitude * Math.exp(-elapsed / timeConstant); 77 | 78 | var x = target - delta; 79 | // target stop range 80 | if (delta > 4 || delta < -4) { 81 | this.translate(target - delta); 82 | requestAnimationFrame(this.autoTranslate); 83 | }else{ 84 | // translate to ending position 85 | x = Math.round(x) - 5; 86 | this._opened = x <= left && x > right; 87 | this.translate(this._opened? left: right); 88 | } 89 | } 90 | }; 91 | 92 | Deleter.prototype.start = function (e) { 93 | 94 | this._state = 1; 95 | this._pre = pos(e); 96 | this._speed = this._amplitude = 0; 97 | this._frame = this._offset; 98 | this._timestamp = getTime(); 99 | 100 | clearInterval(this._ticker); 101 | this._ticker = setInterval(this.track, 100); 102 | }; 103 | 104 | Deleter.prototype.move = function (e) { 105 | 106 | if (this._state >= 1) { 107 | 108 | var cur = pos(e); 109 | var pre = this._pre; 110 | var deltaX = pre.x - cur.x; 111 | var deltaY = pre.y - cur.y; 112 | 113 | if ( (deltaX > 10 || deltaX < -10) && deltaY < 10 && deltaY > -10 ) { 114 | 115 | if(!this._opened && deltaX < -10){ 116 | this._state = 0; 117 | return; 118 | } 119 | // update pre position 120 | this._pre = cur; 121 | // update state 122 | this._state = deltaX > 0? 2: 3; 123 | // translate element 124 | this.translate(this._offset + deltaX); 125 | 126 | e.preventDefault(); 127 | e.stopPropagation(); 128 | return false; 129 | } 130 | } 131 | }; 132 | 133 | Deleter.prototype.end = function (e) { 134 | clearInterval(this._ticker); 135 | var state = this._state; 136 | 137 | if(state > 0){ 138 | 139 | var offset = this._offset; 140 | var speed = this._speed; 141 | var amplitude = this._amplitude; 142 | var target = offset; 143 | 144 | // compute target value 145 | if (speed > 10 || speed < -10) { 146 | amplitude = 1.2 * speed; 147 | target = offset + amplitude; 148 | } 149 | 150 | var snap = this.options.left; 151 | // tap or snap right 152 | if(this._opened && (state == 1 || state == 3)){ 153 | snap = this.options.right; 154 | } 155 | // snap value could be 0 156 | target = snap? (Math.round(target / snap) * snap) : 0; 157 | target = (target < -snap) ? -snap : (target > snap) ? snap : target; 158 | 159 | this._amplitude = target - offset; 160 | this._target = target; 161 | this._timestamp = getTime(); 162 | 163 | requestAnimationFrame(this.autoTranslate); 164 | } 165 | 166 | // reset state 167 | this._state = 0; 168 | }; 169 | 170 | $.Deleter = Deleter; 171 | 172 | $.fn.deletable = function(option){ 173 | 174 | return this.each(function(){ 175 | 176 | var $this = $(this); 177 | var data = $this.data('deleter'); 178 | var options = $.extend({}, Deleter.DEFAULTS, $this.data(), typeof option == 'object' && option); 179 | 180 | if (!data) { 181 | data = new Deleter(this, options) 182 | $this.data('deleter', data) 183 | } 184 | 185 | if (typeof option == 'string') data[option]() 186 | else if (options.init) data.init() 187 | 188 | }) 189 | } 190 | 191 | }); 192 | -------------------------------------------------------------------------------- /js/dialog.js: -------------------------------------------------------------------------------- 1 | define(['./os', './event', './data', './touch', './transition', './fixed'], function(){ 2 | 3 | var os = $.os; 4 | var showClass = 'js-show'; 5 | // why event without namespace? Zepto do not support trigger custom event with namespace like foo.bar . 6 | var showEvent = 'show:dialog'; 7 | var shownEvent = 'shown:dialog'; 8 | var hideEvent = 'hide:dialog'; 9 | var hiddenEvent = 'hidden:dialog'; 10 | 11 | var tapEvent = 'tap'; 12 | // Why not use tap event? We know click event has a 300+ delay, on iOS 5- this will trigger click event on backdrop. 13 | if(os.ios < 5){ 14 | tapEvent = "click"; 15 | } 16 | 17 | var dismissDialogEventName = tapEvent + '.dismiss.dialog'; 18 | 19 | function Dialog(element, options) { 20 | this.options = options; 21 | this.$element = $(element); 22 | this.$backdrop = 23 | this.isShown = null 24 | } 25 | 26 | Dialog.DEFAULTS = { 27 | backdrop: true, 28 | show: true, 29 | expires: 0 30 | }; 31 | 32 | Dialog.prototype.toggle = function (_relatedTarget) { 33 | return this[!this.isShown ? 'show' : 'hide'](_relatedTarget) 34 | }; 35 | 36 | Dialog.prototype.show = function (_relatedTarget) { 37 | var that = this; 38 | var e = $.Event(showEvent, { relatedTarget: _relatedTarget }); 39 | 40 | this.$element.trigger(e); 41 | 42 | if (this.isShown || e.isDefaultPrevented()) return; 43 | 44 | this.isShown = true; 45 | 46 | // killing the scroll on body 47 | $(document).on('touchmove.dialog', function(e){ 48 | return e.preventDefault(); 49 | }) 50 | 51 | this.$element.on( dismissDialogEventName, '[data-dismiss="dialog"]', $.proxy(this.hide, this)) 52 | 53 | this.backdrop(function () { 54 | var transition = $.support.transition && that.options.effect 55 | 56 | if (!that.$element.parent().length) { 57 | that.$element.appendTo(document.body); // don't move dialogs dom position 58 | } 59 | 60 | that.$element.show(); 61 | 62 | if (transition) { 63 | $(document.documentElement).addClass('js-effect-' + that.options.effect); 64 | that.$element[0].offsetWidth; // force reflow 65 | } 66 | 67 | that.$element 68 | .addClass(showClass) 69 | .attr('aria-hidden', false); 70 | 71 | var e = $.Event(shownEvent, { relatedTarget: _relatedTarget }); 72 | 73 | transition ? 74 | that.$element.find('.js-dialog-content') 75 | // wait for dialog to slide in 76 | .one($.support.transition.end, function () { 77 | that.$element.focus().trigger(e) 78 | }) 79 | .emulateTransitionEnd(300) : 80 | that.$element.focus().trigger(e) 81 | }) 82 | 83 | // auto expires 84 | if(Number(that.options.expires) > 0){ 85 | setTimeout($.proxy(that.hide, that), that.options.expires); 86 | } 87 | } 88 | 89 | Dialog.prototype.hide = function (e) { 90 | if (e && e.preventDefault) e.preventDefault(); 91 | 92 | e = $.Event(hideEvent); 93 | 94 | this.$element.trigger(e); 95 | 96 | if (!this.isShown || e.isDefaultPrevented()) return; 97 | 98 | this.isShown = false; 99 | 100 | $(document).off('touchmove.dialog'); 101 | 102 | this.$element 103 | .removeClass(showClass) 104 | .attr('aria-hidden', true) 105 | .off(dismissDialogEventName); 106 | 107 | $.support.transition && (this.options.effect) ? 108 | this.$element 109 | .one($.support.transition.end, $.proxy(this.hideDialog, this)) 110 | .emulateTransitionEnd(300) : 111 | this.hideDialog() 112 | }; 113 | 114 | Dialog.prototype.hideDialog = function () { 115 | var that = this; 116 | this.$element.hide(); 117 | this.backdrop(function () { 118 | that.removeBackdrop(); 119 | $(document.documentElement).removeClass('js-effect-' + that.options.effect); 120 | that.$element.trigger(hiddenEvent) 121 | }) 122 | }; 123 | 124 | Dialog.prototype.removeBackdrop = function () { 125 | this.$backdrop && this.$backdrop.remove(); 126 | this.$backdrop = null 127 | }; 128 | 129 | Dialog.prototype.backdrop = function (callback) { 130 | var animate = this.options.effect ? 'js-effect-fade' : ''; 131 | 132 | if (this.isShown && this.options.backdrop) { 133 | var doAnimate = $.support.transition && animate; 134 | 135 | this.$backdrop = $('
') 136 | .appendTo(this.$element.parent()) 137 | .emulateFixed(); 138 | 139 | this.$element.on(dismissDialogEventName, $.proxy(function (e) { 140 | if (e.target !== e.currentTarget) return; 141 | this.options.backdrop == 'static' 142 | ? this.$element[0].focus.call(this.$element[0]) 143 | : this.hide.call(this) 144 | }, this)); 145 | 146 | if (doAnimate) this.$backdrop[0].offsetWidth; // force reflow 147 | 148 | this.$backdrop.addClass(showClass); 149 | 150 | if (!callback) return; 151 | 152 | doAnimate ? 153 | this.$backdrop 154 | .one($.support.transition.end, callback) 155 | .emulateTransitionEnd(150) : 156 | callback() 157 | 158 | } else if (!this.isShown && this.$backdrop) { 159 | this.$backdrop.removeClass(showClass); 160 | 161 | $.support.transition && this.options.effect ? 162 | this.$backdrop 163 | .one($.support.transition.end, callback) 164 | .emulateTransitionEnd(150) : 165 | callback() 166 | 167 | } else if (callback) { 168 | callback() 169 | } 170 | }; 171 | 172 | $.Dialog = Dialog; 173 | 174 | $.fn.dialog = function (option, _relatedTarget) { 175 | return this.each(function () { 176 | var $this = $(this).emulateFixed(); 177 | 178 | var data = $this.data('dialog'); 179 | var options = $.extend({}, Dialog.DEFAULTS, $this.data(), typeof option == 'object' && option) 180 | 181 | if (!data) data = new Dialog(this, options); 182 | if (options.cache) $this.data('dialog', data); 183 | if (typeof option == 'string') data[option](_relatedTarget); 184 | else if (options.show) data.show(_relatedTarget) 185 | }) 186 | } 187 | 188 | $(document).on(tapEvent + '.dialog.data-api', '[data-toggle="dialog"]', function (e) { 189 | 190 | var $this = $(this); 191 | var $target = $($this.attr('data-target')); 192 | var option = $target.data('dialog') ? 'toggle' : $.extend({}, $target.data(), $this.data()); 193 | 194 | if ($this.is('a')) e.preventDefault(); 195 | 196 | $target.dialog(option, this) 197 | }) 198 | 199 | }); 200 | -------------------------------------------------------------------------------- /js/event.js: -------------------------------------------------------------------------------- 1 | define(['./zepto'], function(){ 2 | // Zepto.js 3 | // (c) 2010-2014 Thomas Fuchs 4 | // Zepto.js may be freely distributed under the MIT license. 5 | 6 | ;(function($){ 7 | var _zid = 1, undefined, 8 | slice = Array.prototype.slice, 9 | isFunction = $.isFunction, 10 | isString = function(obj){ return typeof obj == 'string' }, 11 | handlers = {}, 12 | specialEvents={}, 13 | focusinSupported = 'onfocusin' in window, 14 | focus = { focus: 'focusin', blur: 'focusout' }, 15 | hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' } 16 | 17 | specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents' 18 | 19 | function zid(element) { 20 | return element._zid || (element._zid = _zid++) 21 | } 22 | function findHandlers(element, event, fn, selector) { 23 | event = parse(event) 24 | if (event.ns) var matcher = matcherFor(event.ns) 25 | return (handlers[zid(element)] || []).filter(function(handler) { 26 | return handler 27 | && (!event.e || handler.e == event.e) 28 | && (!event.ns || matcher.test(handler.ns)) 29 | && (!fn || zid(handler.fn) === zid(fn)) 30 | && (!selector || handler.sel == selector) 31 | }) 32 | } 33 | function parse(event) { 34 | var parts = ('' + event).split('.') 35 | return {e: parts[0], ns: parts.slice(1).sort().join(' ')} 36 | } 37 | function matcherFor(ns) { 38 | return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)') 39 | } 40 | 41 | function eventCapture(handler, captureSetting) { 42 | return handler.del && 43 | (!focusinSupported && (handler.e in focus)) || 44 | !!captureSetting 45 | } 46 | 47 | function realEvent(type) { 48 | return hover[type] || (focusinSupported && focus[type]) || type 49 | } 50 | 51 | function add(element, events, fn, data, selector, delegator, capture){ 52 | var id = zid(element), set = (handlers[id] || (handlers[id] = [])) 53 | events.split(/\s/).forEach(function(event){ 54 | if (event == 'ready') return $(document).ready(fn) 55 | var handler = parse(event) 56 | handler.fn = fn 57 | handler.sel = selector 58 | // emulate mouseenter, mouseleave 59 | if (handler.e in hover) fn = function(e){ 60 | var related = e.relatedTarget 61 | if (!related || (related !== this && !$.contains(this, related))) 62 | return handler.fn.apply(this, arguments) 63 | } 64 | handler.del = delegator 65 | var callback = delegator || fn 66 | handler.proxy = function(e){ 67 | e = compatible(e) 68 | if (e.isImmediatePropagationStopped()) return 69 | e.data = data 70 | var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args)) 71 | if (result === false) e.preventDefault(), e.stopPropagation() 72 | return result 73 | } 74 | handler.i = set.length 75 | set.push(handler) 76 | if ('addEventListener' in element) 77 | element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) 78 | }) 79 | } 80 | function remove(element, events, fn, selector, capture){ 81 | var id = zid(element) 82 | ;(events || '').split(/\s/).forEach(function(event){ 83 | findHandlers(element, event, fn, selector).forEach(function(handler){ 84 | delete handlers[id][handler.i] 85 | if ('removeEventListener' in element) 86 | element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) 87 | }) 88 | }) 89 | } 90 | 91 | $.event = { add: add, remove: remove } 92 | 93 | $.proxy = function(fn, context) { 94 | if (isFunction(fn)) { 95 | var proxyFn = function(){ return fn.apply(context, arguments) } 96 | proxyFn._zid = zid(fn) 97 | return proxyFn 98 | } else if (isString(context)) { 99 | return $.proxy(fn[context], fn) 100 | } else { 101 | throw new TypeError("expected function") 102 | } 103 | } 104 | 105 | $.fn.bind = function(event, data, callback){ 106 | return this.on(event, data, callback) 107 | } 108 | $.fn.unbind = function(event, callback){ 109 | return this.off(event, callback) 110 | } 111 | $.fn.one = function(event, selector, data, callback){ 112 | return this.on(event, selector, data, callback, 1) 113 | } 114 | 115 | var returnTrue = function(){return true}, 116 | returnFalse = function(){return false}, 117 | ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$)/, 118 | eventMethods = { 119 | preventDefault: 'isDefaultPrevented', 120 | stopImmediatePropagation: 'isImmediatePropagationStopped', 121 | stopPropagation: 'isPropagationStopped' 122 | } 123 | 124 | function compatible(event, source) { 125 | if (source || !event.isDefaultPrevented) { 126 | source || (source = event) 127 | 128 | $.each(eventMethods, function(name, predicate) { 129 | var sourceMethod = source[name] 130 | event[name] = function(){ 131 | this[predicate] = returnTrue 132 | return sourceMethod && sourceMethod.apply(source, arguments) 133 | } 134 | event[predicate] = returnFalse 135 | }) 136 | 137 | if (source.defaultPrevented !== undefined ? source.defaultPrevented : 138 | 'returnValue' in source ? source.returnValue === false : 139 | source.getPreventDefault && source.getPreventDefault()) 140 | event.isDefaultPrevented = returnTrue 141 | } 142 | return event 143 | } 144 | 145 | function createProxy(event) { 146 | var key, proxy = { originalEvent: event } 147 | for (key in event) 148 | if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key] 149 | 150 | return compatible(proxy, event) 151 | } 152 | 153 | $.fn.delegate = function(selector, event, callback){ 154 | return this.on(event, selector, callback) 155 | } 156 | $.fn.undelegate = function(selector, event, callback){ 157 | return this.off(event, selector, callback) 158 | } 159 | 160 | $.fn.live = function(event, callback){ 161 | $(document.body).delegate(this.selector, event, callback) 162 | return this 163 | } 164 | $.fn.die = function(event, callback){ 165 | $(document.body).undelegate(this.selector, event, callback) 166 | return this 167 | } 168 | 169 | $.fn.on = function(event, selector, data, callback, one){ 170 | var autoRemove, delegator, $this = this 171 | if (event && !isString(event)) { 172 | $.each(event, function(type, fn){ 173 | $this.on(type, selector, data, fn, one) 174 | }) 175 | return $this 176 | } 177 | 178 | if (!isString(selector) && !isFunction(callback) && callback !== false) 179 | callback = data, data = selector, selector = undefined 180 | if (isFunction(data) || data === false) 181 | callback = data, data = undefined 182 | 183 | if (callback === false) callback = returnFalse 184 | 185 | return $this.each(function(_, element){ 186 | if (one) autoRemove = function(e){ 187 | remove(element, e.type, callback) 188 | return callback.apply(this, arguments) 189 | } 190 | 191 | if (selector) delegator = function(e){ 192 | var evt, match = $(e.target).closest(selector, element).get(0) 193 | if (match && match !== element) { 194 | evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element}) 195 | return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1))) 196 | } 197 | } 198 | 199 | add(element, event, callback, data, selector, delegator || autoRemove) 200 | }) 201 | } 202 | $.fn.off = function(event, selector, callback){ 203 | var $this = this 204 | if (event && !isString(event)) { 205 | $.each(event, function(type, fn){ 206 | $this.off(type, selector, fn) 207 | }) 208 | return $this 209 | } 210 | 211 | if (!isString(selector) && !isFunction(callback) && callback !== false) 212 | callback = selector, selector = undefined 213 | 214 | if (callback === false) callback = returnFalse 215 | 216 | return $this.each(function(){ 217 | remove(this, event, callback, selector) 218 | }) 219 | } 220 | 221 | $.fn.trigger = function(event, args){ 222 | event = (isString(event) || $.isPlainObject(event)) ? $.Event(event) : compatible(event) 223 | event._args = args 224 | return this.each(function(){ 225 | // items in the collection might not be DOM elements 226 | if('dispatchEvent' in this) this.dispatchEvent(event) 227 | else $(this).triggerHandler(event, args) 228 | }) 229 | } 230 | 231 | // triggers event handlers on current element just as if an event occurred, 232 | // doesn't trigger an actual event, doesn't bubble 233 | $.fn.triggerHandler = function(event, args){ 234 | var e, result 235 | this.each(function(i, element){ 236 | e = createProxy(isString(event) ? $.Event(event) : event) 237 | e._args = args 238 | e.target = element 239 | $.each(findHandlers(element, event.type || event), function(i, handler){ 240 | result = handler.proxy(e) 241 | if (e.isImmediatePropagationStopped()) return false 242 | }) 243 | }) 244 | return result 245 | } 246 | 247 | // shortcut methods for `.bind(event, fn)` for each event type 248 | ;('focusin focusout load resize scroll unload click dblclick '+ 249 | 'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave '+ 250 | 'change select keydown keypress keyup error').split(' ').forEach(function(event) { 251 | $.fn[event] = function(callback) { 252 | return callback ? 253 | this.bind(event, callback) : 254 | this.trigger(event) 255 | } 256 | }) 257 | 258 | ;['focus', 'blur'].forEach(function(name) { 259 | $.fn[name] = function(callback) { 260 | if (callback) this.bind(name, callback) 261 | else this.each(function(){ 262 | try { this[name]() } 263 | catch(e) {} 264 | }) 265 | return this 266 | } 267 | }) 268 | 269 | $.Event = function(type, props) { 270 | if (!isString(type)) props = type, type = props.type 271 | var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true 272 | if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name]) 273 | event.initEvent(type, bubbles, true) 274 | return compatible(event) 275 | } 276 | 277 | })(Zepto) 278 | 279 | }); 280 | -------------------------------------------------------------------------------- /js/fixed.js: -------------------------------------------------------------------------------- 1 | define(['./os', './event'], function(){ 2 | 3 | var os = $.os; 4 | // Why not use feature detecting? It's performance care and we already know only the iOS 4.3 not support fixed 5 | $.support.positionFixed = !(os.ios < 5); 6 | 7 | $.fn.emulateFixed = function (options) { 8 | var $this = $(this); 9 | if ($this.attr('isFixed') || $.support.positionFixed) return this; 10 | 11 | return this.each(function() { 12 | var $el = $(this); 13 | $el.attr('isFixed', true); 14 | 15 | var styles = $.extend($el.css(['top', 'left', 'bottom', 'right']), options || {}); 16 | $.each(styles, function(k, v) { 17 | styles[k] = parseFloat(v) 18 | }); 19 | 20 | function positionFixed() { 21 | var properties = { 22 | position: 'absolute' 23 | }; 24 | 25 | if(styles.left == 0 && styles.right == 0) { 26 | properties.left = 0; 27 | properties.width = '100%'; 28 | }else{ 29 | properties.left = isNaN(styles.right) ? (styles.left || 0): document.body.offsetWidth - $el.width() - styles.right; 30 | } 31 | 32 | if(styles.top === 0 && styles.bottom === 0) { 33 | properties.height = '100%'; 34 | } 35 | 36 | properties.top = window.pageYOffset + ( isNaN(styles.bottom) ? (styles.top || 0): window.innerHeight - $el.height() - styles.bottom ); 37 | 38 | $el.css(properties); 39 | } 40 | 41 | positionFixed(); 42 | // TODO: events debounce 43 | $(window).on('scroll.fixed', positionFixed); 44 | $(window).on('resize.fixed', positionFixed); 45 | }) 46 | }; 47 | 48 | // TODO: how to disable emulate fixed 49 | }); 50 | -------------------------------------------------------------------------------- /js/lazyload.js: -------------------------------------------------------------------------------- 1 | define(['./debounce', './event'], function () { 2 | // TODO: skip load invisible element 3 | var debounce = $.debounce; 4 | // cache computing rect avoid re-layout 5 | var cacheId = 0; 6 | var boudingClientRectCache = {}; 7 | 8 | function LazyLoad(elements, options) { 9 | this.elements = elements; 10 | this.options = options; 11 | this.handler = options.handler; 12 | this.container = options.container; 13 | this.$container = $(options.container); 14 | this.onScroll = debounce($.proxy(this.onScroll, this), options.defer, false); 15 | this.onResize = debounce($.proxy(this.onResize, this), options.defer, false) 16 | } 17 | 18 | LazyLoad.DEFAULTS = { 19 | start: true, 20 | attribute: 'data-lazy', 21 | defer: 300, 22 | handler: function (el, lazyData){ 23 | el.setAttribute("src", lazyData); 24 | }, 25 | container: window // container should with -webkit-overflow-scrolling: touch style 26 | }; 27 | 28 | LazyLoad.prototype = { 29 | start: function(){ 30 | this.status = 1; 31 | setTimeout(function(){ 32 | if(!this.inited){ 33 | this.inited = true; 34 | this.containerHeight = this.getContainerHeight(); 35 | $(window).on('resize', this.onResize); 36 | this.$container.on('scroll', this.onScroll); 37 | } 38 | 39 | this.onScroll(); 40 | }.bind(this), this.options.defer) 41 | }, 42 | 43 | add: function(elements){ 44 | elements = $(elements).get(); 45 | this.elements = this.elements.concat(elements) 46 | }, 47 | 48 | getContainerHeight: function(){ 49 | var container = this.container; 50 | // if container is window object 51 | if(container.document){ 52 | return window.innerHeight; 53 | }else{ 54 | var style = window.getComputedStyle(container); 55 | // that equal container.offsetHeight 56 | return parseInt(style.height) + parseInt(style.paddingTop) + parseInt(style.paddingBottom) + parseInt(style.marginTop) + parseInt(style.marginBottom); 57 | } 58 | }, 59 | 60 | onResize: function(evt){ 61 | if(!this.status) return; 62 | this.containerHeight = this.getContainerHeight(); 63 | boudingClientRectCache = {}; 64 | this.onScroll(); 65 | }, 66 | 67 | onScroll: function (evt){ 68 | if(!this.status) return; 69 | var elements = this.elements; 70 | var el; 71 | var lazyData; 72 | for(var i=0, l=elements.length; i< l; i++){ 73 | el = elements[i]; 74 | el.cacheId = el.cacheId || ++cacheId; 75 | if (el && this.elementInViewport(el)) { 76 | 77 | if(!(lazyData = el.lazyData)){ 78 | lazyData = el.getAttribute(this.options.attribute); 79 | // cache value 80 | el.lazyData = lazyData; 81 | } 82 | 83 | if (lazyData) this.handler(el, lazyData); 84 | elements.splice(i, 1, null); 85 | } 86 | } 87 | 88 | this.elements = elements.filter(function(v){return v}); 89 | }, 90 | 91 | elementInViewport: function (el) { 92 | var container = this.container; 93 | var id = el.cacheId; // cached by id 94 | var rect = boudingClientRectCache[id] || $(el).offset(); 95 | var scrollY = this.containerHeight; 96 | 97 | if(container.document){ 98 | scrollY += (container.scrollY || container.pageYOffset); 99 | }else{ 100 | scrollY += (container.scrollTop || window.scrollY ) + (container.offsetTop || window.pageYOffset); 101 | } 102 | 103 | boudingClientRectCache[id] = rect; 104 | return (rect.top >= 0 && rect.top <= scrollY ) || (rect.bottom >= 0 && rect.bottom <= scrollY); 105 | }, 106 | 107 | pause: function(){ 108 | this.status = 0 109 | }, 110 | 111 | destory: function(){ 112 | this.$container.off('scroll', this.onScroll); 113 | $(window).off('resize', this.onResize); 114 | boudingClientRectCache = {}; 115 | this.status = 0; 116 | this.elements = null; 117 | this.container = null; 118 | this.$container = null; 119 | } 120 | }; 121 | 122 | $.LazyLoad = LazyLoad; 123 | 124 | $.fn.lazyload = function(option) { 125 | var elements = this.get(); 126 | var options = $.extend({}, LazyLoad.DEFAULTS, typeof option == 'object' && option); 127 | 128 | var $container = $(options.container); 129 | // assume it's a origin node 130 | options.container = $container[0]; 131 | var data = $container.data('lazyload'); 132 | if (!data) { 133 | data = new LazyLoad(elements, options); 134 | $container.data('lazyload', data) 135 | } 136 | if (typeof option == 'string') data[option](); 137 | else if (options.start) data.start(); 138 | 139 | return data; 140 | }; 141 | }); 142 | -------------------------------------------------------------------------------- /js/os.js: -------------------------------------------------------------------------------- 1 | define(['./zepto'], function(){ 2 | var ua = navigator.userAgent.toLowerCase(); 3 | function platform (os){ 4 | var ver = ('' + (new RegExp(os + '(\\d+((\\.|_)\\d+)*)').exec(ua) || [,0])[1]).replace(/_/g, '.'); 5 | // undefined < 3 === false, but null < 3 === true 6 | return parseFloat(ver) || undefined; 7 | } 8 | 9 | $.os = { 10 | // iPad UA contains 'cpu os', and iPod/iPhone UA contains 'iphone os' 11 | ios: platform('os '), 12 | // WTF? ZTE UserAgent: ZTEU880E_TD/1.0 Linux/2.6.35 Android/2.3 Release/12.15.2011 Browser/AppleWebKit533.1 FlyFlow/2.4 baidubrowser/042_1.8.4.2_dio 13 | android: platform('android[/ ]') 14 | }; 15 | }); 16 | -------------------------------------------------------------------------------- /js/pro.js: -------------------------------------------------------------------------------- 1 | define([ 2 | './scrollfix', 3 | './tab', 4 | './dialog', 5 | './spinner', 6 | './carousel', 7 | './lazyload', 8 | './countable', 9 | './deletable' 10 | ],function () { 11 | return $; 12 | }); 13 | -------------------------------------------------------------------------------- /js/requestAnimationFrame.js: -------------------------------------------------------------------------------- 1 | define(function(){ 2 | // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ 3 | // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating 4 | 5 | // requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel 6 | 7 | // MIT license 8 | (function() { 9 | var lastTime = 0; 10 | var vendors = ['ms', 'moz', 'webkit', 'o']; 11 | for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { 12 | window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; 13 | window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] 14 | || window[vendors[x]+'CancelRequestAnimationFrame']; 15 | } 16 | 17 | if (!window.requestAnimationFrame) 18 | window.requestAnimationFrame = function(callback, element) { 19 | var currTime = new Date().getTime(); 20 | var timeToCall = Math.max(0, 16 - (currTime - lastTime)); 21 | var id = window.setTimeout(function() { callback(currTime + timeToCall); }, 22 | timeToCall); 23 | lastTime = currTime + timeToCall; 24 | return id; 25 | }; 26 | 27 | if (!window.cancelAnimationFrame) 28 | window.cancelAnimationFrame = function(id) { 29 | clearTimeout(id); 30 | }; 31 | }()); 32 | }); 33 | 34 | -------------------------------------------------------------------------------- /js/scrollfix.js: -------------------------------------------------------------------------------- 1 | // https://developers.google.com/mobile/articles/webapp_fixed_ui 2 | // https://github.com/filamentgroup/Overthrow/ 3 | // http://bradfrostweb.com/blog/mobile/fixed-position/ 4 | 5 | define(['./os', './event'], function(){ 6 | 7 | var os = $.os; 8 | function scrollFix() { 9 | 10 | $('.js-no-bounce').on('touchmove', function(event){ 11 | event.preventDefault(); 12 | }); 13 | 14 | var $page = $('.ui-page'); 15 | var $content = $('.ui-page-content', $page); 16 | if(!$content[0] || !$page[0]) return; 17 | 18 | // Variables to track inputs 19 | var startTopScroll; 20 | 21 | // Handle the start of interactions 22 | $(document).on('touchstart', '.ui-page', function(event){ 23 | var page = event.currentTarget; 24 | startTopScroll = page.scrollTop; 25 | 26 | if(startTopScroll <= 0) 27 | page.scrollTop = 1; 28 | 29 | if(startTopScroll + page.offsetHeight >= page.scrollHeight) 30 | page.scrollTop = page.scrollHeight - page.offsetHeight - 1; 31 | 32 | }).on('touchmove', '.ui-page', function(event){ 33 | var page = event.currentTarget; 34 | // TODO cache element select 35 | var content = page.querySelector('.ui-page-content'); 36 | // Offset value have include content and border 37 | if( content.offsetHeight < page.clientHeight || 38 | content.offsetWidth < page.clientWidth){ 39 | // your element have overflow 40 | return event.preventDefault(); 41 | } 42 | }) 43 | } 44 | 45 | // Add ScrollFix only for iOS 46 | if(os.ios >= 5 ) { 47 | scrollFix(); 48 | }else{ 49 | var html = document.documentElement; 50 | html.className = html.className + ' ' + 'js-no-overflow-scrolling'; 51 | } 52 | }); 53 | -------------------------------------------------------------------------------- /js/spinner.js: -------------------------------------------------------------------------------- 1 | define(['./event', './data'], function(){ 2 | 3 | var animations = {}; /* Cache animation rules */ 4 | var prefix = '-webkit-'; 5 | var ratio = window.devicePixelRatio || 1; 6 | /** 7 | * Insert a new stylesheet to hold the @keyframe rules. 8 | */ 9 | var sheet = (function() { 10 | var $el = $('