I want to set up a CustomJS script that I can reference in a template. I want to minimize the amount of text I have to add to the template in order to get the code to work.
Things I have tried
I’ve written a block of dataviewjs code that works inside of a page (see here for reference).
let page = dv.current().file.path;
let pages = new Set();
let stack = [page];
while (stack.length > 0) {
let elem = stack.pop();
let meta = dv.page(elem);
if (!meta) continue;
for (let inlink of meta.file.inlinks.array()) {
if (pages.has(inlink.path)) continue;
if (
inlink.path.includes("Database level 1") ||
inlink.path.includes("Database level 2") ||
inlink.path.includes("Database level 3") ||
inlink.path.includes("Database level 4") ||
inlink.path.includes("Content database") ||
inlink.path.includes("Books database") ||
inlink.path.includes("Newspaper database") ||
inlink.path.includes("Blog database")
) {
pages.add(inlink.path);
stack.push(inlink.path);
}
}
}
let data = dv.array(Array.from(pages)).map(p => dv.page(p));
data = data.filter(data =>
data.file.path.split('/').includes("Books database") ||
data.file.path.split('/').includes("Newspaper database") ||
data.file.path.split('/').includes("Blog database")
);
dv.table(["Content Sources"], data.map(p => [p.file.link]));
I’ve copied that entire block into a new page named “supportingContent.js” within a folder in Obsidian named “CustomJS”. The CustomJS folder is referenced in the CustomJS plugin:
I copied the code block from inside here as regular text (omitting any backticks):
```dataviewjs
let page = dv.current().file.path;
let pages = new Set();
let stack = [page];
while (stack.length > 0) {
let elem = stack.pop();
let meta = dv.page(elem);
if (!meta) continue;
for (let inlink of meta.file.inlinks.array()) {
if (pages.has(inlink.path)) continue;
if (
inlink.path.includes("Database level 1") ||
inlink.path.includes("Database level 2") ||
inlink.path.includes("Database level 3") ||
inlink.path.includes("Database level 4") ||
inlink.path.includes("Content database") ||
inlink.path.includes("Books database") ||
inlink.path.includes("Newspaper database") ||
inlink.path.includes("Blog database")
) {
pages.add(inlink.path);
stack.push(inlink.path);
}
}
}
let data = dv.array(Array.from(pages)).map(p => dv.page(p));
data = data.filter(data =>
data.file.path.split('/').includes("Books database") ||
data.file.path.split('/').includes("Newspaper database") ||
data.file.path.split('/').includes("Blog database")
);
dv.table(["Content Sources"], data.map(p => [p.file.link]));
```
into a file named supportingStudies.js inside of a folder named CustomJS. It’s worth noting that part of the text still appears gray after pasting - I guess Obsidian recognizes for loops as code by default even when there are no backticks in place.
Then I added this dataviewjs code into the file where I wanted to call the script:
So now the table is created immediately after pasting script - I don’t have to paste the script and add extra code to create the table as I had seen done in other places.
Normally, in Obsidian, proper formatting is four backticks for code fencing and three for dataviewjs, like so:
````
```dataviewjs
code
```
````
I added an outer fence with 5 backticks now only I can see.
This is needed only if the script is called from Obsidian directly. So people should delete those from the js file.
So you call that script from the template and it’s working.
Good. One ice-cream with roletti for cigar for you.
I slight upgrade would be to also give context on those files:
// Define folderstoCheck array (Add your own folders)
const folderstoCheck = ["Placeholder1", "Placeholder2"];
let currentPage = dv.current().file.path;
let pages = new Set();
let stack = [currentPage];
while (stack.length > 0) {
let elem = stack.pop();
let meta = dv.page(elem);
if (!meta) continue;
for (let inlink of meta.file.inlinks.array()) {
if (pages.has(inlink.path)) continue;
// Check if any folder is included in the inlink path
if (folderstoCheck.some(folder => inlink.path.includes(folder))) {
pages.add(inlink.path);
stack.push(inlink.path);
}
}
}
const processedData = [];
for (let page of pages) {
const content = await dv.io.load(page);
const inlinkedFileName = dv.current().file.name.replace(/\.[^/.]+$/, ""); // Extract the file name without extension
const inlinkRegex = new RegExp(`\\[\\[${inlinkedFileName}.*?\\]\\]`, "g");
const paragraphs = content.split(/\n\s*\n/);
for (let paragraph of paragraphs) {
if (inlinkRegex.test(paragraph)) {
// Remove the path and format the file name with double square brackets
const fileName = `[[${page.split('/').pop().replace(/\.[^/.]+$/, "")}]]`;
processedData.push({
link: fileName,
content: paragraph
});
}
}
}
dv.table(
["Source File", "Context"],
processedData.map(p => [p.link, p.content])
);
For anyone wanting to do what OP wanted:
Save the file as a javascript file in a folder that is not the Templater user scripts folder, but some other folder.
Put in the foldertoCheck array the name of the folders that contain your Zotero annotations or whatever.
Then you can put the query call in a callout and even in a default template, like so:
> [!warning]+ Remember to incorporate this
> ```dataviewjs
> dv.view('javascriptfilenamewithnoextension')
> ```