Embed quotes (callouts) from all notes in one dataview list + add inline fields as columns in a dataviewjs table

What I’m trying to do

2 things that are related:

  • get all my quote callouts from the entire vault to appear in one note, ideally each in the callout format (for now I’ve managed only to get them in table form).
  • get all my (custom) vocab callouts from the entire vault to appear in one note in a table form (I’ve gotten that far), with additional columns to include info (metadata, inline fields?)

Things I have tried

I hope I’m using the correct vocabulary! Please try to explain things as simply as humanly possible; I’ve used Obsidian for a while but not anything super technical. I dabble and tinker with CSS, and I understand the very basics of Dataview, with some trial and error.
I’m now trying Dataviewjs, as this use case seems to require it, but I’ve never used JavaScript, so I’ve gleaned examples on this forum and on Reddit and tried to adapt them. Surprisingly, I’ve gotten to something that kind of works, but still not exactly as I wanted it to.

For the quotes:

I have 2 bits of code that each do part of what I want, but I can’t find a way to the exact thing I had in mind:

```dataviewjs
const pages = dv.pages()
const regex = />\s\[\!quote\]\s(.+?)((\n>\s.*?)*)\n/
const rows = [] 
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 summary via regex 
	for (const callout of contents.match(new RegExp(regex, 'sg')) || []) { 
		const match = callout.match(new RegExp(regex, 's')) 
		rows.push([match[1], match[2], page.file.link])
    }
}
const quote = []
quote.push(rows[Math.floor(Math.random()*rows.length)]);
let author = quote[0][0]
let quotetext = quote[0][1]
let note = quote[0][2]
let text = "> [!quote] " + author + " \| " + note + "\n> " + quotetext
dv.paragraph(text)
```

That first one gets me a callout format, but only for one (randomly selected) quote. It’s great for a “quote of the day” concept, but not what I wanted (seeing all of my quotes).

```dataviewjs

const pages = dv.pages('!"CalloutStyles"')

const regex = />\s\[\!quote\]\s(.+?)((\n>\s.*?)*)\n/

const rows = [] 
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 summary via regex 
	for (const callout of contents.match(new RegExp(regex, 'sg')) || []) { 
		const match = callout.match(new RegExp(regex, 's')) 
		rows.push([match[1], match[2], page.file.link])
    }
}

dv.table(['Author', 'Quote', 'Link'], rows)

```

That second one does give me all of my quotes, but in a table form, which I don’t find great especially for long quotes. I’d prefer the callout format, or at least some type of paragraph. Something like:

[!quote] Author
Quote that goes on and on…
[[Link]]

or
Author
Quote that goes on and on…
[[Link]]

Just to clarify: I always use the first line of the quote callouts to name the author, then below I include the quote itself. And at the beginning of the code here, I exclude a note where I list all my callout styles for reference.

Is there any way to get the best of both worlds?

For the vocab:

Now for the second thing, I’ve used a very similar bit of code to get all my vocab callouts into a table. These are customized callouts that I’ve created with CSS snippets, but I don’t think this really changes anything here.

The table works quite well, but I was wondering if I would include more columns for info like the language and the field for each word.

What I’m imagining would be adding this info in each callout in their respective notes, perhaps something like lg::EN (when the language is English); and the dataview table would include this info in a separate column.

Schematically:
Word | Definition | Language | Field | Link

I didn’t find examples online for this specifically (maybe I didn’t use the right search terms), and when I tried to add inline fields, they were just included in the Definition (main content) column (as you can see in the screenshot at the end of this post). Any of my naive attempts to edit the dv.table line just created errors.

Here’s the code I have at the moment (without that added info):

```dataviewjs

const pages = dv.pages('!"CalloutStyles"')

const regex = />\s\[\!vocab\]\s(.+?)((\n>\s.*?)*)\n/

const rows = [] 
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 summary via regex 
	for (const callout of contents.match(new RegExp(regex, 'sg')) || []) { 
		const match = callout.match(new RegExp(regex, 's')) 
		rows.push([match[1], match[2], page.file.link])
    }
}

dv.table(['Word', 'Definition', 'Link'], rows)

```

Is it possible to add those columns I’m envisioning, and how?

And one last tangentially related question: my dataviewjs table puts an empty line before the content itself, for the second column (the one that comes from the content of the callout below the title). Is that normal/avoidable? See below, the highlighted blank space.

Hi there, so I’ve actually solved my second question (and third, tangential question) to my satisfaction. If anyone’s interested:

```dataviewjs

// From all notes in the vault except for the one called CalloutStyles
const pages = dv.pages('!"CalloutStyles"')

// Define a regex that matches my !vocab callout
const regex = />\s\[\!vocab\]\s(.+?)((\n>\s.*?)*)\n/

const rows = [] 
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 summary via regex 
	for (const callout of contents.match(new RegExp(regex, 'sg')) || []) { 
		const match = callout.match(new RegExp(regex, 's'))

// Define parts of the contents you want (match[2] is the content below the title of your callout, here we're dividing it into smaller parts)

		// The first part goes from 3rd character (actual beginning of the text) to the first "<=" characters 

		const def = match[2].substring(
			3, 
			match[2].indexOf("<=")
		);

		// The second part goes from just after "<=" (+3 means you start after the space following <=) to the first # character

		const etym = match[2].substring(
		    match[2].indexOf("<=") + 3, 
		    match[2].indexOf("#")
		);

		// The third part goes from # (including it because I want to see it as a tag, otherwise add +1) to the last # character

		const lg = match[2].substring(
		    match[2].indexOf("#"), 
		    match[2].lastIndexOf("#")
		);

		// The last part goes from the last # (this excludes it, which doesn't bother me) to the end

		const usg = match[2].split('#').pop();

// Call the parts you've just defined to become rows (match[1] is the title of your callout; page.file.link is the link to the note the callout is in; the others are the names defined earlier in the code)

		rows.push([match[1], def, etym, lg, usg, page.file.link])
    }
}
// Create the table and name each column

dv.table(['Word', 'Definition', 'Etymology', 'Lg', 'Usage', 'Link'], rows)

```

… which gives me this table:

I do have to format the callouts quite carefully, it looks like this:

[!vocab] protean
changeable (protéiforme)
<= Proteus, Greek shape-shifting sea god
#EN #soutenu

(but different formatting could work, as long as you edit the code accordingly)

And the line below const def is the one that solved my blank line issue: it starts 3 characters after the theoretical beginning of the content, removing the characters before the text (added by the callout style, I think, as there is no added line break on my part).

I’m still at a loss on my first question with the quotes, though!