(() => {
// 块菜单配置
const menus = [
{
name: "快速制卡",
operation: "add",
},
{
name: "取消制卡",
operation: "remove",
}
];
// 监听块右键菜单
whenElementExist('#commonMenu .b3-menu__items').then((menuItems) => {
const menusReverse = menus.reverse();
observeBlockMenu(menuItems, async (isTargetMenu) => {
if (menuItems.querySelector('.operate-my-card')) return;
const addAv = menuItems.querySelector('button[data-id="addToDatabase"]');
if (!addAv) return;
if (menus.length === 0) return;
// 生成块菜单
menusReverse.forEach((menu, index) => {
const menuText = menu.name;
const menuIcon = '#iconRiffCard';
const menuClass = `operate-my-card-${menus.operation}-${menus.length - index - 1}`;
const menuButtonHtml = `<button class="b3-menu__item ${menuClass}"><svg class="b3-menu__icon " style=""><use xlink:href="${menuIcon}"></use></svg><span class="b3-menu__label">${menuText}</span></button>`;
addAv.insertAdjacentHTML('afterend', menuButtonHtml);
const menuBtn = menuItems.querySelector('.' + menuClass);
// 块菜单点击事件
menuBtn.onclick = async () => {
window.siyuan.menus.menu.remove();
menuItemClick(menu.operation);
};
});
});
});
// 菜单点击事件
async function menuItemClick(operation) {
let blocks = [];
const selectedRows = document.querySelectorAll('.av__row.av__row--select');
// 遍历每个选中的行
selectedRows.forEach(row => {
// 查找当前行下 data-type 为 block-ref 的元素
const blockRefNodes = row.querySelectorAll('[data-type="block-ref"]');
// 遍历这些元素,提取 data-id
blockRefNodes.forEach(node => {
const dataId = node.dataset.id;
if (dataId) {
blocks.push(dataId);
}
});
});
if (operation === 'remove') {
await removeFlashcard(blocks);
}
else {
await addFlashcard(blocks);
}
}
// 快速制卡
async function addFlashcard(blockIds) {
blockIds = typeof blockIds === 'string' ? [blockIds] : blockIds;
const result = await requestApi("/api/riff/addRiffCards",
{
"blockIDs": blockIds,
"deckID": "20230218211946-2kw8jgx"
});
if (!result || result.code !== 0) console.error(result);
}
async function removeFlashcard(blockIds) {
blockIds = typeof blockIds === 'string' ? [blockIds] : blockIds;
const result = await requestApi("/api/riff/removeRiffCards",
{
"blockIDs": blockIds,
"deckID": "20230218211946-2kw8jgx"
});
if (!result || result.code !== 0) console.error(result);
}
async function requestApi(url, data, method = 'POST') {
return await (await fetch(url, { method: method, body: JSON.stringify(data || {}) })).json();
}
/**
* 监控 body 直接子元素中 #commonMenu 的添加
* @returns {MutationObserver} 返回 MutationObserver 实例,便于后续断开监听
*/
function observeBlockMenu(selector, callback) {
let isTargetMenu = false;
// 创建一个 MutationObserver 实例
const observer = new MutationObserver((mutationsList) => {
// 遍历所有变化
for (const mutation of mutationsList) {
// 检查是否有节点被添加
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
// 遍历所有添加的节点
mutation.addedNodes.forEach((node) => {
// 检查节点是否是目标菜单
if (isTargetMenu) return;
// if (menuItems.querySelector('.add-to-my-av')) return;
if (node.nodeType === 1 && node.closest('[data-id="fields"]')) {
isTargetMenu = true;
// } else if (node.nodeType === 1 && node.closest('[data-id="fields"]')) {
// isTargetMenu = true;
}
if (isTargetMenu) {
callback(isTargetMenu);
setTimeout(() => {
isTargetMenu = false;
}, 200);
}
});
}
}
});
// 开始观察 body 的直接子元素的变化
observer.observe(selector || document.body, {
childList: true, // 监听子节点的添加
subtree: false, // 仅监听直接子元素,不监听子孙元素
});
// 返回 observer 实例,便于后续断开监听
return observer;
}
// 等待元素出现
function whenElementExist(selector, node) {
return new Promise(resolve => {
const check = () => {
const el = typeof selector === 'function' ? selector() : (node || document).querySelector(selector);
if (el) resolve(el); else requestAnimationFrame(check);
};
check();
});
}
}) ();
[js] 闪卡 JS 分享(方便在数据库上制作闪卡)
-
思源笔记
26457 引用 • 110053 回帖 • 1 关注
思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。
融合块、大纲和双向链接,重构你的思维。
-
代码片段
207 引用 • 1446 回帖
代码片段分为 CSS 与 JS 两种代码,添加在 [设置 - 外观 - 代码片段] 中,这些代码会在思源笔记加载时自动执行,用于改善笔记的样式或功能。
用户在该标签下分享代码片段时需在帖子标题前添加
[css]
或[js]
用于区分代码片段类型。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于