mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
export: support HTML format
This commit is contained in:
parent
60635fe5e7
commit
1fe7567d79
@ -289,7 +289,8 @@ void VExportDialog::startExport()
|
|||||||
m_consoleEdit->clear();
|
m_consoleEdit->clear();
|
||||||
appendLogLine(tr("Export to %1.").arg(outputFolder));
|
appendLogLine(tr("Export to %1.").arg(outputFolder));
|
||||||
|
|
||||||
if (opt.m_format == ExportFormat::PDF) {
|
if (opt.m_format == ExportFormat::PDF
|
||||||
|
|| opt.m_format == ExportFormat::HTML) {
|
||||||
m_exporter->prepareExport(opt);
|
m_exporter->prepareExport(opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,6 +407,10 @@ int VExportDialog::doExport(VFile *p_file,
|
|||||||
ret = doExportPDF(p_file, p_opt, p_outputFolder, p_errMsg);
|
ret = doExportPDF(p_file, p_opt, p_outputFolder, p_errMsg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case (int)ExportFormat::HTML:
|
||||||
|
ret = doExportHTML(p_file, p_opt, p_outputFolder, p_errMsg);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -628,6 +633,40 @@ int VExportDialog::doExportPDF(VFile *p_file,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int VExportDialog::doExportHTML(VFile *p_file,
|
||||||
|
const ExportOption &p_opt,
|
||||||
|
const QString &p_outputFolder,
|
||||||
|
QString *p_errMsg)
|
||||||
|
{
|
||||||
|
Q_UNUSED(p_opt);
|
||||||
|
|
||||||
|
QString srcFilePath(p_file->fetchPath());
|
||||||
|
|
||||||
|
if (p_file->getDocType() != DocType::Markdown) {
|
||||||
|
LOGERR(tr("Skip exporting non-Markdown file %1 as HTML.").arg(srcFilePath));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!VUtils::makePath(p_outputFolder)) {
|
||||||
|
LOGERR(tr("Fail to create directory %1.").arg(p_outputFolder));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get output file.
|
||||||
|
QString suffix = ".html";
|
||||||
|
QString name = VUtils::getFileNameWithSequence(p_outputFolder,
|
||||||
|
QFileInfo(p_file->getName()).completeBaseName() + suffix);
|
||||||
|
QString outputPath = QDir(p_outputFolder).filePath(name);
|
||||||
|
|
||||||
|
if (m_exporter->exportHTML(p_file, p_opt, outputPath, p_errMsg)) {
|
||||||
|
appendLogLine(tr("Note %1 exported to %2.").arg(srcFilePath).arg(outputPath));
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
appendLogLine(tr("Fail to export note %1.").arg(srcFilePath));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool VExportDialog::checkUserAction()
|
bool VExportDialog::checkUserAction()
|
||||||
{
|
{
|
||||||
if (m_askedToStop) {
|
if (m_askedToStop) {
|
||||||
|
@ -133,6 +133,11 @@ private:
|
|||||||
const QString &p_outputFolder,
|
const QString &p_outputFolder,
|
||||||
QString *p_errMsg = NULL);
|
QString *p_errMsg = NULL);
|
||||||
|
|
||||||
|
int doExportHTML(VFile *p_file,
|
||||||
|
const ExportOption &p_opt,
|
||||||
|
const QString &p_outputFolder,
|
||||||
|
QString *p_errMsg = NULL);
|
||||||
|
|
||||||
// Return false if we could not continue.
|
// Return false if we could not continue.
|
||||||
bool checkUserAction();
|
bool checkUserAction();
|
||||||
|
|
||||||
|
14
src/resources/export_template.html
Normal file
14
src/resources/export_template.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<head>
|
||||||
|
<style type="text/css">
|
||||||
|
/* BACKGROUND_PLACE_HOLDER */
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- HEAD_PLACE_HOLDER -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- BODY_PLACE_HOLDER -->
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -127,7 +127,7 @@ var updateText = function(text) {
|
|||||||
var highlightText = function(text, id, timeStamp) {
|
var highlightText = function(text, id, timeStamp) {
|
||||||
var html = mdit.render(text);
|
var html = mdit.render(text);
|
||||||
content.highlightTextCB(html, id, timeStamp);
|
content.highlightTextCB(html, id, timeStamp);
|
||||||
}
|
};
|
||||||
|
|
||||||
var textToHtml = function(text) {
|
var textToHtml = function(text) {
|
||||||
var html = mdit.render(text);
|
var html = mdit.render(text);
|
||||||
@ -139,4 +139,4 @@ var textToHtml = function(text) {
|
|||||||
container.innerHTML = "";
|
container.innerHTML = "";
|
||||||
|
|
||||||
content.textToHtmlCB(text, html);
|
content.textToHtmlCB(text, html);
|
||||||
}
|
};
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<head>
|
<head>
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
<!-- BACKGROUND_PLACE_HOLDER -->
|
/* BACKGROUND_PLACE_HOLDER */
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
|
@ -40,6 +40,26 @@ if (typeof VEnableImageCaption == 'undefined') {
|
|||||||
VEnableImageCaption = false;
|
VEnableImageCaption = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var headContent = function() {
|
||||||
|
var styles = "<style type=\"text/css\">\n";
|
||||||
|
|
||||||
|
for (var i = 0; i < document.styleSheets.length; ++i) {
|
||||||
|
var styleSheet = document.styleSheets[i];
|
||||||
|
if (styleSheet.cssRules) {
|
||||||
|
for (var j = 0; j < styleSheet.cssRules.length; ++j) {
|
||||||
|
styles = styles + styleSheet.cssRules[j].cssText + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var styles = styles + "</style>";
|
||||||
|
return styles;
|
||||||
|
};
|
||||||
|
|
||||||
|
var htmlContent = function() {
|
||||||
|
content.htmlContentCB(headContent(), placeholder.innerHTML);
|
||||||
|
};
|
||||||
|
|
||||||
new QWebChannel(qt.webChannelTransport,
|
new QWebChannel(qt.webChannelTransport,
|
||||||
function(channel) {
|
function(channel) {
|
||||||
content = channel.objects.content;
|
content = channel.objects.content;
|
||||||
@ -62,6 +82,10 @@ new QWebChannel(qt.webChannelTransport,
|
|||||||
content.requestTextToHtml.connect(textToHtml);
|
content.requestTextToHtml.connect(textToHtml);
|
||||||
content.noticeReadyToTextToHtml();
|
content.noticeReadyToTextToHtml();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof htmlContent == "function") {
|
||||||
|
content.requestHtmlContent.connect(htmlContent);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var VHighlightedAnchorClass = 'highlighted-anchor';
|
var VHighlightedAnchorClass = 'highlighted-anchor';
|
||||||
@ -447,7 +471,7 @@ var renderMermaidOne = function(code) {
|
|||||||
mermaidIdx++;
|
mermaidIdx++;
|
||||||
try {
|
try {
|
||||||
// Do not increment mermaidIdx here.
|
// Do not increment mermaidIdx here.
|
||||||
var graph = mermaidAPI.render('mermaid-diagram-' + mermaidIdx, code.innerText, function(){});
|
var graph = mermaidAPI.render('mermaid-diagram-' + mermaidIdx, code.textContent, function(){});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
content.setLog("err: " + err);
|
content.setLog("err: " + err);
|
||||||
return false;
|
return false;
|
||||||
@ -493,7 +517,7 @@ var renderFlowchartOne = function(code) {
|
|||||||
// Flowchart code block.
|
// Flowchart code block.
|
||||||
flowchartIdx++;
|
flowchartIdx++;
|
||||||
try {
|
try {
|
||||||
var graph = flowchart.parse(code.innerText);
|
var graph = flowchart.parse(code.textContent);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
content.setLog("err: " + err);
|
content.setLog("err: " + err);
|
||||||
return false;
|
return false;
|
||||||
@ -525,7 +549,7 @@ var renderFlowchartOne = function(code) {
|
|||||||
|
|
||||||
var isImageBlock = function(img) {
|
var isImageBlock = function(img) {
|
||||||
var pn = img.parentNode;
|
var pn = img.parentNode;
|
||||||
return (pn.children.length == 1) && (pn.innerText == '');
|
return (pn.children.length == 1) && (pn.textContent == '');
|
||||||
};
|
};
|
||||||
|
|
||||||
var isImageWithBr = function(img) {
|
var isImageWithBr = function(img) {
|
||||||
@ -617,7 +641,7 @@ var insertImageCaption = function() {
|
|||||||
// Add caption.
|
// Add caption.
|
||||||
var captionDiv = document.createElement('div');
|
var captionDiv = document.createElement('div');
|
||||||
captionDiv.classList.add(VImageCaptionClass);
|
captionDiv.classList.add(VImageCaptionClass);
|
||||||
captionDiv.innerText = img.alt;
|
captionDiv.textContent = img.alt;
|
||||||
img.insertAdjacentElement('afterend', captionDiv);
|
img.insertAdjacentElement('afterend', captionDiv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,6 @@
|
|||||||
<link rel="stylesheet" type="text/css" href="qrc:/resources/typewriter.css">
|
<link rel="stylesheet" type="text/css" href="qrc:/resources/typewriter.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- BODY_PLACE_HOLDER -->
|
<!-- BODY_PLACE_HOLDER -->
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -203,7 +203,7 @@ enable_wildcard_in_simple_search=true
|
|||||||
|
|
||||||
[web]
|
[web]
|
||||||
; Location and configuration for Mathjax
|
; Location and configuration for Mathjax
|
||||||
mathjax_javascript=https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_CHTML
|
mathjax_javascript=https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_HTMLorMML
|
||||||
|
|
||||||
; Styles to be removed when copied
|
; Styles to be removed when copied
|
||||||
; style1,style2,style3
|
; style1,style2,style3
|
||||||
|
@ -690,6 +690,11 @@ QString VUtils::generateHtmlTemplate(const QString &p_template,
|
|||||||
return htmlTemplate;
|
return htmlTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString VUtils::generateExportHtmlTemplate(const QString &p_renderBg)
|
||||||
|
{
|
||||||
|
return VNote::generateExportHtmlTemplate(g_config->getRenderBackgroundColor(p_renderBg));
|
||||||
|
}
|
||||||
|
|
||||||
QString VUtils::getFileNameWithSequence(const QString &p_directory,
|
QString VUtils::getFileNameWithSequence(const QString &p_directory,
|
||||||
const QString &p_baseFileName,
|
const QString &p_baseFileName,
|
||||||
bool p_completeBaseName)
|
bool p_completeBaseName)
|
||||||
|
@ -174,6 +174,9 @@ public:
|
|||||||
const QString &p_renderCodeBlockStyle,
|
const QString &p_renderCodeBlockStyle,
|
||||||
bool p_isPDF);
|
bool p_isPDF);
|
||||||
|
|
||||||
|
// @p_renderBg is the background name.
|
||||||
|
static QString generateExportHtmlTemplate(const QString &p_renderBg);
|
||||||
|
|
||||||
static QString generateSimpleHtmlTemplate(const QString &p_body);
|
static QString generateSimpleHtmlTemplate(const QString &p_body);
|
||||||
|
|
||||||
// Get an available file name in @p_directory with base @p_baseFileName.
|
// Get an available file name in @p_directory with base @p_baseFileName.
|
||||||
|
@ -37,6 +37,7 @@ namespace HtmlHolder
|
|||||||
static const QString c_JSHolder = "JS_PLACE_HOLDER";
|
static const QString c_JSHolder = "JS_PLACE_HOLDER";
|
||||||
static const QString c_extraHolder = "<!-- EXTRA_PLACE_HOLDER -->";
|
static const QString c_extraHolder = "<!-- EXTRA_PLACE_HOLDER -->";
|
||||||
static const QString c_bodyHolder = "<!-- BODY_PLACE_HOLDER -->";
|
static const QString c_bodyHolder = "<!-- BODY_PLACE_HOLDER -->";
|
||||||
|
static const QString c_headHolder = "<!-- HEAD_PLACE_HOLDER -->";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Directory Config file items.
|
// Directory Config file items.
|
||||||
|
@ -82,6 +82,11 @@ void VDocument::textToHtmlAsync(const QString &p_text)
|
|||||||
emit requestTextToHtml(p_text);
|
emit requestTextToHtml(p_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VDocument::getHtmlContentAsync()
|
||||||
|
{
|
||||||
|
emit requestHtmlContent();
|
||||||
|
}
|
||||||
|
|
||||||
void VDocument::textToHtmlCB(const QString &p_text, const QString &p_html)
|
void VDocument::textToHtmlCB(const QString &p_text, const QString &p_html)
|
||||||
{
|
{
|
||||||
emit textToHtmlFinished(p_text, p_html);
|
emit textToHtmlFinished(p_text, p_html);
|
||||||
@ -108,3 +113,8 @@ void VDocument::finishLogics()
|
|||||||
qDebug() << "Web side finished logics";
|
qDebug() << "Web side finished logics";
|
||||||
emit logicsFinished();
|
emit logicsFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VDocument::htmlContentCB(const QString &p_head, const QString &p_body)
|
||||||
|
{
|
||||||
|
emit htmlContentFinished(p_head, p_body);
|
||||||
|
}
|
||||||
|
@ -38,6 +38,9 @@ public:
|
|||||||
|
|
||||||
bool isReadyToTextToHtml() const;
|
bool isReadyToTextToHtml() const;
|
||||||
|
|
||||||
|
// Request to get the HTML content.
|
||||||
|
void getHtmlContentAsync();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
// Will be called in the HTML side
|
// Will be called in the HTML side
|
||||||
|
|
||||||
@ -67,6 +70,8 @@ public slots:
|
|||||||
// But the page may not finish loading, such as images.
|
// But the page may not finish loading, such as images.
|
||||||
void finishLogics();
|
void finishLogics();
|
||||||
|
|
||||||
|
void htmlContentCB(const QString &p_head, const QString &p_body);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void textChanged(const QString &text);
|
void textChanged(const QString &text);
|
||||||
|
|
||||||
@ -95,6 +100,11 @@ signals:
|
|||||||
|
|
||||||
void textToHtmlFinished(const QString &p_text, const QString &p_html);
|
void textToHtmlFinished(const QString &p_text, const QString &p_html);
|
||||||
|
|
||||||
|
void requestHtmlContent();
|
||||||
|
|
||||||
|
void htmlContentFinished(const QString &p_headContent,
|
||||||
|
const QString &p_bodyContent);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_toc;
|
QString m_toc;
|
||||||
QString m_header;
|
QString m_header;
|
||||||
|
@ -29,6 +29,9 @@ void VExporter::prepareExport(const ExportOption &p_opt)
|
|||||||
p_opt.m_renderStyle,
|
p_opt.m_renderStyle,
|
||||||
p_opt.m_renderCodeBlockStyle,
|
p_opt.m_renderCodeBlockStyle,
|
||||||
p_opt.m_format == ExportFormat::PDF);
|
p_opt.m_format == ExportFormat::PDF);
|
||||||
|
|
||||||
|
m_exportHtmlTemplate = VUtils::generateExportHtmlTemplate(p_opt.m_renderBg);
|
||||||
|
|
||||||
m_pageLayout = *(p_opt.m_layout);
|
m_pageLayout = *(p_opt.m_layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,70 +40,15 @@ bool VExporter::exportPDF(VFile *p_file,
|
|||||||
const QString &p_outputFile,
|
const QString &p_outputFile,
|
||||||
QString *p_errMsg)
|
QString *p_errMsg)
|
||||||
{
|
{
|
||||||
Q_UNUSED(p_errMsg);
|
return exportViaWebView(p_file, p_opt, p_outputFile, p_errMsg);
|
||||||
|
}
|
||||||
|
|
||||||
bool ret = false;
|
bool VExporter::exportHTML(VFile *p_file,
|
||||||
|
const ExportOption &p_opt,
|
||||||
bool isOpened = p_file->isOpened();
|
const QString &p_outputFile,
|
||||||
if (!isOpened && !p_file->open()) {
|
QString *p_errMsg)
|
||||||
goto exit;
|
{
|
||||||
}
|
return exportViaWebView(p_file, p_opt, p_outputFile, p_errMsg);
|
||||||
|
|
||||||
Q_ASSERT(m_state == ExportState::Idle);
|
|
||||||
m_state = ExportState::Busy;
|
|
||||||
|
|
||||||
clearNoteState();
|
|
||||||
|
|
||||||
initWebViewer(p_file, p_opt);
|
|
||||||
|
|
||||||
while (!isNoteStateReady()) {
|
|
||||||
VUtils::sleepWait(100);
|
|
||||||
|
|
||||||
if (m_state == ExportState::Cancelled) {
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isNoteStateFailed()) {
|
|
||||||
m_state = ExportState::Failed;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait to ensure Web side is really ready.
|
|
||||||
VUtils::sleepWait(200);
|
|
||||||
|
|
||||||
if (m_state == ExportState::Cancelled) {
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
bool exportRet = exportToPDF(m_webViewer,
|
|
||||||
p_outputFile,
|
|
||||||
m_pageLayout);
|
|
||||||
|
|
||||||
clearNoteState();
|
|
||||||
|
|
||||||
if (!isOpened) {
|
|
||||||
p_file->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exportRet) {
|
|
||||||
m_state = ExportState::Successful;
|
|
||||||
} else {
|
|
||||||
m_state = ExportState::Failed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
|
||||||
clearWebViewer();
|
|
||||||
|
|
||||||
if (m_state == ExportState::Successful) {
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_state = ExportState::Idle;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VExporter::initWebViewer(VFile *p_file, const ExportOption &p_opt)
|
void VExporter::initWebViewer(VFile *p_file, const ExportOption &p_opt)
|
||||||
@ -116,12 +64,12 @@ void VExporter::initWebViewer(VFile *p_file, const ExportOption &p_opt)
|
|||||||
connect(page, &VPreviewPage::loadFinished,
|
connect(page, &VPreviewPage::loadFinished,
|
||||||
this, &VExporter::handleLoadFinished);
|
this, &VExporter::handleLoadFinished);
|
||||||
|
|
||||||
VDocument *document = new VDocument(p_file, m_webViewer);
|
m_webDocument = new VDocument(p_file, m_webViewer);
|
||||||
connect(document, &VDocument::logicsFinished,
|
connect(m_webDocument, &VDocument::logicsFinished,
|
||||||
this, &VExporter::handleLogicsFinished);
|
this, &VExporter::handleLogicsFinished);
|
||||||
|
|
||||||
QWebChannel *channel = new QWebChannel(m_webViewer);
|
QWebChannel *channel = new QWebChannel(m_webViewer);
|
||||||
channel->registerObject(QStringLiteral("content"), document);
|
channel->registerObject(QStringLiteral("content"), m_webDocument);
|
||||||
page->setWebChannel(channel);
|
page->setWebChannel(channel);
|
||||||
|
|
||||||
// Need to generate HTML using Hoedown.
|
// Need to generate HTML using Hoedown.
|
||||||
@ -131,7 +79,7 @@ void VExporter::initWebViewer(VFile *p_file, const ExportOption &p_opt)
|
|||||||
QString html = mdConverter.generateHtml(p_file->getContent(),
|
QString html = mdConverter.generateHtml(p_file->getContent(),
|
||||||
g_config->getMarkdownExtensions(),
|
g_config->getMarkdownExtensions(),
|
||||||
toc);
|
toc);
|
||||||
document->setHtml(html);
|
m_webDocument->setHtml(html);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_webViewer->setHtml(m_htmlTemplate, p_file->getBaseUrl());
|
m_webViewer->setHtml(m_htmlTemplate, p_file->getBaseUrl());
|
||||||
@ -155,10 +103,10 @@ void VExporter::handleLoadFinished(bool p_ok)
|
|||||||
|
|
||||||
void VExporter::clearWebViewer()
|
void VExporter::clearWebViewer()
|
||||||
{
|
{
|
||||||
if (m_webViewer) {
|
// m_webDocument will be freeed by QObject.
|
||||||
delete m_webViewer;
|
delete m_webViewer;
|
||||||
m_webViewer = NULL;
|
m_webViewer = NULL;
|
||||||
}
|
m_webDocument = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VExporter::exportToPDF(VWebView *p_webViewer,
|
bool VExporter::exportToPDF(VWebView *p_webViewer,
|
||||||
@ -198,3 +146,135 @@ bool VExporter::exportToPDF(VWebView *p_webViewer,
|
|||||||
return pdfPrinted == 1;
|
return pdfPrinted == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VExporter::exportViaWebView(VFile *p_file,
|
||||||
|
const ExportOption &p_opt,
|
||||||
|
const QString &p_outputFile,
|
||||||
|
QString *p_errMsg)
|
||||||
|
{
|
||||||
|
Q_UNUSED(p_errMsg);
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
bool isOpened = p_file->isOpened();
|
||||||
|
if (!isOpened && !p_file->open()) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ASSERT(m_state == ExportState::Idle);
|
||||||
|
m_state = ExportState::Busy;
|
||||||
|
|
||||||
|
clearNoteState();
|
||||||
|
|
||||||
|
initWebViewer(p_file, p_opt);
|
||||||
|
|
||||||
|
while (!isNoteStateReady()) {
|
||||||
|
VUtils::sleepWait(100);
|
||||||
|
|
||||||
|
if (m_state == ExportState::Cancelled) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNoteStateFailed()) {
|
||||||
|
m_state = ExportState::Failed;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait to ensure Web side is really ready.
|
||||||
|
VUtils::sleepWait(200);
|
||||||
|
|
||||||
|
if (m_state == ExportState::Cancelled) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
bool exportRet = false;
|
||||||
|
switch (p_opt.m_format) {
|
||||||
|
case ExportFormat::PDF:
|
||||||
|
exportRet = exportToPDF(m_webViewer,
|
||||||
|
p_outputFile,
|
||||||
|
m_pageLayout);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ExportFormat::HTML:
|
||||||
|
exportRet = exportToHTML(m_webViewer,
|
||||||
|
m_webDocument,
|
||||||
|
p_outputFile);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearNoteState();
|
||||||
|
|
||||||
|
if (!isOpened) {
|
||||||
|
p_file->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exportRet) {
|
||||||
|
m_state = ExportState::Successful;
|
||||||
|
} else {
|
||||||
|
m_state = ExportState::Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
clearWebViewer();
|
||||||
|
|
||||||
|
if (m_state == ExportState::Successful) {
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_state = ExportState::Idle;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VExporter::exportToHTML(VWebView *p_webViewer,
|
||||||
|
VDocument *p_webDocument,
|
||||||
|
const QString &p_filePath)
|
||||||
|
{
|
||||||
|
Q_UNUSED(p_webViewer);
|
||||||
|
int htmlExported = 0;
|
||||||
|
|
||||||
|
connect(p_webDocument, &VDocument::htmlContentFinished,
|
||||||
|
this, [&, this](const QString &p_headContent, const QString &p_bodyContent) {
|
||||||
|
if (p_bodyContent.isEmpty() || this->m_state == ExportState::Cancelled) {
|
||||||
|
htmlExported = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ASSERT(!p_filePath.isEmpty());
|
||||||
|
|
||||||
|
QFile file(p_filePath);
|
||||||
|
|
||||||
|
if (!file.open(QFile::WriteOnly)) {
|
||||||
|
htmlExported = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString html(m_exportHtmlTemplate);
|
||||||
|
html.replace(HtmlHolder::c_headHolder, p_headContent);
|
||||||
|
html.replace(HtmlHolder::c_bodyHolder, p_bodyContent);
|
||||||
|
|
||||||
|
file.write(html.toUtf8());
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
htmlExported = 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
p_webDocument->getHtmlContentAsync();
|
||||||
|
|
||||||
|
while (htmlExported == 0) {
|
||||||
|
VUtils::sleepWait(100);
|
||||||
|
|
||||||
|
if (m_state == ExportState::Cancelled) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return htmlExported == 1;
|
||||||
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
class QWidget;
|
class QWidget;
|
||||||
class VWebView;
|
class VWebView;
|
||||||
|
class VDocument;
|
||||||
|
|
||||||
class VExporter : public QObject
|
class VExporter : public QObject
|
||||||
{
|
{
|
||||||
@ -21,6 +22,11 @@ public:
|
|||||||
const QString &p_outputFile,
|
const QString &p_outputFile,
|
||||||
QString *p_errMsg = NULL);
|
QString *p_errMsg = NULL);
|
||||||
|
|
||||||
|
bool exportHTML(VFile *p_file,
|
||||||
|
const ExportOption &p_opt,
|
||||||
|
const QString &p_outputFile,
|
||||||
|
QString *p_errMsg = NULL);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void handleLogicsFinished();
|
void handleLogicsFinished();
|
||||||
|
|
||||||
@ -57,17 +63,31 @@ private:
|
|||||||
|
|
||||||
bool isNoteStateFailed() const;
|
bool isNoteStateFailed() const;
|
||||||
|
|
||||||
|
bool exportViaWebView(VFile *p_file,
|
||||||
|
const ExportOption &p_opt,
|
||||||
|
const QString &p_outputFile,
|
||||||
|
QString *p_errMsg = NULL);
|
||||||
|
|
||||||
bool exportToPDF(VWebView *p_webViewer,
|
bool exportToPDF(VWebView *p_webViewer,
|
||||||
const QString &p_filePath,
|
const QString &p_filePath,
|
||||||
const QPageLayout &p_layout);
|
const QPageLayout &p_layout);
|
||||||
|
|
||||||
|
bool exportToHTML(VWebView *p_webViewer,
|
||||||
|
VDocument *p_webDocument,
|
||||||
|
const QString &p_filePath);
|
||||||
|
|
||||||
QPageLayout m_pageLayout;
|
QPageLayout m_pageLayout;
|
||||||
|
|
||||||
// Will be allocated and free for each conversion.
|
// Will be allocated and free for each conversion.
|
||||||
VWebView *m_webViewer;
|
VWebView *m_webViewer;
|
||||||
|
|
||||||
|
VDocument *m_webDocument;
|
||||||
|
|
||||||
QString m_htmlTemplate;
|
QString m_htmlTemplate;
|
||||||
|
|
||||||
|
// Template to hold the export HTML result.
|
||||||
|
QString m_exportHtmlTemplate;
|
||||||
|
|
||||||
NoteState m_noteState;
|
NoteState m_noteState;
|
||||||
|
|
||||||
ExportState m_state;
|
ExportState m_state;
|
||||||
|
@ -110,7 +110,7 @@ QString VNote::generateHtmlTemplate(const QString &p_renderBg,
|
|||||||
cssStyle += "img { max-width: 100% !important; height: auto !important; }\n";
|
cssStyle += "img { max-width: 100% !important; height: auto !important; }\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString styleHolder("<!-- BACKGROUND_PLACE_HOLDER -->");
|
const QString styleHolder("/* BACKGROUND_PLACE_HOLDER */");
|
||||||
const QString cssHolder("CSS_PLACE_HOLDER");
|
const QString cssHolder("CSS_PLACE_HOLDER");
|
||||||
const QString codeBlockCssHolder("HIGHLIGHTJS_CSS_PLACE_HOLDER");
|
const QString codeBlockCssHolder("HIGHLIGHTJS_CSS_PLACE_HOLDER");
|
||||||
|
|
||||||
@ -142,6 +142,32 @@ QString VNote::generateHtmlTemplate(const QString &p_renderBg,
|
|||||||
return templ;
|
return templ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString VNote::generateExportHtmlTemplate(const QString &p_renderBg)
|
||||||
|
{
|
||||||
|
const QString c_exportTemplatePath(":/resources/export_template.html");
|
||||||
|
|
||||||
|
QString cssStyle;
|
||||||
|
if (!p_renderBg.isEmpty()) {
|
||||||
|
cssStyle += "body { background-color: " + p_renderBg + " !important; }\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_config->getEnableImageConstraint()) {
|
||||||
|
// Constain the image width.
|
||||||
|
cssStyle += "img { max-width: 100% !important; height: auto !important; }\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString styleHolder("/* BACKGROUND_PLACE_HOLDER */");
|
||||||
|
|
||||||
|
QString templ = VUtils::readFileFromDisk(c_exportTemplatePath);
|
||||||
|
g_palette->fillStyle(templ);
|
||||||
|
|
||||||
|
if (!cssStyle.isEmpty()) {
|
||||||
|
templ.replace(styleHolder, cssStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return templ;
|
||||||
|
}
|
||||||
|
|
||||||
void VNote::updateTemplate()
|
void VNote::updateTemplate()
|
||||||
{
|
{
|
||||||
QString renderBg = g_config->getRenderBackgroundColor(g_config->getCurRenderBackgroundColor());
|
QString renderBg = g_config->getRenderBackgroundColor(g_config->getCurRenderBackgroundColor());
|
||||||
|
@ -105,6 +105,9 @@ public:
|
|||||||
const QString &p_codeBlockStyleUrl,
|
const QString &p_codeBlockStyleUrl,
|
||||||
bool p_isPDF);
|
bool p_isPDF);
|
||||||
|
|
||||||
|
// @p_renderBg: background color, empty to not specify given color.
|
||||||
|
static QString generateExportHtmlTemplate(const QString &p_renderBg);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void updateTemplate();
|
void updateTemplate();
|
||||||
|
|
||||||
|
@ -239,5 +239,6 @@
|
|||||||
<file>resources/icons/delete_cart_item.svg</file>
|
<file>resources/icons/delete_cart_item.svg</file>
|
||||||
<file>resources/icons/fullscreen.svg</file>
|
<file>resources/icons/fullscreen.svg</file>
|
||||||
<file>resources/icons/menubar.svg</file>
|
<file>resources/icons/menubar.svg</file>
|
||||||
|
<file>resources/export_template.html</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user