[js] 闪卡 JS 分享(方便在数据库上制作闪卡)-2025.11.06 修

年(不)久失修,让 AI 改了下,能跑了。原帖见:[js] 闪卡 JS 分享(方便在数据库上制作闪卡) - 链滴

(() => {
    // 块菜单配置
    const menus = [
        {
            name: "快速制卡",
            operation: "add",
        },
        {
            name: "取消制卡",
            operation: "remove",
        }
    ];

    // 监听块右键菜单
    whenElementExist('#commonMenu .b3-menu__items').then((menuItems) => {
        const menusReverse = menus.reverse();
        observeBlockMenu(menuItems, async (isTargetMenu) => {
            if (menuItems.querySelector('.operate-my-card')) return;
            const addAv = menuItems.querySelector('button[data-id="addToDatabase"]');
            if (!addAv) return;
            if (menus.length === 0) return;
          
            // 生成块菜单
            menusReverse.forEach((menu, index) => {
                const menuText = menu.name;
                const menuIcon = '#iconRiffCard';
                const menuClass = `operate-my-card-${menu.operation}-${menus.length - index - 1}`;
                const menuButtonHtml = `<button class="b3-menu__item ${menuClass}"><svg class="b3-menu__icon " style=""><use xlink:href="${menuIcon}"></use></svg><span class="b3-menu__label">${menuText}</span></button>`;
                addAv.insertAdjacentHTML('afterend', menuButtonHtml);
                const menuBtn = menuItems.querySelector('.' + menuClass);
              
                // 块菜单点击事件
                menuBtn.onclick = async () => {
                    window.siyuan.menus.menu.remove();
                    await menuItemClick(menu.operation);
                };
            });
        });
    });

    // 菜单点击事件
    async function menuItemClick(operation) {
        let blocks = [];
        const selectedRows = document.querySelectorAll('.av__row.av__row--select');
      
        console.log('选中的行数:', selectedRows.length); // 调试日志
      
        // 遍历每个选中的行
        selectedRows.forEach((row, index) => {
            // 修复:使用正确的选择器
            const blockRefNodes = row.querySelectorAll('[data-type="block-ref"]');
            console.log(`第${index}行块引用数量:`, blockRefNodes.length); // 调试日志
          
            // 遍历这些元素,提取 data-id
            blockRefNodes.forEach(node => {
                const dataId = node.dataset.id;
                console.log('找到块引用:', dataId); // 调试日志
                if (dataId) {
                    blocks.push(dataId);
                }
            });
        });

        console.log('最终收集的块ID:', blocks); // 调试日志

        if (blocks.length === 0) {
            showMessage('未找到任何块引用,请确保选中了包含块引用的行');
            return;
        }

        if (operation === 'remove') {
            await removeFlashcard(blocks);
        } else {
            await addFlashcard(blocks);
        }
    }

    // 快速制卡
    async function addFlashcard(blockIds) {
        console.log('开始添加闪卡:', blockIds); // 调试日志
        blockIds = typeof blockIds === 'string' ? [blockIds] : blockIds;
        try {
            const result = await requestApi("/api/riff/addRiffCards", {
                "blockIDs": blockIds,
                "deckID": "20230218211946-2kw8jgx"
            });
            console.log('添加闪卡结果:', result); // 调试日志
            if (result && result.code === 0) {
                showMessage(`成功添加 ${blockIds.length} 个闪卡`);
            } else {
                showMessage('添加闪卡失败: ' + (result?.msg || '未知错误'));
                console.error('添加闪卡失败:', result);
            }
        } catch (error) {
            showMessage('添加闪卡请求失败: ' + error.message);
            console.error('添加闪卡请求失败:', error);
        }
    }

    async function removeFlashcard(blockIds) {
        console.log('开始移除闪卡:', blockIds); // 调试日志
        blockIds = typeof blockIds === 'string' ? [blockIds] : blockIds;
        try {
            const result = await requestApi("/api/riff/removeRiffCards", {
                "blockIDs": blockIds,
                "deckID": "20230218211946-2kw8jgx"
            });
            console.log('移除闪卡结果:', result); // 调试日志
            if (result && result.code === 0) {
                showMessage(`成功移除 ${blockIds.length} 个闪卡`);
            } else {
                showMessage('移除闪卡失败: ' + (result?.msg || '未知错误'));
                console.error('移除闪卡失败:', result);
            }
        } catch (error) {
            showMessage('移除闪卡请求失败: ' + error.message);
            console.error('移除闪卡请求失败:', error);
        }
    }

    async function requestApi(url, data, method = 'POST') {
        const response = await fetch(url, { 
            method: method, 
            body: JSON.stringify(data || {}) 
        });
        return await response.json();
    }

    // 显示消息
    function showMessage(message) {
        window.siyuan.showMessage(message, 3000);
    }

    /**
     * 监控 body 直接子元素中 #commonMenu 的添加
     */
    function observeBlockMenu(selector, callback) {
        let isTargetMenu = false;
        const observer = new MutationObserver((mutationsList) => {
            for (const mutation of mutationsList) {
                if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
                    mutation.addedNodes.forEach((node) => {
                        if (isTargetMenu) return;
                        if (node.nodeType === 1 && node.closest('[data-id="fields"]')) {
                            isTargetMenu = true;
                        }
                        if (isTargetMenu) {
                            callback(isTargetMenu);
                            setTimeout(() => {
                                isTargetMenu = false;
                            }, 200);
                        }
                    });
                }
            }
        });

        observer.observe(selector || document.body, {
            childList: true,
            subtree: false,
        });

        return observer;
    }

    // 等待元素出现
    function whenElementExist(selector, node) {
        return new Promise(resolve => {
            const check = () => {
                const el = typeof selector === 'function' ? selector() : (node || document).querySelector(selector);
                if (el) resolve(el); else requestAnimationFrame(check);
            };
            check();
        });
    }
})();
  • 思源笔记

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

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

    28442 引用 • 119752 回帖
  • 代码片段

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

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

    285 引用 • 1983 回帖

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • 音乐

    你听到信仰的声音了么?

    63 引用 • 513 回帖 • 1 关注
  • OpenShift

    红帽提供的 PaaS 云,支持多种编程语言,为开发人员提供了更为灵活的框架、存储选择。

    14 引用 • 20 回帖 • 687 关注
  • PHP

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

    167 引用 • 408 回帖 • 494 关注
  • Spark

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

    74 引用 • 46 回帖 • 563 关注
  • 运维

    互联网运维工作,以服务为中心,以稳定、安全、高效为三个基本点,确保公司的互联网业务能够 7×24 小时为用户提供高质量的服务。

    151 引用 • 257 回帖 • 1 关注
  • OneDrive
    2 引用 • 2 关注
  • 机器学习

    机器学习(Machine Learning)是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。

    78 引用 • 37 回帖
  • Facebook

    Facebook 是一个联系朋友的社交工具。大家可以通过它和朋友、同事、同学以及周围的人保持互动交流,分享无限上传的图片,发布链接和视频,更可以增进对朋友的了解。

    4 引用 • 15 回帖 • 445 关注
  • 笔记

    好记性不如烂笔头。

    315 引用 • 790 回帖
  • 思源笔记

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

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

    28442 引用 • 119750 回帖
  • Python

    Python 是一种面向对象、直译式电脑编程语言,具有近二十年的发展历史,成熟且稳定。它包含了一组完善而且容易理解的标准库,能够轻松完成很多常见的任务。它的语法简捷和清晰,尽量使用无异义的英语单词,与其它大多数程序设计语言使用大括号不一样,它使用缩进来定义语句块。

    561 引用 • 677 回帖 • 1 关注
  • 服务

    提供一个服务绝不仅仅是简单的把硬件和软件累加在一起,它包括了服务的可靠性、服务的标准化、以及对服务的监控、维护、技术支持等。

    41 引用 • 24 回帖 • 2 关注
  • 996
    13 引用 • 200 回帖 • 6 关注
  • SendCloud

    SendCloud 由搜狐武汉研发中心孵化的项目,是致力于为开发者提供高质量的触发邮件服务的云端邮件发送平台,为开发者提供便利的 API 接口来调用服务,让邮件准确迅速到达用户收件箱并获得强大的追踪数据。

    2 引用 • 8 回帖 • 544 关注
  • LaTeX

    LaTeX(音译“拉泰赫”)是一种基于 ΤΕΧ 的排版系统,由美国计算机学家莱斯利·兰伯特(Leslie Lamport)在 20 世纪 80 年代初期开发,利用这种格式,即使使用者没有排版和程序设计的知识也可以充分发挥由 TeX 所提供的强大功能,能在几天,甚至几小时内生成很多具有书籍质量的印刷品。对于生成复杂表格和数学公式,这一点表现得尤为突出。因此它非常适用于生成高印刷质量的科技和数学类文档。

    14 引用 • 84 回帖 • 1 关注
  • Docker

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的操作系统上。容器完全使用沙箱机制,几乎没有性能开销,可以很容易地在机器和数据中心中运行。

    498 引用 • 934 回帖
  • 尊园地产

    昆明尊园房地产经纪有限公司,即:Kunming Zunyuan Property Agency Company Limited(简称“尊园地产”)于 2007 年 6 月开始筹备,2007 年 8 月 18 日正式成立,注册资本 200 万元,公司性质为股份经纪有限公司,主营业务为:代租、代售、代办产权过户、办理银行按揭、担保、抵押、评估等。

    1 引用 • 22 回帖 • 838 关注
  • SOHO

    为成为自由职业者在家办公而努力吧!

    7 引用 • 55 回帖 • 1 关注
  • MySQL

    MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 公司。MySQL 是最流行的关系型数据库管理系统之一。

    695 引用 • 538 回帖
  • V2Ray
    1 引用 • 15 回帖 • 5 关注
  • Ant-Design

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

    17 引用 • 23 回帖 • 12 关注
  • 微软

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

    8 引用 • 44 回帖 • 2 关注
  • Quicker

    Quicker 您的指尖工具箱!操作更少,收获更多!

    39 引用 • 170 回帖
  • 外包

    有空闲时间是接外包好呢还是学习好呢?

    26 引用 • 234 回帖 • 3 关注
  • Kafka

    Kafka 是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是现代系统中许多功能的基础。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。

    36 引用 • 35 回帖
  • TensorFlow

    TensorFlow 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库。节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)。

    20 引用 • 19 回帖 • 1 关注
  • DNSPod

    DNSPod 建立于 2006 年 3 月份,是一款免费智能 DNS 产品。 DNSPod 可以为同时有电信、网通、教育网服务器的网站提供智能的解析,让电信用户访问电信的服务器,网通的用户访问网通的服务器,教育网的用户访问教育网的服务器,达到互联互通的效果。

    6 引用 • 26 回帖 • 548 关注