From 40e1a1e6a0ab09c8088183f91b4fe3752c207cd2 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Tue, 12 Jan 2016 23:02:18 +0000 Subject: moodle (12jan16) git-svn-id: svn://tug.org/texlive/trunk@39367 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/tex/latex/moodle/moodle.sty | 2136 +++++++++++++++++++++++++ 1 file changed, 2136 insertions(+) create mode 100644 Master/texmf-dist/tex/latex/moodle/moodle.sty (limited to 'Master/texmf-dist/tex/latex/moodle') diff --git a/Master/texmf-dist/tex/latex/moodle/moodle.sty b/Master/texmf-dist/tex/latex/moodle/moodle.sty new file mode 100644 index 00000000000..dedc78c95c9 --- /dev/null +++ b/Master/texmf-dist/tex/latex/moodle/moodle.sty @@ -0,0 +1,2136 @@ +%% +%% This is file `moodle.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% moodle.dtx (with options: `package') +%% +%% This is a generated file. +%% +%% Copyright (C) 2016 by Anders Hendrickson +%% +%% This work may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either version 1.3 +%% of this license or (at your option) any later version. +%% The latest version of this license is in +%% http://www.latex-project.org/lppl.txt +%% and version 1.3 or later is part of all distributions of LaTeX +%% version 2005/12/01 or later. +%% +\NeedsTeXFormat{LaTeX2e}[1999/12/01] +\ProvidesPackage{moodle} + [2016/01/11 v0.5 Moodle quiz XML generation] +\newif\ifmoodle@draftmode +\newif\ifmoodle@tikzloaded + +%%DECLARATION OF OPTIONS +\DeclareOption{draft}{\moodle@draftmodetrue} + +\moodle@draftmodefalse +\moodle@tikzloadedfalse + +\ProcessOptions + +\RequirePackage{environ} %To be able to take environment body as a macro argument +\RequirePackage{xkeyval} %For key-handling +\RequirePackage{amssymb} %For \checkmark symbol +\RequirePackage{trimspaces} %To remove extra spaces from strings +\RequirePackage{etex} %Expansion control, detokenization, etc. +\RequirePackage{etoolbox}%List management +\RequirePackage{xpatch} %To patch commands easily in HTML mode +\RequirePackage{array} %For formatting tables in the LaTeX mode of Clozes +\RequirePackage{ifplatform} % To choose Ghostscript commands +\RequirePackage{ifpdf} % Needed to know whether we can convert output from PDF to PNG + +\RequirePackage{getitems} %To gather the header and items + +\let\xa=\expandafter +\def\@star{*}% +\def\@hundred{100}% +\def\@moodle@empty{}% +\def\@relax{\relax}% +\def\jobnamewithsuffixtomacro#1#2{% + \filenamewithsuffixtomacro{#1}{\jobname}{#2}% +} +\def\@jn@quote{"}% +\def\filenamewithsuffixtomacro#1#2#3{% + % #1 = macro to create + % #2 = filename to add suffix to + % #3 = suffix to add + \edef\jn@suffix{#3}% + \def\jn@macro{#1}% + \xa\testforquote#2\@jn@rdelim +} +\def\testforquote#1#2\@jn@rdelim{% + \def\jn@test@i{#1}% + \ifx\jn@test@i\@jn@quote + % Involves quotes + \edef\jn@next{"\jn@stripquotes#1#2\jn@suffix"}% + \else + \edef\jn@next{#1#2\jn@suffix}% + \fi + \xa\xdef\jn@macro{\jn@next}% +} +\def\jn@stripquotes"#1"{#1}% + +\jobnamewithsuffixtomacro{\outputfilename}{-moodle.xml} +\newwrite\moodle@outfile +\def\openmoodleout{% + \immediate\openout\moodle@outfile=\outputfilename\relax + \writetomoodle{}% + \writetomoodle{}% + \writetomoodle{ }% +}% +\def\closemoodleout{% + \writetomoodle{ }% + \writetomoodle{}% + \immediate\closeout\moodle@outfile +}% +\def\calculateindent#1{% + \bgroup + \count0=\number#1\relax + \gdef\moodle@indent{}% + \calculateindent@int + \egroup +}% +\def\calculateindent@int{% + \ifnum\count0>0\relax + \g@addto@macro{\moodle@indent}{\otherspace}% + \advance\count0 by -1\relax + \expandafter + \calculateindent@int + \fi +}% +\newcommand\writetomoodle[2][0]{% + \edef\test@ii{#2}% + \ifnum#1=0\relax + \immediate\write\moodle@outfile{\test@ii}% + \else + \calculateindent{#1}% + \immediate\write\moodle@outfile{\moodle@indent\trim@pre@space{\test@ii}}% + \fi +}% +\newenvironment{quiz}[2][]% + {\setkeys{moodle}{#1}% + \@moodle@ifgeneratexml{% + \openmoodleout% + \setcategory{#2}% + }{}% + \subsection*{#2}% + \begin{enumerate}% + } + {\end{enumerate}% + \@moodle@ifgeneratexml{\closemoodleout}{}} + +{\catcode`\$=12\catcode`\ =12% +\gdef\setcategory#1{% +\writetomoodle{}% +\writetomoodle{ }% +\writetomoodle{ $module$/#1}% +\writetomoodle{ }% +\writetomoodle{}% +\writetomoodle{ }% +}}% +\def\passvalueaftergroup#1{% + \xa\xa\xa\gdef\xa\xa\csname moodle@remember@\string#1\endcsname\xa{\xa\def\xa#1\xa{#1}}% + \xa\aftergroup\csname moodle@remember@\string#1\endcsname +} +\long\def\@moodle@ifgeneratexml#1#2{% + % If we are generating XML, do #1; otherwise do #2. + \tikzifexternalizing{% + % This run of LaTeX is currently ONLY generating a Tikz image + % to be saved in an external file. We do NOT want to waste time + % generating XML, and moreover trying to do so would cause errors + % because of file dependencies. + #2% + }{% + \ifmoodle@draftmode + #2% + \else + #1% + \fi + }% +} +\def\moodleset#1{\setkeys{moodle}{#1}}% +\def\generate@moodle@write@code{% + \@ifnextchar*\generate@moodle@write@data\generate@moodle@write@html +}% + +\def\generate@moodle@write@html#1<#2>#3{% + % #1 = NAME for \moodle@writeNAME + % #2 = HTML tag + % #3 = what, exactly, to write + \xa\gdef\csname moodle@write#1\endcsname{% + \xa\def\xa\test@iii\xa{#3}% + \ifx\test@iii\@moodle@empty + \writetomoodle[2]{ <#2 format="html">}% + \else + \xa\converttohtmlmacro\xa\moodle@htmltowrite\xa{#3}% + \writetomoodle[2]{ <#2 format="html">}% + \writetomoodle[4]{ \moodle@htmltowrite

]]>
}% + \writetomoodle[2]{ }% + \fi + }% +}% + +\def\generate@moodle@write@data*#1<#2>#3{% + % #1 = NAME for \moodle@writeNAME + % #2 = HTML tag + % #3 = what, exactly, to write + \xa\gdef\csname moodle@write#1\endcsname{% + \writetomoodle[2]{ <#2>#3}% + }% +}% + +%% QUESTIONNAME + \define@cmdkey{moodle}[moodle@]{questionname}{}% + \gdef\moodle@writequestionname{% + \writetomoodle[2]{}% + \writetomoodle[4]{ \moodle@questionname}% + \writetomoodle[2]{}% + }% + +%% QUESTIONTEXT + %I tried to use questiontext as a key, but it doesn't seem to work. + %The trouble is that xkeyval has trouble parsing a key with a \par token followed by a comma within brackets, + %like \setkeys{moodle}{questiontext={ABC\par [D,E]}} + %It's not worth trying to fix. + + \long\def\questiontext#1{% + %\converttohtmlmacro\myoutput{#1}% + %\let\moodle@questiontext=\myoutput% + \def\moodle@questiontext{#1}% + }% + \generate@moodle@write@code{questiontext}{\moodle@questiontext}%{% + +%% PENALTY FOR WRONG ATTEMPT + \define@cmdkey{moodle}[moodle@]{penalty}[0.1000000]{}% + \generate@moodle@write@code*{penalty}{\moodle@penalty}% + \moodleset{penalty}% + +%% FEEDBACK + % Moodle allows for feedback tailored to each question, + % and feedback tailored to each right or wrong answer. + % We shall use the key 'feedback' to record both kinds of feedback, + % relying on TeX's grouping mechanism to keep them apart. + % When it comes time to write them to XML, + % \moodle@writegeneralfeedback uses the HTML tag + % whereas \moodle@writefeedback uses the tag . + % Note that the general feedback is NOT inherited by each answer! + \define@cmdkey{moodle}[moodle@]{feedback}[]{}% + \generate@moodle@write@code{generalfeedback}{\moodle@feedback}% + \generate@moodle@write@code{feedback}{\moodle@feedback}% + \moodleset{feedback}% + +%% DEFAULT GRADE + %The next line creates \moodle@defaultgrade, + %which is how many points the quiz question is worth. + %Key calls like [default grade=7] set \moodle@defaultgrade. + \define@cmdkey{moodle}[moodle@]{default grade}[1.0]{}% + %Next, makes 'points' a synonym for 'default grade' + \define@key{moodle}{points}[1.0]{\xa\def\csname moodle@default grade\endcsname{#1}} + \generate@moodle@write@code*{defaultgrade}{\csname moodle@default grade\endcsname}% + \moodleset{default grade=1.0} %This sets the default. + +%% HIDDEN + \define@boolkey{moodle}[moodle@]{hidden}[true]{}% + \generate@moodle@write@code*{hidden}{\ifmoodle@hidden 1\else 0\fi}% + \moodleset{hidden=false}% + +\def\moodle@writecommondata{% + \moodle@writequestionname% + \moodle@writequestiontext% + \moodle@writedefaultgrade% + \moodle@writegeneralfeedback% + \moodle@writepenalty% + \moodle@writehidden% +}% + + +%% FRACTION -- how much this answer is worth out of 100 percent + \define@cmdkey{moodle}[moodle@]{fraction}[100]{}% + %We do not create \moodle@writefraction, because the fraction occurs in + %the XML within the answer tag, like . + \moodleset{fraction=100} %This sets the default. + +%% SINGLE and MULTIPLE -- for multichoice, is there 1 right answer or more than 1? + \define@boolkey{moodle}[moodle@]{single}[true]{}% + \generate@moodle@write@code*{single}{\ifmoodle@single true\else false\fi}% + \moodleset{single}% + %The key 'multiple' is an antonym to 'single'. + \define@boolkey{moodle}[moodle@]{multiple}[true]{\ifmoodle@multiple\moodle@singlefalse\else\moodle@singletrue\fi}% + +%% SHUFFLE ANSWERS + \define@boolkey{moodle}[moodle@]{shuffle}[true]{}% + \generate@moodle@write@code*{shuffle}{\ifmoodle@shuffle 1\else 0\fi}% + \moodleset{shuffle=true}% + +%% TO DO: CORRECTFEEDBACK +%% TO DO: PARTIALLYCORRECTFEEDBACK +%% TO DO: INCORRECTFEEDBACK +%% TO DO: NUMCORRECT key + +%% NUMBERING -- for numbering of multichoice questions + \define@choicekey{moodle}{numbering}% + {alpha,alph,Alpha,Alph,arabic,roman,Roman,% + abc,ABC,123,iii,IIII,none}[abc]{% + \def\moodle@numbering{#1}% + \def\test@@i{#1}% + \ifx\test@@i\@moodle@alpha + \def\moodle@numbering{abc}\fi + \ifx\test@@i\@moodle@alph + \def\moodle@numbering{abc}\fi + \ifx\test@@i\@moodle@Alpha + \def\moodle@numbering{ABC}\fi + \ifx\test@@i\@moodle@Alph + \def\moodle@numbering{ABC}\fi + \ifx\test@@i\@moodle@arabic + \def\moodle@numbering{123}\fi + \ifx\test@@i\@moodle@roman + \def\moodle@numbering{iii}\fi + \ifx\test@@i\@moodle@Roman + \def\moodle@numbering{IIII}\fi + }% + %'answer numbering' will be a synonym to 'numbering' + \define@key{moodle}{answer numbering}[abc]{\setkeys{moodle}{numbering={#1}}}% + \generate@moodle@write@code*{answernumbering}{\moodle@numbering}% + %N.B. if we did not set the default here, then \moodle@numbering would be undefined, causing problems. + \moodleset{answer numbering=abc}% + + \def\@moodle@alpha{alpha}% + \def\@moodle@Alpha{Alpha}% + \def\@moodle@alph{alph}% + \def\@moodle@Alph{Alph}% + \def\@moodle@arabic{arabic}% + \def\@moodle@roman{roman}% + \def\@moodle@Roman{Roman}% + \def\@moodle@abc{abc}% + \def\@moodle@ABC{ABC}% + \def\@moodle@arabicnumbers{123}% + \def\@moodle@iii{iii}% + \def\@moodle@IIII{IIII}% + \def\@moodle@none{none}% + \def\moodle@obeynumberingstyle{% + \ifx\moodle@numbering\@moodle@abc + \renewcommand\theenumii{\alph{enumii}}% + \fi + \ifx\moodle@numbering\@moodle@ABC + \renewcommand\theenumii{\Alph{enumii}}% + \fi + \ifx\moodle@numbering\@moodle@arabicnumbers + \renewcommand\theenumii{\arabic{enumii}}% + \fi + \ifx\moodle@numbering\@moodle@iii + \renewcommand\theenumii{\roman{enumii}}% + \fi + \ifx\moodle@numbering\@moodle@IIII + \renewcommand\theenumii{\Roman{enumii}}% + \fi + \ifx\moodle@numbering\@moodle@none + \renewcommand\labelenumii{$\bullet$~}% + \fi + } + %TO DO: * In the PDF, how should 'none' in a multi look different from + % short answer or numerical options? + % * Instead of \theenumi and \labelenumi, + % use \@enumdepth to automatically set the correct depth. + +%% DISPLAY MODE -- affects Cloze multiple choice questions only. + % 0 = inline, 1 = vertical, 2 = horizontal + \def\moodle@multi@mode{0}% + \define@key{moodle}{inline}[]{\def\moodle@multi@mode{0}}% + \define@key{moodle}{vertical}[]{\def\moodle@multi@mode{1}}% + \define@key{moodle}{horizontal}[]{\def\moodle@multi@mode{2}}% +%% TOLERANCE + \define@cmdkey{moodle}[moodle@]{tolerance}[0]{}% + \moodleset{tolerance=0}% + %There is no \moodle@writetolerance, because in the XML the + %tolerance is given within the answer tag, + %like . + +%% CASE SENSITIVE + \define@boolkey{moodle}[moodle@]{case sensitive}[true]{}% + \generate@moodle@write@code*{usecase}{\csname ifmoodle@case sensitive\endcsname 1\else 0\fi}% + % We make 'usecase' a synonym for 'case sensitive'. + \define@boolkey{moodle}[moodle@]{usecase}[true]{\ifmoodle@usecase\csname moodle@case sensitivetrue\endcsname\else\csname moodle@case sensitivefalse\endcsname\fi}% + \moodleset{case sensitive=false}% +%% DRAG-AND-DROP FORMAT + \define@boolkey{moodle}[moodle@]{draganddrop}[true]{}% + % We make 'dd' and 'dragdrop' and 'drag and drop' synonyms for 'draganddrop'. + \define@boolkey{moodle}[moodle@]{dd}[true]{\ifmoodle@dd\moodle@draganddroptrue\else\moodle@draganddropfalse\fi}% + \define@boolkey{moodle}[moodle@]{drag and drop}[true]{\moodle@ddsynonym}% + \def\moodle@ddsynonym{% + \csname ifmoodle@drag and drop\endcsname + \moodle@draganddroptrue + \else + \moodle@draganddropfalse + \fi + } + \moodleset{draganddrop=false}% +%% EDITOR + \def\@moodle@html{html}% + \def\@moodle@htmlfile{html+file}% + \def\@moodle@text{text}% + \def\@moodle@plain{plain}% + \def\@moodle@monospaced{monospaced}% + \def\@moodle@file{file}% + \def\@moodle@noinline{noinline}% + \define@choicekey{moodle}{response format}% + {html,html+file,text,monospaced,file}[html]% + {\def\test@i{#1}% + \ifx\test@i\@moodle@html + % HTML Editor + \def\moodle@responseformat{editor}% + \fi + \ifx\test@i\@moodle@htmlfile + % HTML Editor with File Picker + \def\moodle@responseformat{editorfilepicker}% + \fi + \ifx\test@i\@moodle@text + % Plain text + \def\moodle@responseformat{plain}% + \fi + \ifx\test@i\@moodle@plain + % Plain text + \def\moodle@responseformat{plain}% + \fi + \ifx\test@i\@moodle@monospaced + % Plain text, monospaced font + \def\moodle@responseformat{monospaced}% + \fi + \ifx\test@i\@moodle@file + % No inline text (i.e., attachments only) + \def\moodle@responseformat{noinline}% + \fi + \ifx\test@i\@moodle@noinline + % No inline text (i.e., attachments only) + \def\moodle@responseformat{noinline}% + \fi + }% + \generate@moodle@write@code*{responseformat}{\moodle@responseformat}% + \moodleset{response format=html}% + %N.B. if we did not set a default, then \moodle@responseformat would be undefined, causing problems. + +%% RESPONSE REQUIRED + \define@boolkey{moodle}[moodle@]{response required}[true]{}% + % TO DO: Make synonym 'required' + \generate@moodle@write@code*{responserequired}{\csname ifmoodle@response required\endcsname 1\else 0\fi}% + \moodleset{response required=false}% + +%% RESPONSEFIELDLINES + \define@cmdkey{moodle}[moodle@]{response field lines}[15]{}% + \generate@moodle@write@code*{responsefieldlines}{\csname moodle@response field lines\endcsname}% + %Make synonyms 'input box size' or 'height' or 'lines'? + \moodleset{response field lines=15}% N.B. if we do not set a default, then \moodle@responseformat will be undefined, causing problems. + +%% ATTACHMENTS ALLOWED + \def\@moodle@unlimited{unlimited}% + \define@choicekey{moodle}{attachments allowed}{0,1,2,3,unlimited}[1]{% + \def\test@i{#1}% + \ifx\test@i\@moodle@unlimited + \def\moodle@attachmentsallowed{-1}% + \else + \def\moodle@attachmentsallowed{#1}% + \fi + } + \generate@moodle@write@code*{attachmentsallowed}{\moodle@attachmentsallowed} + \moodleset{attachments allowed=0}% + +%% ATTACHMENTS REQUIRED + \define@choicekey{moodle}{attachments required}{0,1,2,3}[1]{\def\moodle@attachmentsrequired{#1}}% + \generate@moodle@write@code*{attachmentsrequired}{\moodle@attachmentsrequired} + \moodleset{attachments required=0}% + +%% RESPONSE TEMPLATE + \define@key{moodle}{template}{\long\def\moodle@responsetemplate{#1}}% + \generate@moodle@write@code{responsetemplate}{\moodle@responsetemplate} + \moodleset{template={}}% +%% SHOWNUMCORRECT + \define@boolkey{moodle}[moodle@]{shownumcorrect}[true]{}% + \gdef\moodle@writeshownumcorrect{% + \if\moodle@shownumcorrect + \writetomoodle[4]{ }% + \fi + }% + \moodleset{shownumcorrect=false}% + +%% CLEARWRONG + \define@boolkey{moodle}[moodle@]{clearwrong}[true]{}% + \gdef\moodle@writeclearwrong{% + \if\moodle@clearwrong + \writetomoodle[4]{ }% + \fi + }% + \moodleset{clearwrong=false}% + + +\def\moodle@answers@xml{}% +\gdef\moodle@writeanswers{% + \writetomoodle{\moodle@answers@xml}% +}% + +\newcommand\addto@xml[3][0]{% + % #1 = spaces to indent (default=0) + % #2 = macro containing XML code (possibly empty) + % #3 = XML text to be appended to that macro (will be \edef'd) + \calculateindent{#1}% + \edef\xml@to@add{\moodle@indent\trim@pre@space{#3}}% + \ifx#2\@moodle@empty + \edef\newxml{\noexpand#2\xml@to@add}% + \else + \edef\newxml{\noexpand#2^^J\xml@to@add}% + \fi + \xa\xa\xa\def\xa\xa\xa#2\xa\xa\xa{\newxml}% +}% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TRUE/FALSE QUESTIONS %%%%%%%%%%%%%%%%% + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% DESCRIPTION 'QUESTIONS' %%%%%%%%%%%%% + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% CALCULATED %%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\def\moodle@makefrontend#1{% + \NewEnviron{#1}[2][]{% + \bgroup + \setkeys{moodle}{##1,questionname={##2}}% + \expandafter\gatheritems\xa{\BODY}% + \let\moodle@questionheader=\gatheredheader + %First, the LaTeX processing + \item \textbf{\moodle@questionname}\par + \noindent + \moodle@questionheader + \csname moodle@#1@latexprocessing\endcsname + %Now, writing information to XML + \@moodle@ifgeneratexml{% + \xa\questiontext\xa{\moodle@questionheader}% Save the question text. + \bgroup + \gdef\moodle@answers@xml{}% + \setkeys{moodle}{feedback={}}% + \xa\loopthroughitemswithcommand\xa{\csname save#1answer\endcsname}% + \passvalueaftergroup{\moodle@answers@xml}% + \egroup + \csname write#1question\endcsname + }{}% + \egroup + }% +} +\def\moodle@essay@latexprocessing{% + % Moodle cannot automatically grade an essay, + % but if the user puts \item's in, we can list them in an itemize as notes. + \ifnum\c@numgathereditems>0\relax + \par\noindent Notes: (not included in XML) + \begin{itemize} \setlength\itemsep{0pt}\setlength\parskip{0pt}% + \loopthroughitemswithcommand{\moodle@print@essay@answer}% + \end{itemize}% + \fi +} + +\NewEnviron{essay}[2][]{% + \bgroup + \setkeys{moodle}{#1,questionname={#2}}% + \expandafter\gatheritems\expandafter{\BODY}% + \let\moodle@questionheader=\gatheredheader + %First, the LaTeX processing. + \item \textbf{\moodle@questionname}\par + \noindent + \moodle@questionheader + \csname moodle@essay@latexprocessing\endcsname + %Now, writing information to memory. + \@moodle@ifgeneratexml{% + \xa\questiontext\xa{\moodle@questionheader}% Save the question text. + \bgroup + \gdef\moodle@answers@xml{}% + % + \ifnum\c@numgathereditems=0\relax + \addto@xml[2]\moodle@answers@xml{}% + \else + \addto@xml[2]\moodle@answers@xml{1\relax + \addto@xml[4]\moodle@answers@xml{
    }% + \fi + \loopthroughitemswithcommand{\moodle@savegraderinfo}% + \ifnum\c@numgathereditems>1\relax + \addto@xml[4]\moodle@answers@xml{
}% + \fi + \addto@xml[2]\moodle@answers@xml{]]>
}% + \fi + % + \passvalueaftergroup{\moodle@answers@xml}% + \egroup + \writeessayquestion + }{}% + \egroup +}% + +%%%% TO DO +%%%% To make essay work will be tough. +%%%% Every line from \ifnum\c@numgathereditems=0\relax through its \else and \fi, +%%%% with the exception of +%%%% \xa\loopthroughitemswithcommand\xa{\csname save#1answer\endcsname}% +%%%% , does not exist in our current \moodle@makefrontend code. +%%%% How can we cope? +%%%% +%%%% Idea: change \moodle@makefrontend so that +%%%% 1. if \c@numgathereditems=0, we don't do anything. +%%%% 2. it calls a preamble and postamble around the \loopthroughitemswithcommand. +%%%% Like this: +%%%% +%%%% \@moodle@ifgeneratexml{% +%%%% \xa\questiontext\xa{\moodle@questionheader}% Save the question text. +%%%% \bgroup +%%%% \gdef\moodle@answers@xml{}% +%%%% \setkeys{moodle}{feedback={}}% +%%%% \@ifundefined{moodle@#1@answers@preamble}{}{}% +%%%% \csname moodle@#1@answers@preamble\endcsname +%%%% \ifnum\c@numgathereditems=0\relax +%%%% \relax +%%%% \else +%%%% \xa\loopthroughitemswithcommand\xa{\csname save#1answer\endcsname}% +%%%% \fi +%%%% \@ifundefined{moodle@#1@answers@postamble}{}{}% +%%%% \csname moodle@#1@answers@postamble\endcsname +%%%% \passvalueaftergroup{\moodle@answers@xml}% +%%%% \egroup +%%%% \csname write#1question\endcsname +%%%% }{}% +%%%% The \@ifundefined lines should automatically define the +%%%% \...@preamble \...@postamble macros to be \relax if they don't exist already. + +\gdef\writeessayquestion{% + \writetomoodle{}% + \moodle@writecommondata% + \moodle@writeresponserequired% + \moodle@writeresponseformat% + \moodle@writeresponsefieldlines% + \moodle@writeattachmentsallowed% + \moodle@writeattachmentsrequired% + \moodle@writeanswers% The 'answers' XML really contains the grader info. + \moodle@writeresponsetemplate% + \writetomoodle{}% +}% + +\def\moodle@print@essay@answer#1{% + \item #1% +}% + +\def\moodle@savegraderinfo#1{% + \bgroup + \moodle@savegraderinfo@int#1\moodle@answer@rdelim + \passvalueaftergroup{\moodle@answers@xml}% + \egroup +}% +\newcommand\moodle@savegraderinfo@int[1][]{% + \setkeys{moodle}{fraction=0,#1}% + \moodle@savegraderinfo@int@int% +}% +\def\moodle@savegraderinfo@int@int#1\moodle@answer@rdelim{% + \xa\converttohtmlmacro\xa\moodle@answertext@html\xa{#1}% + %\trim@spaces@in\moodle@answertext + \ifnum\c@numgathereditems>1\relax + \addto@xml[6]{\moodle@answers@xml}{
  • \moodle@answertext@html
  • }% + \else + \addto@xml[4]{\moodle@answers@xml}{\moodle@answertext@html}% + \fi +}% +\def\blank{\rule{1in}{0.5pt}}% + + +\moodle@makefrontend{shortanswer}% + +\def\moodle@shortanswer@latexprocessing{% + \begin{itemize} \setlength\itemsep{0pt}\setlength\parskip{0pt}% + \loopthroughitemswithcommand{\moodle@print@shortanswer@answer}% + \end{itemize}% +} + + \def\moodle@print@shortanswer@answer#1{% + \moodle@print@shortanswer@answer@int#1\@rdelim + }% + \newcommand\moodle@print@shortanswer@answer@int[1][]{% + \setkeys{moodle}{#1}% + \moodle@print@shortanswer@answer@int@int% + }% + \def\moodle@print@shortanswer@answer@int@int#1\@rdelim{% + \ifx\moodle@fraction\@hundred + \item #1\quad$\checkmark$% + \else + \item #1\quad (\moodle@fraction\%)% + \fi + }% + +\def\saveshortansweranswer#1{% + \bgroup + \saveshortansweranswer@int#1\moodle@answer@rdelim + \passvalueaftergroup{\moodle@answers@xml}% + \egroup +}% + \newcommand\saveshortansweranswer@int[1][]{% + \setkeys{moodle}{fraction=100,#1}% %%%%%% DEFAULT VALUE IS 100% + \saveshortansweranswer@int@int% + }% + \def\saveshortansweranswer@int@int#1\moodle@answer@rdelim{% + \def\moodle@answertext{#1}% + \addto@xml[2]{\moodle@answers@xml}{}% + \addto@xml[4]{\moodle@answers@xml}{ \moodle@answertext}% + \ifx\moodle@feedback\@empty\relax\else + \addto@xml[4]{\moodle@answers@xml}{ \moodle@feedback

    ]]>
    }% + \fi + \addto@xml[2]{\moodle@answers@xml}{
    }% + }% + +\gdef\writeshortanswerquestion{% + \writetomoodle{}% + \moodle@writecommondata% + \moodle@writeusecase% + \moodle@writeanswers% + \writetomoodle{}% +}% +\moodle@makefrontend{numerical}% + +\def\moodle@numerical@latexprocessing{% + \begin{itemize} \setlength\itemsep{0pt}\setlength\parskip{0pt}% + \loopthroughitemswithcommand{\moodle@print@numerical@answer}% + \end{itemize}% +} + + \def\moodle@print@numerical@answer#1{% + \moodle@print@numerical@answer@int#1\@rdelim + }% + \newcommand\moodle@print@numerical@answer@int[1][]{% + \setkeys{moodle}{#1}% + \moodle@print@numerical@answer@int@int% + }% + \def\moodle@print@numerical@answer@int@int#1\@rdelim{% + \ifdim0pt=\moodle@tolerance pt\relax + \def\moodle@numericalprint@tolerance{}% + \else + \edef\moodle@numericalprint@tolerance{\noexpand\pm\moodle@tolerance}% + \fi + \ifx\moodle@fraction\@hundred + \item $#1\moodle@numericalprint@tolerance\quad\checkmark$% + \else + \item $#1\moodle@numericalprint@tolerance$\quad (\moodle@fraction\%)% + \fi + }% + +\def\savenumericalanswer#1{% + \bgroup + \savenumericalanswer@int#1\moodle@answer@rdelim + \passvalueaftergroup{\moodle@answers@xml}% + \egroup +}% + \newcommand\savenumericalanswer@int[1][]{% + \setkeys{moodle}{fraction=100,#1}% %%%%%% DEFAULT VALUE IS 100% + \savenumericalanswer@int@int% + }% + \def\savenumericalanswer@int@int#1\moodle@answer@rdelim{% + \def\moodle@answertext{#1}% + \addto@xml[2]{\moodle@answers@xml}{}% + \addto@xml[4]{\moodle@answers@xml}{ \moodle@answertext}% + \addto@xml[4]{\moodle@answers@xml}{ \moodle@tolerance}% + \ifx\moodle@feedback\@empty\relax\else + \addto@xml[4]{\moodle@answers@xml}{ \moodle@feedback

    ]]>
    }% + \fi + \addto@xml[2]{\moodle@answers@xml}{
    }% + }% + +\gdef\writenumericalquestion{% + \writetomoodle{}% + \moodle@writecommondata% + \moodle@writeanswers% + \writetomoodle{}% +}% + +\moodle@makefrontend{multi} + +\def\moodle@multi@latexprocessing{% + \moodle@countcorrectanswers + \begin{enumerate}\moodle@obeynumberingstyle + %\renewcommand{\theenumi}{\alph{enumi}}% + \setlength\itemsep{0pt}\setlength\parskip{0pt}% + \loopthroughitemswithcommand{\moodle@print@multichoice@answer}% + \end{enumerate}% +} + \def\moodle@print@multichoice@answer#1{% + \moodle@print@multichoice@answer@int#1\@rdelim + }% + \newcommand\moodle@print@multichoice@answer@int[1][]{% + \setkeys{moodle}{fraction=0,#1}% + \moodle@print@multichoice@answer@int@int + }% + \def\moodle@print@multichoice@answer@int@int#1#2\@rdelim{% + \def\test@i{#1}% + \ifmoodle@single + \ifx\test@i\@star + \item #2$~\checkmark$% + \else + \item #1#2% + \fi + \else + \ifx\test@i\@star + \item #2% + \setkeys{moodle}{fraction=\moodle@autopoints}% + \else + \item #1#2% + \fi + $~(\moodle@fraction\%)$ + \fi + }% + + \newcounter{moodle@numcorrectanswers}% + \newlength{\moodle@pointspercorrect}% + \def\moodle@countcorrectanswers{% + \setcounter{moodle@numcorrectanswers}{0}% + \global\setlength{\moodle@pointspercorrect}{100pt}% + \loopthroughitemswithcommand{\moodle@countcorrectanswers@a}% + \ifnum0=\c@moodle@numcorrectanswers\relax + \PackageError{moodle}{No correct answers given for multiple choice question.}{Please mark at least one answer correct.}% + \gdef\moodle@autopoints{0}% + \else + \global\divide\moodle@pointspercorrect by \c@moodle@numcorrectanswers\relax + \edef\moodle@autopoints{\strip@pt\moodle@pointspercorrect}% + \fi + } + \def\moodle@countcorrectanswers@a#1{% + %The grouping is to keep key answer-specific key changes local. + \bgroup + \moodle@countcorrectanswers@b#1\moodle@answer@rdelim + \egroup + }% + \newcommand\moodle@countcorrectanswers@b[1][]{% + \setkeys{moodle}{fraction=0,#1}% + \moodle@countcorrectanswers@c% + }% + \def\moodle@countcorrectanswers@c#1#2\moodle@answer@rdelim{% + \def\test@i{#1}% + \ifx\test@i\@star + \stepcounter{moodle@numcorrectanswers}% + \else + \global\addtolength{\moodle@pointspercorrect}{-\moodle@fraction pt}% + \fi + }% + \def\moodle@setautopoints#1pt{% + \gdef\moodle@autopoints{#1}% + } + + +\def\savemultianswer#1{% + \bgroup + \savemultianswer@int#1\moodle@answer@rdelim + \passvalueaftergroup{\moodle@answers@xml}% + \egroup +}% + \newcommand\savemultianswer@int[1][]{% + \setkeys{moodle}{fraction=0,#1}% + \savemultianswer@int@int% + }% + \def\savemultianswer@int@int#1#2\moodle@answer@rdelim{% + \def\test@i{#1}% + \ifx\test@i\@star + \ifmoodle@single + \setkeys{moodle}{fraction=100}% + \else + \setkeys{moodle}{fraction=\moodle@autopoints}% + \fi + \def\moodle@answertext{#2}% + \else + \def\moodle@answertext{#1#2}% + \fi + \trim@spaces@in\moodle@answertext + \addto@xml[2]{\moodle@answers@xml}{}% + \xa\converttohtmlmacro\xa\moodle@answertext@html\xa{\moodle@answertext}% + \addto@xml[4]{\moodle@answers@xml}{ \moodle@answertext@html

    ]]>
    }% + \ifx\moodle@feedback\@empty\relax\else + \addto@xml[4]{\moodle@answers@xml}{ \moodle@feedback

    ]]>
    }% + \fi + \addto@xml[2]{\moodle@answers@xml}{
    }% + }% + +\gdef\writemultiquestion{% + \writetomoodle{}% + \moodle@writecommondata% + \moodle@writesingle% + \moodle@writeshuffle% + \moodle@writeanswernumbering% + \moodle@writeanswers% + \writetomoodle{}% +}% +\let\answer=\hfill + +\moodle@makefrontend{matching} + +\def\moodle@matching@latexprocessing{% + \bgroup + \let\answer=\hfill + \begin{enumerate}\renewcommand{\theenumi}{\alph{enumi}}\setlength\itemsep{0pt}\setlength\parskip{0pt}% + \loopthroughitemswithcommand{\moodle@print@matching@answer}% + \end{enumerate}% + \egroup +} + \long\def\moodle@print@matching@answer#1{% + \moodle@print@matching@answer@int#1\@rdelim + }% + \newcommand\moodle@print@matching@answer@int[1][]{% + \moodle@print@matching@answer@int@int\relax + }% + \long\def\moodle@print@matching@answer@int@int#1\answer#2\@rdelim{% + \item #1\hfill #2% + }% + +\long\def\savematchinganswer#1{% + \bgroup + \savematchinganswer@int#1\moodle@answer@rdelim% + \passvalueaftergroup{\moodle@answers@xml}% + \egroup +}% + \newcommand\savematchinganswer@int[1][]{% + \setkeys{moodle}{#1}% + \xa\savematchinganswer@int@int\space% + }% + \long\def\savematchinganswer@int@int#1\answer#2\moodle@answer@rdelim{% + % Note that #1 may simply be \relax. + \def\moodle@subquestiontext{#1}% + \def\moodle@subanswertext{#2}% + \trim@spaces@in\moodle@subquestiontext + \xa\converttohtmlmacro\xa\moodle@subquestiontext@htmlized\xa{\moodle@subquestiontext}% + \trim@spaces@in\moodle@subanswertext + \ifmoodle@draganddrop + \xa\converttohtmlmacro\xa\moodle@subanswertext@htmlized\xa{\moodle@subanswertext}% + \fi + \addto@xml[2]{\moodle@answers@xml}{}% + \ifx\moodle@subquestiontext\@empty + \addto@xml[4]{\moodle@answers@xml}{ }% + \else + \addto@xml[4]{\moodle@answers@xml}{ \moodle@subquestiontext@htmlized

    ]]>
    }% + \fi + \ifmoodle@draganddrop + \addto@xml[4]{\moodle@answers@xml}{ \moodle@subanswertext@htmlized

    ]]>
    }% + \else + \addto@xml[4]{\moodle@answers@xml}{ \moodle@subanswertext}% + \fi + \ifx\moodle@feedback\@empty\relax\else + \addto@xml[4]{\moodle@answers@xml}{ \moodle@feedback

    ]]>
    }% + \fi + \addto@xml[2]{\moodle@answers@xml}{
    }% + }% + +\gdef\writematchingquestion{% + \ifmoodle@draganddrop + \writetomoodle{}% + \else + \writetomoodle{}% + \fi + \moodle@writecommondata% + \moodle@writesingle% + \moodle@writeshuffle% + \moodle@writeanswernumbering% + \moodle@writeanswers% + \writetomoodle{}% +}% + +\NewEnviron{cloze}[2][]{% + \bgroup + \setkeys{moodle}{default grade=1}% + \setkeys{moodle}{#1,questionname={#2}}% + % A cloze question won't have any \item's in it, so we just use \BODY. + \moodle@enableclozeenvironments + %First, the LaTeX processing. + \item \textbf{\moodle@questionname}\par + \noindent + \BODY + %Now, writing information to memory. + \@moodle@ifgeneratexml{% + \xa\questiontext\xa{\BODY}% Save the question text as HTML. + \writeclozequestion + }{}% + \egroup% +} + +\def\moodle@enableclozeenvironments{% + \let\multi=\clozemulti + \let\endmulti=\endclozemulti + \let\numerical=\clozenumerical + \let\endnumerical=\endclozenumerical + \let\shortanswer=\clozeshortanswer + \let\endshortanswer=\endclozeshortanswer +} + +\gdef\writeclozequestion{% + \writetomoodle{}% + \moodle@writecommondata% + \writetomoodle{}% +}% + +\NewEnviron{clozemulti}[1][]{% + \bgroup + \setkeys{moodle}{default grade=1}% + \setkeys{moodle}{#1}% + \expandafter\gatheritems\xa{\BODY}% + \let\moodle@questionheader=\gatheredheader + \ifhtmlizer@active + %HTML version + \def\moodle@clozemulti@output{}% + \xa\g@addto@macro\xa\moodle@clozemulti@output\xa{\moodle@questionheader}% + \def\clozemulti@coding{}% + \edef\clozemulti@coding{\otherlbrace\csname moodle@default grade\endcsname:}% + \ifcase\moodle@multi@mode\relax + % Case 0: dropdown box style + \g@addto@macro{\clozemulti@coding}{MULTICHOICE:}% + \or + % Case 1: vertical style + \g@addto@macro{\clozemulti@coding}{MULTICHOICE_V:}% + \else + % Case 2: horizontal radio buttons + \g@addto@macro{\clozemulti@coding}{MULTICHOICE_H:}% + \fi + \bgroup + \setkeys{moodle}{feedback={}}% + \loopthroughitemswithcommand{\saveclozemultichoiceanswer}% + \egroup + \xa\g@addto@macro\xa\clozemulti@coding\xa{\otherrbrace}% + \xa\g@addto@macro\xa\moodle@clozemulti@output\xa{\clozemulti@coding}% + \xa\gdef\xa\htmlize@afteraction@hook\xa{\moodle@clozemulti@output}% + \def\endclozemulti@code{\htmlize@patchendenvironment}% + \else + %LaTeX version + \moodle@questionheader% %Any introductory text just continues to be typeset. + \def\cloze@multichoice@table@text{}% + \loopthroughitemswithcommand{\moodle@print@clozemultichoice@answer}% + \ifcase\moodle@multi@mode\relax + %Case 0: dropdown box style + \begin{tabular}[t]{|l|}\firsthline% (\firsthline is from the array package.) + \cloze@multichoice@table@text% + \end{tabular}% + \or + %Case 1: vertical style + \begin{itemize}\setlength\itemsep{0pt}\setlength\parskip{0pt}% + \cloze@multichoice@table@text% + \end{itemize}% + \else + %Case 2: horizontal radio buttons + \par{\cloze@multichoice@table@text}\par% + \fi + \def\endclozemulti@code{\relax}% + \fi + \passvalueaftergroup\endclozemulti@code% + \passvalueaftergroup\htmlize@afteraction@hook% + \egroup% +}[\endclozemulti@code]% + +\def\moodle@print@clozemultichoice@answer#1{% + \moodle@print@clozemultichoice@answer@int#1\@rdelim% +}% +\newcommand\moodle@print@clozemultichoice@answer@int[1][]{% + \moodle@print@clozemultichoice@answer@int@int% +}% +\def\moodle@print@clozemultichoice@answer@int@int#1#2\@rdelim{% + % Case 0: "(answer) \\ \hline" + % Case 1: "\item (answer)" + % Case 2: "$\bullet~$(answer)\hfill" + \ifcase\moodle@multi@mode\relax + \relax% Case 0 + \or + \g@addto@macro\cloze@multichoice@table@text{\item}% Case 1 + \else + \g@addto@macro\cloze@multichoice@table@text{$\bullet~$}% Case 2 + \fi + \def\test@i{#1}% + \ifx\test@i\@star + \g@addto@macro\cloze@multichoice@table@text{#2$~\checkmark$}% + \else + \g@addto@macro\cloze@multichoice@table@text{#1#2}% + \fi + \ifcase\moodle@multi@mode\relax + \g@addto@macro{\cloze@multichoice@table@text}{\\ \hline}% Case 0 + \or + \relax% Case 1 + \else + \g@addto@macro{\cloze@multichoice@table@text}{\hfill}% Case 2 + \fi +}% + +\def\saveclozemultichoiceanswer#1{% + \bgroup + \saveclozemultichoiceanswer@int#1\moodle@answer@rdelim + \egroup +}% +\newcommand\saveclozemultichoiceanswer@int[1][]{% + \setkeys{moodle}{fraction=0,#1}% + \saveclozemultichoiceanswer@int@int% +}% +\def\saveclozemultichoiceanswer@int@int#1#2\moodle@answer@rdelim{% + \def\test@i{#1}% + \ifgatherbeginningofloop\else + \xa\gdef\xa\clozemulti@coding\xa{\clozemulti@coding\clozetilde}% separator between answers + \fi + \ifx\test@i\@star + \setkeys{moodle}{fraction=100}% + \def\moodle@answertext{#2}% + \else + \def\moodle@answertext{#1#2}% + \fi + \trim@spaces@in\moodle@answertext + \ifx\moodle@fraction\@hundred + \g@addto@macro\clozemulti@coding{=}% + \fi + \ifnum0<\moodle@fraction\relax + \ifnum\moodle@fraction<100\relax + \xdef\clozemulti@coding{\expandonce\clozemulti@coding\otherpercent\moodle@fraction\otherpercent}% + \fi + \fi + \xdef\clozemulti@coding{\expandonce\clozemulti@coding\expandonce\moodle@answertext}% + \ifx\moodle@feedback\@empty\else + \xdef\clozemulti@coding{\expandonce\clozemulti@coding\otherbackslash\otherhash\moodle@feedback}% + \fi +}% +\NewEnviron{clozenumerical}[1][]{% + \bgroup + \expandafter\gatheritems\expandafter{\BODY}% + \let\moodle@questionheader=\gatheredheader + \setkeys{moodle}{default grade=1}% + \setkeys{moodle}{#1}% + \ifhtmlizer@active + %HTML version + \def\moodle@clozenumerical@output{}% + \xa\g@addto@macro\xa\moodle@clozenumerical@output\xa{\moodle@questionheader}% + \def\clozenumerical@coding{}% + \edef\clozenumerical@coding{\otherlbrace\csname moodle@default grade\endcsname:NUMERICAL:}% + \bgroup + \setkeys{moodle}{feedback={}}% + \loopthroughitemswithcommand{\saveclozenumericalanswer}% + \egroup + \xa\g@addto@macro\xa\clozenumerical@coding\xa{\otherrbrace}% + \xa\g@addto@macro\xa\moodle@clozenumerical@output\xa{\clozenumerical@coding}% + \xa\gdef\xa\htmlize@afteraction@hook\xa{\moodle@clozenumerical@output}% + \def\endclozenumerical@code{\htmlize@patchendenvironment}% + \else + %LaTeX version + \moodle@questionheader% %Any introductory text just continues to be typeset. + \def\cloze@numerical@table@text{}% + \loopthroughitemswithcommand{\moodle@print@clozenumerical@answer}% + \begin{tabular}[t]{|ll|}\firsthline + \cloze@numerical@table@text\hline% + \end{tabular}% + \def\endclozenumerical@code{\relax}% + \fi + \passvalueaftergroup\endclozenumerical@code% + \passvalueaftergroup\htmlize@afteraction@hook% + \egroup +}[\endclozenumerical@code]% + +\def\moodle@print@clozenumerical@answer#1{% + \bgroup + \moodle@print@clozenumerical@answer@int#1\@rdelim + \egroup +}% +\newcommand\moodle@print@clozenumerical@answer@int[1][]{% + \setkeys{moodle}{#1}% + \moodle@print@clozenumerical@answer@int@int% +}% +\def\moodle@print@clozenumerical@answer@int@int#1\@rdelim{% + \ifx\moodle@fraction\@hundred + \def\moodle@clozenumericalprint@fraction{$\checkmark$}% + \else + \edef\moodle@clozenumericalprint@fraction{(\moodle@fraction\%)}% + \fi + \ifdim0pt=\moodle@tolerance pt\relax + \def\moodle@clozenumericalprint@tolerance{}% + \else + \edef\moodle@clozenumericalprint@tolerance{\noexpand\pm\moodle@tolerance}% + \fi + \xdef\moodle@clozenumericalprint@line{$#1\moodle@clozenumericalprint@tolerance$ & \moodle@clozenumericalprint@fraction}% + \xa\g@addto@macro\xa\cloze@numerical@table@text\xa{\moodle@clozenumericalprint@line \\}% +}% + +\def\saveclozenumericalanswer#1{% + \bgroup + \saveclozenumericalanswer@int#1\moodle@answer@rdelim + \egroup +}% +\newcommand\saveclozenumericalanswer@int[1][]{% + \setkeys{moodle}{fraction=100,#1}% %%%%%% DEFAULT VALUE IS 100% + \saveclozenumericalanswer@int@int% +}% +\def\saveclozenumericalanswer@int@int#1\moodle@answer@rdelim{% + \ifgatherbeginningofloop\else + \xa\gdef\xa\clozenumerical@coding\xa{\clozenumerical@coding\clozetilde}% separator between answers + \fi + \def\moodle@answertext{#1}% + \trim@spaces@in\moodle@answertext + \ifx\moodle@fraction\@hundred + \g@addto@macro\clozenumerical@coding{=}% + \fi + \ifnum0<\moodle@fraction\relax + \ifnum\moodle@fraction<100\relax + \xdef\clozenumerical@coding{\expandonce\clozenumerical@coding\otherpercent\moodle@fraction\otherpercent}% + \fi + \fi + \xdef\clozenumerical@coding{\expandonce\clozenumerical@coding\moodle@answertext:\moodle@tolerance}% + \ifx\moodle@feedback\@empty\else + \xdef\clozenumerical@coding{\expandonce\clozenumerical@coding\otherbackslash\otherhash\moodle@feedback}% + \fi +}% +\NewEnviron{clozeshortanswer}[1][]{% + \bgroup + \expandafter\gatheritems\expandafter{\BODY}% + \let\moodle@questionheader=\gatheredheader + \setkeys{moodle}{default grade=1}% + \setkeys{moodle}{#1}% + %Because nesting conditionals built by \csname doesn't work well, + %we'll test '\ifmoodle@case sensitive' now and save the result in \count0. + \csname ifmoodle@case sensitive\endcsname + \count0=1\relax + \else + \count0=0\relax + \fi + \ifhtmlizer@active + %HTML version + \def\moodle@clozeshortanswer@output{}% + \xa\g@addto@macro\xa\moodle@clozeshortanswer@output\xa{\moodle@questionheader}% + \def\clozeshortanswer@coding{}% + \ifnum\count0=1\relax + \edef\clozeshortanswer@coding{\otherlbrace\csname moodle@default grade\endcsname:SHORTANSWER_C:}% + \else + \edef\clozeshortanswer@coding{\otherlbrace\csname moodle@default grade\endcsname:SHORTANSWER:}% + \fi + \bgroup + \setkeys{moodle}{feedback={}}% + \loopthroughitemswithcommand{\saveclozeshortansweranswer}% + \egroup + \xa\g@addto@macro\xa\clozeshortanswer@coding\xa{\otherrbrace}% + \xa\g@addto@macro\xa\moodle@clozeshortanswer@output\xa{\clozeshortanswer@coding}% + \xa\gdef\xa\htmlize@afteraction@hook\xa{\moodle@clozeshortanswer@output}% + \def\endclozeshortanswer@code{\htmlize@patchendenvironment}% + \else + %LaTeX version + \moodle@questionheader% %Any introductory text just continues to be typeset. + \def\cloze@shortanswer@table@text{}% + \loopthroughitemswithcommand{\moodle@print@clozeshortanswer@answer}% + \ifnum\count0=1\relax + \marginpar{\tiny\mbox{(Case-Sensitive)}}% + \fi + \begin{tabular}[t]{|ll|}\firsthline + \cloze@shortanswer@table@text\hline% + \end{tabular}% + \def\endclozeshortanswer@code{\relax}% + \fi + \passvalueaftergroup\endclozeshortanswer@code% + \passvalueaftergroup\htmlize@afteraction@hook% + \egroup +}[\endclozeshortanswer@code]% + +\def\moodle@print@clozeshortanswer@answer#1{% + \bgroup + \moodle@print@clozeshortanswer@answer@int#1\@rdelim + \egroup +}% +\newcommand\moodle@print@clozeshortanswer@answer@int[1][]{% + \setkeys{moodle}{#1}% + \moodle@print@clozeshortanswer@answer@int@int% +}% +\def\moodle@print@clozeshortanswer@answer@int@int#1\@rdelim{% + \ifx\moodle@fraction\@hundred + \def\moodle@clozeshortanswerprint@fraction{$\checkmark$}% + \else + \edef\moodle@clozeshortanswerprint@fraction{(\moodle@fraction\%)}% + \fi + \xdef\moodle@clozeshortanswerprint@line{#1 & \moodle@clozeshortanswerprint@fraction}% + \xa\g@addto@macro\xa\cloze@shortanswer@table@text\xa{\moodle@clozeshortanswerprint@line \\}% +}% + +\def\saveclozeshortansweranswer#1{% + \bgroup + \saveclozeshortansweranswer@int#1\moodle@answer@rdelim + \egroup +}% +\newcommand\saveclozeshortansweranswer@int[1][]{% + \setkeys{moodle}{fraction=100,#1}% %%%%%% DEFAULT VALUE IS 100% + \saveclozeshortansweranswer@int@int% +}% +\def\saveclozeshortansweranswer@int@int#1\moodle@answer@rdelim{% + \ifgatherbeginningofloop\else + \xa\gdef\xa\clozeshortanswer@coding\xa{\clozeshortanswer@coding\clozetilde}% separator between answers + \fi + \def\moodle@answertext{#1}% + \trim@spaces@in\moodle@answertext + \ifx\moodle@fraction\@hundred + \g@addto@macro\clozeshortanswer@coding{=}% + \fi + \ifnum0<\moodle@fraction\relax + \ifnum\moodle@fraction<100\relax + \xdef\clozeshortanswer@coding{\expandonce\clozeshortanswer@coding\otherpercent\moodle@fraction\otherpercent}% + \fi + \fi + \xdef\clozeshortanswer@coding{\expandonce\clozeshortanswer@coding\moodle@answertext}% + \ifx\moodle@feedback\@empty\else + \xdef\clozeshortanswer@coding{\expandonce\clozeshortanswer@coding\otherbackslash\otherhash\moodle@feedback}% + \fi +}% +{\catcode`\#=12\gdef\otherhash{#}% + \catcode`\~=12\gdef\othertilde{~}% + \catcode`\&=12\gdef\otherampersand{&}% + \catcode`\^=12\gdef\othercaret{^}% + \catcode`\$=12\gdef\otherdollar{$}% + \catcode`\%=12\gdef\otherpercent{%}}% +{\catcode`\ =12\gdef\otherspace{ }}% +{\tt\catcode`\|=0\catcode`\\=12\relax|gdef|otherbackslash{\}}% +{\catcode`\[=1\catcode`\]=2\catcode`\{=12\catcode`\}=12% + \gdef\otherlbrace[{]\gdef\otherrbrace[}]] + +\edef\@otherlbrace{\otherlbrace}% +\edef\@otherrbrace{\otherrbrace}% +\edef\@otherdollar{\otherdollar}% +\edef\@otherbackslash{\otherbackslash}% +\edef\@othertilde{\othertilde}% +{ \catcode`\[=1\relax + \catcode`\]=2\relax + \catcode`\|=0\relax + |gdef|verbcatcodesweirdest[ + |catcode`\{=12|relax + |catcode`\}=12|relax + |catcode`\\=12|relax + ]% +}% +\def\verbcatcodes{% + \catcode`\$=12\relax + \catcode`\&=12\relax + \catcode`\#=12\relax + \catcode`\^=12\relax + \catcode`\_=12\relax + \catcode`\~=12\relax + \makeatletter + \catcode`\%=12\relax + \catcode`\ =12\relax\catcode\newlinechar=12\verbcatcodesweirdest}% + +\def\normalcatcodes{% + \catcode`\\=0\relax + \catcode`\{=1\relax + \catcode`\}=2\relax + \catcode`\$=3\relax + \catcode`\&=4\relax + \catcode\endlinechar=5\relax + \catcode`\#=6\relax + \catcode`\^=7\relax + \catcode`\_=8\relax + \catcode`\ =10\relax + \makeatletter% We will be detokenizing and retokenizing internal control sequences, so we need this. + \catcode`\~=13\relax + \catcode`\%=14\relax}% + +\def\retokenizingcatcodes{% + %For rescanning previously scanned text, all true comments will already be gone, + %but % signs may have been inserted by Cloze questions, so we want to treat them as 'other.' + % + % TODO: #'s are more worrisome. + \normalcatcodes + \catcode`\%=12\relax +} +\begingroup + \catcode`\^^A=13\gdef^^A{\gdef\stm@saved}% + \catcode`\^^B=1\catcode`\^^C=2\relax + \long\gdef\scantokens@to@macro#1#2#3{% + % #1 = control sequence to be defined + % #2 = command to change catcodes, e.g. \verbcatcodes, + % and define any command sequences + % #3 = text to be retokenized and saved into #1. + \bgroup + \def\texttorescan{#3}% + \catcode`\^^A=13\catcode`\^^B=1\catcode`\^^C=2\relax + \xa\def\xa\arg\xa{\xa^^A\xa^^B\texttorescan^^C}% + #2% + \catcode\endlinechar=9\relax% + %\scantokens always sees an end-of-line character at its end and converts it to a space. + %The catcode change sets \scantokens to ignore end-of-line chars. + %In practice, we're always calling \scantokens on previously scanned text anyway, + %so we won't miss any real end-of-line chars, since they were already converted to spaces. + \xa\scantokens\xa{\arg}% + \egroup + \xa\def\xa#1\xa{\stm@saved}% + }% +\endgroup% + +\long\def\ultradetokenize@to@macro#1#2{% + \scantokens@to@macro#1{\verbcatcodes}{#2}% +}% +\def\retokenizenormal@to@macro#1#2{% + \scantokens@to@macro#1{\retokenizingcatcodes}{#2}% +}% +\newcount\moodle@mathmodedepth +\moodle@mathmodedepth=0\relax +\def\moodle@ifmathmode#1#2{% + \ifnum\moodle@mathmodedepth>0\relax + #1% + \else + #2% + \fi +} + +\newcount\grouplevel + +\newif\ifhtmlizer@active +\htmlizer@activefalse +\long\def\htmlize@grabblock#1#2\htmlize@rdelim@ii{% + \long\def\htmlize@blockinbraces{#1}% + \long\def\htmlize@remainder{#2}% +}% +\ultradetokenize@to@macro\@htmlize@stop@detokenized{\@htmlize@stop}% +\xa\def\xa\htmlize@remove@stopcode\xa#\xa1\@htmlize@stop@detokenized{#1}% +\newif\ifhtmlize@actioncs +\newif\ifhtmlize@expandcs +\newif\ifhtmlize@passcs + +\long\def\@@begin@cs{\begin}% +\def\@@htmlize@stop{\@htmlize@stop}% + +\long\def\converttohtmlmacro#1#2{% + \grouplevel=0\relax + \def\htmlize@output{}% + \htmlizer@activetrue% + \converttohtml@int{#2}% + \htmlizer@activefalse% + \let#1=\htmlize@output\relax +} + +\long\def\converttohtml@int#1{% + \advance\grouplevel by 1\relax + \bgroup + \ultradetokenize@to@macro\htmlize@texttoscan{#1}% + \xa\htmlize@recursive@i\htmlize@texttoscan\@htmlize@stop\@htmlize@stop\@htmlize@stop\htmlize@rdelim@i + \egroup + \advance\grouplevel by -1\relax +}% + +\def\@lt{<}% +\def\@gt{>}% + +\long\def\htmlize@recursive@i#1#2#3\htmlize@rdelim@i{% + % #1#2#3 is a sequence of tokens. All should be categories 11 (letter) or 12 (other). + % It terminates with the control sequences \@htmlize@stop\@htmlize@stop\@htmlize@stop. + %\long\def\ds{(#1|#2|#3)}\show\ds + \def\test@i{#1}% + \def\test@ii{#2}% + \ifx\test@i\@@htmlize@stop + \let\htmlize@next@i=\relax + \else + \ifx\test@i\@otherlbrace% + \xa\g@addto@macro\xa\htmlize@output\xa{\otherlbrace}% + \bgroup + \normalcatcodes + %We need to rescan the input as TeX code, + % so TeX can automatically pull off the first group in braces. + % First, let's get rid of the terminal \@htmlize@stop codes. + {\def\@htmlize@stop{}\xdef\htmlize@scrap{#1#2#3}}% + \let\htmlize@text@to@rescan=\htmlize@scrap% + % Next, we retokenize the code. + \xa\retokenizenormal@to@macro\xa\htmlize@rescanned\xa{\htmlize@text@to@rescan}% + % Now break it up into two pieces. + \xa\htmlize@grabblock\htmlize@rescanned\@htmlize@stop\htmlize@rdelim@ii% + % The first piece, \htmlize@blockinbraces, will be passed as a unit to \converttohtml@int. + % The second part, \htmlize@remainder, will continue at this depth of grouping. + % Therefore we'll detokenize \htmlize@remainder here. + \xa\ultradetokenize@to@macro\xa\htmlize@remainder@detokenized\xa{\htmlize@remainder}% + \edef\htmlize@remainder@detokenized{\xa\htmlize@remove@stopcode\htmlize@remainder@detokenized}% + % + % Now build \htmlize@next@i. + % When done, should look like + % \converttohtml@int{\htmlize@blockinbraces}% + % \g@addto@macro\htmlize@output{\otherrbrace}% + % \htmlize@recursive@i\htmlize@remainder@detokenized\@htmlize@stop\@htmlize@stop\@htmlize@stop\htmlize@rdelim@i% + % but with all three arguments expanded. + % Note that we are running + \gdef\htmlize@scrap{\converttohtml@int}% + \xa\g@addto@macro\xa\htmlize@scrap\xa{\xa{\htmlize@blockinbraces}}% + \g@addto@macro\htmlize@scrap{\g@addto@macro\htmlize@output}% + \xa\g@addto@macro\xa\htmlize@scrap\xa{\xa{\otherrbrace}}% + \g@addto@macro\htmlize@scrap{\htmlize@recursive@i}% + \xa\g@addto@macro\xa\htmlize@scrap\xa{\htmlize@remainder@detokenized\@htmlize@stop\@htmlize@stop\@htmlize@stop\htmlize@rdelim@i}% + % Okay, that's done. It's stored in a global macro. + % Now we get it out of this group. + \egroup + \let\htmlize@next@i=\htmlize@scrap + \else + \ifx\test@i\@otherdollar% + % Math shift character. + \ifx\test@ii\@otherdollar + % Double dollar sign, so we're entering display math mode. + % We grab everything between $$...$$, sanitize it, and add it verbatim to + % our output. + \htmlize@displaymathshift@replace#1#2#3\htmlize@rdelim@iii% + \else + % Single dollar sign, so we're entering inline math mode. + % We grab everything between $$...$$, sanitize it, and add it verbatim to + % our output. + \htmlize@inlinemathshift@replace#1#2#3\htmlize@rdelim@iii% + \fi + % Now we resume work. + % The \htmlize@xxxxxxmathshift@replace macro stored the remaining text in \htmlize@remaining@text. + % Note that since we never detokenized and retokenized #1#2#3, + % \htmlize@remaining@text still includes the terminating \@htmlize@stop\@htmlize@stop\@htmlize@stop. + \def\htmlize@next@i{\xa\htmlize@recursive@i\htmlize@remaining@text\htmlize@rdelim@i}% + \else + \ifx\test@i\@otherbackslash% + % Control sequence. Oh boy. + % There are three possible things to do: + % 1. Retokenize everything, so we get a token list. + % Expand this control sequence, the first one in the list, + % to obtain a new token list. Then resume processing that list. + % Examples: \def\emph#1{#1}, \def\rec#1{\frac{1}{#1}}, \def\inv{^{-1}} + % \& --> & \# --> #; etc. + % Environments: \begin{center}...\end{center} -->
    ...
    + % 2. Retokenize everything, so we get a token list. + % Let this first command (with its parameters) ACT. + % This may involve work in TeX's stomach (e.g., with counters) + % or with external files (e.g., image processing). + % The command may directly add material to \htmlize@output, + % but it should not typeset anything and should vanish from the + % input stream when it is done. + % When it's done, we somehow need to detokenize and resume + % processing the remainder of the input stream. + % Only commands explicitly crafted (or modified) to work + % with moodle.sty can possibly do all this! + % Examples: (modified) \includegraphics + % Environments: \begin{clozemulti}, \begin{enumerate} + % 3. Ignore that it's a command. Pass it right on as a character + % sequence to \htmlize@output. + % Examples: \alpha, \frac + % Environments: \begin{array} + % + % #2 is only for items on a specific list. + % #1 is anything that runs in TeX's mouth. + % We could keep a list and give users a way to add to it. + % I could also try expanding macros, using \ifcsmacro from etoolbox.sty + % + % The first step is to figure out what control sequence we're dealing with. + % First, let's get rid of the terminal \@htmlize@stop codes. + {\def\@htmlize@stop{}\xdef\htmlize@scrap{#1#2#3}}% + \let\htmlize@text@to@rescan=\htmlize@scrap% + % Next, we retokenize the code. + \xa\retokenizenormal@to@macro\xa\htmlize@rescanned\xa{\htmlize@text@to@rescan}% + % Now break it up into two pieces. + \xa\htmlize@grabblock\htmlize@rescanned\@htmlize@stop\htmlize@rdelim@ii% + \let\@htmlize@cs\htmlize@blockinbraces% + \edef\htmlize@cs@string{\xa\string\@htmlize@cs}% + % The first piece, \htmlize@blockinbraces, will contain the single token in \@htmlize@cs. + % We'll need to keep the second part, \htmlize@remainder, since it probably + % contains arguments to the cs in \@htmlize@cs. + %\edef\ds{Encountered '\xa\string\@htmlize@cs'}\show\ds + % + % N.B. that \@htmlize@cs is a macro *containing* a single control sequence. + % This is good for testing with \ifx. + % \htmlize@cs@string contains the cs as a string, e.g., the characters "\emph". + % + \ifx\@htmlize@cs\@@begin@cs + %This is a \begin. Begin environment-handling routine. + % + % Grab the first {...} from \htmlize@remainder, which is the argument + % to \begin. + \xa\htmlize@grabblock\htmlize@remainder\@htmlize@stop\htmlize@rdelim@ii% + \let\htmlize@envname=\htmlize@blockinbraces% + %We do not need the rest, so we won't pay any attention to the new + %content of \htmlize@remainder. + % + %Now environments are non-expandable, + %so there are only two possibilities: action or pass. + \xa\ifinlist\xa{\htmlize@envname}{\htmlize@env@actionlist}% + {% Action environment! + %\bgroup + %\def\ds{Encountered active environment \string\begin\{{\htmlize@envname}\}}\show\ds + \def\htmlize@next@i{\xa\htmlize@do@actionenv\htmlize@rescanned\@htmlize@stop\htmlize@actionsequence@rdelim}% + %The \bgroup is to active the environments. + %The matching \egroup is found in \htmlize@do@actionenv. + }{%An environment to pass to the HTML + %We just pass the backslash from "\begin" and move on. + \g@addto@macro\htmlize@output{#1}% + \def\htmlize@next@i{\htmlize@recursive@i#2#3\htmlize@rdelim@i}% + }% + \else% + %This is not an environment. Begin macro-handling routine. + \htmlize@actioncsfalse + \htmlize@expandcsfalse + \htmlize@passcsfalse + \xa\ifinlist\xa{\htmlize@cs@string}{\htmlize@cs@actionlist}% + {%Action sequence! + \htmlize@actioncstrue}% + {% Not action sequence! + \xa\ifinlist\xa{\htmlize@cs@string}{\htmlize@cs@expandlist}% + {%CS to be expanded! + \htmlize@expandcstrue% + }% + {%CS to be transcribed to XML + \htmlize@passcstrue% + }% + }% + %Now exactly one of \ifhtmlize@actioncs, \ifhtmlize@expandcs, and \ifhtmlize@passcs is true. + \ifhtmlize@actioncs + % It's an action-sequence. + %\edef\ds{Must let \xa\string\@htmlize@cs\ act!}\show\ds + %\show\htmlize@rescanned + \def\htmlize@next@i{\xa\htmlize@do@actioncs\htmlize@rescanned\@htmlize@stop\htmlize@actionsequence@rdelim}% + %\show\htmlize@rescanned + % Note that \htmlize@do@actioncs should patch the command to have it + % restart the scanning in time. + \else + \ifhtmlize@expandcs + % control sequence to be expanded + %\edef\ds{Must expand \xa\string\@htmlize@cs}\show\ds + \bgroup + \htmlize@redefine@expansionmacros + %The \expandafters first expand \htmlize@rescanned, + %and then expand its first token just once. + \xa\xa\xa\gdef\xa\xa\xa\htmlize@scrap\xa\xa\xa{\htmlize@rescanned}% + \egroup + \xa\ultradetokenize@to@macro\xa\htmlize@remaining@text\xa{\htmlize@scrap}% + \def\htmlize@next@i{\xa\htmlize@recursive@i\htmlize@remaining@text\@htmlize@stop\@htmlize@stop\@htmlize@stop\htmlize@rdelim@i}% + \else + % control sequence to be transcribed to XML. + %\edef\ds{Must pass on \xa\string\@htmlize@cs}\show\ds + \g@addto@macro\htmlize@output{#1}% + \def\htmlize@next@i{\htmlize@recursive@i#2#3\htmlize@rdelim@i}% + \fi + \fi + \fi + \else% + \ifx\test@i\@othertilde% + % The ~ becomes non-breaking space   + \g@addto@macro\htmlize@output{\otherampersand nbsp;}% + \def\htmlize@next@i{\htmlize@recursive@i#2#3\htmlize@rdelim@i}% + \else + \ifx\test@i\@lsinglequote% + \ifx\test@ii\@lsinglequote% + % Double left quote + \g@addto@macro\htmlize@output{\otherampersand ldquo;}% + \def\htmlize@next@i{\htmlize@recursive@i#3\htmlize@rdelim@i}% + \else + \g@addto@macro\htmlize@output{\otherampersand lsquo;}% + \def\htmlize@next@i{\htmlize@recursive@i#2#3\htmlize@rdelim@i}% + \fi + \else + \ifx\test@i\@rsinglequote% + \ifx\test@ii\@rsinglequote% + %Double right quote + \g@addto@macro\htmlize@output{\otherampersand rdquo;}% + \def\htmlize@next@i{\htmlize@recursive@i#3\htmlize@rdelim@i}% + \else + \g@addto@macro\htmlize@output{\otherampersand rsquo;}% + \def\htmlize@next@i{\htmlize@recursive@i#2#3\htmlize@rdelim@i}% + \fi + \else + \ifx\test@i\@doublequote + \g@addto@macro\htmlize@output{\otherampersand rdquo;}% + \def\htmlize@next@i{\htmlize@recursive@i#2#3\htmlize@rdelim@i}% + \else + \ifx\test@i\@lt + \moodle@ifmathmode{\g@addto@macro\htmlize@output{\otherampersand lt;}}% + {\g@addto@macro\htmlize@output{<}}% + \def\htmlize@next@i{\htmlize@recursive@i#2#3\htmlize@rdelim@i}% + \else + \ifx\test@i\@gt + \moodle@ifmathmode{\g@addto@macro\htmlize@output{\otherampersand gt;}}% + {\g@addto@macro\htmlize@output{>}}% + \def\htmlize@next@i{\htmlize@recursive@i#2#3\htmlize@rdelim@i}% + \else + % Default case: write first token to output, call self on remaining tokens. + \g@addto@macro\htmlize@output{#1}% + \def\htmlize@next@i{\htmlize@recursive@i#2#3\htmlize@rdelim@i}% + \fi + \fi + \fi + \fi + \fi + \fi + \fi + \fi + \fi + \fi + \htmlize@next@i +}% + +\def\@lsinglequote{`}% +\def\@rsinglequote{'}% +\def\@doublequote{"}% +\edef\inlinemathleftdelim{\otherbackslash(}% +\def\inlinemathrightdelim#1{\advancemathmodecounter{-1}% + \g@addto@macro\htmlize@output{\otherbackslash)}}% +\edef\displaymathleftdelim{
    \otherbackslash[}% +\def\displaymathrightdelim#1{\advancemathmodecounter{-1}% + \g@addto@macro\htmlize@output{\otherbackslash]
    }}% +{\catcode`\$=12\relax% + \gdef\htmlize@inlinemathshift@replace$#1$#2\htmlize@rdelim@iii{% + %\def\ds{inline math shift has '#1' and '#2'}\show\ds + \xa\g@addto@macro\xa\htmlize@output\xa{\inlinemathleftdelim}% + \advancemathmodecounter{1}% + \def\mathtext{#1}% + \def\aftertext{#2}% + \xdef\htmlize@remaining@text{\expandonce\mathtext% + \otherbackslash inlinemathrightdelim{}% + \expandonce\aftertext}% + %\show\htmlize@remaining@text + }% + \gdef\htmlize@displaymathshift@replace$$#1$$#2\htmlize@rdelim@iii{% + \xa\g@addto@macro\xa\htmlize@output\xa{\displaymathleftdelim}% + \advancemathmodecounter{1}% + \def\mathtext{#1}% + \def\aftertext{#2}% + \xdef\htmlize@remaining@text{\expandonce\mathtext% + \otherbackslash displaymathrightdelim{}% + \expandonce\aftertext}% + }% +} +\long\def\htmlize@do@actionenv#1#2\@htmlize@stop\htmlize@actionsequence@rdelim{% + \bgroup %The corresponding \egroup is given in \htmlize@proceedwiththerest, + %to localize the changes to the environment definitions. + \htmlize@activate@environments + \gdef\htmlize@afteraction@hook{}% + #1#2\@htmlize@stop\htmlize@actionsequence@rdelim% +} + +\def\htmlize@patchendenvironment{\swaptotrueendenvironment{\xa\htmlize@proceedwiththerest\htmlize@afteraction@hook}}% + +\def\swaptotrueendenvironment#1#2\if@ignore\@ignorefalse\ignorespaces\fi{#2\if@ignore\@ignorefalse\ignorespaces\fi#1}% + +\long\def\htmlize@record@environment#1{% + \listadd{\htmlize@env@actionlist}{#1}% +} +\long\def\html@newenvironment#1#2{% + \listadd{\htmlize@env@actionlist}{#1}% + \g@addto@macro\htmlize@activate@environments{% + \xa\let\csname #1\endcsname\relax% + \xa\let\csname end#1\endcsname\relax% + \NewEnviron{#1}{% + #2% + }[\htmlize@patchendenvironment]% + }% +} + +\def\htmlize@activate@environments{}% +\gdef\htmlize@afteraction@hook{}% + +\long\def\htmlize@do@actioncs#1#2\htmlize@actionsequence@rdelim{% + % #1#2 contains the current string to be rendered into HTML; + % N.B. it has been tokenized at this point, + % so TeX can process it directly. + % #1 = the command sequence we need to execute + % #2 = the rest of the string + % + % First, we patch the desired command so that, when it is over, + % it calls \htmlize@proceedwiththerest. + % We do this within the group, so as not to permanently change the command. + \bgroup + % The matching \egroup is issued in \htmlize@proceedwiththerest, + % so that the changes made by \htmlize@activate@css are localized to just the command itself. + \gdef\htmlize@afteraction@hook{}% + \htmlize@activate@css% + \def\test@i{#1}% + \ifx\test@i\@relax + \def#1{\xa\htmlize@proceedwiththerest\htmlize@afteraction@hook}% + \else + \xapptocmd#1{\xa\htmlize@proceedwiththerest\htmlize@afteraction@hook}{}{\PackageError{Could not patch the command \string#1!}}% + \fi + % Now we call that patched command. + #1#2\htmlize@actionsequence@rdelim% + %The matching \egroup now is built into the command #1. +} +\long\def\htmlize@proceedwiththerest#1\htmlize@actionsequence@rdelim{% + % The action cs has done its work. + % Now we gather up the remaining tokens, detokenize them, + % remove the \@htmlize@stop, and get back to work transcribing it. + \egroup %This \egroup matches the \bgroup that was issued either in \htmlize@do@actioncs or in \htmlize@do@actionenv + \ultradetokenize@to@macro\htmlize@remainder@detokenized{#1}% + %This will contain an extra \@htmlize@stop, so we remove it. + \xa\xa\xa\def\xa\xa\xa\htmlize@remainder@detokenized\xa\xa\xa{\xa\htmlize@remove@stopcode\htmlize@remainder@detokenized}% + %Now we get back to work transcribing the remainder. + \xa\htmlize@recursive@i\htmlize@remainder@detokenized\@htmlize@stop\@htmlize@stop\@htmlize@stop\htmlize@rdelim@i% +} + +\long\def\htmlize@record@action#1{% + \xa\listadd\xa\htmlize@cs@actionlist\xa{\string#1}% +} + +\def\htmlize@activate@css{}% +\def\html@action@def#1{% + \htmlize@record@action{#1}% + \xa\def\xa\htmlize@scrap\xa{\xa\let\xa#1\csname html@\string#1\endcsname}% + \xa\g@addto@macro\xa\htmlize@activate@css\xa{\htmlize@scrap}% + \xa\def\csname html@\string#1\endcsname% %And this \def\html@\oldcsname is follows by the remainder of the definition. +} +\def\htmlize@redefine@expansionmacros{}% +\long\def\htmlize@record@expand#1{% + \xa\listadd\xa\htmlize@cs@expandlist\xa{\string#1}% +} +\let\htmlregister=\htmlize@record@expand +\long\def\html@def#1{% + \htmlize@record@expand{#1}% + \xa\def\xa\htmlize@scrap\xa{\xa\let\xa#1\csname html@\string#1\endcsname}% + \xa\g@addto@macro\xa\htmlize@redefine@expansionmacros\xa{\htmlize@scrap}% + \xa\def\csname html@\string#1\endcsname% +} +\htmlize@record@environment{clozemulti} +\htmlize@record@environment{multi} +\htmlize@record@environment{clozenumerical} +\htmlize@record@environment{numerical} +\htmlize@record@environment{clozeshortanswer} +\htmlize@record@environment{shortanswer} + +\html@newenvironment{center}{\xdef\htmlize@afteraction@hook{
    \expandonce\BODY
    }}% +\html@newenvironment{enumerate}{% + \xa\gatheritems\xa{\BODY}% + \gdef\htmlize@afteraction@hook{
      }% + \loopthroughitemswithcommand{\moodle@itemtoLI}% + \g@addto@macro\htmlize@afteraction@hook{
    }% +}% +\html@newenvironment{itemize}{% + \xa\gatheritems\xa{\BODY}% + \gdef\htmlize@afteraction@hook{
      }% + \loopthroughitemswithcommand{\moodle@itemtoLI}% + \g@addto@macro\htmlize@afteraction@hook{
    }% +}% +\def\moodle@itemtoLI#1{% + \g@addto@macro\htmlize@afteraction@hook{
  • #1
  • }% +}% + +\def\advancemathmodecounter#1{% + \global\advance\moodle@mathmodedepth by #1\relax +} +\htmlize@record@action{\advancemathmodecounter}% + +\htmlize@record@action{\relax}% + +\html@action@def\#{\g@addto@macro\htmlize@output{\otherhash}}% +\html@action@def\&{\g@addto@macro\htmlize@output{\otherampersand}}% +\html@action@def\\{\moodle@ifmathmode{\g@addto@macro\htmlize@output{\otherbackslash\otherbackslash}}% + {\g@addto@macro\htmlize@output{
    }}}% +\html@action@def\{{% + \moodle@ifmathmode{\g@addto@macro\htmlize@output{\otherbackslash\otherlbrace}}% + {\g@addto@macro\htmlize@output{\otherlbrace}}% + }% +\html@action@def\}{% + \moodle@ifmathmode{\g@addto@macro\htmlize@output{\otherbackslash\otherrbrace}}% + {\g@addto@macro\htmlize@output{\otherrbrace}}% + }% +\html@action@def\ldots{% + \moodle@ifmathmode{\g@addto@macro\htmlize@output{\string\ldots}}% + {\g@addto@macro\htmlize@output{...}}% + }% +\html@action@def\dots{% + \moodle@ifmathmode{\g@addto@macro\htmlize@output{\string\dots}}% + {\g@addto@macro\htmlize@output{...}}% + }% +\html@action@def\ {% + \moodle@ifmathmode{\g@addto@macro\htmlize@output{\otherbackslash\otherspace}}% + {\g@addto@macro\htmlize@output{\otherspace}}% + }% +\html@action@def\${% + \g@addto@macro\htmlize@output{\otherdollar}% + }% + +\html@action@def\clozetilde{% + \xa\g@addto@macro\xa\htmlize@output\xa{\othertilde}% + }% + +{\catcode`|=3\relax + \gdef\htmlize@vowels{a|e|i|o|u|A|E|I|O|U|}} +\def\htmlize@define@diacritic#1#2{% + \htmlize@record@action{#1}% + \g@addto@macro\htmlize@activate@css{% + \def#1##1{% + \ifinlist{##1}{\htmlize@vowels}% + {\g@addto@macro\htmlize@output{\otherampersand##1#2;}}% + {\xa\g@addto@macro\htmlize@output\xa{\string#1##1}}% + }% + }% +} +\htmlize@define@diacritic{\^}{circ}% +\htmlize@define@diacritic{\'}{acute}% +\htmlize@define@diacritic{\"}{uml}% +\htmlize@define@diacritic{\`}{grave}% + +\def\@o{o}\def\@O{O}\def\@u{u}\def\@U{U}% +\html@action@def\H#1{% + \bgroup + \def\test@i{#1}% + \ifx\test@i\@O + \def\toadd{\otherampersand\otherhash337;}% + \else + \ifx\test@i\@o + \def\toadd{\otherampersand\otherhash337;}% + \else + \ifx\test@i\U + \def\toadd{\otherampersand\otherhash368;}% + \else + \ifx\test@i\u + \def\toadd{\otherampersand\otherhash369;}% + \else + \def\toadd{\otherbackslash\otherlbrace#1\otherrbrace}% + \fi + \fi + \fi + \fi + \xa\g@addto@macro\xa\htmlize@output\xa{\toadd}% + \egroup +}% + +{\catcode`|=3\relax + \gdef\htmlize@tilde{A|N|O|a|n|o|}} +\html@action@def\~#1{% + \ifinlist{#1}{\htmlize@tilde}% + {\g@addto@macro\htmlize@output{\otherampersand#1tilde;}}% + {\xa\g@addto@macro\htmlize@output\xa{\string\~#1}}% + }% +\html@def\underline#1{#1} +\html@def\emph#1{#1}% +\html@def\textbf#1{#1}% +\html@def\blank{____________}% +\html@def\par{

    }% +\html@def\aa{\å}% +\html@def\AA{\Å}% +\html@def\ae{\æ}% +\html@def\AE{\Æ}% +\html@def\S{\§}% +\html@def\euro{\€}% +\html@def\texteuro{\€}% +\html@def\o{\ø}% +\html@def\O{\Ø}% +\html@def\ss{\ß}% +\html@def\l{\ł}% +\html@def\L{\Ł}% + +\htmlize@record@expand{\inv}% +\htmlize@record@expand{\rec}% + +\htmlize@record@action\inlinemathrightdelim +\htmlize@record@action\displaymathrightdelim + +\def\htmlize@setexecutable#1{% + % Defines macro #1 to be #2 in a verbatim mode suitable for filenames + \def\htmlize@executable@macro{#1}% + \bgroup\catcode`\|=0\catcode`\\=12\relax% + \htmlize@setexecutable@int +} +\def\htmlize@setexecutable@int#1{% + \egroup + \expandafter\def\htmlize@executable@macro{#1}% +} + +\def\ghostscriptcommand{\htmlize@setexecutable\gs} +\def\opensslcommand{\htmlize@setexecutable\openssl} +\def\imagemagickcommand{\htmlize@setexecutable\htmlize@imagemagick@convert} + +\ifwindows% + \ghostscriptcommand{gswin64c.exe}% +\else% + \ghostscriptcommand{gs}% +\fi% + +\opensslcommand{openssl}% +\imagemagickcommand{convert}% +\define@cmdkeys{moodle@includegraphics}[moodle@graphics@]{ppi} +\define@cmdkey{moodle}[moodle@graphics@]{ppi}{}% This is so the ppi key can be set at the document, quiz, or question level. +\define@cmdkeys{Gin}{ppi}% This is so the original \includegraphics will not object to a key of ppi. +\setkeys{moodle@includegraphics}{ppi=103} + +\newdimen\moodle@graphics@temp@dimen +\newcount\moodle@graphics@height@pixels +\newcount\moodle@graphics@width@pixels +\def\moodle@graphics@dimentopixels#1#2{% + \moodle@graphics@temp@dimen=#2\relax + \moodle@graphics@temp@dimen=0.013837\moodle@graphics@temp@dimen + \xa\moodle@graphics@temp@dimen\xa=\moodle@graphics@ppi\moodle@graphics@temp@dimen + #1=\moodle@graphics@temp@dimen + \divide #1 by 65536\relax +} +\define@key{moodle@includegraphics}{height}[]{% + \moodle@graphics@dimentopixels{\moodle@graphics@height@pixels}{#1}% +} +\define@key{moodle@includegraphics}{width}[]{% + \moodle@graphics@dimentopixels{\moodle@graphics@width@pixels}{#1}% +} +\setkeys{moodle@includegraphics}{height=0pt,width=0pt} +\html@action@def\includegraphics{\moodle@includegraphics@int}% + % Note that \htmlize@do@actioncs will 'patch' this by putting + % '\xa\htmlize@proceedwiththerest\htmlize@afteraction@hook' + % at the end. We want those 3 tokens to occur instead after + % the graphics filename. +\def\moodle@includegraphics@int#1#2#3{\moodle@includegraphics@int@int}% + % This gobbles up those three spurious tokens, + % which we will re-insert after our work is done. +\newcommand\moodle@includegraphics@int@int[2][]{% + \bgroup% The grouping is to localize the changes caused by \setkeys. + \message{moodle.sty: Processing \string\includegraphics[#1]{#2} for HTML...^^J} + \setkeys*{moodle@includegraphics}{#1}% + % Height or width should be given in TeX dimensions like cm or pt or in, + % and are converted to pixels for web use using the ppi key. + % TO DO: Can we modify \includegraphics to accept height or width in + % pixels? + % TO DO: What about \includegraphics[scale=0.7] ? + % Other keys: keepaspectratio=true|false, angle (rotation), clip & trim + \ifnum\moodle@graphics@height@pixels=0\relax + \ifnum\moodle@graphics@width@pixels=0\relax + % No size specified. Default to height of 200 pixels. + \def\moodle@graphics@geometry{x200}% + \def\moodle@graphics@htmlgeometry{}% + \else + % Width only specified. + \edef\moodle@graphics@geometry{\number\moodle@graphics@width@pixels}% + \edef\moodle@graphics@htmlgeometry{width=\number\moodle@graphics@width@pixels}% + \fi + \else + \ifnum\moodle@graphics@width@pixels=0\relax + % Height only specified. The `x' is part of the syntax. + \edef\moodle@graphics@geometry{x\number\moodle@graphics@height@pixels}% + \edef\moodle@graphics@htmlgeometry{height=\number\moodle@graphics@height@pixels}% + \else + % Height and width both specified. The `!' is part of the syntax. + \edef\moodle@graphics@geometry{\number\moodle@graphics@width@pixels x\number\moodle@graphics@height@pixels!}% + \edef\moodle@graphics@htmlgeometry{width=\number\moodle@graphics@width@pixels\otherspace height=\number\moodle@graphics@height@pixels}% + \fi + \fi + %First, convert it to PNG + \edef\cmdline{\htmlize@imagemagick@convert\otherspace #2 -resize \moodle@graphics@geometry\otherspace #2.png}% + \message{moodle.sty: Converting '#2' to PNG...^^J}% + \expandafter\immediate\expandafter\write18\expandafter{\cmdline}% + %Next, convert the PNG to base64 encoding + \def\cmdline{\openssl\otherspace enc -base64 -in #2.png -out #2.enc}% + \message{moodle.sty: Converting '#2.png' to base64...^^J}% + \expandafter\immediate\expandafter\write18\expandafter{\cmdline}% + %Now, save that base64 encoding in a TeX macro + \def\moodle@newpic@baselxiv{}% + \message{moodle.sty: Reading base64 file '#2.enc'...^^J}% + \openin\baseLXIVdatafile=#2.enc\relax + \savebaselxivdata@recursive + \closein\baseLXIVdatafile + \xa\global\xa\let\csname picbaselxiv@graphics@#2\endcsname=\moodle@newpic@baselxiv% + \edef\htmlize@imagetag{}% + \xa\g@addto@macro\xa\htmlize@output\xa{\htmlize@imagetag}% + \message{moodle.sty: tag inserted.^^J}% + \egroup + % Now we re-insert the code to get the HTMLizing going again. + \xa\htmlize@proceedwiththerest\htmlize@afteraction@hook +} +\newread\baseLXIVdatafile +\def\savebaselxivdata@recursive{% + \ifeof\baseLXIVdatafile + \let\baselxiv@next=\relax + \else + \read\baseLXIVdatafile to \datalinein + %\message{<<\datalinein>>^^J} + \ifx\datalinein\@moodle@par + \let\baselxiv@next=\relax + \else + %We add tokens manually, rather than with \g@addto@macro, to save time. + \xa\xa\xa\gdef\xa\xa\xa\moodle@newpic@baselxiv\xa\xa\xa{\xa\moodle@newpic@baselxiv\datalinein^^J}% + \let\baselxiv@next=\savebaselxivdata@recursive + \fi + \fi + \baselxiv@next +} +\newif\ifmoodle@tikzloaded +\moodle@tikzloadedfalse +\AtBeginDocument{ + \ifx\tikzpicture\@undefined + \moodle@tikzloadedfalse + \else + \moodle@tikzloadedtrue + \fi + \ifmoodle@tikzloaded + \usetikzlibrary{external} + \tikzexternalize% + \tikzset{external/force remake}% + + \ifpdf + \def\pdftopng{\edef\gscmdline{\gs\otherspace -dBATCH -dNOPAUSE -sDEVICE=pngalpha -sOutputFile=\tikzexternalrealjob-tikztemp-\the\numconvertedpictures.png -r200 \tikzexternalrealjob-tikztemp-\the\numconvertedpictures.pdf}% + \expandafter\immediate\expandafter\write18\expandafter{\gscmdline}}% + \else + \def\pstopng{\edef\gscmdline{\gs\otherspace -dBATCH -dNOPAUSE -sDEVICE=pngalpha -sOutputFile=\tikzexternalrealjob-tikztemp-\the\numconvertedpictures.png -r200 \tikzexternalrealjob-tikztemp-\the\numconvertedpictures.ps}% + \expandafter\immediate\expandafter\write18\expandafter{\gscmdline}}% + \fi + \def\pngtobaselxiv{\edef\opensslcmdline{\openssl\otherspace enc -base64 -in \tikzexternalrealjob-tikztemp-\the\numconvertedpictures.png -out \tikzexternalrealjob-tikztemp-\the\numconvertedpictures.enc}% + \expandafter\immediate\expandafter\write18\expandafter{\opensslcmdline}}% + + \let\moodle@oldtikzpicture=\tikzpicture + + %The following code lets us run things *before* the normal \begin{tikzpicture}. + \renewenvironment{tikzpicture}{% + \global\advance\numconvertedpictures by 1\relax + %\jobnamewithsuffixtomacro{\htmlize@picbasename}{-tikztemp-\the\numconvertedpictures}% + %\xa\tikzsetnextfilename\xa{\htmlize@picbasename}% + \tikzsetnextfilename{\tikzexternalrealjob-tikztemp-\the\numconvertedpictures}% + \moodle@oldtikzpicture% + }{}% + % However, the tikz externalize library does *not* run \end{tikzpicture}. + % In order to run commands after the tikz picture is done compiling, we need to + % use a hook into \tikzexternal@closeenvironments. + + \g@addto@macro{\tikzexternal@closeenvironments}{% + \moodle@endtikzpicture@hook + } + \def\moodle@endtikzpicture@hook{% + \@moodle@ifgeneratexml{% + \ifpdf + \message{moodle.sty: Converting picture '\tikzexternalrealjob-tikztemp-\the\numconvertedpictures.pdf' to PNG...^^J}% + \pdftopng + \else + \pstopng + \fi + \message{moodle.sty: Converting '\tikzexternalrealjob-tikztemp-\the\numconvertedpictures.png' to base64...^^J}% + \pngtobaselxiv + \message{moodle.sty: Reading base64 file '\tikzexternalrealjob-tikztemp-\the\numconvertedpictures.enc'...^^J}% + \savebaselxivdata + \message{moodle.sty: base64 data saved.^^J}% + }{}% + } + \tikzset{external/optimize=true} + \tikzset{external/optimize command away={\VerbatimInput}{1}} + % + % The HTMLizer version of the tikzpicture environment, + % which writes an tag to the XML file. + \htmlize@record@environment{tikzpicture} + \g@addto@macro\htmlize@activate@environments{% + \let\tikzpicture\relax\let\endtikzpicture\relax + \NewEnviron{tikzpicture}[1][]{% + \global\advance\numpicturesread by 1\relax + \edef\htmlize@imagetag{}% + \xa\g@addto@macro\xa\htmlize@output\xa{\htmlize@imagetag}% + }[\htmlize@patchendenvironment]% + }% + \else + %TikZ not loaded. Provide dummy definitions for commands. + \long\def\tikzifexternalizing#1#2{#2}% + \fi +} + +\newcount\numconvertedpictures +\numconvertedpictures=0\relax +\newcount\numpicturesread +\numpicturesread=0\relax + +\def\savebaselxivdata{% + \def\moodle@newpic@baselxiv{}% + \openin\baseLXIVdatafile=\tikzexternalrealjob-tikztemp-\the\numconvertedpictures.enc\relax + \savebaselxivdata@recursive + \closein\baseLXIVdatafile + \xa\global\xa\let\csname picbaselxiv@\the\numconvertedpictures\endcsname=\moodle@newpic@baselxiv% +} + +\def\@moodle@par{\par}% +\AtEndDocument{% + \ifmoodle@tikzloaded + \@moodle@ifgeneratexml{% + \ifwindows + \immediate\write18{del \tikzexternalrealjob-tikztemp-*.*}% + \else + \immediate\write18{rm \tikzexternalrealjob-tikztemp-*.*}% + \fi + }{}% + \fi +} + +\endinput +%% +%% End of file `moodle.sty'. -- cgit v1.2.3