#include "htmltemplatehelper.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace vnotex;
HtmlTemplateHelper::Template HtmlTemplateHelper::s_markdownViewerTemplate;
QString WebGlobalOptions::toJavascriptObject() const
{
return QStringLiteral("window.vxOptions = {\n")
+ QString("webPlantUml: %1,\n").arg(Utils::boolToString(m_webPlantUml))
+ QString("webGraphviz: %1,\n").arg(Utils::boolToString(m_webGraphviz))
+ QString("constrainImageWidthEnabled: %1,\n").arg(Utils::boolToString(m_constrainImageWidthEnabled))
+ QString("imageAlignCenterEnabled: %1,\n").arg(Utils::boolToString(m_imageAlignCenterEnabled))
+ QString("protectFromXss: %1,\n").arg(Utils::boolToString(m_protectFromXss))
+ QString("htmlTagEnabled: %1,\n").arg(Utils::boolToString(m_htmlTagEnabled))
+ QString("autoBreakEnabled: %1,\n").arg(Utils::boolToString(m_autoBreakEnabled))
+ QString("linkifyEnabled: %1,\n").arg(Utils::boolToString(m_linkifyEnabled))
+ QString("indentFirstLineEnabled: %1,\n").arg(Utils::boolToString(m_indentFirstLineEnabled))
+ QString("sectionNumberEnabled: %1,\n").arg(Utils::boolToString(m_sectionNumberEnabled))
+ QString("transparentBackgroundEnabled: %1,\n").arg(Utils::boolToString(m_transparentBackgroundEnabled))
+ QString("scrollable: %1,\n").arg(Utils::boolToString(m_scrollable))
+ QString("bodyWidth: %1,\n").arg(m_bodyWidth)
+ QString("bodyHeight: %1,\n").arg(m_bodyHeight)
+ QString("transformSvgToPngEnabled: %1,\n").arg(Utils::boolToString(m_transformSvgToPngEnabled))
+ QString("mathJaxScale: %1,\n").arg(m_mathJaxScale)
+ QString("removeCodeToolBarEnabled: %1,\n").arg(Utils::boolToString(m_removeCodeToolBarEnabled))
+ QString("sectionNumberBaseLevel: %1\n").arg(m_sectionNumberBaseLevel)
+ QStringLiteral("}");
}
// Read "global_styles" from resource and fill the holder with the content.
static void fillGlobalStyles(QString &p_template, const WebResource &p_resource, const QString &p_additionalStyles)
{
QString styles;
for (const auto &ele : p_resource.m_resources) {
if (ele.isGlobal()) {
if (ele.m_enabled) {
for (const auto &style : ele.m_styles) {
// Read the style file content.
auto styleFile = ConfigMgr::getInst().getUserOrAppFile(style);
try {
styles += FileUtils::readTextFile(styleFile);
} catch (Exception &p_e) {
qWarning() << "failed to read global styles" << ele.m_name << styleFile << p_e.what();
}
}
}
break;
}
}
styles += p_additionalStyles;
if (!styles.isEmpty()) {
p_template.replace("/* VX_GLOBAL_STYLES_PLACEHOLDER */", styles);
}
}
static QString fillStyleTag(const QString &p_styleFile)
{
if (p_styleFile.isEmpty()) {
return "";
}
auto url = PathUtils::pathToUrl(p_styleFile);
return QString("\n").arg(url.toString());
}
static QString fillScriptTag(const QString &p_scriptFile)
{
if (p_scriptFile.isEmpty()) {
return "";
}
auto url = PathUtils::pathToUrl(p_scriptFile);
return QString("\n").arg(url.toString());
}
static void fillThemeStyles(QString &p_template, const QString &p_webStyleSheetFile, const QString &p_highlightStyleSheetFile)
{
QString styles;
styles += fillStyleTag(p_webStyleSheetFile);
styles += fillStyleTag(p_highlightStyleSheetFile);
if (!styles.isEmpty()) {
p_template.replace(QStringLiteral(""),
styles);
}
}
static void fillGlobalOptions(QString &p_template, const WebGlobalOptions &p_opts)
{
p_template.replace(QStringLiteral("/* VX_GLOBAL_OPTIONS_PLACEHOLDER */"),
p_opts.toJavascriptObject());
}
// Read all other resources in @p_resource and fill the holder with proper resource path.
static void fillResources(QString &p_template, const WebResource &p_resource)
{
QString styles;
QString scripts;
for (const auto &ele : p_resource.m_resources) {
if (ele.m_enabled && !ele.isGlobal()) {
// Styles.
for (const auto &style : ele.m_styles) {
auto styleFile = ConfigMgr::getInst().getUserOrAppFile(style);
styles += fillStyleTag(styleFile);
}
// Scripts.
for (const auto &script : ele.m_scripts) {
auto scriptFile = ConfigMgr::getInst().getUserOrAppFile(script);
scripts += fillScriptTag(scriptFile);
}
}
}
if (!styles.isEmpty()) {
p_template.replace(QStringLiteral(""),
styles);
}
if (!scripts.isEmpty()) {
p_template.replace(QStringLiteral(""),
scripts);
}
}
static void fillResourcesByContent(QString &p_template, const WebResource &p_resource)
{
QString styles;
QString scripts;
for (const auto &ele : p_resource.m_resources) {
if (ele.m_enabled && !ele.isGlobal()) {
try {
// Styles.
for (const auto &style : ele.m_styles) {
auto styleFile = ConfigMgr::getInst().getUserOrAppFile(style);
styles += FileUtils::readTextFile(styleFile);
}
// Scripts.
for (const auto &script : ele.m_scripts) {
auto scriptFile = ConfigMgr::getInst().getUserOrAppFile(script);
scripts += FileUtils::readTextFile(scriptFile);
}
} catch (Exception &p_e) {
qWarning() << "failed to read resource" << ele.m_name << p_e.what();
}
}
}
if (!styles.isEmpty()) {
p_template.replace(QStringLiteral("/* VX_STYLES_PLACEHOLDER */"), styles);
}
if (!scripts.isEmpty()) {
p_template.replace(QStringLiteral("/* VX_SCRIPTS_PLACEHOLDER */"), scripts);
}
}
const QString &HtmlTemplateHelper::getMarkdownViewerTemplate()
{
return s_markdownViewerTemplate.m_template;
}
void HtmlTemplateHelper::updateMarkdownViewerTemplate(const MarkdownEditorConfig &p_config, bool p_force)
{
if (!p_force && p_config.revision() == s_markdownViewerTemplate.m_revision) {
return;
}
s_markdownViewerTemplate.m_revision = p_config.revision();
Paras paras;
const auto &themeMgr = VNoteX::getInst().getThemeMgr();
paras.m_webStyleSheetFile = themeMgr.getFile(Theme::File::WebStyleSheet);
paras.m_highlightStyleSheetFile = themeMgr.getFile(Theme::File::HighlightStyleSheet);
s_markdownViewerTemplate.m_template = generateMarkdownViewerTemplate(p_config, paras);
}
QString HtmlTemplateHelper::generateMarkdownViewerTemplate(const MarkdownEditorConfig &p_config, const Paras &p_paras)
{
const auto &viewerResource = p_config.getViewerResource();
const auto templateFile = ConfigMgr::getInst().getUserOrAppFile(viewerResource.m_template);
QString htmlTemplate;
try {
htmlTemplate = FileUtils::readTextFile(templateFile);
} catch (Exception &p_e) {
qWarning() << "failed to read HTML template" << templateFile << p_e.what();
return errorPage();
}
fillGlobalStyles(htmlTemplate, viewerResource, "");
fillThemeStyles(htmlTemplate, p_paras.m_webStyleSheetFile, p_paras.m_highlightStyleSheetFile);
{
WebGlobalOptions opts;
opts.m_webPlantUml = p_config.getWebPlantUml();
opts.m_webGraphviz = p_config.getWebGraphviz();
opts.m_sectionNumberEnabled = p_config.getSectionNumberMode() == MarkdownEditorConfig::SectionNumberMode::Read;
opts.m_sectionNumberBaseLevel = p_config.getSectionNumberBaseLevel();
opts.m_constrainImageWidthEnabled = p_config.getConstrainImageWidthEnabled();
opts.m_imageAlignCenterEnabled = p_config.getImageAlignCenterEnabled();
opts.m_protectFromXss = p_config.getProtectFromXss();
opts.m_htmlTagEnabled = p_config.getHtmlTagEnabled();
opts.m_autoBreakEnabled = p_config.getAutoBreakEnabled();
opts.m_linkifyEnabled = p_config.getLinkifyEnabled();
opts.m_indentFirstLineEnabled = p_config.getIndentFirstLineEnabled();
opts.m_transparentBackgroundEnabled = p_paras.m_transparentBackgroundEnabled;
opts.m_scrollable = p_paras.m_scrollable;
opts.m_bodyWidth = p_paras.m_bodyWidth;
opts.m_bodyHeight = p_paras.m_bodyHeight;
opts.m_transformSvgToPngEnabled = p_paras.m_transformSvgToPngEnabled;
opts.m_mathJaxScale = p_paras.m_mathJaxScale;
opts.m_removeCodeToolBarEnabled = p_paras.m_removeCodeToolBarEnabled;
fillGlobalOptions(htmlTemplate, opts);
}
fillResources(htmlTemplate, viewerResource);
return htmlTemplate;
}
QString HtmlTemplateHelper::generateExportTemplate(const MarkdownEditorConfig &p_config,
bool p_addOutlinePanel)
{
auto exportResource = p_config.getExportResource();
const auto templateFile = ConfigMgr::getInst().getUserOrAppFile(exportResource.m_template);
QString htmlTemplate;
try {
htmlTemplate = FileUtils::readTextFile(templateFile);
} catch (Exception &p_e) {
qWarning() << "failed to read export HTML template" << templateFile << p_e.what();
return errorPage();
}
fillGlobalStyles(htmlTemplate, exportResource, "");
fillOutlinePanel(htmlTemplate, exportResource, p_addOutlinePanel);
fillResourcesByContent(htmlTemplate, exportResource);
return htmlTemplate;
}
void HtmlTemplateHelper::fillOutlinePanel(QString &p_template, WebResource &p_exportResource, bool p_addOutlinePanel)
{
for (auto &ele : p_exportResource.m_resources) {
if (ele.m_name == QStringLiteral("outline")) {
ele.m_enabled = p_addOutlinePanel;
break;
}
}
// Remove static content to make the page clean.
if (!p_addOutlinePanel) {
int startIdx = p_template.indexOf("");
QString endMark("");
int endIdx = p_template.lastIndexOf(endMark);
Q_ASSERT(startIdx > -1 && endIdx > startIdx);
p_template.remove(startIdx, endIdx + endMark.size() - startIdx);
startIdx = p_template.indexOf("");
endMark = "";
endIdx = p_template.lastIndexOf(endMark);
Q_ASSERT(startIdx > -1 && endIdx > startIdx);
p_template.remove(startIdx, endIdx + endMark.size() - startIdx);
}
}
void HtmlTemplateHelper::fillTitle(QString &p_template, const QString &p_title)
{
if (!p_title.isEmpty()) {
p_template.replace("",
QString("%1").arg(HtmlUtils::escapeHtml(p_title)));
}
}
void HtmlTemplateHelper::fillStyleContent(QString &p_template, const QString &p_styles)
{
p_template.replace("/* VX_STYLES_CONTENT_PLACEHOLDER */", p_styles);
}
void HtmlTemplateHelper::fillHeadContent(QString &p_template, const QString &p_head)
{
p_template.replace("", p_head);
}
void HtmlTemplateHelper::fillContent(QString &p_template, const QString &p_content)
{
p_template.replace("", p_content);
}
void HtmlTemplateHelper::fillBodyClassList(QString &p_template, const QString &p_classList)
{
p_template.replace("", p_classList);
}
QString HtmlTemplateHelper::errorPage()
{
return VNoteX::tr("Failed to load HTML template. Check the logs for details. "
"Try deleting the user configuration file and the default configuration file.");
}