Exporting excerpts of notes

So I’m back tinkering with digital notebooks (don’t use the z word!). I’d like to try to achieve a complex export outcome and not quite sure how to go about it.

Here’s the context:

I have many notes with this attribute:

$Tags=people

Using zip links, I have linked other notes to each note. E.g., a note with $Tags=people might be named “John Smith” and I have many notes that I used zip links to link back to that note.

What I would like to achieve in export is a separate page for each person that looks something like this:

John Smith

  • Name of Note 1
    brief excerpt of that note. Maybe the first paragraph?
  • Name of Note 2
    brief excerpt of that note. Maybe the first paragraph?
  • Name of note 3
    brief excerpt of that note. Maybe the first paragraph?

To be clear, I’m aiming for HTML export here.

I see that ^text^ will allow me to create the excerpts. What I’m not sure about is how to write the export code so that each note with an inbound link will serve up its $Name (formatted as a hyperlink to that note) and ^text^. ^inboundLinks^ will get me the list, but not the ^text^. I imagine this might need some kind of “collect” but honestly that’s still something I struggle to wrap my mind around.

Sounds do-able. Not via export code without extra effort but definitely with some action code. So you want a note that is a ‘person’ (heavy hint— use a prototype for these if not already doing so) to export for each note linking to it (by a particular link type?):

  • The $Name of the source note
  • The initial N paragraphs of the source note

Correct? If so this is doable.

Yes with one extra bit: On the HTML exported page, $Name should be a Hyperlink to the note.

This will be easiest if you can create an agent for each tag. Then, each agent could take care of exporting its section, and could ^include(children, summaryTemplate) to get the formatted link list.

That assumes the people tags are a closed set, or at least a set that doesn’t add too many new people all the time.

If you want help effecting @eastgate’s solution, just ask.

Actually, I was hoping for something a bit different. While right now I have these “people” notes, I am thinking about extending this technique into other contexts where making a new agent for each one feels like more work than I want to put in each time. If an “action” code approach has drawbacks beyond the need to write it, I’d be curious to hear about them.

Oh – it’s doable. But the agent is easier to explain and implement :wink:

No censure implied here and zip links are good, but I’d like to clarify one mis-use of terminologythat has emerged since the zip link method cof link creation was added.

So, zip links are a method of making text links and not a type of link (linking within a TBX we only have a choice of basic & text types ).

Here, how the links were originally made is actually irrelevant to the task, here. By comparison it may become important to know if links are of basic (note to note) or text ($Text anchor text to note, or $Text anchor text to $Text anchor text).

Sorry Mark. I was trying to imply text links, since, as far as I know, Ziplinks can only make text links. And I wanted to show my appreciation for this new feature, which makes my usage for these notes so much better.

I haven’t made any “basic” links for this notebook. I’m not sure if that will change down the road, but so far I’m just using text links through the ziplinks feature.

No, no—as I said. no critique implied. But, thank you. I just know how easy it to slip innocently into terminology that then the community has to explain to new users for years after.

FWIW, I don’t think basic vs. text link matters here as you want to iterate inbound links, which covers both types. I did have go using an ^action()^ but it got very convoluted (and didn’t) work. My take: I think you want to request a new feature :smile:

I wrote this rule, which I thought would come close.

$backList=links.inbound..$Name;
$backList.each(x){$backLinks = $backLinks + linkTo(x) + "\n" + $Text(/Journal/x).paragraphs(1);
}

$backList properly creates a list of note Names that link to the selected note. Exactly what I want.

However, $backLinks (a string attribute) is not populating. It just says “true”. This is my first use of a .each action code so I’m sure I’m not formatting it correctly but I’m not sure what would be correct.

I think linkto makes links and linkedTo lists links. (It’s late, and it was a very nice chardonnay)

Start by making such that backList is what it ought to be. If so, make the {} of the each clause so simple that it could not possible be wrong. Then, when that works, elaborate step by step until it’s right.

Part of the problem is you want to make text links on the fly, but text links need to be anchored in $text. Anyway, I made a List-type user $BackList and a String-type user $BackLinks and used this stamp:

$BackList=links.inbound..$Name;
$BackLinks=;
$BackList.each(x){
   $BackLinks = $BackLinks + '^linkTo("'+ x +'")^' + "\n" + $Text(x).paragraphs(1);
}

Exported as ^value($Backlinks)^, the ^linkTo()^ statements aren’t evaluated if included in the export template as ^value($BackLinks)^. We can’t use ^value(exportedString(this, tBacklinks)^ and a t’tBacklinks’ template of ^value($BackLinks)^. If I paste $BackLinks as the note’s $Text it does work.

But what is the note already has other $Text. Action code has no easy way to replace only part of the $text (i.e. created via the rule/stamp/etc.) without putting in unwanted markers that then get exported. Grr.

So, I tried using ^value(eval($BackLinks))^ in the template (separate from ^text^) and that worked. But now the white-space between entries is massed up as \n has no HTML meaning and no isn’t processed into `

’ tags as might be hoped.

So I swapped out the \n breaks for HTML tags and now the eval() just returns true for the whole of $BackLinks. The inline HTML angle brackets—the only change—and which can’t be escaped as we want HTML tags not literal angle brackets seems to confure eval() (not sure if that’s a bug @eastgate?) . Anyway…

Challenge on!

The last test showed the way. I edited the stamp code to this, wrapping the HTML tags in a ^value()^ call (showing it can be used for literal text insertion):

$BackList=links.inbound..$Name;
$BackLinks=;
$BackList.each(x){
   $BackLinks = $BackLinks + '^value("<p>")^^linkTo("'+ x +'")^' + '^value("<br/>")^' + $Text(x).paragraphs(1)+ '^value("</p>")^';
}

Now, eval, which was barfing up true returns the expected text:

So, think I’ve cracked it. Here is my test file: imported-summary.tbx (102.4 KB)

1 Like

Wow Mark, virtuoso work! Very clear explanation as well.

One issue remains unfortunately–the links are not functional. The HTML looks like this in your example:

<p><a href=\"\">Event P</a>

But in the actual content of $BackLinks, it looks like it’s doing the right thing:

^value("<p>")^^linkTo("Event P")^^value("<br/>")^This is the first paragraph of text. Mary and Fred will be at this event.
^value("</p>")^^value("<p>")^^linkTo("Org Z")^^value("<br/>")^This is the first paragraph of text. In this case there are several sentences. this makes the paragraph longer. Mary is in this Org.
^value("</p>")^

The correct name of the note is there as expected. So I’m not sure if this is a bug, or it’s necessary to set the root of the HTML export or something? When I put this code into my own file, I get the same result, but the rest of the files export fine with all the links working, so it seems like whatever settings exist to make sure links work functionally is working correctly.

I’m also seeing some escaped punctuation in the paragraph text. E.g.,

you\'re

I think this must be the result of using the “eval” in the export template.

I think I might try another run at this a different way. I think maybe I will try to use the “Create” action code to create a child for each of these people notes that contains the names and first paragraphs of linked notes. I’m not entirely sure how I will get the Name as a text link, but I’ll fiddle with it and see if it’s worth pursuing.

or perhaps I should use the “createAgent” action code, which I wasn’t aware of before, and then just use @eastgate’s original suggestion. If I don’t have to create the agents manually, maybe that solution works best.

The main problem here is that when the ^value()^ export code was added, what was overlooked is you might want to use an attribute value (e.g. $BackLinks here) that needs to container export code that must be evaluated.

If your per-person notes don’t have/need $Text of their own, then do this:

$BackList=links.inbound..$Name;
$Text=;
$BackList.each(x){
   $Text = $Text + '^linkTo("'+ x +'")^' + "\n" + $Text(x).paragraphs(1);
}

…and export. That does appear to work. Otherwise you need to make a feature request for an a new code that export-evaluates an expression. Similar to exportedString() but not tied to note $Text scope but rather able to handle attribute contents that may contain inline export code that must be export-evaluated.

I know the concept of the outcome is simple, it’s just hard if the app never had the concept of being able to do this.

@mwra: Is there a way to use variables when using create? Basically, I want to create a note as a child of each “people” note, but I can’t reuse code like this because of the need to have a “unique” name to create a child note.

create("backlinks")

And I think I can’t use a path, because I would need to use variables there too, something like:

create(this, "backlinks")

EDIT:

solved my own question. what great documentation aTBref is!

collect_if(children,$Tags=="people",$Name).each(x){create(/Journal/x,"backlinks")}
1 Like

For posterity, I believe I have solved this.

  1. Create one agent that creates a list of backlinks for each relevant note, with this agent action:

$backList=links(original).inbound..$Name;

  1. In the top level container for my notes, I created this edict to create a child for each note that needs these backlink references:

collect_if(children,$Tags=="people",$Name).each(x){create(/Journal/x,"backlinks")}

  1. In the prototype for my regular notes, I created this $OnAdd action, so that each new “backlinks” note created in the previous step gets its Text set like so:

$backList(parent).each(x){ $Text = $Text + '^linkTo("'+ x +'")^' + "\n" + $Text(x).paragraphs(1); }

  1. Just in case I decide to use children of other notes for other purposes I created this logic in the HTML export template:
^text^
^if($Tags=="people")^
^include(child)^
^endif^
  1. Finally, these backlink notes don’t get updated automatically, so there’s one more step if you’ve been doing work on the notes that might lead to more notes needing to be collected for backlink references. I made a stamp to apply to the container note holding all of these:

collect_if(descendants,$Name=="backlinks",$Path).each(x){delete(x)};

I may consider an agent or rule or something for step 3 to make these backlink notes updated automatically, but it’s tricky because when I tried that earlier the note text kept being repeated endlessly.

1 Like

Ok, alternate solution using agents.

  1. Same as above. Create an agent that grabs the inbound links as a list

  2. Create a stamp with this code, substituting the path for the agent (here it’s /TagMaker/people but you might use something different):

collect(children(/TagMaker/people),$Name).each(x){create(/Journal/x,"backlinks")}

  1. Create a new boolean attribute $setBackLinks with “false” as default.

  2. Create an agent with this query, to find the newly created backlinks notes, substituting your path in the descendedFrom action:

descendedFrom(/Journal) & $Name=="backlinks" & $setBackLinks == false;

  1. Give that agent this action:

$backList(parent(original)).each(x){ $Text = $Text + '^linkTo("'+ x +'")^' + "\n" + $Text(x).paragraphs(1); };$setBackLinks = true;

  1. Create this stamp to delete all the backlinks notes when you want to update them:

collect_if(descendants(/Journal),$Name=="backlinks",$Path).each(x){delete(x)};

Now, the publishing process works like this:

  1. Invoke the stamp in step 6 to delete all the backlinks notes
  2. Invoke the stamp in step 2 to re-create the backlinks notes
  3. Wait for the agents to populate the text of those notes.
  4. Export.

I have a stamp that automatically fires these stamps in order. So now the process is mostly foolproof–I don’t have to remember to do anything except run my “publish” stamp and be patient for the agents to do their work before I export.