├── .gitignore ├── .jshintrc ├── .nojekyll ├── .travis.yml ├── Gruntfile.js ├── LICENSE ├── README.md ├── css ├── boot.less ├── github.less ├── home.less ├── issuelist.less ├── issues.less ├── labels.less ├── main.less ├── markdown.less ├── menu.less ├── normalize.less ├── pull2refresh.less └── side.less ├── dev.html ├── dist ├── main.min.css └── main.min.js ├── favicon.ico ├── img ├── apple-touch-icon-114x114.png ├── apple-touch-icon-144x144.png ├── apple-touch-startup-image-320x460.png ├── apple-touch-startup-image-640x1096.png ├── apple-touch-startup-image-640x1096.png.png └── apple-touch-startup-image-640x920.png ├── index.html ├── js ├── boot.js ├── home.js ├── issuelist.js ├── issues.js ├── labels.js ├── lib │ ├── detect.js │ ├── highlight.js │ ├── less.js │ ├── marked.js │ ├── spa.js │ ├── template.js │ ├── touch.js │ └── zepto.js ├── menu.js ├── pull2refresh.js └── side.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea/ 3 | .ipr 4 | .iws 5 | *~ 6 | ~* 7 | *.diff 8 | *.patch 9 | *.bak 10 | .DS_Store 11 | Thumbs.db 12 | .svn/ 13 | *.swp 14 | .project 15 | .settings/ 16 | node_modules/ 17 | _site/ 18 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi" : true, 3 | "boss" : true, 4 | "browser" : true, 5 | "curly" : false, 6 | "debug" : true, 7 | "devel" : true, 8 | "eqeqeq" : false, 9 | "eqnull" : true, 10 | "expr" : true, 11 | "laxbreak" : true, 12 | "laxcomma" : true, 13 | "validthis": true, 14 | "multistr" : true 15 | } -------------------------------------------------------------------------------- /.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoda/spring/281a4481ea5b7c8a2e36e9c614f758b737868b95/.nojekyll -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.10 4 | before_script: 5 | - npm install -g grunt-cli -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 'use strict'; 3 | 4 | // Project configuration. 5 | grunt.initConfig({ 6 | 7 | // Task configuration. 8 | jshint: { 9 | options: { 10 | jshintrc: '.jshintrc' 11 | }, 12 | gruntfile: { 13 | src: 'Gruntfile.js' 14 | }, 15 | build: { 16 | src: 'js/*.js' 17 | } 18 | }, 19 | 20 | concat: { 21 | js: { 22 | options: { 23 | separator: ';' 24 | }, 25 | src: [ 26 | 'js/lib/zepto.js', 27 | 'js/lib/detect.js', 28 | 'js/lib/touch.js', 29 | 'js/lib/spa.js', 30 | 'js/lib/template.js', 31 | 'js/lib/marked.js', 32 | 'js/lib/highlight.js', 33 | 'js/boot.js', 34 | 'js/pull2refresh.js', 35 | 'js/issuelist.js', 36 | 'js/side.js', 37 | 'js/menu.js', 38 | 'js/home.js', 39 | 'js/labels.js', 40 | 'js/issues.js' 41 | ], 42 | dest: 'dist/main.js' 43 | } 44 | }, 45 | 46 | uglify: { 47 | js: { 48 | files: { 49 | 'dist/main.min.js': 'dist/main.js' 50 | } 51 | } 52 | }, 53 | 54 | less: { 55 | production: { 56 | options: { 57 | cleancss: true 58 | }, 59 | files: { 60 | 'dist/main.min.css': 'css/boot.less' 61 | } 62 | } 63 | }, 64 | 65 | clean: { 66 | temporary: ['dist/main.js', 'dest/main.min.css'] 67 | } 68 | 69 | }) 70 | 71 | // These plugins provide necessary tasks. 72 | grunt.loadNpmTasks('grunt-contrib-concat') 73 | grunt.loadNpmTasks('grunt-contrib-jshint') 74 | grunt.loadNpmTasks('grunt-contrib-uglify') 75 | grunt.loadNpmTasks('grunt-contrib-less') 76 | grunt.loadNpmTasks('grunt-contrib-clean') 77 | 78 | 79 | // Default task. 80 | grunt.registerTask( 81 | 'default', 82 | [ 83 | 'jshint', 84 | 'concat', 85 | 'uglify', 86 | 'less', 87 | 'clean' 88 | ]) 89 | 90 | // // Test task. 91 | grunt.registerTask('test', ['jshint']) 92 | 93 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 zhaoda(赵达) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spring [![Build Status](https://img.shields.io/travis/zhaoda/spring.svg)](https://travis-ci.org/zhaoda/spring) 2 | 3 | Spring is a blog engine written by GitHub Issues, or is a simple, static web site generator. No more server and database, you can setup it in free hosting with GitHub Pages as a repository, then post the blogs in the repository Issues. 4 | 5 | You can add some labels in your repository Issues as the blog category, and create Issues for writing blog content through Markdown. 6 | 7 | Spring has responsive templates, looking good on mobile, tablet, and desktop.Gracefully degrading in older browsers. Compatible with Internet Explorer 10+ and all modern browsers. 8 | 9 | Get up and running in seconds. 10 | 11 | [中文介绍](http://zhaoda.net/2014/03/21/%E4%BD%BF%E7%94%A8Spring%E5%BF%AB%E9%80%9F%E6%90%AD%E5%BB%BA%E5%8D%9A%E5%AE%A2.html) 12 | 13 | ## Quick start guide 14 | 15 | For the impatient, here's how to get a Spring blog site up and running. 16 | 17 | ### First of all 18 | 19 | * Fork the [Spring](https://github.com/zhaoda/spring "Spring") repository as yours. 20 | * Goto your repository settings page to rename `Repository Name`. 21 | * Hosted directly on [GitHub Pages](http://pages.github.com "GitHub Pages") from your project repository, you can take it as *User or organization site* or *Project site(create a gh-pages branch)*. 22 | * Also, you can [set up a custom domain with Pages](https://help.github.com/articles/setting-up-a-custom-domain-with-pages). 23 | 24 | ### Secondly 25 | 26 | * Open the `index.html` file to edit the config variables with yours below. 27 | 28 | ```javascript 29 | $.extend(spring.config, { 30 | // my blog title 31 | title: 'Spring', 32 | // my blog description 33 | desc: "A blog engine written by github issues [Fork me on GitHub](https://github.com/zhaoda/spring)", 34 | // my github username 35 | owner: 'zhaoda', 36 | // creator's username 37 | creator: 'zhaoda', 38 | // the repository name on github for writting issues 39 | repo: 'spring', 40 | // custom page 41 | pages: [ 42 | ] 43 | }) 44 | ``` 45 | * Put your domain into the `CNAME ` file if you have. 46 | * Commit your change and push it. 47 | 48 | ### And then 49 | 50 | * Goto your repository settings page to turn on the `Issues` feature. 51 | * Browser this repository's issues page, like this `https://github.com/your-username/your-repo-name/issues?state=open`. 52 | * Click the `New Issue` button to just write some content as a new one blog. 53 | 54 | ### Finally 55 | 56 | * Browser this repository's GitHub Pages url, like this `http://your-username.github.io/your-repo-name`, you will see your Spring blog, have a test. 57 | * And you're done! 58 | 59 | ## Custom development 60 | 61 | ### Installation 62 | 63 | * You will need a web server installed on your system, for example, Nginx, Apache etc. 64 | * Configure your spring project to your local web server directory. 65 | * Run and browser it, like `http://localhost/spring/dev.html` . 66 | * `dev.html` is used to develop, `index.html` is used to runtime. 67 | 68 | ### Folder Structure 69 | 70 | ```bash 71 | spring/ 72 | ├── css/ 73 | | ├── boot.less #import other less files 74 | | ├── github.less #github highlight style 75 | | ├── home.less #home page style 76 | | ├── issuelist.less #issue list widget style 77 | | ├── issues.less #issues page style 78 | | ├── labels.less #labels page style 79 | | ├── main.less #commo style 80 | | ├── markdown.less #markdown format style 81 | | ├── menu.less #menu panel style 82 | | ├── normalize.less #normalize style 83 | | ├── pull2refresh.less #pull2refresh widget style 84 | | └── side.html #side panel style 85 | ├── dist/ 86 | | ├── main.min.css #css for runtime 87 | | └── main.min.js #js for runtime 88 | ├── img/ #some icon, startup images 89 | ├── js/ 90 | | ├── lib/ #some js librarys need to use 91 | | ├── boot.js #boot 92 | | ├── home.js #home page 93 | | ├── issuelist.js #issue list widget 94 | | ├── issues.js #issues page 95 | | ├── labels.js #labels page 96 | | ├── menu.js #menu panel 97 | | ├── pull2refresh.less #pull2refresh widget 98 | | └── side.html #side panel 99 | ├── css/ 100 | | ├── boot.less #import other less files 101 | | ├── github.less #github highlight style 102 | | ├── home.less #home page style 103 | | ├── issuelist.less #issue list widget style 104 | | ├── issues.less #issues page style 105 | | ├── labels.less #labels page style 106 | | ├── main.less #commo style 107 | | ├── markdown.less #markdown format style 108 | | ├── menu.less #menu panel style 109 | | ├── normalize.less #normalize style 110 | | ├── pull2refresh.less #pull2refresh widget style 111 | | └── side.html #side panel style 112 | ├── dev.html #used to develop 113 | ├── favicon.ico #website icon 114 | ├── Gruntfile.js #Grunt task config 115 | ├── index.html #used to runtime 116 | └── package.json #nodejs install config 117 | ``` 118 | 119 | ### Customization 120 | 121 | * Browser `http://localhost/spring/dev.html`, enter the development mode. 122 | * Changes you want to modify the source code, like `css`, `js` etc. 123 | * Refresh `dev.html` view change. 124 | 125 | ### Building 126 | 127 | * You will need [Node.js](http://nodejs.org/ "Node.js") installed on your system. 128 | * Installation package. 129 | 130 | ```bash 131 | $ npm install 132 | ``` 133 | * Run grunt task. 134 | 135 | ```bash 136 | $ grunt 137 | ``` 138 | * Browser `http://localhost/spring/index.html`, enter the runtime mode. 139 | * If there is no problem, commit and push the code. 140 | * Don't forget to merge `master` branch into `gh-pages` branch if you have. 141 | * And you're done! Good luck! 142 | 143 | ## Report a bug 144 | 145 | * Check if the bug is already fixed in the [master branch](https://github.com/zhaoda/spring/commits/master) since the last release. 146 | * Check [existing issues](https://github.com/zhaoda/spring/issues). 147 | * [Open a new one](https://github.com/zhaoda/spring/issues/new), including exact browser & platform information. 148 | 149 | ## Who used 150 | 151 | * http://zhaoda.net/spring 152 | * http://zhaoda.net/blog 153 | 154 | If you are using, please [tell me](https://github.com/zhaoda/spring/issues/6). 155 | 156 | ## License 157 | 158 | Spring is available under the terms of the [MIT License](https://raw.githubusercontent.com/zhaoda/spring/master/LICENSE "MIT License") 159 | 160 | -------------------------------------------------------------------------------- /css/boot.less: -------------------------------------------------------------------------------- 1 | @import "normalize"; 2 | @import "github"; 3 | @import "main"; 4 | @import "markdown"; 5 | @import "pull2refresh"; 6 | @import "issuelist"; 7 | @import "side"; 8 | @import "menu"; 9 | @import "home"; 10 | @import "labels"; 11 | @import "issues"; -------------------------------------------------------------------------------- /css/github.less: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | github.com style (c) Vasily Polovnyov 4 | 5 | */ 6 | 7 | .hljs { 8 | display: block; padding: 0.5em; 9 | color: #333; 10 | background: #f8f8f8 11 | } 12 | 13 | .hljs-comment, 14 | .hljs-template_comment, 15 | .diff .hljs-header, 16 | .hljs-javadoc { 17 | color: #998; 18 | font-style: italic 19 | } 20 | 21 | .hljs-keyword, 22 | .css .rule .hljs-keyword, 23 | .hljs-winutils, 24 | .javascript .hljs-title, 25 | .nginx .hljs-title, 26 | .hljs-subst, 27 | .hljs-request, 28 | .hljs-status { 29 | color: #333; 30 | font-weight: bold 31 | } 32 | 33 | .hljs-number, 34 | .hljs-hexcolor, 35 | .ruby .hljs-constant { 36 | color: #099; 37 | } 38 | 39 | .hljs-string, 40 | .hljs-tag .hljs-value, 41 | .hljs-phpdoc, 42 | .tex .hljs-formula { 43 | color: #d14 44 | } 45 | 46 | .hljs-title, 47 | .hljs-id, 48 | .coffeescript .hljs-params, 49 | .scss .hljs-preprocessor { 50 | color: #900; 51 | font-weight: bold 52 | } 53 | 54 | .javascript .hljs-title, 55 | .lisp .hljs-title, 56 | .clojure .hljs-title, 57 | .hljs-subst { 58 | font-weight: normal 59 | } 60 | 61 | .hljs-class .hljs-title, 62 | .haskell .hljs-type, 63 | .vhdl .hljs-literal, 64 | .tex .hljs-command { 65 | color: #458; 66 | font-weight: bold 67 | } 68 | 69 | .hljs-tag, 70 | .hljs-tag .hljs-title, 71 | .hljs-rules .hljs-property, 72 | .django .hljs-tag .hljs-keyword { 73 | color: #000080; 74 | font-weight: normal 75 | } 76 | 77 | .hljs-attribute, 78 | .hljs-variable, 79 | .lisp .hljs-body { 80 | color: #008080 81 | } 82 | 83 | .hljs-regexp { 84 | color: #009926 85 | } 86 | 87 | .hljs-symbol, 88 | .ruby .hljs-symbol .hljs-string, 89 | .lisp .hljs-keyword, 90 | .tex .hljs-special, 91 | .hljs-prompt { 92 | color: #990073 93 | } 94 | 95 | .hljs-built_in, 96 | .lisp .hljs-title, 97 | .clojure .hljs-built_in { 98 | color: #0086b3 99 | } 100 | 101 | .hljs-preprocessor, 102 | .hljs-pragma, 103 | .hljs-pi, 104 | .hljs-doctype, 105 | .hljs-shebang, 106 | .hljs-cdata { 107 | color: #999; 108 | font-weight: bold 109 | } 110 | 111 | .hljs-deletion { 112 | background: #fdd 113 | } 114 | 115 | .hljs-addition { 116 | background: #dfd 117 | } 118 | 119 | .diff .hljs-change { 120 | background: #0086b3 121 | } 122 | 123 | .hljs-chunk { 124 | color: #aaa 125 | } 126 | -------------------------------------------------------------------------------- /css/home.less: -------------------------------------------------------------------------------- 1 | .spa-page-home { 2 | .container { 3 | top: 3em; 4 | 5 | @media screen and (min-width: @screen-tablet) { 6 | top: 0; 7 | 8 | .desc { 9 | display: none; 10 | } 11 | } 12 | 13 | .container-inner { 14 | 15 | @media screen and (min-width: @screen-tablet) { 16 | margin-left: 16em; 17 | } 18 | 19 | @media screen and (min-width: @screen-desktop) { 20 | margin-left: 18em; 21 | margin-right: 1em; 22 | } 23 | 24 | @media screen and (min-width: @screen-large) { 25 | margin-left: 24em; 26 | max-width: 52em; 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /css/issuelist.less: -------------------------------------------------------------------------------- 1 | .issuelist { 2 | position: relative; 3 | 4 | article { 5 | margin: 0 10px; 6 | padding: 20px 0 10px; 7 | box-shadow: 0 1px 0 @lighter; 8 | 9 | span.date { 10 | display: block; 11 | padding: 0 0 5px 0; 12 | color: @light; 13 | font-size: 0.75em; 14 | font-weight: 200; 15 | 16 | @media screen and (min-width: @screen-small) { 17 | font-size: 1em; 18 | } 19 | } 20 | 21 | h3 { 22 | margin: 0; 23 | font-weight: normal; 24 | 25 | @media screen and (min-width: @screen-small) { 26 | font-size: 2em; 27 | } 28 | 29 | @media screen and (min-width: @screen-desktop) { 30 | font-size: 2.5em; 31 | } 32 | 33 | a { 34 | display: block; 35 | } 36 | } 37 | 38 | p.tag { 39 | margin: 0; 40 | padding: 5px 0; 41 | font-size: 0.75em; 42 | 43 | @media screen and (min-width: @screen-small) { 44 | font-size: 1em; 45 | } 46 | 47 | a { 48 | display: inline-block; 49 | margin-right: 5px; 50 | padding: 2px 5px; 51 | font-weight: 200; 52 | color: #fff; 53 | .border-radius(4px); 54 | background: @lighter; 55 | } 56 | } 57 | } 58 | 59 | .end { 60 | padding: 10px 0; 61 | text-align: center; 62 | color: @light; 63 | font-weight: 100; 64 | } 65 | } -------------------------------------------------------------------------------- /css/issues.less: -------------------------------------------------------------------------------- 1 | .spa-page-issues { 2 | header { 3 | .btn-back { 4 | display: block; 5 | } 6 | } 7 | 8 | .container { 9 | top: 3em; 10 | 11 | @media screen and (min-width: @screen-tablet) { 12 | top: 0; 13 | } 14 | 15 | .container-inner { 16 | @media screen and (min-width: @screen-tablet) { 17 | margin-left: 16em; 18 | } 19 | 20 | @media screen and (min-width: @screen-desktop) { 21 | margin-left: 18em; 22 | margin-right: 1em; 23 | } 24 | 25 | @media screen and (min-width: @screen-large) { 26 | margin-left: 24em; 27 | max-width: 52em; 28 | } 29 | } 30 | } 31 | 32 | .btn-back { 33 | display: none; 34 | 35 | @media screen and (min-width: @screen-tablet) { 36 | display: block; 37 | position: fixed; 38 | top: 10px; 39 | right: 10px; 40 | z-index: 2; 41 | .opacity(0.8); 42 | } 43 | 44 | @media screen and (min-width: @screen-large) { 45 | left: 72em; 46 | top: 20px; 47 | right: auto; 48 | } 49 | } 50 | 51 | .btn-menu { 52 | display: none; 53 | } 54 | 55 | .issues { 56 | position: relative; 57 | 58 | .desc { 59 | text-align: center; 60 | } 61 | 62 | .title { 63 | padding: 0 10px; 64 | font-weight: normal; 65 | text-align: center; 66 | margin-bottom: 0.2em; 67 | 68 | @media screen and (min-width: @screen-desktop) { 69 | font-size: 2.5em; 70 | } 71 | } 72 | 73 | article { 74 | video { 75 | max-width: 100%; 76 | } 77 | 78 | @media screen and (min-width: @screen-small) { 79 | font-size: 1em; 80 | 81 | pre { 82 | font-size: 0.8em; 83 | } 84 | } 85 | 86 | @media screen and (min-width: @screen-desktop) { 87 | font-size: 1.2em; 88 | } 89 | 90 | .btn-view { 91 | display: block; 92 | width: 100%; 93 | padding: 0.5em 0; 94 | text-align: center; 95 | font-weight: 200; 96 | .border-radius(4px); 97 | color: @light; 98 | background: @lighter; 99 | text-decoration: none; 100 | } 101 | } 102 | 103 | } 104 | 105 | } -------------------------------------------------------------------------------- /css/labels.less: -------------------------------------------------------------------------------- 1 | .spa-page-labels { 2 | .container { 3 | top: 3em; 4 | 5 | @media screen and (min-width: @screen-tablet) { 6 | top: 0; 7 | } 8 | 9 | .container-inner { 10 | @media screen and (min-width: @screen-tablet) { 11 | margin-left: 16em; 12 | } 13 | 14 | @media screen and (min-width: @screen-desktop) { 15 | margin-left: 18em; 16 | margin-right: 1em; 17 | } 18 | 19 | @media screen and (min-width: @screen-large) { 20 | margin-left: 24em; 21 | max-width: 52em; 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /css/main.less: -------------------------------------------------------------------------------- 1 | @dark: #34495E; 2 | @darker: #2C3E50; 3 | @grey: #95A5A6; 4 | @greyer: #7F8C8D; 5 | @light: #BDC3C7; 6 | @lighter: #ECF0F1; 7 | @black: #000; 8 | @white: #FFF; 9 | 10 | @blue: #3498DB; 11 | @orange: #F39C12; 12 | 13 | @screen-small: 37.5em; 14 | @screen-tablet: 48em; 15 | @screen-desktop: 62em; 16 | @screen-large: 75em; 17 | 18 | .rotate (@rotate: 0deg) { 19 | -webkit-transform: rotate(@rotate); 20 | -moz-transform: rotate(@rotate); 21 | -ms-transform: rotate(@rotate); 22 | -o-transform: rotate(@rotate); 23 | transform: rotate(@rotate); 24 | } 25 | 26 | .box-shadow (@string) { 27 | -webkit-box-shadow: @string; 28 | -moz-box-shadow: @string; 29 | box-shadow: @string; 30 | } 31 | 32 | .border-radius (@radius: 5px) { 33 | -webkit-border-radius: @radius; 34 | -moz-border-radius: @radius; 35 | border-radius: @radius; 36 | 37 | -moz-background-clip: padding; 38 | -webkit-background-clip: padding-box; 39 | background-clip: padding-box; 40 | } 41 | 42 | .opacity (@opacity: 0.5) { 43 | -webkit-opacity: @opacity; 44 | -moz-opacity: @opacity; 45 | opacity: @opacity; 46 | } 47 | 48 | html { 49 | color: @darker; 50 | font-size: 1em; 51 | line-height: 1.4; 52 | 53 | @media screen and (max-width: @screen-tablet) { 54 | -webkit-user-select: none; 55 | user-select: none; 56 | } 57 | } 58 | 59 | body { 60 | font-family: "Helvetica Neue", Helvetica, STHeiTi, sans-serif; 61 | 62 | @media screen and (max-width: @screen-tablet) { 63 | -webkit-user-select: none; 64 | user-select: none; 65 | } 66 | } 67 | 68 | ::-moz-selection { 69 | background: #b3d4fc; 70 | text-shadow: none; 71 | } 72 | 73 | ::selection { 74 | background: #b3d4fc; 75 | text-shadow: none; 76 | } 77 | 78 | hr { 79 | display: block; 80 | height: 1px; 81 | border: 0; 82 | border-top: 1px solid #ccc; 83 | margin: 1em 0; 84 | padding: 0; 85 | } 86 | 87 | audio, 88 | canvas, 89 | img, 90 | svg, 91 | video { 92 | vertical-align: middle; 93 | } 94 | 95 | fieldset { 96 | border: 0; 97 | margin: 0; 98 | padding: 0; 99 | } 100 | 101 | textarea { 102 | resize: vertical; 103 | } 104 | 105 | .visuallyhidden { 106 | border: 0; 107 | clip: rect(0 0 0 0); 108 | height: 1px; 109 | margin: -1px; 110 | overflow: hidden; 111 | padding: 0; 112 | position: absolute; 113 | width: 1px; 114 | } 115 | 116 | .visuallyhidden { 117 | &.focusable { 118 | &:active, &:focus { 119 | clip: auto; 120 | height: auto; 121 | margin: 0; 122 | overflow: visible; 123 | position: static; 124 | width: auto; 125 | } 126 | } 127 | } 128 | 129 | .invisible { 130 | visibility: hidden; 131 | } 132 | 133 | .clearfix { 134 | &:before, &:after { 135 | content: " "; 136 | display: table; 137 | } 138 | &:after { 139 | clear: both; 140 | } 141 | } 142 | 143 | a { 144 | color: @dark; 145 | text-decoration: none; 146 | -webkit-touch-callout: none; 147 | 148 | &:hover, &:active { 149 | color: @dark; 150 | text-decoration: none; 151 | } 152 | } 153 | 154 | .hidden { 155 | display: none !important; 156 | visibility: hidden; 157 | } 158 | 159 | .container { 160 | position: absolute; 161 | top: 0; 162 | right: 0; 163 | bottom: 0; 164 | left: 0; 165 | background: #fff; 166 | 167 | .desc { 168 | color: @greyer; 169 | .box-shadow(0 0 1px @light); 170 | 171 | @media screen and (min-width: @screen-small) { 172 | font-size: 1em; 173 | } 174 | } 175 | 176 | .container-inner { 177 | min-height: 100%; 178 | margin: 0 0 2px 0; 179 | overflow: hidden; 180 | } 181 | 182 | } 183 | 184 | header { 185 | position: absolute; 186 | left: 0; 187 | top: 0; 188 | width: 100%; 189 | height: 3em; 190 | overflow: hidden; 191 | z-index: 1; 192 | background: @dark; 193 | color: @lighter; 194 | 195 | @media screen and (min-width: @screen-tablet) { 196 | display: none; 197 | } 198 | 199 | h1 { 200 | position: absolute; 201 | left: 50%; 202 | top: 0.6em; 203 | margin: 0; 204 | font-size: 1em; 205 | font-weight: 200; 206 | 207 | span { 208 | display: block; 209 | max-width: 8em; 210 | margin-left: -50%; 211 | margin-right: 50%; 212 | font-size: 1.4em; 213 | overflow: hidden; 214 | } 215 | } 216 | 217 | } 218 | 219 | .btn-menu, .btn-back { 220 | float: left; 221 | font-weight: 200; 222 | margin: 0.65em; 223 | padding: 0.2em; 224 | background: @lighter; 225 | .border-radius(3px); 226 | } 227 | -------------------------------------------------------------------------------- /css/markdown.less: -------------------------------------------------------------------------------- 1 | .markdown { 2 | font-family: Helvetica, arial, sans-serif; 3 | font-size: 14px; 4 | line-height: 1.6; 5 | padding: 10px; 6 | 7 | > *:first-child { 8 | margin-top: 0 !important; 9 | } 10 | > *:last-child { 11 | margin-bottom: 0 !important; 12 | } 13 | 14 | a { 15 | color: @blue; 16 | text-decoration: underline; 17 | } 18 | a.absent { 19 | color: #cc0000; 20 | } 21 | a.anchor { 22 | display: block; 23 | padding-left: 30px; 24 | margin-left: -30px; 25 | cursor: pointer; 26 | position: absolute; 27 | top: 0; 28 | left: 0; 29 | bottom: 0; 30 | } 31 | 32 | h1, h2, h3, h4, h5, h6 { 33 | margin: 20px 0 10px; 34 | padding: 0; 35 | font-weight: bold; 36 | -webkit-font-smoothing: antialiased; 37 | cursor: text; 38 | position: relative; } 39 | 40 | h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor { 41 | text-decoration: none; } 42 | 43 | h1 tt, h1 code { 44 | font-size: inherit; } 45 | 46 | h2 tt, h2 code { 47 | font-size: inherit; } 48 | 49 | h3 tt, h3 code { 50 | font-size: inherit; } 51 | 52 | h4 tt, h4 code { 53 | font-size: inherit; } 54 | 55 | h5 tt, h5 code { 56 | font-size: inherit; } 57 | 58 | h6 tt, h6 code { 59 | font-size: inherit; } 60 | 61 | h1 { 62 | font-size: 28px; 63 | color: black; } 64 | 65 | h2 { 66 | font-size: 24px; 67 | border-bottom: 1px solid #cccccc; 68 | color: black; } 69 | 70 | h3 { 71 | font-size: 18px; } 72 | 73 | h4 { 74 | font-size: 16px; } 75 | 76 | h5 { 77 | font-size: 14px; } 78 | 79 | h6 { 80 | color: #777777; 81 | font-size: 14px; } 82 | 83 | p, blockquote, ul, ol, dl, li, table, pre { 84 | margin: 15px 0; } 85 | 86 | hr { 87 | border: 0 none; 88 | color: #cccccc; 89 | height: 4px; 90 | padding: 0; 91 | } 92 | 93 | > h2:first-child { 94 | margin-top: 0; 95 | padding-top: 0; } 96 | > h1:first-child { 97 | margin-top: 0; 98 | padding-top: 0; } 99 | > h1:first-child + h2 { 100 | margin-top: 0; 101 | padding-top: 0; } 102 | > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child { 103 | margin-top: 0; 104 | padding-top: 0; } 105 | 106 | a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 { 107 | margin-top: 0; 108 | padding-top: 0; } 109 | 110 | h1 p, h2 p, h3 p, h4 p, h5 p, h6 p { 111 | margin-top: 0; } 112 | 113 | li p.first { 114 | display: inline-block; } 115 | li { 116 | margin: 0; } 117 | ul, ol { 118 | padding-left: 30px; } 119 | 120 | ul :first-child, ol :first-child { 121 | margin-top: 0; } 122 | 123 | dl { 124 | padding: 0; } 125 | dl dt { 126 | font-size: 14px; 127 | font-weight: bold; 128 | font-style: italic; 129 | padding: 0; 130 | margin: 15px 0 5px; } 131 | dl dt:first-child { 132 | padding: 0; } 133 | dl dt > :first-child { 134 | margin-top: 0; } 135 | dl dt > :last-child { 136 | margin-bottom: 0; } 137 | dl dd { 138 | margin: 0 0 15px; 139 | padding: 0 15px; } 140 | dl dd > :first-child { 141 | margin-top: 0; } 142 | dl dd > :last-child { 143 | margin-bottom: 0; } 144 | 145 | blockquote { 146 | border-left: 4px solid #dddddd; 147 | padding: 0 15px; 148 | color: #777777; } 149 | blockquote > :first-child { 150 | margin-top: 0; } 151 | blockquote > :last-child { 152 | margin-bottom: 0; } 153 | 154 | table { 155 | padding: 0;border-collapse: collapse; } 156 | table tr { 157 | border-top: 1px solid #cccccc; 158 | background-color: white; 159 | margin: 0; 160 | padding: 0; } 161 | table tr:nth-child(2n) { 162 | background-color: #f8f8f8; } 163 | table tr th { 164 | font-weight: bold; 165 | border: 1px solid #cccccc; 166 | margin: 0; 167 | padding: 6px 13px; } 168 | table tr td { 169 | border: 1px solid #cccccc; 170 | margin: 0; 171 | padding: 6px 13px; } 172 | table tr th :first-child, table tr td :first-child { 173 | margin-top: 0; } 174 | table tr th :last-child, table tr td :last-child { 175 | margin-bottom: 0; } 176 | 177 | img { 178 | max-width: 100%; } 179 | 180 | span.frame { 181 | display: block; 182 | overflow: hidden; } 183 | span.frame > span { 184 | border: 1px solid #dddddd; 185 | display: block; 186 | float: left; 187 | overflow: hidden; 188 | margin: 13px 0 0; 189 | padding: 7px; 190 | width: auto; } 191 | span.frame span img { 192 | display: block; 193 | float: left; } 194 | span.frame span span { 195 | clear: both; 196 | color: #333333; 197 | display: block; 198 | padding: 5px 0 0; } 199 | span.align-center { 200 | display: block; 201 | overflow: hidden; 202 | clear: both; } 203 | span.align-center > span { 204 | display: block; 205 | overflow: hidden; 206 | margin: 13px auto 0; 207 | text-align: center; } 208 | span.align-center span img { 209 | margin: 0 auto; 210 | text-align: center; } 211 | span.align-right { 212 | display: block; 213 | overflow: hidden; 214 | clear: both; } 215 | span.align-right > span { 216 | display: block; 217 | overflow: hidden; 218 | margin: 13px 0 0; 219 | text-align: right; } 220 | span.align-right span img { 221 | margin: 0; 222 | text-align: right; } 223 | span.float-left { 224 | display: block; 225 | margin-right: 13px; 226 | overflow: hidden; 227 | float: left; } 228 | span.float-left span { 229 | margin: 13px 0 0; } 230 | span.float-right { 231 | display: block; 232 | margin-left: 13px; 233 | overflow: hidden; 234 | float: right; } 235 | span.float-right > span { 236 | display: block; 237 | overflow: hidden; 238 | margin: 13px auto 0; 239 | text-align: right; } 240 | 241 | code, tt { 242 | margin: 0 2px; 243 | padding: 0 5px; 244 | white-space: nowrap; 245 | border: 1px solid #eaeaea; 246 | background-color: #f8f8f8; 247 | border-radius: 3px; } 248 | 249 | pre code { 250 | margin: 0; 251 | padding: 0; 252 | white-space: pre; 253 | border: none; 254 | background: transparent; } 255 | 256 | .highlight pre { 257 | background-color: #f8f8f8; 258 | border: 1px solid #cccccc; 259 | font-size: 13px; 260 | line-height: 19px; 261 | overflow: auto; 262 | padding: 6px 10px; 263 | border-radius: 3px; } 264 | 265 | pre { 266 | background-color: #f8f8f8; 267 | border: 1px solid #cccccc; 268 | font-size: 13px; 269 | line-height: 19px; 270 | overflow: auto; 271 | padding: 6px 10px; 272 | border-radius: 3px; } 273 | pre code, pre tt { 274 | background-color: transparent; 275 | border: none; } 276 | 277 | sup { 278 | font-size: 0.83em; 279 | vertical-align: super; 280 | line-height: 0; 281 | } 282 | * { 283 | -webkit-print-color-adjust: exact; 284 | } 285 | @media print { 286 | table, pre { 287 | page-break-inside: avoid; 288 | } 289 | pre { 290 | word-wrap: break-word; 291 | } 292 | } 293 | 294 | } -------------------------------------------------------------------------------- /css/menu.less: -------------------------------------------------------------------------------- 1 | .spa-panel-menu { 2 | .container { 3 | width: 12em; 4 | max-width: 100%; 5 | height: 100%; 6 | padding: 0; 7 | background: @lighter; 8 | 9 | @media screen and (min-width: 20em) { 10 | width: 16em; 11 | } 12 | 13 | @media screen and (min-width: @screen-tablet) { 14 | display: none; 15 | } 16 | 17 | } 18 | 19 | .container-shadow { 20 | position: absolute; 21 | width: 1px; 22 | top: 0; 23 | right: -1px; 24 | bottom: 0; 25 | .box-shadow(0 0 4px @dark); 26 | overflow: hidden; 27 | 28 | @media screen and (min-width: @screen-tablet) { 29 | display: none; 30 | } 31 | } 32 | } 33 | 34 | .menu { 35 | width: 100%; 36 | height: 100%; 37 | margin-bottom: 2px; 38 | padding-bottom: 1em; 39 | box-sizing: border-box; 40 | overflow: hidden; 41 | 42 | @media screen and (min-width: @screen-tablet) { 43 | height: auto; 44 | } 45 | 46 | menu { 47 | width: 100%; 48 | margin: 1em 0 0; 49 | padding: 0; 50 | .box-shadow(0 0 1px @grey); 51 | background: @white; 52 | list-style: none; 53 | overflow: hidden; 54 | 55 | li { 56 | position: relative; 57 | height: 2em; 58 | line-height: 2em; 59 | margin: 0 0 0 1.5em; 60 | font-size: 1.2em; 61 | .box-shadow(2px 0px 1px @greyer); 62 | 63 | &:first-child { 64 | margin-top: -1px; 65 | padding-top: 1px; 66 | } 67 | 68 | a { 69 | display: block; 70 | height: 100%; 71 | padding: 0 0.5em 0 0.2em; 72 | color: @darker; 73 | background: @white; 74 | overflow: hidden; 75 | } 76 | 77 | span { 78 | position: absolute; 79 | top: 16px; 80 | left: -14px; 81 | width: 6px; 82 | height: 6px; 83 | .border-radius(50%); 84 | overflow: hidden; 85 | } 86 | 87 | &:after { 88 | content: ""; 89 | position: absolute; 90 | top: 15px; 91 | right: 15px; 92 | width: 6px; 93 | height: 6px; 94 | border-width: 0 2px 2px 0; 95 | border-style: solid; 96 | border-color: @lighter; 97 | .rotate(-45deg); 98 | } 99 | 100 | &:active { 101 | background: @lighter; 102 | } 103 | } 104 | } 105 | 106 | footer { 107 | position: absolute; 108 | left: 0; 109 | bottom: 0; 110 | margin: 1em; 111 | font-weight: 100; 112 | color: @light; 113 | font-style: italic; 114 | 115 | a { 116 | font-weight: 200; 117 | color: @light; 118 | } 119 | } 120 | } 121 | 122 | 123 | -------------------------------------------------------------------------------- /css/normalize.less: -------------------------------------------------------------------------------- 1 | /* normalize.css v3.0.0 | MIT License | git.io/normalize */ 2 | 3 | /** 4 | * 1. Set default font family to sans-serif. 5 | * 2. Prevent iOS text size adjust after orientation change, without disabling 6 | * user zoom. 7 | */ 8 | 9 | html { 10 | font-family: sans-serif; /* 1 */ 11 | -ms-text-size-adjust: 100%; /* 2 */ 12 | -webkit-text-size-adjust: 100%; /* 2 */ 13 | } 14 | 15 | /** 16 | * Remove default margin. 17 | */ 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | /* HTML5 display definitions 24 | ========================================================================== */ 25 | 26 | /** 27 | * Correct `block` display not defined in IE 8/9. 28 | */ 29 | 30 | article, 31 | aside, 32 | details, 33 | figcaption, 34 | figure, 35 | footer, 36 | header, 37 | hgroup, 38 | main, 39 | nav, 40 | section, 41 | summary { 42 | display: block; 43 | } 44 | 45 | /** 46 | * 1. Correct `inline-block` display not defined in IE 8/9. 47 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 48 | */ 49 | 50 | audio, 51 | canvas, 52 | progress, 53 | video { 54 | display: inline-block; /* 1 */ 55 | vertical-align: baseline; /* 2 */ 56 | } 57 | 58 | /** 59 | * Prevent modern browsers from displaying `audio` without controls. 60 | * Remove excess height in iOS 5 devices. 61 | */ 62 | 63 | audio:not([controls]) { 64 | display: none; 65 | height: 0; 66 | } 67 | 68 | /** 69 | * Address `[hidden]` styling not present in IE 8/9. 70 | * Hide the `template` element in IE, Safari, and Firefox < 22. 71 | */ 72 | 73 | [hidden], 74 | template { 75 | display: none; 76 | } 77 | 78 | /* Links 79 | ========================================================================== */ 80 | 81 | /** 82 | * Remove the gray background color from active links in IE 10. 83 | */ 84 | 85 | a { 86 | background: transparent; 87 | } 88 | 89 | /** 90 | * Improve readability when focused and also mouse hovered in all browsers. 91 | */ 92 | 93 | a:active, 94 | a:hover { 95 | outline: 0; 96 | } 97 | 98 | /* Text-level semantics 99 | ========================================================================== */ 100 | 101 | /** 102 | * Address styling not present in IE 8/9, Safari 5, and Chrome. 103 | */ 104 | 105 | abbr[title] { 106 | border-bottom: 1px dotted; 107 | } 108 | 109 | /** 110 | * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. 111 | */ 112 | 113 | b, 114 | strong { 115 | font-weight: bold; 116 | } 117 | 118 | /** 119 | * Address styling not present in Safari 5 and Chrome. 120 | */ 121 | 122 | dfn { 123 | font-style: italic; 124 | } 125 | 126 | /** 127 | * Address variable `h1` font-size and margin within `section` and `article` 128 | * contexts in Firefox 4+, Safari 5, and Chrome. 129 | */ 130 | 131 | h1 { 132 | font-size: 2em; 133 | margin: 0.67em 0; 134 | } 135 | 136 | /** 137 | * Address styling not present in IE 8/9. 138 | */ 139 | 140 | mark { 141 | background: #ff0; 142 | color: #000; 143 | } 144 | 145 | /** 146 | * Address inconsistent and variable font size in all browsers. 147 | */ 148 | 149 | small { 150 | font-size: 80%; 151 | } 152 | 153 | /** 154 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 155 | */ 156 | 157 | sub, 158 | sup { 159 | font-size: 75%; 160 | line-height: 0; 161 | position: relative; 162 | vertical-align: baseline; 163 | } 164 | 165 | sup { 166 | top: -0.5em; 167 | } 168 | 169 | sub { 170 | bottom: -0.25em; 171 | } 172 | 173 | /* Embedded content 174 | ========================================================================== */ 175 | 176 | /** 177 | * Remove border when inside `a` element in IE 8/9. 178 | */ 179 | 180 | img { 181 | border: 0; 182 | } 183 | 184 | /** 185 | * Correct overflow displayed oddly in IE 9. 186 | */ 187 | 188 | svg:not(:root) { 189 | overflow: hidden; 190 | } 191 | 192 | /* Grouping content 193 | ========================================================================== */ 194 | 195 | /** 196 | * Address margin not present in IE 8/9 and Safari 5. 197 | */ 198 | 199 | figure { 200 | margin: 1em 40px; 201 | } 202 | 203 | /** 204 | * Address differences between Firefox and other browsers. 205 | */ 206 | 207 | hr { 208 | -moz-box-sizing: content-box; 209 | box-sizing: content-box; 210 | height: 0; 211 | } 212 | 213 | /** 214 | * Contain overflow in all browsers. 215 | */ 216 | 217 | pre { 218 | overflow: auto; 219 | } 220 | 221 | /** 222 | * Address odd `em`-unit font size rendering in all browsers. 223 | */ 224 | 225 | code, 226 | kbd, 227 | pre, 228 | samp { 229 | font-family: monospace, monospace; 230 | font-size: 1em; 231 | } 232 | 233 | /* Forms 234 | ========================================================================== */ 235 | 236 | /** 237 | * Known limitation: by default, Chrome and Safari on OS X allow very limited 238 | * styling of `select`, unless a `border` property is set. 239 | */ 240 | 241 | /** 242 | * 1. Correct color not being inherited. 243 | * Known issue: affects color of disabled elements. 244 | * 2. Correct font properties not being inherited. 245 | * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. 246 | */ 247 | 248 | button, 249 | input, 250 | optgroup, 251 | select, 252 | textarea { 253 | color: inherit; /* 1 */ 254 | font: inherit; /* 2 */ 255 | margin: 0; /* 3 */ 256 | } 257 | 258 | /** 259 | * Address `overflow` set to `hidden` in IE 8/9/10. 260 | */ 261 | 262 | button { 263 | overflow: visible; 264 | } 265 | 266 | /** 267 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 268 | * All other form control elements do not inherit `text-transform` values. 269 | * Correct `button` style inheritance in Firefox, IE 8+, and Opera 270 | * Correct `select` style inheritance in Firefox. 271 | */ 272 | 273 | button, 274 | select { 275 | text-transform: none; 276 | } 277 | 278 | /** 279 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 280 | * and `video` controls. 281 | * 2. Correct inability to style clickable `input` types in iOS. 282 | * 3. Improve usability and consistency of cursor style between image-type 283 | * `input` and others. 284 | */ 285 | 286 | button, 287 | html input[type="button"], /* 1 */ 288 | input[type="reset"], 289 | input[type="submit"] { 290 | -webkit-appearance: button; /* 2 */ 291 | cursor: pointer; /* 3 */ 292 | } 293 | 294 | /** 295 | * Re-set default cursor for disabled elements. 296 | */ 297 | 298 | button[disabled], 299 | html input[disabled] { 300 | cursor: default; 301 | } 302 | 303 | /** 304 | * Remove inner padding and border in Firefox 4+. 305 | */ 306 | 307 | button::-moz-focus-inner, 308 | input::-moz-focus-inner { 309 | border: 0; 310 | padding: 0; 311 | } 312 | 313 | /** 314 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 315 | * the UA stylesheet. 316 | */ 317 | 318 | input { 319 | line-height: normal; 320 | } 321 | 322 | /** 323 | * It's recommended that you don't attempt to style these elements. 324 | * Firefox's implementation doesn't respect box-sizing, padding, or width. 325 | * 326 | * 1. Address box sizing set to `content-box` in IE 8/9/10. 327 | * 2. Remove excess padding in IE 8/9/10. 328 | */ 329 | 330 | input[type="checkbox"], 331 | input[type="radio"] { 332 | box-sizing: border-box; /* 1 */ 333 | padding: 0; /* 2 */ 334 | } 335 | 336 | /** 337 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain 338 | * `font-size` values of the `input`, it causes the cursor style of the 339 | * decrement button to change from `default` to `text`. 340 | */ 341 | 342 | input[type="number"]::-webkit-inner-spin-button, 343 | input[type="number"]::-webkit-outer-spin-button { 344 | height: auto; 345 | } 346 | 347 | /** 348 | * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. 349 | * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome 350 | * (include `-moz` to future-proof). 351 | */ 352 | 353 | input[type="search"] { 354 | -webkit-appearance: textfield; /* 1 */ 355 | -moz-box-sizing: content-box; 356 | -webkit-box-sizing: content-box; /* 2 */ 357 | box-sizing: content-box; 358 | } 359 | 360 | /** 361 | * Remove inner padding and search cancel button in Safari and Chrome on OS X. 362 | * Safari (but not Chrome) clips the cancel button when the search input has 363 | * padding (and `textfield` appearance). 364 | */ 365 | 366 | input[type="search"]::-webkit-search-cancel-button, 367 | input[type="search"]::-webkit-search-decoration { 368 | -webkit-appearance: none; 369 | } 370 | 371 | /** 372 | * Define consistent border, margin, and padding. 373 | */ 374 | 375 | fieldset { 376 | border: 1px solid #c0c0c0; 377 | margin: 0 2px; 378 | padding: 0.35em 0.625em 0.75em; 379 | } 380 | 381 | /** 382 | * 1. Correct `color` not being inherited in IE 8/9. 383 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 384 | */ 385 | 386 | legend { 387 | border: 0; /* 1 */ 388 | padding: 0; /* 2 */ 389 | } 390 | 391 | /** 392 | * Remove default vertical scrollbar in IE 8/9. 393 | */ 394 | 395 | textarea { 396 | overflow: auto; 397 | } 398 | 399 | /** 400 | * Don't inherit the `font-weight` (applied by a rule above). 401 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 402 | */ 403 | 404 | optgroup { 405 | font-weight: bold; 406 | } 407 | 408 | /* Tables 409 | ========================================================================== */ 410 | 411 | /** 412 | * Remove most spacing between table cells. 413 | */ 414 | 415 | table { 416 | border-collapse: collapse; 417 | border-spacing: 0; 418 | } 419 | 420 | td, 421 | th { 422 | padding: 0; 423 | } -------------------------------------------------------------------------------- /css/pull2refresh.less: -------------------------------------------------------------------------------- 1 | .pulldown, .pullup { 2 | position: absolute; 3 | width: 100%; 4 | height: 3em; 5 | line-height: 3em; 6 | text-align: center; 7 | color: @light; 8 | font-weight: 100; 9 | z-index: 1; 10 | 11 | .ball { 12 | display: inline-block; 13 | padding: 5px; 14 | .border-radius(50%); 15 | } 16 | 17 | .ball:nth-child(1) { 18 | background: @orange; 19 | -webkit-animation: move-left 800ms ease-in-out infinite alternate; 20 | } 21 | 22 | .ball:nth-child(2) { 23 | background: @blue; 24 | -webkit-animation: move-right 800ms ease-in-out infinite alternate; 25 | } 26 | } 27 | 28 | .pulldown { 29 | top: -3em; 30 | } 31 | 32 | .pullup { 33 | bottom: -3em; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /css/side.less: -------------------------------------------------------------------------------- 1 | .side { 2 | display: none; 3 | position: absolute; 4 | left: 0; 5 | top: 0; 6 | bottom: 0; 7 | width: 15em; 8 | z-index: 3000; 9 | box-shadow: 0 0 4px @greyer; 10 | 11 | @media screen and (min-width: @screen-tablet) { 12 | display: block; 13 | } 14 | 15 | @media screen and (min-width: @screen-desktop) { 16 | width: 16em; 17 | } 18 | 19 | @media screen and (min-width: @screen-large) { 20 | width: 18em; 21 | left: 4em; 22 | } 23 | 24 | .container { 25 | background: @lighter; 26 | 27 | .logo { 28 | margin: 20px 10px; 29 | font-size: 3em; 30 | } 31 | 32 | .desc { 33 | box-shadow: none; 34 | 35 | a { 36 | color: @greyer; 37 | } 38 | } 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /dev.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Spring is a blog engine written by github issues 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 56 | 57 | 58 | 63 | 64 | -------------------------------------------------------------------------------- /dist/main.min.css: -------------------------------------------------------------------------------- 1 | html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:0 0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.hljs{display:block;padding:.5em;color:#333;background:#f8f8f8}.hljs-comment,.hljs-template_comment,.diff .hljs-header,.hljs-javadoc{color:#998;font-style:italic}.hljs-keyword,.css .rule .hljs-keyword,.hljs-winutils,.javascript .hljs-title,.nginx .hljs-title,.hljs-subst,.hljs-request,.hljs-status{color:#333;font-weight:700}.hljs-number,.hljs-hexcolor,.ruby .hljs-constant{color:#099}.hljs-string,.hljs-tag .hljs-value,.hljs-phpdoc,.tex .hljs-formula{color:#d14}.hljs-title,.hljs-id,.coffeescript .hljs-params,.scss .hljs-preprocessor{color:#900;font-weight:700}.javascript .hljs-title,.lisp .hljs-title,.clojure .hljs-title,.hljs-subst{font-weight:400}.hljs-class .hljs-title,.haskell .hljs-type,.vhdl .hljs-literal,.tex .hljs-command{color:#458;font-weight:700}.hljs-tag,.hljs-tag .hljs-title,.hljs-rules .hljs-property,.django .hljs-tag .hljs-keyword{color:navy;font-weight:400}.hljs-attribute,.hljs-variable,.lisp .hljs-body{color:teal}.hljs-regexp{color:#009926}.hljs-symbol,.ruby .hljs-symbol .hljs-string,.lisp .hljs-keyword,.tex .hljs-special,.hljs-prompt{color:#990073}.hljs-built_in,.lisp .hljs-title,.clojure .hljs-built_in{color:#0086b3}.hljs-preprocessor,.hljs-pragma,.hljs-pi,.hljs-doctype,.hljs-shebang,.hljs-cdata{color:#999;font-weight:700}.hljs-deletion{background:#fdd}.hljs-addition{background:#dfd}.diff .hljs-change{background:#0086b3}.hljs-chunk{color:#aaa}html{color:#2c3e50;font-size:1em;line-height:1.4}@media screen and (max-width:48em){html{-webkit-user-select:none;user-select:none}}body{font-family:"Helvetica Neue",Helvetica,STHeiTi,sans-serif}@media screen and (max-width:48em){body{-webkit-user-select:none;user-select:none}}::-moz-selection{background:#b3d4fc;text-shadow:none}::selection{background:#b3d4fc;text-shadow:none}hr{display:block;height:1px;border:0;border-top:1px solid #ccc;margin:1em 0;padding:0}audio,canvas,img,svg,video{vertical-align:middle}fieldset{border:0;margin:0;padding:0}textarea{resize:vertical}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.clearfix:before,.clearfix:after{content:" ";display:table}.clearfix:after{clear:both}a{color:#34495e;text-decoration:none;-webkit-touch-callout:none}a:hover,a:active{color:#34495e;text-decoration:none}.hidden{display:none!important;visibility:hidden}.container{position:absolute;top:0;right:0;bottom:0;left:0;background:#fff}.container .desc{color:#7f8c8d;-webkit-box-shadow:0 0 1px #bdc3c7;-moz-box-shadow:0 0 1px #bdc3c7;box-shadow:0 0 1px #bdc3c7}@media screen and (min-width:37.5em){.container .desc{font-size:1em}}.container .container-inner{min-height:100%;margin:0 0 2px;overflow:hidden}header{position:absolute;left:0;top:0;width:100%;height:3em;overflow:hidden;z-index:1;background:#34495e;color:#ecf0f1}@media screen and (min-width:48em){header{display:none}}header h1{position:absolute;left:50%;top:.6em;margin:0;font-size:1em;font-weight:200}header h1 span{display:block;max-width:8em;margin-left:-50%;margin-right:50%;font-size:1.4em;overflow:hidden}.btn-menu,.btn-back{float:left;font-weight:200;margin:.65em;padding:.2em;background:#ecf0f1;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box}.markdown{font-family:Helvetica,arial,sans-serif;font-size:14px;line-height:1.6;padding:10px}.markdown>:first-child{margin-top:0!important}.markdown>:last-child{margin-bottom:0!important}.markdown a{color:#3498db;text-decoration:underline}.markdown a.absent{color:#c00}.markdown a.anchor{display:block;padding-left:30px;margin-left:-30px;cursor:pointer;position:absolute;top:0;left:0;bottom:0}.markdown h1,.markdown h2,.markdown h3,.markdown h4,.markdown h5,.markdown h6{margin:20px 0 10px;padding:0;font-weight:700;-webkit-font-smoothing:antialiased;cursor:text;position:relative}.markdown h1:hover a.anchor,.markdown h2:hover a.anchor,.markdown h3:hover a.anchor,.markdown h4:hover a.anchor,.markdown h5:hover a.anchor,.markdown h6:hover a.anchor{text-decoration:none}.markdown h1 tt,.markdown h1 code{font-size:inherit}.markdown h2 tt,.markdown h2 code{font-size:inherit}.markdown h3 tt,.markdown h3 code{font-size:inherit}.markdown h4 tt,.markdown h4 code{font-size:inherit}.markdown h5 tt,.markdown h5 code{font-size:inherit}.markdown h6 tt,.markdown h6 code{font-size:inherit}.markdown h1{font-size:28px;color:#000}.markdown h2{font-size:24px;border-bottom:1px solid #ccc;color:#000}.markdown h3{font-size:18px}.markdown h4{font-size:16px}.markdown h5{font-size:14px}.markdown h6{color:#777;font-size:14px}.markdown p,.markdown blockquote,.markdown ul,.markdown ol,.markdown dl,.markdown li,.markdown table,.markdown pre{margin:15px 0}.markdown hr{border:0 none;color:#ccc;height:4px;padding:0}.markdown>h2:first-child{margin-top:0;padding-top:0}.markdown>h1:first-child{margin-top:0;padding-top:0}.markdown>h1:first-child+h2{margin-top:0;padding-top:0}.markdown>h3:first-child,.markdown body>h4:first-child,.markdown body>h5:first-child,.markdown body>h6:first-child{margin-top:0;padding-top:0}.markdown a:first-child h1,.markdown a:first-child h2,.markdown a:first-child h3,.markdown a:first-child h4,.markdown a:first-child h5,.markdown a:first-child h6{margin-top:0;padding-top:0}.markdown h1 p,.markdown h2 p,.markdown h3 p,.markdown h4 p,.markdown h5 p,.markdown h6 p{margin-top:0}.markdown li p.first{display:inline-block}.markdown li{margin:0}.markdown ul,.markdown ol{padding-left:30px}.markdown ul :first-child,.markdown ol :first-child{margin-top:0}.markdown dl{padding:0}.markdown dl dt{font-size:14px;font-weight:700;font-style:italic;padding:0;margin:15px 0 5px}.markdown dl dt:first-child{padding:0}.markdown dl dt>:first-child{margin-top:0}.markdown dl dt>:last-child{margin-bottom:0}.markdown dl dd{margin:0 0 15px;padding:0 15px}.markdown dl dd>:first-child{margin-top:0}.markdown dl dd>:last-child{margin-bottom:0}.markdown blockquote{border-left:4px solid #ddd;padding:0 15px;color:#777}.markdown blockquote>:first-child{margin-top:0}.markdown blockquote>:last-child{margin-bottom:0}.markdown table{padding:0;border-collapse:collapse}.markdown table tr{border-top:1px solid #ccc;background-color:#fff;margin:0;padding:0}.markdown table tr:nth-child(2n){background-color:#f8f8f8}.markdown table tr th{font-weight:700;border:1px solid #ccc;margin:0;padding:6px 13px}.markdown table tr td{border:1px solid #ccc;margin:0;padding:6px 13px}.markdown table tr th :first-child,.markdown table tr td :first-child{margin-top:0}.markdown table tr th :last-child,.markdown table tr td :last-child{margin-bottom:0}.markdown img{max-width:100%}.markdown span.frame{display:block;overflow:hidden}.markdown span.frame>span{border:1px solid #ddd;display:block;float:left;overflow:hidden;margin:13px 0 0;padding:7px;width:auto}.markdown span.frame span img{display:block;float:left}.markdown span.frame span span{clear:both;color:#333;display:block;padding:5px 0 0}.markdown span.align-center{display:block;overflow:hidden;clear:both}.markdown span.align-center>span{display:block;overflow:hidden;margin:13px auto 0;text-align:center}.markdown span.align-center span img{margin:0 auto;text-align:center}.markdown span.align-right{display:block;overflow:hidden;clear:both}.markdown span.align-right>span{display:block;overflow:hidden;margin:13px 0 0;text-align:right}.markdown span.align-right span img{margin:0;text-align:right}.markdown span.float-left{display:block;margin-right:13px;overflow:hidden;float:left}.markdown span.float-left span{margin:13px 0 0}.markdown span.float-right{display:block;margin-left:13px;overflow:hidden;float:right}.markdown span.float-right>span{display:block;overflow:hidden;margin:13px auto 0;text-align:right}.markdown code,.markdown tt{margin:0 2px;padding:0 5px;white-space:nowrap;border:1px solid #eaeaea;background-color:#f8f8f8;border-radius:3px}.markdown pre code{margin:0;padding:0;white-space:pre;border:none;background:0 0}.markdown .highlight pre{background-color:#f8f8f8;border:1px solid #ccc;font-size:13px;line-height:19px;overflow:auto;padding:6px 10px;border-radius:3px}.markdown pre{background-color:#f8f8f8;border:1px solid #ccc;font-size:13px;line-height:19px;overflow:auto;padding:6px 10px;border-radius:3px}.markdown pre code,.markdown pre tt{background-color:transparent;border:none}.markdown sup{font-size:.83em;vertical-align:super;line-height:0}.markdown *{-webkit-print-color-adjust:exact}@media print{.markdown table,.markdown pre{page-break-inside:avoid}.markdown pre{word-wrap:break-word}}.pulldown,.pullup{position:absolute;width:100%;height:3em;line-height:3em;text-align:center;color:#bdc3c7;font-weight:100;z-index:1}.pulldown .ball,.pullup .ball{display:inline-block;padding:5px;-webkit-border-radius:50%;-moz-border-radius:50%;border-radius:50%;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box}.pulldown .ball:nth-child(1),.pullup .ball:nth-child(1){background:#f39c12;-webkit-animation:move-left 800ms ease-in-out infinite alternate}.pulldown .ball:nth-child(2),.pullup .ball:nth-child(2){background:#3498db;-webkit-animation:move-right 800ms ease-in-out infinite alternate}.pulldown{top:-3em}.pullup{bottom:-3em}.issuelist{position:relative}.issuelist article{margin:0 10px;padding:20px 0 10px;box-shadow:0 1px 0 #ecf0f1}.issuelist article span.date{display:block;padding:0 0 5px;color:#bdc3c7;font-size:.75em;font-weight:200}@media screen and (min-width:37.5em){.issuelist article span.date{font-size:1em}}.issuelist article h3{margin:0;font-weight:400}@media screen and (min-width:37.5em){.issuelist article h3{font-size:2em}}@media screen and (min-width:62em){.issuelist article h3{font-size:2.5em}}.issuelist article h3 a{display:block}.issuelist article p.tag{margin:0;padding:5px 0;font-size:.75em}@media screen and (min-width:37.5em){.issuelist article p.tag{font-size:1em}}.issuelist article p.tag a{display:inline-block;margin-right:5px;padding:2px 5px;font-weight:200;color:#fff;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box;background:#ecf0f1}.issuelist .end{padding:10px 0;text-align:center;color:#bdc3c7;font-weight:100}.side{display:none;position:absolute;left:0;top:0;bottom:0;width:15em;z-index:3000;box-shadow:0 0 4px #7f8c8d}@media screen and (min-width:48em){.side{display:block}}@media screen and (min-width:62em){.side{width:16em}}@media screen and (min-width:75em){.side{width:18em;left:4em}}.side .container{background:#ecf0f1}.side .container .logo{margin:20px 10px;font-size:3em}.side .container .desc{box-shadow:none}.side .container .desc a{color:#7f8c8d}.spa-panel-menu .container{width:12em;max-width:100%;height:100%;padding:0;background:#ecf0f1}@media screen and (min-width:20em){.spa-panel-menu .container{width:16em}}@media screen and (min-width:48em){.spa-panel-menu .container{display:none}}.spa-panel-menu .container-shadow{position:absolute;width:1px;top:0;right:-1px;bottom:0;-webkit-box-shadow:0 0 4px #34495e;-moz-box-shadow:0 0 4px #34495e;box-shadow:0 0 4px #34495e;overflow:hidden}@media screen and (min-width:48em){.spa-panel-menu .container-shadow{display:none}}.menu{width:100%;height:100%;margin-bottom:2px;padding-bottom:1em;box-sizing:border-box;overflow:hidden}@media screen and (min-width:48em){.menu{height:auto}}.menu menu{width:100%;margin:1em 0 0;padding:0;-webkit-box-shadow:0 0 1px #95a5a6;-moz-box-shadow:0 0 1px #95a5a6;box-shadow:0 0 1px #95a5a6;background:#fff;list-style:none;overflow:hidden}.menu menu li{position:relative;height:2em;line-height:2em;margin:0 0 0 1.5em;font-size:1.2em;-webkit-box-shadow:2px 0 1px #7f8c8d;-moz-box-shadow:2px 0 1px #7f8c8d;box-shadow:2px 0 1px #7f8c8d}.menu menu li:first-child{margin-top:-1px;padding-top:1px}.menu menu li a{display:block;height:100%;padding:0 .5em 0 .2em;color:#2c3e50;background:#fff;overflow:hidden}.menu menu li span{position:absolute;top:16px;left:-14px;width:6px;height:6px;-webkit-border-radius:50%;-moz-border-radius:50%;border-radius:50%;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box;overflow:hidden}.menu menu li:after{content:"";position:absolute;top:15px;right:15px;width:6px;height:6px;border-width:0 2px 2px 0;border-style:solid;border-color:#ecf0f1;-webkit-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg)}.menu menu li:active{background:#ecf0f1}.menu footer{position:absolute;left:0;bottom:0;margin:1em;font-weight:100;color:#bdc3c7;font-style:italic}.menu footer a{font-weight:200;color:#bdc3c7}.spa-page-home .container{top:3em}@media screen and (min-width:48em){.spa-page-home .container{top:0}.spa-page-home .container .desc{display:none}}@media screen and (min-width:48em){.spa-page-home .container .container-inner{margin-left:16em}}@media screen and (min-width:62em){.spa-page-home .container .container-inner{margin-left:18em;margin-right:1em}}@media screen and (min-width:75em){.spa-page-home .container .container-inner{margin-left:24em;max-width:52em}}.spa-page-labels .container{top:3em}@media screen and (min-width:48em){.spa-page-labels .container{top:0}}@media screen and (min-width:48em){.spa-page-labels .container .container-inner{margin-left:16em}}@media screen and (min-width:62em){.spa-page-labels .container .container-inner{margin-left:18em;margin-right:1em}}@media screen and (min-width:75em){.spa-page-labels .container .container-inner{margin-left:24em;max-width:52em}}.spa-page-issues header .btn-back{display:block}.spa-page-issues .container{top:3em}@media screen and (min-width:48em){.spa-page-issues .container{top:0}}@media screen and (min-width:48em){.spa-page-issues .container .container-inner{margin-left:16em}}@media screen and (min-width:62em){.spa-page-issues .container .container-inner{margin-left:18em;margin-right:1em}}@media screen and (min-width:75em){.spa-page-issues .container .container-inner{margin-left:24em;max-width:52em}}.spa-page-issues .btn-back{display:none}@media screen and (min-width:48em){.spa-page-issues .btn-back{display:block;position:fixed;top:10px;right:10px;z-index:2;-webkit-opacity:.8;-moz-opacity:.8;opacity:.8}}@media screen and (min-width:75em){.spa-page-issues .btn-back{left:72em;top:20px;right:auto}}.spa-page-issues .btn-menu{display:none}.spa-page-issues .issues{position:relative}.spa-page-issues .issues .desc{text-align:center}.spa-page-issues .issues .title{padding:0 10px;font-weight:400;text-align:center;margin-bottom:.2em}@media screen and (min-width:62em){.spa-page-issues .issues .title{font-size:2.5em}}.spa-page-issues .issues article video{max-width:100%}@media screen and (min-width:37.5em){.spa-page-issues .issues article{font-size:1em}.spa-page-issues .issues article pre{font-size:.8em}}@media screen and (min-width:62em){.spa-page-issues .issues article{font-size:1.2em}}.spa-page-issues .issues article .btn-view{display:block;width:100%;padding:.5em 0;text-align:center;font-weight:200;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box;color:#bdc3c7;background:#ecf0f1;text-decoration:none} -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoda/spring/281a4481ea5b7c8a2e36e9c614f758b737868b95/favicon.ico -------------------------------------------------------------------------------- /img/apple-touch-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoda/spring/281a4481ea5b7c8a2e36e9c614f758b737868b95/img/apple-touch-icon-114x114.png -------------------------------------------------------------------------------- /img/apple-touch-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoda/spring/281a4481ea5b7c8a2e36e9c614f758b737868b95/img/apple-touch-icon-144x144.png -------------------------------------------------------------------------------- /img/apple-touch-startup-image-320x460.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoda/spring/281a4481ea5b7c8a2e36e9c614f758b737868b95/img/apple-touch-startup-image-320x460.png -------------------------------------------------------------------------------- /img/apple-touch-startup-image-640x1096.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoda/spring/281a4481ea5b7c8a2e36e9c614f758b737868b95/img/apple-touch-startup-image-640x1096.png -------------------------------------------------------------------------------- /img/apple-touch-startup-image-640x1096.png.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoda/spring/281a4481ea5b7c8a2e36e9c614f758b737868b95/img/apple-touch-startup-image-640x1096.png.png -------------------------------------------------------------------------------- /img/apple-touch-startup-image-640x920.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaoda/spring/281a4481ea5b7c8a2e36e9c614f758b737868b95/img/apple-touch-startup-image-640x920.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Spring is a blog engine written by github issues 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 41 | 42 | 51 | 52 | 53 | 54 | 59 | 60 | -------------------------------------------------------------------------------- /js/boot.js: -------------------------------------------------------------------------------- 1 | ;(function($, win, doc) { 2 | 'use strict'; 3 | 4 | var $doc = $(doc), 5 | spring = {}, 6 | appcache = win.applicationCache 7 | 8 | // appcache 9 | if(appcache) { 10 | appcache.addEventListener('updateready', function(e) { 11 | if(appcache.status === appcache.UPDATEREADY) { 12 | appcache.swapCache() 13 | location.reload() 14 | } 15 | }, false) 16 | } 17 | 18 | // default config 19 | spring.config = { 20 | // my blog title 21 | title: 'Spring', 22 | // my blog description 23 | desc: 'A blog engine written by GitHub Issues [Fork me on GitHub](https://github.com/zhaoda/spring)', 24 | // my github username 25 | owner: 'zhaoda', 26 | // creator's username 27 | creator: '', 28 | // the repository name on github for writting issues 29 | repo: 'spring', 30 | // custom page 31 | pages: [], 32 | // github's api 33 | api: 'https://api.github.com', 34 | // the custom page size 35 | per_page: 10 36 | } 37 | 38 | spring.data = { 39 | labels: [], 40 | issues: {} 41 | } 42 | 43 | spring.fn = {} 44 | 45 | spring.fn.request = function(method, parameters, callback) { 46 | var url = spring.config.api + method + '?callback=?' 47 | 48 | $.getJSON(url, parameters, function(data) { 49 | if(!data.meta || !data.data || data.meta.status !== 200) { 50 | try { 51 | console.log(data) 52 | } catch(e) { 53 | } 54 | } 55 | callback.call(spring, data) 56 | }) 57 | } 58 | 59 | spring.fn.getLabels = function(callback) { 60 | spring.fn.request('/repos/' + spring.config.owner + '/' + spring.config.repo + '/labels', {}, function(data) { 61 | spring.data.labels = data.data || [] 62 | callback() 63 | }) 64 | } 65 | 66 | spring.fn.getHash = function(url) { 67 | url = url || location.href 68 | return url.replace(/^[^#]*#?\/?(.*)\/?$/, '$1') 69 | } 70 | 71 | spring.fn.encodeHtml = function(str) { 72 | return (str + '').replace(/&/g, '&').replace(//g, '>').replace(/\x60/g, '`').replace(/\x27/g, ''').replace(/\x22/g, '"') 73 | } 74 | 75 | spring.fn.getDate = function(time) { 76 | return (new Date(time) + '').split(' ').slice(1, 4).join(' ') 77 | } 78 | 79 | marked.setOptions({ 80 | highlight: function(code) { 81 | return hljs.highlightAuto(code).value 82 | } 83 | }) 84 | 85 | template.helper('marked', marked) 86 | template.helper('encodeURIComponent', encodeURIComponent) 87 | template.helper('$', $) 88 | 89 | var tapEvent = (function() { 90 | return "createTouch" in document ? 'tap' : 'click' 91 | })() 92 | 93 | spring.config.tapEvent = tapEvent 94 | 95 | $doc.on('click', 'a.preventlink, a.taplink', function(event) { 96 | event.preventDefault() 97 | event.stopPropagation() 98 | }) 99 | 100 | $doc.on(tapEvent, '.taplink', function(event) { 101 | var $currentTarget = $(event.currentTarget), 102 | $target = $(event.target), 103 | hash = $currentTarget.attr('data-href') || $currentTarget.attr('href') 104 | 105 | if($target.closest('.stoptaplink').length) 106 | return 107 | 108 | $currentTarget.trigger('spa:navigate', {hash: spring.fn.getHash(hash)}) 109 | }) 110 | 111 | // to prevent the click through 112 | if(tapEvent == 'tap') { 113 | $doc.on('touchstart', 'a', function(event) { 114 | var $target = $(event.currentTarget) 115 | $target.data('taptime', +new Date()) 116 | }) 117 | 118 | $doc.on('click', 'a', function(event) { 119 | var $target = $(event.currentTarget), 120 | taptime = $target.data('taptime') 121 | 122 | if(!taptime || (+new Date() - taptime > 500)) { 123 | event.preventDefault() 124 | event.stopPropagation() 125 | } 126 | }) 127 | } 128 | 129 | win.spring = $.spring = spring 130 | 131 | $doc.on(tapEvent, '.btn-back', function(event) { 132 | var $prevPage = $.spa.getViewData($.spa.getCurPage()).prevPage 133 | 134 | if(!$prevPage.hasClass('spa-page-empty')) { 135 | win.history.back() 136 | } else { 137 | $doc.trigger('spa:navigate', {hash: ''}) 138 | } 139 | }) 140 | 141 | $(function() { 142 | $doc.trigger('spa:boot', { 143 | callback: function() { 144 | $doc.trigger('side:create') 145 | 146 | spring.fn.getLabels(function() { 147 | $doc.trigger('menu:render') 148 | $doc.trigger('side:render') 149 | }) 150 | } 151 | }) 152 | }) 153 | 154 | })(Zepto, window, document) -------------------------------------------------------------------------------- /js/home.js: -------------------------------------------------------------------------------- 1 | ;(function($, win, doc) { 2 | 'use strict'; 3 | 4 | var $doc = $(document), 5 | spring = win.spring, 6 | source = '\ 7 |
\ 8 |

<%=$.spring.config.title%>

\ 9 | Menu\ 10 |
\ 11 |
\ 12 |
\ 13 | <%if($.spring.config.desc) {%>\ 14 |
<%=#marked($.spring.config.desc)%>
\ 15 | <%}%>\ 16 |
\ 17 |
\ 18 | \ 19 |
\ 20 |
\ 21 |
\ 22 |
', 23 | render = template.compile(source) 24 | 25 | var pageHome = { 26 | route: '', 27 | classname: 'home', 28 | animate: 'fadeIn', 29 | title: 'Spring', 30 | view: function(pageData) { 31 | var $page = this, 32 | data = {}, 33 | body = render(data) 34 | 35 | $doc.trigger('spa:initpage', [$page, {title: 'Spring', body: body}]) 36 | }, 37 | init: function(pageData) { 38 | var $view = this, 39 | $container = $('.container', $view), 40 | $issuelist = $('.issuelist', $container) 41 | 42 | $container.trigger('spa:scroll', {direction: 'y'}) 43 | 44 | $container.trigger('pull2refresh:init', { 45 | pullup: function() { 46 | $issuelist.trigger('issuelist:getdata', {pull: 'up', container: $container}) 47 | } 48 | }) 49 | 50 | $container.trigger('pull2refresh:pullup') 51 | } 52 | } 53 | 54 | $doc.trigger('spa:route', pageHome) 55 | 56 | })(Zepto, window, document) -------------------------------------------------------------------------------- /js/issuelist.js: -------------------------------------------------------------------------------- 1 | ;(function($, win, doc) { 2 | 'use strict'; 3 | 4 | var $doc = $(doc), 5 | spring = win.spring, 6 | source = '\ 7 | <%$.each(blogs, function(i, blog) {%>\ 8 |
\ 9 | <%=$.spring.fn.getDate(blog.created_at)%>\ 10 |

<%=blog.title%>

\ 11 | <%if(blog.labels.length) {%>\ 12 |

\ 13 | <%$.each(blog.labels, function(j, label) {%>\ 14 | <%=label.name%>\ 15 | <%})%>\ 16 |

\ 17 | <%}%>\ 18 |
\ 19 | <%})%>', 20 | render = template.compile(source) 21 | 22 | function hasNext(link) { 23 | var next = false 24 | 25 | link && $.each(link, function(index, item) { 26 | if(item[1].rel === 'next') { 27 | next = true 28 | } 29 | }) 30 | 31 | return next 32 | } 33 | 34 | $doc.on('issuelist:render', function(event, options) { 35 | var $target = $(event.target), 36 | data = options.data, 37 | next = false, 38 | html = '', 39 | sum = 0 40 | 41 | if(data.meta && data.data) { 42 | next = hasNext(data.meta.Link) 43 | 44 | html = render({blogs: data.data}) 45 | 46 | $target.append(html).trigger('pull2refresh:pullupFinish') 47 | } 48 | 49 | if(!next) { 50 | $('.pullup', $target).hide().remove() 51 | sum = $('article', $target).length 52 | $target.append('
' + sum + (sum > 1 ? ' blogs' : ' blog') + '
') 53 | } 54 | }) 55 | 56 | $doc.on('issuelist:getdata', function(event, options) { 57 | var $target = $(event.target), 58 | method = '/repos/' + spring.config.owner + '/' + spring.config.repo + '/issues', 59 | parameters = {per_page: spring.config.per_page}, 60 | $blogs = $('article', $target), 61 | $lastOne, 62 | labels = $target.attr('data-labels') || '', 63 | page = $target.attr('data-page') || 1 64 | 65 | if(spring.config.creator) { 66 | parameters.creator = spring.config.creator 67 | } 68 | 69 | if(labels) { 70 | parameters.labels = labels 71 | } 72 | 73 | parameters.page = page 74 | 75 | spring.fn.request(method, parameters, function(data) { 76 | $.each(data.data, function(i, issue) { 77 | spring.data.issues[issue.number] = issue 78 | }) 79 | 80 | $target.trigger('issuelist:render', {data: data}) 81 | $target.attr('data-page', + page + 1) 82 | }) 83 | }) 84 | 85 | })(Zepto, window, document) -------------------------------------------------------------------------------- /js/issues.js: -------------------------------------------------------------------------------- 1 | ;(function($, win, doc) { 2 | 'use strict'; 3 | 4 | var $doc = $(document), 5 | spring = win.spring, 6 | source = '\ 7 |
\ 8 |

<%=$.spring.config.title%>

\ 9 | Back\ 10 |
\ 11 | Back\ 12 |
\ 13 |
\ 14 |
\ 15 |
\ 16 | \ 17 |
\ 18 |
\ 19 |
\ 20 |
', 21 | sourceContent = '\ 22 |

<%=title%>

\ 23 |
\ 24 |

\ 25 | Created <%=$.spring.fn.getDate(created_at)%>\ 26 | <%if(created_at !== updated_at) {%>\ 27 | / Updated <%=$.spring.fn.getDate(updated_at)%>\ 28 | <%}%>\ 29 |

\ 30 |
\ 31 |
\ 32 | <%=#marked(body)%>\ 33 |

<%=comments%> comments / view on github

\ 34 |
', 35 | render = template.compile(source), 36 | renderContent = template.compile(sourceContent) 37 | 38 | var pageLabels = { 39 | route: 'issues/(:number)', 40 | classname: 'issues', 41 | animate: 'slideInLeft', 42 | title: 'Spring', 43 | view: function(pageData) { 44 | var $page = this, 45 | number = pageData.requestData[0], 46 | data = {number: number}, 47 | body = render(data) 48 | 49 | if(!number) { 50 | $doc.trigger('spa:navigate', {hash: '', replace: true}) 51 | } 52 | 53 | $doc.trigger('spa:initpage', [$page, {body: body}]) 54 | }, 55 | init: function(pageData) { 56 | var $view = this, 57 | $container = $('.container', $view), 58 | $issues = $('.issues', $container), 59 | number = $issues.attr('data-number'), 60 | issue = spring.data.issues[number] 61 | 62 | $container.trigger('spa:scroll', {direction: 'y'}) 63 | 64 | if(issue) { 65 | $issues.trigger('issues:render', {issue: issue}) 66 | } else { 67 | var method = '/repos/' + spring.config.owner + '/' + spring.config.repo + '/issues/' + number, 68 | parameters = {} 69 | 70 | spring.fn.request(method, parameters, function(data) { 71 | if(data.meta && data.meta.status === 200) { 72 | issue = data.data 73 | spring.data.issues[number] = issue 74 | 75 | $issues.trigger('issues:render', {issue: issue}) 76 | } else { 77 | $doc.trigger('spa:navigate', {hash: '', replace: true}) 78 | } 79 | }) 80 | } 81 | }, 82 | afteropen: function(pageData) { 83 | } 84 | } 85 | 86 | $doc.on('issues:render', function(event, options) { 87 | var $target = $(event.target), 88 | issue = options.issue 89 | 90 | $target.html(renderContent(issue)) 91 | }) 92 | 93 | $doc.trigger('spa:route', pageLabels) 94 | 95 | })(Zepto, window, document) -------------------------------------------------------------------------------- /js/labels.js: -------------------------------------------------------------------------------- 1 | ;(function($, win, doc) { 2 | 'use strict'; 3 | 4 | var $doc = $(document), 5 | spring = win.spring, 6 | source = '\ 7 |
\ 8 |

<%=$.spring.config.title%>

\ 9 | Menu\ 10 |
\ 11 |
\ 12 |
\ 13 |

Labels / <%=label%>

\ 14 |
\ 15 |
\ 16 | \ 17 |
\ 18 |
\ 19 |
\ 20 |
', 21 | render = template.compile(source) 22 | 23 | var pageLabels = { 24 | route: 'labels/(:label)', 25 | classname: 'labels', 26 | animate: 'fadeIn', 27 | title: 'Spring', 28 | view: function(pageData) { 29 | var $page = this, 30 | label = pageData.requestData[0], 31 | data = {label: label}, 32 | body = render(data) 33 | 34 | if(!label) { 35 | $doc.trigger('spa:navigate', {hash: '', replace: true}) 36 | } 37 | 38 | $doc.trigger('spa:initpage', [$page, {title: $.spring.fn.encodeHtml(label), body: body}]) 39 | }, 40 | init: function(pageData) { 41 | var $view = this, 42 | $container = $('.container', $view), 43 | $issuelist = $('.issuelist', $container) 44 | 45 | $container.trigger('spa:scroll', {direction: 'y'}) 46 | 47 | $container.trigger('pull2refresh:init', { 48 | pullup: function() { 49 | $issuelist.trigger('issuelist:getdata', {pull: 'up', container: $container}) 50 | } 51 | }) 52 | 53 | $container.trigger('pull2refresh:pullup') 54 | }, 55 | afteropen: function(pageData) { 56 | } 57 | } 58 | 59 | $doc.trigger('spa:route', pageLabels) 60 | 61 | })(Zepto, window, document) -------------------------------------------------------------------------------- /js/lib/detect.js: -------------------------------------------------------------------------------- 1 | // Zepto.js 2 | // (c) 2010-2014 Thomas Fuchs 3 | // Zepto.js may be freely distributed under the MIT license. 4 | 5 | ;(function($){ 6 | function detect(ua){ 7 | var os = this.os = {}, browser = this.browser = {}, 8 | webkit = ua.match(/Web[kK]it[\/]{0,1}([\d.]+)/), 9 | android = ua.match(/(Android);?[\s\/]+([\d.]+)?/), 10 | osx = !!ua.match(/\(Macintosh\; Intel /), 11 | ipad = ua.match(/(iPad).*OS\s([\d_]+)/), 12 | ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/), 13 | iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/), 14 | webos = ua.match(/(webOS|hpwOS)[\s\/]([\d.]+)/), 15 | touchpad = webos && ua.match(/TouchPad/), 16 | kindle = ua.match(/Kindle\/([\d.]+)/), 17 | silk = ua.match(/Silk\/([\d._]+)/), 18 | blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/), 19 | bb10 = ua.match(/(BB10).*Version\/([\d.]+)/), 20 | rimtabletos = ua.match(/(RIM\sTablet\sOS)\s([\d.]+)/), 21 | playbook = ua.match(/PlayBook/), 22 | chrome = ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/), 23 | firefox = ua.match(/Firefox\/([\d.]+)/), 24 | ie = ua.match(/MSIE\s([\d.]+)/) || ua.match(/Trident\/[\d](?=[^\?]+).*rv:([0-9.].)/), 25 | webview = !chrome && ua.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/), 26 | safari = webview || ua.match(/Version\/([\d.]+)([^S](Safari)|[^M]*(Mobile)[^S]*(Safari))/) 27 | 28 | // Todo: clean this up with a better OS/browser seperation: 29 | // - discern (more) between multiple browsers on android 30 | // - decide if kindle fire in silk mode is android or not 31 | // - Firefox on Android doesn't specify the Android version 32 | // - possibly devide in os, device and browser hashes 33 | 34 | if (browser.webkit = !!webkit) browser.version = webkit[1] 35 | 36 | if (android) os.android = true, os.version = android[2] 37 | if (iphone && !ipod) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.') 38 | if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.') 39 | if (ipod) os.ios = os.ipod = true, os.version = ipod[3] ? ipod[3].replace(/_/g, '.') : null 40 | if (webos) os.webos = true, os.version = webos[2] 41 | if (touchpad) os.touchpad = true 42 | if (blackberry) os.blackberry = true, os.version = blackberry[2] 43 | if (bb10) os.bb10 = true, os.version = bb10[2] 44 | if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2] 45 | if (playbook) browser.playbook = true 46 | if (kindle) os.kindle = true, os.version = kindle[1] 47 | if (silk) browser.silk = true, browser.version = silk[1] 48 | if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true 49 | if (chrome) browser.chrome = true, browser.version = chrome[1] 50 | if (firefox) browser.firefox = true, browser.version = firefox[1] 51 | if (ie) browser.ie = true, browser.version = ie[1] 52 | if (safari && (osx || os.ios)) {browser.safari = true; if (osx) browser.version = safari[1]} 53 | if (webview) browser.webview = true 54 | 55 | os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) || 56 | (firefox && ua.match(/Tablet/)) || (ie && !ua.match(/Phone/) && ua.match(/Touch/))) 57 | os.phone = !!(!os.tablet && !os.ipod && (android || iphone || webos || blackberry || bb10 || 58 | (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\/([\d.]+)/)) || 59 | (firefox && ua.match(/Mobile/)) || (ie && ua.match(/Touch/)))) 60 | } 61 | 62 | detect.call($, navigator.userAgent) 63 | // make available to unit tests 64 | $.__detect = detect 65 | 66 | })(Zepto) -------------------------------------------------------------------------------- /js/lib/highlight.js: -------------------------------------------------------------------------------- 1 | var hljs=new function(){function k(v){return v.replace(/&/gm,"&").replace(//gm,">")}function t(v){return v.nodeName.toLowerCase()}function i(w,x){var v=w&&w.exec(x);return v&&v.index==0}function d(v){return Array.prototype.map.call(v.childNodes,function(w){if(w.nodeType==3){return b.useBR?w.nodeValue.replace(/\n/g,""):w.nodeValue}if(t(w)=="br"){return"\n"}return d(w)}).join("")}function r(w){var v=(w.className+" "+(w.parentNode?w.parentNode.className:"")).split(/\s+/);v=v.map(function(x){return x.replace(/^language-/,"")});return v.filter(function(x){return j(x)||x=="no-highlight"})[0]}function o(x,y){var v={};for(var w in x){v[w]=x[w]}if(y){for(var w in y){v[w]=y[w]}}return v}function u(x){var v=[];(function w(y,z){for(var A=y.firstChild;A;A=A.nextSibling){if(A.nodeType==3){z+=A.nodeValue.length}else{if(t(A)=="br"){z+=1}else{if(A.nodeType==1){v.push({event:"start",offset:z,node:A});z=w(A,z);v.push({event:"stop",offset:z,node:A})}}}}return z})(x,0);return v}function q(w,y,C){var x=0;var F="";var z=[];function B(){if(!w.length||!y.length){return w.length?w:y}if(w[0].offset!=y[0].offset){return(w[0].offset"}function E(G){F+=""}function v(G){(G.event=="start"?A:E)(G.node)}while(w.length||y.length){var D=B();F+=k(C.substr(x,D[0].offset-x));x=D[0].offset;if(D==w){z.reverse().forEach(E);do{v(D.splice(0,1)[0]);D=B()}while(D==w&&D.length&&D[0].offset==x);z.reverse().forEach(A)}else{if(D[0].event=="start"){z.push(D[0].node)}else{z.pop()}v(D.splice(0,1)[0])}}return F+k(C.substr(x))}function m(y){function v(z){return(z&&z.source)||z}function w(A,z){return RegExp(v(A),"m"+(y.cI?"i":"")+(z?"g":""))}function x(D,C){if(D.compiled){return}D.compiled=true;D.k=D.k||D.bK;if(D.k){var z={};function E(G,F){if(y.cI){F=F.toLowerCase()}F.split(" ").forEach(function(H){var I=H.split("|");z[I[0]]=[G,I[1]?Number(I[1]):1]})}if(typeof D.k=="string"){E("keyword",D.k)}else{Object.keys(D.k).forEach(function(F){E(F,D.k[F])})}D.k=z}D.lR=w(D.l||/\b[A-Za-z0-9_]+\b/,true);if(C){if(D.bK){D.b=D.bK.split(" ").join("|")}if(!D.b){D.b=/\B|\b/}D.bR=w(D.b);if(!D.e&&!D.eW){D.e=/\B|\b/}if(D.e){D.eR=w(D.e)}D.tE=v(D.e)||"";if(D.eW&&C.tE){D.tE+=(D.e?"|":"")+C.tE}}if(D.i){D.iR=w(D.i)}if(D.r===undefined){D.r=1}if(!D.c){D.c=[]}var B=[];D.c.forEach(function(F){if(F.v){F.v.forEach(function(G){B.push(o(F,G))})}else{B.push(F=="self"?D:F)}});D.c=B;D.c.forEach(function(F){x(F,D)});if(D.starts){x(D.starts,C)}var A=D.c.map(function(F){return F.bK?"\\.?\\b("+F.b+")\\b\\.?":F.b}).concat([D.tE]).concat([D.i]).map(v).filter(Boolean);D.t=A.length?w(A.join("|"),true):{exec:function(F){return null}};D.continuation={}}x(y)}function c(S,L,J,R){function v(U,V){for(var T=0;T";U+=Z+'">';return U+X+Y}function N(){var U=k(C);if(!I.k){return U}var T="";var X=0;I.lR.lastIndex=0;var V=I.lR.exec(U);while(V){T+=U.substr(X,V.index-X);var W=E(I,V);if(W){H+=W[1];T+=w(W[0],V[0])}else{T+=V[0]}X=I.lR.lastIndex;V=I.lR.exec(U)}return T+U.substr(X)}function F(){if(I.sL&&!f[I.sL]){return k(C)}var T=I.sL?c(I.sL,C,true,I.continuation.top):g(C);if(I.r>0){H+=T.r}if(I.subLanguageMode=="continuous"){I.continuation.top=T.top}return w(T.language,T.value,false,true)}function Q(){return I.sL!==undefined?F():N()}function P(V,U){var T=V.cN?w(V.cN,"",true):"";if(V.rB){D+=T;C=""}else{if(V.eB){D+=k(U)+T;C=""}else{D+=T;C=U}}I=Object.create(V,{parent:{value:I}})}function G(T,X){C+=T;if(X===undefined){D+=Q();return 0}var V=v(X,I);if(V){D+=Q();P(V,X);return V.rB?0:X.length}var W=z(I,X);if(W){var U=I;if(!(U.rE||U.eE)){C+=X}D+=Q();do{if(I.cN){D+=""}H+=I.r;I=I.parent}while(I!=W.parent);if(U.eE){D+=k(X)}C="";if(W.starts){P(W.starts,"")}return U.rE?0:X.length}if(A(X,I)){throw new Error('Illegal lexeme "'+X+'" for mode "'+(I.cN||"")+'"')}C+=X;return X.length||1}var M=j(S);if(!M){throw new Error('Unknown language: "'+S+'"')}m(M);var I=R||M;var D="";for(var K=I;K!=M;K=K.parent){if(K.cN){D=w(K.cN,D,true)}}var C="";var H=0;try{var B,y,x=0;while(true){I.t.lastIndex=x;B=I.t.exec(L);if(!B){break}y=G(L.substr(x,B.index-x),B[0]);x=B.index+y}G(L.substr(x));for(var K=I;K.parent;K=K.parent){if(K.cN){D+=""}}return{r:H,value:D,language:S,top:I}}catch(O){if(O.message.indexOf("Illegal")!=-1){return{r:0,value:k(L)}}else{throw O}}}function g(y,x){x=x||b.languages||Object.keys(f);var v={r:0,value:k(y)};var w=v;x.forEach(function(z){if(!j(z)){return}var A=c(z,y,false);A.language=z;if(A.r>w.r){w=A}if(A.r>v.r){w=v;v=A}});if(w.language){v.second_best=w}return v}function h(v){if(b.tabReplace){v=v.replace(/^((<[^>]+>|\t)+)/gm,function(w,z,y,x){return z.replace(/\t/g,b.tabReplace)})}if(b.useBR){v=v.replace(/\n/g,"
")}return v}function p(z){var y=d(z);var A=r(z);if(A=="no-highlight"){return}var v=A?c(A,y,true):g(y);var w=u(z);if(w.length){var x=document.createElementNS("http://www.w3.org/1999/xhtml","pre");x.innerHTML=v.value;v.value=q(w,u(x),y)}v.value=h(v.value);z.innerHTML=v.value;z.className+=" hljs "+(!A&&v.language||"");z.result={language:v.language,re:v.r};if(v.second_best){z.second_best={language:v.second_best.language,re:v.second_best.r}}}var b={classPrefix:"hljs-",tabReplace:null,useBR:false,languages:undefined};function s(v){b=o(b,v)}function l(){if(l.called){return}l.called=true;var v=document.querySelectorAll("pre code");Array.prototype.forEach.call(v,p)}function a(){addEventListener("DOMContentLoaded",l,false);addEventListener("load",l,false)}var f={};var n={};function e(v,x){var w=f[v]=x(this);if(w.aliases){w.aliases.forEach(function(y){n[y]=v})}}function j(v){return f[v]||f[n[v]]}this.highlight=c;this.highlightAuto=g;this.fixMarkup=h;this.highlightBlock=p;this.configure=s;this.initHighlighting=l;this.initHighlightingOnLoad=a;this.registerLanguage=e;this.getLanguage=j;this.inherit=o;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE]};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE]};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.REGEXP_MODE={cN:"regexp",b:/\//,e:/\/[gim]*/,i:/\n/,c:[this.BE,{b:/\[/,e:/\]/,r:0,c:[this.BE]}]};this.TM={cN:"title",b:this.IR,r:0};this.UTM={cN:"title",b:this.UIR,r:0}}();hljs.registerLanguage("bash",function(b){var a={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)\}/}]};var d={cN:"string",b:/"/,e:/"/,c:[b.BE,a,{cN:"variable",b:/\$\(/,e:/\)/,c:[b.BE]}]};var c={cN:"string",b:/'/,e:/'/};return{l:/-?[a-z\.]+/,k:{keyword:"if then else elif fi for break continue while in do done exit return set declare case esac export exec",literal:"true false",built_in:"printf echo read cd pwd pushd popd dirs let eval unset typeset readonly getopts source shopt caller type hash bind help sudo",operator:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"shebang",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:true,c:[b.inherit(b.TM,{b:/\w[\w\d_]*/})],r:0},b.HCM,b.NM,d,c,a]}});hljs.registerLanguage("cs",function(b){var a="abstract as base bool break byte case catch char checked const continue decimal default delegate do double else enum event explicit extern false finally fixed float for foreach goto if implicit in int interface internal is lock long new null object operator out override params private protected public readonly ref return sbyte sealed short sizeof stackalloc static string struct switch this throw true try typeof uint ulong unchecked unsafe ushort using virtual volatile void while async await ascending descending from get group into join let orderby partial select set value var where yield";return{k:a,c:[{cN:"comment",b:"///",e:"$",rB:true,c:[{cN:"xmlDocTag",b:"///|"},{cN:"xmlDocTag",b:""}]},b.CLCM,b.CBLCLM,{cN:"preprocessor",b:"#",e:"$",k:"if else elif endif define undef warning error line region endregion pragma checksum"},{cN:"string",b:'@"',e:'"',c:[{b:'""'}]},b.ASM,b.QSM,b.CNM,{bK:"protected public private internal",e:/[{;=]/,k:a,c:[{bK:"class namespace interface",starts:{c:[b.TM]}},{b:b.IR+"\\s*\\(",rB:true,c:[b.TM]}]}]}});hljs.registerLanguage("ruby",function(e){var h="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?";var g="and false then defined module in return redo if BEGIN retry end for true self when next until do begin unless END rescue nil else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor";var a={cN:"yardoctag",b:"@[A-Za-z]+"};var i={cN:"comment",v:[{b:"#",e:"$",c:[a]},{b:"^\\=begin",e:"^\\=end",c:[a],r:10},{b:"^__END__",e:"\\n$"}]};var c={cN:"subst",b:"#\\{",e:"}",k:g};var d={cN:"string",c:[e.BE,c],v:[{b:/'/,e:/'/},{b:/"/,e:/"/},{b:"%[qw]?\\(",e:"\\)"},{b:"%[qw]?\\[",e:"\\]"},{b:"%[qw]?{",e:"}"},{b:"%[qw]?<",e:">",r:10},{b:"%[qw]?/",e:"/",r:10},{b:"%[qw]?%",e:"%",r:10},{b:"%[qw]?-",e:"-",r:10},{b:"%[qw]?\\|",e:"\\|",r:10},{b:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/}]};var b={cN:"params",b:"\\(",e:"\\)",k:g};var f=[d,i,{cN:"class",bK:"class module",e:"$|;",i:/=/,c:[e.inherit(e.TM,{b:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{cN:"inheritance",b:"<\\s*",c:[{cN:"parent",b:"("+e.IR+"::)?"+e.IR}]},i]},{cN:"function",bK:"def",e:" |$|;",r:0,c:[e.inherit(e.TM,{b:h}),b,i]},{cN:"constant",b:"(::)?(\\b[A-Z]\\w*(::)?)+",r:0},{cN:"symbol",b:":",c:[d,{b:h}],r:0},{cN:"symbol",b:e.UIR+"(\\!|\\?)?:",r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{cN:"variable",b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{b:"("+e.RSR+")\\s*",c:[i,{cN:"regexp",c:[e.BE,c],i:/\n/,v:[{b:"/",e:"/[a-z]*"},{b:"%r{",e:"}[a-z]*"},{b:"%r\\(",e:"\\)[a-z]*"},{b:"%r!",e:"![a-z]*"},{b:"%r\\[",e:"\\][a-z]*"}]}],r:0}];c.c=f;b.c=f;return{k:g,c:f}});hljs.registerLanguage("diff",function(a){return{c:[{cN:"chunk",r:10,v:[{b:/^\@\@ +\-\d+,\d+ +\+\d+,\d+ +\@\@$/},{b:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{b:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{cN:"header",v:[{b:/Index: /,e:/$/},{b:/=====/,e:/=====$/},{b:/^\-\-\-/,e:/$/},{b:/^\*{3} /,e:/$/},{b:/^\+\+\+/,e:/$/},{b:/\*{5}/,e:/\*{5}$/}]},{cN:"addition",b:"^\\+",e:"$"},{cN:"deletion",b:"^\\-",e:"$"},{cN:"change",b:"^\\!",e:"$"}]}});hljs.registerLanguage("javascript",function(a){return{aliases:["js"],k:{keyword:"in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const class",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require"},c:[{cN:"pi",b:/^\s*('|")use strict('|")/,r:10},a.ASM,a.QSM,a.CLCM,a.CBLCLM,a.CNM,{b:"("+a.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[a.CLCM,a.CBLCLM,a.REGEXP_MODE,{b:/;/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,c:[a.inherit(a.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,c:[a.CLCM,a.CBLCLM],i:/["'\(]/}],i:/\[|%/},{b:/\$[(.]/},{b:"\\."+a.IR,r:0}]}});hljs.registerLanguage("xml",function(a){var c="[A-Za-z0-9\\._:-]+";var d={b:/<\?(php)?(?!\w)/,e:/\?>/,sL:"php",subLanguageMode:"continuous"};var b={eW:true,i:/]+/}]}]}]};return{aliases:["html"],cI:true,c:[{cN:"doctype",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},{cN:"comment",b:"",r:10},{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"|$)",e:">",k:{title:"style"},c:[b],starts:{e:"",rE:true,sL:"css"}},{cN:"tag",b:"|$)",e:">",k:{title:"script"},c:[b],starts:{e:"<\/script>",rE:true,sL:"javascript"}},{b:"<%",e:"%>",sL:"vbscript"},d,{cN:"pi",b:/<\?\w+/,e:/\?>/,r:10},{cN:"tag",b:"",c:[{cN:"title",b:"[^ /><]+",r:0},b]}]}});hljs.registerLanguage("markdown",function(a){return{c:[{cN:"header",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"blockquote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"`.+?`"},{b:"^( {4}|\t)",e:"$",r:0}]},{cN:"horizontal_rule",b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].+?[\\)\\]]",rB:true,c:[{cN:"link_label",b:"\\[",e:"\\]",eB:true,rE:true,r:0},{cN:"link_url",b:"\\]\\(",e:"\\)",eB:true,eE:true},{cN:"link_reference",b:"\\]\\[",e:"\\]",eB:true,eE:true,}],r:10},{b:"^\\[.+\\]:",e:"$",rB:true,c:[{cN:"link_reference",b:"\\[",e:"\\]",eB:true,eE:true},{cN:"link_url",b:"\\s",e:"$"}]}]}});hljs.registerLanguage("css",function(a){var b="[a-zA-Z-][a-zA-Z0-9_-]*";var c={cN:"function",b:b+"\\(",e:"\\)",c:["self",a.NM,a.ASM,a.QSM]};return{cI:true,i:"[=/|']",c:[a.CBLCLM,{cN:"id",b:"\\#[A-Za-z0-9_-]+"},{cN:"class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"attr_selector",b:"\\[",e:"\\]",i:"$"},{cN:"pseudo",b:":(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\\\"\\']+"},{cN:"at_rule",b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{cN:"at_rule",b:"@",e:"[{;]",c:[{cN:"keyword",b:/\S+/},{b:/\s/,eW:true,eE:true,r:0,c:[c,a.ASM,a.QSM,a.NM]}]},{cN:"tag",b:b,r:0},{cN:"rules",b:"{",e:"}",i:"[^\\s]",r:0,c:[a.CBLCLM,{cN:"rule",b:"[^\\s]",rB:true,e:";",eW:true,c:[{cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:true,i:"[^\\s]",starts:{cN:"value",eW:true,eE:true,c:[c,a.NM,a.QSM,a.ASM,a.CBLCLM,{cN:"hexcolor",b:"#[0-9A-Fa-f]+"},{cN:"important",b:"!important"}]}}]}]}]}});hljs.registerLanguage("http",function(a){return{i:"\\S",c:[{cN:"status",b:"^HTTP/[0-9\\.]+",e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{cN:"request",b:"^[A-Z]+ (.*?) HTTP/[0-9\\.]+$",rB:true,e:"$",c:[{cN:"string",b:" ",e:" ",eB:true,eE:true}]},{cN:"attribute",b:"^\\w",e:": ",eE:true,i:"\\n|\\s|=",starts:{cN:"string",e:"$"}},{b:"\\n\\n",starts:{sL:"",eW:true}}]}});hljs.registerLanguage("java",function(b){var a="false synchronized int abstract float private char boolean static null if const for true while long throw strictfp finally protected import native final return void enum else break transient new catch instanceof byte super volatile case assert short package default double public try this switch continue throws";return{k:a,i:/<\//,c:[{cN:"javadoc",b:"/\\*\\*",e:"\\*/",c:[{cN:"javadoctag",b:"(^|\\s)@[A-Za-z]+"}],r:10},b.CLCM,b.CBLCLM,b.ASM,b.QSM,{bK:"protected public private",e:/[{;=]/,k:a,c:[{cN:"class",bK:"class interface",eW:true,i:/[:"<>]/,c:[{bK:"extends implements",r:10},b.UTM]},{b:b.UIR+"\\s*\\(",rB:true,c:[b.UTM]}]},b.CNM,{cN:"annotation",b:"@[A-Za-z]+"}]}});hljs.registerLanguage("php",function(b){var e={cN:"variable",b:"\\$+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*"};var a={cN:"preprocessor",b:/<\?(php)?|\?>/};var c={cN:"string",c:[b.BE,a],v:[{b:'b"',e:'"'},{b:"b'",e:"'"},b.inherit(b.ASM,{i:null}),b.inherit(b.QSM,{i:null})]};var d={v:[b.BNM,b.CNM]};return{cI:true,k:"and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception default die require __FUNCTION__ enddeclare final try switch continue endfor endif declare unset true false trait goto instanceof insteadof __DIR__ __NAMESPACE__ yield finally",c:[b.CLCM,b.HCM,{cN:"comment",b:"/\\*",e:"\\*/",c:[{cN:"phpdoc",b:"\\s@[A-Za-z]+"},a]},{cN:"comment",b:"__halt_compiler.+?;",eW:true,k:"__halt_compiler",l:b.UIR},{cN:"string",b:"<<<['\"]?\\w+['\"]?$",e:"^\\w+;",c:[b.BE]},a,e,{cN:"function",bK:"function",e:/[;{]/,i:"\\$|\\[|%",c:[b.UTM,{cN:"params",b:"\\(",e:"\\)",c:["self",e,b.CBLCLM,c,d]}]},{cN:"class",bK:"class interface",e:"{",i:/[:\(\$"]/,c:[{bK:"extends implements",r:10},b.UTM]},{bK:"namespace",e:";",i:/[\.']/,c:[b.UTM]},{bK:"use",e:";",c:[b.UTM]},{b:"=>"},c,d]}});hljs.registerLanguage("python",function(a){var f={cN:"prompt",b:/^(>>>|\.\.\.) /};var b={cN:"string",c:[a.BE],v:[{b:/(u|b)?r?'''/,e:/'''/,c:[f],r:10},{b:/(u|b)?r?"""/,e:/"""/,c:[f],r:10},{b:/(u|r|ur)'/,e:/'/,r:10},{b:/(u|r|ur)"/,e:/"/,r:10},{b:/(b|br)'/,e:/'/,},{b:/(b|br)"/,e:/"/,},a.ASM,a.QSM]};var d={cN:"number",r:0,v:[{b:a.BNR+"[lLjJ]?"},{b:"\\b(0o[0-7]+)[lLjJ]?"},{b:a.CNR+"[lLjJ]?"}]};var e={cN:"params",b:/\(/,e:/\)/,c:["self",f,d,b]};var c={e:/:/,i:/[${=;\n]/,c:[a.UTM,e]};return{k:{keyword:"and elif is global as in if from raise for except finally print import pass return exec else break not with class assert yield try while continue del or def lambda nonlocal|10 None True False",built_in:"Ellipsis NotImplemented"},i:/(<\/|->|\?)/,c:[f,d,b,a.HCM,a.inherit(c,{cN:"function",bK:"def",r:10}),a.inherit(c,{cN:"class",bK:"class"}),{cN:"decorator",b:/@/,e:/$/},{b:/\b(print|exec)\(/}]}});hljs.registerLanguage("sql",function(a){return{cI:true,i:/[<>]/,c:[{cN:"operator",b:"\\b(begin|end|start|commit|rollback|savepoint|lock|alter|create|drop|rename|call|delete|do|handler|insert|load|replace|select|truncate|update|set|show|pragma|grant|merge)\\b(?!:)",e:";",eW:true,k:{keyword:"all partial global month current_timestamp using go revoke smallint indicator end-exec disconnect zone with character assertion to add current_user usage input local alter match collate real then rollback get read timestamp session_user not integer bit unique day minute desc insert execute like ilike|2 level decimal drop continue isolation found where constraints domain right national some module transaction relative second connect escape close system_user for deferred section cast current sqlstate allocate intersect deallocate numeric public preserve full goto initially asc no key output collation group by union session both last language constraint column of space foreign deferrable prior connection unknown action commit view or first into float year primary cascaded except restrict set references names table outer open select size are rows from prepare distinct leading create only next inner authorization schema corresponding option declare precision immediate else timezone_minute external varying translation true case exception join hour default double scroll value cursor descriptor values dec fetch procedure delete and false int is describe char as at in varchar null trailing any absolute current_time end grant privileges when cross check write current_date pad begin temporary exec time update catalog user sql date on identity timezone_hour natural whenever interval work order cascade diagnostics nchar having left call do handler load replace truncate start lock show pragma exists number trigger if before after each row merge matched database",aggregate:"count sum min max avg"},c:[{cN:"string",b:"'",e:"'",c:[a.BE,{b:"''"}]},{cN:"string",b:'"',e:'"',c:[a.BE,{b:'""'}]},{cN:"string",b:"`",e:"`",c:[a.BE]},a.CNM]},a.CBLCLM,{cN:"comment",b:"--",e:"$"}]}});hljs.registerLanguage("ini",function(a){return{cI:true,i:/\S/,c:[{cN:"comment",b:";",e:"$"},{cN:"title",b:"^\\[",e:"\\]"},{cN:"setting",b:"^[a-z0-9\\[\\]_-]+[ \\t]*=[ \\t]*",e:"$",c:[{cN:"value",eW:true,k:"on off true false yes no",c:[a.QSM,a.NM],r:0}]}]}});hljs.registerLanguage("perl",function(c){var d="getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qqfileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmgetsub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedirioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when";var f={cN:"subst",b:"[$@]\\{",e:"\\}",k:d};var g={b:"->{",e:"}"};var a={cN:"variable",v:[{b:/\$\d/},{b:/[\$\%\@\*](\^\w\b|#\w+(\:\:\w+)*|{\w+}|\w+(\:\:\w*)*)/},{b:/[\$\%\@\*][^\s\w{]/,r:0}]};var e={cN:"comment",b:"^(__END__|__DATA__)",e:"\\n$",r:5};var h=[c.BE,f,a];var b=[a,c.HCM,e,{cN:"comment",b:"^\\=\\w",e:"\\=cut",eW:true},g,{cN:"string",c:h,v:[{b:"q[qwxr]?\\s*\\(",e:"\\)",r:5},{b:"q[qwxr]?\\s*\\[",e:"\\]",r:5},{b:"q[qwxr]?\\s*\\{",e:"\\}",r:5},{b:"q[qwxr]?\\s*\\|",e:"\\|",r:5},{b:"q[qwxr]?\\s*\\<",e:"\\>",r:5},{b:"qw\\s+q",e:"q",r:5},{b:"'",e:"'",c:[c.BE]},{b:'"',e:'"'},{b:"`",e:"`",c:[c.BE]},{b:"{\\w+}",c:[],r:0},{b:"-?\\w+\\s*\\=\\>",c:[],r:0}]},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{b:"(\\/\\/|"+c.RSR+"|\\b(split|return|print|reverse|grep)\\b)\\s*",k:"split return print reverse grep",r:0,c:[c.HCM,e,{cN:"regexp",b:"(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*",r:10},{cN:"regexp",b:"(m|qr)?/",e:"/[a-z]*",c:[c.BE],r:0}]},{cN:"sub",bK:"sub",e:"(\\s*\\(.*?\\))?[;{]",r:5},{cN:"operator",b:"-\\w\\b",r:0}];f.c=b;g.c=b;return{k:d,c:b}});hljs.registerLanguage("objectivec",function(a){var d={keyword:"int float while char export sizeof typedef const struct for union unsigned long volatile static bool mutable if do return goto void enum else break extern asm case short default double register explicit signed typename this switch continue wchar_t inline readonly assign self synchronized id nonatomic super unichar IBOutlet IBAction strong weak @private @protected @public @try @property @end @throw @catch @finally @synthesize @dynamic @selector @optional @required",literal:"false true FALSE TRUE nil YES NO NULL",built_in:"NSString NSDictionary CGRect CGPoint UIButton UILabel UITextView UIWebView MKMapView UISegmentedControl NSObject UITableViewDelegate UITableViewDataSource NSThread UIActivityIndicator UITabbar UIToolBar UIBarButtonItem UIImageView NSAutoreleasePool UITableView BOOL NSInteger CGFloat NSException NSLog NSMutableString NSMutableArray NSMutableDictionary NSURL NSIndexPath CGSize UITableViewCell UIView UIViewController UINavigationBar UINavigationController UITabBarController UIPopoverController UIPopoverControllerDelegate UIImage NSNumber UISearchBar NSFetchedResultsController NSFetchedResultsChangeType UIScrollView UIScrollViewDelegate UIEdgeInsets UIColor UIFont UIApplication NSNotFound NSNotificationCenter NSNotification UILocalNotification NSBundle NSFileManager NSTimeInterval NSDate NSCalendar NSUserDefaults UIWindow NSRange NSArray NSError NSURLRequest NSURLConnection UIInterfaceOrientation MPMoviePlayerController dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once"};var c=/[a-zA-Z@][a-zA-Z0-9_]*/;var b="@interface @class @protocol @implementation";return{k:d,l:c,i:""}]},{cN:"preprocessor",b:"#",e:"$"},{cN:"class",b:"("+b.split(" ").join("|")+")\\b",e:"({|$)",k:b,l:c,c:[a.UTM]},{cN:"variable",b:"\\."+a.UIR,r:0}]}});hljs.registerLanguage("coffeescript",function(c){var b={keyword:"in if for while finally new do return else break catch instanceof throw try this switch continue typeof delete debugger super then unless until loop of by when and or is isnt not",literal:"true false null undefined yes no on off",reserved:"case default function var void with const let enum export import native __hasProp __extends __slice __bind __indexOf",built_in:"npm require console print module exports global window document"};var a="[A-Za-z$_][0-9A-Za-z$_]*";var f=c.inherit(c.TM,{b:a});var e={cN:"subst",b:/#\{/,e:/}/,k:b};var d=[c.BNM,c.inherit(c.CNM,{starts:{e:"(\\s*/)?",r:0}}),{cN:"string",v:[{b:/'''/,e:/'''/,c:[c.BE]},{b:/'/,e:/'/,c:[c.BE]},{b:/"""/,e:/"""/,c:[c.BE,e]},{b:/"/,e:/"/,c:[c.BE,e]}]},{cN:"regexp",v:[{b:"///",e:"///",c:[e,c.HCM]},{b:"//[gim]*",r:0},{b:"/\\S(\\\\.|[^\\n])*?/[gim]*(?=\\s|\\W|$)"}]},{cN:"property",b:"@"+a},{b:"`",e:"`",eB:true,eE:true,sL:"javascript"}];e.c=d;return{k:b,c:d.concat([{cN:"comment",b:"###",e:"###"},c.HCM,{cN:"function",b:"("+a+"\\s*=\\s*)?(\\(.*\\))?\\s*\\B[-=]>",e:"[-=]>",rB:true,c:[f,{cN:"params",b:"\\(",rB:true,c:[{b:/\(/,e:/\)/,k:b,c:["self"].concat(d)}]}]},{cN:"class",bK:"class",e:"$",i:/[:="\[\]]/,c:[{bK:"extends",eW:true,i:/[:="\[\]]/,c:[f]},f]},{cN:"attribute",b:a+":",e:":",rB:true,eE:true,r:0}])}});hljs.registerLanguage("nginx",function(c){var b={cN:"variable",v:[{b:/\$\d+/},{b:/\$\{/,e:/}/},{b:"[\\$\\@]"+c.UIR}]};var a={eW:true,l:"[a-z/_]+",k:{built_in:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll"},r:0,i:"=>",c:[c.HCM,{cN:"string",c:[c.BE,b],v:[{b:/"/,e:/"/},{b:/'/,e:/'/}]},{cN:"url",b:"([a-z]+):/",e:"\\s",eW:true,eE:true},{cN:"regexp",c:[c.BE,b],v:[{b:"\\s\\^",e:"\\s|{|;",rE:true},{b:"~\\*?\\s+",e:"\\s|{|;",rE:true},{b:"\\*(\\.[a-z\\-]+)+"},{b:"([a-z\\-]+\\.)+\\*"}]},{cN:"number",b:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{cN:"number",b:"\\b\\d+[kKmMgGdshdwy]*\\b",r:0},b]};return{c:[c.HCM,{b:c.UIR+"\\s",e:";|{",rB:true,c:[c.inherit(c.UTM,{starts:a})],r:0}],i:"[^\\s\\}]"}});hljs.registerLanguage("json",function(a){var e={literal:"true false null"};var d=[a.QSM,a.CNM];var c={cN:"value",e:",",eW:true,eE:true,c:d,k:e};var b={b:"{",e:"}",c:[{cN:"attribute",b:'\\s*"',e:'"\\s*:\\s*',eB:true,eE:true,c:[a.BE],i:"\\n",starts:c}],i:"\\S"};var f={b:"\\[",e:"\\]",c:[a.inherit(c,{cN:null})],i:"\\S"};d.splice(d.length,0,b,f);return{c:d,k:e,i:"\\S"}});hljs.registerLanguage("apache",function(a){var b={cN:"number",b:"[\\$%]\\d+"};return{cI:true,c:[a.HCM,{cN:"tag",b:""},{cN:"keyword",b:/\w+/,r:0,k:{common:"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername"},starts:{e:/$/,r:0,k:{literal:"on off all"},c:[{cN:"sqbracket",b:"\\s\\[",e:"\\]$"},{cN:"cbracket",b:"[\\$%]\\{",e:"\\}",c:["self",b]},b,a.QSM]}}],i:/\S/}});hljs.registerLanguage("cpp",function(a){var b={keyword:"false int float while private char catch export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const struct for static_cast|10 union namespace unsigned long throw volatile static protected bool template mutable if public friend do return goto auto void enum else break new extern using true class asm case typeid short reinterpret_cast|10 default double register explicit signed typename try this switch continue wchar_t inline delete alignof char16_t char32_t constexpr decltype noexcept nullptr static_assert thread_local restrict _Bool complex _Complex _Imaginary",built_in:"std string cin cout cerr clog stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap array shared_ptr abort abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf"};return{aliases:["c"],k:b,i:"",i:"\\n"},a.CLCM]},{cN:"stl_container",b:"\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<",e:">",k:b,r:10,c:["self"]}]}});hljs.registerLanguage("makefile",function(a){var b={cN:"variable",b:/\$\(/,e:/\)/,c:[a.BE]};return{c:[a.HCM,{b:/^\w+\s*\W*=/,rB:true,r:0,starts:{cN:"constant",e:/\s*\W*=/,eE:true,starts:{e:/$/,r:0,c:[b],}}},{cN:"title",b:/^[\w]+:\s*$/},{cN:"phony",b:/^\.PHONY:/,e:/$/,k:".PHONY",l:/[\.\w]+/},{b:/^\t+/,e:/$/,c:[a.QSM,b]}]}}); -------------------------------------------------------------------------------- /js/lib/marked.js: -------------------------------------------------------------------------------- 1 | /** 2 | * marked - a markdown parser 3 | * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed) 4 | * https://github.com/chjj/marked 5 | */ 6 | 7 | ;(function() { 8 | 9 | /** 10 | * Block-Level Grammar 11 | */ 12 | 13 | var block = { 14 | newline: /^\n+/, 15 | code: /^( {4}[^\n]+\n*)+/, 16 | fences: noop, 17 | hr: /^( *[-*_]){3,} *(?:\n+|$)/, 18 | heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/, 19 | nptable: noop, 20 | lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/, 21 | blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/, 22 | list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/, 23 | html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/, 24 | def: /^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/, 25 | table: noop, 26 | paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/, 27 | text: /^[^\n]+/ 28 | }; 29 | 30 | block.bullet = /(?:[*+-]|\d+\.)/; 31 | block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/; 32 | block.item = replace(block.item, 'gm') 33 | (/bull/g, block.bullet) 34 | (); 35 | 36 | block.list = replace(block.list) 37 | (/bull/g, block.bullet) 38 | ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))') 39 | ('def', '\\n+(?=' + block.def.source + ')') 40 | (); 41 | 42 | block.blockquote = replace(block.blockquote) 43 | ('def', block.def) 44 | (); 45 | 46 | block._tag = '(?!(?:' 47 | + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code' 48 | + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo' 49 | + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b'; 50 | 51 | block.html = replace(block.html) 52 | ('comment', //) 53 | ('closed', /<(tag)[\s\S]+?<\/\1>/) 54 | ('closing', /])*?>/) 55 | (/tag/g, block._tag) 56 | (); 57 | 58 | block.paragraph = replace(block.paragraph) 59 | ('hr', block.hr) 60 | ('heading', block.heading) 61 | ('lheading', block.lheading) 62 | ('blockquote', block.blockquote) 63 | ('tag', '<' + block._tag) 64 | ('def', block.def) 65 | (); 66 | 67 | /** 68 | * Normal Block Grammar 69 | */ 70 | 71 | block.normal = merge({}, block); 72 | 73 | /** 74 | * GFM Block Grammar 75 | */ 76 | 77 | block.gfm = merge({}, block.normal, { 78 | fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/, 79 | paragraph: /^/ 80 | }); 81 | 82 | block.gfm.paragraph = replace(block.paragraph) 83 | ('(?!', '(?!' 84 | + block.gfm.fences.source.replace('\\1', '\\2') + '|' 85 | + block.list.source.replace('\\1', '\\3') + '|') 86 | (); 87 | 88 | /** 89 | * GFM + Tables Block Grammar 90 | */ 91 | 92 | block.tables = merge({}, block.gfm, { 93 | nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/, 94 | table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/ 95 | }); 96 | 97 | /** 98 | * Block Lexer 99 | */ 100 | 101 | function Lexer(options) { 102 | this.tokens = []; 103 | this.tokens.links = {}; 104 | this.options = options || marked.defaults; 105 | this.rules = block.normal; 106 | 107 | if (this.options.gfm) { 108 | if (this.options.tables) { 109 | this.rules = block.tables; 110 | } else { 111 | this.rules = block.gfm; 112 | } 113 | } 114 | } 115 | 116 | /** 117 | * Expose Block Rules 118 | */ 119 | 120 | Lexer.rules = block; 121 | 122 | /** 123 | * Static Lex Method 124 | */ 125 | 126 | Lexer.lex = function(src, options) { 127 | var lexer = new Lexer(options); 128 | return lexer.lex(src); 129 | }; 130 | 131 | /** 132 | * Preprocessing 133 | */ 134 | 135 | Lexer.prototype.lex = function(src) { 136 | src = src 137 | .replace(/\r\n|\r/g, '\n') 138 | .replace(/\t/g, ' ') 139 | .replace(/\u00a0/g, ' ') 140 | .replace(/\u2424/g, '\n'); 141 | 142 | return this.token(src, true); 143 | }; 144 | 145 | /** 146 | * Lexing 147 | */ 148 | 149 | Lexer.prototype.token = function(src, top, bq) { 150 | var src = src.replace(/^ +$/gm, '') 151 | , next 152 | , loose 153 | , cap 154 | , bull 155 | , b 156 | , item 157 | , space 158 | , i 159 | , l; 160 | 161 | while (src) { 162 | // newline 163 | if (cap = this.rules.newline.exec(src)) { 164 | src = src.substring(cap[0].length); 165 | if (cap[0].length > 1) { 166 | this.tokens.push({ 167 | type: 'space' 168 | }); 169 | } 170 | } 171 | 172 | // code 173 | if (cap = this.rules.code.exec(src)) { 174 | src = src.substring(cap[0].length); 175 | cap = cap[0].replace(/^ {4}/gm, ''); 176 | this.tokens.push({ 177 | type: 'code', 178 | text: !this.options.pedantic 179 | ? cap.replace(/\n+$/, '') 180 | : cap 181 | }); 182 | continue; 183 | } 184 | 185 | // fences (gfm) 186 | if (cap = this.rules.fences.exec(src)) { 187 | src = src.substring(cap[0].length); 188 | this.tokens.push({ 189 | type: 'code', 190 | lang: cap[2], 191 | text: cap[3] 192 | }); 193 | continue; 194 | } 195 | 196 | // heading 197 | if (cap = this.rules.heading.exec(src)) { 198 | src = src.substring(cap[0].length); 199 | this.tokens.push({ 200 | type: 'heading', 201 | depth: cap[1].length, 202 | text: cap[2] 203 | }); 204 | continue; 205 | } 206 | 207 | // table no leading pipe (gfm) 208 | if (top && (cap = this.rules.nptable.exec(src))) { 209 | src = src.substring(cap[0].length); 210 | 211 | item = { 212 | type: 'table', 213 | header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */), 214 | align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), 215 | cells: cap[3].replace(/\n$/, '').split('\n') 216 | }; 217 | 218 | for (i = 0; i < item.align.length; i++) { 219 | if (/^ *-+: *$/.test(item.align[i])) { 220 | item.align[i] = 'right'; 221 | } else if (/^ *:-+: *$/.test(item.align[i])) { 222 | item.align[i] = 'center'; 223 | } else if (/^ *:-+ *$/.test(item.align[i])) { 224 | item.align[i] = 'left'; 225 | } else { 226 | item.align[i] = null; 227 | } 228 | } 229 | 230 | for (i = 0; i < item.cells.length; i++) { 231 | item.cells[i] = item.cells[i].split(/ *\| */); 232 | } 233 | 234 | this.tokens.push(item); 235 | 236 | continue; 237 | } 238 | 239 | // lheading 240 | if (cap = this.rules.lheading.exec(src)) { 241 | src = src.substring(cap[0].length); 242 | this.tokens.push({ 243 | type: 'heading', 244 | depth: cap[2] === '=' ? 1 : 2, 245 | text: cap[1] 246 | }); 247 | continue; 248 | } 249 | 250 | // hr 251 | if (cap = this.rules.hr.exec(src)) { 252 | src = src.substring(cap[0].length); 253 | this.tokens.push({ 254 | type: 'hr' 255 | }); 256 | continue; 257 | } 258 | 259 | // blockquote 260 | if (cap = this.rules.blockquote.exec(src)) { 261 | src = src.substring(cap[0].length); 262 | 263 | this.tokens.push({ 264 | type: 'blockquote_start' 265 | }); 266 | 267 | cap = cap[0].replace(/^ *> ?/gm, ''); 268 | 269 | // Pass `top` to keep the current 270 | // "toplevel" state. This is exactly 271 | // how markdown.pl works. 272 | this.token(cap, top, true); 273 | 274 | this.tokens.push({ 275 | type: 'blockquote_end' 276 | }); 277 | 278 | continue; 279 | } 280 | 281 | // list 282 | if (cap = this.rules.list.exec(src)) { 283 | src = src.substring(cap[0].length); 284 | bull = cap[2]; 285 | 286 | this.tokens.push({ 287 | type: 'list_start', 288 | ordered: bull.length > 1 289 | }); 290 | 291 | // Get each top-level item. 292 | cap = cap[0].match(this.rules.item); 293 | 294 | next = false; 295 | l = cap.length; 296 | i = 0; 297 | 298 | for (; i < l; i++) { 299 | item = cap[i]; 300 | 301 | // Remove the list item's bullet 302 | // so it is seen as the next token. 303 | space = item.length; 304 | item = item.replace(/^ *([*+-]|\d+\.) +/, ''); 305 | 306 | // Outdent whatever the 307 | // list item contains. Hacky. 308 | if (~item.indexOf('\n ')) { 309 | space -= item.length; 310 | item = !this.options.pedantic 311 | ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') 312 | : item.replace(/^ {1,4}/gm, ''); 313 | } 314 | 315 | // Determine whether the next list item belongs here. 316 | // Backpedal if it does not belong in this list. 317 | if (this.options.smartLists && i !== l - 1) { 318 | b = block.bullet.exec(cap[i + 1])[0]; 319 | if (bull !== b && !(bull.length > 1 && b.length > 1)) { 320 | src = cap.slice(i + 1).join('\n') + src; 321 | i = l - 1; 322 | } 323 | } 324 | 325 | // Determine whether item is loose or not. 326 | // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ 327 | // for discount behavior. 328 | loose = next || /\n\n(?!\s*$)/.test(item); 329 | if (i !== l - 1) { 330 | next = item.charAt(item.length - 1) === '\n'; 331 | if (!loose) loose = next; 332 | } 333 | 334 | this.tokens.push({ 335 | type: loose 336 | ? 'loose_item_start' 337 | : 'list_item_start' 338 | }); 339 | 340 | // Recurse. 341 | this.token(item, false, bq); 342 | 343 | this.tokens.push({ 344 | type: 'list_item_end' 345 | }); 346 | } 347 | 348 | this.tokens.push({ 349 | type: 'list_end' 350 | }); 351 | 352 | continue; 353 | } 354 | 355 | // html 356 | if (cap = this.rules.html.exec(src)) { 357 | src = src.substring(cap[0].length); 358 | this.tokens.push({ 359 | type: this.options.sanitize 360 | ? 'paragraph' 361 | : 'html', 362 | pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style', 363 | text: cap[0] 364 | }); 365 | continue; 366 | } 367 | 368 | // def 369 | if ((!bq && top) && (cap = this.rules.def.exec(src))) { 370 | src = src.substring(cap[0].length); 371 | this.tokens.links[cap[1].toLowerCase()] = { 372 | href: cap[2], 373 | title: cap[3] 374 | }; 375 | continue; 376 | } 377 | 378 | // table (gfm) 379 | if (top && (cap = this.rules.table.exec(src))) { 380 | src = src.substring(cap[0].length); 381 | 382 | item = { 383 | type: 'table', 384 | header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */), 385 | align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), 386 | cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n') 387 | }; 388 | 389 | for (i = 0; i < item.align.length; i++) { 390 | if (/^ *-+: *$/.test(item.align[i])) { 391 | item.align[i] = 'right'; 392 | } else if (/^ *:-+: *$/.test(item.align[i])) { 393 | item.align[i] = 'center'; 394 | } else if (/^ *:-+ *$/.test(item.align[i])) { 395 | item.align[i] = 'left'; 396 | } else { 397 | item.align[i] = null; 398 | } 399 | } 400 | 401 | for (i = 0; i < item.cells.length; i++) { 402 | item.cells[i] = item.cells[i] 403 | .replace(/^ *\| *| *\| *$/g, '') 404 | .split(/ *\| */); 405 | } 406 | 407 | this.tokens.push(item); 408 | 409 | continue; 410 | } 411 | 412 | // top-level paragraph 413 | if (top && (cap = this.rules.paragraph.exec(src))) { 414 | src = src.substring(cap[0].length); 415 | this.tokens.push({ 416 | type: 'paragraph', 417 | text: cap[1].charAt(cap[1].length - 1) === '\n' 418 | ? cap[1].slice(0, -1) 419 | : cap[1] 420 | }); 421 | continue; 422 | } 423 | 424 | // text 425 | if (cap = this.rules.text.exec(src)) { 426 | // Top-level should never reach here. 427 | src = src.substring(cap[0].length); 428 | this.tokens.push({ 429 | type: 'text', 430 | text: cap[0] 431 | }); 432 | continue; 433 | } 434 | 435 | if (src) { 436 | throw new 437 | Error('Infinite loop on byte: ' + src.charCodeAt(0)); 438 | } 439 | } 440 | 441 | return this.tokens; 442 | }; 443 | 444 | /** 445 | * Inline-Level Grammar 446 | */ 447 | 448 | var inline = { 449 | escape: /^\\([\\`*{}\[\]()#+\-.!_>])/, 450 | autolink: /^<([^ >]+(@|:\/)[^ >]+)>/, 451 | url: noop, 452 | tag: /^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/, 453 | link: /^!?\[(inside)\]\(href\)/, 454 | reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/, 455 | nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/, 456 | strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/, 457 | em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/, 458 | code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/, 459 | br: /^ {2,}\n(?!\s*$)/, 460 | del: noop, 461 | text: /^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/; 466 | 467 | inline.link = replace(inline.link) 468 | ('inside', inline._inside) 469 | ('href', inline._href) 470 | (); 471 | 472 | inline.reflink = replace(inline.reflink) 473 | ('inside', inline._inside) 474 | (); 475 | 476 | /** 477 | * Normal Inline Grammar 478 | */ 479 | 480 | inline.normal = merge({}, inline); 481 | 482 | /** 483 | * Pedantic Inline Grammar 484 | */ 485 | 486 | inline.pedantic = merge({}, inline.normal, { 487 | strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/, 488 | em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/ 489 | }); 490 | 491 | /** 492 | * GFM Inline Grammar 493 | */ 494 | 495 | inline.gfm = merge({}, inline.normal, { 496 | escape: replace(inline.escape)('])', '~|])')(), 497 | url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/, 498 | del: /^~~(?=\S)([\s\S]*?\S)~~/, 499 | text: replace(inline.text) 500 | (']|', '~]|') 501 | ('|', '|https?://|') 502 | () 503 | }); 504 | 505 | /** 506 | * GFM + Line Breaks Inline Grammar 507 | */ 508 | 509 | inline.breaks = merge({}, inline.gfm, { 510 | br: replace(inline.br)('{2,}', '*')(), 511 | text: replace(inline.gfm.text)('{2,}', '*')() 512 | }); 513 | 514 | /** 515 | * Inline Lexer & Compiler 516 | */ 517 | 518 | function InlineLexer(links, options) { 519 | this.options = options || marked.defaults; 520 | this.links = links; 521 | this.rules = inline.normal; 522 | this.renderer = this.options.renderer || new Renderer; 523 | this.renderer.options = this.options; 524 | 525 | if (!this.links) { 526 | throw new 527 | Error('Tokens array requires a `links` property.'); 528 | } 529 | 530 | if (this.options.gfm) { 531 | if (this.options.breaks) { 532 | this.rules = inline.breaks; 533 | } else { 534 | this.rules = inline.gfm; 535 | } 536 | } else if (this.options.pedantic) { 537 | this.rules = inline.pedantic; 538 | } 539 | } 540 | 541 | /** 542 | * Expose Inline Rules 543 | */ 544 | 545 | InlineLexer.rules = inline; 546 | 547 | /** 548 | * Static Lexing/Compiling Method 549 | */ 550 | 551 | InlineLexer.output = function(src, links, options) { 552 | var inline = new InlineLexer(links, options); 553 | return inline.output(src); 554 | }; 555 | 556 | /** 557 | * Lexing/Compiling 558 | */ 559 | 560 | InlineLexer.prototype.output = function(src) { 561 | var out = '' 562 | , link 563 | , text 564 | , href 565 | , cap; 566 | 567 | while (src) { 568 | // escape 569 | if (cap = this.rules.escape.exec(src)) { 570 | src = src.substring(cap[0].length); 571 | out += cap[1]; 572 | continue; 573 | } 574 | 575 | // autolink 576 | if (cap = this.rules.autolink.exec(src)) { 577 | src = src.substring(cap[0].length); 578 | if (cap[2] === '@') { 579 | text = cap[1].charAt(6) === ':' 580 | ? this.mangle(cap[1].substring(7)) 581 | : this.mangle(cap[1]); 582 | href = this.mangle('mailto:') + text; 583 | } else { 584 | text = escape(cap[1]); 585 | href = text; 586 | } 587 | out += this.renderer.link(href, null, text); 588 | continue; 589 | } 590 | 591 | // url (gfm) 592 | if (!this.inLink && (cap = this.rules.url.exec(src))) { 593 | src = src.substring(cap[0].length); 594 | text = escape(cap[1]); 595 | href = text; 596 | out += this.renderer.link(href, null, text); 597 | continue; 598 | } 599 | 600 | // tag 601 | if (cap = this.rules.tag.exec(src)) { 602 | if (!this.inLink && /^/i.test(cap[0])) { 605 | this.inLink = false; 606 | } 607 | src = src.substring(cap[0].length); 608 | out += this.options.sanitize 609 | ? escape(cap[0]) 610 | : cap[0]; 611 | continue; 612 | } 613 | 614 | // link 615 | if (cap = this.rules.link.exec(src)) { 616 | src = src.substring(cap[0].length); 617 | this.inLink = true; 618 | out += this.outputLink(cap, { 619 | href: cap[2], 620 | title: cap[3] 621 | }); 622 | this.inLink = false; 623 | continue; 624 | } 625 | 626 | // reflink, nolink 627 | if ((cap = this.rules.reflink.exec(src)) 628 | || (cap = this.rules.nolink.exec(src))) { 629 | src = src.substring(cap[0].length); 630 | link = (cap[2] || cap[1]).replace(/\s+/g, ' '); 631 | link = this.links[link.toLowerCase()]; 632 | if (!link || !link.href) { 633 | out += cap[0].charAt(0); 634 | src = cap[0].substring(1) + src; 635 | continue; 636 | } 637 | this.inLink = true; 638 | out += this.outputLink(cap, link); 639 | this.inLink = false; 640 | continue; 641 | } 642 | 643 | // strong 644 | if (cap = this.rules.strong.exec(src)) { 645 | src = src.substring(cap[0].length); 646 | out += this.renderer.strong(this.output(cap[2] || cap[1])); 647 | continue; 648 | } 649 | 650 | // em 651 | if (cap = this.rules.em.exec(src)) { 652 | src = src.substring(cap[0].length); 653 | out += this.renderer.em(this.output(cap[2] || cap[1])); 654 | continue; 655 | } 656 | 657 | // code 658 | if (cap = this.rules.code.exec(src)) { 659 | src = src.substring(cap[0].length); 660 | out += this.renderer.codespan(escape(cap[2], true)); 661 | continue; 662 | } 663 | 664 | // br 665 | if (cap = this.rules.br.exec(src)) { 666 | src = src.substring(cap[0].length); 667 | out += this.renderer.br(); 668 | continue; 669 | } 670 | 671 | // del (gfm) 672 | if (cap = this.rules.del.exec(src)) { 673 | src = src.substring(cap[0].length); 674 | out += this.renderer.del(this.output(cap[1])); 675 | continue; 676 | } 677 | 678 | // text 679 | if (cap = this.rules.text.exec(src)) { 680 | src = src.substring(cap[0].length); 681 | out += escape(this.smartypants(cap[0])); 682 | continue; 683 | } 684 | 685 | if (src) { 686 | throw new 687 | Error('Infinite loop on byte: ' + src.charCodeAt(0)); 688 | } 689 | } 690 | 691 | return out; 692 | }; 693 | 694 | /** 695 | * Compile Link 696 | */ 697 | 698 | InlineLexer.prototype.outputLink = function(cap, link) { 699 | var href = escape(link.href) 700 | , title = link.title ? escape(link.title) : null; 701 | 702 | return cap[0].charAt(0) !== '!' 703 | ? this.renderer.link(href, title, this.output(cap[1])) 704 | : this.renderer.image(href, title, escape(cap[1])); 705 | }; 706 | 707 | /** 708 | * Smartypants Transformations 709 | */ 710 | 711 | InlineLexer.prototype.smartypants = function(text) { 712 | if (!this.options.smartypants) return text; 713 | return text 714 | // em-dashes 715 | .replace(/--/g, '\u2014') 716 | // opening singles 717 | .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018') 718 | // closing singles & apostrophes 719 | .replace(/'/g, '\u2019') 720 | // opening doubles 721 | .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c') 722 | // closing doubles 723 | .replace(/"/g, '\u201d') 724 | // ellipses 725 | .replace(/\.{3}/g, '\u2026'); 726 | }; 727 | 728 | /** 729 | * Mangle Links 730 | */ 731 | 732 | InlineLexer.prototype.mangle = function(text) { 733 | var out = '' 734 | , l = text.length 735 | , i = 0 736 | , ch; 737 | 738 | for (; i < l; i++) { 739 | ch = text.charCodeAt(i); 740 | if (Math.random() > 0.5) { 741 | ch = 'x' + ch.toString(16); 742 | } 743 | out += '&#' + ch + ';'; 744 | } 745 | 746 | return out; 747 | }; 748 | 749 | /** 750 | * Renderer 751 | */ 752 | 753 | function Renderer(options) { 754 | this.options = options || {}; 755 | } 756 | 757 | Renderer.prototype.code = function(code, lang, escaped) { 758 | if (this.options.highlight) { 759 | var out = this.options.highlight(code, lang); 760 | if (out != null && out !== code) { 761 | escaped = true; 762 | code = out; 763 | } 764 | } 765 | 766 | if (!lang) { 767 | return '
'
 768 |       + (escaped ? code : escape(code, true))
 769 |       + '\n
'; 770 | } 771 | 772 | return '
'
 776 |     + (escaped ? code : escape(code, true))
 777 |     + '\n
\n'; 778 | }; 779 | 780 | Renderer.prototype.blockquote = function(quote) { 781 | return '
\n' + quote + '
\n'; 782 | }; 783 | 784 | Renderer.prototype.html = function(html) { 785 | return html; 786 | }; 787 | 788 | Renderer.prototype.heading = function(text, level, raw) { 789 | return '' 795 | + text 796 | + '\n'; 799 | }; 800 | 801 | Renderer.prototype.hr = function() { 802 | return this.options.xhtml ? '
\n' : '
\n'; 803 | }; 804 | 805 | Renderer.prototype.list = function(body, ordered) { 806 | var type = ordered ? 'ol' : 'ul'; 807 | return '<' + type + '>\n' + body + '\n'; 808 | }; 809 | 810 | Renderer.prototype.listitem = function(text) { 811 | return '
  • ' + text + '
  • \n'; 812 | }; 813 | 814 | Renderer.prototype.paragraph = function(text) { 815 | return '

    ' + text + '

    \n'; 816 | }; 817 | 818 | Renderer.prototype.table = function(header, body) { 819 | return '\n' 820 | + '\n' 821 | + header 822 | + '\n' 823 | + '\n' 824 | + body 825 | + '\n' 826 | + '
    \n'; 827 | }; 828 | 829 | Renderer.prototype.tablerow = function(content) { 830 | return '\n' + content + '\n'; 831 | }; 832 | 833 | Renderer.prototype.tablecell = function(content, flags) { 834 | var type = flags.header ? 'th' : 'td'; 835 | var tag = flags.align 836 | ? '<' + type + ' style="text-align:' + flags.align + '">' 837 | : '<' + type + '>'; 838 | return tag + content + '\n'; 839 | }; 840 | 841 | // span level renderer 842 | Renderer.prototype.strong = function(text) { 843 | return '' + text + ''; 844 | }; 845 | 846 | Renderer.prototype.em = function(text) { 847 | return '' + text + ''; 848 | }; 849 | 850 | Renderer.prototype.codespan = function(text) { 851 | return '' + text + ''; 852 | }; 853 | 854 | Renderer.prototype.br = function() { 855 | return this.options.xhtml ? '
    ' : '
    '; 856 | }; 857 | 858 | Renderer.prototype.del = function(text) { 859 | return '' + text + ''; 860 | }; 861 | 862 | Renderer.prototype.link = function(href, title, text) { 863 | if (this.options.sanitize) { 864 | try { 865 | var prot = decodeURIComponent(unescape(href)) 866 | .replace(/[^\w:]/g, '') 867 | .toLowerCase(); 868 | } catch (e) { 869 | return ''; 870 | } 871 | if (prot.indexOf('javascript:') === 0) { 872 | return ''; 873 | } 874 | } 875 | var out = '
    '; 880 | return out; 881 | }; 882 | 883 | Renderer.prototype.image = function(href, title, text) { 884 | var out = '' + text + '' : '>'; 889 | return out; 890 | }; 891 | 892 | /** 893 | * Parsing & Compiling 894 | */ 895 | 896 | function Parser(options) { 897 | this.tokens = []; 898 | this.token = null; 899 | this.options = options || marked.defaults; 900 | this.options.renderer = this.options.renderer || new Renderer; 901 | this.renderer = this.options.renderer; 902 | this.renderer.options = this.options; 903 | } 904 | 905 | /** 906 | * Static Parse Method 907 | */ 908 | 909 | Parser.parse = function(src, options, renderer) { 910 | var parser = new Parser(options, renderer); 911 | return parser.parse(src); 912 | }; 913 | 914 | /** 915 | * Parse Loop 916 | */ 917 | 918 | Parser.prototype.parse = function(src) { 919 | this.inline = new InlineLexer(src.links, this.options, this.renderer); 920 | this.tokens = src.reverse(); 921 | 922 | var out = ''; 923 | while (this.next()) { 924 | out += this.tok(); 925 | } 926 | 927 | return out; 928 | }; 929 | 930 | /** 931 | * Next Token 932 | */ 933 | 934 | Parser.prototype.next = function() { 935 | return this.token = this.tokens.pop(); 936 | }; 937 | 938 | /** 939 | * Preview Next Token 940 | */ 941 | 942 | Parser.prototype.peek = function() { 943 | return this.tokens[this.tokens.length - 1] || 0; 944 | }; 945 | 946 | /** 947 | * Parse Text Tokens 948 | */ 949 | 950 | Parser.prototype.parseText = function() { 951 | var body = this.token.text; 952 | 953 | while (this.peek().type === 'text') { 954 | body += '\n' + this.next().text; 955 | } 956 | 957 | return this.inline.output(body); 958 | }; 959 | 960 | /** 961 | * Parse Current Token 962 | */ 963 | 964 | Parser.prototype.tok = function() { 965 | switch (this.token.type) { 966 | case 'space': { 967 | return ''; 968 | } 969 | case 'hr': { 970 | return this.renderer.hr(); 971 | } 972 | case 'heading': { 973 | return this.renderer.heading( 974 | this.inline.output(this.token.text), 975 | this.token.depth, 976 | this.token.text); 977 | } 978 | case 'code': { 979 | return this.renderer.code(this.token.text, 980 | this.token.lang, 981 | this.token.escaped); 982 | } 983 | case 'table': { 984 | var header = '' 985 | , body = '' 986 | , i 987 | , row 988 | , cell 989 | , flags 990 | , j; 991 | 992 | // header 993 | cell = ''; 994 | for (i = 0; i < this.token.header.length; i++) { 995 | flags = { header: true, align: this.token.align[i] }; 996 | cell += this.renderer.tablecell( 997 | this.inline.output(this.token.header[i]), 998 | { header: true, align: this.token.align[i] } 999 | ); 1000 | } 1001 | header += this.renderer.tablerow(cell); 1002 | 1003 | for (i = 0; i < this.token.cells.length; i++) { 1004 | row = this.token.cells[i]; 1005 | 1006 | cell = ''; 1007 | for (j = 0; j < row.length; j++) { 1008 | cell += this.renderer.tablecell( 1009 | this.inline.output(row[j]), 1010 | { header: false, align: this.token.align[j] } 1011 | ); 1012 | } 1013 | 1014 | body += this.renderer.tablerow(cell); 1015 | } 1016 | return this.renderer.table(header, body); 1017 | } 1018 | case 'blockquote_start': { 1019 | var body = ''; 1020 | 1021 | while (this.next().type !== 'blockquote_end') { 1022 | body += this.tok(); 1023 | } 1024 | 1025 | return this.renderer.blockquote(body); 1026 | } 1027 | case 'list_start': { 1028 | var body = '' 1029 | , ordered = this.token.ordered; 1030 | 1031 | while (this.next().type !== 'list_end') { 1032 | body += this.tok(); 1033 | } 1034 | 1035 | return this.renderer.list(body, ordered); 1036 | } 1037 | case 'list_item_start': { 1038 | var body = ''; 1039 | 1040 | while (this.next().type !== 'list_item_end') { 1041 | body += this.token.type === 'text' 1042 | ? this.parseText() 1043 | : this.tok(); 1044 | } 1045 | 1046 | return this.renderer.listitem(body); 1047 | } 1048 | case 'loose_item_start': { 1049 | var body = ''; 1050 | 1051 | while (this.next().type !== 'list_item_end') { 1052 | body += this.tok(); 1053 | } 1054 | 1055 | return this.renderer.listitem(body); 1056 | } 1057 | case 'html': { 1058 | var html = !this.token.pre && !this.options.pedantic 1059 | ? this.inline.output(this.token.text) 1060 | : this.token.text; 1061 | return this.renderer.html(html); 1062 | } 1063 | case 'paragraph': { 1064 | return this.renderer.paragraph(this.inline.output(this.token.text)); 1065 | } 1066 | case 'text': { 1067 | return this.renderer.paragraph(this.parseText()); 1068 | } 1069 | } 1070 | }; 1071 | 1072 | /** 1073 | * Helpers 1074 | */ 1075 | 1076 | function escape(html, encode) { 1077 | return html 1078 | .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&') 1079 | .replace(//g, '>') 1081 | .replace(/"/g, '"') 1082 | .replace(/'/g, '''); 1083 | } 1084 | 1085 | function unescape(html) { 1086 | return html.replace(/&([#\w]+);/g, function(_, n) { 1087 | n = n.toLowerCase(); 1088 | if (n === 'colon') return ':'; 1089 | if (n.charAt(0) === '#') { 1090 | return n.charAt(1) === 'x' 1091 | ? String.fromCharCode(parseInt(n.substring(2), 16)) 1092 | : String.fromCharCode(+n.substring(1)); 1093 | } 1094 | return ''; 1095 | }); 1096 | } 1097 | 1098 | function replace(regex, opt) { 1099 | regex = regex.source; 1100 | opt = opt || ''; 1101 | return function self(name, val) { 1102 | if (!name) return new RegExp(regex, opt); 1103 | val = val.source || val; 1104 | val = val.replace(/(^|[^\[])\^/g, '$1'); 1105 | regex = regex.replace(name, val); 1106 | return self; 1107 | }; 1108 | } 1109 | 1110 | function noop() {} 1111 | noop.exec = noop; 1112 | 1113 | function merge(obj) { 1114 | var i = 1 1115 | , target 1116 | , key; 1117 | 1118 | for (; i < arguments.length; i++) { 1119 | target = arguments[i]; 1120 | for (key in target) { 1121 | if (Object.prototype.hasOwnProperty.call(target, key)) { 1122 | obj[key] = target[key]; 1123 | } 1124 | } 1125 | } 1126 | 1127 | return obj; 1128 | } 1129 | 1130 | 1131 | /** 1132 | * Marked 1133 | */ 1134 | 1135 | function marked(src, opt, callback) { 1136 | if (callback || typeof opt === 'function') { 1137 | if (!callback) { 1138 | callback = opt; 1139 | opt = null; 1140 | } 1141 | 1142 | opt = merge({}, marked.defaults, opt || {}); 1143 | 1144 | var highlight = opt.highlight 1145 | , tokens 1146 | , pending 1147 | , i = 0; 1148 | 1149 | try { 1150 | tokens = Lexer.lex(src, opt) 1151 | } catch (e) { 1152 | return callback(e); 1153 | } 1154 | 1155 | pending = tokens.length; 1156 | 1157 | var done = function() { 1158 | var out, err; 1159 | 1160 | try { 1161 | out = Parser.parse(tokens, opt); 1162 | } catch (e) { 1163 | err = e; 1164 | } 1165 | 1166 | opt.highlight = highlight; 1167 | 1168 | return err 1169 | ? callback(err) 1170 | : callback(null, out); 1171 | }; 1172 | 1173 | if (!highlight || highlight.length < 3) { 1174 | return done(); 1175 | } 1176 | 1177 | delete opt.highlight; 1178 | 1179 | if (!pending) return done(); 1180 | 1181 | for (; i < tokens.length; i++) { 1182 | (function(token) { 1183 | if (token.type !== 'code') { 1184 | return --pending || done(); 1185 | } 1186 | return highlight(token.text, token.lang, function(err, code) { 1187 | if (code == null || code === token.text) { 1188 | return --pending || done(); 1189 | } 1190 | token.text = code; 1191 | token.escaped = true; 1192 | --pending || done(); 1193 | }); 1194 | })(tokens[i]); 1195 | } 1196 | 1197 | return; 1198 | } 1199 | try { 1200 | if (opt) opt = merge({}, marked.defaults, opt); 1201 | return Parser.parse(Lexer.lex(src, opt), opt); 1202 | } catch (e) { 1203 | e.message += '\nPlease report this to https://github.com/chjj/marked.'; 1204 | if ((opt || marked.defaults).silent) { 1205 | return '

    An error occured:

    '
    1206 |         + escape(e.message + '', true)
    1207 |         + '
    '; 1208 | } 1209 | throw e; 1210 | } 1211 | } 1212 | 1213 | /** 1214 | * Options 1215 | */ 1216 | 1217 | marked.options = 1218 | marked.setOptions = function(opt) { 1219 | merge(marked.defaults, opt); 1220 | return marked; 1221 | }; 1222 | 1223 | marked.defaults = { 1224 | gfm: true, 1225 | tables: true, 1226 | breaks: false, 1227 | pedantic: false, 1228 | sanitize: false, 1229 | smartLists: false, 1230 | silent: false, 1231 | highlight: null, 1232 | langPrefix: 'lang-', 1233 | smartypants: false, 1234 | headerPrefix: '', 1235 | renderer: new Renderer, 1236 | xhtml: false 1237 | }; 1238 | 1239 | /** 1240 | * Expose 1241 | */ 1242 | 1243 | marked.Parser = Parser; 1244 | marked.parser = Parser.parse; 1245 | 1246 | marked.Renderer = Renderer; 1247 | 1248 | marked.Lexer = Lexer; 1249 | marked.lexer = Lexer.lex; 1250 | 1251 | marked.InlineLexer = InlineLexer; 1252 | marked.inlineLexer = InlineLexer.output; 1253 | 1254 | marked.parse = marked; 1255 | 1256 | if (typeof exports === 'object') { 1257 | module.exports = marked; 1258 | } else if (typeof define === 'function' && define.amd) { 1259 | define(function() { return marked; }); 1260 | } else { 1261 | this.marked = marked; 1262 | } 1263 | 1264 | }).call(function() { 1265 | return this || (typeof window !== 'undefined' ? window : global); 1266 | }()); 1267 | -------------------------------------------------------------------------------- /js/lib/template.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * artTemplate - Template Engine 3 | * https://github.com/aui/artTemplate 4 | * Released under the MIT, BSD, and GPL Licenses 5 | */ 6 | 7 | (function (global) { 8 | 9 | 'use strict'; 10 | 11 | /** 12 | * 模板引擎 13 | * 若第二个参数类型为 String 则执行 compile 方法, 否则执行 render 方法 14 | * @name template 15 | * @param {String} 模板ID 16 | * @param {Object, String} 数据或者模板字符串 17 | * @return {String, Function} 渲染好的HTML字符串或者渲染方法 18 | */ 19 | var template = function (id, content) { 20 | return template[ 21 | typeof content === 'string' ? 'compile' : 'render' 22 | ].apply(template, arguments); 23 | }; 24 | 25 | 26 | template.version = '2.0.4'; 27 | template.openTag = '<%'; // 设置逻辑语法开始标签 28 | template.closeTag = '%>'; // 设置逻辑语法结束标签 29 | template.isEscape = true; // HTML字符编码输出开关 30 | template.isCompress = false; // 剔除渲染后HTML多余的空白开关 31 | template.parser = null; // 自定义语法插件接口 32 | 33 | 34 | 35 | /** 36 | * 渲染模板 37 | * @name template.render 38 | * @param {String} 模板ID 39 | * @param {Object} 数据 40 | * @return {String} 渲染好的HTML字符串 41 | */ 42 | template.render = function (id, data) { 43 | 44 | var cache = template.get(id) || _debug({ 45 | id: id, 46 | name: 'Render Error', 47 | message: 'No Template' 48 | }); 49 | 50 | return cache(data); 51 | }; 52 | 53 | 54 | 55 | /** 56 | * 编译模板 57 | * 2012-6-6 @TooBug: define 方法名改为 compile,与 Node Express 保持一致 58 | * @name template.compile 59 | * @param {String} 模板ID (可选,用作缓存索引) 60 | * @param {String} 模板字符串 61 | * @return {Function} 渲染方法 62 | */ 63 | template.compile = function (id, source) { 64 | 65 | var params = arguments; 66 | var isDebug = params[2]; 67 | var anonymous = 'anonymous'; 68 | 69 | if (typeof source !== 'string') { 70 | isDebug = params[1]; 71 | source = params[0]; 72 | id = anonymous; 73 | } 74 | 75 | 76 | try { 77 | 78 | var Render = _compile(id, source, isDebug); 79 | 80 | } catch (e) { 81 | 82 | e.id = id || source; 83 | e.name = 'Syntax Error'; 84 | 85 | return _debug(e); 86 | 87 | } 88 | 89 | 90 | function render (data) { 91 | 92 | try { 93 | 94 | return new Render(data, id) + ''; 95 | 96 | } catch (e) { 97 | 98 | if (!isDebug) { 99 | return template.compile(id, source, true)(data); 100 | } 101 | 102 | return _debug(e)(); 103 | 104 | } 105 | 106 | } 107 | 108 | 109 | render.prototype = Render.prototype; 110 | render.toString = function () { 111 | return Render.toString(); 112 | }; 113 | 114 | 115 | if (id !== anonymous) { 116 | _cache[id] = render; 117 | } 118 | 119 | 120 | return render; 121 | 122 | }; 123 | 124 | 125 | 126 | var _cache = template.cache = {}; 127 | 128 | 129 | 130 | 131 | // 辅助方法集合 132 | var _helpers = template.helpers = (function () { 133 | 134 | var toString = function (value, type) { 135 | 136 | if (typeof value !== 'string') { 137 | 138 | type = typeof value; 139 | if (type === 'number') { 140 | value += ''; 141 | } else if (type === 'function') { 142 | value = toString(value.call(value)); 143 | } else { 144 | value = ''; 145 | } 146 | } 147 | 148 | return value; 149 | 150 | }; 151 | 152 | 153 | var escapeMap = { 154 | "<": "<", 155 | ">": ">", 156 | '"': """, 157 | "'": "'", 158 | "&": "&" 159 | }; 160 | 161 | 162 | var escapeHTML = function (content) { 163 | return toString(content) 164 | .replace(/&(?![\w#]+;)|[<>"']/g, function (s) { 165 | return escapeMap[s]; 166 | }); 167 | }; 168 | 169 | 170 | var isArray = Array.isArray || function (obj) { 171 | return ({}).toString.call(obj) === '[object Array]'; 172 | }; 173 | 174 | 175 | var each = function (data, callback) { 176 | if (isArray(data)) { 177 | for (var i = 0, len = data.length; i < len; i++) { 178 | callback.call(data, data[i], i, data); 179 | } 180 | } else { 181 | for (i in data) { 182 | callback.call(data, data[i], i); 183 | } 184 | } 185 | }; 186 | 187 | 188 | return { 189 | 190 | $include: template.render, 191 | 192 | $string: toString, 193 | 194 | $escape: escapeHTML, 195 | 196 | $each: each 197 | 198 | }; 199 | })(); 200 | 201 | 202 | 203 | 204 | /** 205 | * 添加模板辅助方法 206 | * @name template.helper 207 | * @param {String} 名称 208 | * @param {Function} 方法 209 | */ 210 | template.helper = function (name, helper) { 211 | _helpers[name] = helper; 212 | }; 213 | 214 | 215 | 216 | 217 | /** 218 | * 模板错误事件 219 | * @name template.onerror 220 | * @event 221 | */ 222 | template.onerror = function (e) { 223 | var message = 'Template Error\n\n'; 224 | for (var name in e) { 225 | message += '<' + name + '>\n' + e[name] + '\n\n'; 226 | } 227 | 228 | if (global.console) { 229 | console.error(message); 230 | } 231 | }; 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | // 获取模板缓存 240 | template.get = function (id) { 241 | 242 | var cache; 243 | 244 | if (_cache.hasOwnProperty(id)) { 245 | cache = _cache[id]; 246 | } else if ('document' in global) { 247 | var elem = document.getElementById(id); 248 | 249 | if (elem) { 250 | var source = elem.value || elem.innerHTML; 251 | cache = template.compile(id, source.replace(/^\s*|\s*$/g, '')); 252 | } 253 | } 254 | 255 | return cache; 256 | }; 257 | 258 | 259 | 260 | // 模板调试器 261 | var _debug = function (e) { 262 | 263 | template.onerror(e); 264 | 265 | return function () { 266 | return '{Template Error}'; 267 | }; 268 | }; 269 | 270 | 271 | 272 | // 模板编译器 273 | var _compile = (function () { 274 | 275 | 276 | // 数组迭代 277 | var forEach = _helpers.$each; 278 | 279 | 280 | // 静态分析模板变量 281 | var KEYWORDS = 282 | // 关键字 283 | 'break,case,catch,continue,debugger,default,delete,do,else,false' 284 | + ',finally,for,function,if,in,instanceof,new,null,return,switch,this' 285 | + ',throw,true,try,typeof,var,void,while,with' 286 | 287 | // 保留字 288 | + ',abstract,boolean,byte,char,class,const,double,enum,export,extends' 289 | + ',final,float,goto,implements,import,int,interface,long,native' 290 | + ',package,private,protected,public,short,static,super,synchronized' 291 | + ',throws,transient,volatile' 292 | 293 | // ECMA 5 - use strict 294 | + ',arguments,let,yield' 295 | 296 | + ',undefined'; 297 | 298 | var REMOVE_RE = /\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|[\s\t\n]*\.[\s\t\n]*[$\w\.]+/g; 299 | var SPLIT_RE = /[^\w$]+/g; 300 | var KEYWORDS_RE = new RegExp(["\\b" + KEYWORDS.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g'); 301 | var NUMBER_RE = /^\d[^,]*|,\d[^,]*/g; 302 | var BOUNDARY_RE = /^,+|,+$/g; 303 | 304 | var getVariable = function (code) { 305 | return code 306 | .replace(REMOVE_RE, '') 307 | .replace(SPLIT_RE, ',') 308 | .replace(KEYWORDS_RE, '') 309 | .replace(NUMBER_RE, '') 310 | .replace(BOUNDARY_RE, '') 311 | .split(/^$|,+/); 312 | }; 313 | 314 | 315 | return function (id, source, isDebug) { 316 | 317 | var openTag = template.openTag; 318 | var closeTag = template.closeTag; 319 | var parser = template.parser; 320 | 321 | 322 | var code = source; 323 | var tempCode = ''; 324 | var line = 1; 325 | var uniq = {$data:1,$id:1,$helpers:1,$out:1,$line:1}; 326 | var prototype = {}; 327 | 328 | 329 | var variables = "var $helpers=this," 330 | + (isDebug ? "$line=0," : ""); 331 | 332 | var isNewEngine = ''.trim;// '__proto__' in {} 333 | var replaces = isNewEngine 334 | ? ["$out='';", "$out+=", ";", "$out"] 335 | : ["$out=[];", "$out.push(", ");", "$out.join('')"]; 336 | 337 | var concat = isNewEngine 338 | ? "$out+=$text;return $text;" 339 | : "$out.push($text);"; 340 | 341 | var print = "function($text){" + concat + "}"; 342 | 343 | var include = "function(id,data){" 344 | + "data=data||$data;" 345 | + "var $text=$helpers.$include(id,data,$id);" 346 | + concat 347 | + "}"; 348 | 349 | 350 | // html与逻辑语法分离 351 | forEach(code.split(openTag), function (code) { 352 | code = code.split(closeTag); 353 | 354 | var $0 = code[0]; 355 | var $1 = code[1]; 356 | 357 | // code: [html] 358 | if (code.length === 1) { 359 | 360 | tempCode += html($0); 361 | 362 | // code: [logic, html] 363 | } else { 364 | 365 | tempCode += logic($0); 366 | 367 | if ($1) { 368 | tempCode += html($1); 369 | } 370 | } 371 | 372 | 373 | }); 374 | 375 | 376 | 377 | code = tempCode; 378 | 379 | 380 | // 调试语句 381 | if (isDebug) { 382 | code = "try{" + code + "}catch(e){" 383 | + "throw {" 384 | + "id:$id," 385 | + "name:'Render Error'," 386 | + "message:e.message," 387 | + "line:$line," 388 | + "source:" + stringify(source) 389 | + ".split(/\\n/)[$line-1].replace(/^[\\s\\t]+/,'')" 390 | + "};" 391 | + "}"; 392 | } 393 | 394 | 395 | code = variables + replaces[0] + code 396 | + "return new String(" + replaces[3] + ");"; 397 | 398 | 399 | try { 400 | 401 | var Render = new Function("$data", "$id", code); 402 | Render.prototype = prototype; 403 | 404 | return Render; 405 | 406 | } catch (e) { 407 | e.temp = "function anonymous($data,$id) {" + code + "}"; 408 | throw e; 409 | } 410 | 411 | 412 | 413 | 414 | // 处理 HTML 语句 415 | function html (code) { 416 | 417 | // 记录行号 418 | line += code.split(/\n/).length - 1; 419 | 420 | // 压缩多余空白与注释 421 | if (template.isCompress) { 422 | code = code 423 | .replace(/[\n\r\t\s]+/g, ' ') 424 | .replace(//g, ''); 425 | } 426 | 427 | if (code) { 428 | code = replaces[1] + stringify(code) + replaces[2] + "\n"; 429 | } 430 | 431 | return code; 432 | } 433 | 434 | 435 | // 处理逻辑语句 436 | function logic (code) { 437 | 438 | var thisLine = line; 439 | 440 | if (parser) { 441 | 442 | // 语法转换插件钩子 443 | code = parser(code); 444 | 445 | } else if (isDebug) { 446 | 447 | // 记录行号 448 | code = code.replace(/\n/g, function () { 449 | line ++; 450 | return "$line=" + line + ";"; 451 | }); 452 | 453 | } 454 | 455 | 456 | // 输出语句. 转义: <%=value%> 不转义:<%=#value%> 457 | // <%=#value%> 等同 v2.0.3 之前的 <%==value%> 458 | if (code.indexOf('=') === 0) { 459 | 460 | var isEscape = !/^=[=#]/.test(code); 461 | 462 | code = code.replace(/^=[=#]?|[\s;]*$/g, ''); 463 | 464 | if (isEscape && template.isEscape) { 465 | 466 | // 转义处理,但排除辅助方法 467 | var name = code.replace(/\s*\([^\)]+\)/, ''); 468 | if ( 469 | !_helpers.hasOwnProperty(name) 470 | && !/^(include|print)$/.test(name) 471 | ) { 472 | code = "$escape(" + code + ")"; 473 | } 474 | 475 | } else { 476 | code = "$string(" + code + ")"; 477 | } 478 | 479 | 480 | code = replaces[1] + code + replaces[2]; 481 | 482 | } 483 | 484 | if (isDebug) { 485 | code = "$line=" + thisLine + ";" + code; 486 | } 487 | 488 | getKey(code); 489 | 490 | return code + "\n"; 491 | } 492 | 493 | 494 | // 提取模板中的变量名 495 | function getKey (code) { 496 | 497 | code = getVariable(code); 498 | 499 | // 分词 500 | forEach(code, function (name) { 501 | 502 | // 除重 503 | // TODO: name 可能在低版本的安卓浏览器中为空值,这里后续需要改进 getVariable 方法 504 | // @see https://github.com/aui/artTemplate/issues/41#issuecomment-29985469 505 | if (name && !uniq.hasOwnProperty(name)) { 506 | setValue(name); 507 | uniq[name] = true; 508 | } 509 | 510 | }); 511 | 512 | } 513 | 514 | 515 | // 声明模板变量 516 | // 赋值优先级: 517 | // 内置特权方法(include, print) > 私有模板辅助方法 > 数据 > 公用模板辅助方法 518 | function setValue (name) { 519 | 520 | var value; 521 | 522 | if (name === 'print') { 523 | 524 | value = print; 525 | 526 | } else if (name === 'include') { 527 | 528 | prototype["$include"] = _helpers['$include']; 529 | value = include; 530 | 531 | } else { 532 | 533 | value = "$data." + name; 534 | 535 | if (_helpers.hasOwnProperty(name)) { 536 | 537 | prototype[name] = _helpers[name]; 538 | 539 | if (name.indexOf('$') === 0) { 540 | value = "$helpers." + name; 541 | } else { 542 | value = value 543 | + "===undefined?$helpers." + name + ":" + value; 544 | } 545 | } 546 | 547 | 548 | } 549 | 550 | variables += name + "=" + value + ","; 551 | } 552 | 553 | 554 | // 字符串转义 555 | function stringify (code) { 556 | return "'" + code 557 | // 单引号与反斜杠转义 558 | .replace(/('|\\)/g, '\\$1') 559 | // 换行符转义(windows + linux) 560 | .replace(/\r/g, '\\r') 561 | .replace(/\n/g, '\\n') + "'"; 562 | } 563 | 564 | 565 | }; 566 | })(); 567 | 568 | 569 | // RequireJS && SeaJS 570 | if (typeof define === 'function') { 571 | define(function() { 572 | return template; 573 | }); 574 | 575 | // NodeJS 576 | } else if (typeof exports !== 'undefined') { 577 | module.exports = template; 578 | } 579 | 580 | global.template = template; 581 | 582 | 583 | })(this); 584 | 585 | -------------------------------------------------------------------------------- /js/lib/touch.js: -------------------------------------------------------------------------------- 1 | // Zepto.js 2 | // (c) 2010-2014 Thomas Fuchs 3 | // Zepto.js may be freely distributed under the MIT license. 4 | 5 | ;(function($){ 6 | var touch = {}, 7 | touchTimeout, tapTimeout, swipeTimeout, longTapTimeout, 8 | longTapDelay = 750, 9 | gesture 10 | 11 | function swipeDirection(x1, x2, y1, y2) { 12 | return Math.abs(x1 - x2) >= 13 | Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down') 14 | } 15 | 16 | function longTap() { 17 | longTapTimeout = null 18 | if (touch.last) { 19 | touch.el.trigger('longTap') 20 | touch = {} 21 | } 22 | } 23 | 24 | function cancelLongTap() { 25 | if (longTapTimeout) clearTimeout(longTapTimeout) 26 | longTapTimeout = null 27 | } 28 | 29 | function cancelAll() { 30 | if (touchTimeout) clearTimeout(touchTimeout) 31 | if (tapTimeout) clearTimeout(tapTimeout) 32 | if (swipeTimeout) clearTimeout(swipeTimeout) 33 | if (longTapTimeout) clearTimeout(longTapTimeout) 34 | touchTimeout = tapTimeout = swipeTimeout = longTapTimeout = null 35 | touch = {} 36 | } 37 | 38 | function isPrimaryTouch(event){ 39 | return (event.pointerType == 'touch' || 40 | event.pointerType == event.MSPOINTER_TYPE_TOUCH) 41 | && event.isPrimary 42 | } 43 | 44 | function isPointerEventType(e, type){ 45 | return (e.type == 'pointer'+type || 46 | e.type.toLowerCase() == 'mspointer'+type) 47 | } 48 | 49 | $(document).ready(function(){ 50 | var now, delta, deltaX = 0, deltaY = 0, firstTouch, _isPointerType 51 | 52 | if ('MSGesture' in window) { 53 | gesture = new MSGesture() 54 | gesture.target = document.body 55 | } 56 | 57 | $(document) 58 | .bind('MSGestureEnd', function(e){ 59 | var swipeDirectionFromVelocity = 60 | e.velocityX > 1 ? 'Right' : e.velocityX < -1 ? 'Left' : e.velocityY > 1 ? 'Down' : e.velocityY < -1 ? 'Up' : null; 61 | if (swipeDirectionFromVelocity) { 62 | touch.el.trigger('swipe') 63 | touch.el.trigger('swipe'+ swipeDirectionFromVelocity) 64 | } 65 | }) 66 | .on('touchstart MSPointerDown pointerdown', function(e){ 67 | if((_isPointerType = isPointerEventType(e, 'down')) && 68 | !isPrimaryTouch(e)) return 69 | firstTouch = _isPointerType ? e : e.touches[0] 70 | if (e.touches && e.touches.length === 1 && touch.x2) { 71 | // Clear out touch movement data if we have it sticking around 72 | // This can occur if touchcancel doesn't fire due to preventDefault, etc. 73 | touch.x2 = undefined 74 | touch.y2 = undefined 75 | } 76 | now = Date.now() 77 | delta = now - (touch.last || now) 78 | touch.el = $('tagName' in firstTouch.target ? 79 | firstTouch.target : firstTouch.target.parentNode) 80 | touchTimeout && clearTimeout(touchTimeout) 81 | touch.x1 = firstTouch.pageX 82 | touch.y1 = firstTouch.pageY 83 | if (delta > 0 && delta <= 250) touch.isDoubleTap = true 84 | touch.last = now 85 | longTapTimeout = setTimeout(longTap, longTapDelay) 86 | // adds the current touch contact for IE gesture recognition 87 | if (gesture && _isPointerType) gesture.addPointer(e.pointerId); 88 | }) 89 | .on('touchmove MSPointerMove pointermove', function(e){ 90 | if((_isPointerType = isPointerEventType(e, 'move')) && 91 | !isPrimaryTouch(e)) return 92 | firstTouch = _isPointerType ? e : e.touches[0] 93 | cancelLongTap() 94 | touch.x2 = firstTouch.pageX 95 | touch.y2 = firstTouch.pageY 96 | 97 | deltaX += Math.abs(touch.x1 - touch.x2) 98 | deltaY += Math.abs(touch.y1 - touch.y2) 99 | }) 100 | .on('touchend MSPointerUp pointerup', function(e){ 101 | if((_isPointerType = isPointerEventType(e, 'up')) && 102 | !isPrimaryTouch(e)) return 103 | cancelLongTap() 104 | 105 | // swipe 106 | if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > 30) || 107 | (touch.y2 && Math.abs(touch.y1 - touch.y2) > 30)) 108 | 109 | swipeTimeout = setTimeout(function() { 110 | touch.el.trigger('swipe') 111 | touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2))) 112 | touch = {} 113 | }, 0) 114 | 115 | // normal tap 116 | else if ('last' in touch) 117 | // don't fire tap when delta position changed by more than 30 pixels, 118 | // for instance when moving to a point and back to origin 119 | if (deltaX < 30 && deltaY < 30) { 120 | // delay by one tick so we can cancel the 'tap' event if 'scroll' fires 121 | // ('tap' fires before 'scroll') 122 | tapTimeout = setTimeout(function() { 123 | 124 | // trigger universal 'tap' with the option to cancelTouch() 125 | // (cancelTouch cancels processing of single vs double taps for faster 'tap' response) 126 | var event = $.Event('tap') 127 | event.cancelTouch = cancelAll 128 | touch.el.trigger(event) 129 | 130 | // trigger double tap immediately 131 | if (touch.isDoubleTap) { 132 | if (touch.el) touch.el.trigger('doubleTap') 133 | touch = {} 134 | } 135 | 136 | // trigger single tap after 250ms of inactivity 137 | else { 138 | touchTimeout = setTimeout(function(){ 139 | touchTimeout = null 140 | if (touch.el) touch.el.trigger('singleTap') 141 | touch = {} 142 | }, 250) 143 | } 144 | }, 0) 145 | } else { 146 | touch = {} 147 | } 148 | deltaX = deltaY = 0 149 | 150 | }) 151 | // when the browser window loses focus, 152 | // for example when a modal dialog is shown, 153 | // cancel all ongoing events 154 | .on('touchcancel MSPointerCancel pointercancel', cancelAll) 155 | 156 | // scrolling the window indicates intention of the user 157 | // to scroll, not tap or swipe, so cancel all ongoing events 158 | $(window).on('scroll', cancelAll) 159 | }) 160 | 161 | ;['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown', 162 | 'doubleTap', 'tap', 'singleTap', 'longTap'].forEach(function(eventName){ 163 | $.fn[eventName] = function(callback){ return this.on(eventName, callback) } 164 | }) 165 | })(Zepto) -------------------------------------------------------------------------------- /js/menu.js: -------------------------------------------------------------------------------- 1 | ;(function($, win, doc) { 2 | 'use strict'; 3 | 4 | var $doc = $(doc), 5 | spring = win.spring, 6 | source = '\ 7 |
    \ 8 | \ 34 |
    \ 35 |
    ', 36 | render = template.compile(source) 37 | 38 | var panelMenu = { 39 | id: 'menu', 40 | classname: 'menu', 41 | animate: 'revealInRight', 42 | view: function() { 43 | var $panel = this, 44 | data = {}, 45 | body = render(data) 46 | 47 | $doc.trigger('spa:initpanel', [$panel, {body: body}]) 48 | }, 49 | init: function() { 50 | var $view = this, 51 | $container = $('.container', $view) 52 | 53 | $container.trigger('spa:scroll', {direction: 'y'}) 54 | } 55 | } 56 | 57 | $doc.on(spring.config.tapEvent, '.btn-menu', function(event) { 58 | $doc.trigger('spa:openpanel', ['menu']) 59 | }) 60 | 61 | $doc.on('menu:render', function(event, options) { 62 | var data = (options && options.data) || {}, 63 | body = render(data) 64 | 65 | $('.spa-panel-menu .spa-page-body').html(body).find('.container').trigger('spa:scroll', {direction: 'y'}) 66 | }) 67 | 68 | $doc.trigger('spa:panel', panelMenu) 69 | 70 | })(Zepto, window, document) -------------------------------------------------------------------------------- /js/pull2refresh.js: -------------------------------------------------------------------------------- 1 | // `pulldown` load new 2 | // `pullup` load more 3 | ;(function($, win, doc) { 4 | 'use strict'; 5 | 6 | var $doc = $(document), 7 | spring = win.spring 8 | 9 | // pull2refresh:init event 10 | $doc.on('pull2refresh:init', function(event, options) { 11 | var $target = $(event.target), 12 | 13 | $children = $target.children(), 14 | 15 | $pulldown = $('.pulldown', $target), 16 | 17 | $pullup = $('.pullup', $target), 18 | 19 | pulldownHeight = $pulldown.height(), 20 | 21 | pulldownMoveDistance = 0, 22 | 23 | pulldownStartScrollTop = 0, 24 | pulldownStartPageY = 0, 25 | 26 | pulldownDefaultContent = options.pulldownDefaultContent || 'Pull down to refresh', 27 | 28 | pulldownReadyContent = options.pulldownReadyContent || 'Release to refresh', 29 | 30 | pulldownLoadingContent = options.pulldownLoadingContent || '', 31 | 32 | pulldownStatus = 'default', 33 | 34 | pullupDefaultContent = options.pullupDefaultContent || 'Pull up to refresh', 35 | 36 | pullupLoadingContent = options.pullupLoadingContent || '', 37 | 38 | pullupStatus = 'default' 39 | 40 | $target.on('touchstart', function(event) { 41 | pulldownStartScrollTop = $target.prop('scrollTop') 42 | 43 | if(!event.touches.length) return 44 | 45 | pulldownStartPageY = event.touches[0].pageY 46 | }) 47 | 48 | $target.on('touchend', function(event) { 49 | if(pulldownStatus == 'default' && $pulldown.length) { 50 | var css = {} 51 | css[common.transformName] = 'translate3d(0, 0px, 0)' 52 | 53 | $children.css(css) 54 | } else if(pulldownStatus == 'ready') { 55 | $target.trigger('pull2refresh:pulldown') 56 | } 57 | }) 58 | 59 | var scrollTimer, 60 | scrollEnd = function() { 61 | if($pullup.length && $pullup.css('display') != 'none' && $target.prop('scrollTop') + $target.height() >= $target.prop('scrollHeight') - 200) { 62 | $target.trigger('pull2refresh:pullup') 63 | } 64 | } 65 | 66 | $target.on('scroll', function(event) { 67 | if(scrollTimer) { 68 | clearTimeout(scrollTimer) 69 | } 70 | scrollTimer = setTimeout(scrollEnd, 100) 71 | }) 72 | 73 | $target.on('touchmove', function(event) { 74 | if(!event.touches.length) return 75 | 76 | if(pulldownStartScrollTop > 5 || !$pulldown.length || $pulldown.css('display') == 'none' || pulldownStatus == 'loading') 77 | return 78 | 79 | var pageY = event.touches[0].pageY 80 | 81 | if(pageY < pulldownStartPageY) return 82 | event.preventDefault() 83 | 84 | pulldownMoveDistance = (pageY - pulldownStartPageY) * 0.4 85 | 86 | if(pulldownStartScrollTop !== 0) 87 | $target.prop('scrollTop', 0) 88 | 89 | var css = {} 90 | css[common.transformName] = 'translate3d(0, ' + pulldownMoveDistance + 'px, 0)' 91 | 92 | $children.css(css) 93 | 94 | if(pulldownMoveDistance >= pulldownHeight && pulldownStatus == 'default') { 95 | pulldownStatus = 'ready' 96 | $pulldown.html(pulldownReadyContent) 97 | } else if(pulldownMoveDistance < pulldownHeight && pulldownStatus == 'ready') { 98 | pulldownStatus = 'default' 99 | $pulldown.html(pulldownDefaultContent) 100 | } 101 | }) 102 | 103 | $target.on('pull2refresh:pulldown', function(evnet) { 104 | if(pulldownStatus != 'loading') { 105 | 106 | var css = {} 107 | css[common.transformName] = 'translate3d(0, ' + pulldownHeight + 'px, 0)' 108 | 109 | $children.css(css) 110 | pulldownStatus = 'loading' 111 | $pulldown.html(pulldownLoadingContent) 112 | options.pulldown && options.pulldown.call($target) 113 | } 114 | }) 115 | 116 | $target.on('pull2refresh:pulldownFinish', function(event) { 117 | var css = {} 118 | css[common.transformName] = 'translate3d(0, 0px, 0)' 119 | 120 | $children.css(css) 121 | pulldownStatus = 'default' 122 | $pulldown.html(pulldownDefaultContent) 123 | options.pulldownFinish && options.pulldownFinish.call($target) 124 | }) 125 | 126 | $target.on('pull2refresh:pullup', function(evnet) { 127 | if(pullupStatus != 'loading') { 128 | pullupStatus = 'loading' 129 | $pullup.html(pullupLoadingContent) 130 | options.pullup && options.pullup.call($target) 131 | } 132 | }) 133 | 134 | $target.on('pull2refresh:pullupFinish', function(evnet) { 135 | pullupStatus = 'default' 136 | $pullup.html(pullupDefaultContent) 137 | options.pullupFinish && options.pullupFinish.call($target) 138 | }) 139 | 140 | }) 141 | 142 | })(Zepto, window, document) 143 | 144 | -------------------------------------------------------------------------------- /js/side.js: -------------------------------------------------------------------------------- 1 | ;(function($, win, doc) { 2 | 'use strict'; 3 | 4 | var $doc = $(doc), 5 | spring = win.spring, 6 | source = '\ 7 |

    <%=$.spring.config.title%>

    \ 8 |
    <%=#marked($.spring.config.desc)%>
    \ 9 |