vnote/src/resources/template.html
Le Tan fb1a172acf propagate key press event from QWebEngineView to VDocument
Signed-off-by: Le Tan <tamlokveer@gmail.com>
2017-01-21 09:42:48 +08:00

268 lines
7.4 KiB
HTML

<!doctype html>
<html lang="en">
<meta charset="utf-8">
<head>
<style type="text/css">
<!-- BACKGROUND_PLACE_HOLDER -->
</style>
<link rel="stylesheet" type="text/css" href="CSS_PLACE_HOLDER">
<link rel="stylesheet" type="text/css" href="qrc:/utils/highlightjs/styles/default.css">
<script src="qrc:/utils/marked/marked.min.js"></script>
<script src="qrc:/resources/qwebchannel.js"></script>
<script src="qrc:/utils/highlightjs/highlight.pack.js"></script>
</head>
<body>
<div id="placeholder"></div>
<script>
'use strict';
var placeholder = document.getElementById('placeholder');
var renderer = new marked.Renderer();
var toc = []; // Table of contents as a list
var content; // Channel variable with content
var nameCounter = 0;
var keyState = 0;
renderer.heading = function (text, level) {
// Use number to avoid issues with Chinese
var escapedText = 'toc_' + nameCounter++;
toc.push({
level: level,
anchor: escapedText,
title: text
});
return '<h' + level + ' id="' +
escapedText + '">' +
text + '</h' + level + '>';
};
// Highlight.js to highlight code block
marked.setOptions({
highlight: function (code) {
return hljs.highlightAuto(code).value;
}
});
var markdownToHtml = function (markdown, needToc) {
toc = [];
var html = marked(markdown, { renderer: renderer });
nameCounter = 0;
if (needToc) {
return html.replace(/<p>\[TOC\]<\/p>/ig, '<div class="vnote-toc"></div>');
} else {
return html;
}
};
// Handle wrong title levels, such as '#' followed by '###'
var toPerfectToc = function (toc) {
var i;
var curLevel = 1;
var perfToc = [];
for (i in toc) {
var item = toc[i];
while (item.level > curLevel + 1) {
curLevel += 1;
var tmp = { level: curLevel,
anchor: item.anchor,
title: '[EMPTY]'
};
perfToc.push(tmp);
}
perfToc.push(item);
curLevel = item.level;
}
return perfToc;
};
var itemToHtml = function (item) {
return '<a href="#' + item.anchor + '">' + item.title + '</a>';
};
// Turn a perfect toc to a tree using <ul>
var tocToTree = function (toc) {
var i;
var front = '<li>';
var ending = ['</li>'];
var curLevel = 1;
for (i in toc) {
var item = toc[i];
if (item.level == curLevel) {
front += '</li>';
front += '<li>';
front += itemToHtml(item);
} else if (item.level > curLevel) {
// assert(item.level - curLevel == 1)
front += '<ul>';
ending.push('</ul>');
front += '<li>';
front += itemToHtml(item);
ending.push('</li>');
curLevel = item.level;
} else {
while (item.level < curLevel) {
var ele = ending.pop();
front += ele;
if (ele == '</ul>') {
curLevel--;
}
}
front += '</li>';
front += '<li>';
front += itemToHtml(item);
}
}
while (ending.length > 0) {
front += ending.pop();
}
front = front.replace("<li></li>", "");
front = '<ul>' + front + '</ul>';
return front;
};
var handleToc = function(needToc) {
var tocTree = tocToTree(toPerfectToc(toc));
content.setToc(tocTree);
// Add it to html
if (needToc) {
var eles = document.getElementsByClassName('vnote-toc');
for (var i = 0; i < eles.length; ++i) {
eles[i].innerHTML = tocTree;
}
}
};
var mdHasTocSection = function(markdown) {
var n = markdown.search(/(\n|^)\[toc\]/i);
return n != -1;
};
var updateText = function(text) {
var needToc = mdHasTocSection(text);
var html = markdownToHtml(text, needToc);
placeholder.innerHTML = html;
handleToc(needToc);
};
var scrollToAnchor = function(anchor) {
document.getElementById(anchor).scrollIntoView();
};
new QWebChannel(qt.webChannelTransport,
function(channel) {
content = channel.objects.content;
updateText(content.text);
content.textChanged.connect(updateText);
content.requestScrollToAnchor.connect(scrollToAnchor);
}
);
window.onscroll = function() {
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop || window.pageYOffset;
var eles = document.querySelectorAll("h1, h2, h3, h4, h5, h6");
if (eles.length == 0) {
return;
}
var curIdx = 0;
var biaScrollTop = scrollTop + 50;
for (var i = 0; i < eles.length; ++i) {
if (biaScrollTop >= eles[i].offsetTop) {
curIdx = i;
} else {
break;
}
}
var curHeader = eles[curIdx].getAttribute("id");
if (curHeader != null) {
content.setHeader(curHeader);
}
}
document.onkeydown = function(e) {
e = e || window.event;
var key;
var shift;
var ctrl;
if (e.which) {
key = e.which;
} else {
key = e.keyCode;
}
shift = !!e.shiftKey;
ctrl = !!e.ctrlKey;
switch (key) {
case 74: // J
window.scrollBy(0, 100);
keyState = 0;
break;
case 75: // K
window.scrollBy(0, -100);
keyState = 0;
break;
case 72: // H
window.scrollBy(-100, 0);
keyState = 0;
break;
case 76: // L
window.scrollBy(100, 0);
keyState = 0;
break;
case 71: // G
if (shift) {
var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft || window.pageXOffset;
var scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
window.scrollTo(scrollLeft, scrollHeight);
keyState = 0;
break;
} else {
if (keyState == 0) {
keyState = 1;
} else if (keyState == 1) {
keyState = 0;
var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft || window.pageXOffset;
window.scrollTo(scrollLeft, 0);
}
break;
}
return;
case 85: // U
keyState = 0;
if (ctrl) {
var clientHeight = document.documentElement.clientHeight;
window.scrollBy(0, -clientHeight);
break;
}
return;
case 68: // D
keyState = 0;
if (ctrl) {
var clientHeight = document.documentElement.clientHeight;
window.scrollBy(0, clientHeight);
break;
}
return;
default:
content.keyPressEvent(key);
keyState = 0;
return;
}
e.preventDefault();
}
</script>
</body>
</html>