├── .gitignore ├── LICENSE ├── README.md ├── gulpfile.js ├── package.json └── src ├── index.html └── static ├── css └── style.css ├── js └── app.js └── module ├── code-prettify ├── lang-apollo.js ├── lang-basic.js ├── lang-clj.js ├── lang-css.js ├── lang-dart.js ├── lang-erlang.js ├── lang-go.js ├── lang-hs.js ├── lang-lasso.js ├── lang-lisp.js ├── lang-llvm.js ├── lang-logtalk.js ├── lang-lua.js ├── lang-matlab.js ├── lang-ml.js ├── lang-mumps.js ├── lang-n.js ├── lang-pascal.js ├── lang-proto.js ├── lang-r.js ├── lang-rd.js ├── lang-rust.js ├── lang-scala.js ├── lang-sql.js ├── lang-swift.js ├── lang-tcl.js ├── lang-tex.js ├── lang-vb.js ├── lang-vhdl.js ├── lang-wiki.js ├── lang-xq.js ├── lang-yaml.js ├── prettify.css └── prettify.js └── html2canvas └── html2canvas.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.* 3 | 4 | sftp-config.json 5 | 6 | # Logs 7 | logs 8 | *.log 9 | 10 | # Compressed file 11 | *.min.js 12 | *.min.css 13 | 14 | # CDN config 15 | .cdnconf.json 16 | 17 | # Release data 18 | dist 19 | 20 | # Runtime data 21 | runtime/ 22 | pids 23 | *.pid 24 | *.seed 25 | 26 | # node-waf configuration 27 | .lock-wscript 28 | 29 | # Dependency directory 30 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 31 | node_modules/ 32 | 33 | # IDE config 34 | .idea 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Niklas von Hertzen 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Code to Image 2 | 3 | _Code to Image_ converts your blocks of code to a highlighted jpeg base64 image. And you can share it to any code-unfriendly website —— Such website doesn't support markdown or `
` tag or anything else that can make your post contains any blocks of code in it.
 4 | 
 5 | It is much better than screen shot since you can pick a single image from **very large code files**. More than 40 programming languages can be highlighted and picked.
 6 | 
 7 | ## Example
 8 | 
 9 | [http://code2img.75team.com](http://code2img.75team.com/#)
10 | 
11 | Paste blocks of code to textarea and **press Ctrl+D** to pick image.
12 | 
13 | ## Installation
14 | 
15 | ```bash
16 | git clone https://github.com/akira-cn/code-to-image.git
17 | cd code-to-image
18 | npm install
19 | ```
20 | 
21 | ## Development
22 | 
23 | ```bash
24 | npm start
25 | ```
26 | 
27 | ## Compile & Release
28 | 
29 | ```bash
30 | npm run compile
31 | ```
32 | 
33 | ## Default languages
34 | 
35 | Default languages included bash; C; C++; C#; HTML; Java; JavaScript; XML; Perl; Python; Ruby; PHP;
36 | 
37 | ## Extensions
38 | 
39 | Other languages are supported via extensions:
40 | 
41 | [Apollo](http://code2img.test.h5jun.com/#apollo); [Basic](http://code2img.test.h5jun.com/#basic); [Clojure](http://code2img.test.h5jun.com/#clojure); [CSS](http://code2img.test.h5jun.com/#css); [Dart](http://code2img.test.h5jun.com/#dart); [Erlang](http://code2img.test.h5jun.com/#erlang); [Go](http://code2img.test.h5jun.com/#go); [Haskell](http://code2img.test.h5jun.com/#hs); [Lasso](http://code2img.test.h5jun.com/#lasso); [Lisp, Scheme](http://code2img.test.h5jun.com/#lisp); [Llvm](http://code2img.test.h5jun.com/#llvm); [Logtalk](http://code2img.test.h5jun.com/#logtalk); [Lua](http://code2img.test.h5jun.com/#lua); [Matlab](http://code2img.test.h5jun.com/#maltab); [MLs: F#, Ocaml,SML;](http://code2img.test.h5jun.com/#ml) [Mumps](http://code2img.test.h5jun.com/#mumps); [Nemerle](http://code2img.test.h5jun.com/#nemerle); [Pascal](http://code2img.test.h5jun.com/#pascal); [Protocol buffers](http://code2img.test.h5jun.com/#protocol); [R, S](http://code2img.test.h5jun.com/#r); [RD](http://code2img.test.h5jun.com/#rd); [Rust](http://code2img.test.h5jun.com/#rust); [Scala](http://code2img.test.h5jun.com/#scala); [SQL](http://code2img.test.h5jun.com/#sql); [Swift](http://code2img.test.h5jun.com/#swift); [TCL](http://code2img.test.h5jun.com/#tcl); [Latek](http://code2img.test.h5jun.com/#latek); [Visual Basic](http://code2img.test.h5jun.com/#vb); [VHDL](http://code2img.test.h5jun.com/#vhdl); [Wiki](http://code2img.test.h5jun.com/#wiki); [XQ](http://code2img.test.h5jun.com/#xq); [YAML](http://code2img.test.h5jun.com/#yaml)
42 | 
43 | ## Thanks
44 | 
45 | Thanks to [code-prettify](https://github.com/google/code-prettify) and [html2canvas](https://github.com/niklasvh/html2canvas).
46 | 
47 | ## License (Multi-licensing)
48 | 
49 | [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0) [LICENSE](LICENSE)
50 | 


--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
  1 | var uglifyJS = require('uglify-js');
  2 | var cleanCSS = require('clean-css');
  3 | var fs = require('fs');
  4 | var gulp = require('gulp');
  5 | var through = require('through2');
  6 | 
  7 | var config = JSON.parse(fs.readFileSync('./package.json'));
  8 | var cdnconf, cdnBucket, cdnDomain;
  9 | 
 10 | try{
 11 |   cdnconf = JSON.parse(fs.readFileSync('.cdnconf.json'));
 12 |   
 13 |   var qiniu = require('node-qiniu');
 14 |   qiniu.config(cdnconf);
 15 |   
 16 |   cdnBucket = require('node-qiniu').bucket(cdnconf.bucket);
 17 |   cdnDomain = cdnconf.domain;
 18 | }catch(ex){
 19 |   cdnconf = null;
 20 | }
 21 | 
 22 | function compile(src){
 23 | 
 24 |   var query = require('path').parse(src);
 25 | 
 26 |   var name = query.name;
 27 |   var ext = query.ext;
 28 | 
 29 |   var path = srcToFilePath(src);
 30 |   var contents = '';
 31 |   var prePromise = Promise.resolve();
 32 | 
 33 |   if(ext === '.js'){
 34 |     console.log(path);
 35 |     contents = uglifyJS.minify(path).code;
 36 |     if(name === 'app'){
 37 |       var extensions = contents.match(/lang-[a-z]+?\.js/g);
 38 |       var promises = [];
 39 | 
 40 |       var prefix = '/static/module/code-prettify/';
 41 | 
 42 |       //console.log(extensions);
 43 |       extensions.forEach(function(extension){
 44 |         var src = prefix + extension;
 45 |         promises.push(compile(src).then(function(res){
 46 |           contents = contents.replace(extension, res);
 47 |         }));
 48 |       });
 49 |       prePromise = Promise.all(promises).then(function(){
 50 |         contents = contents.replace(prefix, '');
 51 |       });
 52 |     }
 53 |   }else if(ext === '.css'){
 54 |     var cssText = fs.readFileSync(path);
 55 |     contents = new cleanCSS().minify(cssText).styles;      
 56 |   }
 57 | 
 58 |   var re = new RegExp(name + ext + '$');
 59 |   var compressed = name + '.min' + ext;
 60 | 
 61 |   path = path.replace(re, compressed);
 62 | 
 63 |   if(cdnBucket){
 64 |     return prePromise.then(function(){
 65 |       fs.writeFileSync(path, contents, 'utf-8');
 66 |       
 67 |       return new Promise(function(resolve, reject){
 68 |         require('checksum').file(path, function(err, sum){
 69 |           var cdnFile = '!' + sum.slice(0, 16) + '/' + compressed;
 70 | 
 71 |           cdnBucket.putFile(cdnFile, path, function(err, reply){
 72 |             if(!err){
 73 |               var url = cdnDomain +'/'+ reply.key;
 74 |               resolve(url);
 75 |             }else{
 76 |               reject(err);
 77 |             }
 78 |           });  
 79 |         });
 80 |       });  
 81 |     });
 82 |   }else{
 83 |     return prePromise.then(function(){
 84 |       fs.writeFileSync(path, contents, 'utf-8');
 85 |       
 86 |       return Promise.resolve(src.replace(re, compressed) + '?v=' + config.version);
 87 |     });
 88 |   }
 89 | }
 90 | 
 91 | function srcToFilePath(src){
 92 |   src = require('url').parse(src).pathname;
 93 |   return __dirname  + '/src' + src;
 94 | }
 95 | 
 96 | gulp.task('resource', function() {
 97 |   gulp.src(['./src/**/*.min.js', './src/**/*.min.css'])
 98 |       .pipe(gulp.dest('./dist'));
 99 | });
100 | 
101 | gulp.task('default', function() {
102 |   gulp.src(['./src/index.html'])
103 |       .pipe(through.obj(function(file, encode, cb) {
104 |         var contents = file.contents.toString(encode);
105 |         var $ = require('cheerio').load(contents, {decodeEntities: false});
106 | 
107 |         var promises = [];
108 | 
109 |         var links = $('link');
110 |         for(var i = 0; i < links.length; i++){
111 |           var link = $(links[i]);
112 |           if(link.attr('rel') === 'stylesheet'){
113 |             var href = link.attr('href');
114 |             if(/^\/static\//.test(href)){
115 |               (function(link){
116 |                 promises.push(compile(href).then(function(res){
117 |                   link.attr('href', res);
118 |                 }).catch(function(err){
119 |                   console.log(err);
120 |                 }));
121 |               })(link);
122 |             }
123 |           }
124 |         }
125 | 
126 |         var scripts = $('script');
127 |         for(var i = 0; i < scripts.length; i++){
128 |           var s = $(scripts[i]);
129 | 
130 |           if(s.attr('type') == null 
131 |             || s.attr('type') === 'text/javascript'){
132 |             var src = s.attr('src');
133 |             
134 |             if(src){
135 |               if(/^\/static\//.test(src)){
136 |                 (function(s, src){
137 |                   promises.push(compile(src).then(function(res){
138 |                     s.attr('src', res);
139 |                   }).catch(function(err){
140 |                     console.log(err);
141 |                   }));
142 |                 })(s, src);
143 |               }
144 |             }
145 |           }
146 |         }
147 | 
148 |         Promise.all(promises).then(function(){
149 |           contents = $.html();
150 | 
151 |           var HTMLMinifier = require('html-minifier').minify;
152 | 
153 |           var minified = HTMLMinifier(contents, {
154 |             minifyCSS: true,
155 |             minifyJS: true,
156 |             collapseWhitespace: true,
157 |             removeAttributeQuotes: true
158 |           });   
159 | 
160 |           file.contents = new Buffer(minified, encode);
161 | 
162 |           if(!cdnBucket) gulp.start('resource');
163 | 
164 |           cb(null, file, encode);
165 |         });
166 | 
167 |       })).pipe(gulp.dest('./dist'));
168 | });


--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "code-to-image",
 3 |   "version": "0.4.0",
 4 |   "description": "Convert blocks of code to a highlighted jpeg base64 image.",
 5 |   "main": "src/index.html",
 6 |   "scripts": {
 7 |     "test": "echo \"Error: no test specified\" && exit 1",
 8 |     "start": "cd src && http-server -c-1",
 9 |     "compile": "rm -rf dist && gulp"
10 |   },
11 |   "keywords": [
12 |     "code",
13 |     "image",
14 |     "base64",
15 |     "jpeg",
16 |     "html2canvas",
17 |     "highlight"
18 |   ],
19 |   "devDependencies": {
20 |     "http-server": "^0.9.0",
21 |     "gulp": "~3.9.0",
22 |     "through2": "~2.0.0",
23 |     "cheerio": "~0.19.0",
24 |     "uglify-js": "~2.6.0",
25 |     "html-minifier": "~1.0.0",
26 |     "clean-css": "~3.4.6",
27 |     "node-qiniu": "6.2.0",
28 |     "checksum": "~0.1.1"
29 |   },
30 |   "author": "akira-cn",
31 |   "license": "Apache License 2.0"
32 | }
33 | 


--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | 
 4 |   
 5 |   
 6 |   Press Ctrl+D to get Image.
 7 |   
 8 |   
 9 | 
10 | 
11 |   
12 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/static/css/style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | width: 100%; 3 | height: 100%; 4 | overflow-x: hidden; 5 | padding: 0; 6 | margin: 0; 7 | } 8 | 9 | textarea { 10 | width: 100%; 11 | height: 100%; 12 | font-size: 18px; 13 | padding: 5px 10px; 14 | } 15 | 16 | #nav { 17 | padding: 6px; 18 | line-height: 28px; 19 | } 20 | 21 | #nav img { 22 | vertical-align: middle; 23 | cursor: pointer; 24 | margin: 0 10px 6px 0; 25 | } 26 | 27 | #nav a, 28 | #nav label { 29 | text-decoration: none; 30 | margin: 0 5px; 31 | } 32 | 33 | #nav label { 34 | cursor: pointer; 35 | user-select: none; 36 | } 37 | 38 | /*github stars*/ 39 | #nav iframe { 40 | position: relative; 41 | margin-left: 10px; 42 | vertical-align: middle; 43 | } 44 | 45 | ul.languages { 46 | margin-right: 20px; 47 | } 48 | 49 | ul.settings, 50 | ul.languages { 51 | padding: 0; 52 | font-size: 0; 53 | display: inline; 54 | } 55 | 56 | ul.languages li, 57 | ul.settings li { 58 | font-size: 16px; 59 | display: inline-block; 60 | } 61 | 62 | ul.languages.lang-default a[data-lang=default], 63 | ul.languages.lang-css a[data-lang=css], 64 | ul.languages.lang-erlang a[data-lang=erlang], 65 | ul.languages.lang-go a[data-lang=go], 66 | ul.languages.lang-haskell a[data-lang=haskell], 67 | ul.languages.lang-lisp a[data-lang=lisp], 68 | ul.languages.lang-lua a[data-lang=lua], 69 | ul.languages.lang-sql a[data-lang=sql], 70 | ul.languages.lang-swift a[data-lang=swift] 71 | { 72 | font-size: 20px; 73 | } 74 | 75 | ul.settings li:not(:first-child) { 76 | border-left: solid 1px #333; 77 | padding-left: 5px; 78 | } 79 | 80 | ul.settings input { 81 | display: none; 82 | } 83 | 84 | ul.settings input:checked+label { 85 | color: #f00; 86 | } 87 | 88 | #code { 89 | /*width: 1280px;*/ 90 | min-width: 360px; 91 | position: absolute; 92 | font-size: 36px; 93 | left: 0; 94 | top: 0; 95 | z-index: 99; 96 | background-color: #fff; 97 | } 98 | 99 | #code pre.wrap{ 100 | white-space: pre-wrap; 101 | word-wrap: break-word; 102 | } 103 | 104 | #code pre.nowrap{ 105 | white-space: pre; 106 | width: 100%; 107 | } 108 | 109 | #code pre { 110 | margin: 0; 111 | padding: 0; 112 | } 113 | 114 | #code pre.w1280{ 115 | min-width: 1280px; 116 | font-size: 36px; 117 | } 118 | 119 | #code pre.w720{ 120 | min-width: 720px; 121 | font-size: 20px; 122 | } 123 | 124 | #code pre.w480{ 125 | min-width: 480px; 126 | font-size: 14px; 127 | } 128 | 129 | #code pre.w1280.wrap{ 130 | width: 1280px; 131 | } 132 | 133 | #code pre.w720.wrap{ 134 | width: 720px; 135 | } 136 | 137 | #code pre.w480.wrap{ 138 | width: 480px; 139 | } 140 | 141 | #code pre code{ 142 | margin: 0.5em; 143 | display: inline-block; 144 | } 145 | 146 | #code div { 147 | background: rgba(0,0,0,0.5); 148 | position: absolute; 149 | display: block; 150 | } 151 | 152 | #code a.img img { 153 | position: absolute; 154 | top: 50%; 155 | left: 50%; 156 | transform: translate(-50%, -50%); 157 | } 158 | 159 | #code div a.close { 160 | color: white; 161 | position: absolute; 162 | right: 10px; 163 | top: 10px; 164 | cursor: pointer; 165 | } -------------------------------------------------------------------------------- /src/static/js/app.js: -------------------------------------------------------------------------------- 1 | /* global jQuery, html2canvas, PR*/ 2 | 3 | (function(html2canvas, PR){'use strict' 4 | var hash = location.hash.slice(1).toLowerCase(), 5 | lang; 6 | 7 | const langEl = document.querySelector('#nav .languages'); 8 | 9 | if(hash){ 10 | lang = hash; 11 | } 12 | 13 | const srcMap = { 14 | 'apollo': 'lang-apollo.js', 15 | 'basic': 'lang-basic.js', 16 | 'clojure': 'lang-clj.js', 17 | 'css': 'lang-css.js', 18 | 'dart': 'lang-dart.js', 19 | 'erlang': 'lang-erlang.js', 20 | 'go': 'lang-go.js', 21 | 'haskell': 'lang-hs.js', 22 | 'lasso': 'lang-lasso.js', 23 | 'lisp': 'lang-lisp.js', 24 | 'scheme': 'lang-lisp.js', 25 | 'llvm': 'lang-llvm.js', 26 | 'logtalk': 'lang-logtalk.js', 27 | 'lua': 'lang-lua.js', 28 | 'matlab': 'lang-matlab.js', 29 | 'ml': 'lang-ml.js', 30 | 'mumps': 'lang-mumps.js', 31 | 'nemerle': 'lang-n.js', 32 | 'pascal': 'lang-pascal.js', 33 | 'protocol': 'lang-proto.js', 34 | 'r': 'lang-r.js', 35 | 'rd': 'lang-rd.js', 36 | 'rust': 'lang-rust.js', 37 | 'scala': 'lang-scala.js', 38 | 'sql': 'lang-sql.js', 39 | 'swift': 'lang-swift.js', 40 | 'tcl': 'lang-tcl.js', 41 | 'latek': 'lang-tex.js', 42 | 'vb': 'lang-vb.js', 43 | 'vhdl': 'lang-vhdl.js', 44 | 'wiki': 'lang-wiki.js', 45 | 'xq': 'lang-xq.js', 46 | 'yaml': 'lang-yaml.js' 47 | }; 48 | 49 | function loadPlugin(lang){ 50 | var js = srcMap[lang.toLowerCase()]; 51 | 52 | if(typeof js === 'string'){ 53 | var script = document.createElement('script'); 54 | script.src = '/static/module/code-prettify/' + js; 55 | document.body.appendChild(script); 56 | } 57 | 58 | langEl.className = 'languages lang-' + lang; 59 | 60 | //only to load js file once. 61 | srcMap[lang] = true; 62 | } 63 | 64 | if(lang) loadPlugin(lang); 65 | 66 | langEl.addEventListener('click', function(evt){ 67 | var target = evt.target; 68 | var _lang = target.dataset.lang; 69 | 70 | if(target.tagName === 'A' && _lang !== 'more'){ 71 | lang = _lang; 72 | if(lang === 'default') lang = ''; 73 | if(lang) loadPlugin(lang); 74 | else langEl.className = 'languages lang-default'; 75 | } 76 | }); 77 | 78 | 79 | const codeEl = document.getElementById('code'); 80 | const textCodeEl = document.getElementById('text-code'); 81 | 82 | const settingVersion = '1.0'; 83 | 84 | function loadSettings(){ 85 | var settings = localStorage.getItem('settings') || {}; 86 | 87 | if(typeof settings === 'string'){ 88 | try{ 89 | settings = JSON.parse(settings); 90 | document.querySelector('input#setting-theme-' + settings.theme).checked = 'checked'; 91 | document.querySelector('input#setting-width-' + settings.width).checked = 'checked'; 92 | document.querySelector('input#setting-format-' + settings.format).checked = 'checked'; 93 | }catch(ex){ 94 | console.error('settings loaded failed! ' + ex.message); 95 | settings = {}; 96 | } 97 | } 98 | } 99 | 100 | loadSettings(); 101 | 102 | function generateCode(text){ 103 | 104 | function parseProps(propStr){ 105 | var props = propStr.trim().split(';'); 106 | var ret = {}; 107 | 108 | for(var i = 0; i < props.length; i++){ 109 | if(props[i]){ 110 | var pair = props[i].split(':'); 111 | ret[pair[0].trim()] = pair[1].trim(); 112 | } 113 | } 114 | return ret; 115 | } 116 | 117 | var codeClass = 'prettyprint'; 118 | 119 | if(lang){ 120 | codeClass += ' lang-' + lang; 121 | } 122 | 123 | var settings = { 124 | theme : document.querySelector('input[name="setting-theme"]:checked').value, 125 | width: document.querySelector('input[name="setting-width"]:checked').value, 126 | format: document.querySelector('input[name="setting-format"]:checked').value 127 | }; 128 | 129 | localStorage.setItem('settings', JSON.stringify(settings)); 130 | 131 | codeEl.innerHTML = '
' + text.replace(//g,'>') + '
'; 132 | 133 | PR.prettyPrint(); 134 | 135 | setTimeout(function(){ 136 | var canvas = document.createElement('canvas'); 137 | var context = canvas.getContext('2d'); 138 | 139 | html2canvas(codeEl, { 140 | canvas: canvas, 141 | onrendered: function(canvas) { 142 | var img = new Image(); 143 | img.src = canvas.toDataURL('image/jpeg'); 144 | 145 | Object.assign(img.style, { 146 | 'max-width': '100%', 147 | 'max-height': '100%', 148 | 'zoom': Math.min(1.0, Math.max(0.5, 480 / img.width)) 149 | }); 150 | 151 | var a = document.createElement('a'); 152 | a.href = img.src; 153 | a.className = 'img'; 154 | a.appendChild(img); 155 | 156 | var container = document.createElement('div'); 157 | container.appendChild(a); 158 | 159 | var closeBtn = document.createElement('a'); 160 | closeBtn.className = 'close'; 161 | closeBtn.innerHTML = 'X'; 162 | container.appendChild(closeBtn); 163 | 164 | codeEl.innerHTML = ''; 165 | codeEl.style.zoom = '1.0'; 166 | codeEl.appendChild(container); 167 | 168 | closeBtn.addEventListener('click', function(){ 169 | codeEl.innerHTML = ''; 170 | }); 171 | 172 | Object.assign(container.style, { 173 | width: document.documentElement.clientWidth + 'px', 174 | height: document.documentElement.clientHeight + 'px' 175 | }); 176 | } 177 | }); 178 | }, 0); 179 | } 180 | 181 | const codeImgEl = document.querySelector('#nav img'); 182 | 183 | codeImgEl.addEventListener('click', function(){ 184 | var text = textCodeEl.value; 185 | generateCode(text || 'Paste your code first!'); 186 | }); 187 | 188 | textCodeEl.addEventListener('keydown', function(evt){ 189 | var keyCode = evt.keyCode; 190 | var target = evt.target; 191 | 192 | if(keyCode === 68 && evt.ctrlKey){ 193 | evt.preventDefault(); //prevent deletion 194 | return; 195 | } 196 | if(keyCode !== 9 && keyCode !== 13 & keyCode !== 221) return; 197 | 198 | var text = target.value; 199 | var start = target.selectionStart; 200 | var end = target.selectionEnd; 201 | 202 | if(keyCode === 9) { //handle tab 203 | evt.preventDefault(); 204 | 205 | // set textarea value to: text before caret + tab + text after caret 206 | target.value = text.substring(0, start) 207 | + ' ' 208 | + text.substring(end); 209 | 210 | // put caret at right position again 211 | target.selectionStart = target.selectionEnd = start + 4; 212 | }else if(keyCode === 13){ //handle enter 213 | evt.preventDefault(); 214 | 215 | var lines = text.substring(0, start).split('\n'); 216 | var currentLine = lines[lines.length - 1]; 217 | var spaces = (/^\s+/.exec(currentLine) || [''])[0]; 218 | 219 | target.value = text.substring(0, start) 220 | + '\n' + spaces 221 | + text.substring(end); 222 | 223 | target.selectionStart = target.selectionEnd = start + spaces.length + 1; 224 | }else if(keyCode === 221){ //handle } 225 | evt.preventDefault(); 226 | 227 | var lines = text.substring(0, start).split('\n'); 228 | var currentLine = lines[lines.length - 1]; 229 | var spaces = (/^\s+$/.exec(currentLine) || [''])[0]; 230 | var backspace = 0; 231 | 232 | if(spaces){ 233 | backspace = Math.min(spaces.length, 4); 234 | spaces = spaces.slice(0, -4); 235 | } 236 | 237 | target.value = text.substring(0, start).replace(/^\s+$/m, spaces) 238 | + '}' 239 | + text.substring(end); 240 | 241 | target.selectionStart = target.selectionEnd = start - backspace + 1; 242 | } 243 | }); 244 | 245 | window.addEventListener('keydown', function(evt){ 246 | if(evt.ctrlKey && evt.keyCode === 68){ 247 | var text = textCodeEl.value; 248 | generateCode(text || 'Paste your code first!'); 249 | }else{ 250 | if(evt.keyCode === 27){ 251 | codeEl.innerHTML = ''; 252 | codeEl.style.zoom = ''; 253 | } 254 | } 255 | }); 256 | 257 | })(html2canvas, PR); 258 | -------------------------------------------------------------------------------- /src/static/module/code-prettify/lang-apollo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright (C) 2009 Onno Hommes. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * @fileoverview 20 | * Registers a language handler for the AGC/AEA Assembly Language as described 21 | * at http://virtualagc.googlecode.com 22 | *

23 | * This file could be used by goodle code to allow syntax highlight for 24 | * Virtual AGC SVN repository or if you don't want to commonize 25 | * the header for the agc/aea html assembly listing. 26 | * 27 | * @author ohommes@alumni.cmu.edu 28 | */ 29 | 30 | PR['registerLangHandler']( 31 | PR['createSimpleLexer']( 32 | [ 33 | // A line comment that starts with ; 34 | [PR['PR_COMMENT'], /^#[^\r\n]*/, null, '#'], 35 | // Whitespace 36 | [PR['PR_PLAIN'], /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'], 37 | // A double quoted, possibly multi-line, string. 38 | [PR['PR_STRING'], /^\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)/, null, '"'] 39 | ], 40 | [ 41 | [PR['PR_KEYWORD'], /^(?:ADS|AD|AUG|BZF|BZMF|CAE|CAF|CA|CCS|COM|CS|DAS|DCA|DCOM|DCS|DDOUBL|DIM|DOUBLE|DTCB|DTCF|DV|DXCH|EDRUPT|EXTEND|INCR|INDEX|NDX|INHINT|LXCH|MASK|MSK|MP|MSU|NOOP|OVSK|QXCH|RAND|READ|RELINT|RESUME|RETURN|ROR|RXOR|SQUARE|SU|TCR|TCAA|OVSK|TCF|TC|TS|WAND|WOR|WRITE|XCH|XLQ|XXALQ|ZL|ZQ|ADD|ADZ|SUB|SUZ|MPY|MPR|MPZ|DVP|COM|ABS|CLA|CLZ|LDQ|STO|STQ|ALS|LLS|LRS|TRA|TSQ|TMI|TOV|AXT|TIX|DLY|INP|OUT)\s/,null], 42 | [PR['PR_TYPE'], /^(?:-?GENADR|=MINUS|2BCADR|VN|BOF|MM|-?2CADR|-?[1-6]DNADR|ADRES|BBCON|[SE]?BANK\=?|BLOCK|BNKSUM|E?CADR|COUNT\*?|2?DEC\*?|-?DNCHAN|-?DNPTR|EQUALS|ERASE|MEMORY|2?OCT|REMADR|SETLOC|SUBRO|ORG|BSS|BES|SYN|EQU|DEFINE|END)\s/,null], 43 | // A single quote possibly followed by a word that optionally ends with 44 | // = ! or ?. 45 | [PR['PR_LITERAL'], 46 | /^\'(?:-*(?:\w|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?)?/], 47 | // Any word including labels that optionally ends with = ! or ?. 48 | [PR['PR_PLAIN'], 49 | /^-*(?:[!-z_]|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?/i], 50 | // A printable non-space non-special character 51 | [PR['PR_PUNCTUATION'], /^[^\w\t\n\r \xA0()\"\\\';]+/] 52 | ]), 53 | ['apollo', 'agc', 'aea']); 54 | -------------------------------------------------------------------------------- /src/static/module/code-prettify/lang-basic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright (C) 2013 Peter Kofler 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | // Contributed by peter dot kofler at code minus cop dot org 19 | 20 | /** 21 | * @fileoverview 22 | * Registers a language handler for Basic. 23 | * 24 | * To use, include prettify.js and this file in your HTML page. 25 | * Then put your code in an HTML tag like 26 | *

(my BASIC code)
27 | * 28 | * @author peter dot kofler at code minus cop dot org 29 | */ 30 | 31 | PR.registerLangHandler( 32 | PR.createSimpleLexer( 33 | [ // shortcutStylePatterns 34 | // "single-line-string" 35 | [PR.PR_STRING, /^(?:"(?:[^\\"\r\n]|\\.)*(?:"|$))/, null, '"'], 36 | // Whitespace 37 | [PR.PR_PLAIN, /^\s+/, null, ' \r\n\t\xA0'] 38 | ], 39 | [ // fallthroughStylePatterns 40 | // A line comment that starts with REM 41 | [PR.PR_COMMENT, /^REM[^\r\n]*/, null], 42 | [PR.PR_KEYWORD, /^\b(?:AND|CLOSE|CLR|CMD|CONT|DATA|DEF ?FN|DIM|END|FOR|GET|GOSUB|GOTO|IF|INPUT|LET|LIST|LOAD|NEW|NEXT|NOT|ON|OPEN|OR|POKE|PRINT|READ|RESTORE|RETURN|RUN|SAVE|STEP|STOP|SYS|THEN|TO|VERIFY|WAIT)\b/, null], 43 | [PR.PR_PLAIN, /^[A-Z][A-Z0-9]?(?:\$|%)?/i, null], 44 | // Literals .0, 0, 0.0 0E13 45 | [PR.PR_LITERAL, /^(?:\d+(?:\.\d*)?|\.\d+)(?:e[+\-]?\d+)?/i, null, '0123456789'], 46 | [PR.PR_PUNCTUATION, /^.[^\s\w\.$%"]*/, null] 47 | // [PR.PR_PUNCTUATION, /^[-,:;!<>=\+^\/\*]+/] 48 | ]), 49 | ['basic','cbm']); 50 | -------------------------------------------------------------------------------- /src/static/module/code-prettify/lang-clj.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Copyright (C) 2011 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * @fileoverview 19 | * Registers a language handler for Clojure. 20 | * 21 | * 22 | * To use, include prettify.js and this file in your HTML page. 23 | * Then put your code in an HTML tag like 24 | *
(my lisp code)
25 | * The lang-cl class identifies the language as common lisp. 26 | * This file supports the following language extensions: 27 | * lang-clj - Clojure 28 | * 29 | * 30 | * I used lang-lisp.js as the basis for this adding the clojure specific 31 | * keywords and syntax. 32 | * 33 | * "Name" = 'Clojure' 34 | * "Author" = 'Rich Hickey' 35 | * "Version" = '1.2' 36 | * "About" = 'Clojure is a lisp for the jvm with concurrency primitives and a richer set of types.' 37 | * 38 | * 39 | * I used Clojure.org Reference as 40 | * the basis for the reserved word list. 41 | * 42 | * 43 | * @author jwall@google.com 44 | */ 45 | 46 | PR['registerLangHandler']( 47 | PR['createSimpleLexer']( 48 | [ 49 | // clojure has more paren types than minimal lisp. 50 | ['opn', /^[\(\{\[]+/, null, '([{'], 51 | ['clo', /^[\)\}\]]+/, null, ')]}'], 52 | // A line comment that starts with ; 53 | [PR['PR_COMMENT'], /^;[^\r\n]*/, null, ';'], 54 | // Whitespace 55 | [PR['PR_PLAIN'], /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'], 56 | // A double quoted, possibly multi-line, string. 57 | [PR['PR_STRING'], /^\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)/, null, '"'] 58 | ], 59 | [ 60 | // clojure has a much larger set of keywords 61 | [PR['PR_KEYWORD'], /^(?:def|if|do|let|quote|var|fn|loop|recur|throw|try|monitor-enter|monitor-exit|defmacro|defn|defn-|macroexpand|macroexpand-1|for|doseq|dosync|dotimes|and|or|when|not|assert|doto|proxy|defstruct|first|rest|cons|defprotocol|deftype|defrecord|reify|defmulti|defmethod|meta|with-meta|ns|in-ns|create-ns|import|intern|refer|alias|namespace|resolve|ref|deref|refset|new|set!|memfn|to-array|into-array|aset|gen-class|reduce|map|filter|find|nil?|empty?|hash-map|hash-set|vec|vector|seq|flatten|reverse|assoc|dissoc|list|list?|disj|get|union|difference|intersection|extend|extend-type|extend-protocol|prn)\b/, null], 62 | [PR['PR_TYPE'], /^:[0-9a-zA-Z\-]+/] 63 | ]), 64 | ['clj']); 65 | -------------------------------------------------------------------------------- /src/static/module/code-prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright (C) 2009 Google Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * @fileoverview 20 | * Registers a language handler for CSS. 21 | * 22 | * 23 | * To use, include prettify.js and this file in your HTML page. 24 | * Then put your code in an HTML tag like 25 | *

 26 |  *
 27 |  *
 28 |  * http://www.w3.org/TR/CSS21/grammar.html Section G2 defines the lexical
 29 |  * grammar.  This scheme does not recognize keywords containing escapes.
 30 |  *
 31 |  * @author mikesamuel@gmail.com
 32 |  */
 33 | 
 34 | // This file is a call to a function defined in prettify.js which defines a
 35 | // lexical scanner for CSS and maps tokens to styles.
 36 | 
 37 | // The call to PR['registerLangHandler'] is quoted so that Closure Compiler
 38 | // will not rename the call so that this language extensions can be
 39 | // compiled/minified separately from one another.  Other symbols defined in
 40 | // prettify.js are similarly quoted.
 41 | 
 42 | // The call is structured thus:
 43 | // PR['registerLangHandler'](
 44 | //    PR['createSimpleLexer'](
 45 | //        shortcutPatterns,
 46 | //        fallThroughPatterns),
 47 | //    [languageId0, ..., languageIdN])
 48 | 
 49 | // Langugage IDs
 50 | // =============
 51 | // The language IDs are typically the file extensions of source files for
 52 | // that language so that users can syntax highlight arbitrary files based
 53 | // on just the extension.  This is heuristic, but works pretty well in
 54 | // practice.
 55 | 
 56 | // Patterns
 57 | // ========
 58 | // Lexers are typically implemented as a set of regular expressions.
 59 | // The SimpleLexer function takes regular expressions, styles, and some
 60 | // pragma-info and produces a lexer.  A token description looks like
 61 | //   [STYLE_NAME, /regular-expression/, pragmas]
 62 | 
 63 | // Initially, simple lexer's inner loop looked like:
 64 | 
 65 | //    while sourceCode is not empty:
 66 | //      try each regular expression in order until one matches
 67 | //      remove the matched portion from sourceCode
 68 | 
 69 | // This was really slow for large files because some JS interpreters
 70 | // do a buffer copy on the matched portion which is O(n*n)
 71 | 
 72 | // The current loop now looks like
 73 | 
 74 | //    1. use js-modules/combinePrefixPatterns.js to 
 75 | //       combine all regular expressions into one 
 76 | //    2. use a single global regular expresion match to extract all tokens
 77 | //    3. for each token try regular expressions in order until one matches it
 78 | //       and classify it using the associated style
 79 | 
 80 | // This is a lot more efficient but it does mean that lookahead and lookbehind
 81 | // can't be used across boundaries to classify tokens.
 82 | 
 83 | // Sometimes we need lookahead and lookbehind and sometimes we want to handle
 84 | // embedded language -- JavaScript or CSS embedded in HTML, or inline assembly
 85 | // in C.
 86 | 
 87 | // If a particular pattern has a numbered group, and its style pattern starts
 88 | // with "lang-" as in
 89 | //    ['lang-js', /