Outputs a sequence of values from the specified enumerator, applying the specified filtering/ordering/limits.
|X|hax.iterator:myTag: .. directive in a
*.haxproj file,
prefix, suffix, joinVia, content{X|myTag: .. |}Hence, formatting and structure of the output is mostly defined in the X-tag's one-off declaration / configuration, while the per-tag invocation / parameters define what values to enumerate, which ones to show, in what order etc.
This topic is in a compact format for users already familiar with the essentials of declaring X-tags and invoking them. If found challenging, try the more-elaborate-and-introductory topics first to form a better grasp on the basics and overall mechanisms.
Early or Page — this X-renderer determines dynamically (documented further below) whether or not it requires a page context for rendering, so depending on each hax.iterator-invoking X-tag's configuration and/or parameters:
To demonstrate valid *.haxproj directives declaring hax.iterator X-tags:
|X|hax.iterator:myenum
|X|hax.iterator:myenumlist:
prefix = "<ul class=\"my-blogs\"><li>",
suffix = "</li></ul>",
joinVia = "</li><li>",
content =>
<a id="b_link_{:i:}" href="/{:v:}/index.html"> {B|title: {:v:} |} </a>
To elaborate, for example the last one of the above, as all |X| directives declaring X-tags do:
|X| followed by the X-renderer identifier (here hax.iterator) : colon and the desired X-tag name to be used to invoke it (here myenumlist), : colon and now hax.iterator-specific configuration:prefix — (empty by default) the output to produce once immediately prior to enumerationsuffix — (empty by default) the output to produce once immediately following enumerationjoinVia — (, by default) the output to produce in-between all enumerated itemscontent — the principal content output for each enumerated item {:i:} outputs an iteration index: 0 for the first enumerated item and afterwards
increments by 1 for each further item, regardless of its value or which ordering/filtering was active (ie. no gaps ever
between successive such increments). {:v:} outputs the current item in plain-text form as returned by the chosen
enumerator. {:n:} outputs the equivalent to {:i:} + 1. {:l:} outputs the total number ("length of list") of all items being
currently enumerated.content is empty (the default), this is equivalent to it being {:v:}.content does not contain any of these 2 placeholders, it will obviously be output repeatedly, identically,
once per item.For example, given the above example |X| declaration directive:
{X|myenumlist: BlokNames |}
to output (displayed here with added line-wraps for readability)
<ul class="my-blogs">
<li><a id="b_link_0" href="/basics/index.html"> Basics </a></li>
<li><a id="b_link_1" href="/tags/index.html"> haXtags </a></li>
<li><a id="b_link_2" href="/xtypes/index.html"> X-renderers </a></li>
</ul>
BlokNames is one of a handful of built-in enumerators — full list below. But for now,
continuing this first exploration, to apply a sort order to the very same enumerator, prepend a so-called modifier:
{X|myenumlist: But(Ordered Descending) BlokNames |}, this will instead output:
<ul class="my-blogs">
<li><a id="b_link_0" href="/xtypes/index.html"> X-renderers </a></li>
<li><a id="b_link_1" href="/tags/index.html"> haXtags </a></li>
<li><a id="b_link_2" href="/basics/index.html"> Basics </a></li>
</ul>
Here, the But clause allows expressing the Ordered modifier, one of a handful of
built-in such modifiers. Another is LimitTo for applying a limit
{X|myenumlist: But(LimitTo 2) BlokNames |} to output:
<ul class="my-blogs">
<li><a id="b_link_0" href="/basics/index.html"> Basics </a></li>
<li><a id="b_link_1" href="/tags/index.html"> haXtags </a></li>
</ul>
Or applying that limit after sorting
{X|myenumlist: But(LimitTo 2) (But(Ordered Descending) BlokNames )|} to output:
<ul class="my-blogs">
<li><a id="b_link_0" href="/xtypes/index.html"> X-renderers </a></li>
<li><a id="b_link_1" href="/tags/index.html"> haXtags </a></li>
</ul>
By now, this is starting to become unwieldy: multiple such nested Buts can be somewhat verbose and keeping track of
correct parenthesis placement easily error-prone, plus their right-to-left flow (ie. above: first-sort-then-limit logic written as
first the limit part, then the sort part) possibly counterintuitive for non-programmers. The (functionally
equivalent But alternative, the) With clause avoids such nesting-via-parens and flips that right-to-left flow over.
So the same output as above can be achieved with a much simpler notation:
{X|myenumlist: With BlokNames [Ordered Descending , LimitTo 2] |} — ie. "with the
enumerated values, but ordered this way: give us the first 2":
<ul class="my-blogs">
<li><a id="b_link_0" href="/xtypes/index.html"> X-renderers </a></li>
<li><a id="b_link_1" href="/tags/index.html"> haXtags </a></li>
</ul>
Range startnum endnum
— a range of numbers,{X|myenum: Range 2 7 |}
gives: 2, 3, 4, 5, 6, 7Values [..]
— a given list of text values,{X|myenum: Values ["Hudak", "Wadler", "Peyton-Jones", "Bird", "Okasaki"] |}
gives: Hudak, Wadler, Peyton-Jones, Bird, OkasakiBlokNames
— names of all Bloks defined in the project,{X|myenum: BlokNames |}
gives: basics, tags, xtypesFeedNames blokstoo?
— names of all "feeds" known in the project, including or excluding the above BlokNames
{X|myenum: FeedNames True |}
gives: xdesc, basics, tags, xtypes{X|myenum: FeedNames False |}
gives: xdescFeedPosts and FeedValues — a bit more involved:In addition to the simpler enumerators outlined above, FeedValues and FeedPosts enumerate items derived on the fly
from the project's Blok pages (if any) and/or the project's "feed-posts" (if any). These 2
enumerators have quite a few commonalities:
FeedPosts <filter> [] andFeedValues <filter> "<fieldname>"All (no filtering, anything goes), or the functionally exactly
equivalent Some{ feeds=[], cats=[], dates=AnyDate } (also no filtering), or the same syntax-sensitive form but
with some or all of these 3 properties set: [] means "all of them")categories [] means "all of them")AnyDate to indicate "from any date" or
Between "from" "up-until" with both text values of course encoding dates in the well-known,
machine-friendly format "YYYY-MM-DD"In the current version, a known issue: in a project with Blok pages, using in
Blok pages either All or any Some that effectively selects any Bloks as feeds is "not currently supported"
(ie. expect incorrect, inconsistent or missing results). All other pages are OK for such uses, however, as are all
auto-generated Blok 'index' pages (if any). To be rectified in a future release — still, the functionality as-is
is valuable enough for the already-working-today use cases.
In this site, {X|myenum: FeedValues All "cat" |} produces some peculiar outputs:
demoSimplest, demoCfgArgs, hax.miniTag, hax.htmlImage, hax.htmlLink, hax.htmlLinks, hax.htmlAnchors, hax.xmlEscape, hax.dtFormat, hax.unMarkup, hax.noOp, hax.snippet, hax.iterator, hax.feedView, —that final comma baffles, for one— here's how and why:
All uses as input feeds essentially what the described-earlier FeedNames True enumerator
outputs: xdesc, basics, tags, xtypes — in this site there are 3 Bloks defined and 1
"feed" (named xdesc, in the bottom ~80-90 lines of
default.haxproj).xdesc all have (perhaps somewhat-unusually-so) each a unique
categoryhax.* but that's simply due to the content semantics of this site:
documenting HaXtatic) — Blok pages however don't have such categoriesFeedValues in particular doesn't output duplicate values (only 1
faux-cat was output from a few dozen Blok "posts") — making FeedValues the appropriate choice for grouping
for example actual posts together in individual (to be dynamically assembled from such unique-value outputs) sub-ordinate
hax.iterators.So much for All, now to demonstrate Some more examples:
{X|myenum: FeedValues Some{ feeds=[],cats=[],dates=AnyDate } "dt:year"|}
— as mentioned, such a Some is identical to All, but here instead of a post's cat, its date's year
→ 1234, 2016{X|myenum: FeedValues Some{ feeds=["xdesc"],cats=[],dates=AnyDate } "dt:year"|}
→ 1234{X|myenum: FeedValues Some{ feeds=["xdesc"],cats=[],dates=AnyDate } "cat" |}
— as we saw, xdesc has 11 "posts" but each has a uniquely distinct cat:
→ demoSimplest, demoCfgArgs, hax.miniTag, hax.htmlImage, hax.htmlLink, hax.htmlLinks, hax.htmlAnchors, hax.xmlEscape, hax.dtFormat, hax.unMarkup, hax.noOp, hax.snippet, hax.iterator, hax.feedView{X|myenum: FeedValues Some{ feeds=["xdesc"],cats=[],dates=AnyDate } "link"|}
— however, most of them share the same (empty, hence the below extra comma) link:
→ http://github.com/metaleap/haxtatic/blob/master/src/X/DemoSimplest.hs, http://github.com/metaleap/haxtatic/blob/master/src/X/DemoCfgArgs.hs,{X|myenum: FeedValues Some{ feeds=["xdesc"],cats=[],dates=Between "1234-11-" "1234-12-31" } "dt"|}
— filtering by date range:
→ 1234-12-15, 1234-11-15{X|myenum: FeedValues Some{ feeds=["xdesc"],cats=[],dates=Between "1234-11-" "1234-12-31"} "cfgmore"|}
— but both these results from that date-range filter share the same cfgmore (custom more field) value:
→ (no other settings)So the above outlines exhaustively how FeedValues operates, hoes does FeedPosts differ?
FeedValues enumerated unique single-field values for all "posts" selected,FeedPosts the entire (if passing the filter) post (all its field values) is output.Ordered modifier overrides this order.For this, clearly FeedPosts shouldn't just dictate some particular output formatting or other for such data records! Instead,
all that it outputs for each item is a syntactic notation of vars to then be fed directly into an outer hax.snippet. So
just a moderate grasp of snippets and how to populate their vars when invoking them via X-tags, plus
the above joinVia/content directive properties (plus possibly the below WrapEachIn
modifier) clears the path to infinitely versatile micro-content rendering.
To give an impression of this in practice, here's just the output produced when selecting:
{X|myenum: FeedPosts Some{ feeds=["xdesc"], cats=["hax.snippet"], dates=AnyDate} ["cfgmore"] |} — ie. selecting from this site's xdesc "feed" just the "post" describing hax.snippet with not-only all standard
fields (more below) but-also the custom more field cfgmore:
("cfgmore","<code>vars</code>, <code>content</code>"),("feed","xdesc"),("dt","1234-06-05"),("dt:year","1234"),("cat","hax.snippet"),("title",""),("link",""),("content","Renders the named \"snippet\" (aka. \"controls\" / \"components\" / \"sub-templates\") substituting the specified\r\n\tnamed-parameter values.")
A simple list of name-value-pair tuples — just without the enclosing [] square brackets that are
not to be forgotten when ensuring the wrapping of these per-item outputs inside what will typically (effectively have to) end up amounting
to both {X|mysnippet: vars=[ and ], content=> |}.
"That sounds more complicated than necessary, wouldn't it be nicer if one could specify just-the-name of any
snippet and FeedPosts then invoked it directly, instead of outputting syntax to then wrap other syntax
around?" Certainly true, but this would lose the flexibility to include further additional vars (or even content=>, or
future parameters) with the snippet's X-tag. Maybe such a shortcut will appear in a future release.
In addition to the specified haxproj custom more fields, the following standard fields are always returned (even
if empty) as de-facto vars by FeedPosts, and also all understood by FeedValues:
feed — the post's "feed" name or Blok namedt — post date in the standard format YYYY-MM-DDdt:year — post date's year only (eg. for grouping with FeedValues)cat — for Blok "posts": empty — otherwise: as set for the posttitle — for Blok "posts": detected from <h1> like {P|title|} —
otherwise: as set for the postlink — for Blok "posts": relative URI path to the page —
otherwise: as set for the postcontent — for Blok "posts": content of the first <p> if any —
otherwise: as set for the postSo enumerators are built-in routines that know how to iterate certain ranges, collections, lists, etc. Can their result sets be "tweaked"/mangled/sliced/diced/etc prior to the final output? This is achieved by adding to the 1 enumerator possible per hax.iterator X-tag any number of modifiers.
As explained above, any such modifiers can be expressed either one-per-But (which in turn can be nested),
or stated as an ordered sequence of multiple such modifiers per With clause.
(Technically, one could also specify a complete But clause (in parens) as the
enumerator in a With clause, or one could also specify a complete With clause (in parens) as the
enumerator in a But clause, but practically there's no good reason one should want to.)
Syntax: using With (enumerator) [modifier 1st , modifier 2nd , .. , modifier last], always wrap the
enumerator in parentheses and all modifiers together in 1 set of square brackets. Using But (only modifier)
(enumerator-or-another-But), always wrap the 1 modifier in parentheses and then subsequently the enumerator
too.
Limits the number of items:
{X|myenum: But (LimitTo 2) (FeedNames True) |}
produces xdesc, basics
instead of xdesc, basics, tags, xtypesSkips a number of items:
{X|myenum: With (Range 12 3) [Skip 4] |}
produces 8, 7, 6, 5, 4, 3
instead of 12, 11, 10, 9, 8, 7, 6, 5, 4, 3Encloses every item within a given prefix and suffix:
{X|myenum: But ( WrapEachIn ("/" , "/index.html") ) (BlokNames) |}
produces /basics/index.html, /tags/index.html, /xtypes/index.html
instead of basics, tags, xtypesRe-orders the items either Ascending or Descending or Shuffled
{X|myenum: With (FeedNames True) [Ordered Descending] |}
produces xtypes, xdesc, tags, basics
instead of xdesc, basics, tags, xtypes{X|myenum: But (Ordered Ascending) (Values ["zeta","phi","gamma","beta","alpha"]) |}
produces alpha, beta, gamma, phi, zeta
instead of zeta, phi, gamma, beta, alpha{X|myenum: With (Range 1 23) [Ordered (Shuffle False) , LimitTo 6, WrapEachIn ("#",". ")] |}
produces #23. , #22. , #21. , #20. , #18. , #17.
instead of 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23
(Shuffle True) or (Shuffle False) are valid. When used in a central project file such as a
*.haxproj, a template or a snippet (rather than directly inside a
content source file), Shuffle True shuffles differently for each output file while Shuffle False shuffles
identically for all output files during this processing run (but still varying with each processing run).{X|myenum: With (Values ["foo","bar"]) [Ordered None] |}
"produces" foo, bar
"instead of" foo, bar — ie. None does not touch the items at all: useless
perhaps, except for example when quickly and temporarily wanting to disable reordering somewhere inside some But nesting.As noted earlier, the FeedPosts enumerator already orders items returned (not alphabetically
but by post date), and always does so: defaulting to descending absent any Ordered placed to the contrary. So
Ordered Descending, Ordered None or no Ordered modifier whatsoever all result in identical outputs, while
Ordered Ascending shows "oldest first" and of course a Shuffle just randomizes the sort order as described above.
An X-tag of type hax.iterator defaults to Early but is delayed to Page stage
whenever:
Ordered (Shuffle True) modifier (see above)FeedValues or FeedPosts enumerator (see
above) selecting either All or Some that will effectively
include any such Bloks via its specified feeds property.