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

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

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

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

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

    22300 引用 • 89177 回帖 • 1 关注
  • Q&A

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

    8094 引用 • 36944 回帖 • 161 关注

相关帖子

被采纳的回答
  • 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);
      }
    });
    })()
    
    

欢迎来到这里!

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

注册 关于
请输入回帖内容 ...
  • 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 回复
  • 其他回帖
  • 引述、超级块、折叠

    image.png

    image.png

    image.png

    1 回复
  • wenbocn

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

  • wenbocn

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

  • 查看全部回帖

推荐标签 标签

  • PHP

    PHP(Hypertext Preprocessor)是一种开源脚本语言。语法吸收了 C 语言、 Java 和 Perl 的特点,主要适用于 Web 开发领域,据说是世界上最好的编程语言。

    179 引用 • 407 回帖 • 487 关注
  • 书籍

    宋真宗赵恒曾经说过:“书中自有黄金屋,书中自有颜如玉。”

    77 引用 • 390 回帖
  • 笔记

    好记性不如烂笔头。

    308 引用 • 793 回帖
  • 链滴

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

    记录生活,连接点滴

    153 引用 • 3783 回帖
  • iOS

    iOS 是由苹果公司开发的移动操作系统,最早于 2007 年 1 月 9 日的 Macworld 大会上公布这个系统,最初是设计给 iPhone 使用的,后来陆续套用到 iPod touch、iPad 以及 Apple TV 等产品上。iOS 与苹果的 Mac OS X 操作系统一样,属于类 Unix 的商业操作系统。

    85 引用 • 139 回帖 • 1 关注
  • 代码片段

    代码片段分为 CSS 与 JS 两种代码,添加在 [设置 - 外观 - 代码片段] 中,这些代码会在思源笔记加载时自动执行,用于改善笔记的样式或功能。

    用户在该标签下分享代码片段时需在帖子标题前添加 [css] [js] 用于区分代码片段类型。

    68 引用 • 368 回帖
  • 安全

    安全永远都不是一个小问题。

    199 引用 • 816 回帖
  • Ant-Design

    Ant Design 是服务于企业级产品的设计体系,基于确定和自然的设计价值观上的模块化解决方案,让设计者和开发者专注于更好的用户体验。

    17 引用 • 23 回帖 • 2 关注
  • 一些有用的避坑指南。

    69 引用 • 93 回帖
  • 旅游

    希望你我能在旅途中找到人生的下一站。

    90 引用 • 899 回帖 • 3 关注
  • IDEA

    IDEA 全称 IntelliJ IDEA,是一款 Java 语言开发的集成环境,在业界被公认为最好的 Java 开发工具之一。IDEA 是 JetBrains 公司的产品,这家公司总部位于捷克共和国的首都布拉格,开发人员以严谨著称的东欧程序员为主。

    180 引用 • 400 回帖
  • Webswing

    Webswing 是一个能将任何 Swing 应用通过纯 HTML5 运行在浏览器中的 Web 服务器,详细介绍请看 将 Java Swing 应用变成 Web 应用

    1 引用 • 15 回帖 • 628 关注
  • Bug

    Bug 本意是指臭虫、缺陷、损坏、犯贫、窃听器、小虫等。现在人们把在程序中一些缺陷或问题统称为 bug(漏洞)。

    75 引用 • 1737 回帖 • 4 关注
  • 数据库

    据说 99% 的性能瓶颈都在数据库。

    340 引用 • 708 回帖
  • BAE

    百度应用引擎(Baidu App Engine)提供了 PHP、Java、Python 的执行环境,以及云存储、消息服务、云数据库等全面的云服务。它可以让开发者实现自动地部署和管理应用,并且提供动态扩容和负载均衡的运行环境,让开发者不用考虑高成本的运维工作,只需专注于业务逻辑,大大降低了开发者学习和迁移的成本。

    19 引用 • 75 回帖 • 639 关注
  • Unity

    Unity 是由 Unity Technologies 开发的一个让开发者可以轻松创建诸如 2D、3D 多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

    25 引用 • 7 回帖 • 174 关注
  • 设计模式

    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

    200 引用 • 120 回帖
  • DevOps

    DevOps(Development 和 Operations 的组合词)是一组过程、方法与系统的统称,用于促进开发(应用程序/软件工程)、技术运营和质量保障(QA)部门之间的沟通、协作与整合。

    47 引用 • 25 回帖
  • WordPress

    WordPress 是一个使用 PHP 语言开发的博客平台,用户可以在支持 PHP 和 MySQL 数据库的服务器上架设自己的博客。也可以把 WordPress 当作一个内容管理系统(CMS)来使用。WordPress 是一个免费的开源项目,在 GNU 通用公共许可证(GPLv2)下授权发布。

    66 引用 • 114 回帖 • 228 关注
  • 微软

    微软是一家美国跨国科技公司,也是世界 PC 软件开发的先导,由比尔·盖茨与保罗·艾伦创办于 1975 年,公司总部设立在华盛顿州的雷德蒙德(Redmond,邻近西雅图)。以研发、制造、授权和提供广泛的电脑软件服务业务为主。

    8 引用 • 44 回帖 • 1 关注
  • Gzip

    gzip (GNU zip)是 GNU 自由软件的文件压缩程序。我们在 Linux 中经常会用到后缀为 .gz 的文件,它们就是 Gzip 格式的。现今已经成为互联网上使用非常普遍的一种数据压缩格式,或者说一种文件格式。

    9 引用 • 12 回帖 • 137 关注
  • WebClipper

    Web Clipper 是一款浏览器剪藏扩展,它可以帮助你把网页内容剪藏到本地。

    3 引用 • 9 回帖
  • NGINX

    NGINX 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 NGINX 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,第一个公开版本 0.1.0 发布于 2004 年 10 月 4 日。

    311 引用 • 546 回帖
  • WebComponents

    Web Components 是 W3C 定义的标准,它给了前端开发者扩展浏览器标签的能力,可以方便地定制可复用组件,更好的进行模块化开发,解放了前端开发者的生产力。

    1 引用
  • 锤子科技

    锤子科技(Smartisan)成立于 2012 年 5 月,是一家制造移动互联网终端设备的公司,公司的使命是用完美主义的工匠精神,打造用户体验一流的数码消费类产品(智能手机为主),改善人们的生活质量。

    4 引用 • 31 回帖 • 6 关注
  • RabbitMQ

    RabbitMQ 是一个开源的 AMQP 实现,服务器端用 Erlang 语言编写,支持多种语言客户端,如:Python、Ruby、.NET、Java、C、PHP、ActionScript 等。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

    49 引用 • 60 回帖 • 360 关注
  • Vditor

    Vditor 是一款浏览器端的 Markdown 编辑器,支持所见即所得、即时渲染(类似 Typora)和分屏预览模式。它使用 TypeScript 实现,支持原生 JavaScript、Vue、React 和 Angular。

    351 引用 • 1812 回帖 • 2 关注