-
Notifications
You must be signed in to change notification settings - Fork 0
DataviewJS Examples
Josh Glazer edited this page May 31, 2026
·
2 revisions
Annotation Manager integrates with the Dataview plugin. When Dataview is enabled, each note gets a cc field containing one object per annotation found in that note.
Each object in cc has five properties:
| Property | Type | Description |
|---|---|---|
parent |
string | Parent part of the identifier (e.g. math) |
child |
string | Child part (e.g. hot), or empty string if none |
text |
string | Annotation content |
line |
number | 1-based line number where the annotation appears |
citation |
string | BibTeX key from a {=/{key}/=} marker immediately following the annotation, or empty string |
Show all math/hot and stats annotations across the vault as a simple table:
dataview
TABLE rows.c.parent AS Parent, rows.c.child AS Child, rows.c.text AS "Annotation"
FROM ""
FLATTEN cc AS c
WHERE (c.parent = "math" AND c.child = "hot") OR c.parent = "stats"
GROUP BY file.link AS File
Show all math/hot and stats annotations with clickable line numbers, citation keys, and sorted by Note → Identifier → Line → Annotation:
dataviewjs
const targets = [
{ parent: 'math', child: 'hot' },
{ parent: 'stats', child: '' },
];
function matches(ann, t) {
return String(ann.parent) === t.parent && String(ann.child) === t.child;
}
const terms = targets.map(t => t.child ? (t.parent + '/' + t.child) : t.parent);
dv.header(2, 'Annotations for ' + terms.join(' and '));
function lineLink(filePath, line) {
const el = document.createElement('a');
el.textContent = String(line);
el.href = '#';
el.classList.add('internal-link');
el.addEventListener('click', async (e) => {
e.preventDefault();
const file = app.vault.getAbstractFileByPath(filePath);
if (!file) return;
const leaf = app.workspace.getLeaf(false);
await leaf.openFile(file);
const view = leaf.view;
if (view?.editor) {
const pos = { line: line - 1, ch: 0 };
view.editor.setCursor(pos);
view.editor.scrollIntoView({ from: pos, to: pos }, true);
}
});
return el;
}
const rows = [];
for (const page of dv.pages().where(p => p.cc)) {
for (const rawAnn of page.cc) {
const ann = {
parent: String(rawAnn.parent ?? ''),
child: String(rawAnn.child ?? ''),
text: String(rawAnn.text ?? ''),
line: rawAnn.line ? Number(rawAnn.line) : null,
citation: String(rawAnn.citation ?? ''),
};
if (targets.some(t => matches(ann, t))) {
const id = ann.child ? (ann.parent + '/' + ann.child) : ann.parent;
rows.push({
note: page.file.name,
link: page.file.link,
filePath: page.file.path,
id,
line: ann.line,
text: ann.text,
citation: ann.citation,
});
}
}
}
rows.sort((a, b) => {
if (a.note !== b.note) return a.note.localeCompare(b.note);
if (a.id !== b.id) return a.id.localeCompare(b.id);
if (a.line !== b.line) {
if (a.line == null) return 1;
if (b.line == null) return -1;
return a.line - b.line;
}
return String(a.text).localeCompare(String(b.text));
});
dv.table(
['Note', 'Identifier', 'Line', 'Annotation', 'Citation'],
rows.map(r => [r.link, r.id, r.line ? lineLink(r.filePath, r.line) : '', r.text, r.citation])
);Show every annotation that has a citation key attached, across the entire vault, sorted by Note → Identifier → Line → Annotation:
dataviewjs
dv.header(2, 'All citations');
function lineLink(filePath, line) {
const el = document.createElement('a');
el.textContent = String(line);
el.href = '#';
el.classList.add('internal-link');
el.addEventListener('click', async (e) => {
e.preventDefault();
const file = app.vault.getAbstractFileByPath(filePath);
if (!file) return;
const leaf = app.workspace.getLeaf(false);
await leaf.openFile(file);
const view = leaf.view;
if (view?.editor) {
const pos = { line: line - 1, ch: 0 };
view.editor.setCursor(pos);
view.editor.scrollIntoView({ from: pos, to: pos }, true);
}
});
return el;
}
const rows = [];
for (const page of dv.pages().where(p => p.cc)) {
for (const rawAnn of page.cc) {
const ann = {
parent: String(rawAnn.parent ?? ''),
child: String(rawAnn.child ?? ''),
text: String(rawAnn.text ?? ''),
line: rawAnn.line ? Number(rawAnn.line) : null,
citation: String(rawAnn.citation ?? ''),
};
if (!ann.citation) continue;
const id = ann.child ? (ann.parent + '/' + ann.child) : ann.parent;
rows.push({
note: page.file.name,
link: page.file.link,
filePath: page.file.path,
id,
line: ann.line,
text: ann.text,
citation: ann.citation,
});
}
}
rows.sort((a, b) => {
if (a.note !== b.note) return a.note.localeCompare(b.note);
if (a.id !== b.id) return a.id.localeCompare(b.id);
if (a.line !== b.line) {
if (a.line == null) return 1;
if (b.line == null) return -1;
return a.line - b.line;
}
return String(a.text).localeCompare(String(b.text));
});
dv.table(
['Note', 'Identifier', 'Line', 'Annotation', 'Citation'],
rows.map(r => [r.link, r.id, r.line ? lineLink(r.filePath, r.line) : '', r.text, r.citation])
);List every .bib file in your configured bib folder as a level-2 header, with a table of entries (key, author, year, title) sorted alphabetically. Requires the Bib files folder path to be set in settings.
dataviewjs
const plugin = app.plugins.plugins['annotation-manager'];
if (!plugin) { dv.paragraph('Annotation Manager plugin not found.'); return; }
const bibData = await plugin.getBibEntries();
const sorted = [...bibData.entries()].sort(([a], [b]) => a.localeCompare(b));
for (const [filename, entries] of sorted) {
dv.header(2, filename);
if (entries.length === 0) { dv.paragraph('No entries found.'); continue; }
dv.table(
['Key', 'Author', 'Year', 'Title'],
entries.map(e => [e.key, e.author, e.year, e.title])
);
}