%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. See licen-en.pdf for 
%C details. 

\writestatus{loading}{Context JavaScript Macros / Initialization}

% 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.

\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 
