EmberSky
关注
124636 号成员,2024-01-05 18:44:41 加入
579
个人主页 浏览
495
帖子 + 回帖 + 评论
58h18m
在线时长
如果感觉我的回答对你有帮助, 请点击 感谢 支持一下, 谢谢!
  • v3.1.25 版似乎快捷键设置这块坏了

    2025-03-21 17:38

    js 和插件都挨个看一下

    js 一般都是直接监听, 不会正常注册快捷键

    插件的话, 应该是看个人心情

  • 使用 sql 搜索时怎么过滤指定路径?

    2025-03-21 15:14

    我是直接在控制台上找的代码, 过程好死亡

    备注: blur 的时候, local-searchdata 存的是 k, 不是 idPath, idPath 应该在其他地方存的, 懒得找了

    我还发现, 从搜索框失去焦点的时候, 会保存 local-searchkeys, 也就是历史记录

    image.png

  • 使用 sql 搜索时怎么过滤指定路径?

    2025-03-20 12:24

    已解决

    1. 全局搜索, 默认搜索路径可以通过这个获取: window.siyuan.storage['local-searchdata'].idPath

    2. 搜索过程中, 修改了指定路径, 会触发思源的 input-search 事件

      事件回调参数(cfg)里面有路径: cfg.detail.config.idPath

      image.png

  • 使用 sql 搜索时怎么过滤指定路径?

    2025-03-19 15:29

    补充说明一下我为什么需要这个效果

    我安装了 "简易搜索" 这个插件, 这个插件可以 通过输入特殊字符的方式, 达到过滤的效果

    比如我想搜 名字包含 "12" 的文档

    只需要输入 -d 12 就行, 不需要去选择过滤的块

    像这样

    image.png

    这个插件的原理就是, 先将输入的内容转成 sql 语句, 再使用原有的搜索

    现在, 我有个体验不太好: 如果 搜出来的文档名有很多, 就会对我造成困扰, 所以需要用到 指定路径 这个功能

    但是 指定路径 对于 sql 语句 是不生效的

    所以我想通过修改插件的代码, 将 指定的路径 拼接到 插件转换后的 sql 语句里面

    以此达到 输入 -d 12, 指定了笔记 1 之后, 只保留笔记 1 的搜索结果

    且 支持 指定路径 动态变化的场景

    image.png

  • 使用 sql 搜索时怎么过滤指定路径?

    2025-03-19 14:39

    我怀疑他吧这些数据存到哪里了, 因为我退出重进都是有这些路径的

    image.png

  • 好抽象的模式

    2025-03-19 08:30

    这贪吃蛇太快了,刚开始就跟飞一样

  • 如何批量导入 html 文件啊?

    2025-03-17 16:49

    楼主找到解决办法了不, wkmc 的办法, 导入之后, 图片没了, 暂时还不知道怎么解决

  • 如何便捷从使用多年的 Mybase 迁移笔记到思源笔记

    2025-03-17 16:44

    你好, 我用你的这个方法, 图片没了, 咋办, 哈哈

    你遇到这个问题了么

  • 最近好像都是细节优化,啥时候来点大的

    2025-03-17 16:22

    支持细节优化, 把地基打好

  • 希望能将“布局”中的功能拆分,建立“工作区”功能,谢谢

    2025-03-17 14:40

    因为我用的 chrome, 没有这个功能, 然后我在插件市场找到了一个类似的插件, 看起来功能和楼主是一样的

    image.png

    image.png

  • 思源笔记如何关闭插件更新弹窗

    2025-03-17 11:27

    小声: 这个插件看起来好流氓

  • 希望能将“布局”中的功能拆分,建立“工作区”功能,谢谢

    2025-03-17 11:26

    这个组合功能看起来很好用哎, 坐蹲那个大佬搞一个 js

    不过话说楼主 edg 的组合功能真的是 edg 自带的么, 看着更像是某个插件的功能, 我本地的 edg 没有这个功能(可能版本比较低)

  • 请问反链面板中怎么能自动展开上下文

    2025-03-14 10:14

    在窗口上面增加两个按钮, 全部折叠和全部展开

    PixPin20250314101340.gif

    // [js] 折叠/展开所有反链结果 (() => { // 定义目标元素和要插入的 HTML 内容 const targetId = "searchPath"; const insertHTML = ` <span id="foldAllAntiChainRes" class="block__icon block__icon--show b3-tooltips b3-tooltips__sw" aria-label="折叠全部"><svg><use xlink:href="#iconContract"></use></svg></span> <span id="expandAllAntiChainRes" class="block__icon block__icon--show b3-tooltips b3-tooltips__sw" aria-label="展开全部"><svg><use xlink:href="#iconExpand"></use></svg></span> `; // 创建函数来检查元素并添加内容和事件监听 function checkAndAddElements() { document.querySelectorAll('.block__popover--open [data-type="pin"]').forEach((pin_ele) => { // 确保只执行一次 if (pin_ele.parentElement.querySelector("#foldAllAntiChainRes")) return; // 在 pin_ele 前插入内容 pin_ele.previousElementSibling.insertAdjacentHTML('beforebegin', insertHTML); // 添加点击事件监听 pin_ele.parentElement.querySelector("#foldAllAntiChainRes").addEventListener("click", () => { console.log("折叠全部反链"); // 在这里实现折叠功能 pin_ele.parentElement.parentElement.querySelectorAll('[data-type="context"]:not(.fn__none).block__icon--active').forEach(arr => { arr.click() }) }); pin_ele.parentElement.querySelector("#expandAllAntiChainRes").addEventListener("click", () => { console.log("展开全部反链"); // 在这里实现展开功能 pin_ele.parentElement.parentElement.querySelectorAll('[data-type="context"]:not(.fn__none, .block__icon--active)').forEach(arr => { arr.click() }) }); }) } // 使用 MutationObserver 监测 DOM 变化 const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.type === 'childList') { checkAndAddElements(); // 每次子节点变化时检查 } }); }); // 配置观察选项 const config = { childList: true, subtree: true }; // 开始观察 body 节点 observer.observe(document.body, config); // 初始检查 checkAndAddElements(); })()
  • 看见大家的回复

    2025-03-14 09:34

    吃瓜前线

  • 行内代码能不能直接复制,不带 markdown 格式啊

    2025-03-13 17:42
    1. 左键点击行级代码, 右键 复制纯文本

      PixPin20250313173022.gif

    2. 选中, 右键 复制纯文本

      PixPin20250313173123.gif

    3. 添加 js 片段, 点击行级代码, 使用 ctrl+c 复制, 复制的就是纯文本

      (()=>{ function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // 判断是否选取了文本 function hasSelectedText() { const selection = window.getSelection(); return selection && selection.toString().length > 0; } // 获取光标所在的元素 function getElementAtCursor() { const selection = window.getSelection(); if (selection.rangeCount > 0) { const range = selection.getRangeAt(0); const startContainer = range.startContainer; // 如果是文本节点,获取其父元素 const element = startContainer.nodeType === 3 ? startContainer.parentNode : startContainer; return element; } return null; // 如果没有选中内容或光标位置无效 } // 当前块是否被选中 function isSelectedBlock(element) { return element?.closest(".protyle-wysiwyg--select") } // 处理复制行级代码 async function handle_cp_line_code(element) { if (!element) { return; } if (element.getAttribute('data-type') === 'code' && !hasSelectedText() && !isSelectedBlock(element)) { // 是行级代码 && 没有选中内容 && 没有选中块 // 则复制行级代码内容 console.log("[行级代码] 复制行级代码, 功能生效") // 获取行级代码内容 let content = element.textContent; if (content.startsWith('\u200B')) { content = content.slice(1); // 移除前面的零宽空格 } // 复制到剪切板 await navigator.clipboard.writeText(content); await sleep(20) } } // 事件监听 document.addEventListener('keydown', async (event) => { let element = getElementAtCursor(); // event.preventDefault(); // 防止快捷键默认行为 // event.stopPropagation(); // 停止事件传播 if (event.ctrlKey && !event.shiftKey && !event.altKey && event.key.toLowerCase() === 'c') { // 如果光标在行级代码里面, 就复制行级代码纯文本, 而不是复制整个块 handle_cp_line_code(element); } }); })()
  • 求助 SQL 使用两个 LEFT JOIN 时报错

    2025-03-12 17:45

    把给表命名的 as 删掉试试

    SELECT Block1.content AS content1, Block2.content AS content2, Block3.content AS content3 FROM ( SELECT memo, content FROM blocks WHERE id = '20250312162657-u184k20' ) Block1 LEFT JOIN ( SELECT id, content, memo FROM blocks ) Block2 ON Block2.id = Block1.memo LEFT JOIN ( SELECT id, content FROM blocks ) Block3 ON Block3.id = Block2.memo;

    或者试下 ai 改后的

    SELECT Block1.content AS content1, Block2.content AS content2, Block3.content AS content3 FROM ( SELECT memo, content FROM blocks WHERE id = '20250312162657-u184k20' ) AS Block1 LEFT JOIN ( SELECT id AS Block2_id, content AS Block2_content, memo AS Block2_memo FROM blocks ) AS Block2 ON Block1.memo = Block2.Block2_id LEFT JOIN ( SELECT id AS Block3_id, content AS Block3_content FROM blocks ) AS Block3 ON Block2.Block2_memo = Block3.Block3_id;
  • [js] 搜索时自动填充选取内容

    2025-03-11 09:15

    你竟然发现了这个

  • 请问有没有什么方式快速加空行?

    2025-03-10 11:40

    这里的大纲么, 不会

    image.png

  • 请问有没有什么方式快速加空行?

    2025-03-10 09:44

    不用插一行, 可以调整块的前后间隔

    原有效果

    image.png

    第一种: 最外层的块增加间距

    .protyle-wysiwyg>[data-node-id] { margin-top: 20px ; margin-bottom: 20px ; }

    image.png

    第二种, 所有块增加间距

    .protyle-wysiwyg [data-node-id] { margin-top: 20px ; margin-bottom: 20px ; }

    image.png

  • 求页签高度调整 css

    2025-03-10 09:35

    30px 自己调

    .layout__center [data-type="wnd"]>.fn__flex { height: 30px; & .item { min-height: 30px; } }
  • [js] 折叠 / 展开所有搜索结果

    2025-03-06 11:35

    忽然发现, 这里本来就有折叠和展开, 尴尬

    image.png

  • v3.1.23 使用快捷键复制文档块引用粘贴异常

    2025-03-05 10:00

    那我知道了

    因为焦点移动到文档里面了, 所以没复制上文档的 id

    复制的是块 id

    感谢

  • 去掉搜索框顶栏的“保存查询条件”“清空查询条件”

    2025-03-05 09:22

    楼主想要的应该是去掉 按钮所在的那一行, 但是实际上是不太好去掉的, 因为这一行要保留 查询条件, 有的人查询条件很多, 不新起一行就没地方放

    image.png

  • v3.1.23 使用快捷键复制文档块引用粘贴异常

    2025-03-05 09:15

    就是

    1. 点击文档树中 的文档
    2. 按下 复制块引用的快捷键, 我的是 alt+c
    3. 然后在某个文档里面粘贴

    3.1.24 也有问题

  • [css] 优化代码块顶栏按钮样式

    2025-03-04 16:56

    还有一种缩进去的效果, 不过如果第一行太长就会被盖住

    image.png

    /* 代码块 */ .protyle-wysiwyg[contenteditable] .code-block { margin: 2px 0px; /* 1px宽度,实线,黑色 */ border: 1px solid rgba(0, 0, 0, 0.5); /* 顶栏 */ .protyle-action { background-color: var(--b3-theme-surface); position: sticky; margin-left: auto; padding: 2px; width: fit-content; border-radius: 5px; /* 语言选择按钮 */ .protyle-action__language { color: var(--b3-font-color6); opacity: 1; /*常显示*/ padding: 0px 20px; border-radius: 3px; background-color: rgba(0, 0, 0, 0.15); margin-top: 0px; height: 24px; } .protyle-action__language:hover { background-color: rgba(0, 0, 0, 0.3); } /* 间隔 */ span.fn__flex-1 { flex: none; width: 10px; } /* 复制/设置按钮*/ .protyle-icon { opacity: 0.8 !important; margin-top: 0px !important; /* 不透明度设置为不透明 */ } } /* 代码块 代码部分 */ div.hljs { padding: 2px 6px; margin-top: -30px; } } /*调整代码块折叠最大高度 .protyle-wysiwyg [data-node-id][fold="1"]:not(.li):not([data-type=NodeHeading]).code-block { height: 200px; overflow: auto!important; opacity: 1; } */
  • 文档树能否加个配置项,点击文档同时打开下一级,每次都需要点左边的小按钮很麻烦

    2025-03-04 15:50

    单击就展开的体验极其不好, 你可能想要的是双击展开

    // ### [js片段] 双击节点展开/折叠 (DOUBLE_SWITCH 控制) (() => { /***************************自主配置begin**************************************/ // 修改配置后, 需要刷新页面(设置->快捷键->刷新), 否则会有问题 const CONFIG = { DOUBLE_SWITCH : true, // 是否启用双击展开/折叠 DOUBLE_INTERVAL: 300, // 双击最大间隔时间 毫秒 }; /***************************自主配置end****************************************/ // 生成唯一ID用于日志标识 const SESSION_ID = Date.now(); // 点击类型枚举 const CLICK_TYPE = { INVALID: 0, // 无效的点击 NODE : 1, // 点击节点 ARROW : 2, // 点击折叠按钮 BOOK : 3, // 点击笔记本 }; // 工具函数 const utils = { log(...args) { const now = new Date(); const hours = String(now.getHours()).padStart(2, '0'); // 获取小时并补零 const minutes = String(now.getMinutes()).padStart(2, '0'); // 获取分钟并补零 const seconds = String(now.getSeconds()).padStart(2, '0'); // 获取秒数并补零 const milliseconds = String(now.getMilliseconds()).padStart(3, '0'); // 获取毫秒并补零 const timeString = `${hours}:${minutes}:${seconds}.${milliseconds}`; // 形成 hh:mm:ss.SSS 格式 console.log(`[${SESSION_ID}] [${timeString}]:`, ...args); }, getTagName(element) { return element?.tagName?.toLowerCase() || ''; } }; // 树节点处理类 class TreeHandler { constructor() { this.lastClickTime = 0; // 上次点击时间 } // 获取当前元素对应的种类 getClickType(element) { if (!element) return CLICK_TYPE.INVALID; let target = element; let tagName = utils.getTagName(target); // 处理SVG元素 if (tagName === 'use') { target = element.parentElement.parentElement; } else if (tagName === 'svg') { target = element.parentElement; } tagName = utils.getTagName(target); if (tagName === 'ul') { return CLICK_TYPE.INVALID; } else if (tagName === 'li' && target.getAttribute('data-path') === '/') { return CLICK_TYPE.BOOK; } else if (tagName === 'li') { return CLICK_TYPE.NODE; } else if (tagName === 'span') { if (target.classList.contains('b3-list-item__toggle')) { return CLICK_TYPE.ARROW; } else if (target.classList.contains('b3-list-item__text') && target.parentElement.getAttribute('data-path') === '/') { return CLICK_TYPE.BOOK; } else if (target.classList.contains('b3-list-item__text')) { return CLICK_TYPE.NODE; } } return CLICK_TYPE.INVALID; } // 点击节点对应的折叠按钮, 前提: element必须是点击的节点 clickArrowButton(element) { const li = utils.getTagName(element) === 'span' ? element.parentElement : element; if (utils.getTagName(li) !== 'li') return; li.querySelector('span.b3-list-item__toggle:not(.fn__hidden)')?.click(); } // 处理鼠标点击事件 handleClickEvent(event) { const element = event.target; const clickType = this.getClickType(element); // 处理双击, 系统自带的双击监测事件, 有点问题, 所以自己实现一个 const currentTime = Date.now(); utils.log("点击了", (currentTime-this.lastClickTime), clickType, element); if (CONFIG.DOUBLE_SWITCH && currentTime - this.lastClickTime < CONFIG.DOUBLE_INTERVAL && clickType === CLICK_TYPE.NODE) { utils.log("双击展开/折叠触发"); this.clickArrowButton(element); } this.lastClickTime = currentTime; } } // 初始化并监听点击事件 let initInterval = setInterval(() => { const treeContainer = document.querySelector('.sy__file>.fn__flex-1'); if (treeContainer) { clearInterval(initInterval); const handler = new TreeHandler(); treeContainer.addEventListener('click', e => handler.handleClickEvent(e), true); } }, 200); })();
  • 如何在笔记页面双击鼠标左键,就进入编辑状态

    2025-03-01 12:03
    (() => { // 生成唯一ID用于日志标识 const SESSION_ID = 'js_双击解锁' + Date.now(); function mlog(...args) { const now = new Date(); const hours = String(now.getHours()).padStart(2, '0'); // 获取小时并补零 const minutes = String(now.getMinutes()).padStart(2, '0'); // 获取分钟并补零 const seconds = String(now.getSeconds()).padStart(2, '0'); // 获取秒数并补零 const milliseconds = String(now.getMilliseconds()).padStart(3, '0'); // 获取毫秒并补零 const timeString = `${hours}:${minutes}:${seconds}.${milliseconds}`; // 形成 hh:mm:ss.SSS 格式 console.log(`[${SESSION_ID}] [${timeString}]:`, ...args); } // 功能: 监听直到元素存在 // 找到 selector 时,执行 func_cb,监听超时时间默认为 4s // selector: string | #id | function function whenExist(selector, func_cb, time_out = 4000) { console.log("whenExist begin", selector); return new Promise((resolve) => { const startTime = Date.now(); // 记录开始时间 const checkForElement = () => { let element = null; // 根据selector类型进行查找 if (typeof selector === 'string') { if (selector.startsWith('#')) { element = document.getElementById(selector.slice(1)); } else { element = document.querySelector(selector); } } else if (typeof selector === 'function') { element = selector(); } else { // 若 selector 不合法,直接退出 console.error("Invalid selector type"); resolve(false); return; } if (element) { // 元素存在时,执行回调并解析Promise if (func_cb) func_cb(element); resolve(true); } else if (Date.now() - startTime >= time_out) { // 超时处理 console.log(selector, "whenExist timeout"); resolve(false); } else { // 元素不存在且未超时,继续检查 requestAnimationFrame(checkForElement); } }; // 开始检查元素是否存在 checkForElement(); }); } function is_edit_area(elem) { if (!elem) return false; return elem.classList.contains('protyle-content') } function find_parent_while(ele, func) { while (1) { if (!ele) return null; const ret = func(ele); if (ret) return ret; ele = ele.parentElement; } } whenExist('.layout__center', page_parent => { if (!page_parent) return page_parent.addEventListener('dblclick', async (event) => { const click_ele = event.target // mlog(click_ele) const edit_area = find_parent_while(click_ele, (elem) => { // mlog(elem) // mlog(elem.classList) // 找到了根节点, 说明没找到编辑区 if (elem.classList.contains('layout__center')) return elem; // 找到了编辑区 if (is_edit_area(elem)) return elem; return null; }) mlog(edit_area) // 没找到 或 不是编辑区 直接退出 if (!is_edit_area(edit_area)) return; mlog('处理双击事件') const is_lock = edit_area.parentElement.querySelector('.protyle-breadcrumb>button[data-type="readonly"]>svg>use')?.getAttribute('xlink:href') === '#iconLock'; if (!is_lock) return; mlog('点击解锁按钮') edit_area.parentElement.querySelector('.protyle-breadcrumb>button[data-type="readonly"]')?.click() }); }); })()
  • 每次更新的内容窗口关闭后就找不到了

    2025-02-25 20:54

    我觉得, 思源内嵌所有版本的更新日志, 或者跳转到更新日志的网页(https://ld246.com/member/siyuan), 会比较友好

    image.png

    image.png

  • 关于如何去掉排版中自动生成的竖线

    2025-02-20 09:54

    image.png

    image.png

    点击 确定