为了让文档层级导航插件能用于 MOC 笔记法,我写了一个对反链进行过滤的代码片段

使用 dailynote 笔记法的用户,会倾向于用 moc 来管理笔记,而不用文档树管理笔记,管理文档链接而不管理文档,这时候「文档层级导航插件」的显示父子文档功能就没有什么导航作用了,需要靠反链的文档来导航,显示相关文档。

由于使用 dailynote 积累笔记,反链有很多 dailynote,但这些 dailynote 和这篇文档的主题无关系只有补充信息。

我希望文档层级导航插件的反链展示可以只展示与本文档真正有关联的笔记(即真正的相关笔记),排除 dailynote 的干扰,因此希望是可以有一个选项可以过滤掉这些 dailynote 的

我给插件提了一个 issue:反链能支持排除 dailynote 笔记嘛 · Issue #64 · OpaqueGlass/syplugin-hierarchyNavigate (github.com)

暂时没得到回复,于是自己问 GPT 写了一个 js 代码片段,先用上了

具有如下功能

  1. 通过正则过滤 dailynote 笔记,此外我还有周总结、月总结的习惯,也希望反链不出现这些笔记。可以根据需要修改 filterPatterns 变量的正则表达式
  2. 对反链的文档进行排序
  3. 我习惯 moc 笔记添加前缀 @,所以额外处理,将 moc 笔记放在最前面



(async ()=>{function filterAndReorderLinks() {
    const filterPatterns = [
        /^\d{8} \w{3}$/, // Example: 20240728 Sun
        /^\d{6}$/,
        /^\d{8} ~ \d{8}$/,
        /^\d{8} \- \d{8}$/
        // Add more patterns here if needed
    ];

    const containers = document.querySelectorAll("div.og-hierachy-navigate-backlink-doc-container");
    if (containers.length === 0) {
        return;
    }

    containers.forEach(container => {
        const refLinks = container.querySelectorAll("span.refLinks.docLinksWrapper");
        if (refLinks.length === 0) {
            return;
        }

        // Hide elements that match any pattern in filterPatterns
        refLinks.forEach(link => {
            const docName = link.getAttribute("title");
            if (filterPatterns.some(pattern => pattern.test(docName))) {
                link.style.display = "none";
            } else {
                link.style.display = ""; // Reset display property if it doesn't match
            }
        });

        // Separate elements into two arrays: one for @-prefixed and one for otherItems
        const mocItems = [];
        const otherItems = [];

        refLinks.forEach(link => {
            const docName = link.getAttribute("title");
            if (docName.startsWith("@")) {
                mocItems.push(link);
            } else {
                otherItems.push(link);
            }
        });

        // Sort the 'otherItems' array based on the 'title' attribute in ascending order
        otherItems.sort((a, b) => {
            const titleA = a.getAttribute("title").toUpperCase(); // Ignore upper and lowercase
            const titleB = b.getAttribute("title").toUpperCase(); // Ignore upper and lowercase
            return titleA.localeCompare(titleB);
        });

        // Clear only the refLinks elements and append them in the desired order
        refLinks.forEach(link => link.remove());
        mocItems.concat(otherItems).forEach(link => {
            container.appendChild(link);
        });
    });
}
    // 监控dom变化
    function observeDomChange(targetNode, callback) {
        const config = { childList: true, subtree: true };
        const observer = new MutationObserver((mutationsList) => {
            for (const mutation of mutationsList) {
                if (mutation.type === 'childList') {
                    callback(mutation);
                }
            }
        });
        observer.observe(targetNode, config);
        // 返回observer,用于停止观察
        // observer.disconnect();
        return observer;
    }
// 等待元素渲染完成后执行的函数
function whenElementExist(selector) {
    return new Promise(resolve => {
        const checkForElement = () => {
            let element = null;
            if (typeof selector === 'function') {
                element = selector();
            } else {
                element = document.querySelector(selector);
            }
            if (element) {
                resolve(element);
            } else {
                // 如果元素不存在,等浏览器再次重绘,递归调用checkForElement,直到元素出现
                requestAnimationFrame(checkForElement);
            }
        };
        checkForElement();
    });
}

// 等待笔记区出现
whenElementExist(".layout__center").then((element)=>{
  
    const observer = observeDomChange(element, (mutation) => {
    // 监听弹窗代码列表
    if(mutation.target.classList.contains("protyle-top") || mutation.target.classList.contains("og-hn-heading-docs-container")) {
        setTimeout(filterAndReorderLinks, 100);
    }

});
});


})();

使用

Clip20240806194319.png

运行前Clip20240806194059.png

自定义 js 运行后Clip20240806194110.png

  • 思源笔记

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

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

    22750 引用 • 91325 回帖 • 1 关注
2 操作
Achuan-2 在 2024-08-09 17:41:49 更新了该帖
Achuan-2 在 2024-08-09 16:37:24 更新了该帖

相关帖子

欢迎来到这里!

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

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

    确实好用,在这基础上稍微修改一下自己就能用了,感谢。

    我在你这个基础上增加了隐藏链接末尾为*的文档,这样就可以手动标记来完成已经被整理过的反链的筛选,不过还是有点问题,就是这个筛选只针对于文档标题的引用,粒度有点大。

    1 回复
  • Achuan-2

    因为我还是喜欢文档来管理内容,也能更沉浸去创作。

    目前块引用也基本是文档引用,块粒度的引用对我而言,不如文档引用安全,容易失效

  • Achuan-2

    学习这篇帖子代码片段实现代码块最近使用的语言置顶 - 链滴 (ld246.com)

    放弃 setInterval 定时执行,用了 MutationObserver 来监控 DOM 变化

    
    
    (async ()=>{function filterAndReorderLinks() {
        const filterPatterns = [
            /^\d{8} \w{3}$/, // Example: 20240728 Sun
            /^\d{6}$/,
            /^\d{8} ~ \d{8}$/,
            /^\d{8} \- \d{8}$/
            // Add more patterns here if needed
        ];
    
        const containers = document.querySelectorAll("div.og-hierachy-navigate-backlink-doc-container");
        if (containers.length === 0) {
            return;
        }
    
        containers.forEach(container => {
            const refLinks = container.querySelectorAll("span.refLinks.docLinksWrapper");
            if (refLinks.length === 0) {
                return;
            }
    
            // Hide elements that match any pattern in filterPatterns
            refLinks.forEach(link => {
                const docName = link.getAttribute("title");
                if (filterPatterns.some(pattern => pattern.test(docName))) {
                    link.style.display = "none";
                } else {
                    link.style.display = ""; // Reset display property if it doesn't match
                }
            });
    
            // Separate elements into two arrays: one for @-prefixed and one for otherItems
            const mocItems = [];
            const otherItems = [];
    
            refLinks.forEach(link => {
                const docName = link.getAttribute("title");
                if (docName.startsWith("@")) {
                    mocItems.push(link);
                } else {
                    otherItems.push(link);
                }
            });
    
            // Sort the 'otherItems' array based on the 'title' attribute in ascending order
            otherItems.sort((a, b) => {
                const titleA = a.getAttribute("title").toUpperCase(); // Ignore upper and lowercase
                const titleB = b.getAttribute("title").toUpperCase(); // Ignore upper and lowercase
                return titleA.localeCompare(titleB);
            });
    
            // Clear only the refLinks elements and append them in the desired order
            refLinks.forEach(link => link.remove());
            mocItems.concat(otherItems).forEach(link => {
                container.appendChild(link);
            });
        });
    }
        // 监控dom变化
        function observeDomChange(targetNode, callback) {
            const config = { childList: true, subtree: true };
            const observer = new MutationObserver((mutationsList) => {
                for (const mutation of mutationsList) {
                    if (mutation.type === 'childList') {
                        callback(mutation);
                    }
                }
            });
            observer.observe(targetNode, config);
            // 返回observer,用于停止观察
            // observer.disconnect();
            return observer;
        }
    // 等待元素渲染完成后执行的函数
    function whenElementExist(selector) {
        return new Promise(resolve => {
            const checkForElement = () => {
                let element = null;
                if (typeof selector === 'function') {
                    element = selector();
                } else {
                    element = document.querySelector(selector);
                }
                if (element) {
                    resolve(element);
                } else {
                    // 如果元素不存在,等浏览器再次重绘,递归调用checkForElement,直到元素出现
                    requestAnimationFrame(checkForElement);
                }
            };
            checkForElement();
        });
    }
    
    // 等待笔记区出现
    whenElementExist(".layout__center").then((element)=>{
      
        const observer = observeDomChange(element, (mutation) => {
        // 监听弹窗代码列表
        if(mutation.target.classList.contains("protyle-top") || mutation.target.classList.contains("og-hn-heading-docs-container")) {
            setTimeout(filterAndReorderLinks, 100);
        }
    
    });
    });
    
    
    })();
    
    1 操作
    Achuan-2 在 2024-08-09 17:41:12 更新了该回帖
Achuan-2
给时间以生命而不是给生命以时间,如果你喜欢我的分享,欢迎给我买杯咖啡 https://www.yuque.com/achuan-2 上海

推荐标签 标签

  • FFmpeg

    FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。

    23 引用 • 32 回帖
  • WiFiDog

    WiFiDog 是一套开源的无线热点认证管理工具,主要功能包括:位置相关的内容递送;用户认证和授权;集中式网络监控。

    1 引用 • 7 回帖 • 589 关注
  • OkHttp

    OkHttp 是一款 HTTP & HTTP/2 客户端库,专为 Android 和 Java 应用打造。

    16 引用 • 6 回帖 • 77 关注
  • jQuery

    jQuery 是一套跨浏览器的 JavaScript 库,强化 HTML 与 JavaScript 之间的操作。由 John Resig 在 2006 年 1 月的 BarCamp NYC 上释出第一个版本。全球约有 28% 的网站使用 jQuery,是非常受欢迎的 JavaScript 库。

    63 引用 • 134 回帖 • 719 关注
  • 微信

    腾讯公司 2011 年 1 月 21 日推出的一款手机通讯软件。用户可以通过摇一摇、搜索号码、扫描二维码等添加好友和关注公众平台,同时可以将自己看到的精彩内容分享到微信朋友圈。

    131 引用 • 795 回帖
  • danl
    142 关注
  • MongoDB

    MongoDB(来自于英文单词“Humongous”,中文含义为“庞大”)是一个基于分布式文件存储的数据库,由 C++ 语言编写。旨在为应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似 JSON 的 BSON 格式,因此可以存储比较复杂的数据类型。

    90 引用 • 59 回帖
  • Gzip

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

    9 引用 • 12 回帖 • 137 关注
  • 导航

    各种网址链接、内容导航。

    41 引用 • 175 回帖
  • 知乎

    知乎是网络问答社区,连接各行各业的用户。用户分享着彼此的知识、经验和见解,为中文互联网源源不断地提供多种多样的信息。

    10 引用 • 66 回帖
  • JRebel

    JRebel 是一款 Java 虚拟机插件,它使得 Java 程序员能在不进行重部署的情况下,即时看到代码的改变对一个应用程序带来的影响。

    26 引用 • 78 回帖 • 672 关注
  • 小薇

    小薇是一个用 Java 写的 QQ 聊天机器人 Web 服务,可以用于社群互动。

    由于 Smart QQ 从 2019 年 1 月 1 日起停止服务,所以该项目也已经停止维护了!

    34 引用 • 467 回帖 • 745 关注
  • Shell

    Shell 脚本与 Windows/Dos 下的批处理相似,也就是用各类命令预先放入到一个文件中,方便一次性执行的一个程序文件,主要是方便管理员进行设置或者管理用的。但是它比 Windows 下的批处理更强大,比用其他编程程序编辑的程序效率更高,因为它使用了 Linux/Unix 下的命令。

    123 引用 • 74 回帖
  • Hprose

    Hprose 是一款先进的轻量级、跨语言、跨平台、无侵入式、高性能动态远程对象调用引擎库。它不仅简单易用,而且功能强大。你无需专门学习,只需看上几眼,就能用它轻松构建分布式应用系统。

    9 引用 • 17 回帖 • 613 关注
  • Latke

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

    71 引用 • 535 回帖 • 789 关注
  • 数据库

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

    343 引用 • 720 回帖
  • Ant-Design

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

    17 引用 • 23 回帖 • 4 关注
  • 架构

    我们平时所说的“架构”主要是指软件架构,这是有关软件整体结构与组件的抽象描述,用于指导软件系统各个方面的设计。另外还有“业务架构”、“网络架构”、“硬件架构”等细分领域。

    142 引用 • 442 回帖
  • JavaScript

    JavaScript 一种动态类型、弱类型、基于原型的直译式脚本语言,内置支持类型。它的解释器被称为 JavaScript 引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在 HTML 网页上使用,用来给 HTML 网页增加动态功能。

    730 引用 • 1328 回帖
  • gRpc
    11 引用 • 9 回帖 • 70 关注
  • Caddy

    Caddy 是一款默认自动启用 HTTPS 的 HTTP/2 Web 服务器。

    12 引用 • 54 回帖 • 161 关注
  • SQLite

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

    5 引用 • 7 回帖
  • 安装

    你若安好,便是晴天。

    132 引用 • 1184 回帖
  • WordPress

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

    66 引用 • 114 回帖 • 228 关注
  • 百度

    百度(Nasdaq:BIDU)是全球最大的中文搜索引擎、最大的中文网站。2000 年 1 月由李彦宏创立于北京中关村,致力于向人们提供“简单,可依赖”的信息获取方式。“百度”二字源于中国宋朝词人辛弃疾的《青玉案·元夕》词句“众里寻他千百度”,象征着百度对中文信息检索技术的执著追求。

    63 引用 • 785 回帖 • 170 关注
  • GAE

    Google App Engine(GAE)是 Google 管理的数据中心中用于 WEB 应用程序的开发和托管的平台。2008 年 4 月 发布第一个测试版本。目前支持 Python、Java 和 Go 开发部署。全球已有数十万的开发者在其上开发了众多的应用。

    14 引用 • 42 回帖 • 775 关注
  • GitBook

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

    3 引用 • 8 回帖 • 3 关注