├── .gitignore ├── src ├── css │ ├── font │ │ ├── fontello.eot │ │ ├── fontello.ttf │ │ ├── fontello.woff │ │ └── fontello.svg │ ├── loading.css │ └── main.css ├── lib │ ├── local.js │ ├── base64.js │ ├── manager.js │ ├── route.js │ ├── showdown.js │ ├── underscore.js │ ├── ajax.js │ └── github.js ├── template │ ├── main.json │ ├── css │ │ ├── style.css │ │ ├── prism.css │ │ └── entry.css │ ├── post.html │ ├── page.html │ ├── js │ │ ├── hogan.min.js │ │ └── prism.js │ ├── index.html │ └── main.css ├── editor.html ├── index.html └── app.js ├── package.json ├── Gruntfile.js ├── LICENSE.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /src/css/font/fontello.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isnowfy/simple/HEAD/src/css/font/fontello.eot -------------------------------------------------------------------------------- /src/css/font/fontello.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isnowfy/simple/HEAD/src/css/font/fontello.ttf -------------------------------------------------------------------------------- /src/css/font/fontello.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isnowfy/simple/HEAD/src/css/font/fontello.woff -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple", 3 | "version": "0.1.0", 4 | "dependencies": {}, 5 | "devDependencies": { 6 | "grunt": "~0.4.1", 7 | "grunt-contrib-uglify": "~0.2.7", 8 | "grunt-contrib-cssmin": "~0.9.0", 9 | "grunt-contrib-concat": "~0.4.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/local.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.7.1 2 | (function() { 3 | var Spine; 4 | 5 | Spine = this.Spine || require('spine'); 6 | 7 | Spine.Model.Local = { 8 | extended: function() { 9 | this.change(this.saveLocal); 10 | return this.fetch(this.loadLocal); 11 | }, 12 | saveLocal: function() { 13 | var result; 14 | result = JSON.stringify(this); 15 | return localStorage[this.className] = result; 16 | }, 17 | loadLocal: function(options) { 18 | var result; 19 | if (options == null) { 20 | options = {}; 21 | } 22 | if (!options.hasOwnProperty('clear')) { 23 | options.clear = true; 24 | } 25 | result = localStorage[this.className]; 26 | return this.refresh(result || [], options); 27 | } 28 | }; 29 | 30 | if (typeof module !== "undefined" && module !== null) { 31 | module.exports = Spine.Model.Local; 32 | } 33 | 34 | }).call(this); 35 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(grunt) { 4 | 5 | grunt.initConfig({ 6 | pkg: grunt.file.readJSON('package.json'), 7 | cssmin: { 8 | minify: { 9 | src: 'src/template/css/*.css', 10 | dest: 'src/template/main.css' 11 | } 12 | }, 13 | 14 | concat: { 15 | dist: { 16 | src: ['src/lib/jquery.js', "src/template/js/prism.js", "src/template/js/hogan.min.js", 'src/lib/spine.js', 'src/lib/route.js', 'src/lib/manager.js'], 17 | dest: 'src/template/main.js' 18 | } 19 | }, 20 | 21 | uglify: { 22 | build: { 23 | src: 'src/template/main.js', 24 | dest: 'src/template/main.js' 25 | } 26 | } 27 | 28 | }); 29 | 30 | grunt.loadNpmTasks('grunt-contrib-uglify'); 31 | grunt.loadNpmTasks('grunt-contrib-cssmin'); 32 | grunt.loadNpmTasks('grunt-contrib-concat'); 33 | 34 | grunt.registerTask('default', ['cssmin', 'concat', 'uglify']); 35 | 36 | }; 37 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 isnowfy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /src/css/loading.css: -------------------------------------------------------------------------------- 1 | .spinner { 2 | margin: auto; 3 | width: 40px; 4 | height: 40px; 5 | position: fixed; 6 | top: 0; left: 0; bottom: 0; right: 0; 7 | 8 | -webkit-animation: rotate 2.0s infinite linear; 9 | animation: rotate 2.0s infinite linear; 10 | } 11 | 12 | #loading:before { 13 | content: ''; 14 | display: block; 15 | position: fixed; 16 | top: 0; 17 | left: 0; 18 | width: 100%; 19 | height: 100%; 20 | background-color: rgba(0,0,0,0.3); 21 | } 22 | 23 | .dot1, .dot2 { 24 | width: 60%; 25 | height: 60%; 26 | display: inline-block; 27 | position: absolute; 28 | top: 0; 29 | background-color: #333; 30 | border-radius: 100%; 31 | 32 | -webkit-animation: bounce 2.0s infinite ease-in-out; 33 | animation: bounce 2.0s infinite ease-in-out; 34 | } 35 | 36 | .dot2 { 37 | top: auto; 38 | bottom: 0px; 39 | -webkit-animation-delay: -1.0s; 40 | animation-delay: -1.0s; 41 | } 42 | 43 | @-webkit-keyframes rotate { 100% { -webkit-transform: rotate(360deg) }} 44 | @keyframes rotate { 45 | 100% { 46 | transform: rotate(360deg); 47 | -webkit-transform: rotate(360deg); 48 | } 49 | } 50 | 51 | @-webkit-keyframes bounce { 52 | 0%, 100% { -webkit-transform: scale(0.0) } 53 | 50% { -webkit-transform: scale(1.0) } 54 | } 55 | 56 | @keyframes bounce { 57 | 0%, 100% { 58 | transform: scale(0.0); 59 | -webkit-transform: scale(0.0); 60 | } 50% { 61 | transform: scale(1.0); 62 | -webkit-transform: scale(1.0); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/template/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "isnowfy", 3 | "number_of_posts_per_page": 7, 4 | "disqus_shortname": "", 5 | "posts": [ 6 | { 7 | "title": "title tile tile tile", 8 | "path": "/", 9 | "date": "2013-07-01", 10 | "tags": "split with space" 11 | }, 12 | { 13 | "title": "title111111111 1111111 11111", 14 | "path": "/", 15 | "date": "2012-07-01", 16 | "tags": "test with space" 17 | }, 18 | { 19 | "title": "这是个测试的标题", 20 | "path": "/", 21 | "date": "2012-07-01", 22 | "tags": "test with space" 23 | }, 24 | { 25 | "title": "我是一个比较长长长的标题呢啊啊啊", 26 | "path": "/", 27 | "date": "2014-07-01", 28 | "tags": "test with space" 29 | }, 30 | { 31 | "title": "title111111111 1111111 11111", 32 | "path": "/", 33 | "date": "2013-07-01", 34 | "tags": "test with space" 35 | }, 36 | { 37 | "title": "title这个标题啊1111", 38 | "path": "/", 39 | "date": "2013-07-01", 40 | "tags": "test with space" 41 | }, 42 | { 43 | "title": "title111111111 1111111 11111", 44 | "path": "/", 45 | "date": "2013-07-01", 46 | "tags": "test with space" 47 | }, 48 | { 49 | "title": "title111111111 1111111 11111", 50 | "path": "/", 51 | "date": "2013-07-01", 52 | "tags": "test with space" 53 | }, 54 | { 55 | "title": "title111111111 1111111 11111", 56 | "path": "/", 57 | "date": "2013-07-01", 58 | "tags": "test with space" 59 | }, 60 | { 61 | "title": "title2", 62 | "path": "/", 63 | "date": "2013-07-01", 64 | "tags": "test test2 space" 65 | } 66 | ], 67 | "pages": [ 68 | { 69 | "title": "about", 70 | "path": "/", 71 | "date": "2013-07-01", 72 | "tags": "" 73 | } 74 | ] 75 | } 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple 2 | 3 | Simple is a static blog generator with a single static page. You can write you blog online, and it will generate static html files at your repo named `username.github.io` which is supported by [github pages](https://pages.github.com) 4 | 5 | ## Demo 6 | 7 | [Simple](http://isnowfy.github.io/simple) 8 | 9 | [Blog demo](http://isnowfy.github.io/) 10 | 11 | [Lightweight markdown editor](http://isnowfy.github.io/simple/editor.html) 12 | 13 | ## Usage 14 | 15 | With Simple and github pages you can easily create your static blog. Here is what you need to do. 16 | 17 | 1. Create a github account. 18 | 2. Create a repo named `your_user_name.github.io` (remember to check `Initilize and create README`). 19 | 3. Sign in [Simple](http://isnowfy.github.io/simple) with your github account. 20 | 4. Click `Initilize` to set up basic files for your static blog site.(maybe a little slow) 21 | 5. Click `Go` and start writing. 22 | 6. Click `New post` to create a new post and when finish writing click `save` to generate the static page. 23 | 7. Now you can browse the `your_user_name.github.io` site and enjoy it! 24 | 25 |  26 | 27 | * You can use your own blog name, just modify the `main.json` file, and change `name="username"`. 28 | 29 | * You can use disqus comment system, just modify the `main.json` file, and change `disqus_shortname=""` to `disqus_shortname="your_shortname"`. 30 | 31 | * You can use your own custom domain, just modify the `CNAME` file.(see [also](https://help.github.com/articles/setting-up-a-custom-domain-with-github-pages)) 32 | 33 | ## Features 34 | 35 | * Simple, no backend need 36 | * Static blog 37 | * Markdown editor 38 | * Code highlight support 39 | * Tex formula support 40 | * Responsive html 41 | * Drag and drop to upload image 42 | 43 | ## Custom 44 | 45 | The template files are at `/src/template`, so you can modify the template files and css files. If you want use your own theme you can clone the project, modify the template files and push the entire `src` folder in your `gh-pages` branch which will allow you generate your own static blog. 46 | 47 | ## Todo 48 | 49 | Enhance error display, Search, Sitemap, Rss 50 | 51 | ## License 52 | 53 | MIT licensed. 54 | -------------------------------------------------------------------------------- /src/template/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: Georgia, serif; 4 | } 5 | .main { 6 | margin: 0 auto; 7 | width: 600px; 8 | position: relative; 9 | } 10 | #disqus_thread { 11 | padding: 16px; 12 | } 13 | .wrap-header h1 { 14 | width: 100%; 15 | height: 40px; 16 | color: #E93071; 17 | padding: 20px 0 10px 0; 18 | border-bottom: 2px dashed #888; 19 | margin: 0 0 10px; 20 | font-family: "Comic Sans MS", cursive, sans-serif; 21 | } 22 | #title:hover { 23 | border: 0; 24 | } 25 | .header { 26 | margin: 70px 0 0 -210px; 27 | width: 140px; 28 | float: left; 29 | text-align: right; 30 | font-family: Verdana, Geneva, sans-serif; 31 | } 32 | .header li { 33 | list-style: none; 34 | text-transform: uppercase; 35 | margin: 30px 0; 36 | } 37 | .header a { 38 | color: black; 39 | } 40 | a { 41 | text-decoration: none; 42 | color: #E93071; 43 | } 44 | a:hover { 45 | border-bottom: 1px solid #E93071; 46 | } 47 | .selected { 48 | color: black; 49 | } 50 | .item { 51 | margin: 10px 0; 52 | padding: 1px 0; 53 | } 54 | .little { 55 | float: left; 56 | margin-right: 10px; 57 | width: 3px; 58 | height: 30px; 59 | border-radius: 4px; 60 | background: #C5C5BD; 61 | } 62 | .date { 63 | float: left; 64 | color: #C5C5BD; 65 | font-size: 17px; 66 | text-transform: uppercase; 67 | font-weight: bold; 68 | width: 140px; 69 | padding: 16px 0 0; 70 | } 71 | .title { 72 | padding: 0; 73 | margin: 0 0 0 140px; 74 | } 75 | .title a:hover { 76 | padding-bottom: 2px; 77 | border-bottom: 1px solid #E93071; 78 | } 79 | .title h2 { 80 | font-size: 17px; 81 | line-height: 25px; 82 | } 83 | .footer { 84 | border-top: 1px dotted #888; 85 | margin-top: 20px; 86 | text-align: center; 87 | color: #555; 88 | } 89 | .pages { 90 | text-align: center; 91 | margin: 25px 25px 35px; 92 | font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; 93 | } 94 | .pages a:hover{ 95 | border: 1px solid #E93071; 96 | border-radius: 4px; 97 | } 98 | .pages > li { 99 | margin: 0 4px; 100 | display: inline; 101 | } 102 | .pages > li > a, .pages > li > span { 103 | padding: 3px 10px; 104 | border: 1px solid #eee; 105 | border-radius: 4px; 106 | } 107 | .tag { 108 | color: #888; 109 | } 110 | .archive { 111 | margin: 10px; 112 | } 113 | .archive > span { 114 | color: #C5C5BD; 115 | margin-right: 20px; 116 | } 117 | @media (max-width: 800px) { 118 | .main { 119 | width: 500px; 120 | } 121 | .header { 122 | margin: 70px 0 0 -180px; 123 | } 124 | } 125 | @media (max-width: 600px) { 126 | .main { 127 | width: 100%; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/lib/base64.js: -------------------------------------------------------------------------------- 1 | // This code was written by Tyler Akins and has been placed in the 2 | // public domain. It would be nice if you left this header intact. 3 | // Base64 code from Tyler Akins -- http://rumkin.com 4 | 5 | var Base64 = (function () { 6 | var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 7 | 8 | var obj = { 9 | /** 10 | * Encodes a string in base64 11 | * @param {String} input The string to encode in base64. 12 | */ 13 | encode: function (input) { 14 | var output = ""; 15 | var chr1, chr2, chr3; 16 | var enc1, enc2, enc3, enc4; 17 | var i = 0; 18 | 19 | do { 20 | chr1 = input.charCodeAt(i++); 21 | chr2 = input.charCodeAt(i++); 22 | chr3 = input.charCodeAt(i++); 23 | 24 | enc1 = chr1 >> 2; 25 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); 26 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); 27 | enc4 = chr3 & 63; 28 | 29 | if (isNaN(chr2)) { 30 | enc3 = enc4 = 64; 31 | } else if (isNaN(chr3)) { 32 | enc4 = 64; 33 | } 34 | 35 | output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + 36 | keyStr.charAt(enc3) + keyStr.charAt(enc4); 37 | } while (i < input.length); 38 | 39 | return output; 40 | }, 41 | 42 | /** 43 | * Decodes a base64 string. 44 | * @param {String} input The string to decode. 45 | */ 46 | decode: function (input) { 47 | var output = ""; 48 | var chr1, chr2, chr3; 49 | var enc1, enc2, enc3, enc4; 50 | var i = 0; 51 | 52 | // remove all characters that are not A-Z, a-z, 0-9, +, /, or = 53 | input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); 54 | 55 | do { 56 | enc1 = keyStr.indexOf(input.charAt(i++)); 57 | enc2 = keyStr.indexOf(input.charAt(i++)); 58 | enc3 = keyStr.indexOf(input.charAt(i++)); 59 | enc4 = keyStr.indexOf(input.charAt(i++)); 60 | 61 | chr1 = (enc1 << 2) | (enc2 >> 4); 62 | chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); 63 | chr3 = ((enc3 & 3) << 6) | enc4; 64 | 65 | output = output + String.fromCharCode(chr1); 66 | 67 | if (enc3 != 64) { 68 | output = output + String.fromCharCode(chr2); 69 | } 70 | if (enc4 != 64) { 71 | output = output + String.fromCharCode(chr3); 72 | } 73 | } while (i < input.length); 74 | 75 | return output; 76 | } 77 | }; 78 | 79 | return obj; 80 | })(); 81 | if (typeof exports !== 'undefined') { 82 | // Github = exports; 83 | module.exports = Base64; 84 | } else { 85 | window.Base64 = Base64; 86 | } 87 | 88 | -------------------------------------------------------------------------------- /src/editor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |Head over to GitHub and create a new repository named username.github.io, where username is your username on GitHub.(Please selected the "Initialize this repository with a README" when creating the repo.)
56 |If you had initialized the repository you can go to next page directly.
66 | 67 |"+d+"\n",A(d)+e}),a=a.replace(/~0/,""),a},z=function(a){return a+="~0",a=a.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g,function(a,b,c){var d=b,e=c;return e=C(e),e=M(e),e=e.replace(/^\n+/g,""),e=e.replace(/\n+$/g,""),e=""+e+"\n",A(e)}),a=a.replace(/~0/,""),a},A=function(a){return a=a.replace(/(^\n+|\n+$)/g,""),"\n\n~K"+(d.push(a)-1)+"K\n\n"},B=function(a){return a=a.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,function(a,b,c,d,e){var f=d;return f=f.replace(/^([ \t]*)/g,""),f=f.replace(/[ \t]*$/g,""),f=C(f),b+""+f+""}),a},C=function(a){return a=a.replace(/&/g,"&"),a=a.replace(//g,">"),a=N(a,"*_{}[]\\",!1),a},D=function(a){return a=a.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g,"$2"),a=a.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g,"$2"),a},E=function(a){return a=a.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm,function(a,b){var c=b;return c=c.replace(/^[ \t]*>[ \t]?/gm,"~0"),c=c.replace(/~0/g,""),c=c.replace(/^[ \t]+$/gm,""),c=o(c),c=c.replace(/(^|\n)/g,"$1 "),c=c.replace(/(\s*[^\r]+?<\/pre>)/gm,function(a,b){var c=b;return c=c.replace(/^ /mg,"~0"),c=c.replace(/~0/g,""),c}),A("\n"+c+"\n
")}),a},F=function(a){a=a.replace(/^\n+/g,""),a=a.replace(/\n+$/g,"");var b=a.split(/\n{2,}/g),c=[],e=b.length;for(var f=0;f=0?c.push(g):g.search(/\S/)>=0&&(g=p(g),g=g.replace(/^([ \t]*)/g,""),g+="
",c.push(g))}e=c.length;for(var f=0;f=0){var h=d[RegExp.$1];h=h.replace(/\$/g,"$$$$"),c[f]=c[f].replace(/~K\d+K/,h)}return c.join("\n\n")},G=function(a){return a=a.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g,"&"),a=a.replace(/<(?![a-z\/?\$!])/gi,"<"),a},H=function(a){return a=a.replace(/\\(\\)/g,O),a=a.replace(/\\([`*_{}\[\]()>#+-.!])/g,O),a},I=function(a){return a=a.replace(/<((https?|ftp|dict):[^'">\s]+)>/gi,'$1'),a=a.replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,function(a,b){return J(K(b))}),a},J=function(a){var b=[function(a){return""+a.charCodeAt(0)+";"},function(a){return""+a.charCodeAt(0).toString(16)+";"},function(a){return a}];return a="mailto:"+a,a=a.replace(/./g,function(a){if(a=="@")a=b[Math.floor(Math.random()*2)](a);else if(a!=":"){var c=Math.random();a=c>.9?b[2](a):c>.45?b[1](a):b[0](a)}return a}),a=''+a+"",a=a.replace(/">.+:/g,'">'),a},K=function(a){return a=a.replace(/~E(\d+)E/g,function(a,b){var c=parseInt(b);return String.fromCharCode(c)}),a},L=function(a){return a=a.replace(/^(\t|[ ]{1,4})/gm,"~0"),a=a.replace(/~0/g,""),a},M=function(a){return a=a.replace(/\t(?=\t)/g," "),a=a.replace(/\t/g,"~A~B"),a=a.replace(/~B(.+?)~A/g,function(a,b,c){var d=b,e=4-d.length%4;for(var f=0;f2;e==null&&(e=[]);if(d&&e.reduce===d)return r&&(t=T.bind(t,r)),i?e.reduce(t,n):e.reduce(t);N(e,function(e,s,o){i?n=t.call(r,n,e,s,o):(n=e,i=!0)});if(!i)throw new TypeError("Reduce of empty array with no initial value");return n},T.reduceRight=T.foldr=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(v&&e.reduceRight===v)return r&&(t=T.bind(t,r)),arguments.length>2?e.reduceRight(t,n):e.reduceRight(t);var s=e.length;if(s!==+s){var o=T.keys(e);s=o.length}N(e,function(u,a,f){a=o?o[--s]:--s,i?n=t.call(r,n,e[a],a,f):(n=e[a],i=!0)});if(!i)throw new TypeError("Reduce of empty array with no initial value");return n},T.find=T.detect=function(e,t,n){var r;return C(e,function(e,i,s){if(t.call(n,e,i,s))return r=e,!0}),r},T.filter=T.select=function(e,t,n){var r=[];return e==null?r:m&&e.filter===m?e.filter(t,n):(N(e,function(e,i,s){t.call(n,e,i,s)&&(r[r.length]=e)}),r)},T.reject=function(e,t,n){var r=[];return e==null?r:(N(e,function(e,i,s){t.call(n,e,i,s)||(r[r.length]=e)}),r)},T.every=T.all=function(e,t,r){t||(t=T.identity);var i=!0;return e==null?i:g&&e.every===g?e.every(t,r):(N(e,function(e,s,o){if(!(i=i&&t.call(r,e,s,o)))return n}),!!i)};var C=T.some=T.any=function(e,t,r){t||(t=T.identity);var i=!1;return e==null?i:y&&e.some===y?e.some(t,r):(N(e,function(e,s,o){if(i||(i=t.call(r,e,s,o)))return n}),!!i)};T.contains=T.include=function(e,t){var n=!1;return e==null?n:b&&e.indexOf===b?e.indexOf(t)!=-1:(n=C(e,function(e){return e===t}),n)},T.invoke=function(e,t){var n=u.call(arguments,2);return T.map(e,function(e){return(T.isFunction(t)?t:e[t]).apply(e,n)})},T.pluck=function(e,t){return T.map(e,function(e){return e[t]})},T.where=function(e,t){return T.isEmpty(t)?[]:T.filter(e,function(e){for(var n in t)if(t[n]!==e[n])return!1;return!0})},T.max=function(e,t,n){if(!t&&T.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.max.apply(Math,e);if(!t&&T.isEmpty(e))return-Infinity;var r={computed:-Infinity};return N(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o>=r.computed&&(r={value:e,computed:o})}),r.value},T.min=function(e,t,n){if(!t&&T.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.min.apply(Math,e);if(!t&&T.isEmpty(e))return Infinity;var r={computed:Infinity};return N(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;or||n===void 0)return 1;if(n>>1;n.call(r,e[u])=0})})},T.difference=function(e){var t=a.apply(r,u.call(arguments,1));return T.filter(e,function(e){return!T.contains(t,e)})},T.zip=function(){var e=u.call(arguments),t=T.max(T.pluck(e,"length")),n=new Array(t);for(var r=0;r=0;n--)t=[e[n].apply(this,t)];return t[0]}},T.after=function(e,t){return e<=0?t():function(){if(--e<1)return t.apply(this,arguments)}},T.keys=S||function(e){if(e!==Object(e))throw new TypeError("Invalid object");var t=[];for(var n in e)T.has(e,n)&&(t[t.length]=n);return t},T.values=function(e){var t=[];for(var n in e)T.has(e,n)&&t.push(e[n]);return t},T.pairs=function(e){var t=[];for(var n in e)T.has(e,n)&&t.push([n,e[n]]);return t},T.invert=function(e){var t={};for(var n in e)T.has(e,n)&&(t[e[n]]=n);return t},T.functions=T.methods=function(e){var t=[];for(var n in e)T.isFunction(e[n])&&t.push(n);return t.sort()},T.extend=function(e){return N(u.call(arguments,1),function(t){for(var n in t)e[n]=t[n]}),e},T.pick=function(e){var t={},n=a.apply(r,u.call(arguments,1));return N(n,function(n){n in e&&(t[n]=e[n])}),t},T.omit=function(e){var t={},n=a.apply(r,u.call(arguments,1));for(var i in e)T.contains(n,i)||(t[i]=e[i]);return t},T.defaults=function(e){return N(u.call(arguments,1),function(t){for(var n in t)e[n]==null&&(e[n]=t[n])}),e},T.clone=function(e){return T.isObject(e)?T.isArray(e)?e.slice():T.extend({},e):e},T.tap=function(e,t){return t(e),e};var M=function(e,t,n,r){if(e===t)return e!==0||1/e==1/t;if(e==null||t==null)return e===t;e instanceof T&&(e=e._wrapped),t instanceof T&&(t=t._wrapped);var i=l.call(e);if(i!=l.call(t))return!1;switch(i){case"[object String]":return e==String(t);case"[object Number]":return e!=+e?t!=+t:e==0?1/e==1/t:e==+t;case"[object Date]":case"[object Boolean]":return+e==+t;case"[object RegExp]":return e.source==t.source&&e.global==t.global&&e.multiline==t.multiline&&e.ignoreCase==t.ignoreCase}if(typeof e!="object"||typeof t!="object")return!1;var s=n.length;while(s--)if(n[s]==e)return r[s]==t;n.push(e),r.push(t);var o=0,u=!0;if(i=="[object Array]"){o=e.length,u=o==t.length;if(u)while(o--)if(!(u=M(e[o],t[o],n,r)))break}else{var a=e.constructor,f=t.constructor;if(a!==f&&!(T.isFunction(a)&&a instanceof a&&T.isFunction(f)&&f instanceof f))return!1;for(var c in e)if(T.has(e,c)){o++;if(!(u=T.has(t,c)&&M(e[c],t[c],n,r)))break}if(u){for(c in t)if(T.has(t,c)&&!(o--))break;u=!o}}return n.pop(),r.pop(),u};T.isEqual=function(e,t){return M(e,t,[],[])},T.isEmpty=function(e){if(e==null)return!0;if(T.isArray(e)||T.isString(e))return e.length===0;for(var t in e)if(T.has(e,t))return!1;return!0},T.isElement=function(e){return!!e&&e.nodeType===1},T.isArray=E||function(e){return l.call(e)=="[object Array]"},T.isObject=function(e){return e===Object(e)},N(["Arguments","Function","String","Number","Date","RegExp"],function(e){T["is"+e]=function(t){return l.call(t)=="[object "+e+"]"}}),T.isArguments(arguments)||(T.isArguments=function(e){return!!e&&!!T.has(e,"callee")}),typeof /./!="function"&&(T.isFunction=function(e){return typeof e=="function"}),T.isFinite=function(e){return T.isNumber(e)&&isFinite(e)},T.isNaN=function(e){return T.isNumber(e)&&e!=+e},T.isBoolean=function(e){return e===!0||e===!1||l.call(e)=="[object Boolean]"},T.isNull=function(e){return e===null},T.isUndefined=function(e){return e===void 0},T.has=function(e,t){return c.call(e,t)},T.noConflict=function(){return e._=t,this},T.identity=function(e){return e},T.times=function(e,t,n){for(var r=0;r":">",'"':""","'":"'","/":"/"}};_.unescape=T.invert(_.escape);var D={escape:new RegExp("["+T.keys(_.escape).join("")+"]","g"),unescape:new RegExp("("+T.keys(_.unescape).join("|")+")","g")};T.each(["escape","unescape"],function(e){T[e]=function(t){return t==null?"":(""+t).replace(D[e],function(t){return _[e][t]})}}),T.result=function(e,t){if(e==null)return null;var n=e[t];return T.isFunction(n)?n.call(e):n},T.mixin=function(e){N(T.functions(e),function(t){var n=T[t]=e[t];T.prototype[t]=function(){var e=[this._wrapped];return o.apply(e,arguments),F.call(this,n.apply(T,e))}})};var P=0;T.uniqueId=function(e){var t=P++;return e?e+t:t},T.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var H=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},j=/\\|'|\r|\n|\t|\u2028|\u2029/g;T.template=function(e,t,n){n=T.defaults({},n,T.templateSettings);var r=new RegExp([(n.escape||H).source,(n.interpolate||H).source,(n.evaluate||H).source].join("|")+"|$","g"),i=0,s="__p+='";e.replace(r,function(t,n,r,o,u){s+=e.slice(i,u).replace(j,function(e){return"\\"+B[e]}),s+=n?"'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'":r?"'+\n((__t=("+r+"))==null?'':__t)+\n'":o?"';\n"+o+"\n__p+='":"",i=u+t.length}),s+="';\n",n.variable||(s="with(obj||{}){\n"+s+"}\n"),s="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+s+"return __p;\n";try{var o=new Function(n.variable||"obj","_",s)}catch(u){throw u.source=s,u}if(t)return o(t,T);var a=function(e){return o.call(this,e,T)};return a.source="function("+(n.variable||"obj")+"){\n"+s+"}",a},T.chain=function(e){return T(e).chain()};var F=function(e){return this._chain?T(e).chain():e};T.mixin(T),N(["pop","push","reverse","shift","sort","splice","unshift"],function(e){var t=r[e];T.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),(e=="shift"||e=="splice")&&n.length===0&&delete n[0],F.call(this,n)}}),N(["concat","join","slice"],function(e){var t=r[e];T.prototype[e]=function(){return F.call(this,t.apply(this._wrapped,arguments))}}),T.extend(T.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this);
--------------------------------------------------------------------------------
/src/css/font/fontello.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/lib/ajax.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.7.1
2 | (function() {
3 | var $, Ajax, Base, Collection, Extend, GenerateURL, Include, Model, Queue, Singleton, Spine,
4 | __slice = [].slice,
5 | __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
6 | __hasProp = {}.hasOwnProperty,
7 | __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
8 |
9 | Spine = this.Spine || require('spine');
10 |
11 | $ = Spine.$;
12 |
13 | Model = Spine.Model;
14 |
15 | Queue = $({});
16 |
17 | Ajax = {
18 | getURL: function(object) {
19 | if (object.className != null) {
20 | return this.generateURL(object);
21 | } else {
22 | return this.generateURL(object, encodeURIComponent(object.id));
23 | }
24 | },
25 | getCollectionURL: function(object) {
26 | return this.generateURL(object);
27 | },
28 | getScope: function(object) {
29 | return (typeof object.scope === "function" ? object.scope() : void 0) || object.scope;
30 | },
31 | getCollection: function(object) {
32 | if (object.url !== object.generateURL) {
33 | if (typeof object.url === 'function') {
34 | return object.url();
35 | } else {
36 | return object.url;
37 | }
38 | } else if (object.className != null) {
39 | return object.className.toLowerCase() + 's';
40 | }
41 | },
42 | generateURL: function() {
43 | var args, collection, object, path, scope;
44 | object = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
45 | collection = Ajax.getCollection(object) || Ajax.getCollection(object.constructor);
46 | scope = Ajax.getScope(object) || Ajax.getScope(object.constructor);
47 | args.unshift(collection);
48 | args.unshift(scope);
49 | path = args.join('/');
50 | path = path.replace(/(\/\/)/g, "/");
51 | path = path.replace(/^\/|\/$/g, "");
52 | if (path.indexOf("../") !== 0) {
53 | return Model.host + "/" + path;
54 | } else {
55 | return path;
56 | }
57 | },
58 | enabled: true,
59 | disable: function(callback) {
60 | var e;
61 | if (this.enabled) {
62 | this.enabled = false;
63 | try {
64 | return callback();
65 | } catch (_error) {
66 | e = _error;
67 | throw e;
68 | } finally {
69 | this.enabled = true;
70 | }
71 | } else {
72 | return callback();
73 | }
74 | },
75 | queue: function(request) {
76 | if (request) {
77 | return Queue.queue(request);
78 | } else {
79 | return Queue.queue();
80 | }
81 | },
82 | clearQueue: function() {
83 | return this.queue([]);
84 | },
85 | config: {
86 | loadMethod: 'GET',
87 | updateMethod: 'PUT',
88 | createMethod: 'POST',
89 | destroyMethod: 'DELETE'
90 | }
91 | };
92 |
93 | Base = (function() {
94 | function Base() {}
95 |
96 | Base.prototype.defaults = {
97 | dataType: 'json',
98 | processData: false,
99 | headers: {
100 | 'X-Requested-With': 'XMLHttpRequest'
101 | }
102 | };
103 |
104 | Base.prototype.queue = Ajax.queue;
105 |
106 | Base.prototype.ajax = function(params, defaults) {
107 | return $.ajax(this.ajaxSettings(params, defaults));
108 | };
109 |
110 | Base.prototype.ajaxQueue = function(params, defaults, record) {
111 | var deferred, jqXHR, parallel, promise, request, settings;
112 | jqXHR = null;
113 | deferred = $.Deferred();
114 | promise = deferred.promise();
115 | if (!Ajax.enabled) {
116 | return promise;
117 | }
118 | settings = this.ajaxSettings(params, defaults);
119 | parallel = settings.parallel !== void 0 ? settings.parallel : settings.type === 'GET';
120 | request = function(next) {
121 | var _ref;
122 | if ((record != null ? record.id : void 0) != null) {
123 | if (settings.url == null) {
124 | settings.url = Ajax.getURL(record);
125 | }
126 | if ((_ref = settings.data) != null) {
127 | _ref.id = record.id;
128 | }
129 | }
130 | if (typeof settings.data !== 'string' && settings.processData !== true) {
131 | settings.data = JSON.stringify(settings.data);
132 | }
133 | jqXHR = $.ajax(settings).done(deferred.resolve).fail(deferred.reject).then(next, next);
134 | if (parallel) {
135 | return Queue.dequeue();
136 | }
137 | };
138 | promise.abort = function(statusText) {
139 | var index;
140 | if (jqXHR) {
141 | return jqXHR.abort(statusText);
142 | }
143 | index = $.inArray(request, this.queue());
144 | if (index > -1) {
145 | this.queue().splice(index, 1);
146 | }
147 | deferred.rejectWith(settings.context || settings, [promise, statusText, '']);
148 | return promise;
149 | };
150 | this.queue(request);
151 | return promise;
152 | };
153 |
154 | Base.prototype.ajaxSettings = function(params, defaults) {
155 | return $.extend({}, this.defaults, defaults, params);
156 | };
157 |
158 | return Base;
159 |
160 | })();
161 |
162 | Collection = (function(_super) {
163 | __extends(Collection, _super);
164 |
165 | function Collection(model) {
166 | this.model = model;
167 | this.failResponse = __bind(this.failResponse, this);
168 | this.recordsResponse = __bind(this.recordsResponse, this);
169 | }
170 |
171 | Collection.prototype.find = function(id, params, options) {
172 | var record;
173 | if (options == null) {
174 | options = {};
175 | }
176 | record = new this.model({
177 | id: id
178 | });
179 | return this.ajaxQueue(params, {
180 | type: options.method || Ajax.config.loadMethod,
181 | url: options.url || Ajax.getURL(record),
182 | parallel: options.parallel
183 | }).done(this.recordsResponse).fail(this.failResponse);
184 | };
185 |
186 | Collection.prototype.all = function(params, options) {
187 | if (options == null) {
188 | options = {};
189 | }
190 | return this.ajaxQueue(params, {
191 | type: options.method || Ajax.config.loadMethod,
192 | url: options.url || Ajax.getURL(this.model),
193 | parallel: options.parallel
194 | }).done(this.recordsResponse).fail(this.failResponse);
195 | };
196 |
197 | Collection.prototype.fetch = function(params, options) {
198 | var id;
199 | if (params == null) {
200 | params = {};
201 | }
202 | if (options == null) {
203 | options = {};
204 | }
205 | if (id = params.id) {
206 | delete params.id;
207 | return this.find(id, params, options).done((function(_this) {
208 | return function(record) {
209 | return _this.model.refresh(record, options);
210 | };
211 | })(this));
212 | } else {
213 | return this.all(params, options).done((function(_this) {
214 | return function(records) {
215 | return _this.model.refresh(records, options);
216 | };
217 | })(this));
218 | }
219 | };
220 |
221 | Collection.prototype.recordsResponse = function(data, status, xhr) {
222 | return this.model.trigger('ajaxSuccess', null, status, xhr);
223 | };
224 |
225 | Collection.prototype.failResponse = function(xhr, statusText, error) {
226 | return this.model.trigger('ajaxError', null, xhr, statusText, error);
227 | };
228 |
229 | return Collection;
230 |
231 | })(Base);
232 |
233 | Singleton = (function(_super) {
234 | __extends(Singleton, _super);
235 |
236 | function Singleton(record) {
237 | this.record = record;
238 | this.failResponse = __bind(this.failResponse, this);
239 | this.recordResponse = __bind(this.recordResponse, this);
240 | this.model = this.record.constructor;
241 | }
242 |
243 | Singleton.prototype.reload = function(params, options) {
244 | if (options == null) {
245 | options = {};
246 | }
247 | return this.ajaxQueue(params, {
248 | type: options.method || Ajax.config.loadMethod,
249 | url: options.url,
250 | parallel: options.parallel
251 | }, this.record).done(this.recordResponse(options)).fail(this.failResponse(options));
252 | };
253 |
254 | Singleton.prototype.create = function(params, options) {
255 | if (options == null) {
256 | options = {};
257 | }
258 | return this.ajaxQueue(params, {
259 | type: options.method || Ajax.config.createMethod,
260 | contentType: 'application/json',
261 | data: this.record.toJSON(),
262 | url: options.url || Ajax.getCollectionURL(this.record),
263 | parallel: options.parallel
264 | }).done(this.recordResponse(options)).fail(this.failResponse(options));
265 | };
266 |
267 | Singleton.prototype.update = function(params, options) {
268 | if (options == null) {
269 | options = {};
270 | }
271 | return this.ajaxQueue(params, {
272 | type: options.method || Ajax.config.updateMethod,
273 | contentType: 'application/json',
274 | data: this.record.toJSON(),
275 | url: options.url,
276 | parallel: options.parallel
277 | }, this.record).done(this.recordResponse(options)).fail(this.failResponse(options));
278 | };
279 |
280 | Singleton.prototype.destroy = function(params, options) {
281 | if (options == null) {
282 | options = {};
283 | }
284 | return this.ajaxQueue(params, {
285 | type: options.method || Ajax.config.destroyMethod,
286 | url: options.url,
287 | parallel: options.parallel
288 | }, this.record).done(this.recordResponse(options)).fail(this.failResponse(options));
289 | };
290 |
291 | Singleton.prototype.recordResponse = function(options) {
292 | if (options == null) {
293 | options = {};
294 | }
295 | return (function(_this) {
296 | return function(data, status, xhr) {
297 | var _ref;
298 | Ajax.disable(function() {
299 | if (!(Spine.isBlank(data) || _this.record.destroyed)) {
300 | if (data.id && _this.record.id !== data.id) {
301 | _this.record.changeID(data.id);
302 | }
303 | return _this.record.refresh(data);
304 | }
305 | });
306 | _this.record.trigger('ajaxSuccess', data, status, xhr);
307 | return (_ref = options.done) != null ? _ref.apply(_this.record) : void 0;
308 | };
309 | })(this);
310 | };
311 |
312 | Singleton.prototype.failResponse = function(options) {
313 | if (options == null) {
314 | options = {};
315 | }
316 | return (function(_this) {
317 | return function(xhr, statusText, error) {
318 | var _ref;
319 | _this.record.trigger('ajaxError', xhr, statusText, error);
320 | return (_ref = options.fail) != null ? _ref.apply(_this.record) : void 0;
321 | };
322 | })(this);
323 | };
324 |
325 | return Singleton;
326 |
327 | })(Base);
328 |
329 | Model.host = '';
330 |
331 | GenerateURL = {
332 | include: function() {
333 | var args;
334 | args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
335 | args.unshift(encodeURIComponent(this.id));
336 | return Ajax.generateURL.apply(Ajax, [this].concat(__slice.call(args)));
337 | },
338 | extend: function() {
339 | var args;
340 | args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
341 | return Ajax.generateURL.apply(Ajax, [this].concat(__slice.call(args)));
342 | }
343 | };
344 |
345 | Include = {
346 | ajax: function() {
347 | return new Singleton(this);
348 | },
349 | generateURL: GenerateURL.include,
350 | url: GenerateURL.include
351 | };
352 |
353 | Extend = {
354 | ajax: function() {
355 | return new Collection(this);
356 | },
357 | generateURL: GenerateURL.extend,
358 | url: GenerateURL.extend
359 | };
360 |
361 | Model.Ajax = {
362 | extended: function() {
363 | this.fetch(this.ajaxFetch);
364 | this.change(this.ajaxChange);
365 | this.extend(Extend);
366 | return this.include(Include);
367 | },
368 | ajaxFetch: function() {
369 | var _ref;
370 | return (_ref = this.ajax()).fetch.apply(_ref, arguments);
371 | },
372 | ajaxChange: function(record, type, options) {
373 | if (options == null) {
374 | options = {};
375 | }
376 | if (options.ajax === false) {
377 | return;
378 | }
379 | return record.ajax()[type](options.ajax, options);
380 | }
381 | };
382 |
383 | Model.Ajax.Methods = {
384 | extended: function() {
385 | this.extend(Extend);
386 | return this.include(Include);
387 | }
388 | };
389 |
390 | Ajax.defaults = Base.prototype.defaults;
391 |
392 | Ajax.Base = Base;
393 |
394 | Ajax.Singleton = Singleton;
395 |
396 | Ajax.Collection = Collection;
397 |
398 | Spine.Ajax = Ajax;
399 |
400 | if (typeof module !== "undefined" && module !== null) {
401 | module.exports = Ajax;
402 | }
403 |
404 | }).call(this);
405 |
--------------------------------------------------------------------------------
/src/template/js/prism.js:
--------------------------------------------------------------------------------
1 | /* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript+java+php+coffeescript+scss+bash+c+cpp+python+sql+http+ruby+csharp+go&plugins=line-numbers */
2 | var self=typeof window!="undefined"?window:{},Prism=function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=self.Prism={util:{type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},clone:function(e){var n=t.util.type(e);switch(n){case"Object":var r={};for(var i in e)e.hasOwnProperty(i)&&(r[i]=t.util.clone(e[i]));return r;case"Array":return e.slice()}return e}},languages:{extend:function(e,n){var r=t.util.clone(t.languages[e]);for(var i in n)r[i]=n[i];return r},insertBefore:function(e,n,r,i){i=i||t.languages;var s=i[e],o={};for(var u in s)if(s.hasOwnProperty(u)){if(u==n)for(var a in r)r.hasOwnProperty(a)&&(o[a]=r[a]);o[u]=s[u]}return i[e]=o},DFS:function(e,n){for(var r in e){n.call(e,r,e[r]);t.util.type(e)==="Object"&&t.languages.DFS(e[r],n)}}},highlightAll:function(e,n){var r=document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code');for(var i=0,s;s=r[i++];)t.highlightElement(s,e===!0,n)},highlightElement:function(r,i,s){var o,u,a=r;while(a&&!e.test(a.className))a=a.parentNode;if(a){o=(a.className.match(e)||[,""])[1];u=t.languages[o]}if(!u)return;r.className=r.className.replace(e,"").replace(/\s+/g," ")+" language-"+o;a=r.parentNode;/pre/i.test(a.nodeName)&&(a.className=a.className.replace(e,"").replace(/\s+/g," ")+" language-"+o);var f=r.textContent;if(!f)return;f=f.replace(/&/g,"&").replace(/e.length)break e;if(p instanceof i)continue;a.lastIndex=0;var d=a.exec(p);if(d){l&&(c=d[1].length);var v=d.index-1+c,d=d[0].slice(c),m=d.length,g=v+m,y=p.slice(0,v+1),b=p.slice(g+1),w=[h,1];y&&w.push(y);var E=new i(u,f?t.tokenize(d,f):d);w.push(E);b&&w.push(b);Array.prototype.splice.apply(s,w)}}}return s},hooks:{all:{},add:function(e,n){var r=t.hooks.all;r[e]=r[e]||[];r[e].push(n)},run:function(e,n){var r=t.hooks.all[e];if(!r||!r.length)return;for(var i=0,s;s=r[i++];)s(n)}}},n=t.Token=function(e,t){this.type=e;this.content=t};n.stringify=function(e,r,i){if(typeof e=="string")return e;if(Object.prototype.toString.call(e)=="[object Array]")return e.map(function(t){return n.stringify(t,r,e)}).join("");var s={type:e.type,content:n.stringify(e.content,r,i),tag:"span",classes:["token",e.type],attributes:{},language:r,parent:i};s.type=="comment"&&(s.attributes.spellcheck="true");t.hooks.run("wrap",s);var o="";for(var u in s.attributes)o+=u+'="'+(s.attributes[u]||"")+'"';return"<"+s.tag+' class="'+s.classes.join(" ")+'" '+o+">"+s.content+""+s.tag+">"};if(!self.document){if(!self.addEventListener)return self.Prism;self.addEventListener("message",function(e){var n=JSON.parse(e.data),r=n.language,i=n.code;self.postMessage(JSON.stringify(t.tokenize(i,t.languages[r])));self.close()},!1);return self.Prism}var r=document.getElementsByTagName("script");r=r[r.length-1];if(r){t.filename=r.src;document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)}return self.Prism}();typeof module!="undefined"&&module.exports&&(module.exports=Prism);;
3 | Prism.languages.markup={comment:/<!--[\w\W]*?-->/g,prolog:/<\?.+?\?>/,doctype:/<!DOCTYPE.+?>/,cdata:/<!\[CDATA\[[\w\W]*?]]>/i,tag:{pattern:/<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|[^\s'">=]+))?\s*)*\/?>/gi,inside:{tag:{pattern:/^<\/?[\w:-]+/i,inside:{punctuation:/^<\/?/,namespace:/^[\w-]+?:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/gi,inside:{punctuation:/=|>|"/g}},punctuation:/\/?>/g,"attr-name":{pattern:/[\w:-]+/g,inside:{namespace:/^[\w-]+?:/}}}},entity:/&#?[\da-z]{1,8};/gi};Prism.hooks.add("wrap",function(e){e.type==="entity"&&(e.attributes.title=e.content.replace(/&/,"&"))});;
4 | Prism.languages.css={comment:/\/\*[\w\W]*?\*\//g,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*{))/gi,inside:{punctuation:/[;:]/g}},url:/url\((["']?).*?\1\)/gi,selector:/[^\{\}\s][^\{\};]*(?=\s*\{)/g,property:/(\b|\B)[\w-]+(?=\s*:)/ig,string:/("|')(\\?.)*?\1/g,important:/\B!important\b/gi,ignore:/&(lt|gt|amp);/gi,punctuation:/[\{\};:]/g};Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{style:{pattern:/(<|<)style[\w\W]*?(>|>)[\w\W]*?(<|<)\/style(>|>)/ig,inside:{tag:{pattern:/(<|<)style[\w\W]*?(>|>)|(<|<)\/style(>|>)/ig,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.css}}});;
5 | Prism.languages.clike={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])\/\/.*?(\r?\n|$))/g,lookbehind:!0},string:/("|')(\\?.)*?\1/g,"class-name":{pattern:/((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/ig,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/g,"boolean":/\b(true|false)\b/g,"function":{pattern:/[a-z0-9_]+\(/ig,inside:{punctuation:/\(/}},number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g,operator:/[-+]{1,2}|!|<=?|>=?|={1,3}|(&){1,2}|\|?\||\?|\*|\/|\~|\^|\%/g,ignore:/&(lt|gt|amp);/gi,punctuation:/[{}[\];(),.:]/g};;
6 | Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(var|let|if|else|while|do|for|return|in|instanceof|function|get|set|new|with|typeof|try|throw|catch|finally|null|break|continue|this)\b/g,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?|NaN|-?Infinity)\b/g});Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g,lookbehind:!0}});Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/(<|<)script[\w\W]*?(>|>)[\w\W]*?(<|<)\/script(>|>)/ig,inside:{tag:{pattern:/(<|<)script[\w\W]*?(>|>)|(<|<)\/script(>|>)/ig,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.javascript}}});;
7 | Prism.languages.java=Prism.languages.extend("clike",{keyword:/\b(abstract|continue|for|new|switch|assert|default|goto|package|synchronized|boolean|do|if|private|this|break|double|implements|protected|throw|byte|else|import|public|throws|case|enum|instanceof|return|transient|catch|extends|int|short|try|char|final|interface|static|void|class|finally|long|strictfp|volatile|const|float|native|super|while)\b/g,number:/\b0b[01]+\b|\b0x[\da-f]*\.?[\da-fp\-]+\b|\b\d*\.?\d+[e]?[\d]*[df]\b|\W\d*\.?\d+\b/gi,operator:{pattern:/([^\.]|^)([-+]{1,2}|!|=?<|=?>|={1,2}|(&){1,2}|\|?\||\?|\*|\/|%|\^|(<){2}|($gt;){2,3}|:|~)/g,lookbehind:!0}});;
8 | /**
9 | * Original by Aaron Harun: http://aahacreative.com/2012/07/31/php-syntax-highlighting-prism/
10 | * Modified by Miles Johnson: http://milesj.me
11 | *
12 | * Supports the following:
13 | * - Extends clike syntax
14 | * - Support for PHP 5.3 and 5.4 (namespaces, traits, etc)
15 | * - Smarter constant and function matching
16 | *
17 | * Adds the following new token classes:
18 | * constant, delimiter, variable, function, package
19 | */Prism.languages.php=Prism.languages.extend("clike",{keyword:/\b(and|or|xor|array|as|break|case|cfunction|class|const|continue|declare|default|die|do|else|elseif|enddeclare|endfor|endforeach|endif|endswitch|endwhile|extends|for|foreach|function|include|include_once|global|if|new|return|static|switch|use|require|require_once|var|while|abstract|interface|public|implements|private|protected|parent|throw|null|echo|print|trait|namespace|final|yield|goto|instanceof|finally|try|catch)\b/ig,constant:/\b[A-Z0-9_]{2,}\b/g});Prism.languages.insertBefore("php","keyword",{delimiter:/(\?>|<\?php|<\?)/ig,variable:/(\$\w+)\b/ig,"package":{pattern:/(\\|namespace\s+|use\s+)[\w\\]+/g,lookbehind:!0,inside:{punctuation:/\\/}}});Prism.languages.insertBefore("php","operator",{property:{pattern:/(->)[\w]+/g,lookbehind:!0}});if(Prism.languages.markup){Prism.hooks.add("before-highlight",function(e){if(e.language!=="php")return;e.tokenStack=[];e.code=e.code.replace(/(?:<\?php|<\?|<\?php|<\?)[\w\W]*?(?:\?>|\?>)/ig,function(t){e.tokenStack.push(t);return"{{{PHP"+e.tokenStack.length+"}}}"})});Prism.hooks.add("after-highlight",function(e){if(e.language!=="php")return;for(var t=0,n;n=e.tokenStack[t];t++)e.highlightedCode=e.highlightedCode.replace("{{{PHP"+(t+1)+"}}}",Prism.highlight(n,e.grammar,"php"));e.element.innerHTML=e.highlightedCode});Prism.hooks.add("wrap",function(e){e.language==="php"&&e.type==="markup"&&(e.content=e.content.replace(/(\{\{\{PHP[0-9]+\}\}\})/g,'$1'))});Prism.languages.insertBefore("php","comment",{markup:{pattern:/(<|<)[^?]\/?(.*?)(>|>)/g,inside:Prism.languages.markup},php:/\{\{\{PHP[0-9]+\}\}\}/g})};;
20 | Prism.languages.coffeescript=Prism.languages.extend("javascript",{"block-comment":/([#]{3}\s*\r?\n(.*\s*\r*\n*)\s*?\r?\n[#]{3})/g,comment:/(\s|^)([#]{1}[^#^\r^\n]{2,}?(\r?\n|$))/g,keyword:/\b(this|window|delete|class|extends|namespace|extend|ar|let|if|else|while|do|for|each|of|return|in|instanceof|new|with|typeof|try|catch|finally|null|undefined|break|continue)\b/g});Prism.languages.insertBefore("coffeescript","keyword",{"function":{pattern:/[a-z|A-z]+\s*[:|=]\s*(\([.|a-z\s|,|:|{|}|\"|\'|=]*\))?\s*->/gi,inside:{"function-name":/[_?a-z-|A-Z-]+(\s*[:|=])| @[_?$?a-z-|A-Z-]+(\s*)| /g,operator:/[-+]{1,2}|!|=?<|=?>|={1,2}|(&){1,2}|\|?\||\?|\*|\//g}},"attr-name":/[_?a-z-|A-Z-]+(\s*:)| @[_?$?a-z-|A-Z-]+(\s*)| /g});;
21 | Prism.languages.scss=Prism.languages.extend("css",{comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|\/\/.*?(\r?\n|$))/g,lookbehind:!0},atrule:/@[\w-]+(?=\s+(\(|\{|;))/gi,url:/([-a-z]+-)*url(?=\()/gi,selector:/([^@;\{\}\(\)]?([^@;\{\}\(\)]|&|\#\{\$[-_\w]+\})+)(?=\s*\{(\}|\s|[^\}]+(:|\{)[^\}]+))/gm});Prism.languages.insertBefore("scss","atrule",{keyword:/@(if|else if|else|for|each|while|import|extend|debug|warn|mixin|include|function|return|content)|(?=@for\s+\$[-_\w]+\s)+from/i});Prism.languages.insertBefore("scss","property",{variable:/((\$[-_\w]+)|(#\{\$[-_\w]+\}))/i});Prism.languages.insertBefore("scss","ignore",{placeholder:/%[-_\w]+/i,statement:/\B!(default|optional)\b/gi,"boolean":/\b(true|false)\b/g,"null":/\b(null)\b/g,operator:/\s+([-+]{1,2}|={1,2}|!=|\|?\||\?|\*|\/|\%)\s+/g});;
22 | Prism.languages.bash=Prism.languages.extend("clike",{comment:{pattern:/(^|[^"{\\])(#.*?(\r?\n|$))/g,lookbehind:!0},string:{pattern:/("|')(\\?[\s\S])*?\1/g,inside:{property:/\$([a-zA-Z0-9_#\?\-\*!@]+|\{[^\}]+\})/g}},keyword:/\b(if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)\b/g});Prism.languages.insertBefore("bash","keyword",{property:/\$([a-zA-Z0-9_#\?\-\*!@]+|\{[^}]+\})/g});Prism.languages.insertBefore("bash","comment",{important:/(^#!\s*\/bin\/bash)|(^#!\s*\/bin\/sh)/g});;
23 | Prism.languages.c=Prism.languages.extend("clike",{keyword:/\b(asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/g,operator:/[-+]{1,2}|!=?|<{1,2}=?|>{1,2}=?|\->|={1,2}|\^|~|%|(&){1,2}|\|?\||\?|\*|\//g});Prism.languages.insertBefore("c","keyword",{property:{pattern:/#[a-zA-Z]+\ .*/g,inside:{property:/<[a-zA-Z.]+>/g}}});;
24 | Prism.languages.cpp=Prism.languages.extend("c",{keyword:/\b(alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|class|compl|const|constexpr|const_cast|continue|decltype|default|delete|delete\[\]|do|double|dynamic_cast|else|enum|explicit|export|extern|float|for|friend|goto|if|inline|int|long|mutable|namespace|new|new\[\]|noexcept|nullptr|operator|private|protected|public|register|reinterpret_cast|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/g,operator:/[-+]{1,2}|!=?|<{1,2}=?|>{1,2}=?|\->|:{1,2}|={1,2}|\^|~|%|(&){1,2}|\|?\||\?|\*|\/|\b(and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/g});;
25 | Prism.languages.python={comment:{pattern:/(^|[^\\])#.*?(\r?\n|$)/g,lookbehind:!0},string:/("|')(\\?.)*?\1/g,keyword:/\b(as|assert|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|pass|print|raise|return|try|while|with|yield)\b/g,"boolean":/\b(True|False)\b/g,number:/\b-?(0x)?\d*\.?[\da-f]+\b/g,operator:/[-+]{1,2}|=?<|=?>|!|={1,2}|(&){1,2}|(&){1,2}|\|?\||\?|\*|\/|~|\^|%|\b(or|and|not)\b/g,ignore:/&(lt|gt|amp);/gi,punctuation:/[{}[\];(),.:]/g};;
26 | Prism.languages.sql={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|((--)|(\/\/)|#).*?(\r?\n|$))/g,lookbehind:!0},string:/("|')(\\?.)*?\1/g,keyword:/\b(ACTION|ADD|AFTER|ALGORITHM|ALTER|ANALYZE|APPLY|AS|ASC|AUTHORIZATION|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADE|CASCADED|CASE|CHAIN|CHAR VARYING|CHARACTER VARYING|CHECK|CHECKPOINT|CLOSE|CLUSTERED|COALESCE|COLUMN|COLUMNS|COMMENT|COMMIT|COMMITTED|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS|CONTAINSTABLE|CONTINUE|CONVERT|CREATE|CROSS|CURRENT|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|CURRENT_USER|CURSOR|DATA|DATABASE|DATABASES|DATETIME|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DOUBLE PRECISION|DROP|DUMMY|DUMP|DUMPFILE|DUPLICATE KEY|ELSE|ENABLE|ENCLOSED BY|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPE|ESCAPED BY|EXCEPT|EXEC|EXECUTE|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR|FOR EACH ROW|FORCE|FOREIGN|FREETEXT|FREETEXTTABLE|FROM|FULL|FUNCTION|GEOMETRY|GEOMETRYCOLLECTION|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|IDENTITY|IDENTITY_INSERT|IDENTITYCOL|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTO|INVOKER|ISOLATION LEVEL|JOIN|KEY|KEYS|KILL|LANGUAGE SQL|LAST|LEFT|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONGBLOB|LONGTEXT|MATCH|MATCHED|MEDIUMBLOB|MEDIUMINT|MEDIUMTEXT|MERGE|MIDDLEINT|MODIFIES SQL DATA|MODIFY|MULTILINESTRING|MULTIPOINT|MULTIPOLYGON|NATIONAL|NATIONAL CHAR VARYING|NATIONAL CHARACTER|NATIONAL CHARACTER VARYING|NATIONAL VARCHAR|NATURAL|NCHAR|NCHAR VARCHAR|NEXT|NO|NO SQL|NOCHECK|NOCYCLE|NONCLUSTERED|NULLIF|NUMERIC|OF|OFF|OFFSETS|ON|OPEN|OPENDATASOURCE|OPENQUERY|OPENROWSET|OPTIMIZE|OPTION|OPTIONALLY|ORDER|OUT|OUTER|OUTFILE|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREV|PRIMARY|PRINT|PRIVILEGES|PROC|PROCEDURE|PUBLIC|PURGE|QUICK|RAISERROR|READ|READS SQL DATA|READTEXT|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEATABLE|REPLICATION|REQUIRE|RESTORE|RESTRICT|RETURN|RETURNS|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROWCOUNT|ROWGUIDCOL|ROWS?|RTREE|RULE|SAVE|SAVEPOINT|SCHEMA|SELECT|SERIAL|SERIALIZABLE|SESSION|SESSION_USER|SET|SETUSER|SHARE MODE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|START|STARTING BY|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLE|TABLES|TABLESPACE|TEMPORARY|TEMPTABLE|TERMINATED BY|TEXT|TEXTSIZE|THEN|TIMESTAMP|TINYBLOB|TINYINT|TINYTEXT|TO|TOP|TRAN|TRANSACTION|TRANSACTIONS|TRIGGER|TRUNCATE|TSEQUAL|TYPE|TYPES|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNPIVOT|UPDATE|UPDATETEXT|USAGE|USE|USER|USING|VALUE|VALUES|VARBINARY|VARCHAR|VARCHARACTER|VARYING|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH|WITH ROLLUP|WITHIN|WORK|WRITE|WRITETEXT)\b/gi,"boolean":/\b(TRUE|FALSE|NULL)\b/gi,number:/\b-?(0x)?\d*\.?[\da-f]+\b/g,operator:/\b(ALL|AND|ANY|BETWEEN|EXISTS|IN|LIKE|NOT|OR|IS|UNIQUE|CHARACTER SET|COLLATE|DIV|OFFSET|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b|[-+]{1}|!|=?<|=?>|={1}|(&){1,2}|\|?\||\?|\*|\//gi,ignore:/&(lt|gt|amp);/gi,punctuation:/[;[\]()`,.]/g};;
27 | Prism.languages.http={"request-line":{pattern:/^(POST|GET|PUT|DELETE|OPTIONS|PATCH|TRACE|CONNECT)\b\shttps?:\/\/\S+\sHTTP\/[0-9.]+/g,inside:{property:/^\b(POST|GET|PUT|DELETE|OPTIONS|PATCH|TRACE|CONNECT)\b/g,"attr-name":/:\w+/g}},"response-status":{pattern:/^HTTP\/1.[01] [0-9]+.*/g,inside:{property:/[0-9]+[A-Z\s-]+$/g}},keyword:/^[\w-]+:(?=.+)/gm};var httpLanguages={"application/json":Prism.languages.javascript,"application/xml":Prism.languages.markup,"text/xml":Prism.languages.markup,"text/html":Prism.languages.markup};for(var contentType in httpLanguages)if(httpLanguages[contentType]){var options={};options[contentType]={pattern:new RegExp("(content-type:\\s*"+contentType+"[\\w\\W]*?)\\n\\n[\\w\\W]*","gi"),lookbehind:!0,inside:{rest:httpLanguages[contentType]}};Prism.languages.insertBefore("http","keyword",options)};;
28 | /**
29 | * Original by Samuel Flores
30 | *
31 | * Adds the following new token classes:
32 | * constant, builtin, variable, symbol, regex
33 | */Prism.languages.ruby=Prism.languages.extend("clike",{comment:/#[^\r\n]*(\r?\n|$)/g,keyword:/\b(alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|false|for|if|in|module|new|next|nil|not|or|raise|redo|require|rescue|retry|return|self|super|then|throw|true|undef|unless|until|when|while|yield)\b/g,builtin:/\b(Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Stat|File|Fixnum|Fload|Hash|Integer|IO|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|String|Struct|TMS|Symbol|ThreadGroup|Thread|Time|TrueClass)\b/,constant:/\b[A-Z][a-zA-Z_0-9]*[?!]?\b/g});Prism.languages.insertBefore("ruby","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g,lookbehind:!0},variable:/[@$]+\b[a-zA-Z_][a-zA-Z_0-9]*[?!]?\b/g,symbol:/:\b[a-zA-Z_][a-zA-Z_0-9]*[?!]?\b/g});;
34 | Prism.languages.csharp=Prism.languages.extend("clike",{keyword:/\b(abstract|as|base|bool|break|byte|case|catch|char|checked|class|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|namespace|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|void|volatile|while|add|alias|ascending|async|await|descending|dynamic|from|get|global|group|into|join|let|orderby|partial|remove|select|set|value|var|where|yield)\b/g,string:/@?("|')(\\?.)*?\1/g,preprocessor:/^\s*#.*/gm,number:/\b-?(0x)?\d*\.?\d+\b/g});;
35 | Prism.languages.go=Prism.languages.extend("clike",{keyword:/\b(break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/g,builtin:/\b(bool|byte|complex(64|128)|error|float(32|64)|rune|string|u?int(8|16|32|64|)|uintptr|append|cap|close|complex|copy|delete|imag|len|make|new|panic|print(ln)?|real|recover)\b/g,"boolean":/\b(_|iota|nil|true|false)\b/g,operator:/([(){}\[\]]|[*\/%^!]=?|\+[=+]?|-[>=-]?|\|[=|]?|>[=>]?|<(<|[=-])?|==?|&(&|=|^=?)?|\.(\.\.)?|[,;]|:=?)/g,number:/\b(-?(0x[a-f\d]+|(\d+\.?\d*|\.\d+)(e[-+]?\d+)?)i?)\b/ig,string:/("|'|`)(\\?.|\r|\n)*?\1/g});delete Prism.languages.go["class-name"];;
36 | Prism.hooks.add("after-highlight",function(e){var t=e.element.parentNode;if(!t||!/pre/i.test(t.nodeName)||t.className.indexOf("line-numbers")===-1){return}var n=1+e.code.split("\n").length;var r;lines=new Array(n);lines=lines.join("");r=document.createElement("span");r.className="line-numbers-rows";r.innerHTML=lines;if(t.hasAttribute("data-start")){t.style.counterReset="linenumber "+(parseInt(t.getAttribute("data-start"),10)-1)}e.element.appendChild(r)})
37 | ;
38 |
--------------------------------------------------------------------------------
/src/app.js:
--------------------------------------------------------------------------------
1 | var global = {};
2 | var gconfig = null;
3 | var repo = null;
4 | var editor = null;
5 | var contentpattern = /\n([\s\S]*)\n\n/m;
6 | var pathpattern = /\/\/path\nvar path=\"(.*)\";\n\/\/path end\n/m;
7 | var mdpattern = /\n([\s\S]*)\n\n/m;
8 | Date.prototype.yyyymmdd = function() {
9 | var yyyy = this.getFullYear().toString();
10 | var mm = (this.getMonth()+1).toString();
11 | var dd = this.getDate().toString();
12 | return yyyy + "-" + (mm[1]?mm:"0"+mm[0]) + "-" + (dd[1]?dd:"0"+dd[0]);
13 | };
14 | function reescape(data) {
15 | return data.replace(/>/g, ">").replace(/"+reescape(a3)+" ";});
22 | tmp = tmp.replace(/~~~~\n([\s\S]*?)~~~~\n/mg, function(a1, a2) {return ""+reescape(a2)+""});
23 | tmp = converter.makeHtml(tmp);
24 | $("#edithtml").html(tmp);
25 | Prism.highlightAll();
26 | MathJax.Hub.Queue(["Typeset", MathJax.Hub, "edithtml"]);
27 | }
28 | function curry(fn) {
29 | var args = Array.prototype.slice.call(arguments, 1);
30 | return function() {
31 | var innerArgs = Array.prototype.slice.call(arguments);
32 | var finalArgs = args.concat(innerArgs);
33 | return fn.apply(null, finalArgs);
34 | };
35 | }
36 | function asyncFinish(total, success) {
37 | var cnt = 0;
38 | $("#loading").show();
39 | return function() {
40 | cnt++;
41 | if (cnt == total) {
42 | $("#loading").hide();
43 | if (typeof success == "function")
44 | success();
45 | }
46 | }
47 | }
48 | function asyncSeq(success) {
49 | var args = Array.prototype.slice.call(arguments, 1);
50 | var finish = asyncFinish(args.length, success);
51 | for (var i = 0; i < args.length; ++i) {
52 | args[i](finish);
53 | }
54 | }
55 | function syncSeq(success) {
56 | var args = Array.prototype.slice.call(arguments, 1);
57 | var finish = asyncFinish(1, success);
58 | var l = args.length;
59 | var tmp = curry(args[l-1], finish);
60 | for (var i = l-2; i >= 0; --i)
61 | tmp = curry(args[i], tmp);
62 | tmp();
63 | }
64 | function errShow(item, err) {
65 | if (typeof err != "undefined" && err != null) {
66 | console.log(err);
67 | $("#loading").hide();
68 | item.show();
69 | return true;
70 | }
71 | return false;
72 | }
73 | function asyncWrite(data, target, err, finish) {
74 | if (!repo)
75 | Spine.Route.navigate("");
76 | repo.write("master", target, data, "simple",
77 | function(e) {
78 | var ret = err(e);
79 | if (ret == false)
80 | finish();
81 | });
82 | }
83 | function asyncWriteFile(source, target, err, finish) {
84 | if (!repo)
85 | Spine.Route.navigate("");
86 | $.ajax({
87 | url: source,
88 | type: "GET",
89 | success: function(data) {asyncWrite(data, target, err, finish)},
90 | error: function(e) {err(e);}
91 | });
92 | }
93 | function checkpass(user, pass, cbsuccess, cberror) {
94 | var github = new Github({
95 | username: user,
96 | password: pass,
97 | auth: "basic"
98 | });
99 | var u = github.getUser();
100 | u.show(user, function(err, ret){
101 | $("#loading").hide()
102 | if (!cberror(err)) {
103 | global.github = github;
104 | global.user = user;
105 | repo = github.getRepo(user, user+".github.io");
106 | cbsuccess();
107 | }
108 | });
109 | }
110 | $(document).ready(function() {
111 | var Logins = Spine.Controller.sub({
112 | el: $("#login"),
113 | elements: {
114 | "form": "form",
115 | "#loginuser": "user",
116 | "#loginpass": "pass",
117 | "#loginerror": "err",
118 | },
119 | events: {
120 | "submit form": "check",
121 | },
122 | check: function(e) {
123 | $("#loading").show();
124 | e.preventDefault();
125 | checkpass(this.user.val(), this.pass.val(),
126 | function(){Spine.Route.navigate("/main");},
127 | curry(errShow, this.err));
128 | },
129 | init: function() {
130 | this.user.val("");
131 | this.pass.val("");
132 | $("#loading").hide();
133 | this.err.hide();
134 | }
135 | });
136 | var Mains = Spine.Controller.sub({
137 | el: $("#main"),
138 | elements: {
139 | "#initerror": "err",
140 | "#initok": "ok",
141 | },
142 | events: {
143 | "click #init": "initRepo",
144 | "click #go": "go",
145 | },
146 | initRepo: function(e) {
147 | e.preventDefault();
148 | var error = curry(errShow, this.err);
149 | var a1 = curry(asyncWriteFile, "template/index.html", "index.html", error);
150 | var a2 = curry(asyncWriteFile, "template/main.css", "main.css", error);
151 | var a3 = curry(asyncWriteFile, "template/main.js", "main.js", error);
152 | var config = {"name": global.user, "number_of_posts_per_page": 7, "disqus_shortname": "", "posts": [], "pages": []};
153 | var a4 = curry(asyncWrite, JSON.stringify(config), "main.json", error);
154 | var a5 = curry(asyncWrite, "", "CNAME", error);
155 | syncSeq(function() {$("#initok").show()}, a1, a2, a3, a4, a5);
156 | },
157 | go: function(e) {
158 | this.navigate("/posts");
159 | },
160 | init: function() {
161 | $("#loading").hide();
162 | this.err.hide();
163 | }
164 | });
165 | var Posts = Spine.Controller.sub({
166 | el: $("#posts"),
167 | init: function(param) {
168 | $("#loading").hide();
169 | if (editor != null)
170 | editor.destroy();
171 | var type = null;
172 | var num = null;
173 | var now = null;
174 | if (typeof param != "undefined" && param.hasOwnProperty("type"))
175 | type = param.type;
176 | if (typeof param != "undefined" && param.hasOwnProperty("num"))
177 | num = param.num;
178 | if (repo != null) {
179 | $("#loading").show();
180 | repo.read("master", "main.json", function(err, data) {
181 | $("#loading").hide();
182 | $("#posttitle").val("");
183 | $("#postpath").val("");
184 | $("#postdate").val("");
185 | $("#posttags").val("");
186 | $("#editmd").val(sessionStorage.getItem("editmd") || "before begin to write please click 'new post' or 'new page' first");
187 | $("#edithtml").html("");
188 | var config = JSON.parse(data);
189 | config.posts.sort(function(a, b){
190 | if (a.date > b.date)
191 | return -1;
192 | if (a.date < b.date)
193 | return 1;
194 | return 0;
195 | });
196 | gconfig = config;
197 | var posts = config.posts;
198 | var pages = config.pages;
199 | for (var i = 0; i < posts.length; ++i) {
200 | posts[i].num = i;
201 | posts[i].type = "post";
202 | posts[i].active = false;
203 | if (type == "post" && num != "null" && Math.floor(num) == i) {
204 | posts[i].active = true;
205 | now = posts[i];
206 | $("#postSave").attr("href", "#/posts/savepost");
207 | $("#postDelete").attr("href", "#/posts/deletepost/"+i);
208 | }
209 | }
210 | for (var i = 0; i < pages.length; ++i) {
211 | pages[i].num = i;
212 | pages[i].type = "page";
213 | pages[i].active = false;
214 | if (type == "page" && num != "null" && Math.floor(num) == i) {
215 | pages[i].active = true;
216 | now = pages[i];
217 | $("#postSave").attr("href", "#/posts/savepage");
218 | $("#postDelete").attr("href", "#/posts/deletepage/"+i);
219 | }
220 | }
221 | var itemTemplate = Hogan.compile($("#postsItem").html());
222 | var postsItemHtml = itemTemplate.render({items: posts});
223 | var pagesItemHtml = itemTemplate.render({items: pages});
224 | $("#postItems").html(postsItemHtml);
225 | $("#pageItems").html(pagesItemHtml);
226 | if (type != null && type.slice(0, 3) == "new") {
227 | if (type.slice(3) == "post") {
228 | $("#postSave").attr("href", "#/posts/savepost");
229 | $("#postDelete").attr("href", "#/posts");
230 | }
231 | if (type.slice(3) == "page") {
232 | $("#postSave").attr("href", "#/posts/savepage");
233 | $("#postDelete").attr("href", "#/posts");
234 | }
235 | $("#postdate").val((new Date()).yyyymmdd());
236 | }
237 | if (now != null) {
238 | $("#posttitle").val(now.title);
239 | $("#postpath").val(now.path);
240 | $("#postdate").val(now.date);
241 | $("#posttags").val(now.tags);
242 | if (now.path.slice(0, 5) != "http:" && now.path.slice(0, 6) != "https:") {
243 | $("#loading").show();
244 | repo.read("master", now.path, function(err, data) {
245 | $("#loading").hide();
246 | var content = data.match(contentpattern)[1];
247 | var md = data.match(mdpattern)[1];
248 | $("#editmd").val(md);
249 | $("#edithtml").html(content);
250 | });
251 | }
252 | }
253 | });
254 | }
255 | }
256 | });
257 | var SimpleApp = Spine.Controller.sub({
258 | el: $("body"),
259 | init: function() {
260 | this.logins = new Logins();
261 | this.mains = new Mains();
262 | this.posts = new Posts();
263 | $("#postDelete").click(function(){return confirm("Are you sure you want to delete?");});
264 | this.routes({
265 | "": function() {this.logins.init();this.logins.active();},
266 | "/main": function() {this.mains.init();this.mains.active();},
267 | "/posts/:type/:num": function(param) {
268 | var type = param.type;
269 | var num = Math.floor(param.num);
270 | var temp = this;
271 | if (type.slice(0, 6) == "delete") {
272 | $("#loading").show();
273 | var posts = [];
274 | if (type == "deletepost") {
275 | var now = gconfig.posts[num];
276 | for (var i = 0; i < gconfig.posts.length; ++i) {
277 | if (i != num)
278 | posts.push(gconfig.posts[i]);
279 | }
280 | gconfig.posts = posts;
281 | }
282 | if (type == "deletepage") {
283 | var now = gconfig.pages[num];
284 | for (var i = 0; i < gconfig.pages.length; ++i) {
285 | if (i != num)
286 | posts.push(gconfig.pages[i]);
287 | }
288 | gconfig.pages = posts;
289 | }
290 | repo.write("master", "main.json", JSON.stringify(gconfig), "remove", function(err) {
291 | if (now.path.slice(0, 5) != "http:" && now.path.slice(0, 6) != "https:") {
292 | repo.delete("master", now.path, function(err) {
293 | temp.posts.init(param);
294 | temp.posts.active();
295 | });
296 | }
297 | else {
298 | temp.posts.init(param);
299 | temp.posts.active();
300 | }
301 | });
302 | }
303 | else {
304 | temp.posts.init(param);
305 | temp.posts.active();
306 | }
307 | },
308 | "/posts/:type": function(param) {
309 | var type = param.type;
310 | var temp = this;
311 | if (type.slice(0, 4) == "save") {
312 | $("#loading").show();
313 | if (type == "savepost") {
314 | var template = "template/post.html";
315 | var posts = gconfig.posts;
316 | }
317 | if (type == "savepage") {
318 | var template = "template/page.html";
319 | var posts = gconfig.pages;
320 | }
321 | var now = {"title": $("#posttitle").val(),
322 | "date": $("#postdate").val(),
323 | "tags": $("#posttags").val(),
324 | "path": $("#postpath").val()};
325 | var mark = null;
326 | for (var i = 0; i < posts.length; ++i)
327 | if (posts[i].path == now.path)
328 | mark = i;
329 | if (mark != null)
330 | posts[mark] = now;
331 | else
332 | posts.unshift(now);
333 | var content = $("#edithtml").html().replace(/\$/mg, "$$$$");
334 | var md = $("#editmd").val().replace(/\$/mg, "$$$$");
335 | $.ajax({
336 | url: template,
337 | type: "GET",
338 | success: function(data) {
339 | $("#saveerror").hide();
340 | data = data.replace(contentpattern, "\n"+content+"\n\n");
341 | data = data.replace("//path//", now.path);
342 | data = data.replace(mdpattern, "\n"+md+"\n\n");
343 | if (now.path.slice(0, 5) != "http:" && now.path.slice(0, 6) != "https:") {
344 | repo.write("master", now.path, data, "save", function(err) {
345 | repo.write("master", "main.json", JSON.stringify(gconfig), "save", function(err) {
346 | if (!errShow($("saveerror", err))) {
347 | temp.posts.init(param);
348 | temp.posts.active();
349 | }
350 | });
351 | });
352 | }
353 | else {
354 | repo.write("master", "main.json", JSON.stringify(gconfig), "save", function(err) {
355 | if (!errShow($("saveerror", err))) {
356 | temp.posts.init(param);
357 | temp.posts.active();
358 | }
359 | });
360 | }
361 | },
362 | error: function(e) {err(e);}
363 | });
364 | }
365 | else {
366 | temp.posts.init(param);
367 | temp.posts.active();
368 | }
369 | },
370 | "/posts": function() {this.posts.init();this.posts.active();}
371 | });
372 | this.manager = new Spine.Manager(this.logins, this.mains, this.posts);
373 | Spine.Route.setup();
374 | }
375 | });
376 | new SimpleApp();
377 | $("#editmd").on("keyup", function() {
378 | mdupdate();
379 | });
380 | $("#editmd").on("dragenter", function(e) {
381 | e.stopPropagation();
382 | e.preventDefault();
383 | });
384 | $("#editmd").on("dragover", function(e) {
385 | e.stopPropagation();
386 | e.preventDefault();
387 | });
388 | $("#editmd").on("drop", function(e) {
389 | e.stopPropagation();
390 | e.preventDefault();
391 | var a = e.originalEvent;
392 | var files = a.target.files || a.dataTransfer && a.dataTransfer.files;
393 | var tmp = null;
394 | for (var i = 0; i < files.length; i++) {
395 | if (files[i].type.match("image.*")) {
396 | tmp = files[i];
397 | break;
398 | }
399 | }
400 | if (tmp != null) {
401 | var reader = new FileReader();
402 | reader.onload = function() {
403 | var name = tmp.name;
404 | var data = reader.result;
405 | var cursor = $("#editmd")[0].selectionStart;
406 | var content = $("#editmd").val();
407 | var l = content.length;
408 | var head = content.substring(0, cursor);
409 | var tail = content.substring(cursor, l);
410 | var url = " ";
411 | $("#editmd").val(head+"upload image now!"+tail);
412 | mdupdate();
413 | repo.write("master", "img/"+name, data, "upload image",
414 | function(e) {
415 | if (typeof err != "undefined" && err != null) {
416 | console.log(err);
417 | $("#editmd").val(head+"upload image failed"+tail);
418 | }
419 | else {
420 | $("#editmd").val(head+url+tail);
421 | }
422 | mdupdate();
423 | });
424 | };
425 | reader.readAsArrayBuffer(tmp);
426 | }
427 | });
428 | });
429 |
--------------------------------------------------------------------------------
/src/lib/github.js:
--------------------------------------------------------------------------------
1 | // Github.js 0.9.0
2 | // (c) 2013 Michael Aufreiter, Development Seed
3 | // Github.js is freely distributable under the MIT license.
4 | // For all details and documentation:
5 | // http://substance.io/michael/github
6 |
7 | (function() {
8 |
9 | // Initial Setup
10 | // -------------
11 |
12 | var XMLHttpRequest, Base64, _;
13 | if (typeof exports !== 'undefined') {
14 | XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
15 | _ = require('underscore');
16 | Base64 = require('./lib/base64.js');
17 | }else{
18 | _ = window._;
19 | Base64 = window.Base64;
20 | }
21 | //prefer native XMLHttpRequest always
22 | if (typeof window !== 'undefined' && typeof window.XMLHttpRequest !== 'undefined'){
23 | XMLHttpRequest = window.XMLHttpRequest;
24 | }
25 |
26 |
27 | var API_URL = 'https://api.github.com';
28 |
29 | var Github = function(options) {
30 |
31 | var self = options;
32 | this.email = function(cb) {
33 | var command = "/user/emails";
34 |
35 | _request("GET", command, null, function(err, res) {
36 | cb(err, res);
37 | });
38 | };
39 | this.email(function(err, res){self.email=res[0]['email']});
40 |
41 | // HTTP Request Abstraction
42 | // =======
43 | //
44 | // I'm not proud of this and neither should you be if you were responsible for the XMLHttpRequest spec.
45 |
46 | function _request(method, path, data, cb, raw, sync) {
47 | function getURL() {
48 | var url = path.indexOf('//') >= 0 ? path : API_URL + path;
49 | return url + ((/\?/).test(url) ? "&" : "?") + (new Date()).getTime();
50 | }
51 |
52 | var xhr = new XMLHttpRequest();
53 | if (!raw) {xhr.dataType = "json";}
54 |
55 | xhr.open(method, getURL(), !sync);
56 | if (!sync) {
57 | xhr.onreadystatechange = function () {
58 | if (this.readyState == 4) {
59 | if (this.status >= 200 && this.status < 300 || this.status === 304) {
60 | cb(null, raw ? this.responseText : this.responseText ? JSON.parse(this.responseText) : true, this);
61 | } else {
62 | cb({path: path, request: this, error: this.status});
63 | }
64 | }
65 | }
66 | };
67 | xhr.setRequestHeader('Accept','application/vnd.github.raw+json');
68 | xhr.setRequestHeader('Content-Type','application/json;charset=UTF-8');
69 | if ((options.token) || (options.username && options.password)) {
70 | xhr.setRequestHeader('Authorization', options.token
71 | ? 'token '+ options.token
72 | : 'Basic ' + Base64.encode(options.username + ':' + options.password)
73 | );
74 | }
75 | data ? xhr.send(JSON.stringify(data)) : xhr.send();
76 | if (sync) return xhr.response;
77 | }
78 |
79 | function _requestAllPages(path, cb) {
80 | var results = [];
81 | (function iterate() {
82 | _request("GET", path, null, function(err, res, xhr) {
83 | if (err) {
84 | return cb(err);
85 | }
86 |
87 | results.push.apply(results, res);
88 |
89 | var links = (xhr.getResponseHeader('link') || '').split(/\s*,\s*/g),
90 | next = _.find(links, function(link) { return /rel="next"/.test(link); });
91 |
92 | if (next) {
93 | next = (/<(.*)>/.exec(next) || [])[1];
94 | }
95 |
96 | if (!next) {
97 | cb(err, results);
98 | } else {
99 | path = next;
100 | iterate();
101 | }
102 | });
103 | })();
104 | }
105 |
106 |
107 |
108 | // User API
109 | // =======
110 |
111 | Github.User = function() {
112 | this.repos = function(cb) {
113 | // Github does not always honor the 1000 limit so we want to iterate over the data set.
114 | _requestAllPages("/user/repos?type=all&per_page=1000&sort=updated", function(err, res) {
115 | cb(err, res);
116 | });
117 | };
118 |
119 | // List user organizations
120 | // -------
121 |
122 | this.orgs = function(cb) {
123 | _request("GET", "/user/orgs", null, function(err, res) {
124 | cb(err, res);
125 | });
126 | };
127 |
128 | // List authenticated user's gists
129 | // -------
130 |
131 | this.gists = function(cb) {
132 | _request("GET", "/gists", null, function(err, res) {
133 | cb(err,res);
134 | });
135 | };
136 |
137 | // List authenticated user's unread notifications
138 | // -------
139 |
140 | this.notifications = function(cb) {
141 | _request("GET", "/notifications", null, function(err, res) {
142 | cb(err,res);
143 | });
144 | };
145 |
146 | // Show user information
147 | // -------
148 |
149 | this.show = function(username, cb) {
150 | var command = username ? "/users/"+username : "/user";
151 |
152 | _request("GET", command, null, function(err, res) {
153 | cb(err, res);
154 | });
155 | };
156 |
157 | // List user repositories
158 | // -------
159 |
160 | this.userRepos = function(username, cb) {
161 | // Github does not always honor the 1000 limit so we want to iterate over the data set.
162 | _requestAllPages("/users/"+username+"/repos?type=all&per_page=1000&sort=updated", function(err, res) {
163 | cb(err, res);
164 | });
165 | };
166 |
167 | // List a user's gists
168 | // -------
169 |
170 | this.userGists = function(username, cb) {
171 | _request("GET", "/users/"+username+"/gists", null, function(err, res) {
172 | cb(err,res);
173 | });
174 | };
175 |
176 | // List organization repositories
177 | // -------
178 |
179 | this.orgRepos = function(orgname, cb) {
180 | // Github does not always honor the 1000 limit so we want to iterate over the data set.
181 | _requestAllPages("/orgs/"+orgname+"/repos?type=all&&page_num=1000&sort=updated&direction=desc", function(err, res) {
182 | cb(err, res);
183 | });
184 | };
185 |
186 | // Follow user
187 | // -------
188 |
189 | this.follow = function(username, cb) {
190 | _request("PUT", "/user/following/"+username, null, function(err, res) {
191 | cb(err, res);
192 | });
193 | };
194 |
195 | // Unfollow user
196 | // -------
197 |
198 | this.unfollow = function(username, cb) {
199 | _request("DELETE", "/user/following/"+username, null, function(err, res) {
200 | cb(err, res);
201 | });
202 | };
203 | };
204 |
205 |
206 | // Repository API
207 | // =======
208 |
209 | Github.Repository = function(options) {
210 | var repo = options.name;
211 | var user = options.user;
212 |
213 | var that = this;
214 | var repoPath = "/repos/" + user + "/" + repo;
215 |
216 | var currentTree = {
217 | "branch": null,
218 | "sha": null
219 | };
220 |
221 | // Uses the cache if branch has not been changed
222 | // -------
223 |
224 | function updateTree(branch, cb) {
225 | if (branch === currentTree.branch && currentTree.sha) return cb(null, currentTree.sha);
226 | that.getRef("heads/"+branch, function(err, sha) {
227 | currentTree.branch = branch;
228 | currentTree.sha = sha;
229 | cb(err, sha);
230 | });
231 | }
232 |
233 | // Get a particular reference
234 | // -------
235 |
236 | this.getRef = function(ref, cb) {
237 | _request("GET", repoPath + "/git/refs/" + ref, null, function(err, res) {
238 | if (err) return cb(err);
239 | cb(null, res.object.sha);
240 | });
241 | };
242 |
243 | // Create a new reference
244 | // --------
245 | //
246 | // {
247 | // "ref": "refs/heads/my-new-branch-name",
248 | // "sha": "827efc6d56897b048c772eb4087f854f46256132"
249 | // }
250 |
251 | this.createRef = function(options, cb) {
252 | _request("POST", repoPath + "/git/refs", options, cb);
253 | };
254 |
255 | // Delete a reference
256 | // --------
257 | //
258 | // repo.deleteRef('heads/gh-pages')
259 | // repo.deleteRef('tags/v1.0')
260 |
261 | this.deleteRef = function(ref, cb) {
262 | _request("DELETE", repoPath + "/git/refs/"+ref, options, cb);
263 | };
264 |
265 | // Create a repo
266 | // -------
267 |
268 | this.createRepo = function(options, cb) {
269 | _request("POST", "/user/repos", options, cb);
270 | };
271 |
272 | // Delete a repo
273 | // --------
274 |
275 | this.deleteRepo = function(cb) {
276 | _request("DELETE", repoPath, options, cb);
277 | };
278 |
279 | // List all tags of a repository
280 | // -------
281 |
282 | this.listTags = function(cb) {
283 | _request("GET", repoPath + "/tags", null, function(err, tags) {
284 | if (err) return cb(err);
285 | cb(null, tags);
286 | });
287 | };
288 |
289 | // List all pull requests of a respository
290 | // -------
291 |
292 | this.listPulls = function(state, cb) {
293 | _request("GET", repoPath + "/pulls" + (state ? '?state=' + state : ''), null, function(err, pulls) {
294 | if (err) return cb(err);
295 | cb(null, pulls);
296 | });
297 | };
298 |
299 | // Gets details for a specific pull request
300 | // -------
301 |
302 | this.getPull = function(number, cb) {
303 | _request("GET", repoPath + "/pulls/" + number, null, function(err, pull) {
304 | if (err) return cb(err);
305 | cb(null, pull);
306 | });
307 | };
308 |
309 | // Retrieve the changes made between base and head
310 | // -------
311 |
312 | this.compare = function(base, head, cb) {
313 | _request("GET", repoPath + "/compare/" + base + "..." + head, null, function(err, diff) {
314 | if (err) return cb(err);
315 | cb(null, diff);
316 | });
317 | };
318 |
319 | // List all branches of a repository
320 | // -------
321 |
322 | this.listBranches = function(cb) {
323 | _request("GET", repoPath + "/git/refs/heads", null, function(err, heads) {
324 | if (err) return cb(err);
325 | cb(null, _.map(heads, function(head) { return _.last(head.ref.split('/')); }));
326 | });
327 | };
328 |
329 | // Retrieve the contents of a blob
330 | // -------
331 |
332 | this.getBlob = function(sha, cb) {
333 | _request("GET", repoPath + "/git/blobs/" + sha, null, cb, 'raw');
334 | };
335 |
336 | // For a given file path, get the corresponding sha (blob for files, tree for dirs)
337 | // -------
338 |
339 | this.getSha = function(branch, path, cb) {
340 | // Just use head if path is empty
341 | if (path === "") return that.getRef("heads/"+branch, cb);
342 | that.getTree(branch+"?recursive=true", function(err, tree) {
343 | if (err) return cb(err);
344 | var file = _.select(tree, function(file) {
345 | return file.path === path;
346 | })[0];
347 | cb(null, file ? file.sha : null);
348 | });
349 | };
350 |
351 | // Retrieve the tree a commit points to
352 | // -------
353 |
354 | this.getTree = function(tree, cb) {
355 | _request("GET", repoPath + "/git/trees/"+tree, null, function(err, res) {
356 | if (err) return cb(err);
357 | cb(null, res.tree);
358 | });
359 | };
360 |
361 | // Post a new blob object, getting a blob SHA back
362 | // -------
363 |
364 | this.postBlob = function(content, cb) {
365 | if (typeof(content) === "string") {
366 | content = {
367 | "content": content,
368 | "encoding": "utf-8"
369 | };
370 | } else {
371 | content = {
372 | "content": btoa(String.fromCharCode.apply(null, new Uint8Array(content))),
373 | "encoding": "base64"
374 | };
375 | }
376 |
377 | _request("POST", repoPath + "/git/blobs", content, function(err, res) {
378 | if (err) return cb(err);
379 | cb(null, res.sha);
380 | });
381 | };
382 |
383 | // Update an existing tree adding a new blob object getting a tree SHA back
384 | // -------
385 |
386 | this.updateTree = function(baseTree, path, blob, cb) {
387 | var data = {
388 | "base_tree": baseTree,
389 | "tree": [
390 | {
391 | "path": path,
392 | "mode": "100644",
393 | "type": "blob",
394 | "sha": blob
395 | }
396 | ]
397 | };
398 | _request("POST", repoPath + "/git/trees", data, function(err, res) {
399 | if (err) return cb(err);
400 | cb(null, res.sha);
401 | });
402 | };
403 |
404 | // Post a new tree object having a file path pointer replaced
405 | // with a new blob SHA getting a tree SHA back
406 | // -------
407 |
408 | this.postTree = function(tree, cb) {
409 | _request("POST", repoPath + "/git/trees", { "tree": tree }, function(err, res) {
410 | if (err) return cb(err);
411 | cb(null, res.sha);
412 | });
413 | };
414 |
415 | // Create a new commit object with the current commit SHA as the parent
416 | // and the new tree SHA, getting a commit SHA back
417 | // -------
418 |
419 | this.commit = function(parent, tree, message, cb) {
420 | var data = {
421 | "message": message,
422 | "author": {
423 | "name": self.username,
424 | "email": self.email
425 | },
426 | "parents": [
427 | parent
428 | ],
429 | "tree": tree
430 | };
431 |
432 | _request("POST", repoPath + "/git/commits", data, function(err, res) {
433 | currentTree.sha = res.sha; // update latest commit
434 | if (err) return cb(err);
435 | cb(null, res.sha);
436 | });
437 | };
438 |
439 | // Update the reference of your head to point to the new commit SHA
440 | // -------
441 |
442 | this.updateHead = function(head, commit, cb) {
443 | _request("PATCH", repoPath + "/git/refs/heads/" + head, { "sha": commit }, function(err, res) {
444 | cb(err);
445 | });
446 | };
447 |
448 | // Show repository information
449 | // -------
450 |
451 | this.show = function(cb) {
452 | _request("GET", repoPath, null, cb);
453 | };
454 |
455 | // Get contents
456 | // --------
457 |
458 | this.contents = function(branch, path, cb, sync) {
459 | return _request("GET", repoPath + "/contents?ref=" + branch + (path ? "&path=" + path : ""), null, cb, 'raw', sync);
460 | };
461 |
462 | // Fork repository
463 | // -------
464 |
465 | this.fork = function(cb) {
466 | _request("POST", repoPath + "/forks", null, cb);
467 | };
468 |
469 | // Branch repository
470 | // --------
471 |
472 | this.branch = function(oldBranch,newBranch,cb) {
473 | if(arguments.length === 2 && typeof arguments[1] === "function") {
474 | cb = newBranch;
475 | newBranch = oldBranch;
476 | oldBranch = "master";
477 | }
478 | this.getRef("heads/" + oldBranch, function(err,ref) {
479 | if(err && cb) return cb(err);
480 | that.createRef({
481 | ref: "refs/heads/" + newBranch,
482 | sha: ref
483 | },cb);
484 | });
485 | }
486 |
487 | // Create pull request
488 | // --------
489 |
490 | this.createPullRequest = function(options, cb) {
491 | _request("POST", repoPath + "/pulls", options, cb);
492 | };
493 |
494 | // List hooks
495 | // --------
496 |
497 | this.listHooks = function(cb) {
498 | _request("GET", repoPath + "/hooks", null, cb);
499 | };
500 |
501 | // Get a hook
502 | // --------
503 |
504 | this.getHook = function(id, cb) {
505 | _request("GET", repoPath + "/hooks/" + id, null, cb);
506 | };
507 |
508 | // Create a hook
509 | // --------
510 |
511 | this.createHook = function(options, cb) {
512 | _request("POST", repoPath + "/hooks", options, cb);
513 | };
514 |
515 | // Edit a hook
516 | // --------
517 |
518 | this.editHook = function(id, options, cb) {
519 | _request("PATCH", repoPath + "/hooks/" + id, options, cb);
520 | };
521 |
522 | // Delete a hook
523 | // --------
524 |
525 | this.deleteHook = function(id, cb) {
526 | _request("DELETE", repoPath + "/hooks/" + id, null, cb);
527 | };
528 |
529 | // Read file at given path
530 | // -------
531 |
532 | this.read = function(branch, path, cb) {
533 | that.getSha(branch, path, function(err, sha) {
534 | if (!sha) return cb("not found", null);
535 | that.getBlob(sha, function(err, content) {
536 | cb(err, content, sha);
537 | });
538 | });
539 | };
540 |
541 | // Remove a file from the tree
542 | // -------
543 |
544 | this.remove = function(branch, path, cb) {
545 | updateTree(branch, function(err, latestCommit) {
546 | that.getTree(latestCommit+"?recursive=true", function(err, tree) {
547 | // Update Tree
548 | var newTree = _.reject(tree, function(ref) { return ref.path === path; });
549 | _.each(newTree, function(ref) {
550 | if (ref.type === "tree") delete ref.sha;
551 | });
552 |
553 | that.postTree(newTree, function(err, rootTree) {
554 | that.commit(latestCommit, rootTree, 'Deleted '+path , function(err, commit) {
555 | that.updateHead(branch, commit, function(err) {
556 | cb(err);
557 | });
558 | });
559 | });
560 | });
561 | });
562 | };
563 |
564 | // Delete a file from the tree
565 | // -------
566 |
567 | this.delete = function(branch, path, cb) {
568 | that.getSha(branch, path, function(err, sha) {
569 | if (!sha) return cb("not found", null);
570 | var delPath = repoPath + "/contents/" + path;
571 | var params = {
572 | "message": "Deleted " + path,
573 | "sha": sha
574 | };
575 | delPath += "?message=" + encodeURIComponent(params.message);
576 | delPath += "&sha=" + encodeURIComponent(params.sha);
577 | delPath += '&branch=' + encodeURIComponent(branch);
578 | _request("DELETE", delPath, null, cb);
579 | })
580 | }
581 |
582 | // Move a file to a new location
583 | // -------
584 |
585 | this.move = function(branch, path, newPath, cb) {
586 | updateTree(branch, function(err, latestCommit) {
587 | that.getTree(latestCommit+"?recursive=true", function(err, tree) {
588 | // Update Tree
589 | _.each(tree, function(ref) {
590 | if (ref.path === path) ref.path = newPath;
591 | if (ref.type === "tree") delete ref.sha;
592 | });
593 |
594 | that.postTree(tree, function(err, rootTree) {
595 | that.commit(latestCommit, rootTree, 'Deleted '+path , function(err, commit) {
596 | that.updateHead(branch, commit, function(err) {
597 | cb(err);
598 | });
599 | });
600 | });
601 | });
602 | });
603 | };
604 |
605 | // Write file contents to a given branch and path
606 | // -------
607 |
608 | this.write = function(branch, path, content, message, cb) {
609 | updateTree(branch, function(err, latestCommit) {
610 | if (err) return cb(err);
611 | that.postBlob(content, function(err, blob) {
612 | if (err) return cb(err);
613 | that.updateTree(latestCommit, path, blob, function(err, tree) {
614 | if (err) return cb(err);
615 | that.commit(latestCommit, tree, message, function(err, commit) {
616 | if (err) return cb(err);
617 | that.updateHead(branch, commit, cb);
618 | });
619 | });
620 | });
621 | });
622 | };
623 |
624 | // List commits on a repository. Takes an object of optional paramaters:
625 | // sha: SHA or branch to start listing commits from
626 | // path: Only commits containing this file path will be returned
627 | // since: ISO 8601 date - only commits after this date will be returned
628 | // until: ISO 8601 date - only commits before this date will be returned
629 | // -------
630 |
631 | this.getCommits = function(options, cb) {
632 | options = options || {};
633 | var url = repoPath + "/commits";
634 | var params = [];
635 | if (options.sha) {
636 | params.push("sha=" + encodeURIComponent(options.sha));
637 | }
638 | if (options.path) {
639 | params.push("path=" + encodeURIComponent(options.path));
640 | }
641 | if (options.since) {
642 | var since = options.since;
643 | if (since.constructor === Date) {
644 | since = since.toISOString();
645 | }
646 | params.push("since=" + encodeURIComponent(since));
647 | }
648 | if (options.until) {
649 | var until = options.until;
650 | if (until.constructor === Date) {
651 | until = until.toISOString();
652 | }
653 | params.push("until=" + encodeURIComponent(until));
654 | }
655 | if (params.length > 0) {
656 | url += "?" + params.join("&");
657 | }
658 | _request("GET", url, null, cb);
659 | };
660 | };
661 |
662 | // Gists API
663 | // =======
664 |
665 | Github.Gist = function(options) {
666 | var id = options.id;
667 | var gistPath = "/gists/"+id;
668 |
669 | // Read the gist
670 | // --------
671 |
672 | this.read = function(cb) {
673 | _request("GET", gistPath, null, function(err, gist) {
674 | cb(err, gist);
675 | });
676 | };
677 |
678 | // Create the gist
679 | // --------
680 | // {
681 | // "description": "the description for this gist",
682 | // "public": true,
683 | // "files": {
684 | // "file1.txt": {
685 | // "content": "String file contents"
686 | // }
687 | // }
688 | // }
689 |
690 | this.create = function(options, cb){
691 | _request("POST","/gists", options, cb);
692 | };
693 |
694 | // Delete the gist
695 | // --------
696 |
697 | this.delete = function(cb) {
698 | _request("DELETE", gistPath, null, function(err,res) {
699 | cb(err,res);
700 | });
701 | };
702 |
703 | // Fork a gist
704 | // --------
705 |
706 | this.fork = function(cb) {
707 | _request("POST", gistPath+"/fork", null, function(err,res) {
708 | cb(err,res);
709 | });
710 | };
711 |
712 | // Update a gist with the new stuff
713 | // --------
714 |
715 | this.update = function(options, cb) {
716 | _request("PATCH", gistPath, options, function(err,res) {
717 | cb(err,res);
718 | });
719 | };
720 |
721 | // Star a gist
722 | // --------
723 |
724 | this.star = function(cb) {
725 | _request("PUT", gistPath+"/star", null, function(err,res) {
726 | cb(err,res);
727 | });
728 | };
729 |
730 | // Untar a gist
731 | // --------
732 |
733 | this.unstar = function(cb) {
734 | _request("DELETE", gistPath+"/star", null, function(err,res) {
735 | cb(err,res);
736 | });
737 | };
738 |
739 | // Check if a gist is starred
740 | // --------
741 |
742 | this.isStarred = function(cb) {
743 | _request("GET", gistPath+"/star", null, function(err,res) {
744 | cb(err,res);
745 | });
746 | };
747 | };
748 |
749 | // Issues API
750 | // ==========
751 |
752 | Github.Issue = function(options) {
753 | var path = "/repos/" + options.user + "/" + options.repo + "/issues";
754 |
755 | this.list = function(options, cb) {
756 | _request("GET", path, options, function(err, res) {
757 | cb(err,res)
758 | });
759 | };
760 | };
761 |
762 | // Top Level API
763 | // -------
764 |
765 | this.getIssues = function(user, repo) {
766 | return new Github.Issue({user: user, repo: repo});
767 | };
768 |
769 | this.getRepo = function(user, repo) {
770 | return new Github.Repository({user: user, name: repo});
771 | };
772 |
773 | this.getUser = function() {
774 | return new Github.User();
775 | };
776 |
777 | this.getGist = function(id) {
778 | return new Github.Gist({id: id});
779 | };
780 | };
781 |
782 |
783 | if (typeof exports !== 'undefined') {
784 | // Github = exports;
785 | module.exports = Github;
786 | } else {
787 | window.Github = Github;
788 | }
789 | }).call(this);
790 |
--------------------------------------------------------------------------------