API 获取并处理块的一些疑问

因为突然想要写一个插件来帮我格式化一下普通的内容块,所以今天研究了一个晚上的插件开发和 api,现在发现内容块 API 有点问题不好理解,希望各位能帮我解答一二。

  1. 在更新块 API 里支持两种模式:markdownDOM。不过这两种元素我感觉都不是很好获取。
    1. 使用 api 能获取的是 kramdown,这个会带有 {: updated id} 属性,要是用 markdown 再发回去就会当成普通的文字放进去。
    2. DOM 也不算好获取,从块标里面的插件按钮获取到的结果是不带 HTML 的,没法获取当前元素的 html。这样难道只能用 ts 去页面里获取吗?
  2. 获取了 kramdown 之后,如果要更新块一定要去掉 {: updated id} 这个属性吗,有没有可能不处理这个属性也不影响文本显示的办法?
  3. 有可能通过 api 获取到当前块的 dom?或者获取到当前块的类型?
  4. 还在继续思考中...感谢各位的帮助。如果想要先行了解代码可以先在这里了解最新的进度。目前通过 ai 暂时解决了 {: updated id} 属性,不过这个方法不算好,也希望各位能帮我提出一些建议。
  • 思源笔记

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

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

    23064 引用 • 92800 回帖
  • Q&A

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

    8470 引用 • 38572 回帖 • 154 关注

相关帖子

被采纳的回答
  • "/api/block/insertBlock" "/api/block/updateBlock" 可以传入 kramdown。 内容与属性需要用 '\n' 来隔开。

    id updated 可以不用去掉。 如果你要插入新的块,需要生成新的 id 避免重复。

    "/api/block/getBlockDOM" 可以按块 id 读取 dom.

    "/api/transactions" 可以按 dom 来更新或者插入等。

    另外, dom 与 markdown 的转换可以用:
    export const NewLute: () => Lute = (globalThis as any).Lute.New;

    lute = NewLute();

    const md = lute.BlockDOM2Md(div.outerHTML);

    export class Lute {
        public static WalkStop: number;
        public static WalkSkipChildren: number;
        public static WalkContinue: number;
        public static Version: string;
        public static Caret: string;
    
        public static New(): Lute;
    
        public static EChartsMindmapStr(text: string): string;
    
        public static NewNodeID(): string;
    
        public static Sanitize(html: string): string;
    
        public static EscapeHTMLStr(str: string): string;
    
        public static UnEscapeHTMLStr(str: string): string;
    
        public static GetHeadingID(node: ILuteNode): string;
    
        public static BlockDOM2Content(html: string): string;
    
        private constructor();
    
        public BlockDOM2Content(text: string): string;
    
        public BlockDOM2EscapeMarkerContent(text: string): string;
    
        public SetSpin(enable: boolean): void;
    
        public SetTextMark(enable: boolean): void;
    
        public SetHTMLTag2TextMark(enable: boolean): void;
    
        public SetHeadingID(enable: boolean): void;
    
        public SetProtyleMarkNetImg(enable: boolean): void;
    
        public SetSpellcheck(enable: boolean): void;
    
        public SetFileAnnotationRef(enable: boolean): void;
    
        public SetSetext(enable: boolean): void;
    
        public SetYamlFrontMatter(enable: boolean): void;
    
        public SetChineseParagraphBeginningSpace(enable: boolean): void;
    
        public SetRenderListStyle(enable: boolean): void;
    
        public SetImgPathAllowSpace(enable: boolean): void;
    
        public SetKramdownIAL(enable: boolean): void;
    
        public BlockDOM2Md(html: string): string;
    
        public BlockDOM2StdMd(html: string): string;
    
        public SetSuperBlock(enable: boolean): void;
    
        public SetTag(enable: boolean): void;
    
        public SetInlineMath(enable: boolean): void;
    
        public SetGFMStrikethrough(enable: boolean): void;
    
        public SetGFMStrikethrough1(enable: boolean): void;
    
        public SetMark(enable: boolean): void;
    
        public SetSub(enable: boolean): void;
    
        public SetSup(enable: boolean): void;
    
        public SetInlineAsterisk(enable: boolean): void;
    
        public SetInlineUnderscore(enable: boolean): void;
    
        public SetBlockRef(enable: boolean): void;
    
        public SetSanitize(enable: boolean): void;
    
        public SetHeadingAnchor(enable: boolean): void;
    
        public SetImageLazyLoading(imagePath: string): void;
    
        public SetInlineMathAllowDigitAfterOpenMarker(enable: boolean): void;
    
        public SetToC(enable: boolean): void;
    
        public SetIndentCodeBlock(enable: boolean): void;
    
        public SetParagraphBeginningSpace(enable: boolean): void;
    
        public SetFootnotes(enable: boolean): void;
    
        public SetLinkRef(enable: boolean): void;
    
        public SetEmojiSite(emojiSite: string): void;
    
        public PutEmojis(emojis: IObject): void;
    
        public SpinBlockDOM(html: string): string;
    
        public Md2BlockDOM(html: string): string;
    
        public SetProtyleWYSIWYG(wysiwyg: boolean): void;
    
        public MarkdownStr(name: string, md: string): string;
    
        public GetLinkDest(text: string): string;
    
        public BlockDOM2InlineBlockDOM(html: string): string;
    
        public BlockDOM2HTML(html: string): string;
    
        public HTML2Md(html: string): string;
    
        public HTML2BlockDOM(html: string): string;
    }
    

欢迎来到这里!

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

注册 关于
请输入回帖内容 ...
  • EmptyLight 1 评论

    大佬,抱歉打扰一下,我发现 /api/transactions 进行的 update 操作(见 Achuan-2 的回帖)突然就没有写入块 protyle 的 undo 属性,导致撤回操作不能生效。请问这个应该怎么排查问题,代码和实现思路基本上和代码块一致。还是说应该检查一下思源的 respond 来判断有没有成功更新?


    在 protyle 里面的 transactionsTimeundoupdated 这些变量都没有更新,还保持着更新前的状态。

    1 操作
    EmptyLight 在 2024-12-23 20:12:52 更新了该回帖
    undo 要自己加。不然就没有
    player
  • 其他回帖
  • Achuan-2 1

    想问问大佬,/api/transactions 的传入值有没有示例呢,data 值是传入 id 和操作 update 就可以了吗


    摸索了下,这样就能把 html 修改的内容保存了

    // 1. 获取目标元素
    const targetElement = document.querySelector('div[data-node-id="20241205223647-qaxnubd"]');
    
    // 2. 获取 HTML 内容 (并进行一些基本的错误处理)
    let originalHtmlContent = ""; // 用于保存原始 HTML 内容
    let originalNowTime; // 用于保存原始时间
    
    if (targetElement) {
        originalHtmlContent = targetElement.outerHTML;
    } else {
        console.error("未找到指定 data-node-id 的元素!");
        // 可以选择在这里返回或者执行其他错误处理逻辑
        // return; 
    }
    
    // 修改HTML
    newHtmlContent = targetElement.outerHTML;
    
    // 3. 更新
    let nowTime = new Date().getTime(); // 更新后的时间
    const res = await fetchSyncPost("/api/transactions", {
        session: siyuan.ws.app.appId,
        app: siyuan.ws.app.appId,
        reqId: nowTime,
        transactions: [{
            "doOperations": [{
                action: "update",
                id: '20241205223647-qaxnubd',
                data: newHtmlContent, // 更新后的 HTML 内容 (如果需要更新)
            }],
            "undoOperations": [{
                action: "update",
                id: '20241205223647-qaxnubd',
                data: originalHtmlContent, // 使用原始 HTML 内容
            }]
        }]
    });
    console.log(res);
    
    
    3 回复
    1 操作
    Achuan-2 在 2024-12-18 07:22:50 更新了该回帖
  • EmptyLight 1 赞同

    大佬,我在用 transactions 更新之后块内容显示[object Object],需要刷新才能显示内容是不是哪里没用对,还是事务执行本身需要刷新


    不需要了,我已经试出来了,是我传入的时候把获取到的 dom 整个传进入了,把里面的 html 取出来就可以了

    1 操作
    EmptyLight 在 2024-12-20 20:54:35 更新了该回帖
  • 数据库的,有些可能不通用。

     transSetAttrViewColWrap(avID: string, blockID: string, colID: string, wrap = true) {
            const op = {} as IOperation;
            op.action = "setAttrViewColWrap";
            op.avID = avID;
            op.blockID = blockID;
            op.id = colID;
            op.data = wrap;
            return op;
        },
        transSetAttrViewColHidden(avID: string, blockID: string, colID: string, hide = true) {
            const op = {} as IOperation;
            op.action = "setAttrViewColHidden";
            op.avID = avID;
            op.blockID = blockID;
            op.id = colID;
            op.data = hide
            return op;
        },
        transSetAttrViewSorts(avID: string, blockID: string, colID: string, order: "ASC" | "DESC") {
            const op = {} as IOperation;
            op.action = "setAttrViewSorts";
            op.avID = avID;
            op.blockID = blockID;
            op.data = [{ column: colID, order }]
            return op;
        },
        transSetAttrViewColCalc(avID: string, blockID: string, colID: string, operator: CalcOperator) {
            const op = {} as IOperation;
            op.action = "setAttrViewColCalc";
            op.avID = avID;
            op.data = { operator };
            op.blockID = blockID;
            op.id = colID;
            return op;
        },
        transSetAttrViewFilters(avID: string, blockID: string, filters: IAVFilter[]) {
            const op = {} as IOperation;
            op.action = "setAttrViewFilters";
            op.avID = avID;
            op.data = filters;
            op.blockID = blockID;
            return op;
        },
        transSetAttrViewViewName(avID: string, viewID: string, name: string) {
            const op = {} as IOperation;
            op.action = "setAttrViewViewName";
            op.avID = avID;
            op.id = viewID;
            op.data = name;
            return op;
        },
        transUpdateAttrViewCol(avID: string, colId: string, name: string, type?: TAVCol) {
            const op = {} as IOperation;
            op.action = "updateAttrViewCol";
            op.id = colId;
            op.avID = avID;
            op.name = name;
            op.type = type;
            return op;
        },
        transSetAttrViewName(avID: string, name: string) {
            const op = {} as IOperation;
            op.action = "setAttrViewName";
            op.id = avID;
            op.data = name;
            return op;
        },
        transRemoveAttrViewCol(avID: string, colID: string) {
            const op = {} as IOperation;
            op.action = "removeAttrViewCol";
            op.avID = avID;
            op.id = colID;
            return op;
        },
        transAddAttrViewCol(avID: string, name: string, id = NewNodeID(), type: TAVCol = "text", previousID = "") {
            const op = {} as IOperation;
            op.action = "addAttrViewCol";
            op.avID = avID;
            op.name = name;
            op.previousID = previousID;
            op.type = type;
            op.id = id;
            return op;
        },
        transUpdateAttrViewCellBatch(args: { avID: string, cellID?: string, colID: string, rowID_BlockID: string, value: IAVCellValue }[]) {
            return args.map(arg => {
                const op = {} as IOperation;
                op.action = "updateAttrViewCell";
                op.avID = arg.avID;
                op.id = arg.cellID;
                op.keyID = arg.colID;
                op.rowID = arg.rowID_BlockID;
                op.data = arg.value;
                return op;
            })
        },
        transInsertAttrViewBlock(avID: string, blockID: string, srcs: IOperationSrcs[], previousID = "", ignoreFillFilter = true) {
            const op = {} as IOperation;
            op.action = "insertAttrViewBlock";
            op.avID = avID;
            op.blockID = blockID;
            op.previousID = previousID;
            op.ignoreFillFilter = ignoreFillFilter;
            op.srcs = srcs;
            return op;
        },
        transDoUpdateUpdated(blockID: string, data = timeUtil.getYYYYMMDDHHmmss()) {
            const op = {} as IOperation;
            op.action = "doUpdateUpdated";
            op.id = blockID
            op.data = data
            return op;
        },
    
  • 查看全部回帖

推荐标签 标签

  • LeetCode

    LeetCode(力扣)是一个全球极客挚爱的高质量技术成长平台,想要学习和提升专业能力从这里开始,充足技术干货等你来啃,轻松拿下 Dream Offer!

    209 引用 • 72 回帖
  • App

    App(应用程序,Application 的缩写)一般指手机软件。

    91 引用 • 384 回帖
  • GitBook

    GitBook 使您的团队可以轻松编写和维护高质量的文档。 分享知识,提高团队的工作效率,让用户满意。

    3 引用 • 8 回帖
  • PostgreSQL

    PostgreSQL 是一款功能强大的企业级数据库系统,在 BSD 开源许可证下发布。

    22 引用 • 22 回帖 • 2 关注
  • VirtualBox

    VirtualBox 是一款开源虚拟机软件,最早由德国 Innotek 公司开发,由 Sun Microsystems 公司出品的软件,使用 Qt 编写,在 Sun 被 Oracle 收购后正式更名成 Oracle VM VirtualBox。

    10 引用 • 2 回帖 • 2 关注
  • MyBatis

    MyBatis 本是 Apache 软件基金会 的一个开源项目 iBatis,2010 年这个项目由 Apache 软件基金会迁移到了 google code,并且改名为 MyBatis ,2013 年 11 月再次迁移到了 GitHub。

    170 引用 • 414 回帖 • 388 关注
  • 学习

    “梦想从学习开始,事业从实践起步” —— 习近平

    171 引用 • 512 回帖
  • SQLite

    SQLite 是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是全世界使用最为广泛的数据库引擎。

    5 引用 • 7 回帖
  • sts
    2 引用 • 2 回帖 • 198 关注
  • Sphinx

    Sphinx 是一个基于 SQL 的全文检索引擎,可以结合 MySQL、PostgreSQL 做全文搜索,它可以提供比数据库本身更专业的搜索功能,使得应用程序更容易实现专业化的全文检索。

    1 引用 • 222 关注
  • Love2D

    Love2D 是一个开源的, 跨平台的 2D 游戏引擎。使用纯 Lua 脚本来进行游戏开发。目前支持的平台有 Windows, Mac OS X, Linux, Android 和 iOS。

    14 引用 • 53 回帖 • 538 关注
  • InfluxDB

    InfluxDB 是一个开源的没有外部依赖的时间序列数据库。适用于记录度量,事件及实时分析。

    2 引用 • 76 关注
  • 思源笔记

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

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

    23064 引用 • 92800 回帖 • 1 关注
  • SMTP

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

    4 引用 • 18 回帖 • 623 关注
  • Ant-Design

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

    17 引用 • 23 回帖 • 4 关注
  • Swift

    Swift 是苹果于 2014 年 WWDC(苹果开发者大会)发布的开发语言,可与 Objective-C 共同运行于 Mac OS 和 iOS 平台,用于搭建基于苹果平台的应用程序。

    36 引用 • 37 回帖 • 536 关注
  • jsoup

    jsoup 是一款 Java 的 HTML 解析器,可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常省力的 API,可通过 DOM,CSS 以及类似于 jQuery 的操作方法来取出和操作数据。

    6 引用 • 1 回帖 • 483 关注
  • Maven

    Maven 是基于项目对象模型(POM)、通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。

    186 引用 • 318 回帖 • 282 关注
  • 强迫症

    强迫症(OCD)属于焦虑障碍的一种类型,是一组以强迫思维和强迫行为为主要临床表现的神经精神疾病,其特点为有意识的强迫和反强迫并存,一些毫无意义、甚至违背自己意愿的想法或冲动反反复复侵入患者的日常生活。

    15 引用 • 161 回帖 • 3 关注
  • Latke

    Latke 是一款以 JSON 为主的 Java Web 框架。

    71 引用 • 535 回帖 • 790 关注
  • 机器学习

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

    83 引用 • 37 回帖
  • PWL

    组织简介

    用爱发电 (Programming With Love) 是一个以开源精神为核心的民间开源爱好者技术组织,“用爱发电”象征开源与贡献精神,加入组织,代表你将遵守组织的“个人开源爱好者”的各项条款。申请加入:用爱发电组织邀请帖
    用爱发电组织官网:https://programmingwithlove.stackoverflow.wiki/

    用爱发电组织的核心驱动力:

    • 遵守开源守则,体现开源&贡献精神:以分享为目的,拒绝非法牟利。
    • 自我保护:使用适当的 License 保护自己的原创作品。
    • 尊重他人:不以各种理由、各种漏洞进行未经允许的抄袭、散播、洩露;以礼相待,尊重所有对社区做出贡献的开发者;通过他人的分享习得知识,要留下足迹,表示感谢。
    • 热爱编程、热爱学习:加入组织,热爱编程是首当其要的。我们欢迎热爱讨论、分享、提问的朋友,也同样欢迎默默成就的朋友。
    • 倾听:正确并恳切对待、处理问题与建议,及时修复开源项目的 Bug ,及时与反馈者沟通。不抬杠、不无视、不辱骂。
    • 平视:不诋毁、轻视、嘲讽其他开发者,主动提出建议、施以帮助,以和谐为本。只要他人肯努力,你也可能会被昔日小看的人所超越,所以请保持谦虚。
    • 乐观且活跃:你的努力决定了你的高度。不要放弃,多年后回头俯瞰,才会发现自己已经成就往日所仰望的水平。积极地将项目开源,帮助他人学习、改进,自己也会获得相应的提升、成就与成就感。
    1 引用 • 487 回帖 • 2 关注
  • ReactiveX

    ReactiveX 是一个专注于异步编程与控制可观察数据(或者事件)流的 API。它组合了观察者模式,迭代器模式和函数式编程的优秀思想。

    1 引用 • 2 回帖 • 162 关注
  • SEO

    发布对别人有帮助的原创内容是最好的 SEO 方式。

    35 引用 • 200 回帖 • 27 关注
  • jsDelivr

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

    5 引用 • 31 回帖 • 71 关注
  • Ubuntu

    Ubuntu(友帮拓、优般图、乌班图)是一个以桌面应用为主的 Linux 操作系统,其名称来自非洲南部祖鲁语或豪萨语的“ubuntu”一词,意思是“人性”、“我的存在是因为大家的存在”,是非洲传统的一种价值观,类似华人社会的“仁爱”思想。Ubuntu 的目标在于为一般用户提供一个最新的、同时又相当稳定的主要由自由软件构建而成的操作系统。

    126 引用 • 169 回帖
  • 设计模式

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

    200 引用 • 120 回帖