You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2142 lines
81 KiB
2142 lines
81 KiB
%%
|
|
%% 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 <anders.hendrickson@snc.edu>
|
|
%%
|
|
%% 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
|
|
|
|
%%% oter les checkmarks pour pas afficher les solutions
|
|
\renewcommand\checkmark{~}
|
|
|
|
\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{<?xml version="1.0" encoding="UTF-8"?>}%
|
|
\writetomoodle{<quiz>}%
|
|
\writetomoodle{ }%
|
|
}%
|
|
\def\closemoodleout{%
|
|
\writetomoodle{ }%
|
|
\writetomoodle{</quiz>}%
|
|
\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{<question type="category">}%
|
|
\writetomoodle{ <category>}%
|
|
\writetomoodle{ <text>$module$/#1</text>}%
|
|
\writetomoodle{ </category>}%
|
|
\writetomoodle{</question>}%
|
|
\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"><text/></#2>}%
|
|
\else
|
|
\xa\converttohtmlmacro\xa\moodle@htmltowrite\xa{#3}%
|
|
\writetomoodle[2]{ <#2 format="html">}%
|
|
\writetomoodle[4]{ <text><![CDATA[<p>\moodle@htmltowrite</p>]]></text>}%
|
|
\writetomoodle[2]{ </#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</#2>}%
|
|
}%
|
|
}%
|
|
|
|
%% QUESTIONNAME
|
|
\define@cmdkey{moodle}[moodle@]{questionname}{}%
|
|
\gdef\moodle@writequestionname{%
|
|
\writetomoodle[2]{<name>}%
|
|
\writetomoodle[4]{ <text>\moodle@questionname</text>}%
|
|
\writetomoodle[2]{</name>}%
|
|
}%
|
|
|
|
%% 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}<questiontext>{\moodle@questiontext}%{%
|
|
|
|
%% PENALTY FOR WRONG ATTEMPT
|
|
\define@cmdkey{moodle}[moodle@]{penalty}[0.1000000]{}%
|
|
\generate@moodle@write@code*{penalty}<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 <generalfeedback>
|
|
% whereas \moodle@writefeedback uses the tag <feedback>.
|
|
% Note that the general feedback is NOT inherited by each answer!
|
|
\define@cmdkey{moodle}[moodle@]{feedback}[]{}%
|
|
\generate@moodle@write@code{generalfeedback}<generalfeedback>{\moodle@feedback}%
|
|
\generate@moodle@write@code{feedback}<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}<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}<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 <answer fraction="75">.
|
|
\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}<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}<shuffleanswers>{\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}<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 <answer fraction=100 tolerance=0.03>.
|
|
|
|
%% CASE SENSITIVE
|
|
\define@boolkey{moodle}[moodle@]{case sensitive}[true]{}%
|
|
\generate@moodle@write@code*{usecase}<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}<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}<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}<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}<attachments>{\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}<attachmentsrequired>{\moodle@attachmentsrequired}
|
|
\moodleset{attachments required=0}%
|
|
|
|
%% RESPONSE TEMPLATE
|
|
\define@key{moodle}{template}{\long\def\moodle@responsetemplate{#1}}%
|
|
\generate@moodle@write@code{responsetemplate}<responsetemplate>{\moodle@responsetemplate}
|
|
\moodleset{template={}}%
|
|
%% SHOWNUMCORRECT
|
|
\define@boolkey{moodle}[moodle@]{shownumcorrect}[true]{}%
|
|
\gdef\moodle@writeshownumcorrect{%
|
|
\if\moodle@shownumcorrect
|
|
\writetomoodle[4]{ <shownumcorrect/>}%
|
|
\fi
|
|
}%
|
|
\moodleset{shownumcorrect=false}%
|
|
|
|
%% CLEARWRONG
|
|
\define@boolkey{moodle}[moodle@]{clearwrong}[true]{}%
|
|
\gdef\moodle@writeclearwrong{%
|
|
\if\moodle@clearwrong
|
|
\writetomoodle[4]{ <clearwrong/>}%
|
|
\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{<graderinfo format="html"><text/></graderinfo>}%
|
|
\else
|
|
\addto@xml[2]\moodle@answers@xml{<graderinfo format="html"><text><![CDATA[}%
|
|
\ifnum\c@numgathereditems>1\relax
|
|
\addto@xml[4]\moodle@answers@xml{<ul>}%
|
|
\fi
|
|
\loopthroughitemswithcommand{\moodle@savegraderinfo}%
|
|
\ifnum\c@numgathereditems>1\relax
|
|
\addto@xml[4]\moodle@answers@xml{</ul>}%
|
|
\fi
|
|
\addto@xml[2]\moodle@answers@xml{]]></text></graderinfo>}%
|
|
\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{<question type="essay">}%
|
|
\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{</question>}%
|
|
}%
|
|
|
|
\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}{<li>\moodle@answertext@html</li>}%
|
|
\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}{<answer fraction="\moodle@fraction" format="plain_text">}%
|
|
\addto@xml[4]{\moodle@answers@xml}{ <text>\moodle@answertext</text>}%
|
|
\ifx\moodle@feedback\@empty\relax\else
|
|
\addto@xml[4]{\moodle@answers@xml}{ <feedback format="html"><text><![CDATA[<p>\moodle@feedback</p>]]></text></feedback>}%
|
|
\fi
|
|
\addto@xml[2]{\moodle@answers@xml}{</answer>}%
|
|
}%
|
|
|
|
\gdef\writeshortanswerquestion{%
|
|
\writetomoodle{<question type="shortanswer">}%
|
|
\moodle@writecommondata%
|
|
\moodle@writeusecase%
|
|
\moodle@writeanswers%
|
|
\writetomoodle{</question>}%
|
|
}%
|
|
\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}{<answer fraction="\moodle@fraction" format="plain_text">}%
|
|
\addto@xml[4]{\moodle@answers@xml}{ <text>\moodle@answertext</text>}%
|
|
\addto@xml[4]{\moodle@answers@xml}{ <tolerance>\moodle@tolerance</tolerance>}%
|
|
\ifx\moodle@feedback\@empty\relax\else
|
|
\addto@xml[4]{\moodle@answers@xml}{ <feedback format="html"><text><![CDATA[<p>\moodle@feedback</p>]]></text></feedback>}%
|
|
\fi
|
|
\addto@xml[2]{\moodle@answers@xml}{</answer>}%
|
|
}%
|
|
|
|
\gdef\writenumericalquestion{%
|
|
\writetomoodle{<question type="numerical">}%
|
|
\moodle@writecommondata%
|
|
\moodle@writeanswers%
|
|
\writetomoodle{</question>}%
|
|
}%
|
|
|
|
\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
|
|
%%% Ligne commente pour ne pas afficher les solutions
|
|
% $~(\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}{<answer fraction="\moodle@fraction" format="html">}%
|
|
\xa\converttohtmlmacro\xa\moodle@answertext@html\xa{\moodle@answertext}%
|
|
\addto@xml[4]{\moodle@answers@xml}{ <text><![CDATA[<p>\moodle@answertext@html</p>]]></text>}%
|
|
\ifx\moodle@feedback\@empty\relax\else
|
|
\addto@xml[4]{\moodle@answers@xml}{ <feedback format="html"><text><![CDATA[<p>\moodle@feedback</p>]]></text></feedback>}%
|
|
\fi
|
|
\addto@xml[2]{\moodle@answers@xml}{</answer>}%
|
|
}%
|
|
|
|
\gdef\writemultiquestion{%
|
|
\writetomoodle{<question type="multichoice">}%
|
|
\moodle@writecommondata%
|
|
\moodle@writesingle%
|
|
\moodle@writeshuffle%
|
|
\moodle@writeanswernumbering%
|
|
\moodle@writeanswers%
|
|
\writetomoodle{</question>}%
|
|
}%
|
|
\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}{<subquestion format="html">}%
|
|
\ifx\moodle@subquestiontext\@empty
|
|
\addto@xml[4]{\moodle@answers@xml}{ <text></text>}%
|
|
\else
|
|
\addto@xml[4]{\moodle@answers@xml}{ <text><![CDATA[<p>\moodle@subquestiontext@htmlized</p>]]></text>}%
|
|
\fi
|
|
\ifmoodle@draganddrop
|
|
\addto@xml[4]{\moodle@answers@xml}{ <answer format="html"><text><![CDATA[<p>\moodle@subanswertext@htmlized</p>]]></text></answer>}%
|
|
\else
|
|
\addto@xml[4]{\moodle@answers@xml}{ <answer><text>\moodle@subanswertext</text></answer>}%
|
|
\fi
|
|
\ifx\moodle@feedback\@empty\relax\else
|
|
\addto@xml[4]{\moodle@answers@xml}{ <feedback format="html"><text><![CDATA[<p>\moodle@feedback</p>]]></text></feedback>}%
|
|
\fi
|
|
\addto@xml[2]{\moodle@answers@xml}{</subquestion>}%
|
|
}%
|
|
|
|
\gdef\writematchingquestion{%
|
|
\ifmoodle@draganddrop
|
|
\writetomoodle{<question type="ddmatch">}%
|
|
\else
|
|
\writetomoodle{<question type="matching">}%
|
|
\fi
|
|
\moodle@writecommondata%
|
|
\moodle@writesingle%
|
|
\moodle@writeshuffle%
|
|
\moodle@writeanswernumbering%
|
|
\moodle@writeanswers%
|
|
\writetomoodle{</question>}%
|
|
}%
|
|
|
|
\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{<question type="cloze">}%
|
|
\moodle@writecommondata%
|
|
\writetomoodle{</question>}%
|
|
}%
|
|
|
|
\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{<EM>#1</EM>}, \def\rec#1{\frac{1}{#1}}, \def\inv{^{-1}}
|
|
% \& --> & \# --> #; etc.
|
|
% Environments: \begin{center}...\end{center} --> <CENTER>...</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{<CENTER>\otherbackslash[}%
|
|
\def\displaymathrightdelim#1{\advancemathmodecounter{-1}%
|
|
\g@addto@macro\htmlize@output{\otherbackslash]</CENTER>}}%
|
|
{\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{<CENTER>\expandonce\BODY</CENTER>}}%
|
|
\html@newenvironment{enumerate}{%
|
|
\xa\gatheritems\xa{\BODY}%
|
|
\gdef\htmlize@afteraction@hook{<OL>}%
|
|
\loopthroughitemswithcommand{\moodle@itemtoLI}%
|
|
\g@addto@macro\htmlize@afteraction@hook{</OL>}%
|
|
}%
|
|
\html@newenvironment{itemize}{%
|
|
\xa\gatheritems\xa{\BODY}%
|
|
\gdef\htmlize@afteraction@hook{<UL>}%
|
|
\loopthroughitemswithcommand{\moodle@itemtoLI}%
|
|
\g@addto@macro\htmlize@afteraction@hook{</UL>}%
|
|
}%
|
|
\def\moodle@itemtoLI#1{%
|
|
\g@addto@macro\htmlize@afteraction@hook{<LI>#1</LI>}%
|
|
}%
|
|
|
|
\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{<BR/>}}}%
|
|
\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{<SPAN STYLE="text-decoration: underline;">#1</SPAN>}
|
|
\html@def\emph#1{<EM>#1</EM>}%
|
|
\html@def\textbf#1{<B>#1</B>}%
|
|
\html@def\blank{____________}%
|
|
\html@def\par{</P><P>}%
|
|
\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{<IMG \moodle@graphics@htmlgeometry\otherspace SRC="data:image/png;base64,\csname picbaselxiv@graphics@#2\endcsname">}%
|
|
\xa\g@addto@macro\xa\htmlize@output\xa{\htmlize@imagetag}%
|
|
\message{moodle.sty: <IMG> 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 <IMG> 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{<IMG SRC="data:image/png;base64,\csname picbaselxiv@\the\numpicturesread\endcsname">}%
|
|
\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'.
|
|
|