%D \module %D [ file=strc-ref, %D version=2008.10.20, %D title=\CONTEXT\ Structure Macros, %D subtitle=Cross Referencing, %D author=Hans Hagen, %D date=\currentdate, %D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. % todo: (1) configure references, (2) rendering => with presets % % \defineconversionset[default][Character,number,Romannumerals,Character][number] % \defineseparatorset [default][.,.,--][.] % \setuphead[subsection][sectionstopper=),sectionsegments=4:4] % \setupreferencestructureprefix[default][prefixsegments=2:4] % \setupreferencestructureprefix[figure][default][prefixsegments=3:4] % \chapter {One} % \section {One} % \subsection[sec:test]{Two} % See \in[sec:test] and \in[fig:xx] and \in[fig:yy] % \placefigure[here][fig:xx]{}{} % \placefigure[here][fig:yy]{}{} \writestatus{loading}{ConTeXt Structure Macros / Cross Referencing} \registerctxluafile{strc-rsc}{} \registerctxluafile{strc-ref}{} \registerctxluafile{node-ref}{optimize} \unprotect % todo : unknown/illegal reference no arg % todo : +n pages check on 'samepage' (contrastcolor) % todo : multiple text in reference % Makes more sense to build action data first, especially now % openaction etc are supported. % % \definespecial\doexecuteactionchain w h % \definespecial\dosetgotolocation % \definespecial\dosetexecuteJScode % ... %D This module deals with referencing. In \CONTEXT\ referencing is one of the core %D features, although at a first glance probably nobody will notice. This is good, %D because referencing should be as hidden as possible. %D %D Before we start implementing functionality we provide a way to set up this %D mechanism. %D %D \showsetup{setupreferencing} %D %D In interactive documents verbose references don't always make sense (what is a %D page number in an unnumbered document). By setting the \type{interaction} %D variable, one can influences the way interactive references are set. \let\referenceprefix\empty \installcorenamespace{referencing} \installdirectcommandhandler \??referencing {referencing} % \??referencing \newif\ifreferencing \referencingtrue \appendtoks \edef\p_state{\referencingparameter\c!state}% \ifx\p_state\v!start \referencingtrue \else \referencingfalse \fi \to \everysetupreferencing %D In paper documents, referencing comes down to cross referencing, but in %D their interactive counterparts, is also involves navigation. Many features %D implemented here are therefore closely related to navigation. %D %D Many \CONTEXT\ commands can optionally be fed with a reference. Such a %D reference, when called upon, returns the number of a figure, table, chapter %D etc, a piece of text, or a pagenumber. %D %D There are three ways of defining a reference: %D %D \starttyping %D \pagereference[here] %D \textreference[here]{some text} %D \stoptyping %D %D the third alternative combines them in: %D %D \starttyping %D \reference[here]{some text} %D \stoptyping \unexpanded\def\textreference {\dosingleargument\strc_references_text_reference} % no need for \dosingle \unexpanded\def\pagereference {\dosingleargument\strc_references_page_reference} % as they're mandate and \unexpanded\def\reference {\dosingleargument\strc_references_full_reference} % never forgotten \unexpanded\def\setreference {\dodoubleargument\strc_references_set_reference } % % maybe: \let\reference\textreference \unexpanded\def\showreferences {\enabletrackers[nodes.references.show,nodes.destinations.show]} %D These are implemented in a low level form as: \unexpanded\def\strc_references_text_reference [#labels]{\strc_references_set_named_reference\s!text{#labels}{}} \unexpanded\def\strc_references_page_reference [#labels]{\strc_references_set_named_reference\s!page{#labels}{}{}} \unexpanded\def\strc_references_full_reference [#labels]{\strc_references_set_named_reference\s!full{#labels}{}} \unexpanded\def\strc_references_set_reference[#labels][#settings]{\strc_references_set_named_reference\s!user{#labels}{#settings}{}} \unexpanded\def\dosetdirectpagereference#1{\strc_references_set_named_reference\s!page{#1}{}{}} % low level, maybe use _ \unexpanded\def\usereferenceparameter#1% faster local variant {\edef\m_strc_references_asked{#1\c!reference}% \ifx\m_strc_references_asked\empty\else \dosetdirectpagereference\m_strc_references_asked \fi} %D Actually there is not much difference between a text and a full reference, but %D it's the concept that counts. The low level implementation is: \newcount\lastreferenceattribute \newcount\lastdestinationattribute \def\strc_references_finish#prefix#reference#internal% {\normalexpanded{\clf_deferredenhancereference{#prefix}{#reference}}} \let\dofinishreference\strc_references_finish % used at lua end %D This is somewhat tricky: we want to keep the reference with the following word but %D that word should also hyphenate. We need to find a better way. % 0 = nothing % 1 = bind to following word \setnewconstant\c_strc_references_bind_state\plusone \def\strc_references_inject_before {} \def\strc_references_inject_after {\ifcase\c_strc_references_bind_state % nothing \or \prewordbreak % to be tested: \removeunwantedspaces\permithyphenation \fi} \unexpanded\def\strc_references_set_named_reference {\ifreferencing \expandafter\strc_references_set_named_reference_indeed \else \expandafter\gobblefourarguments \fi} \newbox\b_strc_destination_nodes \unexpanded\def\strc_references_flush_destination_nodes {\ifvoid\b_strc_destination_nodes \else \unhbox\b_strc_destination_nodes \fi} \def\strc_references_placeholder {\ifx\dotaggedplaceholder\empty\else \attribute\destinationattribute\lastdestinationattribute \dotaggedplaceholder \fi} \unexpanded\def\strc_references_destination_point_yes {\strc_references_inject_before % new \dostarttagged\t!reference\empty \dontleavehmode\hbox attr \destinationattribute\lastdestinationattribute\bgroup \strc_references_flush_destination_nodes \strc_references_placeholder \egroup \dostoptagged \strc_references_inject_after} \unexpanded\def\strc_references_destination_point_nop {\strc_references_inject_before % new \dostarttagged\t!reference\empty \dontleavehmode\hbox \bgroup \strc_references_flush_destination_nodes \strc_references_placeholder \egroup \dostoptagged \strc_references_inject_after} \unexpanded\def\strc_references_start_destination_nodes % messy but we need the delay {\setbox\b_strc_destination_nodes\hbox\bgroup} % also sets lastdestinationattribute \unexpanded\def\strc_references_stop_destination_nodes {\normalexpanded{\egroup\lastdestinationattribute\the\lastdestinationattribute\relax}} \unexpanded\def\strc_references_set_named_reference_indeed#kind#labels#userdata#text% labels userdata text -> todo: userdata {\ifreferencing % we could have a more efficient one for page references but for the moment % we don't care too much \edef\currentreferencekind {#kind}% \edef\currentreferencelabels {#labels}% \edef\currentreferenceuserdata {#userdata}% \edef\currentreferenceexpansion{\referencingparameter\c!expansion}% {\referenceparameter\c!expansion} \ifx\currentreferencelabels\empty \lastdestinationattribute\attributeunsetvalue \else \ifx\currentreferenceexpansion\s!xml \xmlstartraw \xdef\currentreferencedata{#text}% data, no text else conflict \xmlstopraw \glet\currentreferencecoding\s!xml \else \ifx\currentreferenceexpansion\v!yes \xdef\currentreferencedata{#text}% \else \xdef\currentreferencedata{\detokenize{#text}}% \fi \glet\currentreferencecoding\s!tex \fi % beware, the structures.references.set writes a \setnextinternalreference \strc_references_start_destination_nodes \clf_setdestinationattribute {% references {% internal \locationcount % block {\currentsectionblock}% view {\interactionparameter\c!focus}% \ifx\referenceprefix\empty\else prefix {\referenceprefix}% \fi reference {\currentreferencelabels}% }% metadata {% kind {\currentreferencekind}% \ifx\currentreferencekind\s!page\else \ifx\currentreferencecoding\s!xml xmlroot {\xmldocument}% \fi catcodes \catcodetable \fi }% \ifx\currentreferencedata\empty\else entries {% text {\currentreferencedata}% }% \fi \ifx\currentreferenceuserdata\empty\else userdata {\detokenize{#userdata}}% \fi }% \relax \strc_references_stop_destination_nodes \fi \else \setbox\b_strc_destination_nodes\emptyhbox \lastdestinationattribute\attributeunsetvalue \fi % will become obsolete: \xdef\currentdestinationattribute{\number\lastdestinationattribute}% % will become an option: \ifnum\lastdestinationattribute>\zerocount \strc_references_destination_point_yes \else\ifvoid\b_strc_destination_nodes\else \strc_references_destination_point_nop \fi\fi} \def\strc_references_set_page_only_destination_attribute#labels% could in fact be fully expandable {\ifreferencing \edef\currentreferencelabels{#labels}% \ifx\currentreferencelabels\empty \setbox\b_strc_destination_nodes\emptyhbox \lastdestinationattribute\attributeunsetvalue \else \strc_references_start_destination_nodes \setnextinternalreference \clf_setdestinationattribute {% references {% internal \locationcount % block {\currentsectionblock}% view {\interactionparameter\c!focus}% \ifx\referenceprefix\empty\else prefix {\referenceprefix}% \fi reference {\currentreferencelabels}% }% metadata {% kind {page}% }% }% \relax \strc_references_stop_destination_nodes \fi \else \setbox\b_strc_destination_nodes\emptyhbox \lastdestinationattribute\attributeunsetvalue \fi} \unexpanded\def\strc_references_direct_full_user#user#labels#text% {\ifreferencing \strc_references_start_destination_nodes \setnextinternalreference \edef\m_strc_references_user{#user}% \edef\m_strc_references_text{#text}% \clf_setdestinationattribute {% references {% internal \locationcount % block {\currentsectionblock}% view {\interactionparameter\c!focus}% \ifx\referenceprefix\empty\else prefix {\referenceprefix}% \fi reference {#labels}% }% metadata {% kind {\s!full}% }% \ifx\m_strc_references_text\empty \else entries {% text {\m_strc_references_text}% }% \fi \ifx\m_strc_references_user\empty \else userdata {\m_strc_references_user}% \detokenize\expandafter{\normalexpanded{...}} \fi }% \relax \strc_references_stop_destination_nodes \else \setbox\b_strc_destination_nodes\emptyhbox \lastdestinationattribute\attributeunsetvalue \fi % will become obsolete: \xdef\currentdestinationattribute{\number\lastdestinationattribute}% % will become an option: \ifnum\lastdestinationattribute>\zerocount \strc_references_destination_point_yes \else\ifvoid\b_strc_destination_nodes\else \strc_references_destination_point_nop \fi\fi} \unexpanded\def\strc_references_direct_full {\strc_references_direct_full_user\empty} \let\dodirectfullreference\strc_references_direct_full % for at lua end (no longer) \def\strc_references_set_page_only_destination_box_attribute#cs#labels% {\strc_references_set_page_only_destination_attribute{#labels}% \ifnum\lastdestinationattribute>\zerocount \edef#cs{attr \destinationattribute\number\lastdestinationattribute}% \else \let#cs\empty \fi} %D It's about time to clean up references .. stable enough now. \unexpanded\def\boxreference[#1]% {\begingroup \dowithnextbox {\strc_references_set_page_only_destination_attribute{#1}% \hpack % \hbox \ifnum\lastdestinationattribute=\attributeunsetvalue\else attr \destinationattribute \lastdestinationattribute \fi {\box\b_strc_destination_nodes\box\nextbox}% \endgroup}} \unexpanded\def\hboxreference[#1]{\boxreference[#1]\hbox} \unexpanded\def\vboxreference[#1]{\boxreference[#1]\vbox} % \ifx\currentdestinationattribute\empty % \begingroup\attribute\destinationattribute\currentdestinationattribute\emptyhbox\endgroup % todo % \fi \def\defaultreferencepage#text{[[[#text]]]} \def\defaultreferencetext#text{[[[#text]]]} %D For internal usage: \def\strc_references_set_simple_reference#label% {\iflocation \strc_references_start_destination_nodes \setnextinternalreference \clf_setdestinationattribute {% references {% view {\interactionparameter\c!focus}% \ifx\referenceprefix\empty\else prefix {\referenceprefix}% \fi reference {#label}% internal \locationcount }% metadata {% kind {\s!page}% }% }% \relax \strc_references_stop_destination_nodes \xdef\currentdestinationattribute{\number\lastdestinationattribute}% \else \setbox\b_strc_destination_nodes\emptyhbox \xdef\currentdestinationattribute{\number\attributeunsetvalue}% \fi} \def\strc_references_set_simple_internal_reference#label% no prefix {\iflocation \strc_references_start_destination_nodes \setnextinternalreference \clf_setdestinationattribute {% references {% view {\interactionparameter\c!focus}% reference {#label}% internal \locationcount }% metadata {% kind {\s!page}% }% }% \relax \strc_references_stop_destination_nodes \xdef\currentdestinationattribute{\number\lastdestinationattribute}% \else \setbox\b_strc_destination_nodes\emptyhbox \xdef\currentdestinationattribute{\number\attributeunsetvalue}% \fi} \def\strc_references_get_simple_reference#label% {\iflocation \clf_injectreference {\referenceprefix}% {#label}% {% height \ht\strutbox depth \dp\strutbox \extrareferencearguments }% \relax \xdef\currentreferenceattribute{\number\lastreferenceattribute}% \else \xdef\currentreferenceattribute{\number\attributeunsetvalue}% \fi} %D \macros %D {contentreference} %D %D \starttyping %D \setupinteraction %D [state=start, %D focus=standard] %D %D \setupheader %D [state=stop] %D %D See page \goto{page 2}[page2] \page %D %D \contentreference %D [page2] %D [offset=1cm,toffset=2cm,frame=on] %D {\externalfigure[cow.pdf][factor=fit]} %D %D \stoptyping \unexpanded\def\contentreference {\hbox\bgroup \dodoubleempty\strc_references_content_pickup} \def\strc_references_content_pickup {\ifsecondargument \expandafter\strc_references_content_pickup_yes \else \expandafter\strc_references_content_pickup_nop \fi} \def\strc_references_content_pickup_yes[#1][#2]% {\dowithnextbox{\strc_references_content_yes_finish{#1}{#2}}\hbox} \def\strc_references_content_pickup_nop[#1][#2]% {\dowithnextbox{\strc_references_content_nop_finish{#1}{#2}}\hbox} \def\strc_references_content_yes_finish#1#2% {\scratchwidth \wd\nextbox \scratchheight\ht\nextbox \scratchdepth \dp\nextbox \setbox\nextbox\hpack {\framed[\c!frame=\v!off,#2]{\box\nextbox}}% \strc_references_set_simple_reference{#1}% \setbox\nextbox\hpack attr \destinationattribute \currentdestinationattribute % \hpack ? {\strc_references_flush_destination_nodes \box\nextbox}% \setbox\nextbox\hpack{\box\nextbox}% \wd\nextbox\scratchwidth \ht\nextbox\scratchheight \dp\nextbox\scratchdepth \box\nextbox \egroup} \def\strc_references_content_nop_finish#1#2% {\strc_references_set_simple_reference{#1}% \hpack attr \destinationattribute \currentdestinationattribute % \hpack ? {\strc_references_flush_destination_nodes \box\nextbox}% \egroup} %D \macros %D {everyreference} %D %D For rather tricky purposes, one can assign sanitizing macros to \type %D {\everyreference} (no longer that relevant). \newevery \everyreference \relax %D This is really needed, since for instance Polish has a different alphabet and %D needs accented entries in registers. \appendtoks \cleanupfeatures \to \everyreference %D We did not yet discuss prefixing. Especially in interactive documents, it's not %D always easy to keep track of duplicate references. The prefix mechanism, which we %D will describe later on, solves this problem. By (automatically) adding a prefix %D one keeps references local, but the global ones in view. To enable this feature, %D we explictly split the prefix from the reference. \let\referenceprefix\empty %D For a long time the only way to access an external file was to use the file %D prefix (\type {somefile::}. However, when you split up a document, redefining the %D references may be such a pain, that another approach is feasible. By setting the %D \type {autofile} variable to \type {yes} or \type {page}, you can access the %D reference directly. %D %D \starttabulate[||||] %D \NC filename::tag \NC page(filename::pnum) \NC tag \NC\NR %D \NC $\star$ \NC \NC \NC\NR %D \NC $\star$ \NC $\star$ \NC $\star$ \NC\NR %D \NC \NC $\star$ \NC \NC\NR %D \stoptabulate \unexpanded\def\usereferences[#filename]{} % obsolete %D As mentioned we will also use the cross reference mechanism for navigational %D purposes. The main reason for this is that we want to treat both categories %D alike: %D %D \starttyping %D \goto{go back}[PreviousJump] %D \goto{colofon}[colofon page] %D \stoptyping %D %D Here \type{PreviousJump} is handled by the viewer, while the %D \type{colofon page} reference is, apart from hyperlinking, a %D rather normal reference. %D %D We already saw that cross refences are written to and read from a file. The pure %D navigational ones don't need to be written to file, but both for fast processing %D and transparant integration, they are saved internally as a sort of reference. We %D can easily distinguish such system references from real cross reference ones by %D their tag. %D %D We also use the odd/even characteristic to determine the page state. \let\currentrealreference \empty \let\currentpagereference \empty \let\currenttextreference \empty \let\currentreferenceorder \empty \let\currentsubtextreference \empty \let\currentsubsubtextreference\empty \newcount\referencehastexstate % set in backend % referencepagestate: % % 0 = no page ref, 1=same page, 2=before, 3=after %D Cross references appear as numbers (figure~1.1, chapter~2) or pagenumbers %D (page~2, page 3--2), and are called with \type {\in} and \type {\at}. In %D interactive documents we also have \type {\goto}, \type {\button} and alike. %D These are more versatile and look like: %D %D \starttyping %D \goto[reference] %D \goto[outer reference::] %D \goto[outer reference::inner reference] %D \goto[operation(argument)] %D \goto[operation(action{argument,argument})] %D \goto[action] %D \goto[action{argument}] %D \stoptyping %D %D The first one is a normal reference, the second and third are references to a %D file or \URL. The brace delimited references for instance refer to a \JAVASCRIPT. %D The last example shows that we can pass arguments to the actions. %D %D Now we've come to the testing step. As we can see below, this macro does bit more %D than testing: it also resolves the reference. This means that whenever we test %D for the existance of a reference at an outer level, we have all the relevant %D properties of that reference avaliable inside the true branche~(\type {#2}). %D %D The prefix has to do with localizing references. When a prefix is set, looking %D for a reference comes to looking for the prefixed one, and when not found, %D looking for the non prefixed one. Consider for instance the prefix set to \type %D {sidetrack}. %D %D \starttyping %D \pagereference[important] %D \pagereference[unimportant] %D \setupreferencing[prefix=sidetrack] %D \pagereference[important] %D \stoptyping %D %D results in saving (writing) the references %D %D \starttyping %D ...{}{important} %D ...{}{unimportant} %D ...{sidetrack}{important}... %D \stoptyping %D %D Now when we call for \type{unimportant}, we will indeed get the pagenumber %D associated to this reference. But when we call for \type{important}, while the %D prefix is still set, we will get the pagenumber bound to the prefixed one. %D %D {\em Some day, when processing time and memory are no longer %D performance factors, we will introduce multi||level %D prefixes.} %D %D Before we start analyzing, I introduce a general definition macro. Consider: %D %D \starttyping %D \goto{do}[JS(My_Script{"test",123}),titlepage] %D \stoptyping %D %D This can also be achieved by: %D %D \starttyping %D \definereference[startup][JS(My_Script{"test",123}),titlepage] %D \goto{do}[startup] %D \stoptyping %D %D Now is this is a handy feature or not? %D %D \showsetup{definereference} %D %D We can trace references by setting the next switch to true. \unexpanded\def\definereference {\dodoubleempty\strc_references_define_reference} \def\strc_references_define_reference[#name][#specification]% {\clf_definereference{\referenceprefix}{#name}{\detokenize{#specification}}} \unexpanded\def\resetreference[#name]% {\clf_resetreference{\referenceprefix}{#name}} \def\setpagereference#name#specification% hm,. low level ? {\clf_definereference{}{#name}{\v!page(\detokenize{#specification}}} % is detokenize needed here? %D Chained references are defined as: %D %D \starttyping %D \goto{somewhere}[JS(somescript),nextpage,JS(anotherscript)] %D \stoptyping %D %D Actually supporting chains is up to the special driver. Here we only provide the %D hooks. %D \macros %D {highlighthyperlinks} %D %D The next switch can be used to make user hyperlinks are not highlighted when %D clicked on. \newconditional\highlighthyperlinks \settrue\highlighthyperlinks %D \macros %D {gotonewwindow} %D %D To make the {\em goto previous jump} feature more convenient when using more than %D one file, it makes sense to force the viewer to open a new window for each file %D opened. \newconditional\gotonewwindow \setfalse\gotonewwindow \def\expandtexincurrentreference % will happen in lua some time {\ifcase\referencehastexstate\else\clf_expandcurrentreference\fi} \def\expandreferenceoperation#tag#content{\clf_setreferenceoperation#tag{#content}} \def\expandreferencearguments#tag#content{\clf_setreferencearguments#tag{#content}} \def\doifelsereferencefound#label#yes#nop% {\clf_doifelsereference{\referenceprefix}{#label}{\extrareferencearguments}% {\expandtexincurrentreference #yes}% {#nop}} \let\doifreferencefoundelse \doifelsereferencefound %D The tester only splits the reference in components but does not look into them. %D The following macro does a preroll and determines for instance the current real %D reference pagenumber. The \type {\currentrealreference} macro does the same so %D unless one wants to use the pagestate the next macro seldom needs to be called. %D %D The inner case is simple. Only two cases have to be taken %D care of: %D %D \starttyping %D \goto{some text}[reference] %D \goto{some text}[prefix:reference] %D \stoptyping %D %D References to other files however are treated strict or tolerant, depending on %D their loading and availability: %D %D \starttyping %D \useexternaldocument[somefile][filename][a nice description] %D %D \goto{checked reference}[somefile::reference] %D \goto{unchecked reference}[somefile::] %D \goto{unchecked reference}[anotherfile::reference] %D \stoptyping %D %D An unknown reference is reported on the screen, in the log file and, when %D enabled, in the left margin of the text. \let\unknownreference\gobbleoneargument %D When a reference is not found, we typeset a placeholder (two glyphs are often %D enough to represent the reference text). \def\dummyreference{{\tttf ??}} \def\emptyreference{{\tttf !!}} %D To prevent repetitive messages concerning a reference being defined, we set such %D an unknown reference to an empty one after the first encounter. %D %D Apart from cross references supplied by the user, \CONTEXT\ generates cross %D references itself. Most of them are not saved as a reference, but stored with %D their source, for instance a list or an index entry. Such automatically %D generated, for the user invisible, references are called {\em internal %D references}. The user supplied ones are labeled as {\em external references}. %D %D A second important characteristic is that when we want to support different %D backends (viewers), we need to support named destinations as well as page %D numbers. I invite readers to take a glance at the special driver modules to %D understand the fine points of this. As a result we will deal with {\em locations} %D as well as {\em real page numbers}. We explictly call this pagenumber a real one, %D because it is independant of the page numbering scheme used in the document. %D %D One of the reasons for \CONTEXT\ being the first \TEX\ base macropackage to %D support sophisticated interactive \PDF\ files, lays in the mere fact that real %D page numbers are available in most two pass data, like references, list data and %D index entries. %D %D We will speak of \type {thisis...} when we are marking a location, and %D \type {goto...} when we point to such a location. The latter one can be seen as a %D hyperlink to the former one. In the next macros one we use constructs like: %D %D \starttyping %D \dostart... %D \dostop... %D \stoptyping %D %D The flag \type {\iflocation} signals if we're in interactive mode. \ifdefined\buttonheight \else \newdimen\buttonheight \fi \ifdefined\buttonwidth \else \newdimen\buttonwidth \fi %D Internal references can best be set using the next few macros. Setting such %D references to unique values is completely up to the macros that call them. %D %D \starttyping %D \thisissomeinternal{tag}{identifier} %D \gotosomeinternal {tag}{identifier}{pagenumber}{text} %D \stoptyping %D %D We could do this in \LUA\ \unknown \newif \iflocation \newcount\locationcount \newcount\locationorder \newbox \locationbox \def\nextinternalreference {\the\locationcount} \def\nextinternalorderreference{\the\locationorder} \def\setnextinternalreference {\global\advance\locationcount\plusone} \def\setnextinternalreferences#kind#name% plural {\clf_setnextinternalreference{#kind}{#name}} \def\getinternalorderreference#kind#name% {\clf_currentreferenceorder{#kind}{#name}} \def\thisissomeinternal#kind#name% only for old time sake, will go away {\begingroup \clf_setinternalreference reference {#kind:#name}% no view \relax \hpack attr \destinationattribute\lastdestinationattribute{}% \endgroup} \installcorenamespace{savedinternalreference} \letvalue{\??savedinternalreference\s!default}\!!zerocount \unexpanded\def\storeinternalreference#1#2% {\setxvalue{\??savedinternalreference\currentstructurename}{\number#2}} \newconditional\preferpagereferences \def\gotosomeinternal#kind#name#target#text% {\ifconditional\preferpagereferences \directgoto{#text}[page(#target)]% \else \directgoto{#text}[#kind:#name]% \fi} \def\gotonextinternal#text#target% {\directgoto{#text}[internal(#target)]} %D In this module we define three system references: one for handling navigational, %D viewer specific, commands, another for jumping to special pages, like the first %D or last one, and a third reference for linking tree like lists, like tables of %D contents. The latter two adapt themselves to the current state. %D %D An example of an action is: %D %D \starttyping %D \goto{some action}[PreviousJump] %D \stoptyping %D %D as well as: %D %D \starttyping %D \goto{some text}[\v!action(PreviousJump] %D \stoptyping %D %D One can also activate an automatic prefix mechanism. By setting the %D \type {\prefix} variable to \type {+}, the prefix is incremented, when set to %D \type {-} or empty, the prefix is reset. Other values become the prefix. \newcount\prefixcounter \newconditional\autocrossfilereferences \appendtoks \edef\p_autofile{\referencingparameter\c!autofile}% \ifx\p_autofile\v!yes \settrue \autocrossfilereferences \else \setfalse\autocrossfilereferences \fi \to \everysetupreferencing \appendtoks \edef\p_export{\referencingparameter\c!export}% \ifx\p_export\v!yes \clf_exportreferences \fi \to \everygoodbye \unexpanded\def\setupglobalreferenceprefix[#prefix]% {\xdef\referenceprefix{#prefix}} \unexpanded\def\globalpushreferenceprefix#prefix% {\xdef\referenceprefix{\clf_pushreferenceprefix{#prefix}}} \unexpanded\def\globalpopreferenceprefix {\xdef\referenceprefix{\clf_popreferenceprefix}} \unexpanded\def\pushreferenceprefix#prefix% {\edef\referenceprefix{\clf_pushreferenceprefix{#prefix}}} \unexpanded\def\popreferenceprefix {\edef\referenceprefix{\clf_popreferenceprefix}} \def\m_strc_references_prefix_yes{+} \def\m_strc_references_prefix_nop{-} \unexpanded\def\setupreferenceprefix[#prefix]% {\edef\p_prefix{#prefix}% \ifx\p_prefix\empty \let\referenceprefix\empty \else\ifx\p_prefix\m_strc_references_prefix_yes \letreferencingparameter\c!prefix\s!unknown \global\advance\prefixcounter\plusone \edef\referenceprefix{\the\prefixcounter}% \else\ifx\p_prefix\m_strc_references_prefix_nop \letreferencingparameter\c!prefix\s!unknown \let\referenceprefix\empty \else\ifx\p_prefix\s!unknown % forget about it \else \let\referenceprefix\p_prefix \fi\fi\fi\fi} \appendtoks \setupreferenceprefix[\referencingparameter\c!prefix] \to \everysetupreferencing %D We can typeset a reference using \type {\in}, \type {\at} and \type {\about} and %D goto specific locations using \type {\goto}. The last one does not make that much %D sense in a paper document. To complicate things, \PLAIN\ \TEX\ also implements an %D \type {\in} but fortunately that one only makes sense in math mode. %D %D Typesetting the reference is a bit more complicated than one would at first sight %D expect. This is due to the fact that we distinguish three (five) alternative %D calls: %D %D \placefigure %D [here][three calls] %D {Three alternatives reference calls.} %D {\startcombination[1*3] %D {\framed{\type{ \in }}} {a} %D {\framed{\type{ \at }}} {b} %D {\framed{\type{\goto}}} {c} %D \stopcombination} %D %D \startbuffer %D \in figure[fig:three calls] %D \in{figure}[fig:three calls] %D \in figure a[fig:three calls] %D \in{figure}{a}[fig:three calls] %D figure~\in[fig:three calls] %D \stopbuffer %D %D \typebuffer %D %D This turns up as: %D %D \startlines %D \getbuffer %D \stoplines %D %D The dual \type {{}} results in a split reference. In a document meant for paper, %D one is tempted to use the last (most straightforward) alternative. When a %D document is also meant voor electronic distribution, the former alternatives have %D preference, because everything between the \type {\in} and~\type {[} becomes %D active (and when asked for, typeset in a different color and typeface). \appendtoks \ifdefined\in \let\normalmathin \in \unexpanded\def\in {\mathortext\normalmathin \strc_references_in } \else \let\in \strc_references_in \fi \ifdefined\at \let\normalmathat \at \unexpanded\def\at {\mathortext\normalmathat \strc_references_at } \else \let\at \strc_references_at \fi \ifdefined\about \let\normalmathabout\about \unexpanded\def\about{\mathortext\normalmathabout\strc_references_about} \else \let\about\strc_references_about \fi \ifdefined\from \let\normalmathfrom \from \unexpanded\def\from {\mathortext\normalmathfrom \strc_references_from } \else \let\from \strc_references_from \fi \ifdefined\over \let\normalmathover \over \unexpanded\def\over {\mathortext\normalmathover \strc_references_about} \else \let\over \strc_references_about \fi \to \everydump \def\filterreference #key{\clf_filterreference{#key}} % no checking, expanded \unexpanded\def\getreferenceentry#key{\clf_filterreference{#key}} % no checking, unexpanded \def\currentreferencenumber {\clf_filterreference{number}} \def\currentreferencepage {\clf_filterreference{page}} \def\currentreferencetitle {\clf_filterreference{title}} \def\currentreferencetext {\clf_filterreference{text}} \def\currentreferencedefault {\clf_filterreference{default}} \def\currentreferencerealpage{\clf_filterreference{realpage}} %D The most straightforward way of retrieving references is using \type {\ref}. \unexpanded\def\getreference % checking, unexpanded {\dodoubleargument\strc_references_get_reference} \def\strc_references_get_reference[#key][#label]% #key = number page title text default realpage ... {\ifsecondargument \doifelsereferencefound{#label}{\clf_filterreference{#key}}\dummyreference \else \dummyreference \fi} \let\ref\getreference %D Special cases: \unexpanded\def\strc_references_about[#label]% {\dontleavehmode \begingroup \let\crlf\space \let\\\space \postponenotes % might go \referencingparameter\c!left \doifelsereferencefound{#label} {\goto{\limitatetext\currentreferencetitle{\referencingparameter\c!width}\unknown}[#label]}% not so efficient (dup lookup) {}% todo \flushnotes % might go \referencingparameter\c!right \endgroup} %D The previously discussed setup macro lets us specify the representation of %D references. A symbol reference does not show the specific data, like the number %D of a figure, but shows one of: \hbox {$^\goforwardcharacter$ %D $^\gobackwardcharacter$ $^\gonowherecharacter$}, depending on the direction to %D go. %D %D \starttyping %D ... \somewhere{backward text}{forward text}[someref] ... %D ... \atpage[someref] ... %D \stoptyping % standard detail % % 0 = unknown unknown % 1 = same on same page % 2 = before preceding page % 3 = after following page % % 4 = above above on same page % 5 = below below on same page % todo: optimize for use in pagebody % todo: maybe make it optional % \setuppagenumbering[alternative=doublesided] % \setupreferencing [doublesided=no] % yes is default % % \somewhere{backward}{foreward}[label] % \someplace{preceding}{backward}{current}{foreward}{following}[label] % \atpage[#label] % \doifcheckedpagestate{label}{preceding}{backward}{current}{foreward}{following}{otherwise} % % \dorecurse {20} { % \placefigure[here][fig:#1]{}{\externalfigure[dummy]} % \dorecurse {20} { % ##1: \atpage[fig:##1] / % \doifcheckedpagestate % {fig:##1} % {preceding}{backward}{current}{foreward}{following} % {otherwise} % } % } \newcount \nofreferencestates \newconditional\pagestatespread \appendtoks \doifelse{\referencingparameter\c!doublesided}\v!yes\settrue\setfalse\pagestatespread \to \everysetupreferencing \setupreferencing [\c!doublesided=\v!yes] \def\referencepagestate {\numexpr\clf_referencepagestate {rst::\number\nofreferencestates}% \relax} \def\referencepagedetail {\numexpr\clf_referencepagedetail {rst::\number\nofreferencestates}% true % \ifconditional\pagestatespread false\ifdoublesided true\else false\fi\fi \relax} \def\referencerealpage {\clf_referencerealpage} \def\referencecolumnnumber {\clf_referencecolumn} \unexpanded\def\tracedpagestate {{\blue\tttf(\ifcase\referencepagedetail unknown\or same\or previous\or next\or above\or below\else unknown\fi)}} \unexpanded\def\markreferencepage {\dontleavehmode\begingroup \iftrialtypesetting % issue warning that not stable \else % needs checking ... but probably never in trialmode \global\advance\nofreferencestates\plusone \xypos{rst::\number\nofreferencestates}% % \tracedpagestate \fi \endgroup} \unexpanded\def\doifcheckedpagestate#label% #preceding#backward#current#foreward#following#otherwise% {\doifelsereferencefound{#label}\strc_references_handle_page_state_yes\strc_references_handle_page_state_nop} \let\strc_references_handle_page_state_nop\sixthofsixarguments \def\strc_references_handle_page_state_yes {\markreferencepage \ifcase\referencepagedetail \expandafter\sixthofsixarguments \or \expandafter\thirdofsixarguments \or \expandafter\firstofsixarguments \or \expandafter\fifthofsixarguments \or \expandafter\secondofsixarguments\or \expandafter\fourthofsixarguments\else \expandafter\sixthofsixarguments \fi} \unexpanded\def\referencesymbol {\hpack\bgroup \strut \markreferencepage \high {\setupsymbolset[\interactionparameter\c!symbolset]% \symbol[\ifcase\referencepagedetail\v!somewhere\or\v!nowhere\or\v!previous\or\v!next\or\v!previous\or\v!next\else\v!somewhere\fi]}% \egroup} %D Hereafter the \type {\ignorespaces} binds the state node to next character (more likely %D than a preceding one) and one can always add an explicit space. \unexpanded\def\somewhere#backward#foreward#dummy[#label]% #dummy gobbles space around #foreward {\doifcheckedpagestate{#label}% {\goto{#backward}[#label]}% {\goto{#backward}[#label]}% {\ignorespaces}% {\goto{#foreward}[#label]}% {\goto{#foreward}[#label]}% {#label}}% \unexpanded\def\someplace#preceding#backward#current#foreward#following#dummy[#label]% #dummy gobbles space around #foreward {\doifcheckedpagestate{#label}% {\doifelsenothing{#preceding}{\goto{#preceding}[#label]}\ignorespaces}% {\doifelsenothing {#backward}{\goto {#backward}[#label]}\ignorespaces}% {\doifelsenothing {#current}{\goto {#current}[#label]}\ignorespaces}% {\doifelsenothing {#foreward}{\goto {#foreward}[#label]}\ignorespaces}% {\doifelsenothing{#following}{\goto{#following}[#label]}\ignorespaces}% {#label}} \unexpanded\def\atpage[#label]% todo {\doifcheckedpagestate{#label}% {\goto{\labeltext \v!precedingpage }[#label]}% {\goto{\labeltext \v!hencefore }[#label]}% {\ignorespaces}% {\goto{\labeltext \v!hereafter }[#label]}% {\goto{\labeltext \v!followingpage }[#label]}% {\goto{\labeltexts\v!page\dummyreference}[#label]}} % Someone requested this but in retrospect didn't need it so we keep it as example. % Beware: a node is injected which is why we add ignorespaces! % % \unexpanded\def\strc_references_conditional#action#text[#condition]#dummy[#label]% % {\doifcheckedpagestate{#label}% % {\doifelse{#condition}\v!precedingpage{#action{#text}[#label]}\ignorespaces}% % {\doifelse{#condition}\v!hencefore {#action{#text}[#label]}\ignorespaces}% % {\doifelse{#condition}\v!current {#action{#text}[#label]}\ignorespaces}% % {\doifelse{#condition}\v!hereafter {#action{#text}[#label]}\ignorespaces}% % {\doifelse{#condition}\v!followingpage{#action{#text}[#label]}\ignorespaces}% % {#label}} % % \unexpanded\def\conditionalat {\strc_references_conditional\at} % \unexpanded\def\conditionalin {\strc_references_conditional\in} % \unexpanded\def\conditionalabout{\strc_references_conditional\about} %D The other alternatives just conform their names: only the label, only the text, or the %D label and the text. % \dounknownreference -> \dummyreference \def\symbolreference[#label]% for old times sake {\goto{\referencesymbol}[#label]} % \referencecontentmode 0=all 1=label 2=text 3=symbol \newtoks\leftreferencetoks \newtoks\rightreferencetoks \newtoks\defaultleftreferencetoks \newtoks\defaultrightreferencetoks %def\leftofreferencecontent {\nobreakspace} % we cannot do \definereferenceformat[at] .. so we need this \let\rightofreferencecontent \empty \let\leftofreference \empty \let\rightofreference \empty \unexpanded\def\leftofreferencecontent {\removeunwantedspaces \nonbreakablespace \ignorespaces} \installcorenamespace{referencinginteraction} \def\strc_references_interaction_all {\the\leftreferencetoks \doifelsesometoks\leftreferencetoks \leftofreferencecontent \donothing \leftofreference \doifelsesometoks\leftreferencetoks\onlynonbreakablespace\relax % new, replace space by nonbreakable if present \currentreferencecontent \rightofreference \doifelsesometoks\rightreferencetoks\rightofreferencecontent\donothing \the\rightreferencetoks} \letvalue{\??referencinginteraction\v!all}\strc_references_interaction_all \setvalue{\??referencinginteraction\v!label}% {\leftofreference \the\leftreferencetoks \the\rightreferencetoks \rightofreference} \setvalue{\??referencinginteraction\v!text}% {\leftofreference \currentreferencecontent \rightofreference} \setvalue{\??referencinginteraction\v!symbol}% {\referencesymbol} \def\referencesequence {\ifcsname\??referencinginteraction\referencingparameter\c!interaction\endcsname \expandafter\lastnamedcs \else \expandafter\strc_references_interaction_all \fi} \newtoks\everyresetinatreference \appendtoks \glet\leftofreference \relax \glet\rightofreference\relax \to \everyresetinatreference \def\strc_references_start_goto {\dontleavehmode \begingroup} \def\strc_references_stop_goto {\the\everyresetinatreference \endgroup} \def\strc_references_pickup_goto {\dodoublegroupempty\strc_references_pickup_goto_indeed} \def\strc_references_pickup_goto_indeed#left#right#dummy[#label]% #dummy gobbles spaces (really needed) {\leftreferencetoks \iffirstargument {#left}% \else \defaultleftreferencetoks \let\leftofreferencecontent\empty \fi \rightreferencetoks \ifsecondargument {#right}% \else \defaultrightreferencetoks \let\rightofreferencecontent\empty \fi % inefficient: double resolve \doifelsereferencefound{#label} % we need to resolve the text {\goto{\referencesequence}[#label]} {\let\currentreferencecontent\dummyreference \goto{\referencesequence}[#label]}% \strc_references_stop_goto} \unexpanded\def\strc_references_in {\strc_references_start_goto \let\currentreferencecontent\currentreferencedefault \strc_references_pickup_goto} \unexpanded\def\strc_references_at {\strc_references_start_goto \let\currentreferencecontent\currentreferencepage \strc_references_pickup_goto} %D \macros %D {definereferenceformat} %D %D The next few macros were made for for David Arnold and Taco Hoekwater. They can %D be used for predefining reference texts, and thereby stimulate efficiency. %D %D \starttyping %D \definereferenceformat[informula] [left=(,right=),text=formula] %D \definereferenceformat[informulas] [left=(,right=),text=formulas] %D \definereferenceformat[andformula] [left=(,right=),text=and] %D \definereferenceformat[andformulas][left=(,right=),text=and] %D %D \informula [b] and \informula [for:c] %D the \informula {formulas}[b] \informula {and} [for:c] %D the \informulas {formulas}[b] \informula {and} [for:c] %D the \informulas [b] \informula {en} [for:c] %D the \informulas [b] \andformula [for:c] %D \stoptyping %D %D Instead of a text, one can specify a label, which should be defined with \type %D {\setuplabeltext}. %D %D Watch out: the second argument is somewhat special and mostly meant for a suffix %D to a number: %D %D \startbuffer %D \definereferenceformat [intesta] [left=(,right=),text=Whatever~] %D \definereferenceformat [intestb] [left=(,right=),label=figure] %D %D \placeformula[x]\startformula a \stopformula %D %D \starttabulate[|||||] %D \NC \in [x] \NC \in {left}[x] \NC \in {}{right}[x] \NC \in {left}{right}[x] \NC \NR %D \NC \intesta[x] \NC \intesta{left}[x] \NC \intesta{}{right}[x] \NC \intesta{left}{right}[x] \NC \NR %D \NC \intestb[x] \NC \intestb{left}[x] \NC \intestb{}{right}[x] \NC \intestb{left}{right}[x] \NC \NR %D \stoptabulate %D \stopbuffer %D %D \typebuffer \getbuffer % to be done: interfaced \installcorenamespace{referenceformat} \installcommandhandler \??referenceformat {referenceformat} \??referenceformat \appendtoks \setuevalue\currentreferenceformat{\strc_references_apply_format{\currentreferenceformat}}% \to \everydefinereferenceformat \setupreferenceformat [\c!left=, \c!right=, \c!text=, \c!label=, \c!autocase=\v!no, \c!style=, \c!type=default, % to be done: interfaced \c!setups=, \c!color=] \unexpanded\def\strc_references_apply_format#name% {\strc_references_start_goto \edef\currentreferenceformat{#name}% \gdef\leftofreference {\referenceformatparameter\c!left }% \gdef\rightofreference {\referenceformatparameter\c!right }% \edef\currentreferenceformatlabel {\referenceformatparameter\c!label }% \edef\currentreferenceformattype {\referenceformatparameter\c!type }% \edef\currentreferenceformatsetups {\referenceformatparameter\c!setups }% \edef\currentreferenceformatautocase{\referenceformatparameter\c!autocase}% \usereferenceformatstyleandcolor\c!style\c!color \ifx\currentstyleparameter\empty \else \resetinteractionparameter\c!style \fi \ifx\currentcolorparameter\empty \else \resetinteractionparameter\c!contrastcolor \resetinteractionparameter\c!color \fi \ifx\currentreferenceformatlabel\autoreferencelabeltextflag \edef\currentreferenceformatlabel{\autoreferencelabeltext}% \fi \ifx\currentreferenceformatautocase\v!yes \setcharactercleaning[1]% \fi \ifx\currentreferenceformatlabel\empty \defaultleftreferencetoks {\referenceformatparameter\c!text}% \defaultrightreferencetoks\emptytoks \else \defaultleftreferencetoks {\leftlabeltext \currentreferenceformatlabel}% \defaultrightreferencetoks{\rightlabeltext\currentreferenceformatlabel}% \fi \ifx\currentreferenceformattype\empty \def\currentreferenceformattype{default}% \fi % \ifx\currentreferenceformatsetups\empty \def\currentreferencecontent{\filterreference\currentreferenceformattype}% \else \def\currentreferencecontent{\directsetup\currentreferenceformatsetups}% \fi % \let\leftofreferencecontent \empty \let\rightofreferencecontent\empty \strc_references_pickup_goto} \def\autoreferencelabeltextflag{*} % a proper key like 'auto' or 'name' can clash with a label key \unexpanded\def\autoreferencelabeltext {\clf_getcurrentreferencemetadata{name}} % \starttext % \definereferenceformat[inxx] [left=(,right=),text=txt] % \setupinteraction[state=start] % \chapter[one]{xx} % [\goto{state}[file(mk-last-state)]] % [\goto{state} [file(mk-last-state)]] % [\at{page} [one]] % [\at{page}[one]] % [\at{page}{okay}[one]] % [\inxx{a}{b}[one]] % \stoptext % \startsetups referenceformat:numberplustext % \filterreference{number}, \filterreference{title} % \stopsetups % % \definereferenceformat[hellup][text=Hellup ,setups=referenceformat:numberplustext] %D In interactive documents going to a specific location is not bound to cross %D references. The \type {\goto} commands can be used to let users access another %D part of the document. In this respect, interactive tables of contents and %D registers can be considered goto's. Because in fact a \type {\goto} is just a %D reference without reference specific data, the previous macros are implemented %D using the goto functionality. %D %D \showsetup{goto} %D %D One important characteristic is that the first argument of \type {\goto} (and %D therefore \type {\at} and \type {\in} is split at spaces. This means that, %D although hyphenation is prevented, long references can cross line endings. % \starttext % \setupinteraction[state=start] % [\goto{state}[file(mk-last-state)]] % [\goto{state} [file(mk-last-state)]] % \stoptext \newconditional\uselocationstrut \settrue\uselocationstrut \def\extrareferencearguments {highlight \luaconditional\highlighthyperlinks\space newwindow \luaconditional\gotonewwindow\space layer {\currentviewerlayer}} \unexpanded\def\directgoto {\ifconditional\uselocationstrut \expandafter\strc_references_direct_goto \else \expandafter\strc_references_direct_goto_htdp \fi} \unexpanded\def\goto {\ifconditional\uselocationstrut \expandafter\strc_references_goto \else \expandafter\strc_references_goto_htdp \fi} % The unbox trick is needed in order to permit \par inside a reference. Otherwise % the reference attribute migrates to the outer boxes. \newcount\lastsavedreferenceattribute \newbox\referencebox \def\revivesavedreferenceattribute % sometimes handy as no test etc needed {\attribute\referenceattribute\lastsavedreferenceattribute} \def\strc_references_direct_goto#content[#label]% no test for valid references {\dontleavehmode \begingroup \attribute\referenceattribute\attributeunsetvalue \global\lastsavedreferenceattribute\attributeunsetvalue \iflocation \clf_injectreference {\referenceprefix}% {#label}% {% height \ht\strutbox depth \dp\strutbox \extrareferencearguments }% \relax \setlocationattributes \setstrut % can be option \global\lastsavedreferenceattribute\lastreferenceattribute \attribute\referenceattribute\lastreferenceattribute \dostarttagged\t!link\empty % not here #content% \dostoptagged \else #content% \fi \endgroup} \def\strc_references_direct_goto_htdp#content[#label]% no test for valid references {\dontleavehmode \begingroup \global\lastsavedreferenceattribute\attributeunsetvalue \attribute\referenceattribute\attributeunsetvalue \iflocation \clf_injectreference {\referenceprefix}% {#label}% {% height \dimexpr\interactionparameter\c!height\relax depth \dimexpr\interactionparameter\c!depth \relax \extrareferencearguments }% \relax \setlocationattributes \attribute\referenceattribute\lastreferenceattribute \global\lastsavedreferenceattribute\lastreferenceattribute \dostarttagged\t!link\empty #content% \dostoptagged \else #content% \fi \endgroup} \def\strc_references_goto#content#dummy[#label]% #dummy gobbles spaces {\dontleavehmode \begingroup %\setbox\referencebox\hbox\bgroup % experiment, might change again to non \par support \global\lastsavedreferenceattribute\attributeunsetvalue \attribute\referenceattribute\attributeunsetvalue \iflocation \clf_doifelsereference{\referenceprefix}{#label}{\extrareferencearguments}% {\expandtexincurrentreference \clf_injectcurrentreferencehtdp \ht\strutbox \dp\strutbox \relax \setlocationattributes \setstrut % can be option \global\lastsavedreferenceattribute\lastreferenceattribute \attribute\referenceattribute\lastreferenceattribute \dostarttagged\t!link\empty #content% \dostoptagged}% {#content}% \else #content% \fi %\egroup\unhbox\referencebox} \endgroup} \def\strc_references_goto_internal#content#dummy[#internal]% #dummy gobbles spaces {\dontleavehmode \begingroup \global\lastsavedreferenceattribute\attributeunsetvalue \attribute\referenceattribute\attributeunsetvalue \iflocation \setstrut % can be option \strc_references_get_simple_reference{#internal}% \global\lastsavedreferenceattribute\currentreferenceattribute \attribute\referenceattribute\currentreferenceattribute \setlocationattributes \dostarttagged\t!link\empty #content% \dostoptagged \else #content% \fi \endgroup} \unexpanded\def\startgoto[#label]% {\dontleavehmode \begingroup \iflocation \clf_doifelsereference{\referenceprefix}{#label}{\extrareferencearguments}% {\expandafter\strc_references_start_goto_yes}% {\expandafter\strc_references_start_goto_nop}% \else \expandafter\strc_references_start_goto_nop \fi} \unexpanded\def\strc_references_start_goto_nop {\let\stopgoto\strc_references_stop_goto_nop} \unexpanded\def\strc_references_stop_goto_nop {\endgroup} \unexpanded\def\strc_references_start_goto_yes {\expandtexincurrentreference \clf_injectcurrentreferencehtdp \ht\strutbox \dp\strutbox \relax \setlocationattributes \setstrut % can be option \global\lastsavedreferenceattribute\lastreferenceattribute \attribute\referenceattribute\lastreferenceattribute \dostarttagged\t!link\empty \let\stopgoto\strc_references_stop_goto_yes} \unexpanded\def\strc_references_stop_goto_yes {\dostoptagged \endgroup} \def\strc_references_goto_htdp#content#dummy[#label]% dummy gobbles spaces {\dontleavehmode \begingroup \global\lastsavedreferenceattribute\attributeunsetvalue \attribute\referenceattribute\attributeunsetvalue \iflocation \clf_doifelsereference{\referenceprefix}{#label}{\extrareferencearguments}% {\expandtexincurrentreference \clf_injectcurrentreferencehtdp \dimexpr\interactionparameter\c!height\relax \dimexpr\interactionparameter\c!depth \relax \relax \setlocationattributes \global\lastsavedreferenceattribute\lastreferenceattribute \attribute\referenceattribute\lastreferenceattribute \dostarttagged\t!link\empty #content% \dostoptagged}% {#content}% \else #content% \fi \endgroup} \unexpanded\def\directgotobox#content[#label]% no test for valid references {\dontleavehmode \begingroup \global\lastsavedreferenceattribute\attributeunsetvalue \attribute\referenceattribute\attributeunsetvalue \iflocation \clf_injectreference {\referenceprefix}% {#label}% {\extrareferencearguments}% \relax \setlocationattributes \global\lastsavedreferenceattribute\lastreferenceattribute \dostarttagged\t!link\empty \hbox attr \referenceattribute \lastreferenceattribute {#content}% \dostoptagged \else #content% \fi \endgroup} \unexpanded\def\directgotospecbox#resolver#content[#label]% no test for valid references {\dontleavehmode \begingroup \global\lastsavedreferenceattribute\attributeunsetvalue \attribute\referenceattribute\attributeunsetvalue \iflocation \clf_injectreference {\referenceprefix}% {#label}% {\extrareferencearguments}% \relax \setlocationcolorspec{#resolver}% no consequence for strut \global\lastsavedreferenceattribute\lastreferenceattribute \dostarttagged\t!link\empty \hbox attr \referenceattribute \lastreferenceattribute {#content}% \dostoptagged \else #content% \fi \endgroup} \unexpanded\def\directgotodumbbox#content[#label]% no test for valid references {\dontleavehmode \begingroup \global\lastsavedreferenceattribute\attributeunsetvalue \attribute\referenceattribute\attributeunsetvalue \iflocation \clf_injectreference {\referenceprefix}% {#label}% {\extrareferencearguments}% \relax \global\lastsavedreferenceattribute\lastreferenceattribute \dostarttagged\t!link\empty \hbox attr \referenceattribute \lastreferenceattribute {#content}% \dostoptagged \else #content% \fi \endgroup} \unexpanded\def\gotobox#content[#label]% {\dontleavehmode \begingroup \global\lastsavedreferenceattribute\attributeunsetvalue \attribute\referenceattribute\attributeunsetvalue \iflocation \clf_doifelsereference{\referenceprefix}{#label}{\extrareferencearguments}% {\expandtexincurrentreference \clf_injectcurrentreference \setlocationattributes \global\lastsavedreferenceattribute\lastreferenceattribute \dostarttagged\t!link\empty \hbox attr \referenceattribute \lastreferenceattribute {#content}% \dostoptagged}% {#content}% \else #content% \fi \endgroup} \unexpanded\def\gotowdhtbox#width#height[#label]% fast variant for overlays {\dontleavehmode \begingroup \setbox\scratchbox\emptyhbox \wd\scratchbox#width% \ht\scratchbox#height% \global\lastsavedreferenceattribute\attributeunsetvalue \attribute\referenceattribute\attributeunsetvalue \clf_doifelsereference{\referenceprefix}{#label}{\extrareferencearguments}% {\clf_injectcurrentreference \global\lastsavedreferenceattribute\lastreferenceattribute \hpack attr \referenceattribute \lastreferenceattribute {\box\scratchbox}} {\box\scratchbox}% \endgroup} %D An reference to another document can be specified as a file or as an \URL. Both %D are handled by the same mechanism and can be issued by saying something like: %D %D \starttyping %D \goto[dictionary::the letter a] %D \stoptyping %D %D One can imagine that many references to such a dictionary are made, so in most %D cases such a document reference in an indirect one. %D %D \showsetup{useexternaldocument} %D %D For example: %D %D \starttyping %D \useexternaldocument %D [dictionary][engldict] %D [The Famous English Dictionary] %D \stoptyping %D %D The next macro implements these relations, and also take care of loading the %D document specific references. %D %D The \URL\ alternative takes four arguments: %D %D \showsetup{useURL} %D %D like: %D %D \starttyping %D \useURL %D [dictionary][http://www.publisher.com/public][engldict] %D [The Famous English Dictionary] %D \stoptyping %D %D Several specifications are possible: %D %D \starttyping %D \useURL [id] [url] [file] [description] %D \useURL [id] [url] [file] %D \useURL [id] [url] %D \stoptyping %D %D This time we don't load the references when no file is specified. This is logical %D when one keeps in mind that a valid \URL\ can also be a mail address. \unexpanded\def\useurl {\doquadrupleempty\strc_references_use_url } % so that they can be used in expanded arguments \unexpanded\def\usefile{\dotripleargument\strc_references_use_file} % so that they can be used in expanded arguments \let\useURL \useurl \let\useexternaldocument\usefile \def\strc_references_use_url[#label][#url][#file][#description]% {\clf_useurl{#label}{\detokenize{#url}}{\detokenize{#file}}{\detokenize{#description}}} \def\strc_references_use_file[#label][#file][#description]% {\clf_usefile{#label}{\detokenize{#file}}{\detokenize{#description}}} \def\doifelseurldefined #label{\clf_doifelseurldefined {#label}} \def\doifelsefiledefined#label{\clf_doifelsefiledefined{#label}} \let\doifurldefinedelse \doifelseurldefined \let\doiffiledefinedelse\doifelsefiledefined %D \macros %D {url,setupurl} %D %D We also have: \type {\url} for directly calling the description. So we can say: %D %D \starttyping %D \useURL [one] [http://www.test.nl] %D \useURL [two] [http://www.test.nl] [] [Some Site] %D %D \url[one] or \from[two] or \goto{Whatever Site}[URL(two)] %D \stoptyping %D %D An \URL\ can be set up with %D %D \showsetup{setupurl} \installcorenamespace{url} \installdirectcommandhandler \??url {url} \setupurl [\c!style=\v!type, \c!color=] \unexpanded\def\url[#label]% move \hyphenatedurl to lua end (is already lua) {\dontleavehmode \begingroup \useurlstyleandcolor\c!style\c!color \hyphenatedurl{\clf_geturl{#label}}% \endgroup} %D This macro is hooked into a support macro, and thereby \URL's break ok, according %D to the setting of a switch, %D %D \startbuffer %D \useURL %D [test] %D [sentence_sentence~sentence//sentence:sentence.sentence] %D \stopbuffer %D %D \typebuffer %D %D Such an \URL\ is, depending on the settings, hyphenated as: %D %D \getbuffer %D When defining the external source of information, one can also specify a suitable %D name (the last argument). This name can be called upon with: %D %D \showsetup{from} %D %D We keep this for compatibility reasons, hence the hackery. \unexpanded\def\strc_references_from {\dosingleempty\strc_references_do_special_from} \def\strc_references_do_special_from[#label]% {\dontleavehmode \goto{\clf_from{#label}}[fileorurl(#label)]} \def\dofromurldescription#content% called at the lua end {#content} \def\dofromurlliteral#content% called at the lua end {\useurlstyleandcolor\c!style\c!color \hyphenatedurl{#content}} \let\dofromfiledescription\dofromurldescription \let\dofromfileliteral \dofromurlliteral % maybe some day setupfile that inherits from url %D We also support: %D %D \starttyping %D \goto{some text}[file(identifier{location}] %D \stoptyping %D %D which is completely equivalent with %D %D \starttyping %D \goto{some text}[identifier::location] %D \stoptyping %D A special case of references are those to programs. These, very system dependant %D references are implemented by abusing some of the previous macros. %D %D \showsetup{setupprograms} %D \showsetup{defineprogram} %D \showsetup{program} % changed functionality ! %D %D The latter gives access to the description of the program, %D being the last argument to the definition command. % also lua, like urls and files \installcorenamespace{programs} \installdirectcommandhandler \??programs {programs} \unexpanded\def\defineprogram {\dotripleargument\strc_references_define_program} \def\strc_references_define_program[#name][#program][#description]% {\clf_defineprogram{#name}{#program}{#description}} \unexpanded\def\program[#name]% incompatible, more consistent, hardy used anyway {\dontleavehmode \begingroup \useprogramsstyleandcolor\c!style\c!color \clf_getprogram{#name}% \endgroup} %D As we can see, we directly use the special reference mechanism, which means that %D %D \starttyping %D \goto{some text}[program(name{args})] %D \stoptyping %D %D is valid. %D The next macro provides access to the actual pagenumbers. When documenting and %D sanitizing the original reference macros, I decided to keep the present meaning %D as well as to make this meaning available as a special reference method. So now %D one can use: %D %D \starttyping %D \gotopage{some text}[location] %D \gotopage{some text}[number] %D \gotopage{some text}[file::number] %D \stoptyping %D %D as well as: %D %D \starttyping %D \goto{some text}[page(location)] %D \goto{some text}[page(number)] %D \goto{some text}[file::page(number)] %D \stoptyping %D %D Here location is a keyword like \type{nextpage}. %D %D \showsetup{gotopage} \unexpanded\def\definepage {\dodoubleargument\strc_references_define_page} \def\strc_references_define_page[#name][#target]% {\definereference[#name][page(#target)]} \def\gotopage#text[#target]% {\goto{#text}[\v!page(#target)]} %D The previous definitions are somewhat obsolete so we don't use it here. %D We can cross link documents by using: %D %D \showsetup{coupledocument} %D %D like: %D %D \starttyping %D \coupledocument[print][somefile][chapter,section] %D \stoptyping %D %D After which when applicable, we have available the references: %D %D \starttyping %D \goto{print version}[print::chapter] %D \stoptyping %D %D and alike. The title placement definition macros have a key \type {file}, which %D is interpreted as the file to jump to, that is, when one clicks on the title. \def\coupledocument {\doquadrupleempty\strc_references_couple_document} \def\strc_references_couple_document[#name][#file][#sections][#description]% {\ifthirdargument % this will be done differently (when it's needed) \fi} %D \macros %D {dotextprefix} %D %D In previous macros we used \type {\dotextprefix} to generate a space between %D a label and a number. %D %D \starttyping %D \dotextprefix{text} %D \stoptyping %D %D Only when \type {text} is not empty, a space is inserted. \unexpanded\def\dotextprefix#text% {\begingroup \setbox\scratchbox\hbox{#text}% to be solved some day \ifdim\wd\scratchbox>\zeropoint \unhbox\scratchbox \edef\p_separator{\referencingparameter\c!separator}% \ifx\p_separator\empty \else \removeunwantedspaces % remove is new \p_separator \fi \else \unhbox\scratchbox \fi \endgroup} %D In the next settings we see some variables that were not used here and that %D concern the way the pagenumbers refered to are typeset. \setupreferencing [\c!state=\v!start, \c!autofile=\v!no, \v!part\c!number=\v!yes, \v!chapter\c!number=\v!no, \c!interaction=\v!all, \c!convertfile=\v!no, %\c!strut=\v!no, % some day an option \c!prefix=, \c!width=.75\makeupwidth, \c!left=\quotation\bgroup, \c!right=\egroup, \c!global=\v!no, \c!expansion=\v!no, \c!separator=\nonbreakablespace, \c!export=\v!no] \setupprograms [\c!directory=, \c!style=\v!type, \c!color=] \definereference [\v!CloseDocument ] [action(close)] \definereference [\v!ExitViewer ] [action(exit)] \definereference [\v!FirstPage ] [action(first)] \definereference [\v!LastPage ] [action(last)] \definereference [\v!NextJump ] [action(forward)] \definereference [\v!NextPage ] [action(next)] \definereference [\v!PauseMovie ] [action(pausemovie)] \definereference [\v!PauseSound ] [action(pausesound)] \definereference [\v!PauseRendering ] [action(pauserendering)] \definereference [\v!PreviousJump ] [action(backward)] \definereference [\v!PreviousPage ] [action(previous)] \definereference [\v!PrintDocument ] [action(print)] \definereference [\v!SaveForm ] [action(exportform)] \definereference [\v!LoadForm ] [action(importform)] \definereference [\v!ResetForm ] [action(resetform)] \definereference [\v!ResumeMovie ] [action(resumemovie)] \definereference [\v!ResumeSound ] [action(resumesound)] \definereference [\v!ResumeRendering ] [action(resumerendering)] \definereference [\v!SaveDocument ] [action(save)] \definereference [\v!SaveNamedDocument] [action(savenamed)] \definereference [\v!OpenNamedDocument] [action(opennamed)] \definereference [\v!SearchDocument ] [action(search)] \definereference [\v!SearchAgain ] [action(searchagain)] \definereference [\v!StartMovie ] [action(startmovie)] \definereference [\v!StartSound ] [action(startsound)] \definereference [\v!StartRendering ] [action(startrendering)] \definereference [\v!StopMovie ] [action(stopmovie)] \definereference [\v!StopSound ] [action(stopsound)] \definereference [\v!StopRendering ] [action(stoprendering)] \definereference [\v!SubmitForm ] [action(submitform)] \definereference [\v!ToggleViewer ] [action(toggle)] \definereference [\v!ViewerHelp ] [action(help)] \definereference [\v!HideField ] [action(hide)] \definereference [\v!ShowField ] [action(show)] \definereference [\v!GotoPage ] [action(gotopage)] \definereference [\v!Query ] [action(query)] \definereference [\v!QueryAgain ] [action(queryagain)] \definereference [\v!FitWidth ] [action(fitwidth)] \definereference [\v!FitHeight ] [action(fitheight)] \definereference [\v!ShowThumbs ] [action(thumbnails)] \definereference [\v!ShowBookmarks ] [action(bookmarks)] \definereference [\v!HideLayer ] [action(hidelayer)] \definereference [\v!VideLayer ] [action(videlayer)] \definereference [\v!ToggleLayer ] [action(togglelayer)] \definereference [\v!firstpage] [page(firstpage)] \definereference [\v!previouspage] [page(previouspage)] \definereference [\v!nextpage] [page(nextpage)] \definereference [\v!lastpage] [page(lastpage)] \definereference [\v!forward] [page(forward)] \definereference [\v!backward] [page(backward)] \definereference [\v!firstsubpage] [page(firstsubpage)] \definereference [\v!previoussubpage] [page(previoussubpage)] \definereference [\v!nextsubpage] [page(nextsubpage)] \definereference [\v!lastsubpage] [page(lastsubpage)] % we can do this but only when later in resolve (else problems with \chapter[first]{...} % % \definereference [\v!first] [page(firstpage)] % \definereference [\v!previous] [page(prevpage)] % \definereference [\v!next] [page(nextpage)] % \definereference [\v!last] [page(lastpage)] % \definereference [\v!first\v!sub] [page(firstsubpage)] % \definereference [\v!previous\v!sub] [page(prevsubpage)] % \definereference [\v!next\v!sub] [page(nextsubpage)] % \definereference [\v!last\v!sub] [page(lastsubpage)] %D We cannot set up buttons (not yet, this one calls a menu macro): %D New (and experimental): % \starttext % \chapter{test} % \placefigure[here][xx:1]{}{\framed{one}} \placefigure[here][xx:2]{}{\framed{three}} % \placetable [here][xx:3]{}{\framed{two}} \placetable [here][xx:4]{}{\framed{four}} % \start % \in{fig}[xx:1] and \in{fig}[xx:2] \in{tab}[xx:3] and \in{tab}[xx:4] % \stop \blank \start % \setupreferencestructureprefix[default][prefix=no] % \in{fig}[xx:1] and \in{fig}[xx:2] \in{tab}[xx:3] and \in{tab}[xx:4] % \stop \blank \start % \setupreferencestructureprefix[float][default][prefix=no] % \in{fig}[xx:1] and \in{fig}[xx:2] \in{tab}[xx:3] and \in{tab}[xx:4] % \stop \blank \start % \setupreferencestructureprefix[figure][default][prefix=no] % \in{fig}[xx:1] and \in{fig}[xx:2] \in{tab}[xx:3] and \in{tab}[xx:4] % \stop \blank % \stoptext % todo: parameterhandler \installcorenamespace{referencingprefix} \def\getreferencestructureprefix#kind#name#category% name will change {{% prefix {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefix}% separatorset {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixseparatorset}% conversion {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixconversion}% conversionset {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixconversionset}% starter {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixstarter}% stopper {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixstopper}% set {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixset}% segments {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixsegments}% connector {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixconnector}% }% {% separatorset {\referencestructureprefixparameter{#kind}{#name}{#category}\c!numberseparatorset}% conversion {\referencestructureprefixparameter{#kind}{#name}{#category}\c!numberconversion}% conversionset {\referencestructureprefixparameter{#kind}{#name}{#category}\c!numberconversionset}% starter {\referencestructureprefixparameter{#kind}{#name}{#category}\c!numberstarter}% stopper {\referencestructureprefixparameter{#kind}{#name}{#category}\c!numberstopper}% segments {\referencestructureprefixparameter{#kind}{#name}{#category}\c!numbersegments}% }} \unexpanded\def\setupreferencestructureprefix {\dotripleempty\strc_references_setup_reference_structure_prefix} \def\strc_references_setup_reference_structure_prefix[#kind][#category][#settings]% {\ifthirdargument \getparameters[\??referencingprefix#kind:#category][#settings]% \else\ifsecondargument \getparameters[\??referencingprefix:#kind][#category]% \fi\fi} \def\referencestructureprefixparameter#kind#name#category#parameter% {\ifcsname\??referencingprefix#name:#category#parameter\endcsname \lastnamedcs \else\ifcsname\??referencingprefix#kind:#category#parameter\endcsname \lastnamedcs \else\ifcsname\??referencingprefix:#category#parameter\endcsname \lastnamedcs \fi\fi\fi} \def\currentreferencedefault % for some reason we need to explicitly expand {\normalexpanded{\noexpand\clf_filterdefaultreference {\s!default}% \noexpand\getreferencestructureprefix\clf_getcurrentprefixspec{\s!default}% returns #kind#name#category \relax}} %D Not all support is visible by looking at the \TEX\ code; here is one of those:^ %D %D \starttyping %D \startinteractionmenu[right] %D \startbut [section(first {chapter})] first chapter \stopbut %D \startbut [section(previous{chapter})] previous chapter \stopbut %D \startbut [section(next {chapter})] next chapter \stopbut %D \startbut [section(last {chapter})] last chapter \stopbut %D \blank[2*big] %D \startbut [section(first {section})] first section \stopbut %D \startbut [section(previous{section})] previous section \stopbut %D \startbut [section(next {section})] next section \stopbut %D \startbut [section(last {section})] last section \stopbut %D \stopinteractionmenu %D \stoptyping %D Relatively new: %D %D \starttyping %D \chapter{The never ending story} %D %D \section{An ending story} %D %D \in{chapter}[match(complex bibliographies)] %D \in{chapter}[match(never ending)] %D \in{chapter}[match(ending)] %D \in{chapter}[match(chapter:never ending)] %D \in{chapter}[match(chapter:ending)] %D \in{section}[match(section:ending)] %D \in{figure}[match(float:mess)] %D \in{figure}[match(figure:mess)] %D \in{figure (not found)}[match(section:mess)] %D \in{figure (not found)}[match(section:xxxx)] %D \in{figure}[match(mess)] %D %D \placefigure{What a mess}{} %D %D \chapter{About complex bibliographies} %D %D \in{chapter}[match(complex bibliographies)] %D \in{chapter}[match(never ending)] %D \in{figure}[match(mess)] %D \stoptyping \protect \endinput % tricky: % % \enabletrackers[nodes.references] % \setupinteraction[state=start] % \def\KnuthTest{\input knuth } % \def\KnuthTest{\input tufte } % \def\TufteTest{\input tufte } % \defineoverlay[xxx][\overlaybutton{page(3)}] % \setupbackgrounds[text][background=xxx] % \starttext % test {\red \KnuthTest} test \par % \button{test}[page(1)] \par % \goto{page 2 \TeX}[page(2)] \goto{page 2 \TeX}[page(2)] \goto{\TufteTest}[page(2)] test \page % test \goto{page 3}[page(3)] \goto{\TufteTest\space\par\TufteTest}[page(4)] test \page % \goto{page 1}[page(1)] \goto{\TufteTest\space test}[page(1)] \page % \goto{page 1}[page(1)] \goto{\KnuthTest\space test}[page(1)] \page % test \goto{page 1}[page(1)] {\goto{\KnuthTest\space test}[page(1)]} test % \goto{page 1}[page(1)] \goto{\TufteTest}[page(1)] test \page % \stoptext