Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions ipynb-quicklook.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@
219F673A1E37F49800CA4392 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1010;
LastUpgradeCheck = 1120;
ORGANIZATIONNAME = "Tino Wagner";
TargetAttributes = {
219F67421E37F49800CA4392 = {
Expand All @@ -119,10 +119,11 @@
};
buildConfigurationList = 219F673D1E37F49800CA4392 /* Build configuration list for PBXProject "ipynb-quicklook" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 219F67391E37F49800CA4392;
productRefGroup = 219F67441E37F49800CA4392 /* Products */;
Expand Down Expand Up @@ -165,6 +166,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
Expand Down Expand Up @@ -220,6 +222,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1120"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "219F67421E37F49800CA4392"
BuildableName = "ipynb-quicklook.qlgenerator"
BlueprintName = "ipynb-quicklook"
ReferencedContainer = "container:ipynb-quicklook.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "219F67421E37F49800CA4392"
BuildableName = "ipynb-quicklook.qlgenerator"
BlueprintName = "ipynb-quicklook"
ReferencedContainer = "container:ipynb-quicklook.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
5 changes: 5 additions & 0 deletions ipynb-quicklook/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
<script src='https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.6/marked.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/prism.min.js' data-manual></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/components/prism-python.min.js' data-manual></script>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css" />

<script src="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.js" data-manual></script>

<script src='cid:nbv.js'></script>
<style type='text/css'>
body {
Expand Down
10 changes: 10 additions & 0 deletions nbviewer.js/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ I thought it could be easier and more lightweight. So I hacked together this cli

[**Try a live demo**](https://kokes.github.io/nbviewer.js/viewer.html)

#### NEW: Rendering Github notebooks

You can now render notebooks hosted on Github. You can copy and paste their URL in the viewer, linked above, or you can save this following link as a bookmark:

```
javascript:(function(){location.href="https://kokes.github.io/nbviewer.js/viewer.html#"+btoa(location.href);})();
```

Clicking this while on Github, looking at a notebook, will launch our nbviewer with this notebook rendered here instead. You'll also get a permanent link for you to share.

#### Usage

There are two ways one can use this. You can use the library itself, there is just a single public method, you call `nbv.render(data, target)`, where `data` is the JSON representation of your Jupyter notebook and `target` is the node where the notebook is to be rendered.
Expand Down
17 changes: 13 additions & 4 deletions nbviewer.js/lib/nbv.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ var nbv = (function() {
var st = {}; // settings

function render_ipynb(obj, target, settings) {
if (!window.marked || !window.Prism) {
console.error('expecting libraries marked.js and Prism.js to be present');
if (!window.marked || !window.Prism || !window.katex) {
console.error('expecting libraries marked.js, Prism.js and KaTeX to be present');
return;
}
st = settings || {};
Expand All @@ -28,7 +28,7 @@ var nbv = (function() {
var t = d.createElement('div');
t.setAttribute('style', [
'max-width: 960px',
'border: 1px solid #ccc',
'border: 1px solid #ccc',
'margin: 1em auto',
'padding: 1.5em 1.5em 1.5em 7em',
'background-color: white',
Expand Down Expand Up @@ -291,9 +291,18 @@ var nbv = (function() {
return cn;
}

function latexer(match, m1, offset, string) {
return katex.renderToString(m1, {
throwOnError: false, // we do not want to stop rendering because of bad LaTeX
});
}

function handle_mdown(cell) {
var el = d.createElement('div');
el.innerHTML = marked(cell.source.join(''));
var source = cell.source.join('');
var latexed = source.replace(/\$\$([\s\S]+?)\$\$/g, latexer); // block-based math
latexed = latexed.replace(/\$(.+?)\$/g, latexer); // inline math
el.innerHTML = marked(latexed);

return el;
}
Expand Down
118 changes: 115 additions & 3 deletions nbviewer.js/viewer.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
<script src='https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/prism.min.js' data-manual></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/components/prism-python.min.js' data-manual></script>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css" integrity="sha384-zB1R0rpPzHqg7Kpt0Aljp8JPLqbXI3bhnPWROx27a9N0Ll6ZP/+DiW/UqRcLbRjq" crossorigin="anonymous">

<script src="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.js" integrity="sha384-y23I5Q6l+B6vatafAwxRu/0oK/79VlbSz7Q9aiSZUvyWYIYsd+qj+o24G5ZU2zJz" crossorigin="anonymous"></script>


<style type='text/css'>
body {
font: 0.8em Arial, sans-serif;
Expand Down Expand Up @@ -40,6 +45,24 @@
font-size: 2em;
margin: 0 auto;
}
button#download-notebook {
display: none;
margin: 1em auto 0 auto;
}
input#github-link {
font-size: 1em;
text-align: center;
width: 60%;
}
input#github-link::placeholder {
color: #ccc;
}
div#serving-info {
font-size: 1.2em;
font-style: italic;
margin-top: 1em;
text-align: center;
}
</style>

<!-- nbviewer.js -->
Expand All @@ -50,20 +73,44 @@

<div id='doc'>
<select id='file-selector'></select>
<div id='instructions'>Drag and drop Jupyter notebooks anywhere here</div>
<button id='download-notebook'>Download this notebook in HTML</button>
<div id='instructions'>Drag and drop Jupyter notebooks anywhere here...<br />
or paste a link from Github: <br />
<input id='github-link' placeholder='https://github.com/...'/>
</div>

<div id='serving-info'></div>

</div>


<script type='text/javascript'>
var d = document
var doc = d.getElementById('doc')
var dn = d.getElementById('download-notebook')

dn.addEventListener('click', function() {
var nbs = d.querySelectorAll('div.rendered-notebook')
for (var j=0; j<nbs.length; j++) {
if (nbs[j].style.display == 'none') continue

var link = d.createElement('a')
var content = encodeURIComponent(nbs[j].innerHTML)
var filename = nbs[j].getAttribute('rel').replace('.ipynb', '.html')
link.setAttribute('href', 'data:text/plain;charset=utf-8,' + content)
link.setAttribute('download', filename)

d.body.appendChild(link)
link.click()
d.body.removeChild(link)
break
}
})

var fs = d.getElementById('file-selector')
fs.addEventListener('change', function() {
var nbs = doc.childNodes
var nbs = d.querySelectorAll('div.rendered-notebook')
for (var j=0; j<nbs.length; j++) {
if (nbs[j].nodeName != 'DIV') continue
if (nbs[j].getAttribute('rel') == fs.value) {
nbs[j].style.display = 'block'
continue
Expand Down Expand Up @@ -115,6 +162,7 @@
function renderFiles(fns) {
d.getElementById('instructions').style.display = 'none'
fs.style.display = 'block'
dn.style.display = 'block'

for (var j=0; j<fns.length; j++) {
var fn = fns[j]
Expand All @@ -135,6 +183,7 @@
var tg = doc.querySelector('div[rel="' + fn.name + '"]')
if (tg === null) {
tg = d.createElement('div')
tg.setAttribute('class', 'rendered-notebook')
tg.setAttribute('rel', fn.name)
doc.appendChild(tg)
}
Expand All @@ -161,6 +210,69 @@
}
}

// github rendering shenanigans
var ghl = document.getElementById('github-link')

ghl.addEventListener('keyup', (x) => {
// TODO: verify the link via regexp or something
// and change the input's css accordingly (red border)
window.location.hash = btoa(ghl.value);
render_gh_files()
})

// what if we loaded a site with a hash already
if (window.location.hash.length > 1) {
ghl.value = atob(window.location.hash.slice(1))
var event = new CustomEvent('keyup')
ghl.dispatchEvent(event)
}

// `atob` won't decode utf8 characters correctly, we need to do more about this
// taken from this excellent answer https://stackoverflow.com/a/30106551
function b64DecodeUnicode(str) {
return decodeURIComponent(atob(str).split('').map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
}

async function render_gh_files() {
console.log('rendering')
var hs = window.location.hash.slice(1); // without '#'
var hsurl = atob(hs); // base64 -> text

// extract relevant bits from the URL and create a URL for the Github API
var ghparts = new RegExp(/https:\/\/github.com\/(.+?)\/(.+?)\/blob\/(.+?)\/(.+\.ipynb)/)
var m = hsurl.match(ghparts)
if (!m) {
// TODO: render some place
console.error('invalid URL ' + hsurl)
return
}

var api_url = `https://api.github.com/repos/${m[1]}/${m[2]}/contents/${m[4]}?ref=${m[3]}`
var filename = m[4].split('/').pop()
console.log(`translated ${hsurl} into ${api_url}, fetching`)

var dd = await fetch(api_url) // TODO: this could fail on API limits
var ddj = await dd.json()
var dt = JSON.parse(b64DecodeUnicode(ddj.content)) // decode incoming data
gg = dt;

d.getElementById('instructions').style.display = 'none'

tg = d.createElement('div')
tg.setAttribute('class', 'rendered-notebook')
tg.setAttribute('rel', hsurl)
doc.appendChild(tg)

nbv.render(dt, tg)

document.getElementById('download-notebook').style.display = 'block'

document.getElementById('serving-info').innerHTML = `Serving <code>${decodeURI(filename)}</code>. <a href='${window.location}'>Permanent link to this render</a> / <a href='${hsurl}'>original Github source</a>, <a href='${api_url}'>API source data</a>`;
// return;
}

</script>

<script>
Expand Down