|
| 1 | +<!DOCTYPE html> |
| 2 | +<html> |
| 3 | +<head> |
| 4 | + <meta charset='utf-8' /> |
| 5 | + <title>nbviewer.js</title> |
| 6 | + |
| 7 | + <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/themes/prism.min.css'/> |
| 8 | + <script src='https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.6/marked.min.js'></script> |
| 9 | + <script src='https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/prism.min.js' data-manual></script> |
| 10 | + <script src='https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/components/prism-python.min.js' data-manual></script> |
| 11 | + |
| 12 | + <style type='text/css'> |
| 13 | + body { |
| 14 | + font: 0.8em Arial, sans-serif; |
| 15 | + background-color: #eee; |
| 16 | + } |
| 17 | + div#instructions { |
| 18 | + max-width: 960px; |
| 19 | + font-size: 2em; |
| 20 | + color: #aaa; |
| 21 | + text-align: center; |
| 22 | + /*padding-top: 5%;*/ |
| 23 | + margin: 0 auto; |
| 24 | + } |
| 25 | + p#examples { |
| 26 | + font-size: .5em; |
| 27 | + } |
| 28 | + div#serving-info { |
| 29 | + font-size: .7em; |
| 30 | + font-style: italic; |
| 31 | + margin-top: 1em; |
| 32 | + } |
| 33 | + div#bugs { |
| 34 | + font-size: .6em; |
| 35 | + } |
| 36 | + input#ghproj { |
| 37 | + display: block; |
| 38 | + font-size: 1em; |
| 39 | + text-align: center; |
| 40 | + margin: 0 auto; |
| 41 | + width: 50%; |
| 42 | + } |
| 43 | + div#filelist { |
| 44 | + margin: 0 auto; |
| 45 | + width: 50%; |
| 46 | + text-align: left; |
| 47 | + font-size: .8em; |
| 48 | + } |
| 49 | + div#filelist ul { |
| 50 | + list-style-type: none; |
| 51 | + } |
| 52 | + div#filelist ul li { |
| 53 | + vertical-align: center; |
| 54 | + } |
| 55 | + div#filelist ul li a { |
| 56 | + text-decoration: none; |
| 57 | + } |
| 58 | + </style> |
| 59 | + |
| 60 | + <!-- nbviewer.js --> |
| 61 | + <script src='lib/nbv.js'></script> |
| 62 | +</head> |
| 63 | +<body> |
| 64 | +<a href="https://github.com/kokes/nbviewer.js"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://camo.githubusercontent.com/a6677b08c955af8400f44c6298f40e7d19cc5b2d/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f677261795f3664366436642e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png"></a> |
| 65 | + |
| 66 | +<div id='doc'> |
| 67 | + <div id='instructions'> |
| 68 | + <p>Enter a <code>username/repo</code> combination from Github</p> |
| 69 | + <p id='examples'> |
| 70 | + <a href='#aHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9yc3ZwL2ZlY29uMjM1L2NvbnRlbnRzL25iL2ZyZWQtZW1wbG95LW5mcC5pcHluYj9yZWY9bWFzdGVy'>Example 1</a> |
| 71 | + <a href='#aHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9hcm9rZW0vdGVhY2hfb3B0aW1pemF0aW9uL2NvbnRlbnRzL29wdGltaXphdGlvbi5pcHluYj9yZWY9bWFzdGVy'>Example 2</a> |
| 72 | + <form> |
| 73 | + <input id='ghproj' type='text' placeholder='username/repo' /> |
| 74 | + <input id='ghlookup' type='submit' value='Browse repo' /> |
| 75 | + </form> |
| 76 | + |
| 77 | + <div id='serving-info'></div> |
| 78 | + <div id='bugs'>(We know there's an encoding issue making non-latin characters render incorrectly.)</div> |
| 79 | + |
| 80 | + <div id='filelist'> |
| 81 | + |
| 82 | + </div> |
| 83 | + </div> |
| 84 | + <div id='notebook'> |
| 85 | + |
| 86 | + </div> |
| 87 | + |
| 88 | +</div> |
| 89 | + |
| 90 | + |
| 91 | +<script type='text/javascript'> |
| 92 | + var d = document; |
| 93 | + var cache = {}; |
| 94 | + var gg; // debugging |
| 95 | + |
| 96 | + window.onload = function() { |
| 97 | + var lk = d.getElementById('ghlookup'); |
| 98 | + var ghproj = d.getElementById('ghproj'); |
| 99 | + |
| 100 | + // block submitting again |
| 101 | + lk.addEventListener('click', function(e) { |
| 102 | + e.target.disabled = 'disabled'; |
| 103 | + // TODO: validate inputs |
| 104 | + // should be something like [a-zA-Z0-9_\-]+\/[a-zA-Z0-9_\-], not sure what exactly |
| 105 | + var turl = get_gh_url('repos/' + ghproj.value + '/contents/'); // living on the edgeeee |
| 106 | + window.location.hash = btoa(turl); |
| 107 | + }); |
| 108 | + // re-enable the submit button when changed |
| 109 | + ghproj.addEventListener('keyup', function(e) { |
| 110 | + lk.disabled = ''; |
| 111 | + }); |
| 112 | + hash_changed(); |
| 113 | + }; |
| 114 | + |
| 115 | + window.onhashchange = hash_changed; |
| 116 | + |
| 117 | + function hash_changed() { |
| 118 | + render_gh_files(); |
| 119 | + } |
| 120 | + |
| 121 | + function render_gh_files() { |
| 122 | + wipeElement(d.getElementById('serving-info')); // clear |
| 123 | + var hs = window.location.hash.slice(1); // without '#' |
| 124 | + var hsurl = atob(hs); // base64 -> text |
| 125 | + ajax_get_json(hsurl, function(dt) { |
| 126 | + gg = dt; |
| 127 | + // get pathname |
| 128 | + var a = d.createElement('a'); |
| 129 | + a.href = hsurl; |
| 130 | + var path = a.pathname; |
| 131 | + |
| 132 | + if (path.endsWith('ipynb')) { |
| 133 | + var nb = JSON.parse(atob(dt.content)); // decode incoming data |
| 134 | + var tg = d.getElementById('notebook'); |
| 135 | + nbv.render(nb, tg); |
| 136 | + |
| 137 | + // serving info |
| 138 | + var turl = window.location; |
| 139 | + d.getElementById('serving-info').innerHTML = `Serving <code>${dt.name}</code>. <a href='${turl}'>Link to this render</a> / <a href='${dt.html_url}'>original Github source</a>`; |
| 140 | + return; |
| 141 | + } |
| 142 | + |
| 143 | + var fl = d.getElementById('filelist'); |
| 144 | + var ul = d.createElement('ul'); |
| 145 | + wipeElement(fl); |
| 146 | + for (var j=0; j<dt.length; j++) { |
| 147 | + var el = dt[j]; |
| 148 | + var li = d.createElement('li'); |
| 149 | + li.appendChild(function() { |
| 150 | + if (el.type === 'file' && !el.name.endsWith('.ipynb')) { |
| 151 | + return d.createTextNode(el.name); |
| 152 | + } |
| 153 | + |
| 154 | + var a = d.createElement('a'); |
| 155 | + a.textContent = el.name; |
| 156 | + a.setAttribute('href', '#' + btoa(el.url)); |
| 157 | + return a; |
| 158 | + }()); |
| 159 | + |
| 160 | + ul.appendChild(li); |
| 161 | + } |
| 162 | + fl.appendChild(ul); |
| 163 | + |
| 164 | + }); |
| 165 | + } |
| 166 | + |
| 167 | + function get_gh_url(path) { |
| 168 | + return 'https://api.github.com/' + path; |
| 169 | + } |
| 170 | + |
| 171 | + function ajax_get_json(url, callback) |
| 172 | + { |
| 173 | + console.log(url); |
| 174 | + if (cache[url] !== undefined) { |
| 175 | + console.log('serving from cache'); |
| 176 | + return callback(cache[url]); |
| 177 | + } |
| 178 | + |
| 179 | + var rr = new XMLHttpRequest(); |
| 180 | + rr.onreadystatechange = function() { |
| 181 | + if (rr.readyState == 4 && rr.status == 200) { |
| 182 | + cache[url] = JSON.parse(rr.responseText) |
| 183 | + callback(JSON.parse(rr.responseText)); |
| 184 | + } else if (rr.readyState == 4) { |
| 185 | + throw Error(err); |
| 186 | + } |
| 187 | + } |
| 188 | + rr.open('GET', url); |
| 189 | + rr.send(null); |
| 190 | + } |
| 191 | + |
| 192 | + function wipeElement(el) { |
| 193 | + while (el.firstChild) { |
| 194 | + el.removeChild(el.firstChild); |
| 195 | + } |
| 196 | +} |
| 197 | + |
| 198 | +</script> |
| 199 | + |
| 200 | +<script> |
| 201 | + (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ |
| 202 | + (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), |
| 203 | + m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) |
| 204 | + })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); |
| 205 | + |
| 206 | + ga('create', 'UA-98368126-1', 'auto'); |
| 207 | + ga('send', 'pageview'); |
| 208 | + |
| 209 | +</script> |
| 210 | + |
| 211 | +</body> |
| 212 | +</html> |
| 213 | + |
0 commit comments