kopia lustrzana https://github.com/c9/core
302 wiersze
12 KiB
HTML
302 wiersze
12 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<script src="remarkable.min.js"></script>
|
|
<link rel="stylesheet" type="text/css" href="github-markdown.css">
|
|
<style>
|
|
body, html{
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
#preview{
|
|
overflow: auto;
|
|
color: rgb(0, 0, 0);
|
|
|
|
min-width: 200px;
|
|
max-width: 790px;
|
|
margin: 0 auto;
|
|
padding: 30px;
|
|
|
|
-webkit-font-smoothing: antialiased;
|
|
-moz-osx-font-smoothing: grayscale;
|
|
}
|
|
#preview pre code div {
|
|
background: transparent !important;
|
|
}
|
|
#preview .ace_line {
|
|
white-space: pre;
|
|
}
|
|
#preview .ace_static_highlight {
|
|
font-family: inherit;
|
|
font-size: inherit;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="markdown-body" id="preview">
|
|
|
|
</div>
|
|
<script>
|
|
(function(){
|
|
/*global Remarkable*/
|
|
var preview = document.getElementById("preview");
|
|
var host = location.href.match(/host=(.*?)(\&|$)/)[1];
|
|
var id = location.href.match(/id=(.*)/)[1];
|
|
var parent = window.opener || window.parent;
|
|
|
|
var count = 0;
|
|
|
|
var md = new Remarkable({
|
|
html: true, // Enable HTML tags in source
|
|
xhtmlOut: false, // Use '/' to close single tags (<br />)
|
|
breaks: false, // Convert '\n' in paragraphs into <br>
|
|
langPrefix: 'language-', // CSS language prefix for fenced blocks
|
|
linkify: true, // Autoconvert URL-like text to links
|
|
|
|
// Enable some language-neutral replacement + quotes beautification
|
|
typographer: true,
|
|
|
|
// Double + single quotes replacement pairs, when typographer enabled,
|
|
// and smartquotes on. Set doubles to '«»' for Russian, '„“' for German.
|
|
quotes: '“”‘’',
|
|
|
|
// Highlighter function. Should return escaped HTML,
|
|
// or '' if the source string is not changed
|
|
highlight: function (str, lang) {
|
|
var id = count++;
|
|
send({
|
|
message: "highlight",
|
|
content: str,
|
|
lang: lang,
|
|
hid: id
|
|
});
|
|
|
|
return '<span id="findme' + id + '"></span>' + str;
|
|
}
|
|
});
|
|
md.renderer.rules.paragraph_open = function (tokens, idx) {
|
|
var line;
|
|
if (tokens[idx].lines && tokens[idx].level === 0) {
|
|
line = tokens[idx].lines[0];
|
|
return '<p class="line" data-line="' + line + '">';
|
|
}
|
|
return '<p>';
|
|
};
|
|
|
|
md.renderer.rules.heading_open = function (tokens, idx) {
|
|
var line;
|
|
if (tokens[idx].lines && tokens[idx].level === 0) {
|
|
line = tokens[idx].lines[0];
|
|
return '<h' + tokens[idx].hLevel + ' class="line" data-line="' + line + '">';
|
|
}
|
|
return '<h' + tokens[idx].hLevel + '>';
|
|
};
|
|
|
|
md.renderer.rules.list_item_open = function (tokens, idx) {
|
|
var line;
|
|
if (tokens[idx].lines) {
|
|
line = tokens[idx].lines[0];
|
|
return '<li class="line" data-line="' + line + '">';
|
|
}
|
|
return '<li>';
|
|
};
|
|
|
|
md.renderer.rules.blockquote_open = function (tokens, idx) {
|
|
var line;
|
|
if (tokens[idx].lines) {
|
|
line = tokens[idx].lines[0];
|
|
return '<blockquote class="line" data-line="' + line + '">';
|
|
}
|
|
return '<blockquote>';
|
|
};
|
|
|
|
// Build offsets for each line (lines can be wrapped)
|
|
// That's a bit dirty to process each line everytime, but ok for demo.
|
|
// Optimizations are required only for big texts.
|
|
var sourceLikeDiv, cStyle;
|
|
function buildScrollMap(value) {
|
|
var i, offset, nonEmptyList, pos, a, b, lineHeightMap, linesCount,
|
|
acc, _scrollMap;
|
|
|
|
if (!sourceLikeDiv) {
|
|
sourceLikeDiv = document.createElement("div");
|
|
sourceLikeDiv.style.position = 'absolute';
|
|
sourceLikeDiv.style.visibility = 'hidden';
|
|
sourceLikeDiv.style.height = 'auto';
|
|
sourceLikeDiv.style.width = preview.clientWidth;
|
|
sourceLikeDiv.style.fontSize = cStyle.fontSize;
|
|
sourceLikeDiv.style.fontFamily = cStyle.fontFamily;
|
|
// sourceLikeDiv.style.lineHeight = cStyle.lineHeight;
|
|
sourceLikeDiv.style.whiteSpace = "pre";
|
|
}
|
|
document.body.appendChild(sourceLikeDiv);
|
|
|
|
offset = 0;
|
|
_scrollMap = [];
|
|
nonEmptyList = [];
|
|
lineHeightMap = [];
|
|
|
|
acc = 0;
|
|
value.split('\n').forEach(function(str) {
|
|
var h, lh;
|
|
|
|
lineHeightMap.push(acc);
|
|
|
|
if (str.length === 0) {
|
|
acc++;
|
|
return;
|
|
}
|
|
|
|
sourceLikeDiv.innerHTML = str;
|
|
var sStyle = getComputedStyle(sourceLikeDiv);
|
|
h = parseFloat(sStyle.height);
|
|
lh = parseFloat(sStyle.fontSize);
|
|
acc += Math.round(h / lh);
|
|
});
|
|
sourceLikeDiv.remove();
|
|
lineHeightMap.push(acc);
|
|
linesCount = acc;
|
|
|
|
for (i = 0; i < linesCount; i++) { _scrollMap.push(-1); }
|
|
|
|
nonEmptyList.push(0);
|
|
_scrollMap[0] = 0;
|
|
|
|
var lines = preview.querySelectorAll(".line");
|
|
for (var i = 0, l = lines.length; i < l; i++) {
|
|
var t = lines[i].getAttribute("data-line");
|
|
if (t === '') { return; }
|
|
t = lineHeightMap[t];
|
|
if (t !== 0) { nonEmptyList.push(t); }
|
|
_scrollMap[t] = Math.round(lines[i].offsetTop + offset);
|
|
}
|
|
|
|
nonEmptyList.push(linesCount);
|
|
_scrollMap[linesCount] = preview.scrollHeight;
|
|
|
|
pos = 0;
|
|
for (i = 1; i < linesCount; i++) {
|
|
if (_scrollMap[i] !== -1) {
|
|
pos++;
|
|
continue;
|
|
}
|
|
|
|
a = nonEmptyList[pos];
|
|
b = nonEmptyList[pos + 1];
|
|
_scrollMap[i] = Math.round((_scrollMap[b] * (i - a)
|
|
+ _scrollMap[a] * (b - i)) / (b - a));
|
|
}
|
|
|
|
_scrollMap[0] = 0;
|
|
return _scrollMap;
|
|
}
|
|
|
|
var ckb;
|
|
function setKeys(list){
|
|
ckb = {};
|
|
|
|
list.forEach(function(item) {
|
|
var binding = item.binding;
|
|
var command = item.command;
|
|
var hashId = binding.hashId;
|
|
var hash = (ckb[hashId] || (ckb[hashId] = {}));
|
|
|
|
if (!hash[binding.key]) {
|
|
hash[binding.key] = command;
|
|
} else {
|
|
if (!Array.isArray(hash[binding.key]))
|
|
hash[binding.key] = [hash[binding.key]];
|
|
|
|
hash[binding.key].push(command);
|
|
}
|
|
}, this);
|
|
}
|
|
|
|
var timer;
|
|
function scrollTo(posTo){
|
|
clearInterval(timer);
|
|
var curPos = document.body.scrollTop;
|
|
var dist = posTo - curPos;
|
|
var incr = dist / 10;
|
|
|
|
timer = setInterval(function(){
|
|
if (incr < 0
|
|
? document.body.scrollTop + incr < posTo
|
|
: document.body.scrollTop + incr > posTo) {
|
|
document.body.scrollTop = posTo;
|
|
clearInterval(timer);
|
|
}
|
|
else
|
|
document.body.scrollTop += incr;
|
|
}, 10);
|
|
}
|
|
|
|
document.addEventListener("keydown", function(e){
|
|
var hashId = 0 | (e.ctrlKey ? 1 : 0) | (e.altKey ? 2 : 0)
|
|
| (e.shiftKey ? 4 : 0) | (e.metaKey ? 8 : 0);
|
|
|
|
var keys = ckb[hashId];
|
|
var cmd = keys && keys[e.keyCode];
|
|
|
|
if (cmd) {
|
|
send({ message: "exec", command: cmd });
|
|
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
});
|
|
|
|
var scrollMap, lastValue, highlightStyle;
|
|
window.addEventListener("message", function(e){
|
|
if (host != "local" && e.origin !== host)
|
|
return;
|
|
|
|
if (e.data.type == "document") {
|
|
lastValue = e.data.content;
|
|
preview.innerHTML = md.render(lastValue);
|
|
cStyle = e.data;
|
|
scrollMap = null;
|
|
}
|
|
else if (e.data.type == "keys")
|
|
setKeys(e.data.keys);
|
|
else if (e.data.type == "scroll") {
|
|
if (!scrollMap)
|
|
scrollMap = buildScrollMap(lastValue);
|
|
var line = Math.max(0, e.data.lineNumber - 2);
|
|
var posTo = scrollMap[line];
|
|
|
|
scrollTo(posTo);
|
|
}
|
|
else if (e.data.type == "highlight") {
|
|
var el = document.getElementById("findme" + e.data.hid);
|
|
if (!el) return;
|
|
if (!highlightStyle) {
|
|
highlightStyle = document.head.appendChild(document.createElement("style"));
|
|
highlightStyle.innerText = e.data.css;
|
|
}
|
|
el.parentNode.innerHTML = e.data.html;
|
|
}
|
|
}, false);
|
|
|
|
window.addEventListener("focus", function(){
|
|
send({ message: "focus" });
|
|
});
|
|
|
|
function send(message){
|
|
message.id = id;
|
|
parent.postMessage(message,
|
|
host == "local" ? "*" : host);
|
|
}
|
|
|
|
window.start = function(win){
|
|
parent = win || window.parent;
|
|
send({ message: "stream.document" });
|
|
}
|
|
|
|
if (parent != window)
|
|
window.start(parent);
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html> |