比如有如下结构
[!faq] 测试
- 任务1
- 任务2
我想通过dataview(js) 的方式去定向查询在faq
的callout 块下的任务,如何去写呢;范围是整个库
比如有如下结构
[!faq] 测试
- 任务1
- 任务2
我想通过dataview(js) 的方式去定向查询在faq
的callout 块下的任务,如何去写呢;范围是整个库
发现比想象的复杂, 我遇到的难题是, 元数据似乎没有标记 callout 块的类型 (note, faq, tip …)
最后只能老实读笔记原文去提取 callout 首行
基本思路参照 DataviewJS 的提取与汇总 - 经验分享
```dataviewjs
const asyncFilter = async (arr, predicate) => {
const results = await Promise.all(arr.map(predicate));
return arr.filter((_v, index) => results[index]);
}
// 获取所有文件中的任务
const allTasks = dv.pages('"仓库里的/指定的/子目录"').file.tasks.values;
// 过滤出在指定 callout 块中的任务
const faqTasks = await asyncFilter(allTasks, (async task => {
// 检查任务的父级是否是 callout 块
// task column start = 0 的 一定不在 callout 块里
if (task.position.start.col === 0) {
return false;
}
const path = app.vault.getAbstractFileByPath(task.path);
const callouts = app.metadataCache.getFileCache(path).sections.filter(p=> p.type == 'callout');
// 笔记里没 callout 的, 一定不是目标 task
if (callouts.length === 0) {
return false;
}
const rawlines = (await dv.io.load(task.path)).split('\n');
// 检查 callout类型 检查任务的行号是否在 callout 块里
let taskInFaq = false;
callouts.forEach(callout => {
const calloutHeader = rawlines[callout.position.start.line];
if (calloutHeader.includes("!faq") &&
(task.line >= callout.position.start.line) &&
(task.line <= callout.position.end.line)) {
task.visual = task.text + ` (in ${calloutHeader.slice(2,)})`;
taskInFaq = true;
}
});
return taskInFaq;
}));
// 输出任务 console.log('faqTasks', faqTasks); dv.list(faqTasks.map(t => t.visual));
dv.taskList(faqTasks);
dv.span('done, 可能逻辑细节有问题需核查')
```
另一个坑点是我刚知道 array.filter(elem => ...)
里没法用异步函数…
测试任务类似下面这样 (未考虑 callout 嵌套等复杂情况):
> [!note] 不该命中测试
>
> - [ ] 不该命中任务1 inside callout
> - [x] 不该命中任务2 完成 inside callout
- [ ] 不该命中任务5 普通 outside callout
> [!faq] 测试
>
> - [x] 目标任务1 inside callout
> - [ ] 目标任务2 完成 inside callout
- [ ] 不该命中任务3 普通 outside callout
最后效果大致如下:
感谢大佬 ,我不用复杂场景,这个代码就很好了