title: $:/core/macros/toc tags: $:/tags/Macro <!-- Naming rules / pattern - functions: tf.toc-variableName, "tf." -> function prefix reservered for TW, "toc-" -> global macro prefix, "variableName" - procedures eg: toc-procedureName, - macro parameters: path, itemTemplate - derived macro parameters: _path, _itemTemplate -> derived variables start with an underscore --> \whitespace trim \procedure toc-defaultItemTemplate() <span class="tc-toc-caption tc-tiny-gap-left" title={{!!tooltip}}> <$let tv-wikilinks="no"> <$transclude $tiddler={{{ [<itemTemplate>!is[blank]then<itemTemplate>else<currentTiddler>] }}} $field={{{ [<itemTemplate>!is[blank]then[text]] :else[<captionField>!is[blank]then<captionField>else[caption]] }}} > <$view field="title"/> </$transclude> </$let> </span> \end <!-- returns the title of a tiddler --> \function tf.toc-getItemTemplate() [<itemTemplate>!is[blank]then<itemTemplate>] :else[<currentTiddler>get[toc-itemTemplate]] <!-- Use macro itemTemplate or one defined as a toc-itemTemplate field --> \procedure _itemTemplate() <$transclude $tiddler=<<tf.toc-getItemTemplate>> > <<toc-defaultItemTemplate>> </$transclude> \end <!-- v5.2.4 add "Custom Icons" --> \procedure toc-open-icon() $:/core/images/down-arrow \procedure toc-closed-icon() $:/core/images/right-arrow \procedure toc-hideField() toc-hide \procedure toc-includeField() toc-include \procedure toc-filterField() toc-filter <!-- helper functions for li class definitions --> \function tf.toc-itemClassFilter() [<selectedTiddler>get[text]match<currentTiddler>then[toc-item-selected]else[toc-item]] \function tf.toc-includeClass() [subfilter<tf.toc-include>match<currentTiddler>then[toc-item-include]] \function tf.toc-filterClass() [subfilter<tf.toc-filter>match<currentTiddler>then[toc-item-filter]] \function tf.toc-hideClass() [<tf.toc-hide>!is[blank]then[toc-item-hide]] <!-- join the CSS definitions from above --> \function tf.toc-itemClass() [<tf.toc-itemClassFilter>] [<tf.toc-includeClass>] [<tf.toc-filterClass>] [<tf.toc-hideClass>] +[join[ ]] <!-- Special case, if toc-hide field is "yes", we need a currentTiddler *titlelist* -- otherwise return the content as text --> <!-- the following functions need to use <currentTiddler> --> \function tf.toc-getHideText() [<currentTiddler>get<toc-hideField>] \function tf.toc-hideIsYes() [<currentTiddler>format:titlelist[]] \function tf.toc-hide() [<tf.toc-getHideText>match[yes]then<tf.toc-hideIsYes>] :else[<tf.toc-getHideText>] <!-- Read tf.toc-include and tf.toc-filter from fields. Need to use <tag> --> \function tf.toc-include() [<tag>get<toc-includeField>] \function tf.toc-filter() [<tag>get<toc-filterField>] <!-- Define default filter strings for different usecases: tag (default), parentField and using tag-like field --> \procedure toc-filterDefault() [all[shadows+tiddlers]tag<tag>!has[draft.of]] \procedure toc-filterParent() [has<parentField>!has[draft.of]] :filter[get<parentField>match<tag>] \procedure toc-filterTagLike() [<tag>get<tagField>enlist-input[]!has[draft.of]] <!-- TODO tiddlers with parentField need caching --> <!-- activate the filterString depending on tagField, parentField or default. tagField takes precedence --> \function tf.toc-filterString() [<tagField>!is[blank]then<toc-filterTagLike>] :else[<parentField>!is[blank]then<toc-filterParent>else<toc-filterDefault>] <!-- define unique path based state title --> \function tf.toc-newPath() [<path>addsuffix[/]addsuffix<tag>] <!-- simple toc helper body --> \procedure toc-body(tag,sort:"",itemClassFilter,exclude,path) <!-- Be aware: if parentField is set, the "tag" parameter contains the currentTiddler --> <$set name=currentTiddler filter="[<parentField>!is[blank]then<tag>else<currentTiddler>]"> <ol class="tc-toc"> <!-- text substitution for "sort" parameter backwards compatibility --> <$list filter=` [subfilter<tf.toc-filter>] :else[subfilter<tf.toc-filterString>$(sort)$] [subfilter<tf.toc-include>] -[<tag>] -[subfilter<exclude>]`> <%if [<currentTiddler>] -[subfilter<tf.toc-hide>] %> <$let _path=<<tf.toc-newPath>> > <!-- adding tf.toc-hide, excludes blocked elements from all visible sub-nodes --> <$set name="_excluded" filter="[subfilter<exclude>] [<tag>] [subfilter<tf.toc-hide>]"> <li class=<<tf.toc-itemClass>>> <% if [all[current]toc-link[no]] %> <<_itemTemplate>> <% else %> <!-- v5.1.23 use target-field if present in tiddler --> <$link to={{{ [<currentTiddler>get[target]else<currentTiddler>] }}}> <<_itemTemplate>> </$link> <% endif %> <!-- toc-body only calls itself, so only modified variables have to be passed on. --> <!-- The rest can be reused from toc parameters --> <$macrocall $name="toc-body" tag=<<currentTiddler>> exclude=<<_excluded>> path=<<_path>> /> </li> </$set> </$let> <% endif %> </$list> </ol> </$set> \end <!-- --> <!-- <$log tag=<<tag>> parentField=<<parentField>> toc-filter=<<toc-filter>> ct=<<currentTiddler>> captionField=<<captionField>>/> --> <!-- --> <!-- ============================================================= Simple toc macro which shows the full tree This macro is _not_ used by other toc-macros v5.3.4 itemClassFilter has been replaced by tf.toc-itemClassFilter ================================================================== --> \procedure toc(tag,sort:"",itemClassFilter,exclude,captionField,tagField,parentField,itemTemplate) <$macrocall $name="toc-body" tag=<<tag>> sort=<<sort>> exclude=<<exclude>>/> \end \procedure toc-tagLikeChildFilter() [<currentTiddler>get<tagField>enlist-input[]] \procedure toc-parentChildFilter() [has<parentField>] :filter[get<parentField>match<..currentTiddler>] \procedure toc-tagChildFilter() [tag<currentTiddler>] <!-- this function uses the variables NOT the tiddler fields --> \function tf.toc-hasChildren() [<tagField>!is[blank]then<toc-tagLikeChildFilter>] :else[<parentField>!is[blank]then<toc-parentChildFilter>else<toc-tagChildFilter>] \procedure toc-openBranch(path,currentTiddler,manual:"no") \procedure recursiveOpen(exclude, path) <!-- tf-toc-stateTitle needs the path variable! --> <$let path={{{ [<path>] "/" [<currentTiddler>] +[join[]] }}}> <$list filter="[subfilter<tf.toc-hasChildren>] [subfilter<tf.toc-curTidInclude>] -[<currentTiddler>] -[subfilter<exclude>]" > <% if [subfilter<tf.toc-hasChildren>] %> <$set name="_excluded" filter="[subfilter<exclude>] [<currentTiddler>]"> <!-- tf-toc-stateTitle needs the path variable! --> <$qualify name="toc-state" title=<<tf.toc-stateTitle>> > <$action-setfield $tiddler=<<toc-state>> text="open"/> <$macrocall $name="recursiveOpen" exclude=<<_excluded>> path=<<path>> /> </$qualify> </$set> <% endif %> </$list> </$let> \end recursiveOpen <% if [<manual>match[yes]] %> <$qualify name="toc-state" title=<<tf.toc-stateTitle>> > <$action-setfield $tiddler=<<toc-state>> text="open"/> <$macrocall $name="recursiveOpen" exclude=<<exclude>> path=<<path>> /> </$qualify> <% elseif [<modifier>match[ctrl]] %> <$macrocall $name="recursiveOpen" exclude=<<exclude>> path=<<path>> /> <% endif %> \end <!-- <$action-log/> --> <!-- <$action-log ct=<<currentTiddler>> hasChildren=<<tf.toc-hasChildren>> path=<<path>> exclude=<<exclude>>/> --> <!-- <$action-log toc-state=<<toc-state>> path=<<path>> exclude=<<exclude>> ct=<<currentTiddler>> /> --> <!-- <$action-log ct=<<currentTiddler>> prefix=<<prefix>> toc-state=<<toc-state>>/> --> \procedure toc-closeBranch(path,currentTiddler,manual:"no") <% if [<modifier>match[ctrl]] :else[<manual>match[yes]] %> <$let prefix={{{ [<tf.toc-stateTitle>] }}} > <$action-deletetiddler $filter="[prefix<prefix>]"/> </$let> <% endif %> \end <!-- If a toc-item shows a link. Clicking the caption will open the tiddler If toc-item is linked, the _itemTemplate is managed in the parent procedure If a toc-item should not show a link, the _itemTemplate is part of the button. So it can be clicked to open / close one branch The buttons also call toc-stateOpen and toc-stateClose, which by default allow us to CTRL-click to expand / fold the whole branch --> \procedure toc-item(isUnlinked:"") <% if [<toc-state>get[text]else[close]match[close]] %> <$button actions=<<toc-openBranch>> setTitle=<<toc-state>> setTo="open" class="tc-btn-invisible" tooltip=<<toc-state>>> <$transclude tiddler=<<toc-closed-icon>> /> <% if [<isUnlinked>match[yes]] %> <<_itemTemplate>> <% endif %> </$button> <% elseif [<toc-state>get[text]match[open]] %> <$button actions=<<toc-closeBranch>> setTitle=<<toc-state>> setTo="close" class="tc-btn-invisible" tooltip=<<toc-state>>> <$transclude tiddler=<<toc-open-icon>> /> <% if [<isUnlinked>match[yes]] %> <<_itemTemplate>> <% endif %> </$button> <% endif %> \end \function tf.toc-stateTitle() [[$:/state/toc]] [<path>] "/" [<currentTiddler>] +[join[]] \procedure toc-linked-expandable-body(tag,sort:"",itemClassFilter,exclude,path,captionField,tagField,parentField,itemTemplate) <$qualify name="toc-state" title=<<tf.toc-stateTitle>> > <li class=<<tf.toc-itemClass>>> <!-- v5.1.23 use target-field if present in tiddler --> <$link to={{{ [<currentTiddler>get[target]else<currentTiddler>] }}}> <<toc-item>> <<_itemTemplate>> </$link> <!-- TODO auto expand --> <% if [<toc-state>get[text]match[open]] %> <$macrocall $name="toc-expandable" tag=<<currentTiddler>> sort=<<sort>> exclude=<<exclude>> path=<<path>> captionField=<<captionField>> tagField=<<tagField>> parentField=<<parentField>> itemTemplate=<<itemTemplate>> /> <% endif %> </li> </$qualify> \end \procedure toc-unlinked-expandable-body(tag,sort:"",itemClassFilter,exclude,path,captionField,tagField,parentField,itemTemplate) <$qualify name="toc-state" title=<<tf.toc-stateTitle>>> <li class=<<tf.toc-itemClass>>> <<toc-item isUnlinked:"yes">> <!-- TODO auto expand --> <% if [<toc-state>get[text]match[open]] %> <$macrocall $name="toc-expandable" tag=<<currentTiddler>> sort=<<sort>> exclude=<<exclude>> path=<<path>> captionField=<<captionField>> tagField=<<tagField>> parentField=<<parentField>> itemTemplate=<<itemTemplate>> /> <% endif %> </li> </$qualify> \end <!-- ========================================================== Shows an expandable toc. Item always have an open/close chevron =============================================================== --> \procedure toc-expandable(tag,sort:"",itemClassFilter:"",exclude,path,captionField,tagField,parentField,itemTemplate) <$set name=currentTiddler filter="[<parentField>!is[blank]then<tag>else<currentTiddler>]"> <ol class="tc-toc toc-expandable"> <!-- text substitution is needed for backwards compatibility --> <$list filter=` [subfilter<tf.toc-filter>] :else[subfilter<tf.toc-filterString>$(sort)$] [subfilter<tf.toc-include>] -[<tag>] -[subfilter<exclude>]`> <%if [<currentTiddler>] -[subfilter<tf.toc-hide>] %> <$let _path=<<tf.toc-newPath>>> <$set name="_excluded" filter="[subfilter<exclude>] [<tag>] [subfilter<tf.toc-hide>]"> <% if [all[current]toc-link[no]] %> <$macrocall $name="toc-unlinked-expandable-body" tag=<<tag>> sort=<<sort>> exclude=<<_excluded>> path=<<_path>> captionField=<<captionField>> tagField=<<tagField>> parentField=<<parentField>> itemTemplate=<<itemTemplate>> /> <% else %> <$macrocall $name="toc-linked-expandable-body" tag=<<tag>> sort=<<sort>> exclude=<<_excluded>> path=<<_path>> captionField=<<captionField>> tagField=<<tagField>> parentField=<<parentField>> itemTemplate=<<itemTemplate>> /> <% endif %> </$set> </$let> <% endif %> </$list> </ol> </$set> \end \function tf.toc-curTidInclude() [<currentTiddler>get<toc-includeField>] \procedure toc-linked-selective-expandable-body(tag,sort:"",itemClassFilter,exclude,path,captionField,tagField,parentField,itemTemplate) <$qualify name="toc-state" title=<<tf.toc-stateTitle>>> <li class=<<tf.toc-itemClass>>> <!-- v5.1.23 use target-field if present in tiddler --> <$link to={{{ [<currentTiddler>get[target]else<currentTiddler>] }}}> <!-- The subfilter<exclude> needs to be the last filter run --> <% if [subfilter<tf.toc-hasChildren>] [subfilter<tf.toc-curTidInclude>] -[<currentTiddler>] -[subfilter<exclude>] +[limit[1]] %> <<toc-item>> <% else %> <$button class='tc-btn-invisible'> {{$:/core/images/blank}} </$button> <% endif %> <<_itemTemplate>> </$link> <!-- TODO auto expand --> <% if [<toc-state>get[text]match[open]] %> <$macrocall $name="toc-selective-expandable" tag=<<currentTiddler>> sort=<<sort>> exclude=<<exclude>> path=<<path>> captionField=<<captionField>> tagField=<<tagField>> parentField=<<parentField>> itemTemplate=<<itemTemplate>> /> <% endif %> </li> </$qualify> \end <!-- <$log ct=<<currentTiddler>> includeList={{{ [subfilter<tf.toc-hasChildren>] [subfilter<tf.toc-curTidInclude>] -[subfilter<exclude>] +[limit[1]] }}} hasChildren={{{ [subfilter<tf.toc-hasChildren>] }}} path=<<path>> exclude=<<exclude>>/> --> \procedure toc-unlinked-selective-expandable-body(tag,sort:"",itemClassFilter,exclude,path,captionField,tagField,parentField,itemTemplate) <$qualify name="toc-state" title=<<tf.toc-stateTitle>> > <li class=<<tf.toc-itemClass>>> <% if [subfilter<tf.toc-hasChildren>] [subfilter<tf.toc-curTidInclude>] -[<currentTiddler>] -[subfilter<exclude>] +[limit[1]] %> <<toc-item isUnlinked:"yes">> <% else %> <$button class="tc-btn-invisible"> {{$:/core/images/blank}} </$button> <span class="toc-item-muted"> <<_itemTemplate>> </span> <% endif %> <!-- TODO auto expand --> <% if [<toc-state>get[text]match[open]] %> <$macrocall $name="toc-selective-expandable" tag=<<currentTiddler>> sort=<<sort>> exclude=<<exclude>> path=<<path> captionField=<<captionField>> tagField=<<tagField>> parentField=<<parentField>> itemTemplate=<<itemTemplate>> /> <% endif %> </li> </$qualify> \end <!-- ===================================================== Shows a selctive expandable toc. If an item has no children, there is no open/close chevron ========================================================== --> \procedure toc-selective-expandable(tag,sort:"",itemClassFilter,exclude,path,captionField,tagField,parentField,itemTemplate) <$set name=currentTiddler filter="[<parentField>!is[blank]then<tag>else<currentTiddler>]"> <ol class="tc-toc toc-selective-expandable"> <!-- text substitution is needed for backwards compatibility --> <$list filter=` [subfilter<tf.toc-filter>] :else[subfilter<tf.toc-filterString>$(sort)$] [subfilter<tf.toc-include>] -[<tag>] -[subfilter<exclude>]`> <%if [<currentTiddler>] -[subfilter<tf.toc-hide>] %> <$let _path=<<tf.toc-newPath>>> <$set name="_excluded" filter="[subfilter<exclude>] [<tag>] [subfilter<tf.toc-hide>]"> <% if [all[current]toc-link[no]] %> <$macrocall $name="toc-unlinked-selective-expandable-body" tag=<<tag>> sort=<<sort>> exclude=<<_excluded>> path=<<_path>> captionField=<<captionField>> tagField=<<tagField>> parentField=<<parentField>> itemTemplate=<<itemTemplate>> /> <% else %> <$macrocall $name="toc-linked-selective-expandable-body" tag=<<tag>> sort=<<sort>> exclude=<<_excluded>> path=<<_path>> captionField=<<captionField>> tagField=<<tagField>> parentField=<<parentField>> itemTemplate=<<itemTemplate>> /> <% endif %> </$set> </$let> <% endif %> </$list> </ol> </$set> \end <!-- ============================================================== Shows a tabbed toc. If a toc-item link is clicked it will open the tiddler in the story =================================================================== --> \procedure toc-tabbed-external-nav(tag,sort:"",selectedTiddler:"$:/temp/toc/selectedTiddler",unselectedText,missingText,template:"",exclude,captionField,tagField,parentField,itemTemplate) <$tiddler tiddler={{{ [<selectedTiddler>get[text]] }}}> <div class="tc-tabbed-table-of-contents"> <$linkcatcher to=<<selectedTiddler>>> <div class="tc-table-of-contents"> <!-- v5.3.4 itemClassFilter has been replaced by tf.toc-itemClassFilter --> <$macrocall $name="toc-selective-expandable" tag=<<tag>> sort=<<sort>> exclude=<<exclude>> captionField=<<captionField>> tagField=<<tagField>> parentField=<<parentField>> itemTemplate=<<itemTemplate>> /> </div> </$linkcatcher> <div class="tc-tabbed-table-of-contents-content"> <$reveal stateTitle=<<selectedTiddler>> type="nomatch" text=""> <$transclude mode="block" tiddler=<<template>>> <h1><<_itemTemplate>></h1> <$transclude mode="block">$missingText$</$transclude> </$transclude> </$reveal> <$reveal stateTitle=<<selectedTiddler>> type="match" text=""> <<unselectedText>> </$reveal> </div> </div> </$tiddler> \end <!-- ======================================================== Shows a tabbed toc. If a toc-item link is clicked it will open the tiddler in the view area of the same tiddler ============================================================= --> \procedure toc-tabbed-internal-nav(tag,sort:"",selectedTiddler:"$:/temp/toc/selectedTiddler",unselectedText,missingText,template:"",exclude,captionField,tagField,parentField,itemTemplate) <$linkcatcher to=<<selectedTiddler>>> <$macrocall $name="toc-tabbed-external-nav" tag=<<tag>> sort=<<sort>> selectedTiddler=<<selectedTiddler>> unselectedText=<<unselectedText>> missingText=<<missingText>> template=<<template>> exclude=<<exclude>> captionField=<<captionField>> tagField=<<tagField>> parentField=<<parentField>> itemTemplate=<<itemTemplate>> /> </$linkcatcher> \end