mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
LivePreview: smart live preview
This commit is contained in:
parent
13fb03bd11
commit
cda48a612a
@ -190,7 +190,9 @@ new QWebChannel(qt.webChannelTransport,
|
||||
content.requestPreviewEnabled.connect(setPreviewEnabled);
|
||||
|
||||
content.requestPreviewCodeBlock.connect(previewCodeBlock);
|
||||
|
||||
content.requestSetPreviewContent.connect(setPreviewContent);
|
||||
content.requestPerformSmartLivePreview.connect(performSmartLivePreview);
|
||||
|
||||
if (typeof updateHtml == "function") {
|
||||
updateHtml(content.html);
|
||||
@ -1577,3 +1579,77 @@ var htmlToText = function(identifier, id, timeStamp, html) {
|
||||
var markdown = ts.turndown(html);
|
||||
content.htmlToTextCB(identifier, id, timeStamp, markdown);
|
||||
};
|
||||
|
||||
var performSmartLivePreview = function(lang, text) {
|
||||
if (previewDiv.style.display == 'none') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (lang != 'puml') {
|
||||
return;
|
||||
}
|
||||
|
||||
// PlantUML.
|
||||
var targetNode = findNodeWithText(previewDiv, new RegExp(text));
|
||||
if (!targetNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
// (left, top) is relative to the viewport.
|
||||
// Should add window.scrollX and window.scrollY to get the real content offset.
|
||||
var trect = targetNode.getBoundingClientRect();
|
||||
|
||||
var vrect = {
|
||||
left: document.documentElement.scrollLeft || document.body.scrollLeft || window.pageXOffset,
|
||||
top: document.documentElement.scrollTop || document.body.scrollTop || window.pageYOffset,
|
||||
width: document.documentElement.clientWidth || document.body.clientWidth,
|
||||
height: document.documentElement.clientHeight || document.body.clientHeight
|
||||
}
|
||||
|
||||
var dx = 0, dy = 0;
|
||||
|
||||
// If target is already in, do not scroll.
|
||||
if (trect.left < 0
|
||||
|| trect.left + trect.width > vrect.width) {
|
||||
if (trect.width >= vrect.width) {
|
||||
dx = trect.left;
|
||||
} else {
|
||||
dx = trect.left - (vrect.width - trect.width) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (trect.top < 0
|
||||
|| trect.top + trect.height > vrect.height) {
|
||||
if (trect.height >= vrect.height) {
|
||||
dy = trect.top;
|
||||
} else {
|
||||
dy = trect.top - (vrect.height - trect.width) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
window.scrollBy(dx, dy);
|
||||
}
|
||||
|
||||
var findNodeWithText = function(node, reg) {
|
||||
var children = node.children;
|
||||
if (children.length == 0) {
|
||||
if (reg.test(node.textContent)) {
|
||||
return node;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < children.length; ++i) {
|
||||
var ret = findNodeWithText(children[i], reg);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (reg.test(node.textContent)) {
|
||||
return node;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -245,6 +245,9 @@ max_tag_label_length=10
|
||||
; Max number of tag labels to display
|
||||
max_num_of_tag_labels=3
|
||||
|
||||
; Smart live preview
|
||||
smart_live_preview=true
|
||||
|
||||
[editor]
|
||||
; Auto indent as previous line
|
||||
auto_indent=true
|
||||
|
@ -311,6 +311,9 @@ void VConfigManager::initialize()
|
||||
m_maxNumOfTagLabels = getConfigFromSettings("global",
|
||||
"max_num_of_tag_labels").toInt();
|
||||
|
||||
m_smartLivePreview = getConfigFromSettings("global",
|
||||
"smart_live_preview").toBool();
|
||||
|
||||
initEditorConfigs();
|
||||
}
|
||||
|
||||
|
@ -547,6 +547,8 @@ public:
|
||||
|
||||
QChar getVimLeaderKey() const;
|
||||
|
||||
bool getSmartLivePreview() const;
|
||||
|
||||
private:
|
||||
// Look up a config from user and default settings.
|
||||
QVariant getConfigFromSettings(const QString §ion, const QString &key) const;
|
||||
@ -984,6 +986,9 @@ private:
|
||||
// Vim leader key.
|
||||
QChar m_vimLeaderKey;
|
||||
|
||||
// Smart live preview.
|
||||
bool m_smartLivePreview;
|
||||
|
||||
// The name of the config file in each directory.
|
||||
static const QString c_dirConfigFile;
|
||||
|
||||
@ -2539,4 +2544,9 @@ inline QChar VConfigManager::getVimLeaderKey() const
|
||||
{
|
||||
return m_vimLeaderKey;
|
||||
}
|
||||
|
||||
inline bool VConfigManager::getSmartLivePreview() const
|
||||
{
|
||||
return m_smartLivePreview;
|
||||
}
|
||||
#endif // VCONFIGMANAGER_H
|
||||
|
@ -202,3 +202,10 @@ void VDocument::previewCodeBlockCB(int p_id, const QString &p_lang, const QStrin
|
||||
{
|
||||
emit codeBlockPreviewReady(p_id, p_lang, p_html);
|
||||
}
|
||||
|
||||
void VDocument::performSmartLivePreview(const QString &p_lang, const QString &p_text)
|
||||
{
|
||||
if (!p_text.isEmpty()) {
|
||||
emit requestPerformSmartLivePreview(p_lang, p_text);
|
||||
}
|
||||
}
|
||||
|
@ -75,6 +75,8 @@ public:
|
||||
|
||||
void muteWebView(bool p_muted);
|
||||
|
||||
void performSmartLivePreview(const QString &p_lang, const QString &p_text);
|
||||
|
||||
public slots:
|
||||
// Will be called in the HTML side
|
||||
|
||||
@ -192,6 +194,8 @@ signals:
|
||||
|
||||
void requestMuted(bool p_muted);
|
||||
|
||||
void requestPerformSmartLivePreview(const QString &p_lang, const QString &p_text);
|
||||
|
||||
private:
|
||||
QString m_toc;
|
||||
QString m_header;
|
||||
|
@ -95,7 +95,7 @@ VLivePreviewHelper::VLivePreviewHelper(VEditor *p_editor,
|
||||
{
|
||||
m_livePreviewTimer = new QTimer(this);
|
||||
m_livePreviewTimer->setSingleShot(true);
|
||||
m_livePreviewTimer->setInterval(100);
|
||||
m_livePreviewTimer->setInterval(500);
|
||||
connect(m_livePreviewTimer, &QTimer::timeout,
|
||||
this, &VLivePreviewHelper::handleCursorPositionChanged);
|
||||
|
||||
@ -214,6 +214,7 @@ void VLivePreviewHelper::updateCodeBlocks(TimeStamp p_timeStamp, const QVector<V
|
||||
|
||||
if (needUpdate) {
|
||||
updateLivePreview();
|
||||
performSmartLivePreview();
|
||||
}
|
||||
|
||||
clearObsoleteCache();
|
||||
@ -227,10 +228,7 @@ void VLivePreviewHelper::handleCursorPositionChanged()
|
||||
}
|
||||
|
||||
int cursorBlock = m_editor->textCursorW().block().blockNumber();
|
||||
if (m_lastCursorBlock == cursorBlock) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_lastCursorBlock != cursorBlock) {
|
||||
m_lastCursorBlock = cursorBlock;
|
||||
|
||||
int left = 0, right = m_codeBlocks.size() - 1;
|
||||
@ -254,6 +252,9 @@ void VLivePreviewHelper::handleCursorPositionChanged()
|
||||
updateLivePreview();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
performSmartLivePreview();
|
||||
}
|
||||
|
||||
void VLivePreviewHelper::updateLivePreview()
|
||||
@ -396,6 +397,7 @@ void VLivePreviewHelper::localAsyncResultReady(int p_id,
|
||||
}
|
||||
|
||||
m_document->setPreviewContent(lang, p_result);
|
||||
performSmartLivePreview();
|
||||
} else {
|
||||
// Inplace preview.
|
||||
updateInplacePreview();
|
||||
@ -523,3 +525,27 @@ void VLivePreviewHelper::clearObsoleteCache()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VLivePreviewHelper::performSmartLivePreview()
|
||||
{
|
||||
if (m_cbIndex < 0
|
||||
|| m_cbIndex >= m_codeBlocks.size()
|
||||
|| !g_config->getSmartLivePreview()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const CodeBlockPreviewInfo &cb = m_codeBlocks[m_cbIndex];
|
||||
const VCodeBlock &vcb = cb.codeBlock();
|
||||
const QTextBlock block = m_editor->textCursorW().block();
|
||||
if (block.blockNumber() <= vcb.m_startBlock
|
||||
|| block.blockNumber() >= vcb.m_endBlock) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString keyword;
|
||||
if (vcb.m_lang == "puml" && m_plantUMLMode == PlantUMLMode::LocalPlantUML) {
|
||||
keyword = VPlantUMLHelper::keywordForSmartLivePreview(block.text());
|
||||
}
|
||||
|
||||
m_document->performSmartLivePreview(vcb.m_lang, keyword);
|
||||
}
|
||||
|
@ -233,6 +233,8 @@ private:
|
||||
|
||||
void clearObsoleteCache();
|
||||
|
||||
void performSmartLivePreview();
|
||||
|
||||
// Sorted by m_startBlock in ascending order.
|
||||
QVector<CodeBlockPreviewInfo> m_codeBlocks;
|
||||
|
||||
|
@ -188,3 +188,40 @@ QByteArray VPlantUMLHelper::process(const QString &p_format, const QString &p_te
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static bool tryClassDiagram(QString &p_keyword)
|
||||
{
|
||||
{
|
||||
// class ABC #Pink {
|
||||
QRegExp classDef1("class\\s*(\\w+)\\s*.*");
|
||||
if (classDef1.indexIn(p_keyword) >= 0) {
|
||||
p_keyword = classDef1.cap(1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// class "ABC DEF" as AD #Pink {
|
||||
QRegExp classDef2("class\\s*\"([^\"]+)\"\\s*.*");
|
||||
if (classDef2.indexIn(p_keyword) >= 0) {
|
||||
p_keyword = classDef2.cap(1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QString VPlantUMLHelper::keywordForSmartLivePreview(const QString &p_text)
|
||||
{
|
||||
QString kw = p_text.trimmed();
|
||||
if (kw.isEmpty()) {
|
||||
return kw;
|
||||
}
|
||||
|
||||
if (tryClassDiagram(kw)) {
|
||||
return kw;
|
||||
}
|
||||
|
||||
return kw;
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ public:
|
||||
|
||||
static QByteArray process(const QString &p_format, const QString &p_text);
|
||||
|
||||
static QString keywordForSmartLivePreview(const QString &p_text);
|
||||
|
||||
signals:
|
||||
void resultReady(int p_id,
|
||||
TimeStamp p_timeStamp,
|
||||
|
Loading…
x
Reference in New Issue
Block a user