Skip to content

feat(tiptap): add scroll reporting channel and wire host interactions - #445

Open
dengzhongyuan365-dev wants to merge 2 commits into
linuxdeepin:develop/snipefrom
dengzhongyuan365-dev:feat/tiptap-host-interaction-backend
Open

feat(tiptap): add scroll reporting channel and wire host interactions#445
dengzhongyuan365-dev wants to merge 2 commits into
linuxdeepin:develop/snipefrom
dengzhongyuan365-dev:feat/tiptap-host-interaction-backend

Conversation

@dengzhongyuan365-dev

@dengzhongyuan365-dev dengzhongyuan365-dev commented Aug 2, 2026

Copy link
Copy Markdown
Member

What changed

Adds scroll position reporting to the Tiptap channel bridge and wires the Tiptap WebView into existing host-interaction flows (context menu, scroll, focus, search). All behind the debug-only flag.

  • TiptapChannelBridge: new jsReportScroll entry point and scrollChanged signal to receive scroll position from the frontend editor.
  • VNoteMainManager: connect scrollChanged to track whether the editor is scrolled to the top.
  • WebEngineView.qml: wire tiptapWebView for context menu requests, scroll reporting, editor focus, and findText-based search.
  • web_engine_handler: add Qt5/Qt6 context menu request adaptation to dispatch menu type and parameters, with a debug-mode tiptap fallback for voice menu deletion.
  • Unit tests: add ut_tiptapchannelbridge tests covering top and scrolled scroll states.

Why

The Tiptap editor (debug-only) lacked host-interaction parity with the legacy editor — no scroll reporting, context menu, focus, or search wiring. This adds the channel and QML wiring needed for the debug-mode editor to reach feature parity without affecting the default editor.

How verified

  • C++ unit tests: ut_tiptapchannelbridge passes (39 tests including 2 new scroll tests).
  • Debug mode is off by default; no behavior change in release builds.

Summary by Sourcery

Add scroll position reporting and host interaction wiring for the debug-only Tiptap editor to reach parity with the legacy editor.

New Features:

  • Introduce a JS-exposed scroll reporting API in TiptapChannelBridge that emits a scrollChanged signal consumed by the main manager.
  • Wire the Tiptap WebView into context menu handling, search, and editor focus/select-all/delete commands when the debug flag is enabled.

Bug Fixes:

  • Avoid invoking legacy Summernote JS deletion when the debug Tiptap editor is active in voice menu handling.

Tests:

  • Extend ut_tiptapchannelbridge with coverage for scroll-to-top and scrolled states driven by jsReportScroll.

Add jsReportScroll entry point and scrollChanged signal to TiptapChannelBridge for receiving scroll position from the frontend editor, connected in VNoteMainManager. Wire tiptapWebView in WebEngineView.qml for context menu, scroll, focus, and findText search. Add Qt5/Qt6 context menu adaptation in web_engine_handler. Add unit tests for scroll reporting.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @dengzhongyuan365-dev, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: dengzhongyuan365-dev

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@sourcery-ai

sourcery-ai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds scroll position reporting from the Tiptap editor to the host, wires the debug-only Tiptap WebView into existing host interactions (context menu, search, focus, select/delete), and adapts voice-menu handling to avoid legacy JS paths in Tiptap mode, with unit tests validating the new scroll reporting behavior.

Sequence diagram for Tiptap scroll reporting to host

sequenceDiagram
    participant JsEditor as JsTiptapEditor
    participant Bridge as TiptapChannelBridge
    participant MainMgr as VNoteMainManager

    JsEditor->>Bridge: jsReportScroll(scrollTop)
    Bridge->>Bridge: compute isTop = (scrollTop <= 0)
    Bridge-->>MainMgr: scrollChanged(isTop)
    MainMgr->>MainMgr: scrollChange(isTop) (update hasScroll / header state)
Loading

Sequence diagram for Tiptap context menu and voice deletion handling

sequenceDiagram
    actor User
    participant TiptapView as tiptapWebView
    participant Handler as WebEngineHandler
    participant JsContent as JsContent
    participant Bridge as TiptapChannelBridge

    User->>TiptapView: onContextMenuRequested(req)
    TiptapView->>TiptapView: runJavaScript(probeJs)
    TiptapView-->>Handler: onSaveMenuParam(type, json)
    TiptapView-->>Handler: onContextMenuRequested(req)
    Handler->>Handler: processVoiceMenuRequest(request)
    alt debugEnabled() is false
        Handler-->>JsContent: callJsDeleteSelection()
    else debugEnabled() is true
        Handler->>Handler: skip legacy Summernote delete path
    end
Loading

File-Level Changes

Change Details Files
Add JS→C++ scroll reporting for the Tiptap editor and propagate it into main manager scroll handling.
  • Introduce Q_INVOKABLE jsReportScroll(int scrollTop) on TiptapChannelBridge and emit scrollChanged(bool isTop) based on scrollTop.
  • Declare the new scrollChanged(bool isTop) signal in the TiptapChannelBridge interface.
  • Connect TiptapChannelBridge::scrollChanged to VNoteMainManager::scrollChange alongside the existing WebRichTextManager::scrollChange connection.
src/common/tiptapchannelbridge.cpp
src/common/tiptapchannelbridge.h
src/common/VNoteMainManager.cpp
Wire the debug-only Tiptap WebView into existing WebEngineView interactions (web actions, context menu, search, focus, selection).
  • Route triggerWebAction to tiptapWebView when TiptapChannel.debugEnabled and the Tiptap loader is instantiated, otherwise keep existing webView behavior.
  • Add tiptapWebView context menu handling that probes DOM elements via injected JavaScript and dispatches menu parameters through handler.onSaveMenuParam and handler.onContextMenuRequested.
  • Route rich-text search (findText) calls to tiptapWebView under debug mode, falling back to webView otherwise.
  • Add Webobj signal connections that, in Tiptap debug mode, run JavaScript against window.__dvnTiptapEditor to select all, delete selection, and focus the editor.
src/gui/mainwindow/WebEngineView.qml
Adapt web engine voice menu handling so Tiptap debug mode bypasses legacy Summernote JS deletion paths.
  • Wrap JsContent::instance()->callJsDeleteSelection() calls in a debugEnabled() check so they are only executed when TiptapChannelBridge debug mode is off.
  • Apply the same guard for both QObject-based and QWebEngineContextMenuRequest-based voice menu handling paths.
src/handler/web_engine_handler.cpp
Add unit tests for TiptapChannelBridge scroll reporting behavior.
  • Create tests that call jsReportScroll(0) and verify a single scrollChanged(true) emission via QSignalSpy.
  • Create tests that call jsReportScroll with a positive value and verify a single scrollChanged(false) emission.
  • Extend the ut_tiptapchannelbridge suite to include these scroll-top/scrolled scenarios.
tests/src/tiptapchannel/ut_tiptapchannelbridge.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Coerce req.position.x/y via Number() with isNaN guard to reject
non-numeric values early. Use String(Math.round()) to produce pure
digit strings before concatenating into the probe script, eliminating
JavaScript injection risk from untrusted position data.
@dengzhongyuan365-dev

Copy link
Copy Markdown
Member Author

/test github-pr-review-ci

@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

★ 总体评分:95分

■ 【总体评价】

代码实现了Tiptap编辑器在调试模式下的功能对齐,逻辑严谨且包含完善的单元测试
各项功能正确实现,QML中DOM操作和JS注入防护得当,因部分代码可读性可进一步优化扣5分

■ 【详细分析】

  • 1.语法逻辑(完全正确)✓

C++部分的信号槽连接(VNoteMainManager.cpptiptapchannelbridge.cpp)和条件判断(web_engine_handler.cpp)逻辑清晰无误。QML部分(WebEngineView.qml)中新增的右键菜单处理通过 elementFromPointclosest 准确识别了语音块、图片和普通文本,并正确路由了编辑器操作命令。测试用例覆盖了滚动到顶部和未到顶部的边界情况。
潜在问题:无
建议:无

  • 2.代码质量(良好)✓

代码注释详尽,解释了各处改动的意图(如"调试态下 Tiptap 编辑器不走 Summernote JS 删除路径")。QML中拼接JS字符串的方式虽然常见,但较长且包含多层嵌套,略微影响可读性。JSON解析部分使用了 try-catch,增强了代码的健壮性。
潜在问题:WebEngineView.qmlonContextMenuRequested 内的JS字符串拼接较长,维护成本较高。
建议:考虑将复杂的DOM检测逻辑封装为前端JS函数,QML仅传参调用,以提高可读性和可维护性。

  • 3.代码性能(无性能问题)✓

右键菜单触发时的DOM查询(elementFromPointclosest)属于轻量级操作,不会引起性能瓶颈。滚动事件上报仅传递一个布尔值,开销极小。信号槽连接使用默认方式,无额外性能损耗。
潜在问题:无
建议:无

  • 4.代码安全(存在0个安全漏洞)✓

漏洞对比统计:新增漏洞 0 个,减少漏洞 0 个,持平 0 个
代码在处理外部输入(右键菜单坐标)时,使用了 isNaN 进行严格校验,并通过 Math.roundString 转换确保了拼接进JS字符串的参数为纯数字,有效防止了JS注入。其他部分均为内部逻辑路由,无外部输入直接参与敏感操作。

  • 建议:继续保持对动态拼接JS代码的输入校验。

■ 【改进建议代码示例】

// WebEngineView.qml 优化示例:将DOM检测逻辑移至前端JS函数
// 假设前端已定义 window.__dvnCheckContextMenu(x, y) 函数
onContextMenuRequested: req => {
    req.accepted = true;
    var rawX = Number(req.position.x);
    var rawY = Number(req.position.y);
    if (isNaN(rawX) || isNaN(rawY)) return;
    var sx = String(Math.round(rawX));
    var sy = String(Math.round(rawY));
    
    tiptapWebView.runJavaScript(
        "window.__dvnCheckContextMenu ? window.__dvnCheckContextMenu(" + sx + "," + sy + ") : JSON.stringify({type:2,json:''})",
        function(result) {
            var info = null;
            try { info = JSON.parse(result); } catch(e) {}
            if (!info) return;
            if (info.type === 0) return;
            handler.onSaveMenuParam(info.type, info.json);
            handler.onContextMenuRequested(req);
        });
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants