Set link type automatically based on container of destination notes?

I know I sound pedantic, but I see the confusion ‘ziplinks’ causes those learning the app, thus the explanations. :slight_smile:

1 Like

I see. I have learned two things over the couple of years I have used TB. First, that there is almost always a solution for TB to do what I want. Second, that the solution rarely is what I have envisaged :blush:. Thanks a million for not only telling me what’s wrong, but also for explaining why it is wrong so I may actually learn.

So, the solution would be to:

  1. An agent query that selects all notes with an outgoing *untitled link in the entire document. I can select all notes with outbound links with the query $OutboundLinkCount > 0 but it would be unnecessarily cumbersome to select all link types. What query selects only *untitled links?

  2. Action code that loops through all selected links, selects the ones with a destination containing /Sources/ in their paths and assigns the link type referencesto them. I think I know how to select link with a particular destination note:
    eachLink(aLink,original){ if(aLink["destination"] == "Source 1"){ aLink["type"] = "reference"; } };

But how do I select all links with destinations containing the particular container name Sources in their paths?

ALTERNATIVELY
Would it be possible to design a query that only selects notes with outgoing *untitled links to notes containing /Sources/ in their paths? And then run the action code originally suggested:
eachLink(aLink,original){ if(aLink["type"] == "*untitled" { aLink["type"] = "reference"; } };

However, I simply don’t know what such a query would look like…

1 Like

I added some notes to your document and reset the agent query to:

$TextLinkCount(original)>0

For ease of testing, the above matches any note with 1 or Text links ($PlainLinkCount), for as we know know all links created via the ‘zip’ method are, in Tinderbox terms, Text links. This query ensure you don’t you won’t match notes with only Basic type links.

The agent action we came up with earlier is:

eachLink(aLink,original){
   if(aLink["type"] == "*untitled"){
      aLink["type"] = "reference";
   }
};

Can you see the problem? If I have an untiled link from Note 4 to Note I, this incorrectly resets the link type as it fails to check the destination is in /Sources. We need to be more specific, we need to test not only the the link type but also that the destination includes the path /Sources and that anchor is not empty (in which case the link must be a basic link , as only Text links have anchor text).

The action becomes:

eachLink(aLink,original){
   if(aLink["type"] == "*untitled"&aLink["destination"].contains("/Sources")&aLink["anchor"]!=""){
      aLink["type"] = "reference";
   }
};

In my test there are the following links:

  • Source 1. ‘untitled’ text link to ‘Note 3’: should be unaffected.
  • Source 2. ‘untitled’ text link to ‘Source 3’: should change to ‘reference’.
  • Source 3. ‘untitled’ basic link to ‘source 2’: should be unaffected.
  • Note 1. ‘untitled’ text link to ‘Source 1’: should change to ‘reference’.
  • Note 2. ‘disagree’ text link to ‘Note 3’: should be unaffected.
  • Note 3. ‘disagree’ text link to ‘Note 2’: should be unaffected.
  • Note 4. ‘untitled’ text link to ‘Source 2’: should change to ‘reference’.
  • Note 5. ‘untitled’ text link to ‘note 2’: should be unaffected.
  • Note 6. ‘untitled’ basic link to ‘source 2’: should be unaffected.

Here is my test file in two versions:

Look at both, and check their links against the results I listed above: remember use Browse Links with the original note selected and not the alias in the agent. Then, in the ‘before’ version, turn the agent query on. To to this, in the Query Inspector, open the Priority pop-up menu bottom left, change the selection from ‘Off’ to ‘Normal’. Allow a few moments for the agent to run, then check the links and note any changes.

1 Like

Thanks @mwra ! You have not only helped me creating the functionality I aspired, but also provided a pedagogical crash course in TB agents and automation that I am sure will also benefit others on this forum (at least other relative newbies). Simply fantastic!

However, I suspect there is something fishy with my TB installation or version (9.2.1). Nothing happens when I open your “before”-file, set the agents query priority to normal and let the agent run. I tested if there is something wrong with agent actions in general by just letting an agent select a note ($Name == "Note 4") and turn it red ($Color = "red";) and that worked like normal. If it would have been my own TB document that is acting out, I would have been certain it was something I have done or not done, but I cannot understand why your tested document fail to execute on my computer and TB version. Any ideas?

Thanks again!

Too kind. In truth, most of it I’d never actually done before and so it took a few missteps to get right. I’m as aware as any that there’s a gap between reading a description and understanding it and another from understanding conceptually to putting into action. That’s my impetus for posting my test file (hardly a demo as there are no instruction in there, etc.), plus the fact that seeing the process or at least before/after states is it gives confidence that re-using the concept should work when ported to personal projects.

Expanding for later reader, as much as for now, this shows the structural limitations to auto-interrogating links. Importantly, regardless of the context you are interested in, link data is only accessible from the link source’s note. So fine if the context is looking at outbound links; not so fine if looking at inbound links because each must be interrogated outside the context in their source note. This is better explained thus:

I’ve used an adornment ‘Context of Interest’ to simulate the part of the document where we are interested in the links. We can address most of the links in that context by looking at notes ‘in’ the area, i.e. note A and note D. But, to look at all the links in the area of interest, we must also look at notes outside the contest—note B and Note E as they link into the context area.

I hope that helps helps illustrate how we address working on 'links into ‘Context of Interest’. The context could be a whole map, an outline container, an arbitrary section of the map (the example I show here), etc.

Other action code tools can help is collecting the necessary—and minimum—number of note’s whose links will process:

continuing in a new post…

1 Like

We’ve also learned that we can use $PlainLinkCount (Basic links out from a note) and $TextLinkCount (Text links out from a note) to filter notes with either or both Basic and Text links. Thus if only using the ‘zip’ method for links of interest you would only want notes where $TextLinkCount >0. But what if some notes have both basic and test links?

Then the filtering has to happen within use of eachLink(). For each link processed, the operator offers a Dictionary of properties (sometimes referred to a ‘facets’) some of which my be empty. In terms of what they are/do:

  • start/end:
    • source. The $Path of source object, though it is also the note whose links we are processing so it is essentially already known. Read/write.
    • destination The $Path of destination object. Read/write.
  • type. The links’ link type. Read/write.
  • anchor (only for text links, the links’ anchor text within $Text). Read-only.
  • comment (internal link comment, otherwise accessed via Browse Links—the blank box the the bottom of the dialog). Read-only.
  • Info only for Web links (i.e. out of Tinderbox to external URLs—local or on the Web). Used for HTML mark-up when exported:
    • title. For HTML link’s <title> value. Read-only.
    • target. For HTML’s <target> value. Read-only.
    • url. For HTML link’s <href> value. Read-only.
    • class. For HTML link’s <class> value. Read-only.

By checking anchor, we can filter Basic from Text links as it will be empty only for Basic Links.

By checking destination, we can filter for inks going to a specific note, container, or branch of the document outline.

By checking type, we can check the link’s link type. This always has a value; the default is *untitled which in pop-up lists is ‘untitled’ and sows in a default map as a link with no link label (though beware, users can turn off the screen labels on other link types via the Links Inspector.

In summary: “some assembly required”, so to speak, but you can to a lot once you’ve figured out what to test and he code to do that. But questions like that are a key role for this forum.

A lesson I’d offer for starters, from this topic, is don’t be overly visual in your framing of the problem. By all means start with what you see—especially if using the map. Then consider where the information you see is actually stored. For instance you see links as lines between notes, but to interrogate a links’ data the only context you can do so is the links source note. But what if the link comes from a different map—where is the source. One additional bit of info can be obtained from link stubs. The inbound link stub (inbound from notes outside the map) is drawn above a note: click the number at the top of the arrow to show the source(s) of these link(s). Once you have an idea of where the notes are that you need to work with, you can start to figure out a query to find them (or make an agent) and then work on the links themselves.

HTH :slight_smile:

1 Like

In 8.x they were called ziplinks. Due to confusion, they are no longer called that. “Links” has far too many different meanings.

1 Like

This is a great functionality that I am sure will be useful for many! All thanks to @mwra, and Tinderbox 9.5!

When implementing it in my personal knowledge management system (Zettelkästen), I remembered @mwra 's earlier advice in this thread about making sure the name of the destination container remains unique in the entire document.

Since there it a significant probability that I will come up with names containing Sources in the string in the future, I changed the name of the container with my sources to zSources. This is perhaps obvious for experienced users, but I thought it was worth emphasising in this thread anyway.

1 Like

It is a good idea, and one that tends to only be obvious once you know. Simple prefixes are a simple stylistic device—even if only used when needed—to help avoid title ($Name) collisions. I tend to prefix all my (user) prototypes with a ‘p’ (‘pNote’) and other prefix styles are available according to personal taste.

Something like ‘zSources’ might look ugly to some eyes, but I see it as enlightened self-interest. If it makes something unambiguous something that otherwise is not, that is a gain and less worry about query/action mis-steps.

1 Like