mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
refine copy HTML logics
This commit is contained in:
parent
9dad67739a
commit
14df9e6e90
@ -13,8 +13,12 @@
|
|||||||
|
|
||||||
extern VConfigManager *g_config;
|
extern VConfigManager *g_config;
|
||||||
|
|
||||||
VCopyTextAsHtmlDialog::VCopyTextAsHtmlDialog(const QString &p_text, QWidget *p_parent)
|
extern VWebUtils *g_webUtils;
|
||||||
: QDialog(p_parent), m_text(p_text)
|
|
||||||
|
VCopyTextAsHtmlDialog::VCopyTextAsHtmlDialog(const QString &p_text,
|
||||||
|
const QString &p_copyTarget,
|
||||||
|
QWidget *p_parent)
|
||||||
|
: QDialog(p_parent), m_text(p_text), m_copyTarget(p_copyTarget)
|
||||||
{
|
{
|
||||||
setupUI();
|
setupUI();
|
||||||
}
|
}
|
||||||
@ -47,7 +51,7 @@ void VCopyTextAsHtmlDialog::setupUI()
|
|||||||
mainLayout->addWidget(m_btnBox);
|
mainLayout->addWidget(m_btnBox);
|
||||||
|
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
setWindowTitle(tr("Copy Text As HTML"));
|
setWindowTitle(tr("Copy Text As HTML (%1)").arg(m_copyTarget));
|
||||||
|
|
||||||
setHtmlVisible(false);
|
setHtmlVisible(false);
|
||||||
}
|
}
|
||||||
@ -61,16 +65,11 @@ void VCopyTextAsHtmlDialog::setHtmlVisible(bool p_visible)
|
|||||||
void VCopyTextAsHtmlDialog::setConvertedHtml(const QUrl &p_baseUrl,
|
void VCopyTextAsHtmlDialog::setConvertedHtml(const QUrl &p_baseUrl,
|
||||||
const QString &p_html)
|
const QString &p_html)
|
||||||
{
|
{
|
||||||
QString html = QString("<html><body>%1</body></html>").arg(p_html);
|
QString html = p_html;
|
||||||
m_htmlViewer->setHtml(html, p_baseUrl);
|
m_htmlViewer->setHtml("<html><body>" + html + "</body></html>", p_baseUrl);
|
||||||
setHtmlVisible(true);
|
setHtmlVisible(true);
|
||||||
|
|
||||||
VWebUtils::translateColors(html);
|
g_webUtils->alterHtmlAsTarget(p_baseUrl, html, m_copyTarget);
|
||||||
|
|
||||||
// Fix image source.
|
|
||||||
if (g_config->getFixImageSrcInWebWhenCopied()) {
|
|
||||||
VWebUtils::fixImageSrcInHtml(p_baseUrl, html);
|
|
||||||
}
|
|
||||||
|
|
||||||
QClipboard *clipboard = QApplication::clipboard();
|
QClipboard *clipboard = QApplication::clipboard();
|
||||||
QMimeData *data = new QMimeData();
|
QMimeData *data = new QMimeData();
|
||||||
|
@ -15,7 +15,9 @@ class VCopyTextAsHtmlDialog : public QDialog
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
VCopyTextAsHtmlDialog(const QString &p_text, QWidget *p_parent = nullptr);
|
VCopyTextAsHtmlDialog(const QString &p_text,
|
||||||
|
const QString &p_copyTarget,
|
||||||
|
QWidget *p_parent = nullptr);
|
||||||
|
|
||||||
void setConvertedHtml(const QUrl &p_baseUrl, const QString &p_html);
|
void setConvertedHtml(const QUrl &p_baseUrl, const QString &p_html);
|
||||||
|
|
||||||
@ -37,6 +39,8 @@ private:
|
|||||||
QDialogButtonBox *m_btnBox;
|
QDialogButtonBox *m_btnBox;
|
||||||
|
|
||||||
QString m_text;
|
QString m_text;
|
||||||
|
|
||||||
|
QString m_copyTarget;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const QString &VCopyTextAsHtmlDialog::getText() const
|
inline const QString &VCopyTextAsHtmlDialog::getText() const
|
||||||
|
@ -193,17 +193,31 @@ custom_colors=White:#FFFFFF,LightGrey:#EEEEEE
|
|||||||
; 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_CHTML
|
||||||
|
|
||||||
; Fix local relative image source when copied
|
; Styles to be removed when copied
|
||||||
fix_img_src_when_copied=true
|
|
||||||
|
|
||||||
; Styles to be removed when copied in read mode
|
|
||||||
; style1,style2,style3
|
; style1,style2,style3
|
||||||
styles_to_remove_when_copied=margin,margin-left,margin-right,padding,padding-left,padding-right
|
styles_to_remove_when_copied=
|
||||||
|
|
||||||
|
; Styles when transform <mark> to <span>
|
||||||
|
style_of_span_for_mark="background-color: #FFFF00;"
|
||||||
|
|
||||||
; CSS properties to embed as inline styles when copied in edit mode
|
; CSS properties to embed as inline styles when copied in edit mode
|
||||||
; tag1:tag2:tag3$property1:property2:property3,tag4:tag5$property2:property3
|
; tag1:tag2:tag3$property1:property2:property3,tag4:tag5$property2:property3
|
||||||
; "all" for all tags not specified explicitly
|
; "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
|
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:background-color,code$font-family:font-size:line-height:color:display:overfow-x:background-color,li$line-height:background-color,a$color:vertical-align:background-color,pre$display:overflow-y:overflow-x:color:font-size:font-style:font-weight:letter-spacing:text-align:text-indent:word-spacing:background-color
|
||||||
|
|
||||||
|
; Define targets the copied content will be pasted into
|
||||||
|
; target_name$action1:action2:action3,targeet_name2$action2:action3
|
||||||
|
; Available actions:
|
||||||
|
; s - add surrounding tags <html><body>
|
||||||
|
; b(tag1|tag2) - remove background color of all tags except tag1 and tag2
|
||||||
|
; c(tag1|tag2) - translate colors using palette defined mapping except tag1 and tag2
|
||||||
|
; i - fix local relative <img src>
|
||||||
|
; m(tag1|tag2) - remove margin/margin-left/margin-right/padding/padding-left/padding-right of all tags except tag1 and tag2
|
||||||
|
; r - raw html with all styles removed
|
||||||
|
; a - transform <mark> to <span>
|
||||||
|
; x(tag1|tag2) - remove styles specified in [styles_to_inline_when_copied] of all tags except tag1 and tag2
|
||||||
|
; p - replace the background color of <pre> with that of its child <code>
|
||||||
|
copy_targets=WithoutBackground$s:b(mark):c:i:x,OneNote$s:b(mark):c:i:m:a:x,MicroSoftWord$s:p:b(mark|pre):c(pre):i:m:a:x,RawHTML$r
|
||||||
|
|
||||||
[shortcuts]
|
[shortcuts]
|
||||||
; Define shortcuts here, with each item in the form "operation=keysequence".
|
; Define shortcuts here, with each item in the form "operation=keysequence".
|
||||||
|
@ -5,14 +5,79 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include "vpalette.h"
|
#include "vpalette.h"
|
||||||
|
#include "vconfigmanager.h"
|
||||||
|
|
||||||
extern VPalette *g_palette;
|
extern VPalette *g_palette;
|
||||||
|
|
||||||
|
extern VConfigManager *g_config;
|
||||||
|
|
||||||
VWebUtils::VWebUtils()
|
VWebUtils::VWebUtils()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VWebUtils::fixImageSrcInHtml(const QUrl &p_baseUrl, QString &p_html)
|
void VWebUtils::init()
|
||||||
|
{
|
||||||
|
m_stylesToRemoveWhenCopied = g_config->getStylesToRemoveWhenCopied();
|
||||||
|
|
||||||
|
m_styleOfSpanForMark = g_config->getStyleOfSpanForMark();
|
||||||
|
|
||||||
|
m_tagReg = QRegExp("<([^>/\\s]+)([^>]*)>");
|
||||||
|
|
||||||
|
m_styleTagReg = QRegExp("<([^>\\s]+)([^>]*\\s)style=\"([^\">]+)\"([^>]*)>");
|
||||||
|
|
||||||
|
initCopyTargets(g_config->getCopyTargets());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VWebUtils::initCopyTargets(const QStringList &p_str)
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_copyTargets.isEmpty());
|
||||||
|
// cap(1): action;
|
||||||
|
// cap(3): arguments;
|
||||||
|
QRegExp actReg("([0-9a-zA-Z])(\\(([^\\)]*)\\))?");
|
||||||
|
|
||||||
|
for (auto const & str : p_str) {
|
||||||
|
auto vals = str.split('$');
|
||||||
|
if (vals.size() != 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CopyTarget tar;
|
||||||
|
tar.m_name = vals[0];
|
||||||
|
if (tar.m_name.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto acts = vals[1].split(':');
|
||||||
|
for (auto const & it : acts) {
|
||||||
|
if (it.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!actReg.exactMatch(it)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actReg.cap(1).size() != 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CopyTargetAction act;
|
||||||
|
act.m_act = actReg.cap(1)[0];
|
||||||
|
|
||||||
|
if (!actReg.cap(3).isEmpty()) {
|
||||||
|
act.m_args = actReg.cap(3).toLower().split('|');
|
||||||
|
}
|
||||||
|
|
||||||
|
tar.m_actions.append(act);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_copyTargets.append(tar);
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "init" << m_copyTargets.size() << "copy targets";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VWebUtils::fixImageSrc(const QUrl &p_baseUrl, QString &p_html)
|
||||||
{
|
{
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
@ -61,15 +126,142 @@ bool VWebUtils::fixImageSrcInHtml(const QUrl &p_baseUrl, QString &p_html)
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VWebUtils::removeBackgroundColor(QString &p_html)
|
QStringList VWebUtils::getCopyTargetsName() const
|
||||||
{
|
{
|
||||||
QRegExp reg("(<[^>]+\\sstyle=[^>]*(\\s|\"))background(-color)?:[^;]+;([^>]*>)");
|
QStringList names;
|
||||||
int size = p_html.size();
|
for (auto const & it : m_copyTargets) {
|
||||||
p_html.replace(reg, "\\1\\4");
|
names << it.m_name;
|
||||||
return p_html.size() != size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VWebUtils::translateColors(QString &p_html)
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VWebUtils::alterHtmlAsTarget(const QUrl &p_baseUrl, QString &p_html, const QString &p_target) const
|
||||||
|
{
|
||||||
|
int idx = targetIndex(p_target);
|
||||||
|
if (idx == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool altered = false;
|
||||||
|
for (auto const & act : m_copyTargets[idx].m_actions) {
|
||||||
|
if (const_cast<VWebUtils *>(this)->alterHtmlByTargetAction(p_baseUrl, p_html, act)) {
|
||||||
|
altered = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return altered;
|
||||||
|
}
|
||||||
|
|
||||||
|
int VWebUtils::targetIndex(const QString &p_target) const
|
||||||
|
{
|
||||||
|
if (p_target.isEmpty()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < m_copyTargets.size(); ++i) {
|
||||||
|
if (m_copyTargets[i].m_name == p_target) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VWebUtils::alterHtmlByTargetAction(const QUrl &p_baseUrl, QString &p_html, const CopyTargetAction &p_action)
|
||||||
|
{
|
||||||
|
bool altered = false;
|
||||||
|
switch (p_action.m_act.toLatin1()) {
|
||||||
|
case 's':
|
||||||
|
if (!p_html.startsWith("<html>")) {
|
||||||
|
p_html = "<html><body>" + p_html + "</body></html>";
|
||||||
|
altered = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'b':
|
||||||
|
altered = removeBackgroundColor(p_html, p_action.m_args);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
altered = translateColors(p_html, p_action.m_args);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'i':
|
||||||
|
altered = fixImageSrc(p_baseUrl, p_html);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'm':
|
||||||
|
altered = removeMarginPadding(p_html, p_action.m_args);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'x':
|
||||||
|
altered = removeStylesToRemoveWhenCopied(p_html, p_action.m_args);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
altered = removeAllStyles(p_html, p_action.m_args);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'a':
|
||||||
|
altered = transformMarkToSpan(p_html);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
altered = replacePreBackgroundColorWithCode(p_html);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return altered;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int skipToTagEnd(const QString &p_html, int p_pos, const QString &p_tag)
|
||||||
|
{
|
||||||
|
QRegExp beginReg(QString("<%1 ").arg(p_tag));
|
||||||
|
QRegExp endReg(QString("</%1>").arg(p_tag));
|
||||||
|
|
||||||
|
int pos = p_pos;
|
||||||
|
int nBegin = p_html.indexOf(beginReg, pos);
|
||||||
|
int nEnd = p_html.indexOf(endReg, pos);
|
||||||
|
if (nBegin > -1 && nBegin < nEnd) {
|
||||||
|
// Nested tag.
|
||||||
|
pos = skipToTagEnd(p_html, nBegin + beginReg.matchedLength(), p_tag);
|
||||||
|
nEnd = p_html.indexOf(endReg, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nEnd > -1) {
|
||||||
|
pos = nEnd + endReg.matchedLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @p_html is the style string.
|
||||||
|
static bool removeStylesInStyleString(QString &p_html, const QStringList &p_styles)
|
||||||
|
{
|
||||||
|
if (p_styles.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int size = p_html.size();
|
||||||
|
QRegExp reg(QString("(\\s|^)(%1):[^:]+;").arg(p_styles.join('|')));
|
||||||
|
p_html.remove(reg);
|
||||||
|
|
||||||
|
return size != p_html.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VWebUtils::removeBackgroundColor(QString &p_html, const QStringList &p_skipTags)
|
||||||
|
{
|
||||||
|
QStringList styles({"background", "background-color"});
|
||||||
|
|
||||||
|
return removeStyles(p_html, p_skipTags, styles);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VWebUtils::translateColors(QString &p_html, const QStringList &p_skipTags)
|
||||||
{
|
{
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
@ -78,20 +270,34 @@ bool VWebUtils::translateColors(QString &p_html)
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
QRegExp tagReg("(<[^>]+\\sstyle=[^>]*>)");
|
|
||||||
// Won't mixed up with background-color.
|
// Won't mixed up with background-color.
|
||||||
QRegExp colorReg("(\\s|\")color:([^;]+);");
|
QRegExp colorReg("(\\s|^)color:([^;]+);");
|
||||||
|
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
while (pos < p_html.size()) {
|
while (pos < p_html.size()) {
|
||||||
int idx = p_html.indexOf(tagReg, pos);
|
int tagIdx = p_html.indexOf(m_tagReg, pos);
|
||||||
if (idx == -1) {
|
if (tagIdx == -1) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString styleStr = tagReg.cap(1);
|
QString tagName = m_tagReg.cap(1);
|
||||||
QString alteredStyleStr = styleStr;
|
if (p_skipTags.contains(tagName.toLower())) {
|
||||||
|
// Skip this tag.
|
||||||
|
pos = skipToTagEnd(p_html, tagIdx + m_tagReg.matchedLength(), tagName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = tagIdx;
|
||||||
|
int idx = p_html.indexOf(m_styleTagReg, pos);
|
||||||
|
if (idx == -1) {
|
||||||
|
break;
|
||||||
|
} else if (idx != tagIdx) {
|
||||||
|
pos = tagIdx + m_tagReg.matchedLength();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString styleStr = m_styleTagReg.cap(3);
|
||||||
|
QString alteredStyleStr = styleStr;
|
||||||
int posb = 0;
|
int posb = 0;
|
||||||
while (posb < alteredStyleStr.size()) {
|
while (posb < alteredStyleStr.size()) {
|
||||||
int idxb = alteredStyleStr.indexOf(colorReg, posb);
|
int idxb = alteredStyleStr.indexOf(colorReg, posb);
|
||||||
@ -108,19 +314,280 @@ bool VWebUtils::translateColors(QString &p_html)
|
|||||||
|
|
||||||
// Replace the color.
|
// Replace the color.
|
||||||
QString newCol = it.value();
|
QString newCol = it.value();
|
||||||
// Add one extra space between color and :.
|
// Should not add extra space before :.
|
||||||
QString newStr = QString("%1color: %2;").arg(colorReg.cap(1)).arg(newCol);
|
QString newStr = QString("%1color: %2;").arg(colorReg.cap(1)).arg(newCol);
|
||||||
alteredStyleStr.replace(idxb, colorReg.matchedLength(), newStr);
|
alteredStyleStr.replace(idxb, colorReg.matchedLength(), newStr);
|
||||||
posb = idxb + newStr.size();
|
posb = idxb + newStr.size();
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = idx + tagReg.matchedLength();
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
pos = pos + alteredStyleStr.size() - styleStr.size();
|
QString newTag = QString("<%1%2style=\"%3\"%4>").arg(m_styleTagReg.cap(1))
|
||||||
p_html.replace(idx, tagReg.matchedLength(), alteredStyleStr);
|
.arg(m_styleTagReg.cap(2))
|
||||||
|
.arg(alteredStyleStr)
|
||||||
|
.arg(m_styleTagReg.cap(4));
|
||||||
|
|
||||||
|
p_html.replace(idx, m_styleTagReg.matchedLength(), newTag);
|
||||||
|
|
||||||
|
pos = idx + newTag.size();
|
||||||
|
} else {
|
||||||
|
pos = idx + m_styleTagReg.matchedLength();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VWebUtils::removeMarginPadding(QString &p_html, const QStringList &p_skipTags)
|
||||||
|
{
|
||||||
|
QStringList styles({"margin", "margin-left", "margin-right",
|
||||||
|
"padding", "padding-left", "padding-right"});
|
||||||
|
|
||||||
|
return removeStyles(p_html, p_skipTags, styles);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VWebUtils::removeStyles(QString &p_html, const QStringList &p_skipTags, const QStringList &p_styles)
|
||||||
|
{
|
||||||
|
if (p_styles.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool altered = false;
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
while (pos < p_html.size()) {
|
||||||
|
int tagIdx = p_html.indexOf(m_tagReg, pos);
|
||||||
|
if (tagIdx == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString tagName = m_tagReg.cap(1);
|
||||||
|
if (p_skipTags.contains(tagName.toLower())) {
|
||||||
|
// Skip this tag.
|
||||||
|
pos = skipToTagEnd(p_html, tagIdx + m_tagReg.matchedLength(), tagName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = tagIdx;
|
||||||
|
int idx = p_html.indexOf(m_styleTagReg, pos);
|
||||||
|
if (idx == -1) {
|
||||||
|
break;
|
||||||
|
} else if (idx != tagIdx) {
|
||||||
|
pos = tagIdx + m_tagReg.matchedLength();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString styleStr = m_styleTagReg.cap(3);
|
||||||
|
if (removeStylesInStyleString(styleStr, p_styles)) {
|
||||||
|
QString newTag = QString("<%1%2style=\"%3\"%4>").arg(m_styleTagReg.cap(1))
|
||||||
|
.arg(m_styleTagReg.cap(2))
|
||||||
|
.arg(styleStr)
|
||||||
|
.arg(m_styleTagReg.cap(4));
|
||||||
|
p_html.replace(idx, m_styleTagReg.matchedLength(), newTag);
|
||||||
|
|
||||||
|
pos = idx + newTag.size();
|
||||||
|
|
||||||
|
altered = true;
|
||||||
|
} else {
|
||||||
|
pos = idx + m_styleTagReg.matchedLength();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return altered;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VWebUtils::removeStylesToRemoveWhenCopied(QString &p_html, const QStringList &p_skipTags)
|
||||||
|
{
|
||||||
|
return removeStyles(p_html, p_skipTags, m_stylesToRemoveWhenCopied);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VWebUtils::removeAllStyles(QString &p_html, const QStringList &p_skipTags)
|
||||||
|
{
|
||||||
|
bool altered = false;
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
while (pos < p_html.size()) {
|
||||||
|
int tagIdx = p_html.indexOf(m_tagReg, pos);
|
||||||
|
if (tagIdx == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString tagName = m_tagReg.cap(1);
|
||||||
|
if (p_skipTags.contains(tagName.toLower())) {
|
||||||
|
// Skip this tag.
|
||||||
|
pos = skipToTagEnd(p_html, tagIdx + m_tagReg.matchedLength(), tagName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = tagIdx;
|
||||||
|
int idx = p_html.indexOf(m_styleTagReg, pos);
|
||||||
|
if (idx == -1) {
|
||||||
|
break;
|
||||||
|
} else if (idx != tagIdx) {
|
||||||
|
pos = tagIdx + m_tagReg.matchedLength();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString newTag = QString("<%1%2%3>").arg(m_styleTagReg.cap(1))
|
||||||
|
.arg(m_styleTagReg.cap(2))
|
||||||
|
.arg(m_styleTagReg.cap(4));
|
||||||
|
p_html.replace(idx, m_styleTagReg.matchedLength(), newTag);
|
||||||
|
|
||||||
|
pos = idx + newTag.size();
|
||||||
|
|
||||||
|
altered = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return altered;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VWebUtils::transformMarkToSpan(QString &p_html)
|
||||||
|
{
|
||||||
|
bool altered = false;
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
while (pos < p_html.size()) {
|
||||||
|
int tagIdx = p_html.indexOf(m_tagReg, pos);
|
||||||
|
if (tagIdx == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString tagName = m_tagReg.cap(1);
|
||||||
|
if (tagName.toLower() != "mark") {
|
||||||
|
pos = tagIdx + m_tagReg.matchedLength();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = tagIdx;
|
||||||
|
int idx = p_html.indexOf(m_styleTagReg, pos);
|
||||||
|
if (idx == -1 || idx != tagIdx) {
|
||||||
|
// <mark> without "style".
|
||||||
|
QString newTag = QString("<span style=\"%1\" %2>").arg(m_styleOfSpanForMark)
|
||||||
|
.arg(m_tagReg.cap(2));
|
||||||
|
p_html.replace(tagIdx, m_tagReg.matchedLength(), newTag);
|
||||||
|
|
||||||
|
pos = tagIdx + newTag.size();
|
||||||
|
|
||||||
|
altered = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString newTag = QString("<span%1style=\"%2\"%3>").arg(m_styleTagReg.cap(2))
|
||||||
|
.arg(m_styleTagReg.cap(3) + m_styleOfSpanForMark)
|
||||||
|
.arg(m_styleTagReg.cap(4));
|
||||||
|
p_html.replace(idx, m_styleTagReg.matchedLength(), newTag);
|
||||||
|
|
||||||
|
pos = idx + newTag.size();
|
||||||
|
|
||||||
|
altered = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (altered) {
|
||||||
|
// Replace all </mark> with </span>.
|
||||||
|
p_html.replace("</mark>", "</span>");
|
||||||
|
}
|
||||||
|
|
||||||
|
return altered;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VWebUtils::replacePreBackgroundColorWithCode(QString &p_html)
|
||||||
|
{
|
||||||
|
if (p_html.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool altered = false;
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
QRegExp bgReg("(\\s|^)(background(-color)?:[^;]+;)");
|
||||||
|
|
||||||
|
while (pos < p_html.size()) {
|
||||||
|
int tagIdx = p_html.indexOf(m_tagReg, pos);
|
||||||
|
if (tagIdx == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString tagName = m_tagReg.cap(1);
|
||||||
|
pos = tagIdx + m_tagReg.matchedLength();
|
||||||
|
if (tagName.toLower() != "pre") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int preEnd = skipToTagEnd(p_html, pos, tagName);
|
||||||
|
|
||||||
|
HtmlTag nextTag = readNextTag(p_html, pos);
|
||||||
|
if (nextTag.m_name != "code"
|
||||||
|
|| nextTag.m_start >= preEnd
|
||||||
|
|| nextTag.m_style.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the background style of <code>.
|
||||||
|
int idx = nextTag.m_style.indexOf(bgReg);
|
||||||
|
if (idx == -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString bgStyle = bgReg.cap(2);
|
||||||
|
|
||||||
|
pos = tagIdx;
|
||||||
|
idx = p_html.indexOf(m_styleTagReg, pos);
|
||||||
|
if (idx == -1 || idx != tagIdx) {
|
||||||
|
// <pre> without "style".
|
||||||
|
QString newTag = QString("<%1 style=\"%2\" %3>").arg(m_tagReg.cap(1))
|
||||||
|
.arg(bgStyle)
|
||||||
|
.arg(m_tagReg.cap(2));
|
||||||
|
p_html.replace(tagIdx, m_tagReg.matchedLength(), newTag);
|
||||||
|
|
||||||
|
pos = tagIdx + newTag.size();
|
||||||
|
|
||||||
|
altered = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString newTag;
|
||||||
|
if (m_styleTagReg.cap(3).indexOf(bgReg) == -1) {
|
||||||
|
// No background style specified.
|
||||||
|
newTag = QString("<%1%2style=\"%3\"%4>").arg(m_styleTagReg.cap(1))
|
||||||
|
.arg(m_styleTagReg.cap(2))
|
||||||
|
.arg(m_styleTagReg.cap(3) + bgStyle)
|
||||||
|
.arg(m_styleTagReg.cap(4));
|
||||||
|
} else {
|
||||||
|
// Replace background style.
|
||||||
|
newTag = QString("<%1%2style=\"%3\"%4>").arg(m_styleTagReg.cap(1))
|
||||||
|
.arg(m_styleTagReg.cap(2))
|
||||||
|
.arg(m_styleTagReg.cap(3).replace(bgReg, " " + bgStyle))
|
||||||
|
.arg(m_styleTagReg.cap(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
p_html.replace(idx, m_styleTagReg.matchedLength(), newTag);
|
||||||
|
|
||||||
|
pos = idx + newTag.size();
|
||||||
|
|
||||||
|
altered = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return altered;
|
||||||
|
}
|
||||||
|
|
||||||
|
VWebUtils::HtmlTag VWebUtils::readNextTag(const QString &p_html, int p_pos)
|
||||||
|
{
|
||||||
|
HtmlTag tag;
|
||||||
|
|
||||||
|
int tagIdx = p_html.indexOf(m_tagReg, p_pos);
|
||||||
|
if (tagIdx == -1) {
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag.m_name = m_tagReg.cap(1);
|
||||||
|
tag.m_start = tagIdx;
|
||||||
|
tag.m_end = skipToTagEnd(p_html, tagIdx + m_tagReg.matchedLength(), tag.m_name);
|
||||||
|
|
||||||
|
int idx = p_html.indexOf(m_styleTagReg, tagIdx);
|
||||||
|
if (idx == -1 || idx != tagIdx) {
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag.m_style = m_styleTagReg.cap(3);
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
@ -3,22 +3,114 @@
|
|||||||
|
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QVector>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QRegExp>
|
||||||
|
|
||||||
|
|
||||||
class VWebUtils
|
class VWebUtils
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Fix <img src> in @p_html.
|
VWebUtils();
|
||||||
static bool fixImageSrcInHtml(const QUrl &p_baseUrl, QString &p_html);
|
|
||||||
|
|
||||||
// Remove background color style in @p_html.
|
void init();
|
||||||
static bool removeBackgroundColor(QString &p_html);
|
|
||||||
|
|
||||||
// Translate color styles in @p_html using mappings from VPalette.
|
QStringList getCopyTargetsName() const;
|
||||||
static bool translateColors(QString &p_html);
|
|
||||||
|
// Alter @p_html using @p_target.
|
||||||
|
// Returns true if @p_html is modified.
|
||||||
|
bool alterHtmlAsTarget(const QUrl &p_baseUrl, QString &p_html, const QString &p_target) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VWebUtils();
|
struct CopyTargetAction
|
||||||
|
{
|
||||||
|
QChar m_act;
|
||||||
|
|
||||||
|
QStringList m_args;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CopyTarget
|
||||||
|
{
|
||||||
|
QString m_name;
|
||||||
|
|
||||||
|
QVector<CopyTargetAction> m_actions;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HtmlTag
|
||||||
|
{
|
||||||
|
HtmlTag()
|
||||||
|
: m_start(-1), m_end(-1)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNull()
|
||||||
|
{
|
||||||
|
return m_name.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString m_name;
|
||||||
|
QString m_style;
|
||||||
|
|
||||||
|
int m_start;
|
||||||
|
int m_end;
|
||||||
|
};
|
||||||
|
|
||||||
|
void initCopyTargets(const QStringList &p_str);
|
||||||
|
|
||||||
|
// Return the index in m_copyTargets of @p_target.
|
||||||
|
int targetIndex(const QString &p_target) const;
|
||||||
|
|
||||||
|
bool alterHtmlByTargetAction(const QUrl &p_baseUrl, QString &p_html, const CopyTargetAction &p_action);
|
||||||
|
|
||||||
|
// Remove background color style in @p_html of all tags except @p_skipTags.
|
||||||
|
bool removeBackgroundColor(QString &p_html, const QStringList &p_skipTags);
|
||||||
|
|
||||||
|
// Translate color styles in @p_html using mappings from VPalette.
|
||||||
|
bool translateColors(QString &p_html, const QStringList &p_skipTags);
|
||||||
|
|
||||||
|
// Fix <img src> in @p_html.
|
||||||
|
bool fixImageSrc(const QUrl &p_baseUrl, QString &p_html);
|
||||||
|
|
||||||
|
// Remove margin/padding/margin-left/right/padding-left/right.
|
||||||
|
bool removeMarginPadding(QString &p_html, const QStringList &p_skipTags);
|
||||||
|
|
||||||
|
bool removeStyles(QString &p_html, const QStringList &p_skipTags, const QStringList &p_styles);
|
||||||
|
|
||||||
|
// Remove styles specified in [web]/styles_to_remove_when_copied.
|
||||||
|
bool removeStylesToRemoveWhenCopied(QString &p_html, const QStringList &p_skipTags);
|
||||||
|
|
||||||
|
// Remove all styles.
|
||||||
|
bool removeAllStyles(QString &p_html, const QStringList &p_skipTags);
|
||||||
|
|
||||||
|
// Transform <mark> to <span>.
|
||||||
|
bool transformMarkToSpan(QString &p_html);
|
||||||
|
|
||||||
|
// Replace the background color of <pre> with that of its child <code>.
|
||||||
|
bool replacePreBackgroundColorWithCode(QString &p_html);
|
||||||
|
|
||||||
|
VWebUtils::HtmlTag readNextTag(const QString &p_html, int p_pos);
|
||||||
|
|
||||||
|
QVector<CopyTarget> m_copyTargets;
|
||||||
|
|
||||||
|
// Custom styles to remove when copied.
|
||||||
|
QStringList m_stylesToRemoveWhenCopied;
|
||||||
|
|
||||||
|
// Style of <span> which is transformed from <mark>.
|
||||||
|
QString m_styleOfSpanForMark;
|
||||||
|
|
||||||
|
// Html start tag.
|
||||||
|
// Captured texts:
|
||||||
|
// 1. The tag name like 'code';
|
||||||
|
// 2. Text after tag name and before the end '>';
|
||||||
|
QRegExp m_tagReg;
|
||||||
|
|
||||||
|
// Html start tag with "style" defined.
|
||||||
|
// Captured texts:
|
||||||
|
// 1. The tag name like 'code';
|
||||||
|
// 2. Text before 'style=""';
|
||||||
|
// 3. Text inside 'style=""';
|
||||||
|
// 4. Text after 'style=""' and before '>';
|
||||||
|
QRegExp m_styleTagReg;
|
||||||
|
};
|
||||||
#endif // VWEBUTILS_H
|
#endif // VWEBUTILS_H
|
||||||
|
@ -285,12 +285,6 @@ void VConfigManager::initialize()
|
|||||||
m_closeBeforeExternalEditor = getConfigFromSettings("global",
|
m_closeBeforeExternalEditor = getConfigFromSettings("global",
|
||||||
"close_before_external_editor").toBool();
|
"close_before_external_editor").toBool();
|
||||||
|
|
||||||
m_fixImageSrcInWebWhenCopied = getConfigFromSettings("web",
|
|
||||||
"fix_img_src_when_copied").toBool();
|
|
||||||
|
|
||||||
m_stylesToRemoveWhenCopied = getConfigFromSettings("web",
|
|
||||||
"styles_to_remove_when_copied").toStringList();
|
|
||||||
|
|
||||||
m_stylesToInlineWhenCopied = getConfigFromSettings("web",
|
m_stylesToInlineWhenCopied = getConfigFromSettings("web",
|
||||||
"styles_to_inline_when_copied").toStringList().join(",");
|
"styles_to_inline_when_copied").toStringList().join(",");
|
||||||
}
|
}
|
||||||
|
@ -426,12 +426,15 @@ public:
|
|||||||
|
|
||||||
bool getCloseBeforeExternalEditor() const;
|
bool getCloseBeforeExternalEditor() const;
|
||||||
|
|
||||||
bool getFixImageSrcInWebWhenCopied() const;
|
QStringList getStylesToRemoveWhenCopied() const;
|
||||||
|
|
||||||
const QStringList &getStylesToRemoveWhenCopied() const;
|
|
||||||
|
|
||||||
const QString &getStylesToInlineWhenCopied() const;
|
const QString &getStylesToInlineWhenCopied() const;
|
||||||
|
|
||||||
|
QString getStyleOfSpanForMark() const;
|
||||||
|
|
||||||
|
// Return [web]/copy_targets.
|
||||||
|
QStringList getCopyTargets() 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;
|
||||||
@ -822,12 +825,6 @@ private:
|
|||||||
// Whether user has reset the configurations.
|
// Whether user has reset the configurations.
|
||||||
bool m_hasReset;
|
bool m_hasReset;
|
||||||
|
|
||||||
// Whether fix the local relative image src in read mode when copied.
|
|
||||||
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.
|
// The string containing styles to inline when copied in edit mode.
|
||||||
QString m_stylesToInlineWhenCopied;
|
QString m_stylesToInlineWhenCopied;
|
||||||
|
|
||||||
@ -1998,18 +1995,27 @@ inline bool VConfigManager::getCloseBeforeExternalEditor() const
|
|||||||
return m_closeBeforeExternalEditor;
|
return m_closeBeforeExternalEditor;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool VConfigManager::getFixImageSrcInWebWhenCopied() const
|
inline QStringList VConfigManager::getStylesToRemoveWhenCopied() const
|
||||||
{
|
{
|
||||||
return m_fixImageSrcInWebWhenCopied;
|
return getConfigFromSettings("web",
|
||||||
}
|
"styles_to_remove_when_copied").toStringList();
|
||||||
|
|
||||||
inline const QStringList &VConfigManager::getStylesToRemoveWhenCopied() const
|
|
||||||
{
|
|
||||||
return m_stylesToRemoveWhenCopied;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const QString &VConfigManager::getStylesToInlineWhenCopied() const
|
inline const QString &VConfigManager::getStylesToInlineWhenCopied() const
|
||||||
{
|
{
|
||||||
return m_stylesToInlineWhenCopied;
|
return m_stylesToInlineWhenCopied;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline QStringList VConfigManager::getCopyTargets() const
|
||||||
|
{
|
||||||
|
return getConfigFromSettings("web",
|
||||||
|
"copy_targets").toStringList();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QString VConfigManager::getStyleOfSpanForMark() const
|
||||||
|
{
|
||||||
|
return getConfigFromSettings("web",
|
||||||
|
"style_of_span_for_mark").toString();
|
||||||
|
}
|
||||||
#endif // VCONFIGMANAGER_H
|
#endif // VCONFIGMANAGER_H
|
||||||
|
@ -36,14 +36,16 @@
|
|||||||
#include "utils/viconutils.h"
|
#include "utils/viconutils.h"
|
||||||
#include "dialog/vtipsdialog.h"
|
#include "dialog/vtipsdialog.h"
|
||||||
|
|
||||||
VMainWindow *g_mainWin;
|
|
||||||
|
|
||||||
extern VConfigManager *g_config;
|
extern VConfigManager *g_config;
|
||||||
|
|
||||||
extern VPalette *g_palette;
|
extern VPalette *g_palette;
|
||||||
|
|
||||||
|
VMainWindow *g_mainWin;
|
||||||
|
|
||||||
VNote *g_vnote;
|
VNote *g_vnote;
|
||||||
|
|
||||||
|
VWebUtils *g_webUtils;
|
||||||
|
|
||||||
const int VMainWindow::c_sharedMemTimerInterval = 1000;
|
const int VMainWindow::c_sharedMemTimerInterval = 1000;
|
||||||
|
|
||||||
#if defined(QT_NO_DEBUG)
|
#if defined(QT_NO_DEBUG)
|
||||||
@ -62,9 +64,13 @@ VMainWindow::VMainWindow(VSingleInstanceGuard *p_guard, QWidget *p_parent)
|
|||||||
g_mainWin = this;
|
g_mainWin = this;
|
||||||
|
|
||||||
setWindowIcon(QIcon(":/resources/icons/vnote.ico"));
|
setWindowIcon(QIcon(":/resources/icons/vnote.ico"));
|
||||||
|
|
||||||
vnote = new VNote(this);
|
vnote = new VNote(this);
|
||||||
g_vnote = vnote;
|
g_vnote = vnote;
|
||||||
|
|
||||||
|
m_webUtils.init();
|
||||||
|
g_webUtils = &m_webUtils;
|
||||||
|
|
||||||
if (g_config->getEnableCompactMode()) {
|
if (g_config->getEnableCompactMode()) {
|
||||||
m_panelViewState = PanelViewState::CompactMode;
|
m_panelViewState = PanelViewState::CompactMode;
|
||||||
} else {
|
} else {
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include "vfile.h"
|
#include "vfile.h"
|
||||||
#include "vedittab.h"
|
#include "vedittab.h"
|
||||||
|
#include "utils/vwebutils.h"
|
||||||
|
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class QComboBox;
|
class QComboBox;
|
||||||
@ -376,6 +377,8 @@ private:
|
|||||||
// Whether user request VNote to quit.
|
// Whether user request VNote to quit.
|
||||||
bool m_requestQuit;
|
bool m_requestQuit;
|
||||||
|
|
||||||
|
VWebUtils m_webUtils;
|
||||||
|
|
||||||
// Interval of the shared memory timer in ms.
|
// Interval of the shared memory timer in ms.
|
||||||
static const int c_sharedMemTimerInterval;
|
static const int c_sharedMemTimerInterval;
|
||||||
};
|
};
|
||||||
|
@ -20,6 +20,9 @@
|
|||||||
#include "vpreviewmanager.h"
|
#include "vpreviewmanager.h"
|
||||||
#include "utils/viconutils.h"
|
#include "utils/viconutils.h"
|
||||||
#include "dialog/vcopytextashtmldialog.h"
|
#include "dialog/vcopytextashtmldialog.h"
|
||||||
|
#include "utils/vwebutils.h"
|
||||||
|
|
||||||
|
extern VWebUtils *g_webUtils;
|
||||||
|
|
||||||
extern VConfigManager *g_config;
|
extern VConfigManager *g_config;
|
||||||
|
|
||||||
@ -275,12 +278,7 @@ void VMdEditor::contextMenuEvent(QContextMenuEvent *p_event)
|
|||||||
const QList<QAction *> actions = menu->actions();
|
const QList<QAction *> actions = menu->actions();
|
||||||
|
|
||||||
if (textCursor().hasSelection()) {
|
if (textCursor().hasSelection()) {
|
||||||
QAction *copyAsHtmlAct = new QAction(tr("Copy As &HTML without Background"), menu);
|
initCopyAsMenu(actions.isEmpty() ? NULL : actions.last(), menu);
|
||||||
copyAsHtmlAct->setToolTip(tr("Copy selected contents as HTML without background styles"));
|
|
||||||
connect(copyAsHtmlAct, &QAction::triggered,
|
|
||||||
this, &VMdEditor::handleCopyAsHtmlAction);
|
|
||||||
|
|
||||||
menu->insertAction(actions.isEmpty() ? NULL : actions[0], copyAsHtmlAct);
|
|
||||||
} else {
|
} 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"),
|
||||||
@ -1042,7 +1040,7 @@ void VMdEditor::updateInitAndInsertedImages(bool p_fileChanged, UpdateAction p_a
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMdEditor::handleCopyAsHtmlAction()
|
void VMdEditor::handleCopyAsAction(QAction *p_act)
|
||||||
{
|
{
|
||||||
QTextCursor cursor = textCursor();
|
QTextCursor cursor = textCursor();
|
||||||
Q_ASSERT(cursor.hasSelection());
|
Q_ASSERT(cursor.hasSelection());
|
||||||
@ -1051,7 +1049,7 @@ void VMdEditor::handleCopyAsHtmlAction()
|
|||||||
Q_ASSERT(!text.isEmpty());
|
Q_ASSERT(!text.isEmpty());
|
||||||
|
|
||||||
Q_ASSERT(!m_textToHtmlDialog);
|
Q_ASSERT(!m_textToHtmlDialog);
|
||||||
m_textToHtmlDialog = new VCopyTextAsHtmlDialog(text, this);
|
m_textToHtmlDialog = new VCopyTextAsHtmlDialog(text, p_act->data().toString(), this);
|
||||||
|
|
||||||
// For Hoedown, we use marked.js to convert the text to have a general interface.
|
// For Hoedown, we use marked.js to convert the text to have a general interface.
|
||||||
emit requestTextToHtml(text);
|
emit requestTextToHtml(text);
|
||||||
@ -1129,3 +1127,31 @@ void VMdEditor::zoomPage(bool p_zoomIn, int p_range)
|
|||||||
|
|
||||||
m_mdHighlighter->rehighlight();
|
m_mdHighlighter->rehighlight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VMdEditor::initCopyAsMenu(QAction *p_before, QMenu *p_menu)
|
||||||
|
{
|
||||||
|
QStringList targets = g_webUtils->getCopyTargetsName();
|
||||||
|
if (targets.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu *subMenu = new QMenu(tr("Copy HTML As"), p_menu);
|
||||||
|
subMenu->setToolTipsVisible(true);
|
||||||
|
for (auto const & target : targets) {
|
||||||
|
QAction *act = new QAction(target, subMenu);
|
||||||
|
act->setData(target);
|
||||||
|
act->setToolTip(tr("Copy selected content as HTML using rules specified by target %1").arg(target));
|
||||||
|
|
||||||
|
subMenu->addAction(act);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(subMenu, &QMenu::triggered,
|
||||||
|
this, &VMdEditor::handleCopyAsAction);
|
||||||
|
|
||||||
|
QAction *menuAct = p_menu->insertMenu(p_before, subMenu);
|
||||||
|
if (p_before) {
|
||||||
|
p_menu->removeAction(p_before);
|
||||||
|
p_menu->insertAction(menuAct, p_before);
|
||||||
|
p_menu->insertSeparator(menuAct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -211,7 +211,7 @@ private slots:
|
|||||||
void updateCurrentHeader();
|
void updateCurrentHeader();
|
||||||
|
|
||||||
// Copy selected text as HTML.
|
// Copy selected text as HTML.
|
||||||
void handleCopyAsHtmlAction();
|
void handleCopyAsAction(QAction *p_act);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Update the config of VTextEdit according to global configurations.
|
// Update the config of VTextEdit according to global configurations.
|
||||||
@ -232,6 +232,8 @@ private:
|
|||||||
// We need to maintain the styles font size.
|
// We need to maintain the styles font size.
|
||||||
void zoomPage(bool p_zoomIn, int p_range = 1);
|
void zoomPage(bool p_zoomIn, int p_range = 1);
|
||||||
|
|
||||||
|
void initCopyAsMenu(QAction *p_before, QMenu *p_menu);
|
||||||
|
|
||||||
HGMarkdownHighlighter *m_mdHighlighter;
|
HGMarkdownHighlighter *m_mdHighlighter;
|
||||||
|
|
||||||
VCodeBlockHighlightHelper *m_cbHighlighter;
|
VCodeBlockHighlightHelper *m_cbHighlighter;
|
||||||
|
160
src/vwebview.cpp
160
src/vwebview.cpp
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
extern VConfigManager *g_config;
|
extern VConfigManager *g_config;
|
||||||
|
|
||||||
|
extern VWebUtils *g_webUtils;
|
||||||
|
|
||||||
// We set the property of the clipboard to mark that the URL copied in the
|
// We set the property of the clipboard to mark that the URL copied in the
|
||||||
// clipboard has been altered.
|
// clipboard has been altered.
|
||||||
static const QString c_ClipboardPropertyMark = "CopiedImageURLAltered";
|
static const QString c_ClipboardPropertyMark = "CopiedImageURLAltered";
|
||||||
@ -27,8 +29,6 @@ VWebView::VWebView(VFile *p_file, QWidget *p_parent)
|
|||||||
: QWebEngineView(p_parent),
|
: QWebEngineView(p_parent),
|
||||||
m_file(p_file),
|
m_file(p_file),
|
||||||
m_copyImageUrlActionHooked(false),
|
m_copyImageUrlActionHooked(false),
|
||||||
m_needRemoveBackground(false),
|
|
||||||
m_fixImgSrc(g_config->getFixImageSrcInWebWhenCopied()),
|
|
||||||
m_afterCopyImage(false)
|
m_afterCopyImage(false)
|
||||||
{
|
{
|
||||||
setAcceptDrops(false);
|
setAcceptDrops(false);
|
||||||
@ -75,16 +75,10 @@ void VWebView::contextMenuEvent(QContextMenuEvent *p_event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add Copy without Background action.
|
// Add Copy As menu.
|
||||||
QAction *copyAct = pageAction(QWebEnginePage::Copy);
|
QAction *copyAct = pageAction(QWebEnginePage::Copy);
|
||||||
if (actions.contains(copyAct)) {
|
if (actions.contains(copyAct)) {
|
||||||
QAction *copyWithoutBgAct = new QAction(tr("Copy &without Background"), menu);
|
initCopyAsMenu(copyAct, menu);
|
||||||
copyWithoutBgAct->setToolTip(tr("Copy selected content without background styles"));
|
|
||||||
connect(copyWithoutBgAct, &QAction::triggered,
|
|
||||||
this, &VWebView::handleCopyWithoutBackgroundAction);
|
|
||||||
menu->insertAction(copyAct, copyWithoutBgAct);
|
|
||||||
menu->removeAction(copyAct);
|
|
||||||
menu->insertAction(copyWithoutBgAct, copyAct);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to replace the "Copy Image" action:
|
// We need to replace the "Copy Image" action:
|
||||||
@ -101,14 +95,8 @@ void VWebView::contextMenuEvent(QContextMenuEvent *p_event)
|
|||||||
defaultCopyImageAct->setVisible(false);
|
defaultCopyImageAct->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add Copy All without Background action.
|
// Add Copy All As menu.
|
||||||
QAction *copyAllWithoutBgAct = new QAction(tr("Copy &All without Background"), menu);
|
initCopyAllAsMenu(menu);
|
||||||
copyAllWithoutBgAct->setToolTip(tr("Copy all contents without background styles"));
|
|
||||||
connect(copyAllWithoutBgAct, &QAction::triggered,
|
|
||||||
this, &VWebView::handleCopyAllWithoutBackgroundAction);
|
|
||||||
// Add it to the back.
|
|
||||||
menu->addSeparator();
|
|
||||||
menu->addAction(copyAllWithoutBgAct);
|
|
||||||
|
|
||||||
hideUnusedActions(menu);
|
hideUnusedActions(menu);
|
||||||
|
|
||||||
@ -267,27 +255,10 @@ bool VWebView::removeStyles(QString &p_html)
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VWebView::handleCopyWithoutBackgroundAction()
|
|
||||||
{
|
|
||||||
m_needRemoveBackground = true;
|
|
||||||
|
|
||||||
triggerPageAction(QWebEnginePage::Copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VWebView::handleCopyAllWithoutBackgroundAction()
|
|
||||||
{
|
|
||||||
triggerPageAction(QWebEnginePage::SelectAll);
|
|
||||||
|
|
||||||
m_needRemoveBackground = true;
|
|
||||||
triggerPageAction(QWebEnginePage::Copy);
|
|
||||||
|
|
||||||
triggerPageAction(QWebEnginePage::Unselect);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VWebView::handleClipboardChanged(QClipboard::Mode p_mode)
|
void VWebView::handleClipboardChanged(QClipboard::Mode p_mode)
|
||||||
{
|
{
|
||||||
bool removeBackground = m_needRemoveBackground;
|
QString copyTarget = m_copyTarget;
|
||||||
m_needRemoveBackground = false;
|
m_copyTarget.clear();
|
||||||
|
|
||||||
bool afterCopyImage = m_afterCopyImage;
|
bool afterCopyImage = m_afterCopyImage;
|
||||||
m_afterCopyImage = false;
|
m_afterCopyImage = false;
|
||||||
@ -306,49 +277,22 @@ void VWebView::handleClipboardChanged(QClipboard::Mode p_mode)
|
|||||||
if (afterCopyImage) {
|
if (afterCopyImage) {
|
||||||
removeHtmlFromImageData(clipboard, mimeData);
|
removeHtmlFromImageData(clipboard, mimeData);
|
||||||
} else {
|
} else {
|
||||||
alterHtmlMimeData(clipboard, mimeData, removeBackground);
|
alterHtmlMimeData(clipboard, mimeData, copyTarget);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VWebView::alterHtmlMimeData(QClipboard *p_clipboard,
|
void VWebView::alterHtmlMimeData(QClipboard *p_clipboard,
|
||||||
const QMimeData *p_mimeData,
|
const QMimeData *p_mimeData,
|
||||||
bool p_removeBackground)
|
const QString &p_copyTarget)
|
||||||
{
|
{
|
||||||
if (!p_mimeData->hasHtml() || p_mimeData->hasImage()) {
|
if (!p_mimeData->hasHtml()
|
||||||
|
|| p_mimeData->hasImage()
|
||||||
|
|| p_copyTarget.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool altered = false;
|
|
||||||
QString html = p_mimeData->html();
|
QString html = p_mimeData->html();
|
||||||
|
if (!g_webUtils->alterHtmlAsTarget(url(), html, p_copyTarget)) {
|
||||||
// Add surrounded tags.
|
|
||||||
if (!html.startsWith("<html>")) {
|
|
||||||
altered = true;
|
|
||||||
html = QString("<html><body>%1</body></html>").arg(html);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove background color.
|
|
||||||
if (p_removeBackground) {
|
|
||||||
if (VWebUtils::removeBackgroundColor(html)) {
|
|
||||||
altered = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (VWebUtils::translateColors(html)) {
|
|
||||||
altered = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix local relative images.
|
|
||||||
if (m_fixImgSrc && VWebUtils::fixImageSrcInHtml(url(), html)) {
|
|
||||||
altered = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix margin and padding.
|
|
||||||
if (removeStyles(html)) {
|
|
||||||
altered = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!altered) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,3 +318,79 @@ void VWebView::removeHtmlFromImageData(QClipboard *p_clipboard,
|
|||||||
VClipboardUtils::setMimeDataToClipboard(p_clipboard, data, QClipboard::Clipboard);
|
VClipboardUtils::setMimeDataToClipboard(p_clipboard, data, QClipboard::Clipboard);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VWebView::initCopyAsMenu(QAction *p_after, QMenu *p_menu)
|
||||||
|
{
|
||||||
|
QStringList targets = g_webUtils->getCopyTargetsName();
|
||||||
|
if (targets.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu *subMenu = new QMenu(tr("Copy As"), p_menu);
|
||||||
|
subMenu->setToolTipsVisible(true);
|
||||||
|
for (auto const & target : targets) {
|
||||||
|
QAction *act = new QAction(target, subMenu);
|
||||||
|
act->setData(target);
|
||||||
|
act->setToolTip(tr("Copy selected content using rules specified by target %1").arg(target));
|
||||||
|
|
||||||
|
subMenu->addAction(act);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(subMenu, &QMenu::triggered,
|
||||||
|
this, &VWebView::handleCopyAsAction);
|
||||||
|
|
||||||
|
QAction *menuAct = p_menu->insertMenu(p_after, subMenu);
|
||||||
|
p_menu->removeAction(p_after);
|
||||||
|
p_menu->insertAction(menuAct, p_after);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VWebView::handleCopyAsAction(QAction *p_act)
|
||||||
|
{
|
||||||
|
if (!p_act) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_copyTarget = p_act->data().toString();
|
||||||
|
|
||||||
|
triggerPageAction(QWebEnginePage::Copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VWebView::initCopyAllAsMenu(QMenu *p_menu)
|
||||||
|
{
|
||||||
|
QStringList targets = g_webUtils->getCopyTargetsName();
|
||||||
|
if (targets.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu *subMenu = new QMenu(tr("Copy All As"), p_menu);
|
||||||
|
subMenu->setToolTipsVisible(true);
|
||||||
|
for (auto const & target : targets) {
|
||||||
|
QAction *act = new QAction(target, subMenu);
|
||||||
|
act->setData(target);
|
||||||
|
act->setToolTip(tr("Copy all content using rules specified by target %1").arg(target));
|
||||||
|
|
||||||
|
subMenu->addAction(act);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(subMenu, &QMenu::triggered,
|
||||||
|
this, &VWebView::handleCopyAllAsAction);
|
||||||
|
|
||||||
|
p_menu->addSeparator();
|
||||||
|
p_menu->addMenu(subMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VWebView::handleCopyAllAsAction(QAction *p_act)
|
||||||
|
{
|
||||||
|
if (!p_act) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerPageAction(QWebEnginePage::SelectAll);
|
||||||
|
|
||||||
|
m_copyTarget = p_act->data().toString();
|
||||||
|
|
||||||
|
triggerPageAction(QWebEnginePage::Copy);
|
||||||
|
|
||||||
|
triggerPageAction(QWebEnginePage::Unselect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -26,9 +26,9 @@ private slots:
|
|||||||
|
|
||||||
void handleCopyImageUrlAction();
|
void handleCopyImageUrlAction();
|
||||||
|
|
||||||
void handleCopyWithoutBackgroundAction();
|
void handleCopyAsAction(QAction *p_act);
|
||||||
|
|
||||||
void handleCopyAllWithoutBackgroundAction();
|
void handleCopyAllAsAction(QAction *p_act);
|
||||||
|
|
||||||
// Copy the clicked image.
|
// Copy the clicked image.
|
||||||
// Used to replace the default CopyImageToClipboard action.
|
// Used to replace the default CopyImageToClipboard action.
|
||||||
@ -41,24 +41,27 @@ private:
|
|||||||
|
|
||||||
void alterHtmlMimeData(QClipboard *p_clipboard,
|
void alterHtmlMimeData(QClipboard *p_clipboard,
|
||||||
const QMimeData *p_mimeData,
|
const QMimeData *p_mimeData,
|
||||||
bool p_removeBackground);
|
const QString &p_copyTarget);
|
||||||
|
|
||||||
void removeHtmlFromImageData(QClipboard *p_clipboard,
|
void removeHtmlFromImageData(QClipboard *p_clipboard,
|
||||||
const QMimeData *p_mimeData);
|
const QMimeData *p_mimeData);
|
||||||
|
|
||||||
bool removeStyles(QString &p_html);
|
bool removeStyles(QString &p_html);
|
||||||
|
|
||||||
|
void initCopyAsMenu(QAction *p_after, QMenu *p_menu);
|
||||||
|
|
||||||
|
void initCopyAllAsMenu(QMenu *p_menu);
|
||||||
|
|
||||||
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.
|
||||||
bool m_copyImageUrlActionHooked;
|
bool m_copyImageUrlActionHooked;
|
||||||
|
|
||||||
bool m_needRemoveBackground;
|
|
||||||
|
|
||||||
bool m_fixImgSrc;
|
|
||||||
|
|
||||||
// Whether it is after copy image action.
|
// Whether it is after copy image action.
|
||||||
bool m_afterCopyImage;
|
bool m_afterCopyImage;
|
||||||
|
|
||||||
|
// Target of Copy As.
|
||||||
|
QString m_copyTarget;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // VWEBVIEW_H
|
#endif // VWEBVIEW_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user