通过标签插入当前块到数据库(思源 SuperTag)

通过标签插入当前块到数据库(思源SuperTag)

根据 @qiancang 大佬的帖子实现,https://ld246.com/article/1731945645865

功能:给块设置标签,将块添加到标签同名的数据库,支持pc,web及手机版。

注意事项:

1、数据库名称需要与标签同名

2、如果有多个同名数据库,只会将块添加到其中一个,所以不要建立同名数据库

3、需要提前建立数据库才能添加成功

代码如下:(把该代码添加到思源js代码片段中即可)

// 思源通过标签插入当前块到数据库(SuperTag)
// 功能:给块设置标签,将块添加到标签同名的数据库。
// 说明;
// 1、数据库名称需要与标签同名
// 2、如果有多个同名数据库,只会将块添加到其中一个,所以不要建立同名数据库
// 3、需要提前建立数据库才能添加成功 
// version:0.0.1
// 根据qiancang大佬的帖子实现 https://ld246.com/article/1731945645865
(()=>{
    // 添加tag后多少毫秒添加当前块到数据库
    // 不宜设置过小,过小可能导致标签被插入一半
    const delay = 500;
  
    // 发布服务立即返回
    if(siyuan.config.readonly) return;
    // 监听tag输入
    observeTagSpans(async tagEl => {
        // 去掉零宽度字符&ZeroWithSpace;
        const tag = tagEl?.textContent?.replace(/[\u200B-\u200D\uFEFF]/g, '')?.trim();
        if(!tag) return;
        // 获取数据库信息
        const av = await getAvByName(tag);
        if(!av) return;
        const avId = av.avID;
        if(!avId) return;
        const avBlockID = av.blockID;
        if(!avBlockID) return;
        // 获取文档块信息
        const block = tagEl.closest('div[data-node-id][data-type]');
        const blockId = block?.dataset?.nodeId;
        if(!blockId) return;
        // 添加块到数据库
        await sleep(delay || 500);
        addBlocksToAv(blockId, avId, avBlockID);
    });
    // 插入块到数据库
    async function addBlocksToAv(blockIds, avId, avBlockID) {
        blockIds = typeof blockIds === 'string' ? [blockIds] : blockIds;
        const srcs = blockIds.map(blockId => ({
            "id": blockId,
            "isDetached": false,
        }));
        const input = {
          "avID": avId,
          "blockID": avBlockID,
          'srcs': srcs
        }
        const result = await fetchSyncPost('/api/av/addAttributeViewBlocks', input);
        if(!result || result.code !== 0) console.error(result);
    }
    // 通过该tag查询数据库
    async function getAvByName(name) {
        const result = await fetchSyncPost('/api/av/searchAttributeView', {
            "keyword": name
        });
        if(!result || result.code !== 0 || !result?.data?.results || result?.data?.results?.length === 0) return null;
        for (const av of result.data.results) {
            if (av.avName === name || av.avName === `#${name}#`) {
                return av;
            }
        }
        return null;
    }
    // 请求api
    // returnType json返回json格式,text返回文本格式
    async function fetchSyncPost(url, data, returnType = 'json') {
        const init = {
            method: "POST",
        };
        if (data) {
            if (data instanceof FormData) {
                init.body = data;
            } else {
                init.body = JSON.stringify(data);
            }
        }
        try {
            const res = await fetch(url, init);
            const res2 = returnType === 'json' ? await res.json() : await res.text();
            return res2;
        } catch(e) {
            console.log(e);
            return returnType === 'json' ? {code:e.code||1, msg: e.message||"", data: null} : "";
        }
    }
    // 延迟执行
    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
    // 监听tag被添加
    function observeTagSpans(callback) {
        // 创建一个观察者实例并传入回调函数
        const observer = new MutationObserver((mutationsList, observer) => {
            for (const mutation of mutationsList) {
                if (mutation.type === 'childList') {
                    // 检查新增的节点
                    for (const node of mutation.addedNodes) {
                        if (node.nodeType === Node.ELEMENT_NODE && node.tagName.toLowerCase() === 'span' && node.getAttribute('data-type') === 'tag') {
                            // 调用回调函数,传递新添加的元素
                            callback(node);
                        }
                    }
                }
            }
        });
        // 配置观察选项:
        const config = { 
            childList: true, // 观察子节点的变化(添加/删除)
            subtree: true // 观察所有后代节点
        };
        // 选择需要观察变动的节点
        const targetNode = document.body; // 或者选择更具体的父节点以减少性能消耗
        // 开始观察目标节点
        observer.observe(targetNode, config);
        // 返回一个取消观察的方法
        return () => observer.disconnect();
    }
})();

https://gitee.com/wish163/mysoft/blob/main/%E6%80%9D%E6%BA%90/%E6%80%9D%E6%BA%90%E9%80%9A%E8%BF%87%E6%A0%87%E7%AD%BE%E6%8F%92%E5%85%A5%E5%BD%93%E5%89%8D%E5%9D%97%E5%88%B0%E6%95%B0%E6%8D%AE%E5%BA%93SuperTag.js

效果:

r93.gif

发版说明:

之所以实现这个功能,是有人想要手机和Mac支持,无意冒犯 @qiancang 大佬的创意,如大佬后续有插件或js片段方面的计划等立即删帖。

image.png

留下你的脚步
推荐阅读