mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 22:09:52 +08:00
VMdEditor: support copy selected text as HTML
This commit is contained in:
parent
ce48c80cd0
commit
2f1971476d
81
src/dialog/vcopytextashtmldialog.cpp
Normal file
81
src/dialog/vcopytextashtmldialog.cpp
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#include "vcopytextashtmldialog.h"
|
||||||
|
|
||||||
|
#include <QtWidgets>
|
||||||
|
#include <QWebEngineView>
|
||||||
|
#include <QClipboard>
|
||||||
|
#include <QMimeData>
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
#include "utils/vutils.h"
|
||||||
|
#include "utils/vclipboardutils.h"
|
||||||
|
#include "utils/vwebutils.h"
|
||||||
|
#include "vconfigmanager.h"
|
||||||
|
|
||||||
|
extern VConfigManager *g_config;
|
||||||
|
|
||||||
|
VCopyTextAsHtmlDialog::VCopyTextAsHtmlDialog(const QString &p_text, QWidget *p_parent)
|
||||||
|
: QDialog(p_parent), m_text(p_text)
|
||||||
|
{
|
||||||
|
setupUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VCopyTextAsHtmlDialog::setupUI()
|
||||||
|
{
|
||||||
|
QLabel *textLabel = new QLabel(tr("Text:"));
|
||||||
|
m_textEdit = new QPlainTextEdit(m_text);
|
||||||
|
m_textEdit->setReadOnly(true);
|
||||||
|
m_textEdit->setProperty("LineEdit", true);
|
||||||
|
|
||||||
|
m_htmlLabel = new QLabel(tr("HTML:"));
|
||||||
|
m_htmlViewer = VUtils::getWebEngineView();
|
||||||
|
m_htmlViewer->setContextMenuPolicy(Qt::NoContextMenu);
|
||||||
|
m_htmlViewer->setMinimumSize(600, 400);
|
||||||
|
|
||||||
|
m_infoLabel = new QLabel(tr("Converting text to HTML ..."));
|
||||||
|
|
||||||
|
m_btnBox = new QDialogButtonBox(QDialogButtonBox::Ok);
|
||||||
|
connect(m_btnBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||||
|
m_btnBox->button(QDialogButtonBox::Ok)->setProperty("SpecialBtn", true);
|
||||||
|
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout();
|
||||||
|
mainLayout->addWidget(textLabel);
|
||||||
|
mainLayout->addWidget(m_textEdit);
|
||||||
|
mainLayout->addWidget(m_htmlLabel);
|
||||||
|
mainLayout->addWidget(m_htmlViewer);
|
||||||
|
mainLayout->addWidget(m_infoLabel);
|
||||||
|
mainLayout->addStretch();
|
||||||
|
mainLayout->addWidget(m_btnBox);
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
setWindowTitle(tr("Copy Text As HTML"));
|
||||||
|
|
||||||
|
setHtmlVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VCopyTextAsHtmlDialog::setHtmlVisible(bool p_visible)
|
||||||
|
{
|
||||||
|
m_htmlLabel->setVisible(p_visible);
|
||||||
|
m_htmlViewer->setVisible(p_visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VCopyTextAsHtmlDialog::setConvertedHtml(const QUrl &p_baseUrl,
|
||||||
|
const QString &p_html)
|
||||||
|
{
|
||||||
|
QString html = QString("<html><body>%1</body></html>").arg(p_html);
|
||||||
|
m_htmlViewer->setHtml(html, p_baseUrl);
|
||||||
|
setHtmlVisible(true);
|
||||||
|
|
||||||
|
// Fix image source.
|
||||||
|
if (g_config->getFixImageSrcInWebWhenCopied()) {
|
||||||
|
VWebUtils::fixImageSrcInHtml(p_baseUrl, html);
|
||||||
|
}
|
||||||
|
|
||||||
|
QClipboard *clipboard = QApplication::clipboard();
|
||||||
|
QMimeData *data = new QMimeData();
|
||||||
|
data->setText(m_text);
|
||||||
|
data->setHtml(html);
|
||||||
|
VClipboardUtils::setMimeDataToClipboard(clipboard, data, QClipboard::Clipboard);
|
||||||
|
|
||||||
|
QTimer::singleShot(3000, this, &VCopyTextAsHtmlDialog::accept);
|
||||||
|
m_infoLabel->setText(tr("HTML has been copied. Will be closed in 3 seconds."));
|
||||||
|
}
|
46
src/dialog/vcopytextashtmldialog.h
Normal file
46
src/dialog/vcopytextashtmldialog.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#ifndef VCOPYTEXTASHTMLDIALOG_H
|
||||||
|
#define VCOPYTEXTASHTMLDIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
|
||||||
|
class QPlainTextEdit;
|
||||||
|
class QWebEngineView;
|
||||||
|
class QDialogButtonBox;
|
||||||
|
class VWaitingWidget;
|
||||||
|
class QLabel;
|
||||||
|
|
||||||
|
class VCopyTextAsHtmlDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
VCopyTextAsHtmlDialog(const QString &p_text, QWidget *p_parent = nullptr);
|
||||||
|
|
||||||
|
void setConvertedHtml(const QUrl &p_baseUrl, const QString &p_html);
|
||||||
|
|
||||||
|
const QString &getText() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupUI();
|
||||||
|
|
||||||
|
void setHtmlVisible(bool p_visible);
|
||||||
|
|
||||||
|
QPlainTextEdit *m_textEdit;
|
||||||
|
|
||||||
|
QLabel *m_htmlLabel;
|
||||||
|
|
||||||
|
QWebEngineView *m_htmlViewer;
|
||||||
|
|
||||||
|
QLabel *m_infoLabel;
|
||||||
|
|
||||||
|
QDialogButtonBox *m_btnBox;
|
||||||
|
|
||||||
|
QString m_text;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const QString &VCopyTextAsHtmlDialog::getText() const
|
||||||
|
{
|
||||||
|
return m_text;
|
||||||
|
}
|
||||||
|
#endif // VCOPYTEXTASHTMLDIALOG_H
|
@ -69,3 +69,15 @@ var highlightText = function(text, id, timeStamp) {
|
|||||||
var html = marked(text);
|
var html = marked(text);
|
||||||
content.highlightTextCB(html, id, timeStamp);
|
content.highlightTextCB(html, id, timeStamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var textToHtml = function(text) {
|
||||||
|
var html = marked(text);
|
||||||
|
var container = document.getElementById('text-to-html-div');
|
||||||
|
container.innerHTML = html;
|
||||||
|
|
||||||
|
html = getHtmlWithInlineStyles(container);
|
||||||
|
|
||||||
|
container.innerHTML = "";
|
||||||
|
|
||||||
|
content.textToHtmlCB(text, html);
|
||||||
|
}
|
||||||
|
@ -124,3 +124,14 @@ var highlightText = function(text, id, timeStamp) {
|
|||||||
content.highlightTextCB(html, id, timeStamp);
|
content.highlightTextCB(html, id, timeStamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var textToHtml = function(text) {
|
||||||
|
var html = mdit.render(text);
|
||||||
|
var container = document.getElementById('text-to-html-div');
|
||||||
|
container.innerHTML = html;
|
||||||
|
|
||||||
|
html = getHtmlWithInlineStyles(container);
|
||||||
|
|
||||||
|
container.innerHTML = "";
|
||||||
|
|
||||||
|
content.textToHtmlCB(text, html);
|
||||||
|
}
|
||||||
|
@ -31,5 +31,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="placeholder"></div>
|
<div id="placeholder"></div>
|
||||||
|
|
||||||
|
<div id="text-to-html-div" style="display:none;"></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -28,6 +28,10 @@ if (typeof VEnableHighlightLineNumber == 'undefined') {
|
|||||||
VEnableHighlightLineNumber = false;
|
VEnableHighlightLineNumber = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof VStylesToInline == 'undefined') {
|
||||||
|
VStylesToInline = '';
|
||||||
|
}
|
||||||
|
|
||||||
// Add a caption (using alt text) under the image.
|
// Add a caption (using alt text) under the image.
|
||||||
var VImageCenterClass = 'img-center';
|
var VImageCenterClass = 'img-center';
|
||||||
var VImageCaptionClass = 'img-caption';
|
var VImageCaptionClass = 'img-caption';
|
||||||
@ -53,6 +57,11 @@ new QWebChannel(qt.webChannelTransport,
|
|||||||
content.requestHighlightText.connect(highlightText);
|
content.requestHighlightText.connect(highlightText);
|
||||||
content.noticeReadyToHighlightText();
|
content.noticeReadyToHighlightText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof textToHtml == "function") {
|
||||||
|
content.requestTextToHtml.connect(textToHtml);
|
||||||
|
content.noticeReadyToTextToHtml();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var VHighlightedAnchorClass = 'highlighted-anchor';
|
var VHighlightedAnchorClass = 'highlighted-anchor';
|
||||||
@ -853,4 +862,68 @@ var listContainsRegex = function(strs, exp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
var StylesToInline = null;
|
||||||
|
|
||||||
|
var initStylesToInline = function() {
|
||||||
|
console.log('initStylesToInline');
|
||||||
|
StylesToInline = new Map();
|
||||||
|
|
||||||
|
if (VStylesToInline.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rules = VStylesToInline.split(',');
|
||||||
|
for (var i = 0; i < rules.length; ++i) {
|
||||||
|
var vals = rules[i].split('$');
|
||||||
|
if (vals.length != 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tags = vals[0].split(':');
|
||||||
|
var pros = vals[1].split(':');
|
||||||
|
for (var j = 0; j < tags.length; ++j) {
|
||||||
|
StylesToInline.set(tags[j].toLowerCase(), pros);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Embed the CSS styles of @ele and all its children.
|
||||||
|
var embedInlineStyles = function(ele) {
|
||||||
|
var tagName = ele.tagName.toLowerCase();
|
||||||
|
var props = StylesToInline.get(tagName);
|
||||||
|
if (!props) {
|
||||||
|
props = StylesToInline.get('all');
|
||||||
|
|
||||||
|
if (!props) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Embed itself.
|
||||||
|
var style = window.getComputedStyle(ele, null);
|
||||||
|
for (var i = 0; i < props.length; ++i) {
|
||||||
|
var pro = props[i];
|
||||||
|
ele.style.setProperty(pro, style.getPropertyValue(pro));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Embed children.
|
||||||
|
var children = ele.children;
|
||||||
|
for (var i = 0; i < children.length; ++i) {
|
||||||
|
embedInlineStyles(children[i]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var getHtmlWithInlineStyles = function(container) {
|
||||||
|
if (!StylesToInline) {
|
||||||
|
initStylesToInline();
|
||||||
|
}
|
||||||
|
|
||||||
|
var children = container.children;
|
||||||
|
for (var i = 0; i < children.length; ++i) {
|
||||||
|
embedInlineStyles(children[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return container.innerHTML;
|
||||||
|
};
|
||||||
|
@ -75,3 +75,14 @@ var highlightText = function(text, id, timeStamp) {
|
|||||||
content.highlightTextCB(html, id, timeStamp);
|
content.highlightTextCB(html, id, timeStamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var textToHtml = function(text) {
|
||||||
|
var html = marked(text);
|
||||||
|
var container = document.getElementById('text-to-html-div');
|
||||||
|
container.innerHTML = html;
|
||||||
|
|
||||||
|
html = getHtmlWithInlineStyles(container);
|
||||||
|
|
||||||
|
container.innerHTML = "";
|
||||||
|
|
||||||
|
content.textToHtmlCB(text, html);
|
||||||
|
}
|
||||||
|
@ -109,3 +109,23 @@ var highlightText = function(text, id, timeStamp) {
|
|||||||
content.highlightTextCB(html, id, timeStamp);
|
content.highlightTextCB(html, id, timeStamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var textToHtml = function(text) {
|
||||||
|
var html = renderer.makeHtml(text);
|
||||||
|
|
||||||
|
var parser = new DOMParser();
|
||||||
|
var htmlDoc = parser.parseFromString("<div id=\"showdown-container\">" + html + "</div>", 'text/html');
|
||||||
|
highlightCodeBlocks(htmlDoc, false, false);
|
||||||
|
|
||||||
|
html = htmlDoc.getElementById('showdown-container').innerHTML;
|
||||||
|
|
||||||
|
delete parser;
|
||||||
|
|
||||||
|
var container = document.getElementById('text-to-html-div');
|
||||||
|
container.innerHTML = html;
|
||||||
|
|
||||||
|
html = getHtmlWithInlineStyles(container);
|
||||||
|
|
||||||
|
container.innerHTML = "";
|
||||||
|
|
||||||
|
content.textToHtmlCB(text, html);
|
||||||
|
}
|
||||||
|
@ -196,6 +196,15 @@ mathjax_javascript=https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.
|
|||||||
; Fix local relative image source when copied
|
; Fix local relative image source when copied
|
||||||
fix_img_src_when_copied=true
|
fix_img_src_when_copied=true
|
||||||
|
|
||||||
|
; Styles to be removed when copied in read mode
|
||||||
|
; style1,style2,style3
|
||||||
|
styles_to_remove_when_copied=margin,margin-left,margin-right,padding,padding-left,padding-right
|
||||||
|
|
||||||
|
; CSS properties to embed as inline styles when copied in edit mode
|
||||||
|
; tag1:tag2:tag3$property1:property2:property3,tag4:tag5$property2:property3
|
||||||
|
; "all" for all tags not specified explicitly
|
||||||
|
styles_to_inline_when_copied=all$border:color:display:font-family:font-size:font-style:white-space:word-spacing:line-height:text-align:text-indent:padding-top:padding-bottom:margin-top:margin-bottom,code$font-family:font-size:line-height:color:display:overfow-x,li$line-height,a$color:vertical-align,pre$display:overflow-y:overflow-x:color:font-size:font-style:font-weight:letter-spacing:text-align:text-indent:word-spacing
|
||||||
|
|
||||||
[shortcuts]
|
[shortcuts]
|
||||||
; Define shortcuts here, with each item in the form "operation=keysequence".
|
; Define shortcuts here, with each item in the form "operation=keysequence".
|
||||||
; Leave keysequence empty to disable the shortcut of an operation.
|
; Leave keysequence empty to disable the shortcut of an operation.
|
||||||
|
10
src/src.pro
10
src/src.pro
@ -102,7 +102,10 @@ SOURCES += main.cpp\
|
|||||||
vbuttonmenuitem.cpp \
|
vbuttonmenuitem.cpp \
|
||||||
utils/viconutils.cpp \
|
utils/viconutils.cpp \
|
||||||
lineeditdelegate.cpp \
|
lineeditdelegate.cpp \
|
||||||
dialog/vtipsdialog.cpp
|
dialog/vtipsdialog.cpp \
|
||||||
|
dialog/vcopytextashtmldialog.cpp \
|
||||||
|
vwaitingwidget.cpp \
|
||||||
|
utils/vwebutils.cpp
|
||||||
|
|
||||||
HEADERS += vmainwindow.h \
|
HEADERS += vmainwindow.h \
|
||||||
vdirectorytree.h \
|
vdirectorytree.h \
|
||||||
@ -191,7 +194,10 @@ HEADERS += vmainwindow.h \
|
|||||||
vbuttonmenuitem.h \
|
vbuttonmenuitem.h \
|
||||||
utils/viconutils.h \
|
utils/viconutils.h \
|
||||||
lineeditdelegate.h \
|
lineeditdelegate.h \
|
||||||
dialog/vtipsdialog.h
|
dialog/vtipsdialog.h \
|
||||||
|
dialog/vcopytextashtmldialog.h \
|
||||||
|
vwaitingwidget.h \
|
||||||
|
utils/vwebutils.h
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
vnote.qrc \
|
vnote.qrc \
|
||||||
|
@ -664,6 +664,8 @@ QString VUtils::generateHtmlTemplate(MarkdownConverterType p_conType, bool p_exp
|
|||||||
"<script>var VEnableHighlightLineNumber = true;</script>\n";
|
"<script>var VEnableHighlightLineNumber = true;</script>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extraFile += "<script>var VStylesToInline = '" + g_config->getStylesToInlineWhenCopied() + "';</script>\n";
|
||||||
|
|
||||||
QString htmlTemplate;
|
QString htmlTemplate;
|
||||||
if (p_exportPdf) {
|
if (p_exportPdf) {
|
||||||
htmlTemplate = VNote::s_markdownTemplatePDF;
|
htmlTemplate = VNote::s_markdownTemplatePDF;
|
||||||
|
@ -6321,9 +6321,7 @@ void VVim::handleMouseMoved(QMouseEvent *p_event)
|
|||||||
|
|
||||||
void VVim::handleMouseReleased(QMouseEvent *p_event)
|
void VVim::handleMouseReleased(QMouseEvent *p_event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(p_event);
|
if (checkMode(VimMode::Normal) && p_event->button() == Qt::LeftButton) {
|
||||||
|
|
||||||
if (checkMode(VimMode::Normal)) {
|
|
||||||
QTextCursor cursor = m_editor->textCursorW();
|
QTextCursor cursor = m_editor->textCursorW();
|
||||||
if (cursor.hasSelection()) {
|
if (cursor.hasSelection()) {
|
||||||
return;
|
return;
|
||||||
|
58
src/utils/vwebutils.cpp
Normal file
58
src/utils/vwebutils.cpp
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include "vwebutils.h"
|
||||||
|
|
||||||
|
#include <QRegExp>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
VWebUtils::VWebUtils()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VWebUtils::fixImageSrcInHtml(const QUrl &p_baseUrl, QString &p_html)
|
||||||
|
{
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
QUrl::ComponentFormattingOption strOpt = QUrl::EncodeSpaces;
|
||||||
|
#else
|
||||||
|
QUrl::ComponentFormattingOption strOpt = QUrl::FullyEncoded;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QRegExp reg("(<img src=\")([^\"]+)\"");
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
while (pos < p_html.size()) {
|
||||||
|
int idx = p_html.indexOf(reg, pos);
|
||||||
|
if (idx == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString urlStr = reg.cap(2);
|
||||||
|
QUrl imgUrl(urlStr);
|
||||||
|
|
||||||
|
QString fixedStr;
|
||||||
|
if (imgUrl.isRelative()) {
|
||||||
|
fixedStr = p_baseUrl.resolved(imgUrl).toString(strOpt);
|
||||||
|
} else if (imgUrl.isLocalFile()) {
|
||||||
|
fixedStr = imgUrl.toString(strOpt);
|
||||||
|
} else if (imgUrl.scheme() != "https" && imgUrl.scheme() != "http") {
|
||||||
|
QString tmp = imgUrl.toString();
|
||||||
|
if (QFileInfo::exists(tmp)) {
|
||||||
|
fixedStr = QUrl::fromLocalFile(tmp).toString(strOpt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = idx + reg.matchedLength();
|
||||||
|
if (!fixedStr.isEmpty() && urlStr != fixedStr) {
|
||||||
|
qDebug() << "fix img url" << urlStr << fixedStr;
|
||||||
|
// Insert one more space to avoid fix the url twice.
|
||||||
|
pos = pos + fixedStr.size() + 1 - urlStr.size();
|
||||||
|
p_html.replace(idx,
|
||||||
|
reg.matchedLength(),
|
||||||
|
QString("<img src=\"%1\"").arg(fixedStr));
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
18
src/utils/vwebutils.h
Normal file
18
src/utils/vwebutils.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef VWEBUTILS_H
|
||||||
|
#define VWEBUTILS_H
|
||||||
|
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
|
||||||
|
class VWebUtils
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Fix <img src> in @p_html.
|
||||||
|
static bool fixImageSrcInHtml(const QUrl &p_baseUrl, QString &p_html);
|
||||||
|
|
||||||
|
private:
|
||||||
|
VWebUtils();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VWEBUTILS_H
|
@ -287,6 +287,12 @@ void VConfigManager::initialize()
|
|||||||
|
|
||||||
m_fixImageSrcInWebWhenCopied = getConfigFromSettings("web",
|
m_fixImageSrcInWebWhenCopied = getConfigFromSettings("web",
|
||||||
"fix_img_src_when_copied").toBool();
|
"fix_img_src_when_copied").toBool();
|
||||||
|
|
||||||
|
m_stylesToRemoveWhenCopied = getConfigFromSettings("web",
|
||||||
|
"styles_to_remove_when_copied").toStringList();
|
||||||
|
|
||||||
|
m_stylesToInlineWhenCopied = getConfigFromSettings("web",
|
||||||
|
"styles_to_inline_when_copied").toStringList().join(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
void VConfigManager::initSettings()
|
void VConfigManager::initSettings()
|
||||||
|
@ -428,6 +428,10 @@ public:
|
|||||||
|
|
||||||
bool getFixImageSrcInWebWhenCopied() const;
|
bool getFixImageSrcInWebWhenCopied() const;
|
||||||
|
|
||||||
|
const QStringList &getStylesToRemoveWhenCopied() const;
|
||||||
|
|
||||||
|
const QString &getStylesToInlineWhenCopied() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Look up a config from user and default settings.
|
// Look up a config from user and default settings.
|
||||||
QVariant getConfigFromSettings(const QString §ion, const QString &key) const;
|
QVariant getConfigFromSettings(const QString §ion, const QString &key) const;
|
||||||
@ -821,6 +825,12 @@ private:
|
|||||||
// Whether fix the local relative image src in read mode when copied.
|
// Whether fix the local relative image src in read mode when copied.
|
||||||
bool m_fixImageSrcInWebWhenCopied;
|
bool m_fixImageSrcInWebWhenCopied;
|
||||||
|
|
||||||
|
// Styles to be removed when copied in read mode.
|
||||||
|
QStringList m_stylesToRemoveWhenCopied;
|
||||||
|
|
||||||
|
// The string containing styles to inline when copied in edit mode.
|
||||||
|
QString m_stylesToInlineWhenCopied;
|
||||||
|
|
||||||
// The name of the config file in each directory, obsolete.
|
// The name of the config file in each directory, obsolete.
|
||||||
// Use c_dirConfigFile instead.
|
// Use c_dirConfigFile instead.
|
||||||
static const QString c_obsoleteDirConfigFile;
|
static const QString c_obsoleteDirConfigFile;
|
||||||
@ -1993,4 +2003,13 @@ inline bool VConfigManager::getFixImageSrcInWebWhenCopied() const
|
|||||||
return m_fixImageSrcInWebWhenCopied;
|
return m_fixImageSrcInWebWhenCopied;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline const QStringList &VConfigManager::getStylesToRemoveWhenCopied() const
|
||||||
|
{
|
||||||
|
return m_stylesToRemoveWhenCopied;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const QString &VConfigManager::getStylesToInlineWhenCopied() const
|
||||||
|
{
|
||||||
|
return m_stylesToInlineWhenCopied;
|
||||||
|
}
|
||||||
#endif // VCONFIGMANAGER_H
|
#endif // VCONFIGMANAGER_H
|
||||||
|
@ -77,12 +77,27 @@ void VDocument::highlightTextCB(const QString &p_html, int p_id, int p_timeStamp
|
|||||||
emit textHighlighted(p_html, p_id, p_timeStamp);
|
emit textHighlighted(p_html, p_id, p_timeStamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VDocument::textToHtmlAsync(const QString &p_text)
|
||||||
|
{
|
||||||
|
emit requestTextToHtml(p_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VDocument::textToHtmlCB(const QString &p_text, const QString &p_html)
|
||||||
|
{
|
||||||
|
emit textToHtmlFinished(p_text, p_html);
|
||||||
|
}
|
||||||
|
|
||||||
void VDocument::noticeReadyToHighlightText()
|
void VDocument::noticeReadyToHighlightText()
|
||||||
{
|
{
|
||||||
m_readyToHighlight = true;
|
m_readyToHighlight = true;
|
||||||
emit readyToHighlightText();
|
emit readyToHighlightText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VDocument::noticeReadyToTextToHtml()
|
||||||
|
{
|
||||||
|
m_readyToTextToHtml = true;
|
||||||
|
}
|
||||||
|
|
||||||
void VDocument::setFile(const VFile *p_file)
|
void VDocument::setFile(const VFile *p_file)
|
||||||
{
|
{
|
||||||
m_file = p_file;
|
m_file = p_file;
|
||||||
|
@ -29,10 +29,15 @@ public:
|
|||||||
// Use p_id to identify the result.
|
// Use p_id to identify the result.
|
||||||
void highlightTextAsync(const QString &p_text, int p_id, int p_timeStamp);
|
void highlightTextAsync(const QString &p_text, int p_id, int p_timeStamp);
|
||||||
|
|
||||||
|
// Request to convert @p_text to HTML.
|
||||||
|
void textToHtmlAsync(const QString &p_text);
|
||||||
|
|
||||||
void setFile(const VFile *p_file);
|
void setFile(const VFile *p_file);
|
||||||
|
|
||||||
bool isReadyToHighlight() const;
|
bool isReadyToHighlight() const;
|
||||||
|
|
||||||
|
bool isReadyToTextToHtml() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
// Will be called in the HTML side
|
// Will be called in the HTML side
|
||||||
|
|
||||||
@ -49,9 +54,15 @@ public slots:
|
|||||||
void setLog(const QString &p_log);
|
void setLog(const QString &p_log);
|
||||||
void keyPressEvent(int p_key, bool p_ctrl, bool p_shift);
|
void keyPressEvent(int p_key, bool p_ctrl, bool p_shift);
|
||||||
void updateText();
|
void updateText();
|
||||||
|
|
||||||
void highlightTextCB(const QString &p_html, int p_id, int p_timeStamp);
|
void highlightTextCB(const QString &p_html, int p_id, int p_timeStamp);
|
||||||
|
|
||||||
void noticeReadyToHighlightText();
|
void noticeReadyToHighlightText();
|
||||||
|
|
||||||
|
void textToHtmlCB(const QString &p_text, const QString &p_html);
|
||||||
|
|
||||||
|
void noticeReadyToTextToHtml();
|
||||||
|
|
||||||
// Web-side handle logics (MathJax etc.) is finished.
|
// Web-side handle logics (MathJax etc.) is finished.
|
||||||
// But the page may not finish loading, such as images.
|
// But the page may not finish loading, such as images.
|
||||||
void finishLogics();
|
void finishLogics();
|
||||||
@ -65,14 +76,25 @@ signals:
|
|||||||
|
|
||||||
// @anchor is the id of that anchor, without '#'.
|
// @anchor is the id of that anchor, without '#'.
|
||||||
void headerChanged(const QString &anchor);
|
void headerChanged(const QString &anchor);
|
||||||
|
|
||||||
void htmlChanged(const QString &html);
|
void htmlChanged(const QString &html);
|
||||||
|
|
||||||
void logChanged(const QString &p_log);
|
void logChanged(const QString &p_log);
|
||||||
|
|
||||||
void keyPressed(int p_key, bool p_ctrl, bool p_shift);
|
void keyPressed(int p_key, bool p_ctrl, bool p_shift);
|
||||||
|
|
||||||
void requestHighlightText(const QString &p_text, int p_id, int p_timeStamp);
|
void requestHighlightText(const QString &p_text, int p_id, int p_timeStamp);
|
||||||
|
|
||||||
void textHighlighted(const QString &p_html, int p_id, int p_timeStamp);
|
void textHighlighted(const QString &p_html, int p_id, int p_timeStamp);
|
||||||
|
|
||||||
void readyToHighlightText();
|
void readyToHighlightText();
|
||||||
|
|
||||||
void logicsFinished();
|
void logicsFinished();
|
||||||
|
|
||||||
|
void requestTextToHtml(const QString &p_text);
|
||||||
|
|
||||||
|
void textToHtmlFinished(const QString &p_text, const QString &p_html);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_toc;
|
QString m_toc;
|
||||||
QString m_header;
|
QString m_header;
|
||||||
@ -87,10 +109,18 @@ private:
|
|||||||
|
|
||||||
// Whether the web side is ready to handle highlight text request.
|
// Whether the web side is ready to handle highlight text request.
|
||||||
bool m_readyToHighlight;
|
bool m_readyToHighlight;
|
||||||
|
|
||||||
|
// Whether the web side is ready to convert text to html.
|
||||||
|
bool m_readyToTextToHtml;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool VDocument::isReadyToHighlight() const
|
inline bool VDocument::isReadyToHighlight() const
|
||||||
{
|
{
|
||||||
return m_readyToHighlight;
|
return m_readyToHighlight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool VDocument::isReadyToTextToHtml() const
|
||||||
|
{
|
||||||
|
return m_readyToTextToHtml;
|
||||||
|
}
|
||||||
#endif // VDOCUMENT_H
|
#endif // VDOCUMENT_H
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "vnotefile.h"
|
#include "vnotefile.h"
|
||||||
#include "vpreviewmanager.h"
|
#include "vpreviewmanager.h"
|
||||||
#include "utils/viconutils.h"
|
#include "utils/viconutils.h"
|
||||||
|
#include "dialog/vcopytextashtmldialog.h"
|
||||||
|
|
||||||
extern VConfigManager *g_config;
|
extern VConfigManager *g_config;
|
||||||
|
|
||||||
@ -29,7 +30,8 @@ VMdEditor::VMdEditor(VFile *p_file,
|
|||||||
: VTextEdit(p_parent),
|
: VTextEdit(p_parent),
|
||||||
VEditor(p_file, this),
|
VEditor(p_file, this),
|
||||||
m_mdHighlighter(NULL),
|
m_mdHighlighter(NULL),
|
||||||
m_freshEdit(true)
|
m_freshEdit(true),
|
||||||
|
m_textToHtmlDialog(NULL)
|
||||||
{
|
{
|
||||||
Q_ASSERT(p_file->getDocType() == DocType::Markdown);
|
Q_ASSERT(p_file->getDocType() == DocType::Markdown);
|
||||||
|
|
||||||
@ -266,12 +268,19 @@ void VMdEditor::contextMenuEvent(QContextMenuEvent *p_event)
|
|||||||
QMenu *menu = createStandardContextMenu();
|
QMenu *menu = createStandardContextMenu();
|
||||||
menu->setToolTipsVisible(true);
|
menu->setToolTipsVisible(true);
|
||||||
|
|
||||||
const QList<QAction *> actions = menu->actions();
|
VEditTab *editTab = dynamic_cast<VEditTab *>(parent());
|
||||||
|
Q_ASSERT(editTab);
|
||||||
|
if (editTab->isEditMode()) {
|
||||||
|
const QList<QAction *> actions = menu->actions();
|
||||||
|
|
||||||
if (!textCursor().hasSelection()) {
|
if (textCursor().hasSelection()) {
|
||||||
VEditTab *editTab = dynamic_cast<VEditTab *>(parent());
|
QAction *copyAsHtmlAct = new QAction(tr("Copy As &HTML without Background"), menu);
|
||||||
Q_ASSERT(editTab);
|
copyAsHtmlAct->setToolTip(tr("Copy selected contents as HTML without background styles"));
|
||||||
if (editTab->isEditMode()) {
|
connect(copyAsHtmlAct, &QAction::triggered,
|
||||||
|
this, &VMdEditor::handleCopyAsHtmlAction);
|
||||||
|
|
||||||
|
menu->insertAction(actions.isEmpty() ? NULL : actions[0], copyAsHtmlAct);
|
||||||
|
} else {
|
||||||
QAction *saveExitAct = new QAction(VIconUtils::menuIcon(":/resources/icons/save_exit.svg"),
|
QAction *saveExitAct = new QAction(VIconUtils::menuIcon(":/resources/icons/save_exit.svg"),
|
||||||
tr("&Save Changes And Read"),
|
tr("&Save Changes And Read"),
|
||||||
menu);
|
menu);
|
||||||
@ -292,9 +301,10 @@ void VMdEditor::contextMenuEvent(QContextMenuEvent *p_event)
|
|||||||
|
|
||||||
menu->insertAction(actions.isEmpty() ? NULL : actions[0], discardExitAct);
|
menu->insertAction(actions.isEmpty() ? NULL : actions[0], discardExitAct);
|
||||||
menu->insertAction(discardExitAct, saveExitAct);
|
menu->insertAction(discardExitAct, saveExitAct);
|
||||||
if (!actions.isEmpty()) {
|
}
|
||||||
menu->insertSeparator(actions[0]);
|
|
||||||
}
|
if (!actions.isEmpty()) {
|
||||||
|
menu->insertSeparator(actions[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -990,3 +1000,32 @@ void VMdEditor::updateInitAndInsertedImages(bool p_fileChanged, UpdateAction p_a
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VMdEditor::handleCopyAsHtmlAction()
|
||||||
|
{
|
||||||
|
QTextCursor cursor = textCursor();
|
||||||
|
Q_ASSERT(cursor.hasSelection());
|
||||||
|
|
||||||
|
QString text = VEditUtils::selectedText(cursor);
|
||||||
|
Q_ASSERT(!text.isEmpty());
|
||||||
|
|
||||||
|
Q_ASSERT(!m_textToHtmlDialog);
|
||||||
|
m_textToHtmlDialog = new VCopyTextAsHtmlDialog(text, this);
|
||||||
|
|
||||||
|
// For Hoedown, we use marked.js to convert the text to have a general interface.
|
||||||
|
emit requestTextToHtml(text);
|
||||||
|
|
||||||
|
m_textToHtmlDialog->exec();
|
||||||
|
|
||||||
|
delete m_textToHtmlDialog;
|
||||||
|
m_textToHtmlDialog = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VMdEditor::textToHtmlFinished(const QString &p_text,
|
||||||
|
const QUrl &p_baseUrl,
|
||||||
|
const QString &p_html)
|
||||||
|
{
|
||||||
|
if (m_textToHtmlDialog && m_textToHtmlDialog->getText() == p_text) {
|
||||||
|
m_textToHtmlDialog->setConvertedHtml(p_baseUrl, p_html);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
#include "vtextedit.h"
|
#include "vtextedit.h"
|
||||||
#include "veditor.h"
|
#include "veditor.h"
|
||||||
@ -17,6 +18,7 @@ class HGMarkdownHighlighter;
|
|||||||
class VCodeBlockHighlightHelper;
|
class VCodeBlockHighlightHelper;
|
||||||
class VDocument;
|
class VDocument;
|
||||||
class VPreviewManager;
|
class VPreviewManager;
|
||||||
|
class VCopyTextAsHtmlDialog;
|
||||||
|
|
||||||
class VMdEditor : public VTextEdit, public VEditor
|
class VMdEditor : public VTextEdit, public VEditor
|
||||||
{
|
{
|
||||||
@ -68,6 +70,8 @@ public:
|
|||||||
public slots:
|
public slots:
|
||||||
bool jumpTitle(bool p_forward, int p_relativeLevel, int p_repeat) Q_DECL_OVERRIDE;
|
bool jumpTitle(bool p_forward, int p_relativeLevel, int p_repeat) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
void textToHtmlFinished(const QString &p_text, const QUrl &p_baseUrl, const QString &p_html);
|
||||||
|
|
||||||
// Wrapper functions for QPlainTextEdit/QTextEdit.
|
// Wrapper functions for QPlainTextEdit/QTextEdit.
|
||||||
public:
|
public:
|
||||||
void setExtraSelectionsW(const QList<QTextEdit::ExtraSelection> &p_selections) Q_DECL_OVERRIDE
|
void setExtraSelectionsW(const QList<QTextEdit::ExtraSelection> &p_selections) Q_DECL_OVERRIDE
|
||||||
@ -165,6 +169,9 @@ signals:
|
|||||||
// Will be emitted by VImagePreviewer for now.
|
// Will be emitted by VImagePreviewer for now.
|
||||||
void statusChanged();
|
void statusChanged();
|
||||||
|
|
||||||
|
// Request to convert @p_text to Html.
|
||||||
|
void requestTextToHtml(const QString &p_text);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void updateFontAndPalette() Q_DECL_OVERRIDE;
|
void updateFontAndPalette() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
@ -191,6 +198,9 @@ private slots:
|
|||||||
// When there is no header in current cursor, will signal an invalid header.
|
// When there is no header in current cursor, will signal an invalid header.
|
||||||
void updateCurrentHeader();
|
void updateCurrentHeader();
|
||||||
|
|
||||||
|
// Copy selected text as HTML.
|
||||||
|
void handleCopyAsHtmlAction();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Update the config of VTextEdit according to global configurations.
|
// Update the config of VTextEdit according to global configurations.
|
||||||
void updateTextEditConfig();
|
void updateTextEditConfig();
|
||||||
@ -222,5 +232,7 @@ private:
|
|||||||
QVector<VTableOfContentItem> m_headers;
|
QVector<VTableOfContentItem> m_headers;
|
||||||
|
|
||||||
bool m_freshEdit;
|
bool m_freshEdit;
|
||||||
|
|
||||||
|
VCopyTextAsHtmlDialog *m_textToHtmlDialog;
|
||||||
};
|
};
|
||||||
#endif // VMDEDITOR_H
|
#endif // VMDEDITOR_H
|
||||||
|
@ -413,6 +413,11 @@ void VMdTab::setupMarkdownViewer()
|
|||||||
|
|
||||||
tabIsReady(TabReady::ReadMode);
|
tabIsReady(TabReady::ReadMode);
|
||||||
});
|
});
|
||||||
|
connect(m_document, &VDocument::textToHtmlFinished,
|
||||||
|
this, [this](const QString &p_text, const QString &p_html) {
|
||||||
|
Q_ASSERT(m_editor);
|
||||||
|
m_editor->textToHtmlFinished(p_text, m_webViewer->url(), p_html);
|
||||||
|
});
|
||||||
|
|
||||||
page->setWebChannel(channel);
|
page->setWebChannel(channel);
|
||||||
|
|
||||||
@ -464,6 +469,8 @@ void VMdTab::setupMarkdownEditor()
|
|||||||
|
|
||||||
tabIsReady(TabReady::EditMode);
|
tabIsReady(TabReady::EditMode);
|
||||||
});
|
});
|
||||||
|
connect(m_editor, &VMdEditor::requestTextToHtml,
|
||||||
|
this, &VMdTab::textToHtmlViaWebView);
|
||||||
|
|
||||||
enableHeadingSequence(m_enableHeadingSequence);
|
enableHeadingSequence(m_enableHeadingSequence);
|
||||||
m_editor->reloadFile();
|
m_editor->reloadFile();
|
||||||
@ -1006,3 +1013,20 @@ void VMdTab::handleFileOrDirectoryChange(bool p_isFile, UpdateAction p_act)
|
|||||||
m_editor->refreshPreview();
|
m_editor->refreshPreview();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VMdTab::textToHtmlViaWebView(const QString &p_text)
|
||||||
|
{
|
||||||
|
int maxRetry = 50;
|
||||||
|
while (!m_document->isReadyToTextToHtml() && maxRetry > 0) {
|
||||||
|
qDebug() << "wait for web side ready to convert text to HTML";
|
||||||
|
VUtils::sleepWait(100);
|
||||||
|
--maxRetry;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxRetry == 0) {
|
||||||
|
qWarning() << "web side is not ready to convert text to HTML";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_document->textToHtmlAsync(p_text);
|
||||||
|
}
|
||||||
|
@ -184,6 +184,8 @@ private:
|
|||||||
// updateStatus() with only cursor position information.
|
// updateStatus() with only cursor position information.
|
||||||
void updateCursorStatus();
|
void updateCursorStatus();
|
||||||
|
|
||||||
|
void textToHtmlViaWebView(const QString &p_text);
|
||||||
|
|
||||||
VMdEditor *m_editor;
|
VMdEditor *m_editor;
|
||||||
VWebView *m_webViewer;
|
VWebView *m_webViewer;
|
||||||
VDocument *m_document;
|
VDocument *m_document;
|
||||||
|
33
src/vwaitingwidget.cpp
Normal file
33
src/vwaitingwidget.cpp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#include "vwaitingwidget.h"
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
|
||||||
|
VWaitingWidget::VWaitingWidget(QWidget *p_parent)
|
||||||
|
: QWidget(p_parent)
|
||||||
|
{
|
||||||
|
setupUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VWaitingWidget::setupUI()
|
||||||
|
{
|
||||||
|
QSize imgSize(64, 64);
|
||||||
|
QLabel *logoLabel = new QLabel();
|
||||||
|
logoLabel->setPixmap(QPixmap(":/resources/icons/vnote.svg").scaled(imgSize, Qt::KeepAspectRatio));
|
||||||
|
|
||||||
|
QHBoxLayout *layout = new QHBoxLayout();
|
||||||
|
layout->addStretch();
|
||||||
|
layout->addWidget(logoLabel);
|
||||||
|
layout->addStretch();
|
||||||
|
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout();
|
||||||
|
mainLayout->addStretch();
|
||||||
|
mainLayout->addLayout(layout);
|
||||||
|
mainLayout->addStretch();
|
||||||
|
|
||||||
|
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
}
|
19
src/vwaitingwidget.h
Normal file
19
src/vwaitingwidget.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef VWAITINGWIDGET_H
|
||||||
|
#define VWAITINGWIDGET_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class QLabel;
|
||||||
|
|
||||||
|
|
||||||
|
class VWaitingWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit VWaitingWidget(QWidget *p_parent = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupUI();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VWAITINGWIDGET_H
|
101
src/vwebview.cpp
101
src/vwebview.cpp
@ -10,12 +10,12 @@
|
|||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QRegExp>
|
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include "vfile.h"
|
#include "vfile.h"
|
||||||
#include "utils/vclipboardutils.h"
|
#include "utils/vclipboardutils.h"
|
||||||
#include "utils/viconutils.h"
|
#include "utils/viconutils.h"
|
||||||
#include "vconfigmanager.h"
|
#include "vconfigmanager.h"
|
||||||
|
#include "utils/vwebutils.h"
|
||||||
|
|
||||||
extern VConfigManager *g_config;
|
extern VConfigManager *g_config;
|
||||||
|
|
||||||
@ -231,12 +231,50 @@ void VWebView::hideUnusedActions(QMenu *p_menu)
|
|||||||
|
|
||||||
static bool removeBackgroundColor(QString &p_html)
|
static bool removeBackgroundColor(QString &p_html)
|
||||||
{
|
{
|
||||||
QRegExp reg("(\\s|\")background(-color)?:[^;]+;");
|
QRegExp reg("(<[^>]+\\sstyle=[^>]*(\\s|\"))background(-color)?:[^;]+;([^>]*>)");
|
||||||
int size = p_html.size();
|
int size = p_html.size();
|
||||||
p_html.replace(reg, "\\1");
|
p_html.replace(reg, "\\1\\4");
|
||||||
return p_html.size() != size;
|
return p_html.size() != size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VWebView::removeStyles(QString &p_html)
|
||||||
|
{
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
const QStringList &styles = g_config->getStylesToRemoveWhenCopied();
|
||||||
|
if (styles.isEmpty()) {
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRegExp tagReg("(<[^>]+\\sstyle=[^>]*>)");
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
while (pos < p_html.size()) {
|
||||||
|
int idx = p_html.indexOf(tagReg, pos);
|
||||||
|
if (idx == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString styleStr = tagReg.cap(1);
|
||||||
|
QString alteredStyleStr = styleStr;
|
||||||
|
|
||||||
|
QString regPatt("(\\s|\")%1:[^;]+;");
|
||||||
|
for (auto const & sty : styles) {
|
||||||
|
QRegExp reg(regPatt.arg(sty));
|
||||||
|
alteredStyleStr.replace(reg, "\\1");
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = idx + tagReg.matchedLength();
|
||||||
|
if (styleStr != alteredStyleStr) {
|
||||||
|
pos = pos + alteredStyleStr.size() - styleStr.size();
|
||||||
|
p_html.replace(idx, tagReg.matchedLength(), alteredStyleStr);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
void VWebView::handleCopyWithoutBackgroundAction()
|
void VWebView::handleCopyWithoutBackgroundAction()
|
||||||
{
|
{
|
||||||
m_needRemoveBackground = true;
|
m_needRemoveBackground = true;
|
||||||
@ -280,56 +318,6 @@ void VWebView::handleClipboardChanged(QClipboard::Mode p_mode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VWebView::fixImgSrc(QString &p_html)
|
|
||||||
{
|
|
||||||
bool changed = false;
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
QUrl::ComponentFormattingOption strOpt = QUrl::EncodeSpaces;
|
|
||||||
#else
|
|
||||||
QUrl::ComponentFormattingOption strOpt = QUrl::FullyEncoded;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QRegExp reg("(<img src=\")([^\"]+)\"");
|
|
||||||
QUrl baseUrl(url());
|
|
||||||
|
|
||||||
int pos = 0;
|
|
||||||
while (pos < p_html.size()) {
|
|
||||||
int idx = p_html.indexOf(reg, pos);
|
|
||||||
if (idx == -1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString urlStr = reg.cap(2);
|
|
||||||
QUrl imgUrl(urlStr);
|
|
||||||
|
|
||||||
QString fixedStr;
|
|
||||||
if (imgUrl.isRelative()) {
|
|
||||||
fixedStr = baseUrl.resolved(imgUrl).toString(strOpt);
|
|
||||||
} else if (imgUrl.isLocalFile()) {
|
|
||||||
fixedStr = imgUrl.toString(strOpt);
|
|
||||||
} else if (imgUrl.scheme() != "https" && imgUrl.scheme() != "http") {
|
|
||||||
QString tmp = imgUrl.toString();
|
|
||||||
if (QFileInfo::exists(tmp)) {
|
|
||||||
fixedStr = QUrl::fromLocalFile(tmp).toString(strOpt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = idx + reg.matchedLength();
|
|
||||||
if (!fixedStr.isEmpty() && urlStr != fixedStr) {
|
|
||||||
qDebug() << "fix img url" << urlStr << fixedStr;
|
|
||||||
// Insert one more space to avoid fix the url twice.
|
|
||||||
pos = pos + fixedStr.size() + 1 - urlStr.size();
|
|
||||||
p_html.replace(idx,
|
|
||||||
reg.matchedLength(),
|
|
||||||
QString("<img src=\"%1\"").arg(fixedStr));
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VWebView::alterHtmlMimeData(QClipboard *p_clipboard,
|
void VWebView::alterHtmlMimeData(QClipboard *p_clipboard,
|
||||||
const QMimeData *p_mimeData,
|
const QMimeData *p_mimeData,
|
||||||
bool p_removeBackground)
|
bool p_removeBackground)
|
||||||
@ -353,7 +341,12 @@ void VWebView::alterHtmlMimeData(QClipboard *p_clipboard,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fix local relative images.
|
// Fix local relative images.
|
||||||
if (m_fixImgSrc && fixImgSrc(html)) {
|
if (m_fixImgSrc && VWebUtils::fixImageSrcInHtml(url(), html)) {
|
||||||
|
altered = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix margin and padding.
|
||||||
|
if (removeStyles(html)) {
|
||||||
altered = true;
|
altered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <QWebEngineView>
|
#include <QWebEngineView>
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
|
#include <QRegExp>
|
||||||
|
|
||||||
class VFile;
|
class VFile;
|
||||||
class QMenu;
|
class QMenu;
|
||||||
@ -42,11 +43,11 @@ private:
|
|||||||
const QMimeData *p_mimeData,
|
const QMimeData *p_mimeData,
|
||||||
bool p_removeBackground);
|
bool p_removeBackground);
|
||||||
|
|
||||||
bool fixImgSrc(QString &p_html);
|
|
||||||
|
|
||||||
void removeHtmlFromImageData(QClipboard *p_clipboard,
|
void removeHtmlFromImageData(QClipboard *p_clipboard,
|
||||||
const QMimeData *p_mimeData);
|
const QMimeData *p_mimeData);
|
||||||
|
|
||||||
|
bool removeStyles(QString &p_html);
|
||||||
|
|
||||||
VFile *m_file;
|
VFile *m_file;
|
||||||
|
|
||||||
// Whether this view has hooked the Copy Image Url action.
|
// Whether this view has hooked the Copy Image Url action.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user