--- loncom/html/adm/help/tex/Developer_Tutorial.tex 2003/08/20 16:17:40 1.1 +++ loncom/html/adm/help/tex/Developer_Tutorial.tex 2005/04/07 06:56:22 1.6 @@ -1,3 +1,5 @@ +\label{Developer_Tutorial} + \section{Adding a Handler to LON-CAPA} In this section, we will add a brand new {}``handler'' to LON-CAPA. @@ -33,7 +35,7 @@ for the log files, or make a symlink the \item LON-CAPA must be installed and running. \item \textbf{Perl}: You're going to need to know some or you will not understand the code. You don't need to be intimately familiar with the many hundreds -of libraries Perl has, though, which is much harder then learning +of libraries Perl has, though, which is much harder than learning the language. \item Knowledge of the Apache server is not required for this tutorial, but {}``real work'' may require more information then is given here. @@ -252,7 +254,7 @@ If Apache is claiming it can't find the something is wrong with your \texttt{loncapa\_apache.conf} file. Please double check the entry to make sure it is in the right place, that it is typed correctly, and that all the lines are present. If it is -still incorrect, please ask for help on the \texttt{lon-capa-dev@mail.msu.edu} +still incorrect, please ask for help on the \texttt{lon-capa-dev@mail.lon-capa.org} list, including a copy of your \texttt{loncapa\_apache.conf} file in the email; either something is wrong that is beyond the scope of this document(other system configuration issues) or you really can't @@ -277,7 +279,7 @@ tail~/var/log/httpd/error\_log Since I can't guess what error you encountered, I'm afraid I can't help you out here. But I do know the code I wrote above worked, so as a last resort try to figure out what is different. If you are absolutely -stumped, please ask for help on the \texttt{lon-capa-dev@mail.msu.edu} +stumped, please ask for help on the \texttt{lon-capa-dev@mail.lon-capa.org} list, including a copy of your \texttt{lontutorial.pm} file in the email; either something is wrong that is beyond the scope of this document (other system configuration issues) or you really can't find @@ -361,7 +363,7 @@ To send back a proper HTTP response, add ~~~~if~(\$r->header\_only)~\{ -~~~~~~~~if~(\$ENV\{'browser.mathml'\})~\{ +~~~~~~~~if~(\$env\{'browser.mathml'\})~\{ ~~~~~~~~~~~~\$r->content\_type('text/xml'); @@ -379,7 +381,7 @@ To send back a proper HTTP response, add ~~~~\#~Send~header,~don't~cache~this~page -~~~~if~(\$ENV\{'browser.mathml'\})~\{ +~~~~if~(\$env\{'browser.mathml'\})~\{ ~~~~~~~~\$r->content\_type('text/xml'); @@ -451,7 +453,7 @@ use~Apache::lonnavmaps; Remove the {}``Hello world!'' line and replace it with this: \begin{lyxcode} -\$ENV\{'form.condition'\}~=~1; +\$env\{'form.condition'\}~=~1; my~\$renderArgs~=~\{~'cols'~=>~{[}Apache::lonnavmaps::resource{]}, @@ -468,19 +470,21 @@ Line by line: contains routines that help render navmaps. For more information, see later in this manual or type \texttt{man Apache::lonnavmaps}. This ensures these routines are loaded into memory. -\item \texttt{\textbf{\$ENV\{'form.condition'\} = 1;}}: This is an an argument +\item \texttt{\textbf{\$env\{'form.condition'\} = 1;}}: This is an an argument being passed to the Apache::lonnavmaps::render routine in a rather unorthodox way. This will cause the navmap to render all of the resources, by default, except for what we explicitly exclude. Since we're not -going to exclude anything (which we would do with \texttt{\$ENV\{'form.filter'\}}), +going to exclude anything (which we would do with \texttt{\$env\{'form.filter'\}}), all resources will be shown. \item \texttt{\textbf{my \$renderArgs\ldots{}\$r\};}}: Since the \texttt{render} routine takes a \emph{lot} of arguments, the \texttt{render} routine takes in a hash reference instead of a traditional list of arguments. For full information about what that function takes, consult the documentation. \texttt{'cols'} will tell the render function what to render in the -navmap; {}``0'' is the standard listing of the resource with a link -to the resource. \texttt{'showParts' => 0} tells the render function +navmap; {}``Apache::lonnavmaps::resource'' is a constant that +indicates the standard listing of the resource with a link +to the resource, which is the first column of the \textbf{NAV} display +you are used to. \texttt{'showParts' => 0} tells the render function not to show individual parts, which will not be useful to us. \texttt{'r' => \$r} passes the Apache response object to the \texttt{render} function, which it uses to provide periodic output to the user by using the @@ -520,7 +524,7 @@ In doing this, we'll learn: The first thing we need to do to accomplish this is to add an HTML form to the screen so we have something to submit. Just above the -\texttt{\$ENV\{'form.condition'\}} line, add the following: +\texttt{\$env\{'form.condition'\}} line, add the following: \begin{lyxcode} \$r->print(\char`\"{}\char`\"{}); @@ -545,15 +549,15 @@ submit button won't do much. \subsubsection{Seeing The Incoming Data} LON-CAPA automatically processing incoming POST data and exposes it -to you in the \texttt{\%ENV} hash. The data will appear in \texttt{\$ENV\{'form.\$varname'\}}, +to you in the \texttt{\%env} hash. The data will appear in \texttt{\$env\{'form.\$varname'\}}, where \texttt{\$varname} is the variable name of the HTML form element. In this case, since we have an element named {}``submission'', a -{}``1'' will appear in \texttt{\$ENV\{'form.submission'\}} when +{}``1'' will appear in \texttt{\$env\{'form.submission'\}} when we hit the {}``Increment'' button. To see this, add the following after the \texttt{bodytag} call: \begin{lyxcode} -if~(\$ENV\{'form.submission'\})~\{ +if~(\$env\{'form.submission'\})~\{ ~~~~\$r->print('

Form~submitted.

'); @@ -568,9 +572,12 @@ Reload the tutorial code into the server When you hit {}``Increment'', {}``Form submitted.'' will appear. Note this only applies to POST'ed data. If you use GET, the data will -appear on the query string. For your code, this will show up in \texttt{\$ENV\{QUERY\_STRING\}}. +appear on the query string. For your code, this will show up in \texttt{\$env\{QUERY\_STRING\}}. If you want to invoke LON-CAPA's processing on that string, so you -see the variables in \texttt{\%ENV}, use \texttt{Apache::loncommon::get\_unprocessed\_cgi(\$ENV\{QUERY\_STRING\});}. +see the variables in \texttt{\%env}, use +\texttt{Apache::loncommon::get\_unprocessed\_cgi(\$env\{QUERY\_STRING\});}. +This is particularly useful for cases where input may be coming in via +either POST or GET. \subsubsection{Adding Checkboxes for Input} @@ -579,7 +586,8 @@ Now we want to add a checkbox column int we have a place to input our selections. In order to do that, we need to provide the rendering code with a subroutine that will take an \texttt{Apache::lonnavmaps::resource} object and return the string -we want to print, including the and tags. (For more information, +we want to print, including the \texttt{td} and +\texttt{/td} tags. (For more information, consult the \texttt{Apache::lonnavmaps::render} documentation.) Add the following after the second and last \texttt{send\_http\_header} line: @@ -617,7 +625,7 @@ Add the following code before the \textt code: \begin{lyxcode} -foreach~(keys~\%ENV)~\{ +foreach~(keys~\%env)~\{ ~~~~if~(substr(\$\_,~0,~10)~eq~'form.symb.')~\{ @@ -650,7 +658,7 @@ you can't depend on being on the same sy Let's go ahead and retrieve the hash we're going to store. If it doesn't already exist, it will end up getting created implicitly. Before the -\texttt{foreach (keys \%ENV)}, add +\texttt{foreach (keys \%env)}, add \begin{lyxcode} my~\%countHash~=~Apache::lonnet::restore('tutorial'); @@ -672,7 +680,7 @@ Replace the \texttt{foreach} loop that i this: \begin{lyxcode} -foreach~(keys~\%ENV)~\{ +foreach~(keys~\%env)~\{ ~~~~if~(substr(\$\_,~0,~10)~eq~'form.symb.')~\{ @@ -727,6 +735,91 @@ my~\$renderArgs~=~\{~'cols'~=>~{[}Apache Viola! That should do it. +\subsection{Internationalization} + +In order for your handler to be able to submitted to LON-CAPA, we'd +really appreciate it if your handler was already +internationalized. ``Internationalization'' refers to the process of +adding hooks to code to make it easy to ``localize''. ``Localizing'' a +program means taking advantage of those hooks and create a file that +describes to the LON-CAPA web system how to display LON-CAPA in a +language other than English. + +For more complete information about Internationalization and +Localization, please refer to the Internationalization chapter. For +now, suffice it to say we need to wrap the text strings we are using +in the program in calls to the hook subroutine, which will be named +\texttt{\&mt}. + +First, at the top of your handler, near the other \texttt{use} +commands, add \texttt{use Apache::lonlocal;}. + +Second, find where all the strings are in your program and wrap them +in calls to \texttt{\&mt}. I see the following: + +\begin{enumerate} + +\item In the \texttt{bodytag} call, the title: + +\begin{lyxcode} +\$r->print(\&Apache::loncommon::bodytag(\&mt('Tutorial~Handler'),'','')); + +\end{lyxcode} + +\item In the two messages printed out showing the form submissions: + (Of course in this case these are really just debugging messages + we'd remove before actually using this handler. But let's localize + them for practice) + +\begin{lyxcode} +if~(\$env{'form.submission'})~{ + +~~~~\$r->print('

'.\&mt('Form submitted').'

'); + +}~else~{ + +~~~~\$r->print('

'.\&mt('No form information submitted.').'

'); + +} + +\end{lyxcode} + +Note we do \emph{not} generally want to wrap HTML tags unless we are +absolutely forced to; those are constant across human languages and +would only burder the translators with stuff they should not need to +deal with. + +\item The label of the button we've created: + +\begin{lyxcode} +\$r->print(''); + +\end{lyxcode} + +\end{enumerate} + +Note we only need to wrap things the human user will see; we don't +need to wrap the \texttt{tutorial} parameter to the +\texttt{Apache::lonnet::restore} call, for instance, and in fact wierd +things could happen if we did! Also note that resource names and such +are already as internationalized as they are going to get, so we don't +need to worry about them. + +Since the internationalization system will return the value passed to +\texttt{\&mt} by default if it can't find a translation, it's safe to +internationalize code before translations exist, and in fact it's a +necessary step. + +Also note that punctuation should be wrapped in the \texttt{\&mt} +calls, including things like trailing periods, since not all languages +have the same punctuation standards as English. + +This only covers simple internationalization. This can take you a long +way, but if you encounter a more difficult problem, please send a note +to the \texttt{lon-capa-dev@mail.lon-capa.org} mailing list. + \subsection{Complete Code Listing} For your reference, I include the complete code listing for the tutorial @@ -743,6 +836,8 @@ use~Apache::lonnavmaps; use~Apache::Constants~qw(:common); +use~Apache::lonlocal; + ~ =pod @@ -781,7 +876,7 @@ sub~handler~\{ ~~~~if~(\$r->header\_only)~\{ -~~~~~~~~if~(\$ENV\{'browser.mathml'\})~\{ +~~~~~~~~if~(\$env\{'browser.mathml'\})~\{ ~~~~~~~~~~~~\$r->content\_type('text/xml'); @@ -799,7 +894,7 @@ sub~handler~\{ ~~~~\#~Send~header,~don't~cache~this~page -~~~~if~(\$ENV\{'browser.mathml'\})~\{ +~~~~if~(\$env\{'browser.mathml'\})~\{ ~~~~~~~~\$r->content\_type('text/xml'); @@ -827,17 +922,17 @@ sub~handler~\{ ~~~~\$r->print('Tutorial~Page'); -~~~~\$r->print(\&Apache::loncommon::bodytag('Tutorial~Handler','','')); +~~~~\$r->print(\&Apache::loncommon::bodytag(\&mt('Tutorial~Handler'),'','')); -~~~~if~(\$ENV\{'form.submission'\})~\{ +~~~~if~(\$env\{'form.submission'\})~\{ -~~~~~~~~\$r->print('

Form~submitted.

'); +~~~~~~~~\$r->print('

'~.~\&mt('Form~submitted.')~.'

'); ~~~~\}~else~\{ -~~~~~~~~\$r->print('

No~form~information~submitted.

'); +~~~~~~~~\$r->print('

'~.~\&mt('No~form~information~submitted.')~.~'

'); ~~~~\} @@ -847,7 +942,7 @@ sub~handler~\{ ~~~~my~\%newHash~=~(); -~~~~foreach~(keys~\%ENV)~\{ +~~~~foreach~(keys~\%env)~\{ ~~~~~~~~if~(substr(\$\_,~0,~10)~eq~'form.symb.')~\{ @@ -881,7 +976,7 @@ sub~handler~\{ ~~~~~~~~~~~~~~\char`\"{}name='submission'~value='1'~/>\char`\"{}); -~~~~\$ENV\{'form.condition'\}~=~1; +~~~~\$env\{'form.condition'\}~=~1; ~~~~my~\$renderArgs~=~\{~'cols'~=>~{[}Apache::lonnavmaps::resource, @@ -895,7 +990,9 @@ sub~handler~\{ -~~~~\$r->print(''); +~~~~\$r->print(''); ~~~~\$r->print('');