Welcome, Guest. Please Login
Tinderbox
  News:
IMPORTANT MESSAGE! This forum has now been replaced by a new forum at http://forum.eastgate.com and no further posting or member registration is allowed. The forum is still accessible via read-only access for reference purposes. If you wish to discuss content here, please use the new forum. N.B. - posting in the new forum requires a fresh registration in the new forum (sorry - member data can't be ported).
  HomeHelpSearchLogin  
 
Pages: 1 2 
Send Topic Print
Exporting links to SOME children / aliases (Read 4389 times)
Pat Maddox
Full Member
*
Offline



Posts: 66

Exporting links to SOME children / aliases
Apr 12th, 2016, 4:18pm
 
I'm using Tinderbox to publish articles to my site, and I want to easily set up "Read these next..." links at the end of each article.

My plan was to alias the relevant articles as children of the main article. Then I can change my export template to show something like, "If any children have the prototype p_article, show a header 'Read these next' and link to the articles.

I don't really have any idea how to do that Smiley

Here's a screenshot of the note in question. You can see it has other children which should not be exported. Only the italicized notes (aliases) should be exported in the "Read these next" section.



And here's the article online with its links at the bottom (I just manually created links inside the article note for the time being).

Any idea how I can modify my export template / document structure to do what I want?
Back to top
 
 
  IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 5689
Southsea, UK
Re: Exporting links to SOME children / aliases
Reply #1 - Apr 12th, 2016, 6:06pm
 
My understanding;
  • "Refactor away..." exports as a page
  • The above page wants to add a link to the last 4 children only
The simple way is to set the non-exporting containers to not export a page and then add ^childLinks^ to the page template for the main page. You can modify ^childLinks^ via its option inputs.  If you need greater HTML control you could use ^children^ instead using a second template which would emit just the HTML for the link. Both codes ignore non-exporting children. The method should (working from memory - not tested) still work if the last 4 items are aliases - the link will simply point to a different place.
Back to top
 
« Last Edit: Apr 12th, 2016, 6:06pm by Mark Anderson »  

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v6
(TB consulting - email me)
WWW shoantel   IP Logged
Pat Maddox
Full Member
*
Offline



Posts: 66

Re: Exporting links to SOME children / aliases
Reply #2 - Apr 12th, 2016, 6:37pm
 
Okay thanks, that's helpful. I managed to conditionally show the "Read next" links if there were any children with a specific prototype:

Code:
^if(any(children, $Prototype == "p_article"))^

## Read these next

^childLinks("<ul>", "<li>", "</li>", "</ul>")^
^endif^ 



But this brings up another question that I have: how could I tell this note to only export children that have that prototype? It happens to work in this case because the other child notes have HTMLDontExport set to on. But what if I had other children in there? How could I render a list of children that match a specific condition?
Back to top
 
 
  IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 5689
Southsea, UK
Re: Exporting links to SOME children / aliases
Reply #3 - Apr 13th, 2016, 3:06am
 
If the output of a template is nothing, i.e. no text or mark-up at all, then no exported file is created even though the source note is being 'exported' (as opposed to export being suppressed via $HTMLDontExport). Thus if you wrap the entire contents of the template's code in an ^if()^ conditional statement, then a page is emitted on export oly if the condition is true.

I posted late last night and didn't have time to add in some links which might be useful. See:
Back to top
 
« Last Edit: Apr 13th, 2016, 3:08am by Mark Anderson »  

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v6
(TB consulting - email me)
WWW shoantel   IP Logged
Pat Maddox
Full Member
*
Offline



Posts: 66

Re: Exporting links to SOME children / aliases
Reply #4 - Apr 13th, 2016, 10:44am
 
Okay, let's say I have two kinds of children: one with prototype p_article, and another with p_video.

I want to render TWO lists: one with p_article children, and one with p_video children. How do I do that? p_article and p_video both have HTMLDontExport=false. So I can't just use ^children^. I need some way of specifying which children I intend to render.
Back to top
 
 
  IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 5689
Southsea, UK
Re: Exporting links to SOME children / aliases
Reply #5 - Apr 13th, 2016, 12:24pm
 
Ok, this gets little more complex - in terms of construction - but is quite easy. You need a command that says "at this point insert data from notes meeting [criterion], laid out using [templatename]". If you don't give the second input (the template) you'll get the target notes' own default template output and you may end up nesting an HTML page in another which is an HTML coding error (even if it might render in a browser)

So let's start by assuming you've created an attribute called 'listing' which you'll used for the second part of the above. For example, something like:

Code:
<li>^linkTo(this)^</li> 


Now we can use a separate ^include()^ command for each of your two lists. As you want two discrete sub-group listings of items from the current page's children - and possibly not even all children - you can't use a single group designator like 'children'. [url=]find()[/url] is your friend here. In your main template:

Code:
...
<p>Listing of articles:</p>
<ul>
^include(find(inside(that)&$Prototype=="p_article"),"listing")^
</ul>
<p>Listing of videos:</p>
<ul>
^include(find(inside(that)&$Prototype=="p_video"),"listing")^
</ul>
... 



What is you'd like to use a different CSS class of the <li> element in each list. You could make a different version of the template (listing1, listing2, etc) for each list type. Of you could use an if clause in a single template:

Code:
<li class"^if($Prototype=="p_article")^green^else^red^endIf^"... 



The uses just one template but the condition gets long and complex if you've now say 4 different stylings.  Better to add a user string attribute $CSSClass and get each prototype to stop the appropriate CSS class value. Thus all notes using that prototype inherit that $CSSClass. Now you only need one listing:

Code:
<li class="^value($CSSClass)^">^linkTo(this)^</li> 



Note: time precludes me doing a full test of this, but I've linked to aTbRef listings on the codes which should explain syntax.
Back to top
 
 

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v6
(TB consulting - email me)
WWW shoantel   IP Logged
Pat Maddox
Full Member
*
Offline



Posts: 66

Re: Exporting links to SOME children / aliases
Reply #6 - Apr 15th, 2016, 5:52am
 
That all makes sense to me. But I must be doing something wrong in practice. Check out this test document.

I've set up a single prototype "p_funky". If I modify your code to the following, it doesn't render any children (notice I took out the inside() call as well):

Code:
^include(find($Prototype == "p_funky"),"/Templates/HTML page/HTML item")^ 



but if I do a find based on the name, it returns the correct child:

Code:
^include(find($Name == "child 1"),"/Templates/HTML page/HTML item")^ 



but if I add a call to inside() (my nemesis!!!), then it no longer finds the child!

Code:
^include(find(inside(that) & $Name == "child 1"),"/Templates/HTML page/HTML item")^ 



So it seems like it doesn't work when I use $Prototype, which I find hard to believe (I must be doing something boneheaded). And it also appears not to work with inside(), which I totally believe because I still don't understand how that thing works  Shocked
Back to top
 
 
  IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 5689
Southsea, UK
Re: Exporting links to SOME children / aliases
Reply #7 - Apr 15th, 2016, 8:03am
 
As noted in my last, I didn't have time to run the code posted but in the aTbRef reference to which I linked, you'll see I'd forgotten to enclose the find() action/query code in a ^value()^ tag. This works - in that it finds things:

^include(^value(find($Prototype == "p_funky"))^,"/Templates/HTML page/HTML item")^

But that filter finds every note with the 'p_funky' prototype (and every alias of those notes!). Also, doing tests using notes with names that are designator values designator is likely to only garner strange false results. So I re-named the container 'thingx' and the children 'x 1', 'x 2' and 'x 3'. I also added a root-level exporting note 'other note' that uses the 'p_funky' prototype - as we don't want to match out-of-container scope notes.

So, adding ^value()^ in the mix, what we probably want is something like:

Code:
^include(^value(find($Prototype == "p_funky"&inside($Name(that))))^,"/Templates/HTML page/HTML item")^ 



But (using v6.5.0) that doesn't work, though I don't know why. Knowing inside() has some not-easily-guessed logic quirks, I tried using descendedFrom($Name(that)) to see if using inside() where the issue. At which point the penny dropped.

Historically, ^include()^ was there to allow one note to import data from another, non-descendant, note of the one currently being processed. Likely it was never configured to do this sort of in-container-scope filtering - Eastgate can better answer that nuance. ^children()^ gives us all children, but not means to filter. But…

^children()^ can use a specified template for the import. So, we filter there, in the called template. Recall that if a template evaluates to nothing, nothing is returned (well some white-space may be but that's easy to tidy up once the bigger issue is resolved). Put this in the main page template:

^children("/Templates/HTML page/HTML item")^

Now, the 'HTML item' template becomes:

^if($Prototype == "p_funky")^<h2>^title^</h2>
^text
^children(/Templates/HTML page/HTML item)^
^endIf^


That works!  If you need different output for different page types, just put more conditions here. A single ^if^ with no 'else' here offers some or no output. An if/else structure could offer a choice of two outputs (or none).  If you've lots of choices and they're mutually exclusive, e.g. different prototype assignments, then you can just use lots of discrete ^if^ tests with not alternate as each tested note will only match one if test at most because a note can only have one prototype.

~~~~~~~
Template naming/references. You don't need to cite the full path to the template. I think that in the  built-in examples its a reflective hang-over from the days when templates were external text files and you had to tell TB where in the OS look Luckily that hassle is gone - all templates are in the TBX.

So, it's enough to use the title ($Name) of the template, assuming the name is unique in the whole TBX  - as templates are just a note with special characteristics.  If 'HTML item' is a unique name both these work:

^children("/Templates/HTML page/HTML item")^
^children("HTML item")^

The added quotes are now best practice but the legacy quote-less version still works. As can be seen, 'HTML item' is quite possibly a title one could use in a note, so a good idea is to use prefixes - as with your prototypes. I then to use a 't_' prefix, so would probably use 't_HTML_item' though tHTML item' would do just as well.  As long as it's a unique and valid name, choose a naming style that suits your style.

Sorry for the long post, but I hope the wider explanation will help folk bootstrap solving other export puzzles.  Smiley
Back to top
 
« Last Edit: Apr 15th, 2016, 8:04am by Mark Anderson »  

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v6
(TB consulting - email me)
WWW shoantel   IP Logged
Pat Maddox
Full Member
*
Offline



Posts: 66

Re: Exporting links to SOME children / aliases
Reply #8 - Apr 25th, 2016, 12:04pm
 
Well, here's something that I totally do not understand.

How come find() with $Name works without ^value^, but find() with $Protoype requires ^value^ to work?

e.g. this finds something:

Code:
^include(find($Name == "child 1"),"/Templates/HTML page/HTML item")^  



this doesn't:

Code:
^include(find($Prototype == "p_funky"),"/Templates/HTML page/HTML item")^ 



and this does:

Code:
^include(^value(find($Prototype == "p_funky"))^,"/Templates/HTML page/HTML item")^ 



That seems inconsistent in a way that doesn't make any sense to me.


Also it's a bummer that neither inside() nor descendedFrom() works for this. I think this will get messy, as I'll have to create these conditional templates for every variation of "include specific children" that I want to do. But we'll see what happens over time I guess. Thanks for digging into this.
Back to top
 
 
  IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 5689
Southsea, UK
Re: Exporting links to SOME children / aliases
Reply #9 - Apr 25th, 2016, 5:14pm
 
My notes indicate that all expressions, such as find() within an ^include^ require a ^value^ wrapper. I can't get your first example to work, but it does if I use ^value()^. so, for me - using your test file - behaviour is consistent.

Behaviour of inside and descendedFrom is baked into the app, if you need that changed you need to write in as it's not user configurable.

Quote:
as I'll have to create these conditional templates for every variation of "include specific children" that I want to do

How else would Tinderbox know your context-specific export needs? Surely if a different behaviour is needed, it needs to be described somewhere?
Back to top
 
 

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v6
(TB consulting - email me)
WWW shoantel   IP Logged
Pat Maddox
Full Member
*
Offline



Posts: 66

Re: Exporting links to SOME children / aliases
Reply #10 - Apr 25th, 2016, 6:15pm
 
Quote:
My notes indicate that all expressions, such as find() within an ^include^ require a ^value^ wrapper. I can't get your first example to work, but it does if I use ^value()^. so, for me - using your test file - behaviour is consistent.


Well, that's strange. I've uploaded a second version of the document which finds based on the name, but does not use ^value^. When looking at the HTML preview, it shows the child.

I would think it very strange if your Tinderbox treats that document differently than mine, unless of course you're using a version that I don't have access to and something has changed.

Quote:
How else would Tinderbox know your context-specific export needs? Surely if a different behaviour is needed, it needs to be described somewhere?


Of course. It just bugs me that it'll require a new template every single time. I thought I had identified a really useful pattern: "find a collection of notes, and include them." But instead of doing that, I'll have to create another template, have it iterate over more notes than I need, and render nothing in the case of notes that don't match. I find that significantly less elegant than finding the notes that I need and including them specifically... but this isn't the first time that my mental model has differed greatly from Tinderbox's model. I'll get there, one of these days Smiley
Back to top
 
 
  IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 5689
Southsea, UK
Re: Exporting links to SOME children / aliases
Reply #11 - Apr 26th, 2016, 3:49am
 
Re ^value()^, I think you're drawing the wrong inference re find(). Re-read my notes on ^include()^

Note (emphasis added here by me):

Quote:
Expressions must take a ^value()^ wrapper. The most common use with an expression is a find():

The 'bug', if such there is, is that your find($Name == "child 1") works when it should not.

This edge case doesn't surprise me. Reading between the lines, the role of ^value^ is to ensure the find() expression is fully evaluated before further use. As the (aTbRef) notes on ^include^ state, if the first input is a simple object or object designator then it's fine; anything more complex as a first input requires a ^value()^ call.

You should understand that (a) ^export^ code is a very old (15+ years) part of Tinderbox and predates action code and (b) ^include()^ has had functionality added over time. Originally, include - as per the Tinderbox Help - allowed a single object (note) to be included. Including more than one object, i.e. a group instead of an item was an improvement added in v5.9.2 and IIRC in response to supporting a rather complex export I was designing for another Tinderbox user. It needed find because different children needed handling different ways. I can't post from that project here as it was private consulting work.

Viewed in terms of how the feature has grown, it's not surprising - to me - that some use requires a little extra scaffolding compered with the basic original use.  Even if my memory failed me up-thread about ^value()^ the reference I cited was correct.

Quote:
I thought I had identified a really useful pattern: "find a collection of notes, and include them."

Yes, but you're not doing that. your workflow is "find a collection of notes, and include them using different export mark-up depending on the nature of each child." It is your latter requirement which is causing you to need to write extra templates. From Tinderbox's perspective it doesn't matter how manny templates are needed as long as you connect them up correctly. So 'how many' is in part down to how export works and the rest to the users desire for more/fewer pieces. Although aTbref uses one big template for most pages, that was only an exercise in seeing if it were possible to replace the c.10 templates I had previously. I wouldn't argue the monolithic template is easier to use just because it's one item - it's certainly harder for a new user to deconstruct.

^include()^ need a second template argument if the target objects' own export template is not the one needed in this context.  If the target objects won't export as HTML pages in their own right, then you can set them to use the 'include' template code as their template (better, their prototype's template). Either way you still need to define each discrete differing set of HTML code.

If you're happy for the children to list in $OutlineOrder but want different mark-up (or no export) for each, then you can use ^children^ making sure you cite a template - or the children have a template - that resolves the differing export outcomes for each child. The latter has to encoded somewhere.
Back to top
 
 

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v6
(TB consulting - email me)
WWW shoantel   IP Logged
Mark Bernstein
YaBB Administrator
*
Offline

designer of
Tinderbox

Posts: 2871
Eastgate Systems, Inc.
Re: Exporting links to SOME children / aliases
Reply #12 - Apr 26th, 2016, 8:30am
 
This may  perhaps be made simpler and clearer by breaking the work down into two parts.

a) Choose which notes you want to include. Store that list in a convenient place -- perhaps a user attribute $ExportHighlights.  This might be done by a rule or agent.  Or, if you need to do this at export time,

   ^action( $ExportHighlights=find(.....) )

b) Export those notes:  ^include( ^value($ExportHighlights) )

This gives you the advantage of knowing, should problems arise, whether the difficulty lies in the choice of notes you're including, or with the way the included notes are being exported.

My recommendation is to keep export templates as simple as you can.
Back to top
 
 
WWW   IP Logged
Pat Maddox
Full Member
*
Offline



Posts: 66

Re: Exporting links to SOME children / aliases
Reply #13 - Apr 26th, 2016, 10:31am
 
Quote:
The 'bug', if such there is, is that your find($Name == "child 1") works when it should not.


Well okay. It's not like I had any way of knowing that. I'm just sharing what I observed.

Quote:
Quote:
I thought I had identified a really useful pattern: "find a collection of notes, and include them."


Yes, but you're not doing that. your workflow is "find a collection of notes, and include them using different export mark-up depending on the nature of each child."


Not true. That was an addition we made later. But the original example document is quite clear: "find children that have a specific prototype, and include them."

That's the first step of my workflow. "Find a collection of notes [matching certain criteria] and include them."

A solution that appears to work

In any case, I may have found something simple that works. It relies on the fact that include() appears to look within the current note first. So I can create an agent that finds the notes I need, or simply create a container, and include that specific note. Here's an example document.

With any luck, this behavior will stay consistent on my larger doc...
Back to top
 
 
  IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 5689
Southsea, UK
Re: Exporting links to SOME children / aliases
Reply #14 - Apr 26th, 2016, 12:14pm
 
Quote:
appears to look in the current note first

appears [sic]. Actually, your code ^include("child 1",... is asking Tinderbox to find the note named "child 1" within the entire TBX, and you have several.

When matching notes, Tinderbox convention if a single match is required is to take the first match by $OutlineOrder (the first child note of the first container in your TBX) and use that $Path to find date to include. However, where a multiple match is allowed, as with ^include^, it makes a list of the $Path of each note of that name (or whatever matches the query**), of which you have 3, and processes those.

** Note that find() doesn't de-dupe so will return a list of matching notes and all (in-scope) aliases of those notes - such as the aliases inside you agent.

Aside, I'd repeat my earlier suggestion of avoiding using designator names in your test file (e.g. 'parent') as it may confuse Tinderbox in the exact scenario where you don't want confusion.

At this point, if you've good something that works for you that's fine and it looks like you're done which is good.
Back to top
 
 

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v6
(TB consulting - email me)
WWW shoantel   IP Logged
Pages: 1 2 
Send Topic Print