Skip to content

Commit 7c41156

Browse files
committed
static apps/htmlpreview: intro local devel preview
1 parent 58c543e commit 7c41156

File tree

3 files changed

+187
-0
lines changed

3 files changed

+187
-0
lines changed

docs/apps/README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# mtulio.dev Apps
2+
3+
Apps page hosts static html apps hosted by mkdocs.
4+
5+
Access those using the url https://mtulio.dev/apps/<app_name>.
6+
7+
Available apps:
8+
9+
- [htmlpreview](https://mtulio.dev/apps/htmlpreview): Powered by [htmlpreview.github.io](https://github.com/htmlpreview/htmlpreview.github.com)
10+
11+
12+
## Apps Setup
13+
14+
15+
### htmlpreview
16+
17+
Steps to update:
18+
- clone/copy the repo content into the directory htmlpreview
19+
- remove unused data to prevent mkdocs rendering:
20+
```sh
21+
rm docs/apps/htmlpreview/readme.md
22+
```
23+
- update htmlpreview.js to match the relative path
24+
```sh
25+
sed -i 's/\"\/htmlpreview.js/"\.\/htmlpreview.js/' docs/apps/htmlpreview/index.html
26+
```
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
(function () {
2+
3+
var previewForm = document.getElementById('previewform');
4+
5+
var url = location.search.substring(1).replace(/\/\/github\.com/, '//raw.githubusercontent.com').replace(/\/blob\//, '/'); //Get URL of the raw file
6+
7+
var replaceAssets = function () {
8+
var frame, a, link, links = [], script, scripts = [], i, href, src;
9+
//Framesets
10+
if (document.querySelectorAll('frameset').length)
11+
return; //Don't replace CSS/JS if it's a frameset, because it will be erased by document.write()
12+
//Frames
13+
frame = document.querySelectorAll('iframe[src],frame[src]');
14+
for (i = 0; i < frame.length; ++i) {
15+
src = frame[i].src; //Get absolute URL
16+
if (src.indexOf('//raw.githubusercontent.com') > 0 || src.indexOf('//bitbucket.org') > 0) { //Check if it's from raw.github.com or bitbucket.org
17+
frame[i].src = '//' + location.hostname + location.pathname + '/apps/htmlpreview/?' + src; //Then rewrite URL so it can be loaded using CORS proxy
18+
}
19+
}
20+
//Links
21+
a = document.querySelectorAll('a[href]');
22+
for (i = 0; i < a.length; ++i) {
23+
href = a[i].href; //Get absolute URL
24+
if (href.indexOf('#') > 0) { //Check if it's an anchor
25+
a[i].href = '//' + location.hostname + location.pathname + location.search + '#' + a[i].hash.substring(1); //Then rewrite URL with support for empty anchor
26+
} else if ((href.indexOf('//raw.githubusercontent.com') > 0 || href.indexOf('//bitbucket.org') > 0) && (href.indexOf('.html') > 0 || href.indexOf('.htm') > 0)) { //Check if it's from raw.github.com or bitbucket.org and to HTML files
27+
a[i].href = '//' + location.hostname + location.pathname + '/apps/htmlpreview/?' + href; //Then rewrite URL so it can be loaded using CORS proxy
28+
}
29+
}
30+
//Stylesheets
31+
link = document.querySelectorAll('link[rel=stylesheet]');
32+
for (i = 0; i < link.length; ++i) {
33+
href = link[i].href; //Get absolute URL
34+
if (href.indexOf('//raw.githubusercontent.com') > 0 || href.indexOf('//bitbucket.org') > 0) { //Check if it's from raw.github.com or bitbucket.org
35+
links.push(fetchProxy(href, null, 0)); //Then add it to links queue and fetch using CORS proxy
36+
}
37+
}
38+
Promise.all(links).then(function (res) {
39+
for (i = 0; i < res.length; ++i) {
40+
loadCSS(res[i]);
41+
}
42+
});
43+
//Scripts
44+
script = document.querySelectorAll('script[type="text/htmlpreview"]');
45+
for (i = 0; i < script.length; ++i) {
46+
src = script[i].src; //Get absolute URL
47+
if (src.indexOf('//raw.githubusercontent.com') > 0 || src.indexOf('//bitbucket.org') > 0) { //Check if it's from raw.github.com or bitbucket.org
48+
scripts.push(fetchProxy(src, null, 0)); //Then add it to scripts queue and fetch using CORS proxy
49+
} else {
50+
script[i].removeAttribute('type');
51+
scripts.push(script[i].innerHTML); //Add inline script to queue to eval in order
52+
}
53+
}
54+
Promise.all(scripts).then(function (res) {
55+
for (i = 0; i < res.length; ++i) {
56+
loadJS(res[i]);
57+
}
58+
document.dispatchEvent(new Event('DOMContentLoaded', {bubbles: true, cancelable: true})); //Dispatch DOMContentLoaded event after loading all scripts
59+
});
60+
};
61+
62+
var loadHTML = function (data) {
63+
if (data) {
64+
data = data.replace(/<head([^>]*)>/i, '<head$1><base href="' + url + '">').replace(/<script(\s*src=["'][^"']*["'])?(\s*type=["'](text|application)\/javascript["'])?/gi, '<script type="text/htmlpreview"$1'); //Add <base> just after <head> and replace <script type="text/javascript"> with <script type="text/htmlpreview">
65+
setTimeout(function () {
66+
document.open();
67+
document.write(data);
68+
document.close();
69+
replaceAssets();
70+
}, 10); //Delay updating document to have it cleared before
71+
}
72+
};
73+
74+
var loadCSS = function (data) {
75+
if (data) {
76+
var style = document.createElement('style');
77+
style.innerHTML = data;
78+
document.head.appendChild(style);
79+
}
80+
};
81+
82+
var loadJS = function (data) {
83+
if (data) {
84+
var script = document.createElement('script');
85+
script.innerHTML = data;
86+
document.body.appendChild(script);
87+
}
88+
};
89+
90+
var fetchProxy = function (url, options, i) {
91+
var proxy = [
92+
'', // try without proxy first
93+
'https://api.codetabs.com/v1/proxy/?quest='
94+
];
95+
return fetch(proxy[i] + url, options).then(function (res) {
96+
if (!res.ok) throw new Error('Cannot load ' + url + ': ' + res.status + ' ' + res.statusText);
97+
return res.text();
98+
}).catch(function (error) {
99+
if (i === proxy.length - 1)
100+
throw error;
101+
return fetchProxy(url, options, i + 1);
102+
})
103+
};
104+
105+
if (url && url.indexOf(location.hostname) < 0)
106+
fetchProxy(url, null, 0).then(loadHTML).catch(function (error) {
107+
console.error(error);
108+
previewForm.style.display = 'block';
109+
previewForm.innerText = error;
110+
});
111+
else
112+
previewForm.style.display = 'block';
113+
114+
})()

docs/apps/htmlpreview/index.html

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<title>GitHub &amp; BitBucket HTML Preview</title>
6+
<style>
7+
body {
8+
font: 12px 'Helvetica Neue', Helvetica, Arial, freesans, clean, sans-serif;
9+
color: #333;
10+
}
11+
h1 {
12+
font-size: 20px;
13+
}
14+
a {
15+
color: #666;
16+
}
17+
#previewform {
18+
display: none;
19+
padding: 20px;
20+
text-align: center;
21+
}
22+
strong {
23+
color: #333;
24+
background-color: #FAFFA6;
25+
padding: 0.1em;
26+
}
27+
#footer {
28+
margin: 20px 0;
29+
font-size: 10px;
30+
color: #666;
31+
}
32+
</style>
33+
</head>
34+
<body>
35+
<form id="previewform" onsubmit="location.href='/?'+this.file.value;return false">
36+
<h1>GitHub &amp; BitBucket HTML Preview</h1>
37+
<p>
38+
Enter URL of the HTML file to preview:
39+
<input type="url" id="file" value="" placeholder="e.g. https://github.com/user/repo/blob/master/index.html" size="60" autofocus>
40+
<input type="submit" value="Preview">
41+
</p>
42+
<p>or prepend to the URL: <code><strong>http://htmlpreview.github.io/?</strong>https://github.com/twbs/bootstrap/blob/gh-pages/2.3.2/index.html</code></p>
43+
<p id="footer">Developed by <a href="https://github.com/niutech">niu tech</a> | Contribute on <a href="https://github.com/htmlpreview/htmlpreview.github.com">GitHub</a></p>
44+
</form>
45+
<script src="./htmlpreview.js"></script>
46+
</body>
47+
</html>

0 commit comments

Comments
 (0)