diff options
Diffstat (limited to 'tex/context/base/java-ini.tex')
-rw-r--r-- | tex/context/base/java-ini.tex | 636 |
1 files changed, 636 insertions, 0 deletions
diff --git a/tex/context/base/java-ini.tex b/tex/context/base/java-ini.tex new file mode 100644 index 000000000..95c7ae08b --- /dev/null +++ b/tex/context/base/java-ini.tex @@ -0,0 +1,636 @@ +% JavaScript support is under development. In the near future +% a slightly different model will be used. The JScode stuff +% will probably become just auto function inclusion and the +% JS_* things will disappear. First I have to find a way to +% deal with global variables so the 'uses' thing will remain. + +% Also, obeylines will be supported. + +%D \module +%D [ file=java-ini, +%D version=1998.01.30, +%D title=\CONTEXT\ JavaScript Macros, +%D subtitle=Initialization, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA / Hans Hagen \& Ton Otten}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. Non||commercial use is +%C granted. + +\writestatus{loading}{Context JavaScript Macros / Initialization} + +\unprotect + +%D \JAVA\ support is not implemented as a generic support +%D module. The main reason for this is that passing system +%D variables to a \JAVASCRIPT\ is closely related to other core +%D macros. First some messages: + +\startmessages dutch library: javascript + title: javascript + 1: script set -- wordt geladen + 2: onbekende preamble -- +\stopmessages + +\startmessages english library: javascript + title: javascript + 1: loading script set -- + 2: unknown preamble -- +\stopmessages + +\startmessages german library: javascript + title: javascript + 1: Lade Scriptdatei -- + 2: unbekannte Preamble -- +\stopmessages + +%D \TEX\ is not the right tool to check the \JAVA\ code; the +%D most we can do is reporting some passed variables: + +\newif\iftraceJScode \traceJScodefalse + +\let\traceJScode\traceJScodetrue + +%D A bit out of place, but not dangerous: + +\bgroup +\catcode127=\@@letter +\gdef\delcharacter{^^7f} +\egroup + +%D The number of passed variables is minimalized by setting the +%D next switch. + +\newif\ifminimalizeJScode \minimalizeJScodetrue + +%D \macros +%D {JS*} +%D +%D Because \JAVASCRIPT's are activated by the user, for +%D instance by activating on a button, their support is closely +%D related to the referencing mechanism. Integration takes +%D place by +%D +%D \starttypen +%D \naar{calculate total}[Sum()] +%D \stoptypen +%D +%D The \type{()} classify this as a script. If they are absent, +%D the keyword is treated as a normal reference. +%D +%D One can pass arguments to such a script by saying: +%D +%D \starttypen +%D \naar{calculate total}[Sum(1.5,2.3)] +%D \stoptypen +%D +%D References are passed by using the \type{R{}} classifier. +%D +%D \starttypen +%D \naar{calculate total}[Sum(1.5,2.3,R{overflow})] +%D \stoptypen +%D +%D The last call calls the script \type{Sum} and passes the +%D next set of variables: +%D +%D \starttypen +%D JS_S_1="1.5"; +%D JS_S_2="2.3"; +%D JS_R_3="overflow"; +%D JS_P_3=3; +%D \stoptypen +%D +%D The first two parameters are just strings, the third one +%D however is treated as a reference and results in passing the +%D reference (if needed this references is prefixed) and the +%D (real) page number. The alternative: +%D +%D \starttypen +%D \naar{calculate total}[JS(Sum{V{1.5},V{2.3},R{overflow}})] +%D \stoptypen +%D +%D does a verbose passing: +%D +%D \starttypen +%D JS_V_1=1.5; +%D JS_V_2=2.3; +%D JS_R_3="overflow"; +%D JS_P_3=3; +%D \stoptypen +% %D +% %D Finally we have a counter that tells\JAVA\ how many +% %D arguments were passed, +% %D +% %D \starttypen +% %D JS_N +% %D \stoptypen + +%D We will also support direct function calls. In that case +%D no intermediate variables are used. + +%D \macros +%D {startJScode} +%D +%D A piece of \JAVASCRIPT\ code is defined by saying: +%D +%D \starttypen +%D \startJScode{SomeScript} +%D var Item=this.getField("item"); +%D N=Item.getArray(); +%D Total=this.getField("total"); +%D Total.value=0; +%D for (j=0; j<N.length; j++) +%D { if (N[j].value!="") +%D { Total.value += N[j].value } } ; +%D if ((JS_N>0) && (JS_R_1!="")) +%D { gotoNamedDest(JS_R_1) }; +%D \stopJScode +%D \stoptypen +%D +%D Such a piece of code is closely related to the interpreter +%D used. Watch the last two lines, here the script adapts +%D itself to the presence of a reference. +%D +%D While +%D +%D \starttypen +%D \startJScode{name} +%D name = 4 ; +%D \stopJScode +%D \stoptypen +%D +%D assumes uses no preamble or presumes that the preamble is +%D always loaded, the next definition also tells \CONTEXT\ to +%D actually include the preamble needed. +%D +%D \starttypen +%D \startJScode{uses} uses {later} +%D uses = 6 ; +%D \stopJScode +%D \stoptypen + +\long\gdef\startJScode#1 #2 + {\doifelse{#2}{uses} + {\def\next{\dostartJScodeA{#1}}} + {\def\next{\dostartJScodeB{#1} #2}}% + \next} + +\long\gdef\dostartJScodeA#1#2 #3\stopJScode% + {\long\setgvalue{\r!java#1}{\do{#2}{#3}}} + +\long\gdef\dostartJScodeB#1#2\stopJScode% + {\long\setgvalue{\r!java#1}{\do{}{#2}}} + +%D \macros +%D {presetJScode} +%D +%D The code can be retrieved by saying +%D +%D \starttypen +%D \presetJScode{SomeScript}{template} +%D \stoptypen +%D +%D Such a template is a comma separated list, where +%D individual entries can optionally be transformed by +%D \type{R{}} and \type{V{}}. +%D +%D After this call, the code is available in \type{\JScode}. + +\def\setverbosecscharacter#1% + {\edef#1{\string#1}} + +\def\setverbosecscharacters% temporary hack + {\setverbosecscharacter |\setverbosecscharacter ~% + \setverbosecscharacter\:\setverbosecscharacter\;% + \setverbosecscharacter\+\setverbosecscharacter\-% + \setverbosecscharacter\[\setverbosecscharacter\]% + \setverbosecscharacter\.\setverbosecscharacter\\% + \setverbosecscharacter\)\setverbosecscharacter\(% + \setverbosecscharacter\0\setverbosecscharacter\1% + \setverbosecscharacter\2\setverbosecscharacter\3% + \setverbosecscharacter\4\setverbosecscharacter\5% + \setverbosecscharacter\6\setverbosecscharacter\7% + \setverbosecscharacter\8\setverbosecscharacter\9% + \setverbosecscharacter\/\setverbosecscharacter\s} + +\newif\ifdirectJScode + +\def\presetJScode#1#2% #1=operation #2=arguments + {\setverbosecscharacters + \def\par{\delcharacter}% was: { } + \scratchcounter=0 + \global\let\JScode=\empty + \def\do##1##2% + {\doifelse{##2}{!}{\directJScodetrue}{\directJScodefalse}}% + \getvalue{\r!java#1}% + \edef\!!stringa{#2}% + \ifx\!!stringa\empty \else + \processcommacommand[\!!stringa]\dopresetJSvariables + \fi + \def\docommando##1% + {\doifundefinedelse{\r!java\r!java##1} + {\showmessage{\m!javascript}{2}{##1}} + {\doglobal\increment\currentJSpreamble + \doglobal\addtocommalist{##1}\allJSpreambles}}% + \def\do##1##2% + {\xdef\JScode{\ifdirectJScode#1(\JScode)\else\JScode##2\fi}% + %\xdef\JScode{JS\string_N=\the\scratchcounter;\JScode}% + \processcommalist[##1]\docommando}% + \getvalue{\r!java#1}} + +\def\dopresetJSvariables#1% + {\advance\scratchcounter by 1 + \donefalse + \dodopresetJSvariables#1\end}% + +\def\dodopresetJSvariables% + {\doifnextcharelse{R} + {\dodopresetJSrefvariables} + {\doifnextcharelse{V} + {\dodopresetJSvervariables} + {\doifnextcharelse{S} + {\dodopresetJSstrvariables} + {\dodopresetJSrawvariables}}}} + +\def\dodopresetJSrefvariables R#1\end% + {\doifreferencefoundelse{#1} + {\donetrue\dododopresetJSvariables R{\referenceprefix#1}% + \donefalse\dododopresetJSvariables P{\currentrealreference}} + {\unknownreference{#1}}% + \ifminimalizeJScode \else + \donetrue\dododopresetJSvariables S{#1}% + \fi} + +\def\dodopresetJSvervariables V#1\end% + {\donefalse\dododopresetJSvariables V{#1}% + \ifminimalizeJScode \else + \donetrue\dododopresetJSvariables S{#1}% + \fi} + +\def\dodopresetJSstrvariables S#1\end% + {\donetrue\dododopresetJSvariables S{#1}} + +\def\dodopresetJSrawvariables #1\end% + {\donetrue\dododopresetJSvariables S{#1}} + +\def\JSprefix#1% + {JS\string_#1\string_\the\scratchcounter} + +\def\dododopresetJSvariables#1#2% + {\iftraceJScode + \writestatus{JavaScript}{\JSprefix#1=#2} + \xdef\JScode{\JScode console.println("\JSprefix#1=#2"); }% + \fi + \ifdirectJScode + \xdef\JScode{\ifx\JScode\empty\else\JScode,\fi\ifdone"#2"\else#2\fi}% + \else + \xdef\JScode{\JScode\JSprefix#1=\ifdone"#2"\else#2\fi; }% + \fi} + +%D \macros +%D {startJSpreamble, flushJSpreamble} +%D +%D One can define insert \JAVASCRIPT\ code at the document level +%D by using: +%D +%D \starttypen +%D \startJSpreamble{oeps} +%D oeps = 1 ; +%D \stopJSpreamble +%D \stoptypen +%D +%D which is the same as: +%D +%D \starttypen +%D \startJSpreamble{now} used now +%D now = 2 ; +%D \stopJSpreamble +%D \stoptypen +%D +%D while the next definition is only included when actually +%D used. +%D +%D \starttypen +%D \startJSpreamble{later} used later +%D later = 3 ; +%D \stopJSpreamble +%D \stoptypen +%D +%D This command may be used more that once, but always before +%D the first page is shipped out. + +\newif\ifoneJSpreamble \oneJSpreambletrue + +\let\allJSpreambles=\empty +\newcounter\nofJSpreambles +\newcounter\currentJSpreamble + +\long\gdef\startJSpreamble#1 #2 + {\doifelse{#2}{used} + {\def\next{\dostartJSpreamble{#1} }} + {\def\next{\dostartJSpreamble{#1} now #2 }}% + \next} + +\long\def\dostartJSpreamble#1 #2 #3\stopJSpreamble% + {\bgroup + \processaction + [#2] + [ later=>\chardef\JSstatus=0, + now=>\chardef\JSstatus=1, + \s!default=>\chardef\JSstatus=2, + \s!unknown=>\chardef\JSstatus=2]% + \presetJSfunctions #3function ()\end% + \ifcase\JSstatus + \long\setgvalue{\r!java\r!java#1}{#3}% + \else + \long\setgvalue{\r!java\r!java#1}{#3}% + \doglobal\increment\currentJSpreamble + \doglobal\addtocommalist{#1}\allJSpreambles + \fi + \egroup} + +%D Because we want to check for valid calls, we preload the +%D functions. This means that we can call them directly as +%D well as indirectly when defined by \type {\startJScode} etc. + +\long\def\presetJSfunctions#1function #2(#3)% + {\doifelsenothing{#2} + {\long\def\presetJSfunctions##1\end{}} + {\stripspaces\from#2\to\ascii + \doifundefined{\r!java\ascii}{\setgvalue{\r!java\ascii}{\do{}{!}}}}% + \presetJSfunctions} + +\def\getJSpreamble#1% + {\getvalue{\r!java\r!java#1}} + +\def\presetJSpreamble% + {\ifx\allJSpreambles\empty\else + \bgroup + \setverbosecscharacters + \def\par{\delcharacter}% was: { } + \global\let\JSpreamble=\empty + \def\@@collectedJSpreamble{\r!java\r!java collected}% + \letvalue{\@@collectedJSpreamble}=\empty + \def\docommando##1% + {\xdef\JScode{\getvalue{\r!java\r!java##1}}% + \ifoneJSpreamble + \@EA\setxvalue\@EA\@@collectedJSpreamble\@EA + {\csname\@@collectedJSpreamble\endcsname\JScode}% + \else + \setxvalue{\r!java\r!java##1}% + {\JScode}% + \fi}% + \processcommacommand[\allJSpreambles]\docommando + \ifoneJSpreamble + \gdef\allJSpreambles{collected}% + \fi + \global\let\presetJSpreamble=\relax + \egroup + \fi} + +%\def\flushJSpreamble% +% {\iflocation\ifx\allJSpreambles\empty\else +% \bgroup +% \presetJSpreamble +% \expanded{\doflushJSpreamble{\allJSpreambles}}% +% \global\let\flushJSpreamble=\relax +% \global\let\allJSpreambles=\empty +% \egroup +% \fi\fi} +% +%\prependtoks \flushJSpreamble \to \everylastshipout + +\def\flushJSpreamble% + {\iflocation\ifx\allJSpreambles\empty\else + \ifcase\nofJSpreambles\else\ifnum\nofJSpreambles=\currentJSpreamble + \bgroup + \presetJSpreamble + \expanded{\doflushJSpreamble{\allJSpreambles}}% + \global\let\flushJSpreamble=\relax + \global\let\allJSpreambles=\empty + \egroup + \fi\fi + \fi\fi} + +\def\finalflushJSpreamble% + {\iflocation + \flushJSpreamble + \ifcase\currentJSpreamble\relax\else + \savecurrentvalue\nofJSpreambles\currentJSpreamble + \global\let\currentJSpreamble\nofJSpreambles + \fi + \fi} + +\prependtoks \flushJSpreamble \to \everyshipout +\prependtoks \finalflushJSpreamble \to \everylastshipout + +%D \macros +%D {doPSsanitizeJScode} +%D +%D Before the code can be passed to the (\POSTSCRIPT\ or \PDF) +%D output file, some precautions must be made concerning the +%D use of \type{(} and~\type{)}. Here we use a beautiful +%D \type{\aftergroup} trick I discovered in the \TABLE\ format. + +\def\doPSsanitizeJScode#1\to#2% + {\begingroup + \scratchcounter=0 % \aftergroup counter + \aftergroup\xdef + \aftergroup#2% + \aftergroup{% + \expanded{\convertargument#1\noexpand\to\noexpand\JScode}% + \expandafter\handletokens\JScode\with\dodoPSsanitizeJScode + \aftergroup}% + \endgroup + \iftraceJScode + \writestatus{JS trace}{#2}% + \fi} + +%D I started with: +%D +%D \starttypen +%D \def\dodoPSsanitizeJScode#1% +%D {\aftergroup\string +%D \if#1(% +%D \expandafter\aftergroup\csname#1\endcsname +%D \else\if#1)% +%D \expandafter\aftergroup\csname#1\endcsname +%D \else\if#1;% +%D \aftergroup;\aftergroup\string\expandafter\aftergroup\ +%D \else +%D \expandafter\aftergroup#1% +%D \fi\fi\fi +%D \advance\scratchcounter by 1 +%D \ifnum\scratchcounter=500 +%D \expandafter\dododoPSsanitizeJScode +%D \fi} +%D \stoptypen +%D +%D For pretty printing purposes, we need some way to signal +%D \TEX\ macros. Therefore we introduce a special keyword +%D \type{TEX}. When followed by a space, this keyword is +%D ignored, that is, filtered from the stream. Now we have: + +\chardef\JSisTEX=0 +\chardef\JScomment=0 + +\newif\ifaddJSlinebreaks + +\def\flushJSisTEX% + {\ifcase\JSisTEX + \or \aftergroup T% + \or \aftergroup T\aftergroup E% + \or \aftergroup T\aftergroup E\aftergroup X% + \fi + \chardef\JSisTEX=0 } + +\def\doJSlinebreak% + {\ifaddJSlinebreaks + \aftergroup\string\aftergroup\n% + \fi} + +\def\dodoPSsanitizeJScode#1% % input stack>500 & TEX check + {\if#1/% + \ifnum\JScomment=0 + \chardef\JScomment=1 + \else\ifnum\JScomment=1 + \chardef\JScomment=2 + \fi\fi + \else + \ifnum\JScomment=1 + \aftergroup/% + \chardef\JScomment=0 + \fi + \ifnum\JScomment=2 + \if#1\delcharacter + \chardef\JScomment=0 + \fi + \else + \if#1\delcharacter + \flushJSisTEX\doJSlinebreak + \else\if#1(% + \flushJSisTEX\aftergroup\string\expandafter\aftergroup\csname#1\endcsname + \else\if#1)% + \flushJSisTEX\aftergroup\string\expandafter\aftergroup\csname#1\endcsname + \else\if#1;% + \flushJSisTEX\aftergroup;\doJSlinebreak + \else\if#1T% + \ifnum\JSisTEX=0 \chardef\JSisTEX=1 \else\flushJSisTEX\aftergroup T\fi + \else\if#1E% + \ifnum\JSisTEX=1 \chardef\JSisTEX=2 \else\flushJSisTEX\aftergroup E\fi + \else\if#1X% + \ifnum\JSisTEX=2 \chardef\JSisTEX=3 \else\flushJSisTEX\aftergroup X\fi + \else\if#1\normalspace + \ifnum\JSisTEX=3 \chardef\JSisTEX=0 \else\flushJSisTEX\aftergroup#1\fi + \else + \flushJSisTEX\aftergroup\string\expandafter\aftergroup#1% + \fi\fi\fi\fi\fi\fi\fi\fi + \fi + \fi + \dododoPSsanitizeJScode} + +%D Close reading learns that one line comments (\type{// ...}) +%D are removed from the stream. This permits switching in +%D pretty printing \JAVASCRIPT\ sources as well as saves +%D some bytes. + +%D The magic 500 in the next hack prevents the input stack from +%D overflowing when large scripts are sanitized. + +\beginTEX + +\def\dododoPSsanitizeJScode% + {\ifcase\JSisTEX\ifcase\JScomment + \advance\scratchcounter by 1 + \fi\fi + \ifnum\scratchcounter=500 + \expandafter\dodododoPSsanitizeJScode + \fi} + +\def\dodododoPSsanitizeJScode% + {\let\next={% + \aftergroup}% + \endgroup + \begingroup + \aftergroup\xdef + \aftergroup\sanitizedJScode + \aftergroup{% + \aftergroup\sanitizedJScode + \let\next=}} + +\endTEX + +\beginETEX \aftergroup + +\let\dododoPSsanitizeJScode\relax + +\endETEX + +%D The macro \type{\doPSsanitizeJScode} converts its argument +%D into the macro \type{\sanitizedJScode}, thereby prefixing +%D each \type{(} and \type{)} by a slash. + +%D Hooking this mechanism into the general \CONTEXT\ reference +%D mechanism does not take much effort: + +\definespecialtest{JS} + {\doifdefinedelse{\r!java\currentreferenceoperation}} + +\definespeciallocation{JS}#1#2% + {\iflocation + \bgroup + \presetJScode + \currentreferenceoperation + \currentreferencearguments + \dostartgoto + \data + {#2}% + \start + \dostartgotoJS + {\number\buttonwidth}{\number\buttonheight} + {\JScode}% + \stop + \dostopgotoJS + \dostopgoto + \egroup + \else + {#2}% + \fi} + +%D \macros +%D {useJSscripts} +%D +%D In due time, users will build their collections of scripts, +%D which can be used (loaded) when applicable. Although not all +%D public, we will provide some general purpose scripts, +%D collected in files with names like \type{java-...}. One can +%D load these scripts with \type{\useJSscripts}, like: +%D +%D \starttypen +%D \useJSscripts[fld] +%D \stoptypen +%D +%D The not so complicated implementation of this macro is: + +\def\douseJSscripts#1% + {\doifelse{#1}{\v!reset} + {\let\allJSpreambles=\empty} + {\doifundefined{\c!file\f!javascriptprefix#1} + {\bgroup + \setbox0=\hbox % forget spaces and worse + {\setgvalue{\c!file\f!javascriptprefix#1}{}% + \makeshortfilename[\f!javascriptprefix#1]% + \showmessage{\m!javascript}{1}{#1}% + \startreadingfile + \readsysfile{\shortfilename}{}{}% + \stopreadingfile}% + \egroup}}} + +\def\useJSscripts[#1]% + {\processcommalist[#1]\douseJSscripts} + +\protect + +\endinput |