[思源笔记挂件] Query: 一个将思源笔记数据库查询结果以表格样式渲染的挂件

本贴最后更新于 800 天前,其中的信息可能已经时移世改

项目地址: Zuoqiu-Yingyi/widget-query

本文章不会与项目文档同步更新, 可能已经过时, 具体内容请以项目的 README 为准

widget-query

GitHub release (latest by date including pre-releases) GitHub Release Date GitHub GitHub last commit GitHub repo size jsDelivr hits (GitHub) GitHub all releases

一个将思源笔记数据库查询结果以表格样式渲染的挂件

现已上架思源笔记社区集市, 如果您需要订阅思源笔记增值服务,欢迎使用我的推荐码: h0sc9rc

预览 | PREVIEW

1644419419908.png

1644420736088.png

功能 | FUNCTION

  1. 符合正则表达式 ^\s*SELECT\s+\*\s+FROM\s+blocks.* 的 SQL 语句将启用自定义渲染模式
    • 这个正则表达式在 /src/script/module/config.js 中的 config.query.regs.blocks 配置
  2. 自定义渲染模式 | Custom rendering modes
    • 可以在 config.query.limit 中设置过长查询结果的截取方案
      • config.query.maxlen: 最大长度
      • config.query.maxrow: 最多行数
    • 可以在 config.query.fields 中设置想要显示的字段
    • 可以在 config.query.align 中设置各字段的对齐方式
    • 可以在 config.query.handler 中设置各字段的处理方法
  3. 部分模板字段解析支持
    • .prefix{.field}
      • prefix: 前缀字段
        • block: 挂件块
        • parent: 挂件块的上级块
        • root: 挂件块所在文档块
      • field: 属性字段
        • 数据库中 blocks 表的字段名
  4. 普通模式
    • 完整显示查询结果

自定义配置 | CUSTOM CONFIG

  1. 创建文件 <工作空间>/data/widgets/custom.js
  2. 在文件 <工作空间>/data/widgets/custom.js 中定义的值将覆盖 <工作空间>/widgets/Query/src/script/module/config.js 中对应的值

配置示例 | CONFIG EXAMPLE

/* 路径 | Path
 * <工作空间>/data/widgets/custom.js
 * <workspace>/data/widgets/custom.js
 */

import {
    cutString,
    ReplaceSpace,
    ReplaceCRLF,
    ialParser,
    markdown2span,
    timestampFormat,
    isEmptyString,
} from '/widgets/Query/src/script/utils/string.js';

import {
    templateParse
} from '/widgets/Query/src/script/utils/templateParser.js'

export var config = {
    token: '', // API token, 无需填写
    query: { // 查询配置
        width: '128px', // 宽度
        height: '32px', // 高度
        radius: '8px', // 圆角
        regs: {
            blocks: /^\s*SELECT\s+\*\s+FROM\s+blocks.*/i, // 块查询的正则表达式
        },
        maxlen: 64, // 查询结果每个字段最大长度
        maxrow: 3, // 查询结果每个字段最大行数
        limit: 'row', // 查询结果字段限制, (null 为不限制, 'len' 为限制长度, 'row' 为限制行数)
        CRLF: '<br />', // 换行符替换
        space: ' ', // 空白字符替换
        template: { // 类似模板字段解析支持, 类似 .prefix{.field}, 目前支持的有 .root{.<挂件所在文档块的字段名>} .parent{.<挂件上级块的字段名>} .block{挂件块的字段名}
            enable: true, // 是否启用模板解析
            handler: async (data) => { // 模板解析处理函数
                return await templateParse(data);
            }
        },
        fields: [ // 需渲染的 blocks 表的字段, 顺序分先后
            // 'content', // 去除了 Markdown 标记符的文本
            'markdown', // 包含完整 Markdown 标记符的文本
            'created', // 创建时间
            'updated', // 更新时间
            'type', // 内容块类型,参考((20210210103523-ombf290 "类型字段"))
            'hpath', // 人类可读的内容块所在文档路径

            // 'id', // 内容块 ID
            // 'parent_id', // 双亲块 ID, 如果内容块是文档块则该字段为空
            // 'root_id', // 文档块 ID
            // 'box', // 笔记本 ID
            // 'path', // 内容块所在文档路径
            // 'name', // 内容块名称
            // 'alias', // 内容块别名
            // 'memo', // 内容块备注
            // 'hash', // content 字段的 SHA256 校验和
            // 'length', // markdown 字段文本长度
            // 'subtype', // 内容块子类型,参考((20210210103411-tcbcjja "子类型字段"))
            // 'ial', // 内联属性列表,形如 `{: name="value"}`
            // 'sort', // 排序权重, 数值越小排序越靠前
        ],
        align: { // 查询结果字段对齐样式(':-' 左对齐, ':-:' 居中, '-:' 右对齐)
            content: ':-',
            markdown: ':-',
            created: ':-:',
            updated: ':-:',
            type: ':-:',
            hpath: ':-',

            id: ':-:',
            parent_id: ':-:',
            root_id: ':-:',
            hash: ':-:',
            box: ':-:',
            path: ':-',
            name: ':-',
            alias: ':-',
            memo: ':-',
            length: '-:',
            subtype: '-:',
            ial: ':-',
            sort: '-:',
        },
        default: {
            handler: (row) => { // 其他查询结果默认处理方法
                return `\`${row[key]}\``;
            },
        },
        handler: { // 块查询结果各字段处理方法
            content: (row) => {
                switch (config.query.limit) {
                    case 'len':
                        return markdown2span(cutString(ReplaceSpace(row.content, config.query.space), config.query.maxlen));
                    case 'row':
                        return markdown2span(ReplaceCRLF(cutString(row.content, undefined, config.query.maxrow), config.query.CRLF));
                    default:
                        return markdown2span(row.content);
                }
            },
            markdown: (row) => {
                switch (config.query.limit) {
                    case 'len':
                        return markdown2span(cutString(ReplaceSpace(row.markdown, config.query.space), config.query.maxlen));
                    case 'row':
                        return markdown2span(ReplaceCRLF(cutString(row.markdown, undefined, config.query.maxrow), config.query.CRLF));
                    default:
                        return markdown2span(row.markdown);
                }
            },
            created: (row) => {
                return timestampFormat(row.created);
            },
            updated: (row) => {
                return timestampFormat(row.updated);
            },
            type: (row) => {
                return `((${row.id} "${config.query.map.blocktype[row.type]}"))`;
            },
            hpath: (row) => {
                return `((${row.root_id} "${row.hpath}"))`;
            },

            id: (row) => {
                return `((${row.id} "${row.id}"))`;
            },
            parent_id: (row) => {
                if (isEmptyString(row.parent_id)) return '';
                else return `((${row.parent_id} "${row.parent_id}"))`;
            },
            root_id: (row) => {
                return `((${row.root_id} "${row.root_id}"))`;
            },
            hash: (row) => {
                return `\`${row.hash}\``;
            },
            box: (row) => {
                return `\`${row.box}\``;
            },
            path: (row) => {
                return `\`${row.path}\``;
            },
            name: (row) => {
                return markdown2span(row.name);
            },
            alias: (row) => {
                return markdown2span(row.alias);
            },
            memo: (row) => {
                return markdown2span(row.memo);
            },
            length: (row) => {
                return row.length;
            },
            subtype: (row) => {
                return config.query.map.subtype[row.subtype];
            },
            ial: (row) => {
                let ial = ialParser(row.ial);
                let ial_markdown = [];
                for (let key of Object.keys(ial)) {
                    switch (key) {
                        case 'id':
                        case 'updated':
                            continue;
                        case 'icon':
                            ial_markdown.push(`\`${key}\`\: :${ial[key].replace(/\.\w+$/, '')}:`);
                            break;
                        default:
                            ial_markdown.push(`\`${key}\`\: \`${ial[key]}\``);
                            break;
                    }
                }
                return ial_markdown.join(config.query.CRLF);
            },
            sort: (row) => {
                return row.sort;
            },
        },
        map: { // 映射表
            blocktype: { // 块类型映射
                d: '文档块',
                h: '标题块',
                l: '列表块',
                i: '列表项',
                c: '代码块',
                m: '公式块',
                t: '表格块',
                b: '引述块',
                s: '超级块',
                p: '段落块',
                tb: '分隔线',
                video: '视频块',
                audio: '音频块',
                widget: '挂件块',
                iframe: 'iframe',
                query_embed: '嵌入块',
                '': '',
                null: '',
                undefined: '',
            },
            subtype: { // 子类型映射
                o: '有序列表',
                u: '无序列表',
                t: '任务列表',
                h1: '一级标题',
                h2: '二级标题',
                h3: '三级标题',
                h4: '四级标题',
                h5: '五级标题',
                h6: '六级标题',
                '': '',
                null: '',
                undefined: '',
            },
        },
    },
};

开始 | START

该挂件已在思源笔记社区集市上架, 可直接在集市中安装

参考 & 感谢 | REFERENCE & THANKS

作者 | Author 项目 | Project 许可证 | License
leolee9086 leolee9086/cc-baselib Unknown

更改日志 | CHANGE LOG

CHANGE LOG

  • 思源笔记

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

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

    18619 引用 • 69283 回帖

相关帖子

欢迎来到这里!

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

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

    这个挂件真的很不错啊

  • 其他回帖
  • SELECT
        *
    FROM
        blocks
    WHERE
        id IN (
            SELECT
                block_id
            FROM
                attributes
            WHERE
                name = 'custom-class'
                AND value = 'report'
        )
        AND id IN (
            SELECT
                block_id
            FROM
                attributes
            WHERE
                name = 'custom-status'
                AND value = 'finish'
        )
    

    上述 SQL 语句我没有测试过, 不过应该可以满足要求

  • 孩子用上了,很喜欢

    image.png

  • akaCarlo

    感谢前面的回答,再请教下,如果通过搜索自定义属性,返回同时满足两项自定义属性的内容,比如说 custom-class 为 report,与此同时 custom-status 为 finish

    1 回复
  • 查看全部回帖