好家伙!原来没留意——发帖还要扣分的,亏本分享
虽然对我来说,分有啥用啊~所以我更新了……
看到隔壁讨论的需求,标签搜索功能 - 链滴
本来想直接回复,字数超了
论坛有过分享的
[js] 大纲过滤器, 支持大部分面板的过滤 (大纲, 标签, 书签, 书签 +, 文件树, 反链) - 链滴
站在大佬肩膀上按个人需求完善了下,按需修改吧,我才学的 js
// add filters for all各种过滤器
// 原作者版本https://ld246.com/article/1736828257787 https://github.com/leeyaunlong/siyuan_scripts/
// chuchen接力版:增加按钮循环控制,css优化,支持拼音模糊搜索,
// 支持混合逻辑语法:'空格 '分割关键词(AND逻辑),'竖线|'分割关键词(OR逻辑),'英文感叹号!'开头的关键词(NOT逻辑),暂不支持转义
// 待完善功能,支持闪卡过滤器,支持手机版
(() => {
// 定义过滤器配置
const filterConfigs = [
{ id: 'tree_filter_container', placeholder: "文档树过滤器", selector: '.fn__flex-1.fn__flex-column.file-tree.sy__file', positionMark: 1 },
{ id: 'outline_filter_container', placeholder: "大纲过滤器", selector: '.fn__flex-1.fn__flex-column.file-tree.sy__outline', positionMark: 1 },
{ id: 'bmsp_filter_container', placeholder: "书签+过滤器", selector: '.fn__flex-1.b3-list.b3-list--background.custom-bookmark-body', positionMark: 3 },
{ id: 'tags_filter_container', placeholder: "标签过滤器", selector: '.fn__flex-1.fn__flex-column.file-tree.sy__tag', positionMark: 2 },
{ id: 'bms_filter_container', placeholder: "书签过滤器", selector: '.fn__flex-1.fn__flex-column.file-tree.sy__bookmark', positionMark: 2 },
{ id: 'backlink_filter_container', placeholder: "反链过滤器", selector: '.fn__flex-1.fn__flex-column.file-tree.sy__backlink', positionMark: 2 },
// { id: 'flashcard_filter_container', placeholder: "闪卡过滤器", selector: '[data - key= "dialog-viewcards"] .fn__flex - column', positionMark: 2 }
];
// 检查是否为手机版
function isMobile() {
return !!document.getElementById("sidebar");
}
// 等待元素出现
function whenElementExist(selector, node = document, timeout = 5000) {
return new Promise((resolve, reject) => {
const start = Date.now();
function check() {
let el;
try {
el = typeof selector === 'function'
? selector()
: node.querySelector(selector);
} catch (err) {
return reject(err);
}
if (el) {
resolve(el);
} else if (Date.now() - start >= timeout) {
reject(new Error(`Timed out after ${timeout}ms waiting for element ${selector}`));
} else {
requestAnimationFrame(check);
}
}
check();
});
}
// 支持拼音模糊过滤
const loadPinyin = new Promise((resolve) => {
// 优先检查现有库
if (window.pinyinPro) return resolve(window.pinyinPro);
// 定义多个CDN源
const sources = [
'https://cdn.bootcdn.net/ajax/libs/pinyin-pro/3.26.0/index.min.js',
'https://unpkg.com/pinyin-pro@3.18.2/dist/index.js',
'https://cdn.jsdelivr.net/npm/pinyin-pro@3.18.2/dist/index.js',
'/plugins/myFonts/pinyin-pro.min.js'
];
let retryCount = 0;
const tryNextSource = () => {
if (retryCount >= sources.length) {
console.warn('代码片段-过滤器-所有拼音源加载失败,启用纯文本过滤');
return resolve(null);
}
const script = document.createElement('script');
script.src = sources[retryCount];
script.onload = () => resolve(window.pinyinPro);
script.onerror = () => {
retryCount++;
tryNextSource();
};
document.head.appendChild(script);
};
tryNextSource();
});
// 在addFilterMo函数中修改input事件监听器:
function addFilterMo({ id, placeholder, selector, positionMark }) {
const existingInput = document.getElementById(id);
if (existingInput) existingInput.remove();
const container = document.createElement('div');
container.id = id;
container.style.display = 'flex';
container.style.alignItems = 'center';
const input = document.createElement('input');
input.id = 'outline_filter';
input.type = 'text';
input.placeholder = placeholder;
input.style.flex = '1';
input.style.minWidth = 0;
input.style.borderWidth = '1px';
input.style.borderStyle = 'dashed';
input.style.borderColor = 'var(--b3-theme-on-surface)';
input.style.backgroundColor = 'var(--b3-theme-surface)';
input.style.color = 'var(--b3-theme-on-background)';
input.className = 'b3-text-field fn__block';
const resetButton = document.createElement('button');
resetButton.textContent = '↺';
resetButton.style.color = 'var(--color-text-3)';
resetButton.style.fontWeight = "900";
resetButton.style.cursor = 'pointer';
resetButton.style.backgroundColor = 'var(--b3-theme-surface-light)';
resetButton.style.borderWidth = '1px';
resetButton.style.borderStyle = 'dotted';
resetButton.style.borderColor = 'var(--b3-theme-on-surface)';
resetButton.style.marginRight = '3px';
const closeButton = document.createElement('button');
closeButton.textContent = '⨉';
closeButton.style.color = 'var(--color-text-3)';
closeButton.style.fontWeight = "900";
closeButton.style.cursor = 'pointer';
closeButton.style.backgroundColor = 'var(--b3-theme-surface-light)';
closeButton.style.borderWidth = '1px';
closeButton.style.borderStyle = 'dotted';
closeButton.style.borderColor = 'var(--b3-theme-on-surface)';
closeButton.style.marginLeft = '3px';
container.appendChild(resetButton);
container.appendChild(input);
container.appendChild(closeButton);
const targetElement = document.querySelector(selector);
if (targetElement) {
if (positionMark === 0) {
targetElement.parentElement.insertBefore(container, targetElement);
} else if (positionMark === 1) {
targetElement.parentElement.insertAdjacentElement('beforebegin', container);
} else if (positionMark === 2) {
targetElement.appendChild(container);
} else if (positionMark === 3) {
targetElement.parentElement.insertAdjacentElement('beforeend', container);
} else if (positionMark === 4) {
targetElement.prepend(container);
} else if (positionMark === 5) {
targetElement.parentElement.insertAdjacentElement('afterebegin', container);
}
}
const targetElement1 = document.querySelector(selector + '.fn__none');
if (targetElement1) {
container.remove(); // 移除输入框容器
}
const resetDisplay = () => {
const spans = document.querySelectorAll(selector + ' li span.b3-list-item__text.ariaLabel');
spans.forEach(span => {
const listItem = span.parentElement;
listItem.style.display = ''; // 重置所有项的显示状态
});
};
// input.focus(); // 添加自动聚焦
// 修改输入事件处理中的拼音调用部分
input.addEventListener('input', async function () {
const filterText = input.value.toLowerCase();
// 分割逻辑组(OR)和条件(AND/NOT)
const orGroups = filterText.split('|').map(group =>
group.split(' ').filter(k => k.trim()).map(term => ({
value: term.replace(/^!/, ''),
isNot: term.startsWith('!')
}))
);
const spans = document.querySelectorAll(selector + ' li span.b3-list-item__text.ariaLabel');
try {
const pinyin = await loadPinyin;
if (!pinyin?.pinyin) throw new Error('代码片段-过滤器拼音库初始化失败');
spans.forEach(span => {
const listItem = span.parentElement;
const text = span.textContent;
// 生成拼音数据
const pinyinInitials = pinyin.pinyin(text, {
pattern: 'first',
type: 'array',
toneType: 'none',
multiple: true
}).join('').toLowerCase();
const pinyinFull = pinyin.pinyin(text, {
pattern: 'pinyin',
type: 'array',
toneType: 'none',
multiple: true
}).join('').toLowerCase();
// OR逻辑:任意一组满足即显示
const matchAnyGroup = orGroups.some(group => {
// AND逻辑:组内所有条件必须满足
return group.every(({ value, isNot }) => {
const hasMatch = [
text.toLowerCase().includes(value),
pinyinInitials.includes(value),
pinyinFull.includes(value)
].some(Boolean);
return isNot ? !hasMatch : hasMatch;
});
});
listItem.style.display = matchAnyGroup ? '' : 'none';
});
} catch (e) {
// 降级处理
spans.forEach(span => {
const text = span.textContent.toLowerCase();
const matchAnyGroup = orGroups.some(group =>
group.every(({ value, isNot }) => {
const hasMatch = text.includes(value);
return isNot ? !hasMatch : hasMatch;
})
);
span.parentElement.style.display = matchAnyGroup ? '' : 'none';
});
}
});
resetButton.addEventListener('click', function () {
input.value = ''; // 清空输入框
resetDisplay(); // 重置显示状态
});
closeButton.addEventListener('click', function () {
input.value = ''; // 清空输入框
resetDisplay(); // 重置显示状态
container.remove(); // 移除输入框容器
});
}
// 设置所有过滤器
function set_addFilter() {
filterConfigs.forEach(config => {
addFilterMo(config);
});
}
// 检查并移除所有过滤器
function checkFilter() {
filterConfigs.forEach(config => {
const fCs = document.getElementById(config.id);
if (fCs) {
fCs.remove();
}
});
}
// 添加按钮
function addButton(vtext, pin) {
let flag = false;
const button = document.createElement('span');
button.className = 'dock__item ariaLabel';
button.textContent = vtext;
button.setAttribute('aria-label', ' 关闭筛选');
button.onclick = (event) => {
event.preventDefault();
event.stopPropagation();
checkFilter();
if (flag) {
set_addFilter();
startTabObserver('.layout-tab-container.fn__flex-1', 'layout__tab--active', tabObservers, set_addFilter); // 启用筛选时启动监听
observer2.observe(targetBody, config2);
} else {
stopTabObserver(tabObservers); // 禁用筛选时停止监听
observer2.disconnect()
}
flag = !flag;
button.setAttribute('aria-label', flag ? ' 开启筛选' : ' 关闭筛选');
button.textContent = flag ? '🕸︎' : '🕸️';
};
pin.before(button);
}
// Tab切换监听器
let tabObservers = [];
// 启动Tab切换监听
function startTabObserver(fatherClass, childClass, obArray, callback) {
if (obArray.length > 0) return;
whenAllElementsExist(fatherClass).then((parentElements) => {
parentElements.forEach((parentElement) => {
const observer = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(node => {
if (node.classList?.contains(childClass)) {
callback();
}
});
}
if (mutation.type === 'attributes' && mutation.target.classList?.contains(childClass)) {
callback();
}
}
});
observer.observe(parentElement, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['class']
});
obArray.push(observer);
});
}).catch(() => {
// 后备方案:监听整个文档
const documentObserver = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
if (mutation.target.classList?.contains(childClass)) {
callback();
}
}
});
documentObserver.observe(document, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['class']
});
obArray.push(documentObserver);
});
};
// 停止Tab切换监听
function stopTabObserver(obArray) {
obArray.forEach(observer => observer.disconnect());
obArray.length = 0;
}
// 等待所有匹配元素出现
function whenAllElementsExist(selector) {
return new Promise(resolve => {
const check = () => {
const elements = document.querySelectorAll(selector);
if (elements.length > 0) resolve(Array.from(elements));
else requestAnimationFrame(check);
};
check();
});
}
// 手机版返回
if (isMobile()) return;
// 监听dock加载完毕
whenElementExist('#dockLeft .dock__items .dock__item--pin').then((pin) => {
let vtext = "🕸️";
addButton(vtext, pin);
set_addFilter();
startTabObserver('.layout-tab-container.fn__flex-1', 'layout__tab--active', tabObservers, set_addFilter);
});
// whenAllElementsExist('.b3-dialog--open').then(() => {
// set_addFilter();
// });
// 获取要观察的目标节点
const targetBody = document.querySelector('body');
// 配置观察选项
const config2 = { childList: true, subtree: true };
// 定义一个回调函数,当观察到DOM变化时会被调用
const callback2 = function (mutationsList, observer2) {
for (let mutation of mutationsList) {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE && node.matches('[data-key="dialog-viewcards"].b3-dialog--open')) {
// console.log('5555The specific div has been added!');
set_addFilter();
}
});
}
}
};
// 创建一个观察器实例并传入回调函数
const observer2 = new MutationObserver(callback2);
})();
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于