求助实现多个块的快速合并及折叠

求助一个 quicker 动作、思源按钮或快捷键,手动选中思源笔记的连续多个块时,点击思源按钮或 quicker 动作,实现以下功能:

  1. 将选中的多个块转换成引述或超级块。
  2. 将这个整体的引述或超级块折叠。
  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    24055 引用 • 98032 回帖 • 1 关注
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    9000 引用 • 41002 回帖 • 129 关注
被采纳的回答
  • EmberSky

    选中后 ctrl+q 触发, 触发后会将选中的内容转换成引用, 过程中会有点卡顿, 因为不知道为啥, 延时低了就会报错, 所以只能先让 sleep 时间长一点

    触发前, image.png, 触发后, image.png

    (()=>{
    // 延迟执行
    function sleep(ms) {
      return new Promise(resolve => setTimeout(resolve, ms));
    }
    function press_once(keyInit, selector = null) {
      keyInit["bubbles"] = true;
      if (selector == null) {
        selector = document.querySelector('[data-type="wnd"].layout__wnd--active .protyle:not(.fn__none) .protyle-wysiwyg.protyle-wysiwyg--attr')
      }
      else if (typeof selector === 'function') {
        selector = selector()
      }
      else if (typeof selector === 'string') {
        selector = document.querySelector(selector)
      }
      if (!selector) return
      selector.dispatchEvent(new KeyboardEvent('keydown', keyInit));
      selector.dispatchEvent(new KeyboardEvent('keyup', keyInit));
    }
    async function add_new_line_before() {
      press_once({
        key: 'Enter',
        ctrlKey: true,
        shiftKey: true,
        keyCode: 13, // 不推荐使用,但某些情况下需要
      });
    }
    function click_right(ele) {
      // 创建一个右键点击的 MouseEvent
      const rightClickEvent = new MouseEvent('contextmenu', {
        bubbles: true,
        cancelable: true,
        view: window,
        button: 2 
      });
      ele.dispatchEvent(rightClickEvent);
    }
    
    
    // 获取光标所在的元素
    function getElementAtCursor() {
      const selection = window.getSelection();
    
      if (selection.rangeCount > 0) {
        const range = selection.getRangeAt(0);
        const startContainer = range.startContainer;
        // 如果是文本节点,获取其父元素
        const element = startContainer.nodeType === 3 ? startContainer.parentNode : startContainer;
        return element;
      }
    
      return null; // 如果没有选中内容或光标位置无效
    }
    
    // 获取当前选中的文本
    async function get_selected_data() {
      // 触发 ctrl+c, 复制选中的块
      document.execCommand('copy');
      // 获取剪贴板文本
      return await navigator.clipboard.readText();
    }
    // 设置文本
    async function paste_data(data) {
      // 将处理后的文本复制到剪贴板
      await navigator.clipboard.writeText(data);
      // 触发 ctrl+v, 粘贴处理后的内容
      document.execCommand('paste');
      await sleep(20)
    }
    
    // 清空选中的内容: 先剪切, 再增加空行
    async function clear_selected_data() {
      // 触发 ctrl+x, 剪切选中的块, 目的是删除原有内容
      document.execCommand('cut');
      await add_new_line_before()
    }
    
    // 转换引用 - 使用系统自带的转换功能 
    function convert_quote_from_sys(event) {
      click_right(event.target)
      // 创建 mouseover 事件
      const mouseOverEvent = new MouseEvent('mouseover', {
        view: window,
        bubbles: true,
        cancelable: true,
      });
      let turn_ele = document.querySelector('.b3-menu__items>[data-id="turnInto"]')
      turn_ele?.dispatchEvent(mouseOverEvent);
      turn_ele = turn_ele?.querySelector('.b3-menu__submenu>.b3-menu__items>[data-id="quote"]')
      if (!turn_ele) return false
      turn_ele.click()
      return true
    }
    // 转换引用 - 使用自己实现的的转换功能
    async function convert_quote_from_my(clipboardText) {
      // 删除原有内容, 并增加空行
      await clear_selected_data()
      let clipboardTextRet = clipboardText
        .split('\n')
        .map(line => "> " + line)
        .join('\n')
      // 粘贴处理后的文本
      await paste_data(clipboardTextRet);
    }
    async function fold_block() {
      await sleep(300);
      let ele = getElementAtCursor();
      if (!ele) return
      while (!ele.parentNode.classList.contains("protyle-wysiwyg--attr") && ele.getAttribute('data-type') != 'NodeBlockquote') {
        ele = ele.parentNode
      }
      click_right(ele)
      await sleep(300)
      document.querySelector('.b3-menu__items>[data-id="fold"]')?.click()
    }
    
    // 合并选中的块
    async function handle_merge(event) {
      // 获取当前选中的文本
      let clipboardText = await get_selected_data();
      // 如果不需要处理, 则直接返回
      if (clipboardText == "") {
        console.log("不需要处理")
        return;
      }
      
      if (convert_quote_from_sys(event)) {
        console.log("系统转换成功")
      }
      else {
        await convert_quote_from_my(clipboardText)
        console.log("自定义转换成功")
      }
      await fold_block();
    }
    
    // 事件监听
    document.addEventListener('keydown', async (event) => {
      // 检查是否按下了 Ctrl + q
      if (event.ctrlKey && event.key === 'q') {
        // event.preventDefault(); // 防止快捷键默认行为
        await handle_merge(event);
      }
    });
    })()
    
    

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • wenbocn

    或选中多个块后,中键任意一个块的块标,能够实现组合这些块并折叠,那就更好了
    [js] 鼠标中键折叠块 - 链滴

  • 引述、超级块、折叠

    image.png

    image.png

    image.png

    1 回复
  • wenbocn

    折叠快捷键,只能折叠一个块。只能折叠引述里面光标所在的单个块

  • EmberSky

    选中后 ctrl+q 触发, 触发后会将选中的内容转换成引用, 过程中会有点卡顿, 因为不知道为啥, 延时低了就会报错, 所以只能先让 sleep 时间长一点

    触发前, image.png, 触发后, image.png

    (()=>{
    // 延迟执行
    function sleep(ms) {
      return new Promise(resolve => setTimeout(resolve, ms));
    }
    function press_once(keyInit, selector = null) {
      keyInit["bubbles"] = true;
      if (selector == null) {
        selector = document.querySelector('[data-type="wnd"].layout__wnd--active .protyle:not(.fn__none) .protyle-wysiwyg.protyle-wysiwyg--attr')
      }
      else if (typeof selector === 'function') {
        selector = selector()
      }
      else if (typeof selector === 'string') {
        selector = document.querySelector(selector)
      }
      if (!selector) return
      selector.dispatchEvent(new KeyboardEvent('keydown', keyInit));
      selector.dispatchEvent(new KeyboardEvent('keyup', keyInit));
    }
    async function add_new_line_before() {
      press_once({
        key: 'Enter',
        ctrlKey: true,
        shiftKey: true,
        keyCode: 13, // 不推荐使用,但某些情况下需要
      });
    }
    function click_right(ele) {
      // 创建一个右键点击的 MouseEvent
      const rightClickEvent = new MouseEvent('contextmenu', {
        bubbles: true,
        cancelable: true,
        view: window,
        button: 2 
      });
      ele.dispatchEvent(rightClickEvent);
    }
    
    
    // 获取光标所在的元素
    function getElementAtCursor() {
      const selection = window.getSelection();
    
      if (selection.rangeCount > 0) {
        const range = selection.getRangeAt(0);
        const startContainer = range.startContainer;
        // 如果是文本节点,获取其父元素
        const element = startContainer.nodeType === 3 ? startContainer.parentNode : startContainer;
        return element;
      }
    
      return null; // 如果没有选中内容或光标位置无效
    }
    
    // 获取当前选中的文本
    async function get_selected_data() {
      // 触发 ctrl+c, 复制选中的块
      document.execCommand('copy');
      // 获取剪贴板文本
      return await navigator.clipboard.readText();
    }
    // 设置文本
    async function paste_data(data) {
      // 将处理后的文本复制到剪贴板
      await navigator.clipboard.writeText(data);
      // 触发 ctrl+v, 粘贴处理后的内容
      document.execCommand('paste');
      await sleep(20)
    }
    
    // 清空选中的内容: 先剪切, 再增加空行
    async function clear_selected_data() {
      // 触发 ctrl+x, 剪切选中的块, 目的是删除原有内容
      document.execCommand('cut');
      await add_new_line_before()
    }
    
    // 转换引用 - 使用系统自带的转换功能 
    function convert_quote_from_sys(event) {
      click_right(event.target)
      // 创建 mouseover 事件
      const mouseOverEvent = new MouseEvent('mouseover', {
        view: window,
        bubbles: true,
        cancelable: true,
      });
      let turn_ele = document.querySelector('.b3-menu__items>[data-id="turnInto"]')
      turn_ele?.dispatchEvent(mouseOverEvent);
      turn_ele = turn_ele?.querySelector('.b3-menu__submenu>.b3-menu__items>[data-id="quote"]')
      if (!turn_ele) return false
      turn_ele.click()
      return true
    }
    // 转换引用 - 使用自己实现的的转换功能
    async function convert_quote_from_my(clipboardText) {
      // 删除原有内容, 并增加空行
      await clear_selected_data()
      let clipboardTextRet = clipboardText
        .split('\n')
        .map(line => "> " + line)
        .join('\n')
      // 粘贴处理后的文本
      await paste_data(clipboardTextRet);
    }
    async function fold_block() {
      await sleep(300);
      let ele = getElementAtCursor();
      if (!ele) return
      while (!ele.parentNode.classList.contains("protyle-wysiwyg--attr") && ele.getAttribute('data-type') != 'NodeBlockquote') {
        ele = ele.parentNode
      }
      click_right(ele)
      await sleep(300)
      document.querySelector('.b3-menu__items>[data-id="fold"]')?.click()
    }
    
    // 合并选中的块
    async function handle_merge(event) {
      // 获取当前选中的文本
      let clipboardText = await get_selected_data();
      // 如果不需要处理, 则直接返回
      if (clipboardText == "") {
        console.log("不需要处理")
        return;
      }
      
      if (convert_quote_from_sys(event)) {
        console.log("系统转换成功")
      }
      else {
        await convert_quote_from_my(clipboardText)
        console.log("自定义转换成功")
      }
      await fold_block();
    }
    
    // 事件监听
    document.addEventListener('keydown', async (event) => {
      // 检查是否按下了 Ctrl + q
      if (event.ctrlKey && event.key === 'q') {
        // event.preventDefault(); // 防止快捷键默认行为
        await handle_merge(event);
      }
    });
    })()
    
    
    1 回复
  • wenbocn

    可用,非常感谢!

推荐标签 标签

  • Pipe

    Pipe 是一款小而美的开源博客平台。Pipe 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    132 引用 • 1114 回帖 • 122 关注
  • 996
    13 引用 • 200 回帖 • 10 关注
  • jQuery

    jQuery 是一套跨浏览器的 JavaScript 库,强化 HTML 与 JavaScript 之间的操作。由 John Resig 在 2006 年 1 月的 BarCamp NYC 上释出第一个版本。全球约有 28% 的网站使用 jQuery,是非常受欢迎的 JavaScript 库。

    63 引用 • 134 回帖 • 731 关注
  • 链滴

    链滴是一个记录生活的地方。

    记录生活,连接点滴

    163 引用 • 3820 回帖 • 1 关注
  • jsDelivr

    jsDelivr 是一个开源的 CDN 服务,可为 npm 包、GitHub 仓库提供免费、快速并且可靠的全球 CDN 加速服务。

    5 引用 • 31 回帖 • 85 关注
  • Shell

    Shell 脚本与 Windows/Dos 下的批处理相似,也就是用各类命令预先放入到一个文件中,方便一次性执行的一个程序文件,主要是方便管理员进行设置或者管理用的。但是它比 Windows 下的批处理更强大,比用其他编程程序编辑的程序效率更高,因为它使用了 Linux/Unix 下的命令。

    124 引用 • 74 回帖
  • 持续集成

    持续集成(Continuous Integration)是一种软件开发实践,即团队开发成员经常集成他们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

    15 引用 • 7 回帖
  • Sublime

    Sublime Text 是一款可以用来写代码、写文章的文本编辑器。支持代码高亮、自动完成,还支持通过插件进行扩展。

    10 引用 • 5 回帖 • 2 关注
  • Elasticsearch

    Elasticsearch 是一个基于 Lucene 的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful 接口。Elasticsearch 是用 Java 开发的,并作为 Apache 许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。

    117 引用 • 99 回帖 • 215 关注
  • Sym

    Sym 是一款用 Java 实现的现代化社区(论坛/BBS/社交网络/博客)系统平台。

    下一代的社区系统,为未来而构建

    524 引用 • 4601 回帖 • 696 关注
  • OnlyOffice
    4 引用 • 14 关注
  • FlowUs

    FlowUs.息流 个人及团队的新一代生产力工具。

    让复杂的信息管理更轻松、自由、充满创意。

    1 引用 • 3 关注
  • Outlook
    1 引用 • 5 回帖
  • 分享

    有什么新发现就分享给大家吧!

    247 引用 • 1793 回帖
  • 新人

    让我们欢迎这对新人。哦,不好意思说错了,让我们欢迎这位新人!
    新手上路,请谨慎驾驶!

    52 引用 • 228 回帖
  • Vim

    Vim 是类 UNIX 系统文本编辑器 Vi 的加强版本,加入了更多特性来帮助编辑源代码。Vim 的部分增强功能包括文件比较(vimdiff)、语法高亮、全面的帮助系统、本地脚本(Vimscript)和便于选择的可视化模式。

    29 引用 • 66 回帖
  • Excel
    31 引用 • 28 回帖
  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    943 引用 • 1460 回帖
  • Gitea

    Gitea 是一个开源社区驱动的轻量级代码托管解决方案,后端采用 Go 编写,采用 MIT 许可证。

    4 引用 • 16 回帖 • 6 关注
  • OpenStack

    OpenStack 是一个云操作系统,通过数据中心可控制大型的计算、存储、网络等资源池。所有的管理通过前端界面管理员就可以完成,同样也可以通过 Web 接口让最终用户部署资源。

    10 引用
  • Spark

    Spark 是 UC Berkeley AMP lab 所开源的类 Hadoop MapReduce 的通用并行框架。Spark 拥有 Hadoop MapReduce 所具有的优点;但不同于 MapReduce 的是 Job 中间输出结果可以保存在内存中,从而不再需要读写 HDFS,因此 Spark 能更好地适用于数据挖掘与机器学习等需要迭代的 MapReduce 的算法。

    74 引用 • 46 回帖 • 563 关注
  • FreeMarker

    FreeMarker 是一款好用且功能强大的 Java 模版引擎。

    23 引用 • 20 回帖 • 457 关注
  • SMTP

    SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。

    4 引用 • 18 回帖 • 625 关注
  • 电影

    这是一个不能说的秘密。

    121 引用 • 606 回帖
  • Laravel

    Laravel 是一套简洁、优雅的 PHP Web 开发框架。它采用 MVC 设计,是一款崇尚开发效率的全栈框架。

    20 引用 • 23 回帖 • 733 关注
  • Telegram

    Telegram 是一个非盈利性、基于云端的即时消息服务。它提供了支持各大操作系统平台的开源的客户端,也提供了很多强大的 APIs 给开发者创建自己的客户端和机器人。

    5 引用 • 35 回帖 • 1 关注
  • GitLab

    GitLab 是利用 Ruby 一个开源的版本管理系统,实现一个自托管的 Git 项目仓库,可通过 Web 界面操作公开或私有项目。

    46 引用 • 72 回帖 • 1 关注