diff --git a/src/resources/hoedown.js b/src/resources/hoedown.js index 6a71810f..3f77ca6e 100644 --- a/src/resources/hoedown.js +++ b/src/resources/hoedown.js @@ -13,6 +13,9 @@ marked.setOptions({ var updateHtml = function(html) { placeholder.innerHTML = html; + + insertImageCaption(); + var codes = document.getElementsByTagName('code'); mermaidIdx = 0; for (var i = 0; i < codes.length; ++i) { diff --git a/src/resources/markdown-it.js b/src/resources/markdown-it.js index a2ecacf1..69c23b1e 100644 --- a/src/resources/markdown-it.js +++ b/src/resources/markdown-it.js @@ -167,6 +167,7 @@ var updateText = function(text) { var html = markdownToHtml(text, needToc); placeholder.innerHTML = html; handleToc(needToc); + insertImageCaption(); renderMermaid('lang-mermaid'); if (VEnableMathjax) { try { diff --git a/src/resources/markdown_template.js b/src/resources/markdown_template.js index 4ebfaba8..8c1fb6de 100644 --- a/src/resources/markdown_template.js +++ b/src/resources/markdown_template.js @@ -14,6 +14,14 @@ if (typeof VEnableMathjax == 'undefined') { VEnableMathjax = false; } +// Add a caption (using alt text) under the image. +var VImageCenterClass = 'img-center'; +var VImageCaptionClass = 'img-caption'; +var VImagePackageClass = 'img-package'; +if (typeof VEnableImageCaption == 'undefined') { + VEnableImageCaption = false; +} + new QWebChannel(qt.webChannelTransport, function(channel) { content = channel.objects.content; @@ -200,3 +208,40 @@ var renderMermaid = function(className) { } } }; + +var isImageBlock = function(img) { + var pn = img.parentNode; + return (pn.children.length == 1) && (pn.innerText == ''); +} + +// Center the image block and insert the alt text as caption. +var insertImageCaption = function() { + if (!VEnableImageCaption) { + return; + } + + var imgs = document.getElementsByTagName('img'); + for (var i = 0; i < imgs.length; ++i) { + var img = imgs[i]; + + if (!isImageBlock(img)) { + continue; + } + + // Make the parent img-package. + img.parentNode.classList.add(VImagePackageClass); + + // Make it center. + img.classList.add(VImageCenterClass); + + if (img.alt == '') { + continue; + } + + // Add caption. + var captionDiv = document.createElement('div'); + captionDiv.classList.add(VImageCaptionClass); + captionDiv.innerText = img.alt; + img.insertAdjacentElement('afterend', captionDiv); + } +} diff --git a/src/resources/marked.js b/src/resources/marked.js index 5d9c53be..49b1c4a2 100644 --- a/src/resources/marked.js +++ b/src/resources/marked.js @@ -125,6 +125,7 @@ var updateText = function(text) { var html = markdownToHtml(text, needToc); placeholder.innerHTML = html; handleToc(needToc); + insertImageCaption(); renderMermaid('lang-mermaid'); if (VEnableMathjax) { try { diff --git a/src/resources/styles/default.css b/src/resources/styles/default.css index 1c15f51b..4a2d97f7 100644 --- a/src/resources/styles/default.css +++ b/src/resources/styles/default.css @@ -138,13 +138,37 @@ table tr th :first-child, table tr td :first-child { table tr th :last-child, table tr td :last-child { margin-bottom: 0; } + div.mermaid-diagram { overflow-y: hidden; } + pre.mermaid-diagram { overflow-y: hidden; } +.img-package { + text-align: center; +} + +img.img-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +div.img-caption { + min-width: 20%; + max-width: 80%; + display: inline-block; + padding: 10px; + margin: 0 auto; + border-bottom: 1px solid #c0c0c0; + color: #6c6c6c; + text-align: center; + line-height: 1.5; +} + /* Code below this line is copyright Twitter Inc. */ button, diff --git a/src/resources/vnote.ini b/src/resources/vnote.ini index e563cfcc..98a621ac 100644 --- a/src/resources/vnote.ini +++ b/src/resources/vnote.ini @@ -33,6 +33,9 @@ enable_preview_image_constraint=true ; Enable image constraint in read mode to constrain the width of the image enable_image_constraint=true +; Center image and add the alt text as caption +enable_image_caption=false + [session] tools_dock_checked=true diff --git a/src/vconfigmanager.cpp b/src/vconfigmanager.cpp index 65fef234..5c30f326 100644 --- a/src/vconfigmanager.cpp +++ b/src/vconfigmanager.cpp @@ -133,6 +133,9 @@ void VConfigManager::initialize() m_enableImageConstraint = getConfigFromSettings("global", "enable_image_constraint").toBool(); + + m_enableImageCaption = getConfigFromSettings("global", + "enable_image_caption").toBool(); } void VConfigManager::readPredefinedColorsFromSettings() diff --git a/src/vconfigmanager.h b/src/vconfigmanager.h index 75156dfe..962a079c 100644 --- a/src/vconfigmanager.h +++ b/src/vconfigmanager.h @@ -168,6 +168,9 @@ public: inline bool getEnableImageConstraint() const; inline void setEnableImageConstraint(bool p_enabled); + inline bool getEnableImageCaption() const; + inline void setEnableImageCaption(bool p_enabled); + // Get the folder the ini file exists. QString getConfigFolder() const; @@ -284,6 +287,9 @@ private: // Constrain the width of image in read mode. bool m_enableImageConstraint; + // Center image and add the alt text as caption. + bool m_enableImageCaption; + // The name of the config file in each directory, obsolete. // Use c_dirConfigFile instead. static const QString c_obsoleteDirConfigFile; @@ -757,4 +763,19 @@ inline void VConfigManager::setEnableImageConstraint(bool p_enabled) m_enableImageConstraint); } +inline bool VConfigManager::getEnableImageCaption() const +{ + return m_enableImageCaption; +} + +inline void VConfigManager::setEnableImageCaption(bool p_enabled) +{ + if (m_enableImageCaption == p_enabled) { + return; + } + m_enableImageCaption = p_enabled; + setConfigToSettings("global", "enable_image_caption", + m_enableImageCaption); +} + #endif // VCONFIGMANAGER_H diff --git a/src/vedittab.cpp b/src/vedittab.cpp index 1a97c380..b9e8a242 100644 --- a/src/vedittab.cpp +++ b/src/vedittab.cpp @@ -356,6 +356,10 @@ void VEditTab::setupMarkdownPreview() "\n"; } + if (vconfig.getEnableImageCaption()) { + extraFile += "\n"; + } + QString htmlTemplate = VNote::s_markdownTemplate; htmlTemplate.replace(jsHolder, jsFile); if (!extraFile.isEmpty()) { diff --git a/src/vmainwindow.cpp b/src/vmainwindow.cpp index ceaf00c6..65fda46a 100644 --- a/src/vmainwindow.cpp +++ b/src/vmainwindow.cpp @@ -352,7 +352,7 @@ void VMainWindow::initMarkdownMenu() initRenderBackgroundMenu(markdownMenu); - QAction *constrainImageAct = new QAction(tr("Constrain The Width of Images in Read Mode"), this); + QAction *constrainImageAct = new QAction(tr("Constrain The Width of Images"), this); constrainImageAct->setToolTip(tr("Constrain the width of images to the window in read mode (re-open current tabs to make it work)")); constrainImageAct->setCheckable(true); connect(constrainImageAct, &QAction::triggered, @@ -360,6 +360,14 @@ void VMainWindow::initMarkdownMenu() markdownMenu->addAction(constrainImageAct); constrainImageAct->setChecked(vconfig.getEnableImageConstraint()); + QAction *imageCaptionAct = new QAction(tr("Enable Image Caption"), this); + imageCaptionAct->setToolTip(tr("Center the images and display the alt text as caption (re-open current tabs to make it work)")); + imageCaptionAct->setCheckable(true); + connect(imageCaptionAct, &QAction::triggered, + this, &VMainWindow::enableImageCaption); + markdownMenu->addAction(imageCaptionAct); + imageCaptionAct->setChecked(vconfig.getEnableImageCaption()); + markdownMenu->addSeparator(); QAction *mermaidAct = new QAction(tr("&Mermaid Diagram"), this); @@ -1316,6 +1324,11 @@ void VMainWindow::enableImageConstraint(bool p_checked) vnote->updateTemplate(); } +void VMainWindow::enableImageCaption(bool p_checked) +{ + vconfig.setEnableImageCaption(p_checked); +} + void VMainWindow::shortcutHelp() { QString locale = VUtils::getLocale(); diff --git a/src/vmainwindow.h b/src/vmainwindow.h index 3c53dcc2..7b61d452 100644 --- a/src/vmainwindow.h +++ b/src/vmainwindow.h @@ -79,6 +79,7 @@ private slots: void enableImagePreview(bool p_checked); void enableImagePreviewConstraint(bool p_checked); void enableImageConstraint(bool p_checked); + void enableImageCaption(bool p_checked); protected: void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;