Transclusion of callouts with block link ID

I am trying to transclude notes that contain callouts with their respective block link id’s (such as ^a1a2b3). I am having some difficulties rendering the transclusion with dataview. For instance, the note file path, plus the block id show fine in the console.log, but on the screen does not render properly.

This is the script I am using to transclude the callouts:

let pages = dv.pages("#transcl/blockid")
const blockid = "^a2b3c4"
const regex = />\s\[\!(\w+)\]\s(.+?)((\n>\s.*?)*)\n/

for (const page of pages) {
    const file = app.vault.getAbstractFileByPath(page.file.path)
    console.log(file)
    const contents = await app.vault.read(file)
	for (const callout of contents.match(new RegExp(regex, 'sg')) ) {
		const match = callout.match(new RegExp(regex, 's')) 
		if (match[1] == "award") {
			const transcl = `![[${page.file.path}#${blockid}]]`
			console.log(transcl)
			dv.el("p", transcl)
		}
	}
}

Note. To make the explanation shorter I am using a common block-id: ^a1b2c3, but generally these Id’s are generated automatically.

A note contains callouts such as:

---
tags:
  - transcl/blockid
---

> [!award] A best note with a block link
> This is a text line.
> Then, this is a picture:
> ![](Pasted%20image%2020240110222128.png) ^a2b3c4

> [!note] ### Another callout
> Without figures.

A second note looks like this:

---
tags:
  - transcl/blockid
---

> [!info]  ### Information note
> Text
> Text
> Latex: $c^2 = a^2 + b^2$
> ^a2b3c4

> [!warning] ### Check if second block is chosen
> The second block should not be shown because doesn't have a block link.

In the console, transcl renders like this:
![[Note with callout and block link.md#^a2b3c4]]

But on the screen, when I do dv.el("p", transcl), I get this:
Note with callout and block link.md > ^a2b3c4

Yes, there is a greater than sign where it shouldn’t.

Would anyone know how to transclude callouts that have a block link id?

Not sure which way would work but I’d try to tackle this in either of the following ways:

  • CSS. See e.g. this thread.
  • Would try to regex replace > (greater than plus a whitespace after it) with '' (nothing), as mentioned in this post (there I deleted - as well).

This is a larger issue with Dataview which often has issues with embeds. It seems that only the images can somewhat reliable be embedded from within a dataviewjs script.

Where the author of Dataview says:

Dataview delegates to Obsidian markdown rendering which will not render transclusions at all, sadly.

Thanks @gino_m.
I tried both approaches. The one with css I think is not applicable.
The idea of replacing the > symbol with empty was very attractive, and addressed the problem. Unfortunately, the > symbol only shows when #^ are together; so, no symbol to remove. But it was useful because I discover another function dv.blockLink, which even has the option (true/false) of returning an embedded link. Still didn’t work because the > continues to interfere.

I have continued exploring the issue, and it seems that dataviewjs will not solve the problem by itself, as @holroy mentioned in the subsequent post.

What I just found is an indirect way of circumventing Dataview, which is writing to a md file the string ![[note_name.md#^a1b2c3]], giving no chance to Dataview to interfere. Got the idea from here Zettelizer.js which QuickAdd will execute - not in real time - like dataviewjs does, but asynchronously. I have to make some changes to the original script; instead of looking for ### header, it should look for ^, join it with the note filename, the #, the ^, and the block-id.

You are right @holroy.
No matter in how many different ways I tried to obtain a real-time transclusion of a callout block, it will never work. There is something in Obsidian, or Dataview, that automatically converts the combination of #^ to the greater-than symbol >. I even found and tested dv.blockLink() with the embedded option activated, and no success. Always, the > symbol will pop up whenever #^ are together in a string, in the view mode in the editor. In the console everything shows as it should be.

I am trying now a different approach with QuickAdd and a macro that will run as needed, writing to a md file, called manually with Ctrl+P, etc.

I’m not quite sure whether you need this to be re-run all the time, or just every now an then, but another approach could be the following (especially since your dataview is so mature):

```dataviewjs 
... script which writes to note "collation_a1b2c3"
```

![[collation_a1b2c3]]

In other words, have the script write either the transclusion text or embed links into a secondary file, and have that file permanently embedded below the script.
If you don’t need to re-run the collation often, you could just run it through Templater or QuickAdd every now and then. Potentially with them returning when it was last collated.

Finally, I got this to work.
Thanks to @gino_m and @holroy for sharing their excellent ideas and providing potential solutions.

What it works consistently is using templater to execute the JavaScript code and generate the transclusions for the callouts inside the new note that templater creates.

I am using this template to make collections of the best paper extracts that I put on inside callout blocks. Obsidian doesn’t have direct support of callouts as in headings, lists and tasks, so one has to do it from scratch.

While reading papers I extract the best lines, paragraphs, plots, tables, or equations and put them inside a callout with a title and a heading. I have three quality categories: gold, silver and bronze. Instead of creating a new callout I use existing ones such as “award”, “sun”, and “rocket”. I believe they come with the plugin Callout Manager. Since every paper has its own note that are located under the folder Sources, I read their data from there. A paper source note may have one, two or more than ten callouts, but only one can be gold, and silver, and bronze. Of course, the paper source note has several sections such as Critique, Highlights, Extracts, Mechanisms, Citation, References, Glossary, and the PDF paper Preview. The section that has the callouts is Extracts.

What the template does is iterating through the pages under the folder Sources, then iterate through all the callouts, and then only extract the callout that is labeled as “award” (gold), “sun” (silver), or “rocket” (bronze). The callout label, title, and block-id are extracted through the array match. Then, each of the callout blocks is transcluded with tR += "![[" + page.file.name + "#" + match[4] + "]]". Here the variable tR is acting like a print statement inside templater. The final note contains all the transclusions from all the papers in one place. You can name the note whatever you want. I use something like “Gold callouts”, etc.

I think this is a better and more stable solution that doing the transclusion directly using dataviewjs. DVJ works sometimes, and is very fragile, as in showing the code instead of the transclusion.

<%*
const dv = app.plugins.plugins.dataview.api
const pages = dv.pages('"Sources"')                   // folder
const regex = />\s\[\!(\w+)\]\s(.+?)((\n>\s.*?)*)\n/  // callout
const blockID = /((\^)([0-9a-z]{6}))/g                // block-id

// iterate through notes
for (const page of pages) {
    const file = app.vault.getAbstractFileByPath(page.file.path)
    // Read the file contents
    const contents = await app.vault.read(file)
    // Extract the callouts via regex
    for (const callout of contents.match(new RegExp(regex, 'sg')) || [] ) {
	    // on each callout read the type, title, and block-id
	    const match = callout.match(new RegExp(regex, 's')) 
	    if (match[1] == "award") {          // callout for Gold
		    match[2] = match[2].split("#")[match[2].split("#").length-1].trim()  // title
		    match[4] = match[3].match(blockID)     // block-id
		    tR += "[[" + page.file.name + "]]"     // link to note
		    tR += "\n"
		    // transclusion to content of whole callout
		    tR += "![[" + page.file.name + "#" + match[4] + "]]"
		    tR += "\n\n"
		}
    }
}
%>

This is an example of the callout labeled as Gold:

> [!award] ###  Numerical results on the BDR mechanism
> Numerical results showed that the [MBDR](Bubble%20Drag%20Reduction.md) mechanism can be attributed to the following three factors: 
> 1. An **additional momentum source** is caused due to the injection of gas bubbles. This redistributes the flow structure of the carrier phase in the boundary layer and reduces the resultant skin-friction coefficient along the wall surface by increasing the normal flow velocity, leading to a significant decrease in the mean stream-wise velocities. 
> 2. The presence of the micro-bubbles **causes perceptible turbulence modification** to the carrier phase. Turbulence attenuation occurring near the wall surface may contribute to drag reduction. 
> 3. The injection of microbubbles **creates a thin film of liquid that covers the wall surface**, thereby reducing the shear stress and drag forces between water and wall.
>  ^gnt6kf

It is key to add the block-id to the callout. That is how the script makes the transclusion possible.

Enjoy!

2 Likes

Looks very nice and thanks for the detailed explanations as well.
I’m sure a lot of people will benefit from your contribution(s).

Cheers

1 Like

I see more and more solutions around here which rely on reading complete files, and regex matching on the content. And that might be the way to go sometimes, but in other cases one could use other structures which are easier to query. Below I’ve used a [w] (for win(?) ) tasks), which I styled using CSS:

-  [w] Numerical results on the BDR mechanism
	-   Numerical results showed that the [MBDR](Bubble%20Drag%20Reduction.md) mechanism can be attributed to the following three factors:  
		1. The presence of the micro-bubbles **causes perceptible turbulence modification** to the carrier phase. Turbulence attenuation occurring near the wall surface may contribute to drag reduction.
		2. The injection of microbubbles **creates a thin film of liquid that covers the wall surface**, thereby reducing the shear stress and drag forces between water and wall.
		3.  An **additional momentum source** is caused due to the injection of gas bubbles. This redistributes the flow structure of the carrier phase in the boundary layer and reduces the resultant skin-friction coefficient along the wall surface by increasing the normal flow velocity, leading to a significant decrease in the mean stream-wise velocities. 

With my ugly styling, this resulted in this output:

My styling for the ugly output above
input[data-task="w"]:checked,
li[data-task="w"] ,
li[data-task="w"] {
  border: 2px solid blue;
  background: #052236;
  padding: 3px;

  &  .tasks-list-text {
    background: #178978;
    float: right;
    width: 100%; 
    display: block;
    padding: 8px; /* */
    font-weight: 700;
    font-size: 1.4rem;
    border: 2px solid blue; 
  }
}

Hopefully this gets the message across that you could style the task with sub-lists to your liking (and to somewhat match the callout style).

But the main benefit of using this markup is that now your query becomes:

```dataview
TASK
WHERE status = "w"
```
3 Likes