mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 05:49:53 +08:00
Export: support outline panel in exported HTML file
This commit is contained in:
parent
03ff391948
commit
77dd8d0f32
@ -372,11 +372,16 @@ QWidget *VExportDialog::setupHTMLAdvancedSettings()
|
||||
m_completeHTMLCB->setEnabled(!checked);
|
||||
});
|
||||
|
||||
QFormLayout *advLayout = new QFormLayout();
|
||||
advLayout->addRow(m_embedStyleCB);
|
||||
advLayout->addRow(m_completeHTMLCB);
|
||||
advLayout->addRow(m_embedImagesCB);
|
||||
advLayout->addRow(m_mimeHTMLCB);
|
||||
// Outline panel.
|
||||
m_outlinePanelCB = new QCheckBox(tr("Enable outline panel"), this);
|
||||
m_outlinePanelCB->setToolTip(tr("Add an outline panel in HTML file"));
|
||||
|
||||
QGridLayout *advLayout = new QGridLayout();
|
||||
advLayout->addWidget(m_embedStyleCB, 0, 1, 1, 2);
|
||||
advLayout->addWidget(m_completeHTMLCB, 0, 4, 1, 2);
|
||||
advLayout->addWidget(m_embedImagesCB, 1, 1, 1, 2);
|
||||
advLayout->addWidget(m_mimeHTMLCB, 1, 4, 1, 2);
|
||||
advLayout->addWidget(m_outlinePanelCB, 2, 1, 1, 2);
|
||||
|
||||
advLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
@ -483,6 +488,8 @@ void VExportDialog::initUIFields(MarkdownConverterType p_renderer)
|
||||
|
||||
m_mimeHTMLCB->setChecked(s_opt.m_htmlOpt.m_mimeHTML);
|
||||
|
||||
m_outlinePanelCB->setChecked(s_opt.m_htmlOpt.m_outlinePanel);
|
||||
|
||||
m_tableOfContentsCB->setChecked(s_opt.m_pdfOpt.m_enableTableOfContents);
|
||||
|
||||
m_wkhtmltopdfCB->setChecked(s_opt.m_pdfOpt.m_wkhtmltopdf);
|
||||
@ -587,7 +594,8 @@ void VExportDialog::startExport()
|
||||
ExportHTMLOption(m_embedStyleCB->isChecked(),
|
||||
m_completeHTMLCB->isChecked(),
|
||||
m_embedImagesCB->isChecked(),
|
||||
m_mimeHTMLCB->isChecked()),
|
||||
m_mimeHTMLCB->isChecked(),
|
||||
m_outlinePanelCB->isChecked()),
|
||||
ExportCustomOption((ExportCustomOption::SourceFormat)
|
||||
m_customSrcFormatCB->currentData().toInt(),
|
||||
m_customSuffixEdit->text(),
|
||||
|
@ -58,18 +58,21 @@ struct ExportHTMLOption
|
||||
: m_embedCssStyle(true),
|
||||
m_completeHTML(true),
|
||||
m_embedImages(true),
|
||||
m_mimeHTML(false)
|
||||
m_mimeHTML(false),
|
||||
m_outlinePanel(true)
|
||||
{
|
||||
}
|
||||
|
||||
ExportHTMLOption(bool p_embedCssStyle,
|
||||
bool p_completeHTML,
|
||||
bool p_embedImages,
|
||||
bool p_mimeHTML)
|
||||
bool p_mimeHTML,
|
||||
bool p_outlinePanel)
|
||||
: m_embedCssStyle(p_embedCssStyle),
|
||||
m_completeHTML(p_completeHTML),
|
||||
m_embedImages(p_embedImages),
|
||||
m_mimeHTML(p_mimeHTML)
|
||||
m_mimeHTML(p_mimeHTML),
|
||||
m_outlinePanel(p_outlinePanel)
|
||||
{
|
||||
}
|
||||
|
||||
@ -77,6 +80,7 @@ struct ExportHTMLOption
|
||||
bool m_completeHTML;
|
||||
bool m_embedImages;
|
||||
bool m_mimeHTML;
|
||||
bool m_outlinePanel;
|
||||
};
|
||||
|
||||
|
||||
@ -452,6 +456,8 @@ private:
|
||||
|
||||
QCheckBox *m_mimeHTMLCB;
|
||||
|
||||
QCheckBox *m_outlinePanelCB;
|
||||
|
||||
QCheckBox *m_subfolderCB;
|
||||
|
||||
QComboBox *m_customSrcFormatCB;
|
||||
|
36
src/resources/export/export_template.html
Normal file
36
src/resources/export/export_template.html
Normal file
@ -0,0 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<head>
|
||||
<style type="text/css">
|
||||
/* STYLE_GLOBAL_PLACE_HOLDER */
|
||||
</style>
|
||||
|
||||
<style type="text/css">
|
||||
/* STYLE_OUTLINE_PLACE_HOLDER */
|
||||
/* STYLE_PLACE_HOLDER */
|
||||
</style>
|
||||
|
||||
<!-- EXTRA_PLACE_HOLDER -->
|
||||
|
||||
<!-- HEAD_PLACE_HOLDER -->
|
||||
</head>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<div class="row flex-xl-nowrap">
|
||||
<div id="outline-panel" style="display:none;" class="d-none d-md-block d-xl-block col-md-3 col-xl-2 bd-toc">
|
||||
<div id="outline-content" class="section-nav"></div>
|
||||
</div>
|
||||
<div id="post-content" class="col-12 col-md-9 col-xl-10 py-md-3 pl-md-5 bd-content">
|
||||
<!-- BODY_PLACE_HOLDER -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="container-floating" style="display:none;" class="d-none d-md-block d-xl-block">
|
||||
<div id="floating-button" onclick="toggleMore()">
|
||||
<p id="floating-more" class="more">></p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
199
src/resources/export/outline.css
Normal file
199
src/resources/export/outline.css
Normal file
@ -0,0 +1,199 @@
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.container-fluid {
|
||||
width: 100%;
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.col, .col-1, .col-10, .col-11, .col-12, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-auto, .col-lg, .col-lg-1, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-auto, .col-md, .col-md-1, .col-md-10, .col-md-11, .col-md-12, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-auto, .col-sm, .col-sm-1, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-auto, .col-xl, .col-xl-1, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-auto {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 1px;
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.col-12 {
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 0 0 100%;
|
||||
flex: 0 0 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.col-md-3 {
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 0 0 25%;
|
||||
flex: 0 0 25%;
|
||||
max-width: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.col-md-9 {
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 0 0 75%;
|
||||
flex: 0 0 75%;
|
||||
max-width: 75%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.col-xl-2 {
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 0 0 16.666667%;
|
||||
flex: 0 0 16.666667%;
|
||||
max-width: 16.666667%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.col-xl-10 {
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 0 0 83.333333%;
|
||||
flex: 0 0 83.333333%;
|
||||
max-width: 83.333333%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.pt-md-3, .py-md-3 {
|
||||
padding-top: 1rem!important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.pb-md-3, .py-md-3 {
|
||||
padding-bottom: 1rem!important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.pl-md-5, .px-md-5 {
|
||||
padding-left: 3rem!important;
|
||||
}
|
||||
}
|
||||
|
||||
.d-none {
|
||||
display: none!important;
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.d-xl-block {
|
||||
display: block!important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.d-md-block {
|
||||
display: block!important;
|
||||
}
|
||||
}
|
||||
|
||||
.bd-content {
|
||||
-webkit-box-ordinal-group: 1;
|
||||
-ms-flex-order: 0;
|
||||
order: 0;
|
||||
}
|
||||
|
||||
.bd-toc {
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
top: 4rem;
|
||||
height: calc(100vh - 10rem);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.bd-toc {
|
||||
-webkit-box-ordinal-group: 2;
|
||||
-ms-flex-order: 1;
|
||||
order: 1;
|
||||
padding-top: 1.5rem;
|
||||
padding-bottom: 1.5rem;
|
||||
font-size: .875rem;
|
||||
}
|
||||
|
||||
.section-nav {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.section-nav ul {
|
||||
font-size: .875rem;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.section-nav li {
|
||||
font-size: .875rem;
|
||||
}
|
||||
|
||||
.section-nav a {
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-ms-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
margin-right: -15px;
|
||||
margin-left: -15px;
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.flex-xl-nowrap {
|
||||
flex-wrap: nowrap !important;
|
||||
}
|
||||
}
|
||||
|
||||
#floating-button {
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
border-radius: 50%;
|
||||
background: #00897B;
|
||||
position: fixed;
|
||||
top: .5rem;
|
||||
right: .5rem;
|
||||
cursor: pointer;
|
||||
box-shadow: 0px 2px 5px #666;
|
||||
}
|
||||
|
||||
#floating-button .more {
|
||||
color: #F5F5F5;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
display: block;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
line-height: 2.5rem;
|
||||
font-size: 2rem;
|
||||
font-family: 'monospace';
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.hide-none {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.col-expand {
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 0 0 100% !important;
|
||||
flex: 0 0 100% !important;
|
||||
max-width: 100% !important;
|
||||
padding-right: 3rem !important;
|
||||
}
|
||||
|
||||
.outline-bold {
|
||||
font-weight: bolder !important;
|
||||
}
|
228
src/resources/export/outline.js
Normal file
228
src/resources/export/outline.js
Normal file
@ -0,0 +1,228 @@
|
||||
var toc = [];
|
||||
|
||||
var setVisible = function(node, visible) {
|
||||
var cl = 'hide-none';
|
||||
if (visible) {
|
||||
node.classList.remove(cl);
|
||||
} else {
|
||||
node.classList.add(cl);
|
||||
}
|
||||
};
|
||||
|
||||
var isVisible = function(node) {
|
||||
var cl = 'hide-none';
|
||||
return !node.classList.contains(cl);
|
||||
};
|
||||
|
||||
var setPostContentExpanded = function(node, expanded) {
|
||||
var cl = 'col-expand';
|
||||
if (expanded) {
|
||||
node.classList.add(cl);
|
||||
} else {
|
||||
node.classList.remove(cl);
|
||||
}
|
||||
};
|
||||
|
||||
var setOutlinePanelVisible = function(visible) {
|
||||
var outlinePanel = document.getElementById('outline-panel');
|
||||
var postContent = document.getElementById('post-content');
|
||||
|
||||
setVisible(outlinePanel, visible);
|
||||
setPostContentExpanded(postContent, !visible);
|
||||
};
|
||||
|
||||
var isOutlinePanelVisible = function() {
|
||||
var outlinePanel = document.getElementById('outline-panel');
|
||||
return isVisible(outlinePanel);
|
||||
};
|
||||
|
||||
window.addEventListener('load', function() {
|
||||
var outlinePanel = document.getElementById('outline-panel');
|
||||
outlinePanel.style.display = 'initial';
|
||||
|
||||
var floatingContainer = document.getElementById('container-floating');
|
||||
floatingContainer.style.display = 'initial';
|
||||
|
||||
var outlineContent = document.getElementById('outline-content');
|
||||
var postContent = document.getElementById('post-content');
|
||||
|
||||
// Fetch the outline.
|
||||
var headers = postContent.querySelectorAll("h1, h2, h3, h4, h5, h6");
|
||||
toc = [];
|
||||
for (var i = 0; i < headers.length; ++i) {
|
||||
var header = headers[i];
|
||||
|
||||
toc.push({
|
||||
level: parseInt(header.tagName.substr(1)),
|
||||
anchor: header.id,
|
||||
title: header.textContent
|
||||
});
|
||||
}
|
||||
|
||||
if (toc.length == 0) {
|
||||
setOutlinePanelVisible(false);
|
||||
setVisible(floatingContainer, false);
|
||||
return;
|
||||
}
|
||||
|
||||
var baseLevel = baseLevelOfToc(toc);
|
||||
var tocTree = tocToTree(toPerfectToc(toc, baseLevel), baseLevel);
|
||||
|
||||
outlineContent.innerHTML = tocTree;
|
||||
setOutlinePanelVisible(true);
|
||||
setVisible(floatingContainer, true);
|
||||
});
|
||||
|
||||
// Return the topest level of @toc, starting from 1.
|
||||
var baseLevelOfToc = function(p_toc) {
|
||||
var level = -1;
|
||||
for (i in p_toc) {
|
||||
if (level == -1) {
|
||||
level = p_toc[i].level;
|
||||
} else if (level > p_toc[i].level) {
|
||||
level = p_toc[i].level;
|
||||
}
|
||||
}
|
||||
|
||||
if (level == -1) {
|
||||
level = 1;
|
||||
}
|
||||
|
||||
return level;
|
||||
};
|
||||
|
||||
// Handle wrong title levels, such as '#' followed by '###'
|
||||
var toPerfectToc = function(p_toc, p_baseLevel) {
|
||||
var i;
|
||||
var curLevel = p_baseLevel - 1;
|
||||
var perfToc = [];
|
||||
for (i in p_toc) {
|
||||
var item = p_toc[i];
|
||||
|
||||
// Insert empty header.
|
||||
while (item.level > curLevel + 1) {
|
||||
curLevel += 1;
|
||||
var tmp = { level: curLevel,
|
||||
anchor: '',
|
||||
title: '[EMPTY]'
|
||||
};
|
||||
perfToc.push(tmp);
|
||||
}
|
||||
|
||||
perfToc.push(item);
|
||||
curLevel = item.level;
|
||||
}
|
||||
|
||||
return perfToc;
|
||||
};
|
||||
|
||||
var itemToHtml = function(item) {
|
||||
return '<a href="#' + item.anchor + '" data="' + item.anchor + '">' + item.title + '</a>';
|
||||
};
|
||||
|
||||
// Turn a perfect toc to a tree using <ul>
|
||||
var tocToTree = function(p_toc, p_baseLevel) {
|
||||
var i;
|
||||
var front = '<li>';
|
||||
var ending = ['</li>'];
|
||||
var curLevel = p_baseLevel;
|
||||
for (i in p_toc) {
|
||||
var item = p_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 toggleMore = function() {
|
||||
if (toc.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var p = document.getElementById('floating-more');
|
||||
if (isOutlinePanelVisible()) {
|
||||
p.textContent = '<';
|
||||
setOutlinePanelVisible(false);
|
||||
} else {
|
||||
p.textContent = '>';
|
||||
setOutlinePanelVisible(true);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('scroll', function() {
|
||||
if (toc.length == 0 || !isOutlinePanelVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var postContent = document.getElementById('post-content');
|
||||
var scrollTop = document.documentElement.scrollTop
|
||||
|| document.body.scrollTop
|
||||
|| window.pageYOffset;
|
||||
var eles = postContent.querySelectorAll("h1, h2, h3, h4, h5, h6");
|
||||
|
||||
if (eles.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var idx = -1;
|
||||
var biaScrollTop = scrollTop + 50;
|
||||
for (var i = 0; i < eles.length; ++i) {
|
||||
if (biaScrollTop >= eles[i].offsetTop) {
|
||||
idx = i;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var header = '';
|
||||
if (idx != -1) {
|
||||
header = eles[idx].id;
|
||||
}
|
||||
|
||||
highlightItemOnlyInOutline(header);
|
||||
});
|
||||
|
||||
var highlightItemOnlyInOutline = function(id) {
|
||||
var cl = 'outline-bold';
|
||||
var outlineContent = document.getElementById('outline-content');
|
||||
var eles = outlineContent.querySelectorAll("a");
|
||||
var target = null;
|
||||
for (var i = 0; i < eles.length; ++i) {
|
||||
var ele = eles[i];
|
||||
if (ele.getAttribute('data') == id) {
|
||||
target = ele;
|
||||
ele.classList.add(cl);
|
||||
} else {
|
||||
ele.classList.remove(cl);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: scroll target into view within the outline panel scroll area.
|
||||
};
|
@ -1,20 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<head>
|
||||
<style type="text/css">
|
||||
/* STYLE_GLOBAL_PLACE_HOLDER */
|
||||
</style>
|
||||
|
||||
<style type="text/css">
|
||||
/* STYLE_PLACE_HOLDER */
|
||||
</style>
|
||||
|
||||
<!-- EXTRA_PLACE_HOLDER -->
|
||||
|
||||
<!-- HEAD_PLACE_HOLDER -->
|
||||
</head>
|
||||
<body>
|
||||
<!-- BODY_PLACE_HOLDER -->
|
||||
</body>
|
||||
</html>
|
@ -1,56 +0,0 @@
|
||||
.post-content {
|
||||
width: 960px;
|
||||
min-height: 200px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
}
|
||||
.toc {
|
||||
overflow: hidden;
|
||||
color: #555;
|
||||
border: 1px solid #d2d2d2;
|
||||
border-radius: 3px;
|
||||
min-width: 150px;
|
||||
opacity: 1;
|
||||
font-size: inherit;
|
||||
z-index: 19941112;
|
||||
}
|
||||
.toc {
|
||||
display: none;
|
||||
margin-bottom: 2em;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
.toc a {
|
||||
color: #333;
|
||||
}
|
||||
.toc a:hover{
|
||||
color: #555;
|
||||
background-color: #fff;
|
||||
}
|
||||
.toc .catalog-title {
|
||||
cursor: move;
|
||||
padding-left: 12px;
|
||||
width: 100%;
|
||||
height: 35px;
|
||||
line-height: 36px;
|
||||
border-bottom: 1px solid #eee;
|
||||
font-size: 14px;
|
||||
color: #555;
|
||||
overflow: hidden;
|
||||
}
|
||||
.toc .catalog-close {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
top: 6px;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
.fixed {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 250px;
|
||||
width: auto;
|
||||
}
|
||||
.blodtoc {
|
||||
font-weight: bold;
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<head>
|
||||
<style type="text/css">
|
||||
/* STYLE_GLOBAL_PLACE_HOLDER */
|
||||
</style>
|
||||
|
||||
<style type="text/css">
|
||||
/* STYLE_PLACE_HOLDER */
|
||||
</style>
|
||||
|
||||
<!-- EXTRA_PLACE_HOLDER -->
|
||||
|
||||
<!-- HEAD_PLACE_HOLDER -->
|
||||
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="toc fixed">
|
||||
<div class="catalog-title"><span>目录</span></div>
|
||||
<a class="catalog-close"><span>X</span></a>
|
||||
</div>
|
||||
<div class="post-content">
|
||||
<!-- BODY_PLACE_HOLDER -->
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,100 +0,0 @@
|
||||
/**
|
||||
* Convert item of header array to html in li
|
||||
* @param item An element of header array
|
||||
*/
|
||||
var itemToHtml = function(item) {
|
||||
return '<a href="#' + item.id + '" id="' + 'menu-'+ item.id + '" >' + item.innerText + '</a>';
|
||||
};
|
||||
/**
|
||||
* Generate tree from header array
|
||||
* @param toc_list An array containing header elements
|
||||
* @param p_baseLevel The base level number of the toc you want to display
|
||||
*/
|
||||
var tocToTree = function(toc_list, p_baseLevel) {
|
||||
let i;
|
||||
let p_toc = [];
|
||||
for (i in toc_list) {
|
||||
let itemLevel = parseInt(toc_list[i].tagName.substring(1));
|
||||
if (itemLevel >= p_baseLevel) {
|
||||
p_toc.push(toc_list[i]);
|
||||
}
|
||||
}
|
||||
let front = '<li>';
|
||||
let ending = ['</li>'];
|
||||
let curLevel = p_baseLevel;
|
||||
let toclen = p_toc.length;
|
||||
for (i in p_toc) {
|
||||
let item = p_toc[i];
|
||||
console.log(item.tagName);
|
||||
let itemLevel = parseInt(item.tagName.substring(1));
|
||||
if (item.tagName == curLevel) {
|
||||
front += '</li>';
|
||||
front += '<li>';
|
||||
front += itemToHtml(item);
|
||||
} else if (itemLevel > curLevel) {
|
||||
// assert(item.level - curLevel == 1)
|
||||
front += '<ul>';
|
||||
ending.push('</ul>');
|
||||
front += '<li>';
|
||||
front += itemToHtml(item);
|
||||
ending.push('</li>');
|
||||
curLevel = itemLevel;
|
||||
} else {
|
||||
while (itemLevel < curLevel) {
|
||||
let 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;
|
||||
};
|
||||
|
||||
let headerObjList = $(":header").toArray();
|
||||
$('.toc').append(tocToTree( headerObjList, 2 ));
|
||||
|
||||
|
||||
// scroll to display side outline
|
||||
$(window).bind('scroll', function(){
|
||||
if ($(document).scrollTop() >= 100) {
|
||||
$('.toc').css("display", "block");
|
||||
highToc();
|
||||
} else {
|
||||
$('.toc').css("display", "none");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// make the corresponding outline text blod
|
||||
let highToc = function(){
|
||||
$(":header").each(function(index, element) {
|
||||
var wst = $(window).scrollTop();
|
||||
let tag_id = $(this).attr("id");
|
||||
if($("#"+tag_id).offset().top <= wst){
|
||||
$('.toc a').removeClass("blodtoc");
|
||||
$('#menu-'+tag_id).addClass("blodtoc");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// click to make outline text blod
|
||||
$('.toc a').click(function(){
|
||||
$('.toc a').removeClass("blodtoc");
|
||||
$(this).addClass("blodtoc");
|
||||
});
|
||||
|
||||
// button to close the outline
|
||||
$('.toc .catalog-close').click(function(){
|
||||
$('.toc').hide();
|
||||
$(window).unbind('scroll');
|
||||
});
|
@ -868,7 +868,9 @@ QString VUtils::generateHtmlTemplate(const QString &p_template,
|
||||
return htmlTemplate;
|
||||
}
|
||||
|
||||
QString VUtils::generateExportHtmlTemplate(const QString &p_renderBg, bool p_includeMathJax)
|
||||
QString VUtils::generateExportHtmlTemplate(const QString &p_renderBg,
|
||||
bool p_includeMathJax,
|
||||
bool p_outlinePanel)
|
||||
{
|
||||
QString templ = VNote::generateExportHtmlTemplate(g_config->getRenderBackgroundColor(p_renderBg));
|
||||
QString extra;
|
||||
@ -902,6 +904,18 @@ with 2em, if there are Chinese characters in it, the font will be a mess.
|
||||
extra += "<script type=\"text/javascript\" async src=\"" + mj + "\"></script>\n";
|
||||
}
|
||||
|
||||
if (p_outlinePanel) {
|
||||
const QString outlineCss(":/resources/export/outline.css");
|
||||
QString css = VUtils::readFileFromDisk(outlineCss);
|
||||
if (!css.isEmpty()) {
|
||||
templ.replace(HtmlHolder::c_outlineStyleHolder, css);
|
||||
}
|
||||
|
||||
const QString outlineJs(":/resources/export/outline.js");
|
||||
QString js = VUtils::readFileFromDisk(outlineJs);
|
||||
extra += QString("<script type=\"text/javascript\">\n%1\n</script>\n").arg(js);
|
||||
}
|
||||
|
||||
if (!extra.isEmpty()) {
|
||||
templ.replace(HtmlHolder::c_extraHolder, extra);
|
||||
}
|
||||
|
@ -195,7 +195,9 @@ public:
|
||||
bool p_addToc = false);
|
||||
|
||||
// @p_renderBg is the background name.
|
||||
static QString generateExportHtmlTemplate(const QString &p_renderBg, bool p_includeMathJax);
|
||||
static QString generateExportHtmlTemplate(const QString &p_renderBg,
|
||||
bool p_includeMathJax,
|
||||
bool p_outlinePanel);
|
||||
|
||||
static QString generateSimpleHtmlTemplate(const QString &p_body);
|
||||
|
||||
|
@ -48,6 +48,7 @@ namespace HtmlHolder
|
||||
static const QString c_bodyHolder = "<!-- BODY_PLACE_HOLDER -->";
|
||||
static const QString c_headHolder = "<!-- HEAD_PLACE_HOLDER -->";
|
||||
static const QString c_styleHolder = "/* STYLE_PLACE_HOLDER */";
|
||||
static const QString c_outlineStyleHolder = "/* STYLE_OUTLINE_PLACE_HOLDER */";
|
||||
}
|
||||
|
||||
// Directory Config file items.
|
||||
|
@ -55,8 +55,13 @@ void VExporter::prepareExport(const ExportOption &p_opt)
|
||||
isPdf && p_opt.m_pdfOpt.m_wkhtmltopdf,
|
||||
extraToc);
|
||||
|
||||
bool outline = p_opt.m_htmlOpt.m_outlinePanel
|
||||
&& !isPdf
|
||||
&& (p_opt.m_format == ExportFormat::HTML
|
||||
|| p_opt.m_format == ExportFormat::Custom);
|
||||
m_exportHtmlTemplate = VUtils::generateExportHtmlTemplate(p_opt.m_renderBg,
|
||||
isPdf && p_opt.m_pdfOpt.m_wkhtmltopdf);
|
||||
isPdf && p_opt.m_pdfOpt.m_wkhtmltopdf,
|
||||
outline);
|
||||
|
||||
m_pageLayout = *(p_opt.m_pdfOpt.m_layout);
|
||||
|
||||
|
@ -152,7 +152,7 @@ QString VNote::generateHtmlTemplate(const QString &p_renderBg,
|
||||
|
||||
QString VNote::generateExportHtmlTemplate(const QString &p_renderBg)
|
||||
{
|
||||
const QString c_exportTemplatePath(":/resources/export_template.html");
|
||||
const QString c_exportTemplatePath(":/resources/export/export_template.html");
|
||||
|
||||
QString cssStyle;
|
||||
if (!p_renderBg.isEmpty()) {
|
||||
|
@ -177,7 +177,6 @@
|
||||
<file>resources/icons/delete_cart_item.svg</file>
|
||||
<file>resources/icons/fullscreen.svg</file>
|
||||
<file>resources/icons/menubar.svg</file>
|
||||
<file>resources/export_template.html</file>
|
||||
<file>resources/themes/v_pure/v_pure_mermaid.css</file>
|
||||
<file>resources/themes/v_moonlight/v_moonlight_mermaid.css</file>
|
||||
<file>resources/themes/v_moonlight/arrow_dropdown_disabled.svg</file>
|
||||
@ -272,5 +271,8 @@
|
||||
<file>resources/common.css</file>
|
||||
<file>resources/icons/quick_access.svg</file>
|
||||
<file>resources/common.js</file>
|
||||
<file>resources/export/export_template.html</file>
|
||||
<file>resources/export/outline.css</file>
|
||||
<file>resources/export/outline.js</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
Loading…
x
Reference in New Issue
Block a user