[js] 第二弹,openAny 教程之全局搜索仅搜文档 / 快速灵感输入 / 快速显示隐藏侧边栏等

注意,以下所以功能必须先安装 [js] 连续点击 openAny,小代码,大作用,让一切触手可达 这个代码片段才行。

ctrl+shif+p 全局搜索仅搜文档(不影响原有搜索状态)

功能简介:

ctrl+shif+p 打开全局搜索对话框,然后自动临时设置搜索参数为仅搜索文档,当关闭搜索窗口后,一切复原,不影响原本的搜索设置。

代码:

// ctrl+shif+p 全局搜索仅搜文档(不影响原有搜索状态)
(async ()=>{
    // 等待openAny加载完毕  
    await waitFor(() => typeof openAny !== 'undefined');
    // 注册快捷键
    const ctrl = navigator.platform.indexOf("Mac") > -1 ? 'meta' : 'ctrl';
    openAny.setKeymap(`shift+${ctrl}+p`, async (event, {getSelectedText}) => {
      openAny
        .press(`${ctrl}+p`) // 打开搜索框
        .click("#searchFilter") // 点击类型过滤按钮
        .input(getSelectedText(), "#searchInput") // 搜索框置空
        .invoke(async ({sleep,whenElementRemoved}) => {
          // 【注意】invoke内部建议用新的OpenAny对象,防止用await时与上层链相互等待造成死锁
          const openAny = new OpenAny();
          // 获取当前的文档类型
          const oldTypes = siyuan?.storage['local-searchdata']?.types;
          // 查询所有文档类型,仅保留文档类型打开,其他全关闭
          openAny
            .queryElAll('[data-key="dialog-searchtype"] [type="checkbox"]')
            .forEach(async (checkbox) =>
              checkbox.matches('[data-type="document"]')
                ? !checkbox.checked && checkbox.click()
                : checkbox.checked && checkbox.click()
            );
          // 点击确定按钮
          openAny.click('[data-key="dialog-searchtype"] .b3-dialog__action .b3-button--text')
          await sleep(100); // 等待100ms
          openAny.focus("#searchInput"); // 聚焦搜索框
          // placehoder
          openAny.queryEl('#searchInput').placeholder = '请输入文档标题';
          // 等待搜索对话框被关闭
          whenElementRemoved('[data-key="dialog-globalsearch"]', ()=>{
            // 恢复原本的文档类型
            if(oldTypes) siyuan.storage['local-searchdata'].types = oldTypes;
          });
        });
    });
    function waitFor(conditionFn, timeoutMs=5000) {
      return new Promise((resolve, reject) => {
        const start = Date.now();
        const check = () => {
          if(typeof conditionFn === 'string') 
              conditionFn = () => document.querySelector(conditionFn);
          const result = conditionFn();
          if (result) resolve(result);
          else if (Date.now() - start > timeoutMs) reject();
          else requestAnimationFrame(check); // 利用浏览器刷新周期
        };
        check();
      });
    }
})();

代码放到思源 js 代码片段中即可。

快速输入,灵感输入

功能简介:

当你在思源中阅读或写文章时,突然有灵感迸发,如果你找到录入灵感的文档再录入,可能由于思维改变或者如果有人突然打扰,你的灵感有可能消失,即使后来再想起来也得花费些功夫。

这个代码可以让你按快捷键 alt+i 快速录入你的灵感,回车后自动保存到你指定的文档,方便日后查看。

代码:

// 快速输入,灵感记录等
(async ()=>{
    // 请填写灵感即将保存的文档ID
    const captureDocId = '20250307013535-lreu6jb';

    // 是否按回车键提交
    // 当为 true 时,回车键提交,shift+回车 换行
    // 当为 false 时,回车换行,ctrl+回车 提交
    const enterSubmit = true;

    // 输入框显示行数,默认3行,当行数是1时,无法换行,同时始终回车提交
    const inputLines = 3;

    // 等待openAny加载完毕  
    await waitFor(() => typeof openAny !== 'undefined');
    // 注册快捷键
    openAny.setKeymap("alt+i", async (event, {fetchSyncPost, showInputBox}) => {
        const input = await showInputBox("", "", "", inputLines, enterSubmit);
        if(!input) return;
        const result = await fetchSyncPost('/api/block/insertBlock', {
            "dataType": "markdown",
            "data": getFormattedDateTime() + "\n{: style=\"color:#989898;\"}\n" + input + "\n---",
            "nextID": "",
            "previousID": "",
            "parentID": captureDocId
        });
        console.log(result);
    });

    function getFormattedDateTime() {
        const now = new Date();
        // 获取年、月、日、时、分、秒
        const year = now.getFullYear(); // 年
        const month = String(now.getMonth() + 1).padStart(2, '0'); // 月(注意月份从 0 开始,需要加 1)
        const day = String(now.getDate()).padStart(2, '0'); // 日
        const hours = String(now.getHours()).padStart(2, '0'); // 时
        const minutes = String(now.getMinutes()).padStart(2, '0'); // 分
        const seconds = String(now.getSeconds()).padStart(2, '0'); // 秒
        // 拼接成字符串
        return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
    }
    function waitFor(conditionFn, timeoutMs=5000) {
      return new Promise((resolve, reject) => {
        const start = Date.now();
        const check = () => {
          if(typeof conditionFn === 'string') 
              conditionFn = () => document.querySelector(conditionFn);
          const result = conditionFn();
          if (result) resolve(result);
          else if (Date.now() - start > timeoutMs) reject();
          else requestAnimationFrame(check); // 利用浏览器刷新周期
        };
        check();
      });
    }
})();

代码放到思源 js 代码片段中即可。

快速隐藏/显示上次打开的侧边栏

功能简介:

如图所示,在面包屑右边增加一个按钮,用于快速隐藏当前展开的侧栏/重新打开上次隐藏的侧栏(或者按 Alt+Z 快捷键)

image.png

这个功能已经内置在 QYL 主题,也欢迎大家使用 @queguaiya 大佬的这个主题。

代码:

请前往帖子 [js] 快速隐藏 / 呼出侧栏代码片段分享 查看

感谢 @queguaiya 大佬分享的代码!

快速查询不重复列表

功能简介:

通过关键词查询有序、无序列表及任务列表,然后打开全局搜索框并显示查询结果,在查询结果中不会显示重复的列表(注意仅定位到最外层的列表,不会直接定位到子级)

搜索关键词,空格表示并且,OR 表示或

image.png

代码:

// // 快速查询不重复列表(自动生成SQL并打开全局搜索对话框)
{
    let results = await openAny.fn.showInputBox('', '', '请输入要查询的关键词,空格代表并且,OR代表或');
    if (results) {
        // 检查是否包含 OR 逻辑
        if (results.includes(' OR ')) {
            // 按 OR 分割,并去重、过滤空字符串
            const orKeywords = [...new Set(results.split(' OR '))]
                .filter(keyword => keyword.trim())
                .map(keyword => `b.markdown LIKE '%${keyword}%'`)
                .join(' OR ');
            results = `AND (${orKeywords})`;
        } else {
            // 如果没有 OR,则按空格分割,并去重、过滤空字符串
            results = [...new Set(results.split(' '))]
                .filter(keyword => keyword.trim())
                .map(keyword => `AND b.markdown LIKE '%${keyword}%'`)
                .join(' ');
        }
        // 构造最终 SQL 查询
        const sql = `select * from (SELECT b.* FROM blocks b LEFT JOIN blocks p ON b.parent_id = p.id WHERE b.type = 'l' ${results} AND (b.parent_id = b.root_id OR (p.type IS NULL OR p.type NOT IN ('l', 'i')))) as blocks`;
        openAny.press((navigator.platform.indexOf("Mac") > -1) ? 'meta+p' : 'ctrl+p')
            .clicks('#searchSyntaxCheck', '[data-name="searchMethod"] .b3-menu__item:nth-child(3)')
            .input(sql, '#searchInput');
    }
}

关联帖子:

思源怎么实现 Obsidian 这样的搜索效果?困扰了好久,用 SQL 能实现吗? - wilsons 的回帖

快速查询制卡数据

功能简介:

通过关键词查询制卡数据,然后打开全局搜索框并显示查询结果。

搜索关键词,空格表示并且,OR 表示或

image.png

代码:

// 快速查询制卡数据(自动生成SQL并打开全局搜索对话框)
setTimeout(() => {
    // 这里设置快捷键即可👇
    openAny.addKeymap('alt+z', async (event) => {
        event.preventDefault();
        let sql = `select * from blocks where 1 {{query_keywords}} and ial like '%custom-riff-decks=%' order by updated desc`;
        let results = await openAny.fn.showInputBox('', '', '请输入要查询的关键词,空格代表并且,OR代表或');
        if (results) {
            // 检查是否包含 OR 逻辑
            if (results.includes(' OR ')) {
                // 按 OR 分割,并去重、过滤空字符串
                const orKeywords = [...new Set(results.split(' OR '))]
                    .filter(keyword => keyword.trim())
                    .map(keyword => `markdown LIKE '%${keyword}%'`)
                    .join(' OR ');
                results = `AND (${orKeywords})`;
            } else {
                // 如果没有 OR,则按空格分割,并去重、过滤空字符串
                results = [...new Set(results.split(' '))]
                    .filter(keyword => keyword.trim())
                    .map(keyword => `AND markdown LIKE '%${keyword}%'`)
                    .join(' ');
            }
            // 构造最终 SQL 查询
            sql = sql.replace(/\{\{query_keywords\}\}/ig, results);
            openAny.press((navigator.platform.indexOf("Mac") > -1) ? 'meta+p' : 'ctrl+p')
                .clicks('#searchSyntaxCheck', '[data-name="searchMethod"] .b3-menu__item:nth-child(3)')
                .input(sql, '#searchInput');
        }
    });
}, 1500);

关联帖子:

闪卡有查找的功能吗?

点击块引用后自动聚焦块

功能简介:

点击引用自动聚焦,以排除其他块内容的影响,当内容非常多且相似时,这个很有用。

代码:

setTimeout(()=>{ // 兼容超级和普通块
   openAny.setKeymap('mouseleft', async (event, {sleep}) => {
        if(!event.target.closest('[data-type~="block-ref"]')) return;
        let el; const start = Date.now();
        while(!el){
            if (Date.now() - start > 5000) {console.warn('获取聚焦块元素失败');break;}
            el = document.querySelector('[data-node-id].protyle-wysiwyg--hl')
            await sleep(40);
        }
        if(el.closest('.sb')){ // 超级块
            openAny.press('mouseover', el.firstElementChild.querySelector('[contenteditable="true"]'));
            const superBtn = await whenElementExist(()=>document.querySelector('use[*|href="#iconSuper"]')?.closest('button'));
            openAny.click(superBtn).click('#commonMenu [data-id="enter"]');
        } else { // 普通块
            openAny.press('alt+arrowright', el);
        }
    }); 
}, 2000);

关联帖子:

希望可以点击块引自动聚焦

其他

ctrl+alt+x 只显示文字外观窗口一部分

之前一个同学提的这个需求,虽然 css 可以实现,我认为 js 实现是最完美的,因为按快捷键后临时修改,关闭窗口后恢复原状,不具有侵入性。

image.png

openAny.setKeymap('ctrl+alt+x', async (event, {newSetStyle})=>{
    const setStyle = newSetStyle();
    // 设置样式  
    setStyle(`.protyle-font > *:not(:nth-child(7),:nth-child(8)):not(:last-child) {
       display:none;
    }`);
    // 等待外观窗口出现
    await openAny.getEl('.protyle-util:not(.fn__none)');
    // 等待外观窗口关闭
    await openAny.getEl('.protyle-util.fn__none', null, -1);
    // 删除样式,不影响后续操作
    setStyle('');
});

alt+z 给文字添加指定颜色和背景色

openAny.setKeymap('alt+z', (event)=>{event.preventDefault();openAny.press('ctrl+alt+x', document.activeElement).clicks('.protyle-util [style="color:var(--b3-font-color9)"]', '.protyle-util [style="background-color:var(--b3-font-background6)"]').invoke(()=>openAny.queryEl('.protyle-util:not(.fn__none)')?.classList?.add('fn__none'))});

打开指定笔记的今日日记

// 在这里输入你想在哪个笔记本中打开今日日记
const noteBookName = '我的笔记';
// 这里用wwhenExist先等待指定元素出现,否则需要在do内调用 await new OpenAny().whenExist()等待目标出现
openAny.click('#barWorkspace').whenExist('[data-name="barWorkspace"]').do(()=>{
    const subMenuItems = [...openAny.queryElAll('[data-id="dailyNote"] .b3-menu__label')];
    const notebutton = subMenuItems.find(item => item.textContent === noteBookName)?.closest('button.b3-menu__item');
    // 返回链元素,供下一个链click调用,也可以直接在这里click,不用再次调用下一个链click
    return notebutton;
}).click();

模式切换(预览和所见即所得切换)

按 ctrl+alt+7 即可

setTimeout(()=>{
    openAny.addKeymap('alt+meta+7', ()=>{
        const isPreview = document.querySelector('.protyle-preview:not(.fn__none) .protyle-preview__action');
        setTimeout(()=>{if(!isPreview) openAny.press('alt+meta+9');}, 50);
    });
}, 1500);

感谢作者

  • 思源笔记

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

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

    25645 引用 • 106063 回帖
  • 代码片段

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

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

    173 引用 • 1183 回帖
4 操作
wilsons 在 2025-05-07 00:45:06 更新了该帖
wilsons 在 2025-05-01 21:52:12 更新了该帖
wilsons 在 2025-04-27 10:06:29 更新了该帖
wilsons 在 2025-04-25 19:14:01 更新了该帖

相关帖子

欢迎来到这里!

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

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