summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/moodle
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2021-01-05 03:01:29 +0000
committerNorbert Preining <norbert@preining.info>2021-01-05 03:01:29 +0000
commit3e4b487ff7bce6f8b3965a0fb2a8f73923ed7e63 (patch)
treec12b747e0d08405362064b931be5099bd84b3a5a /macros/latex/contrib/moodle
parentb49dd7c340dbe68a28c8a976cd6a1429ca8aafff (diff)
CTAN sync 202101050301
Diffstat (limited to 'macros/latex/contrib/moodle')
-rw-r--r--macros/latex/contrib/moodle/README.md117
-rw-r--r--macros/latex/contrib/moodle/moodle.dtx3975
-rw-r--r--macros/latex/contrib/moodle/moodle.ins8
-rw-r--r--macros/latex/contrib/moodle/moodle.pdfbin306019 -> 241634 bytes
4 files changed, 3499 insertions, 601 deletions
diff --git a/macros/latex/contrib/moodle/README.md b/macros/latex/contrib/moodle/README.md
index e2ab4cd420..83eb22b4bf 100644
--- a/macros/latex/contrib/moodle/README.md
+++ b/macros/latex/contrib/moodle/README.md
@@ -1,50 +1,67 @@
-==============================================================================
-
-The `moodle' package v0.5
-Copyright (C) 2016 Anders Hendrickson (anders.hendrickson@snc.edu)
-
-This package allows dramatic highlighting of words and phrases
-by painting shapes around them. It is chiefly intended for
-use in Beamer presentations, but it can be used in other
-document classes as well.
-
-Changes:
-- 2016/01/11 Initial version
-
-==============================================================================
-
-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.
-
-
-==============================================================================
-
- This work consists of the files:
-README (this file)
-moodle.dtx
-moodle.ins
- and the derived file:
-moodle.sty
-
- The distribution consists of the files:
-README (this file)
-moodle.dtx
-moodle.ins
-moodle.pdf (the user manual)
-
------------------------------------------------------------------
-
- To install the package:
-- run: latex moodle.ins (which will generate moodle.sty)
-- Move moodle.sty to a location where LaTeX will find it (typically
- in a local texmf tree at tex/latex/moodle) and refresh the
- file database. See the FAQ on CTAN at help/uk-tex-faq or
- http://www.tug.ac.uk/faq for more information on this.
- To process the user manual
-- run: pdflatex moodle.dtx
-- run: pdflatex moodle.dtx
+# License
+
+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.
+
+# Authors
+
+Original contents (2016): [Anders O.F. Hendrickson](/author/hendrickson) ([contact](mailto:anders.o.f.hendricksonATgmail.com))
+
+2019-2021: [Matthieu Guerquin-Kern](author/guerquin-kern) ([contact](mailto:guerquin-kernATcrans.org))
+
+# Contents
+
+This work, under version number 0.8, consists of the files
+[`moodle.dtx`](/tex-archive/macros/latex/contrib/moodle/moodle.dtx),
+[`moodle.ins`](/tex-archive/macros/latex/contrib/moodle/moodle.ins), and the derived documentation
+file [`moodle.pdf`](/tex-archive/macros/latex/contrib/moodle/moodle.pdf).
+
+A TDS archive [moodle.tds.zip](http://mirrors.ctan.org/install/macros/latex/contrib/moodle.tds.zip) is
+also available to be conveniently expanded in your local texmf directory.
+It contains the derived file `moodle.sty` and a set of test files.
+
+# Requirements
+
+This package (`moodle.sty`) requires the following packages:
+- [`environ`](/pkg/environ),
+- [`xkeyval`](/pkg/xkeyval),
+- [`amssymb`](/pkg/amssymb),
+- [`trimspaces`](/pkg/trimspaces),
+- [`etex`](pkg/etex),
+- [`etoolbox`](pkg/etoolbox),
+- [`xpatch`](pkg/xpatch),
+- [`array`](pkg/array),
+- [`ifplatform`](/pkg/ifplatform),
+- [`fancybox`](pkg/fancybox), and
+- [`getitems`](pkg/getitems).
+
+In order to manipulate images, the package relies on the following external tools:
+- [GhostScript](www.ghostscript.com),
+- [ImageMagick](www.imagemagick.org), and
+- [optipng](http://optipng.sourceforge.net/).
+
+In addition, to compile the documentation, the following LaTeX packages are
+necessary:
+- [`amssymb`](pkg/amssymb),
+- [`metalogo`](pkg/metalogo),
+- [`multirow`](pkg/multirow),
+- [`threeparttable`](pkg/threeparttable),
+- [`booktabs`](pkg/booktabs),
+- [`hyperref`](pkg/hyperref),
+- [`tikz`](pkg/tikz),
+- [`minted`](pkg/minted), and
+- [`microtype`](pkg/microtype).
+
+# Building
+
+The file `moodle.sty` can be generated using the command
+```bash
+latex moodle.ins
+````
+The documentation file `moodle.pdf` can be generated by running twice the command
+```bash
+lualatex -shell-escape moodle.dtx
+```
diff --git a/macros/latex/contrib/moodle/moodle.dtx b/macros/latex/contrib/moodle/moodle.dtx
index 02b43f7923..17a7b125b4 100644
--- a/macros/latex/contrib/moodle/moodle.dtx
+++ b/macros/latex/contrib/moodle/moodle.dtx
@@ -1,7 +1,8 @@
% \iffalse meta-comment
%
% moodle.dtx
-% Copyright 2016 by Anders O.F. Hendrickson (anders.hendrickson@snc.edu)
+% Copyright 2016 by Anders O.F. Hendrickson (anders.o.f.hendrickson AT gmail.com)
+% and 2019-2021 by Matthieu Guerquin-Kern (guerquin-kern AT crans.org).
%
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3
@@ -13,7 +14,7 @@
%
% This work has the LPPL maintenance status `maintained'.
%
-% The Current Maintainer of this work is Anders O.F. Hendrickson.
+% The Current Maintainer of this work is Matthieu Guerquin-Kern.
%
% This work consists of the files moodle.dtx and moodle.ins
% and the derived files moodle.sty and getitems.sty.
@@ -27,27 +28,37 @@
%<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01]
%<package>\ProvidesPackage{moodle}
%<*package>
- [2016/01/11 v0.5 Moodle quiz XML generation]
+ [2021/01/04 v0.8 Moodle quiz XML generation]
%</package>
%
%<*driver>
-\documentclass{ltxdoc}
-\usepackage{moodle}
-\usepackage{amssymb}
-\usepackage{fancyvrb}
+\documentclass[a4paper]{ltxdoc}
+\usepackage{iftex}
+\ifPDFTeX
+ \usepackage[utf8]{inputenc} % necessary
+ \usepackage[T1]{fontenc} % necessary
+ \usepackage[protrusion=true,expansion]{microtype}
+ \usepackage[ttscale=.875]{libertine}
+\else % assuming LuaLaTeX or XeLaTeX
+ \usepackage{fontspec}
+ \setmainfont[Mapping=tex-text]{Linux Libertine O}
+\fi
+%\usepackage{moodle}[2020/07/09]
+\usepackage{amssymb,metalogo,multirow,threeparttable,booktabs,hyperref,tikz,minted,changelog}
+\usetikzlibrary{arrows,positioning,decorations.text}
+%\usemintedstyle{Wombat}
\EnableCrossrefs
\CodelineIndex
\OnlyDescription
\RecordChanges
\begin{document}
\DocInput{moodle.dtx}
- \PrintChanges
- %\PrintIndex
+ %\PrintChanges
\end{document}
%</driver>
% \fi
%
-% \CheckSum{3827}
+% \CheckSum{7442} ^^A Comment \OnlyDescription above to adjust
%
% \CharacterTable
% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
@@ -66,9 +77,7 @@
% Right brace \} Tilde \~}
%
%
-% \changes{v0.5}{2016/01/05}{Initial version}
-%
-% \GetFileInfo{moodle.sty}
+% \GetFileInfo{\jobname.dtx}
%
% \DoNotIndex{\newcommand,\newenvironment,\def}
%
@@ -77,8 +86,12 @@
% generating Moodle quizzes via \LaTeX%
% \thanks{This document
% corresponds to \textsf{moodle.sty}~\fileversion, dated \filedate.}}
-% \author{Anders Hendrickson\\ St.~Norbert College, De~Pere, WI, USA \\ \url{anders.hendrickson@snc.edu}}
-% \date{January 11, 2016}
+% \author{Anders Hendrickson\footnote{original author of the package (\texttt{v0.5}), inactive.}\\
+% \texttt{anders.o.f.hendrickson AT gmail.com} \and
+% Matthieu Guerquin-Kern\footnote{current maintainer, author of the updates (\texttt{v0.6}
+% to \texttt{v0.8}), partially funded by \href{https://www.ensea.fr/en/}{ENSEA Graduate School}, France.}\\
+% \href{mailto:guerquin-kern AT crans.org}{guerquin-kern AT crans.org}}
+% \date{January 4, 2021}
%
% \maketitle
%
@@ -87,8 +100,8 @@
% \section{Motivation}
%
% The acronym Moodle stands for ``Modular Object-Oriented Dynamic Learning Environment.''
-% It is an open source learning management system employed by many universities, colleges,
-% and high schools to provide digital access to course materials, such as
+% It is an open source learning management system (LMS) employed by many universities,
+% colleges, and high schools to provide digital access to course materials, such as
% notes, video lectures, forums, and the like; see
% \url{https://moodle.com/moodle-lms/} for more information.
% One of the many useful
@@ -148,28 +161,82 @@
% and the PDF may be previewed onscreen or printed out for ease of proofreading.
% Mathematical graphics can be integrated within the main file through \TikZ,
% and of course \LaTeX\ macros can be customized.
-% Using the present \textsf{moodle.sty} package,
+% Using the present \textsf{moodle} package,
% a quiz author can type a quiz using familiar \LaTeX\ syntax and document
% structure. Upon compilation, \LaTeX\ will generate both a well-organized
% PDF that is easy to proofread and an XML file that can be uploaded directly
% to Moodle. The entire process is far faster than using Moodle's own
% web-based editor, makes it easier to catch one's mistakes,
% and the ultimate source code of one's work is a human-readable |.tex| file
-% that can be archived, browsed, and edited offline.
+% that can be archived, versioned, browsed, and edited offline.
+%
+% Strictly speaking, the \textsf{moodle} package does not generate quizzes:
+% it generates question banks that can be imported in the LMS. The teacher
+% still needs to compose manually a quiz from the question banks. Hopefully,
+% two Moodle features supported by the package make this task easier:
+% categories and tags.
+%
+% In this documentation the LMS is referred to as Moodle (uppercase M and
+% roman font) while the \LaTeX\ package that is documented here is referred
+% to as \textsf{moodle} (all lower case and sans serif font).
%
% \section{Workflow}
-% The process of creating a quiz in Moodle using this package is as follows:
+% The process of creating a quiz in Moodle using this package is depicted in
+% Figure~\ref{fig:workflow}. It follows a few steps:
% \begin{enumerate}
-% \item Write a \LaTeX\ document using |\usepackage{moodle}| as described below.
-% \item Compile the document to PDF using pdf\LaTeX. This will also produce the file
-% \meta{jobname}|-moodle.xml|.
+% \item Write a \LaTeX\ document using |\usepackage{moodle}| as described
+% below.
+% \item Compile the document to PDF using pdf\LaTeX\, \XeLaTeX\ or \LuaLaTeX.
+% This will also produce the file \meta{jobname}|-moodle.xml|.
% \item Open Moodle, navigate to the desired course,
% and under ``Question bank'' select ``Import.''
% \item Select ``Moodle XML format,'' choose the XML file to upload, and press ``Import.''
% \item After Moodle verifies that the questions have been imported correctly,
% you may add them to your quizzes.
% \end{enumerate}
-%
+% \begin{figure}[tbp]
+% \centering
+% \begin{tikzpicture}[node distance=1,auto,bend
+% angle=45,box/.style={rectangle,draw=blue!50,rounded corners=3,top
+% color=white,bottom color=black!20,thick,align=center,text
+% width=2.5cm},elmt/.style={font=\itshape,align=left},
+% cmnt/.style={font=\footnotesize,align=center},
+% bigcmnt/.style={font=\normalsize,align=center},pre/.style={<-,>=stealth',thick},
+% post/.style={->,>=stealth',thick}, prepost/.style={<->,>=stealth',thick}]
+% \draw[white,fill=orange!20,rounded corners=10]
+% (-1.5,-.7)--++(0,1.4)--++(10.3,0)--++(0,-3.3)--++(-6.7,0)--++(-.25,1.725)--cycle;
+% \node[orange!80!black,above] (dev) at (7.5,-2.6) {\textit{Developpement}};
+% \fill[green,fill opacity=.2,rounded corners=10]
+% (-1.5,.7)--++(3,0)--++(0.5,-3.4)--++(6.8,0)--++(0,-2)--++(-10.3,0)--cycle;
+% \node[green!80!black,below] (dev) at (7.5,-2.7) {\textit{Publishing}};
+% \node[box,text width=2cm] (tex) {\texttt{.tex} source file};
+% \node[rectangle,fill=white,draw,align=center,text
+% width=1.5cm,below=of tex] (compfinal) {\LaTeX{}\\ engine};
+% \node[rectangle,fill=white,draw,align=center,text width=1.5cm,right=of tex,xshift=4.5cm]
+% (compdraft) {\LaTeX{}\\ engine};
+% \node[box,right=of compfinal,xshift=.5cm] (pdf) {\texttt{.pdf} file for proofreading};
+% \node[rectangle,fill=white,draw,align=center,text width=2cm,below=of compfinal] (extern)
+% {Picture\\processing};
+% \draw (pdf|-extern) node[box,anchor=center] (xml) {\texttt{.xml} file\\\footnotesize(pictures embedded)};
+% \draw (compdraft|-xml)
+% node[rectangle,fill=white,draw,align=center,text width=1.5cm,anchor=center] (moodle)
+% {Moodle\\Server};
+% \draw (tex) edge [post,bend right=10] node[cmnt,pos=.5,left] {\texttt{final}} (compfinal);
+% \draw (tex) edge [post,bend left=10] node[cmnt,pos=.5,below] {\texttt{draft}} (compdraft);
+% \draw (compdraft) edge [post,bend left=10] (pdf);
+% \draw (compfinal) edge [post] (pdf);
+% \draw (compfinal) edge [post,bend left=10] (xml);
+% \draw (compfinal) edge [post,bend right=30] node[cmnt,black!40,pos=.5,text width=1cm,left]
+% {\texttt{tikz}, \texttt{.png}, \texttt{.jpg}} (extern);
+% \draw (extern) edge [post,green,bend right=30] node[cmnt,black!40,pos=.5,below,right]
+% {\texttt{base64}} (compfinal);
+% \draw (pdf) edge [post,red,bend right=15] node[sloped,cmnt,pos=.5,above] {improve} (tex);
+% \draw (xml) edge [post,red] node[cmnt,pos=.5,below] {import} (moodle);
+% \end{tikzpicture}
+% \caption{Block diagram describing a typical workflow using the \textsf{moodle} package.}
+% \label{fig:workflow}
+% \end{figure}
+%
% \section{Usage}\label{sect:usage}
% \subsection{Example Document}
%
@@ -177,35 +244,34 @@
% and editing Moodle quizzes through the web interface.
% The |xkeyval| package is used to provide a key-value interface.
% Here is a simple example document:
-% \begin{verbatim}
+% \begin{VerbatimOut}[gobble=1]{minted.doc.out}
% \documentclass[12pt]{article}
-% \usepackage{moodle}
-%
+% \usepackage[section]{moodle}
+% \moodleregisternewcommands
+% \newcommand\monomial[1]{x^{#1}}
+% \newcommand\sillyanswer{What!?}
% \begin{document}
-%
% \begin{quiz}{My first quiz}
% \begin{numerical}[points=2]{Basic addition}
% What is $8+3$?
% \item 11
% \end{numerical}
-%
-% \begin{shortanswer}[case sensitive=true]{Newton's name}
+% \begin{shortanswer}[usecase]{Newton's name}
% What was Newton's first name?
% \item Isaac
-% \item[fraction=0, feedback={No, silly!}] Fig
-% \item{fraction=0} Sir
+% \item[fraction=0, feedback={\sillyanswer}] Fig
+% \item[fraction=0] Sir
% \end{shortanswer}
-%
% \begin{multi}[points=3]{A first derivative}
-% What is the first derivative of $x^3$?
-% \item $\frac{1}{4} x^4+C$
-% \item* $3x^2$
-% \item $51$
+% What is the first derivative of $\monomial{3}$?
+% \item $\frac{1}{4}\monomial{4}+C$
+% \item[feedback={yes!}]* $3\monomial{2}$
+% \item[feedback={\sillyanswer}] $51$
% \end{multi}
% \end{quiz}
-%
% \end{document}
-% \end{verbatim}
+% \end{VerbatimOut}
+% \inputminted[gobble=2,frame=lines]{latex}{minted.doc.out}
% Key features to note in this first example are that a |quiz| environment
% contains several question environments.
% Each question takes a name as a mandatory argument,
@@ -214,39 +280,102 @@
% such as |itemize| or |enumerate|, in that answers are set off by
% |\item|'s, but the question itself is the text that occurs before
% the first |\item|.
+%
+%^^A \DescribeMacro{\moodleregisternewcommands}\DescribeMacro{\htmlregister}
+%^^A Calling |\moodleregisternewcommands| tells the package to treat
+%^^A specifically the macros defined subsequently.
+%^^A This way, the macros that Moodle's \LaTeX\ renderer does not know
+%^^A about can be properly expanded in the XML file.
+%^^A This mechanism applies only to the macros defined using |\newcommand|
+%^^A and \emph{without} optional argument.
+%^^A Using |\htmlregister|\marg{macroname}, lets you declare a specific
+%^^A macro for expansion. This mechanism, instead, also applies to the
+%^^A macros defined using \TeX's primitive |\def|.
%
+% \subsection{Package Options}
% \DescribeMacro{draft}
-% If the package option |draft| is invoked, by calling |\usepackage[draft]{moodle}|,
-% then no XML file will be generated. This is especially useful while editing a quiz
-% containing graphics, so as to avoid the time spent converting image files.
+% \DescribeMacro{final}
+% If the package option |draft| is invoked, by calling
+% |\usepackage[draft]{moodle}| or |\documentclass[draft]{...}|, then no
+% XML file will be generated. This is especially useful while editing a
+% quiz containing graphics, so as to avoid the time spent converting
+% image files. The package option |final| might be useful if one wants
+% to avoid the option |draft| to be inherited from the |documentclass|.
+%
+% \DescribeMacro{handout}
+% If the package option |handout| is invoked (|\usepackage[handout]{moodle}|),
+% the PDF file is generated clean from teacher-only information (answers,
+% points, penalty, feedback, tags) and, hence, can be given to students for
+% classroom work. In particular, as would Moodle do, answers in
+% \texttt{matching} questions are shuffled and the option \texttt{shuffle}
+% triggers the shuffling of choices offered (\texttt{multi} and
+% \texttt{matching}). This is achieved thanks to the package
+% \texttt{randomlist}, loaded if the option is invoked.
+% The XML file is generated as usual.
+%
+% \DescribeMacro{nostamp}
+% By default, the package will output a stamp as a comment in the XML
+% file. This stamp contains information gathered about the TeX engine,
+% the operating system used and the package version. For instance:
+% \begin{quote}\small
+% |<!-- This file was generated on 2020-11-30 by LuaLaTeX -->|\\
+% |<!-- running on Linux with the package moodle |\texttt{\fileversion}| -->|
+% \end{quote}
+% The package option
+% |nostamp| prevents this stamp to be written in the XML file.
+%
+% \DescribeMacro{section}
+% \DescribeMacro{section*}
+% \DescribeMacro{subsection}
+% \DescribeMacro{subsection*}
+% If the package option |section| is invoked (|\usepackage[section]{moodle}|),
+% then each quiz is represented by a different \LaTeX\ section. Starred
+% variants correspond to unnumbered sections or subsections. To preserve
+% compatibility with Version 0.5 of this package, the default is |subsection*|.
+% Consequently, |\usepackage{moodle}| is equivalent to
+% |\usepackage[subsection*]{moodle}|.
+%
+% \DescribeMacro{tikz} The package option \texttt{tikz} is described in section
+% \ref{subsec:tikz}.
+%
+% \DescribeMacro{svg} The package option \texttt{svg} is described in section
+% \ref{subsec:svg}.
%
-% \newpage
% \subsection{Quiz and Question Environments}
%
% \DescribeMacro{quiz}
% A |.tex| document to generate Moodle quizzes contains one or more
% |quiz| environments, within which various question environments are nested.
-% The required argument to the |quiz| environment names the ``question bank''
-% to which the questions inside will belong after being uploaded to moodle.
+% The required argument to the |quiz| environment names a category for Moodles
+% ``question bank'': after import, the questions defined in this environment
+% will be gathered in this category.
% \begin{center}
-% |\begin{quiz}|\oarg{options}\marg{question bank name}%
+% |\begin{quiz}|\oarg{options}\marg{category name}%
% \end{center}
% There are no |quiz|-specific options,
% but any \meta{options} set with |\begin{quiz}|
% will be inherited by all questions contained within that |quiz| environment.
%
% \DescribeMacro{\moodleset}
-% Options may also be set at any time with |\moodleset|\marg{options};
-% these changes are local to \TeX-groups.
-% \bigskip
+% Options may also be set outside question environments with
+% |\moodleset|\marg{options}; these changes are local to \TeX-groups.
+%
+% \DescribeMacro{\setcategory}\DescribeMacro{\setsubcategory}
+% Although the |quiz| environment defines a category by its own, one can change
+% the current category inside the quiz environment and in between questions,
+% using the macro |\setcategory|\marg{category name}. A subcategory can also be
+% defined with |\setsubcategory|\marg{subcategory name}. The categories and
+% subcategories are reflected in the PDF file as sections, subsections, or
+% subsubsections, in accordance to the package setting |section|, |section*|,
+% |subsection|, or |subsection*|.
%
% The syntax for each question environment is
% \begin{quote}
% |\begin|\marg{question type}\oarg{question options}\marg{question name} \\
% \rule{2em}{0pt}\meta{question text} \\
-% \rule{2em}{0pt}|\item| \meta{item} \\
+% \rule{2em}{0pt}|\item|\oarg{item options} \meta{item} \\
% \rule{2em}{0pt}\quad$\vdots$ \\
-% \rule{2em}{0pt}|\item| \meta{item} \\
+% \rule{2em}{0pt}|\item|\oarg{item options} \meta{item} \\
% |\end|\marg{question type}
% \end{quote}
% The meaning of the \meta{item}s varies depending on the question type,
@@ -268,13 +397,54 @@
% \DescribeMacro{fraction}
% In most question types, it is possible to designate some answers as being
% worth partial credit---that is, some fraction of a completely correct answer.
-% The |fraction| key may be set to any integer from |0| (entirely wrong) to |100| (entirely correct).
+% The |fraction| key may be set to any of the values given in Table~\ref{tab:fraction},
+% from |0| (entirely wrong) to |100| (entirely correct).
+%
+% \begin{table}[tbp]
+% \centering
+% \caption{\href{https://github.com/moodle/moodle/blob/MOODLE\_310\_STABLE/question/engine/bank.php\#L339}{Valid positive options} for the \texttt{fraction} key: $100\cdot(p/q)$.}
+% \label{tab:fraction}
+% \footnotesize
+% \begin{tabular}{l*{10}{l}}
+% \toprule
+% Denominator $q$ & \multicolumn{10}{c}{Numerator $p$}\\
+% \cmidrule{2-11}
+% & 0 & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9\\
+% \cmidrule(lr){1-1}\cmidrule(lr){2-2}\cmidrule(lr){3-3}\cmidrule(lr){4-4}
+% \cmidrule(lr){5-5}\cmidrule(lr){6-6}\cmidrule(lr){7-7}\cmidrule(lr){8-8}
+% \cmidrule(lr){9-9}\cmidrule(lr){10-10}\cmidrule(lr){11-11}
+% 20 & 0&5&&&&&&&&\\\cmidrule(lr){1-1}
+% 10 & &10&20&30&40&50&60&70&80&90\\\cmidrule(lr){1-1}
+% 9 & &11.11111&&&&&&&&100\\\cmidrule(lr){1-1}
+% 8 & &12.5&&&&&&&100&\\\cmidrule(lr){1-1}
+% 7 & &14.28571&&&&&&100&&\\\cmidrule(lr){1-1}
+% 6 & &16.66667&&&&83.33333&100&&&\\\cmidrule(lr){1-1}
+% 5 & &20&&&80&100&&&&\\\cmidrule(lr){1-1}
+% 4 & &25&&75&100&&&&&\\\cmidrule(lr){1-1}
+% 3 & &33.33333&66.66667&100&&&&&&\\\cmidrule(lr){1-1}
+% 2 & &50&100&&&&&&&\\\cmidrule(lr){1-1}
+% 1 & 0&100&&&&&&&&\\\cmidrule(lr){1-1}
+% \bottomrule
+% \end{tabular}
+% \end{table}
+% In questions where several choices can be selected (see |multi| with the option
+% |multiple|), positive fractions must sum up to exactly 100. It is also possible to set
+% negative fractions (from -100 to 0) for wrong choices, in order to prevent the
+% selection of all choices from leading to a good grade.
+% In this case, the value ranging from -100 to 0 must be the opposite of one of the
+% values listed in Table~\ref{tab:fraction}.
%
+% \DescribeMacro{fractiontol}
+% The package tries to match the |fraction| key to one of the admissible values.
+% To this end, the tolerance is controlled by the |fractiontol| key. It defaults
+% to |0.01| but may be changed. When no admissible fraction value is matched, the
+% package throws an error.
+%
% \DescribeMacro{feedback}
% The |feedback| key sets text that will appear to the student after completing the quiz.
% For example, one might set
% \begin{center}
-% |feedback={A question like this will appear on the exam.}|
+% |feedback={This question might show up in the final exam.}|
% \end{center}
% The desired feedback should be included in braces.
%
@@ -282,13 +452,56 @@
% question, then that feedback will appear to each student regardless of the student's answer.
% Answer-specific feedback (perhaps explaining a common mistake)
% may also be given by setting the |feedback| key \emph{at the individual answer}.
+%
+% \DescribeMacro{tags}
+% The |tags| key sets a keyword for the question that will be taken into account by Moodle for
+% filtering purposes or classification of questions inside the question bank. It is possible
+% for instance to build a quiz with questions cherry-picked among the set of questions holding
+% a particular tag.
+% For example, one might set
+% \begin{center}
+% |tags={easy}|
+% \end{center}
+% The desired tag should be included in braces.
+%
+% Tags can be assigned at two levels. If the |tags| key is set at the quiz level,
+% then that tags will be assigned by default to each question of the quiz.
+% Question-specific tags can be assigned by setting the |tags| key \emph{at the question level}.
+% Since only single tag is supported, the tag a the question-level overrides eventual tags
+% specified at the quiz-level.
%
-% \newpage
% \subsection{Question Types}
%
-% We next discuss the various question types supported by \textsf{moodle.sty}
+% We next discuss the various question types supported by \textsf{moodle}
% and the options that may be set.
+%
+%\subsubsection{True/False}
+%
+% \DescribeMacro{truefalse}
+% The syntax for a True/False question is as follows:
+% \begin{quote}
+% |\begin{truefalse}|\oarg{question options}\marg{question name} \\
+% \rule{2em}{0pt}\meta{question text} \\
+% \rule{2em}{0pt}|\item*| \meta{feedback when ``true" is chosen} \\
+% \rule{2em}{0pt}|\item| \meta{feedback when ``false" is chosen} \\
+% |\end{truefalse}|
+% \end{quote}
+% The correct answer is designated by the asterisk |*| after the |\item|;
+% it need not appear first in the list.
+%
+% Answer-specific feedback can also be defined as an item option, similarly to
+% other types.
+% \begin{quote}
+% |\begin{truefalse}|\oarg{question options}\marg{question name} \\
+% \rule{2em}{0pt}\meta{question text} \\
+% \rule{2em}{0pt}|\item[feedback={|\meta{When ``true" is chosen}|}]*| \\
+% |\end{truefalse}|
+% \end{quote}
+% Note that, in this example, no feedback is defined for the incorrect answer
+% ``False": the corresponding item can be omitted.
%
+% With the True/False question type, the |penalty| key has no effect.
+%
% \subsubsection{Multiple Choice}
%
% \DescribeMacro{multi}
@@ -319,54 +532,66 @@
% which mirror the usual \LaTeX\ syntax:
% |alph|, |Alph|, |arabic|, |roman|, |Roman|, and |none|.
% Calling |numbering=none| produces an unnumbered list of answers.
-% The Moodle syntax of |abc|, |ABC|, |123|, |iii|, and |IIII| is also acceptable,
-% but note that it requires \emph{four} |I|'s to obtain upper-case Roman numerals this way.
+% The Moodle syntax of |abc|, |ABCD|, |123|, |iii|, and |IIII| is also
+% acceptable,
+% but note that it requires \emph{four} capital letters to obtain
+% upper-case Roman or alphabetic numerals this way.
%
% \DescribeMacro{fraction}
% The |fraction| key can be used to designate some wrong answers
% as being worth partial credit. For example, a question might read thus:
-% \begin{verbatim}
+% \begin{VerbatimOut}[gobble=1]{minted.doc.out}
% \begin{multi}{my question}
% Compute $\int 4x^3\,dx$.
% \item* $x^4+C$
% \item[fraction=50] $x^4$
% \item $12x^2$
% \end{multi}
-% \end{verbatim}
+% \end{VerbatimOut}
+% \inputminted[gobble=2,frame=lines]{latex}{minted.doc.out}
% Thus the asterisk |*| is shorthand for |fraction=100|,
% whereas a bare |\item| sets |fraction=0|.
%
-% \DescribeMacro{single}\DescribeMacro{multiple}
+% \DescribeMacro{single}
% By default, the |multi| environment produces
-% a multiple choice question operates with only one correct answer;
+% a multiple choice question with only one correct answer;
% this is called |single| mode, and on Moodle it appears with radio buttons.
-% It is also possible to write questions with more than one correct answer,
-% asking the user to check all correct answers.
-% To do this, use the key |multiple| or |single=false|.
-%
+%
+% \DescribeMacro{multiple}
+% It is also possible to write questions with possibly more than one correct answer,
+% asking the user to check all correct answers. To do this, use the key |multiple|
+% or |single=false|.
% The worth of each correct answers in |multiple| mode may be set by |fraction|,
-% but Moodle will require that all the fractions add up to at least 100.
-% If you simply designate each correct answer with |\item*|, then \textsf{moodle.sty}
-% will divide the 100\% equally among those answers.
-% For example, the following two examples produce equivalent results:
-% \begin{verbatim}
+% but Moodle asks that all the fractions add up to \emph{exactly} 100.
+% If you simply designate each correct answer with |\item*|, then \textsf{moodle}
+% will divide equally among those answers the points lefts for a sum of 100\%.
+% Items that are not given a |fraction| are considered incorrect and selecting them
+% results in negative points such that the sum of all incorrect answers is -100\%.
+% For example, the following two examples are equivalent:
+% \begin{VerbatimOut}[gobble=1]{minted.doc.out}
% \begin{multi}[multiple]{my question}
% Which numbers are prime?
+% \item[fraction=20] 2
% \item* 5
-% \item 6
% \item* 7
+% \item[fraction=-10] 1
+% \item 6
% \item 8
% \end{multi}
-% \end{verbatim}
-% \begin{verbatim}
+%
% \begin{multi}[multiple]{my question}
% Which numbers are prime?
-% \item[fraction=50] 5
-% \item 6
-% \item[fraction=50] 7
-% \item 8
+% \item[fraction=20] 2
+% \item[fraction=40] 5
+% \item[fraction=40] 7
+% \item[fraction=-10] 1
+% \item[fraction=-45] 6
+% \item[fraction=-45] 8
% \end{multi}
-% \end{verbatim}
+% \end{VerbatimOut}
+% \inputminted[gobble=2,frame=lines]{latex}{minted.doc.out}
+% Note that, in this example, negative fractions are set for wrong choices. This
+% prevents students selecting all options to obtain a good grade with no merit.
%
% \subsubsection{Numerical}
%
@@ -387,8 +612,41 @@
% \begin{quote}\footnotesize
% |\item[fraction=0,feedback={You forgot to antidifferentiate!}]| \meta{incorrect answer}
% \end{quote}
+%
+% \DescribeMacro{tolerance}
+% The |tolerance| key can be used to specify the validity of answers within some margin.
+% This key can be set at different levels: quiz, question, item.
+% For example, with the question
+% \begin{VerbatimOut}[gobble=1]{minted.doc.out}
+% \begin{numerical}[tolerance=0.01]{my question}
+% Approximate value of $\sqrt{2}$?
+% \item[tolerance={1e-1}] 1.4142
+% \item[fraction=20,feedback={twice this!}] 7.0711e-1
+% \item[fraction=0,feedback={Wrong!}] *
+% \end{numerical}
+% \end{VerbatimOut}
+% \inputminted[gobble=2,frame=lines]{latex}{minted.doc.out}
+% In this example,
+% \begin{itemize}
+% \item any answer in the range $[1.4042,1.4242]$ will be validated,
+% \item any answer in the range $[0.69711,0.71711]$ will get the specific feedback
+% \emph{twice this!} and 20\% of points,
+% \item any other answer is incorrect and will get the specific feedback
+% \emph{Wrong!}.
+% \end{itemize}
+%
+% When feedback is to be given for any non-specified answer, one can add a \emph{last} answer
+% item containing the wilcard character |*| only. In this case, the |tolerance| key is irrelevant.
+%
+% Both answers and tolerance can be specified with the comma (|,|) as a decimal separator.
+% Exponent notation is accepted. After import, Moodle will recognize indifferently |0.000165|,
+% |0,000165|, |1.65E-4|, |1.65e-4|, |1,65E-4|, and |1,65e-4|.
+%
+% If the \textsf{siunitx} package is loaded, \textsf{moodle} will detect it and
+% numbers will be rendered nicely in the PDF output.
%
-% \newpage
+% Units, unit-handling and multipliers are currently unsupported.
+%
% \subsubsection{Short Answer}
% A short answer question resembles a numerical question: the student is to fill
% in a text box with a missing word or phrase.
@@ -403,25 +661,40 @@
% You can make the text box appear as part of the question with the
% control sequence |\blank|. For example,
% your question might read
-% \begin{verbatim}
+% \begin{VerbatimOut}[gobble=1]{minted.doc.out}
% \begin{shortanswer}{Leibniz}
% Newton's rival was Gottfried Wilhelm \blank.
% \item Leibniz
% \item Leibniz.
% \end{shortanswer}
-% \end{verbatim}
+% \end{VerbatimOut}
+% \inputminted[gobble=2,frame=lines]{latex}{minted.doc.out}
% Note that as the blank occurred at the end of a sentence,
% we included two answers,
% lest students get the question wrong merely by
% including or omitting a period.
%
% \DescribeMacro{case sensitive}\DescribeMacro{usecase}
-% By default, Moodle ignores the distinction between upper- and lower-case letters
-% when grading a short answer question.
+% The default setting when creating a Short Answer question in Moodle
+% is to ignore the distinction between upper- and lower-case letters
+% when grading a short answer question. This default is preserved by
+% \textsf{moodle}.
% You can make a question case-sensitive with the key |case sensitive|
% or its shorter synonym |usecase|.
+%
+% The wildcard character |*| can used to grab answers that match
+% a specific pattern. For instance:
+% \begin{itemize}
+% \item ``\emph{Sir Isaac Newton}'', ``\emph{Isaac Newton}'' and
+% ``\emph{Newton}'' will match the pattern |*Newton|,
+% \item ``\emph{Gaston}'' and ``\emph{Wellington}'' will match the
+% pattern |*ton|,
+% \item ``\emph{Isaac}'' and ``\emph{Isaac Newton}'' will match the
+% pattern |Isaac*|,
+% \item any non empty answer will match the pattern |*| (wildcard alone).
+% \end{itemize}
%
-% \subsubsection{Essay Questions}
+% \subsubsection{Essay}\label{subsubsect:essay}
% Instructors may ask essay questions on a Moodle quiz,
% although Moodle's software is not up to the task of grading them!
% Instead each essay question answer must be graded manually by the
@@ -443,22 +716,23 @@
% If the |response required| key is set, Moodle will insist that the student
% enter something in the blank before accepting the quiz as completed.
%
-% \newpage
% \DescribeMacro{response format}
% Moodle offers five different ways for students to enter and/or upload their
% answers to an essay question. You may choose one of these five options:
% \begin{description}
-% \item[{\tt html}] An editor with the ability to format HTML responses
+% \item[{\ttfamily html}] An editor with the ability to format HTML responses
% including markup for italics, boldface, etc. This is the default.
-% \item[{\tt file}] A file picker allowing the student to upload a file, such as
-% a PDF or DOC file, containing the essay.
-% \item[{\tt html+file}] The same HTML editor as above, but with the ability
-% to upload files as well. This permits some students to type answers
-% directly into the web form, and others to compose their essays in
-% another program first.
-% \item[{\tt text}] This editor allows only for entering plain text without any markup.
-% \item[{\tt monospaced}] This yields a plain text editor, without any markup,
-% and with a fixed-width font. This could be useful for entering code snippets, for example.
+% \item[{\ttfamily file}] A file picker allowing the student to upload a
+% file, such as a PDF or DOC file, containing the essay.
+% \item[{\ttfamily html+file}] The same HTML editor as above, but with the
+% ability to upload files as well. This permits some students to type
+% answers directly into the web form, and others to compose their
+% essays in another program first.
+% \item[{\ttfamily text}] This editor allows only for entering plain text
+% without any markup.
+% \item[{\ttfamily monospaced}] This yields a plain text editor, without any
+% markup, and with a fixed-width font. This could be useful for
+% entering code snippets, for example.
% \end{description}
%
% \DescribeMacro{response field lines}
@@ -473,16 +747,16 @@
% You may also require the student to upload a certain number of attachments
% by setting |attachments required| to |0|, |1|, |2|, or |3|.
%
-% \DescribeMacro{response template}
+% \DescribeMacro{template}
% Finally, you may preload the essay question with a template that the student
-% will edit and/or type over, with the key |response template=|\marg{template}.
+% will edit and/or type over, with the key |template=|\marg{template}.
% The \meta{template} should be enclosed in braces.
%
-% \subsection{Matching Questions}
+% \subsubsection{Matching}
%
% A matching question offers a series of subquestions
% and a set of possible answers from which to choose.
-% If there are $m$ questions and $n$ possible answers,
+% If there are $m$ questions and $n\geq m$ possible answers,
% a matching question will look like this:
%
% \begin{quote}
@@ -508,19 +782,18 @@
% permute the questions and answers; by default |shuffle=true|.
%
% \DescribeMacro{drag and drop}\DescribeMacro{dd}
-% Moodle has two formats for matching questions.
-% The older matching question offered a dropdown box
-% for choosing the answer to each question;
-% the newer ``drag and drop matching'' format
+% The standard matching question offered by Moodle corresponds to
+% a dropdown box for choosing the answer to each question.
+% There also exists a ``drag and drop matching'' plugin for Moodle that
% shows all questions in one column,
% all answers in a second column, and allows students to drag the correct
% answer to the question using a mouse.
-% To enable drag-and-drop matching, use the key `|drag and drop|' or `|dd|' for
-% short. The default is |dd=false|. If you choose the older format,
-% then due to the limitations of dropdown boxes, no \LaTeX\ or HTML code can be used
-% in the answers.
+% In this package, to enable drag-and-drop matching, use the key
+% `|drag and drop|' or `|dd|' for short. The default is |dd=false|.
+% If you choose the standard format, then due to the limitations of
+% dropdown boxes, no \LaTeX\ or HTML code can be used in the answers.
%
-% \subsection{Cloze Questions}
+% \subsubsection{Cloze Questions and Subquestions}
%
% A ``cloze question'' has one or more subquestions embedded within a passage of text.
% For example, you might ask students to fill in several missing words within
@@ -528,10 +801,10 @@
% To encode cloze questions in \LaTeX\ using this package is easy:
% you simply nest one or more |multi|, |shortanswer|, or |numerical| environments
% within a |cloze| environment, as in the following example:
-% \begin{verbatim}
-% \begin{cloze}{my cloze question} \\
+% \begin{VerbatimOut}[gobble=1]{minted.doc.out}
+% \begin{cloze}{my cloze question}
% Thanks to calculus, invented by Isaac
-% \begin{shortanswer}
+% \begin{shortanswer}[usecase]
% \item Newton
% \end{shortanswer},
% we know that the derivative of $x^2$ is
@@ -542,80 +815,207 @@
% \end{multi}
% and that $\int_0^2 x^2\,dx$ equals
% \begin{numerical}
-% \item[tolerance=0.0004] 2.667
+% \item[tolerance={4e-4}] 2.667
% \end{numerical}.
% Thanks, Isaac!
% \end{cloze}
-% \end{verbatim}
+% \end{VerbatimOut}
+% \inputminted[gobble=2,frame=lines]{latex}{minted.doc.out}
% Note that when used as a subquestion within a cloze question,
% |\begin{multi}| is \emph{not} followed by name in braces;
% the same is true for the |shortanswer| and |numerical|
% environments.
%
-% \DescribeMacro{vertical}\DescribeMacro{horizontal}
-% Within a cloze question, by default a multiple choice question is implemented
-% as an inline dropdown box. This is visually compact, but it also prevents the
-% use of mathematical or HTML formatting.
+% \DescribeMacro{single=true}\DescribeMacro{single=false}\DescribeMacro{multiple}
+% Before Moodle version 3.5, within a cloze question, a multiple choice question
+% was necessarily of type |single|, i.e. with a single good answer. If you intend
+% to export your quiz to Moodle 3.5+, the option |multiple| can be used, when
+% multiple good answers are to be found.
+%
+% \DescribeMacro{vertical}\DescribeMacro{horizontal}\DescribeMacro{inline}
+% Within a cloze question, by default, a multiple choice question is implemented
+% as an |inline| dropdown box. This is visually compact, but it also prevents
+% the use of mathematical or HTML formatting.
% Adding the option |vertical| displays the subquestion as a vertical column
% of radio buttons instead; likewise the option |horizontal| creates a horizontal
% row of radio buttons.
+% The option |inline| is incompatible with |multiple| or |single=false|
+% (dropdown boxes don't let you pick up several answers!).
+%
+% \DescribeMacro{shuffle}
+% Starting from Moodle version 3.0, within a cloze question, the items of a
+% multiple choice question can be shuffled. Setting |shuffle=false| will
+% guarantee that the answer appear in the order they were typed; the
+% default is |shuffle=true|.
+%
+% \DescribeMacro{case sensitive}\DescribeMacro{usecase}
+% Within a cloze question, the short answer question can be made case sensitive.
+% This option, disabled by default, is selected with |case sensitive| or |usecase|.
+%
+%\subsubsection{Description}
+%
+% The Moodle description type is not really a question. It is more like a label.
+% One can set a |feedback| that the student gets when reviewing the submission.
+% Tags can be set as well.
+%
+% For descriptions, \textsf{moodle} redefines the existing |description| environment.
+%
+% The syntax for a Description question is as follows:
+% \begin{quote}
+% |\begin{description}|\oarg{question options}\marg{question name} \\
+% \rule{2em}{0pt}\meta{question text} \\
+% |\end{description}|
+% \end{quote}
+%
+% \subsection{Summary of the Key Options}
+%
+% Table~\ref{tab:key-options} summarizes the key options available at the question
+% and answer levels depending on the question type. For the essay questions,
+% please refer to section~\ref{subsubsect:essay}.
+%
+% \begin{table}[tbp]
+% \centering
+% \caption{Options offered at the question and answer levels for each question type.}
+% \label{tab:key-options}
+% \small
+% \begin{tabular}{*{14}{l}}
+% \toprule
+% & \multicolumn{10}{l}{Question} & \multicolumn{3}{l}{Answer}\\
+% \cmidrule(lr){2-11}\cmidrule(lr){12-14}
+% Question type & \rotatebox{90}{points} &
+% \rotatebox{90}{penalty} & \rotatebox{90}{feedback} & \rotatebox{90}{tags} &
+% \rotatebox{90}{shuffle} & \rotatebox{90}{numbering} & \rotatebox{90}{multiple} &
+% \rotatebox{90}{usecase} & \rotatebox{90}{tolerance} &\rotatebox{90}{dd} &
+% \rotatebox{90}{fraction} & \rotatebox{90}{feedback} &
+% \rotatebox{90}{tolerance}\\\cmidrule(lr){1-1}\cmidrule(lr){2-2}\cmidrule(lr){3-3}
+% \cmidrule(lr){4-4}\cmidrule(lr){5-5}\cmidrule(lr){6-6}\cmidrule(lr){7-7}
+% \cmidrule(lr){8-8}\cmidrule(lr){9-9}\cmidrule(lr){10-10}\cmidrule(lr){11-11}
+% \cmidrule(lr){12-12}\cmidrule(lr){13-13}\cmidrule(lr){14-14}
+% \href{https://docs.moodle.org/35/en/Multiple_Choice_question_type}
+% {Multichoice} & $\bullet$ & $\bullet$ & $\bullet$ & $\bullet$ &
+% $\bullet$ & $\bullet$ & $\bullet$ & & & & $\bullet$ & $\bullet$ \\
+% \href{https://docs.moodle.org/35/en/Numerical_question_type}{Numerical}
+% & $\bullet$ & $\bullet$ & $\bullet$ & $\bullet$ & & &
+% & & $\bullet$ & & $\bullet$ & $\bullet$ & $\bullet$ \\
+% \href{https://docs.moodle.org/35/en/Short-Answer_question_type}{Short
+% Answer} & $\bullet$ & $\bullet$ & $\bullet$ & $\bullet$ & & &
+% & $\bullet$ & & & $\bullet$ & $\bullet$ \\
+% \href{https://docs.moodle.org/35/en/Matching_question_type}{Matching}
+% & $\bullet$ & $\bullet$ & $\bullet$ & $\bullet$ & $\bullet$ & &
+% & & & $\bullet$ & $\bullet$ & \\
+% \href{https://docs.moodle.org/35/en/True/False_question_type}
+% {True/False} & $\bullet$ & & $\bullet$ & $\bullet$ & & &
+% & & & & & $\bullet$ \\
+% \href{https://docs.moodle.org/35/en/Description_question_type}
+% {Description} & & & $\bullet$ & $\bullet$ & & &
+% & & & & & \\
+% ^^A\href{https://docs.moodle.org/35/en/Essay_question_type}{Essay} & \\\hline%
+% \href{https://docs.moodle.org/35/en/Embedded_Answers_(Cloze)_question_type}{Cloze}
+% & $\bullet$ & $\bullet$ & $\bullet$ & $\bullet$ & & &
+% & & & & & \\\cmidrule(lr){1-1}
+% \hspace{1em}Numerical & $\bullet$ & & & & & &
+% & &$\bullet$ & & $\bullet$ & $\bullet$ & $\bullet$ \\
+% \hspace{1em}Short Answer & $\bullet$ & & & & & &
+% & $\bullet$ & & & $\bullet$ & $\bullet$ \\
+% \hspace{1em}Multi (regular) & $\bullet$ & & & & $\bullet$ & & $\bullet$
+% & & & & $\bullet$ & $\bullet$ \\
+% \hspace{1em}Multi (horizontal)& $\bullet$ & & & & $\bullet$ & & $\bullet$
+% & & & & $\bullet$ & $\bullet$ \\
+% \hspace{1em}Multi (vertical)& $\bullet$ & & & & $\bullet$ & &
+% & & & & $\bullet$ & $\bullet$ \\
+% \bottomrule
+% \end{tabular}
+% \end{table}
%
% \section{Conversion to HTML}
%
% Questions should be typed as usual for \LaTeX,
-% including |\$| to obtain dollar signs, |$|'s for math shifts,
-% |$$|'s for display math, et cetera.
+% including |\$| to obtain dollar signs, |$|'s or |\(|...|\)| for math shifts,
+% |$$|'s or |\[|...|\]| for display math, et cetera.
% The package \textsf{moodle.sty} automatically converts
% this \LaTeX\ code into HTML for web display.
%
-% The following table lists \LaTeX\ commands and environments that
-% will be converted to HTML:
-% \begin{center}
-% \begin{tabular}{lll}
-% |~| & |\#| & |\$| \\
-% |\&| & |\\| & |\S| \\
-% |\{| & |\}| & {\tt\catcode`\ =12\relax\catcode`\\=12\relax\ }\\
-% |\emph| & |\textbf| & |\par| \\
-% |\ldots| & |\dots| & |\relax| \\
-% |\euro| & |\texteuro| \\
-% |\begin{center}| \\
-% |\begin{enumerate}| \\
-% |\begin{itemize}| \\
-% |\begin{tikzpicture}| \\
-% \end{tabular}
-% \end{center}
-% Single and double quotation marks and the diacritical commands |\^|, |\'|, |\`|, |\"|, |\~|, and |\H| are also handled,
-% as are the characters |\aa|, |\ae|, |\o|, |\ss|, |\l|, and their capitalizations.
+% Table~\ref{tab:html} lists \LaTeX\ macros, commands, and environments that
+% are specifically converted to HTML.
+% \begin{table}[tbp]
+% \centering
+% \caption{Conversion of \LaTeX\ material to HTML.}
+% \label{tab:html}
+% \begin{tabular}{llll}
+% \toprule
+% \multicolumn{2}{l}{Macros} & Commands & Environnments \\
+% \cmidrule(lr){1-2}\cmidrule(lr){3-3}\cmidrule(lr){4-4}
+% |~| & |\#| &|\emph{}| & |\begin{center}|\\
+% |\$| & |\&| &|\textbf{}| & |\begin{enumerate}|\\
+% |\\| & |\par| &|\textit{}| & |\begin{itemize}|\\
+% |\&| & |\S| & |\texttt{}| & |\begin{tikzpicture}|\\
+% |\{| & |\}| & |\textsc{}| & \\
+% |\|\textvisiblespace & |\relax| & |\underline{}| &\\
+% |\,| & |\thinspace| & |\textsuperscript{}| & \\
+% |\dots| & |\ldots| & |\up{}| & \\
+% |\euro| & |\texteuro| & |\fup{}| & \\
+% |\TeX| & |\LaTeX|& |\textsubscript{}| & \\
+% |\_| & |\textbackslash| & |\url{}| & \\
+% & & |\href{}{}| & \\
+% & & |\tikz[]{}| & \\
+% & & |\includegraphics[]{}| & \\
+% & & |\verbatiminput{}| & \\
+% & & |\VerbatimInput[]{}| & \\
+% & & |\LVerbatimInput[]{}| & \\
+% & & |\BVerbatimInput[]{}| & \\
+% & & |\inputminted[]{}{}| & \\
+% \bottomrule
+% \end{tabular}
+% \end{table}
+% Single and double quotation marks, french quotation marks, inverted exclamation and
+% question marks, and the diacritical
+% commands |\^|, |\'|, |\`|, |\"|, |\~|, |\c|, |\H|, |\u| and |\v| are also handled,
+% as are the characters |\aa|, |\ae|, |\l|, |\oe|, |\o|, |\ss|, and their
+% capitalizations. See Tables~\ref{tab:diacritical}, \ref{tab:ligatures}, and
+% \ref{tab:other} for more details.
%
% In addition, |<| and |>| will be converted to |&lt;| and |&gt;| \emph{within math mode only}.
% If they should be typed outside of math mode, they will be passed as typed to
% the HTML, and probably interpreted by students' browsers as HTML tags
% or other unpredicated results.
%
-% Be aware that \emph{\textsf{moodle.sty} does not know how to convert any
+% Be aware that \emph{\textsf{moodle} does not know how to convert any
% other \TeX\ or \LaTeX\ commands to HTML.}
% If other sequences are used, they may be passed verbatim to the XML file
% or may cause unpredicted results.
+% \DescribeMacro{\htmlregister}The |\htmlregister| command lets you specify
+% the macros that must be expanded in the XML file. It works only when no
+% optional argument is used.
+%
+% \DescribeMacro{\moodleregisternewcommands}
+% When the list of macros is long, it becomes cumbersome to record them
+% individually for expansion.
+% Calling |\moodleregisternewcommands| triggers the automatic
+% expansion of macros defined subsequently using |\newcommand|,
+% |\renewcommand|, |\providecommand|, or their starred variants.
+% Again, this works only if the macros are defined \emph{without} optional
+% argument.
%
% If you think of another \LaTeX\ command that should be changed to an HTML equivalent,
-% please contact the author at \url{anders.hendrickson@snc.edu}
+% please contact the maintainer at \url{guerquin-kern AT crans.org}
% so that it may be added to a future revision of the package.
%
% \section{Graphics}
-% The \textsf{moodle.sty} package can handle two kinds of graphics seamlessly.
+% The \textsf{moodle} package can handle two kinds of graphics seamlessly.
% External graphics files may be included with the |\includegraphics| command
-% from the |graphicx| package,
-% and graphics may be generated internally using \TikZ. In either case, the
-% graphics will be embedded in base-64 encoding directly within
+% from the |graphicx| package, and graphics may be generated internally using \TikZ.
+% In either case, the graphics will be embedded in base-64 encoding directly within
% the Moodle~XML produced. This prevents the hassle of managing separate
% graphics files on the Moodle server, as Moodle will store the picture
% within the question in the question bank.
%
+% \subsection{Default \texttt{includegraphics}}
% \DescribeMacro{\includegraphics}\DescribeMacro{height}\DescribeMacro{width}
% When using |\includegraphics|, the only options currently supported
% are |height| and |width|. Attempts to use other |\includegraphics| options,
% such as |scale| or |angle|, will affect the PDF but not the XML output.
-% The dimensions set by |height| and |width| are \TeX\ dimensions such as |4in| or |2.3cm|.
+% The dimensions set by |height| and |width| are \TeX\ dimensions such as \texttt{4\,in}
+% or \texttt{2.3\,cm}.
% In order to prepare the image for web viewing, this package converts those
% dimensions to pixels using a default of
% 103 pixels per inch.\footnote{This
@@ -627,11 +1027,50 @@
% That value may be changed by setting the |ppi| key (e.g., |ppi=72|);
% this is probably best done for the entire document with a |\moodleset| command,
% rather than image-by-image.
-%
-% The mechanism used is somewhat fragile and relies upon one \TikZ\ library and three free external programs.
+% \DescribeMacro{\graphicspath}
+% You can use |\graphicspath{{|\emph{path}|}}| to specify a directory where the
+% pictures to be included are located.
+%
+% A special rule was added for the inclusion of GIF pictures (|.gif| extension).
+% These files are passed as-is to the XML, preserving potential animations.
+% However, as pdf\TeX\ engines do not support the GIF format, the picture is
+% passed to the PDF output after a conversion to the PNG format. When the GIF
+% file is animated, only its first frame is passed to the PDF.
+%
+%^^A \DescribeMacro{\DeclareGraphicsAlien} Users may declare other graphic
+%^^A formats with the command |\DeclareGraphicsAlien|\marg{alien extension}
+%^^A \marg{native extension}\marg{command line for conversion}.
+%
+% \subsection{\TikZ\ Pictures}
+% When \TikZ\ is loaded and used to define pictures, \textsf{moodle} invokes
+% the |external| \TikZ\ library, so that each |tikzpicture| environment is compiled
+% to a freestanding PDF file.
+%
+% \subsection{Package Option \texttt{tikz}}\label{subsec:tikz}
+% \DescribeMacro{tikz}
+% The \textsf{moodle} package admits a \texttt{tikz} option which has the following effects:
+% \begin{itemize}
+% \item the package \texttt{tikz} is loaded.
+% \item \texttt{includegraphics} is embedded in a \TikZ\ picture. Consequences are that
+% \begin{itemize}
+% \item the pictures encoded in the XML file are resampled. This prevents encoding
+% images at a higher resolution than rendered by Moodle.
+% \item the full set of \texttt{includegraphics} options is accessible,
+% e.g.~|scale=.5|, |angle=90|, or |width=.2\textwidth|.
+% \end{itemize}
+% \item \DescribeMacro{\embedaspict} a macro |\embedaspict{...}| is provided for the
+% inclusion of inline \LaTeX\ material as images. This can serve as a workaround to
+% overcome limitations of this package---like the conversion of tabulars to HTML---
+% or limitations of Moodle itself.
+% For the definition of this macro, the package \texttt{varwidth} is loaded.
+% \item optimizations of the \TikZ-external library are disabled. Compilation might get
+% sensibly slower.
+% \end{itemize}
+%
+% \subsection{External Tools}
+% The mechanisms used for handling graphics are somewhat fragile and rely upon
+% three free external programs.
% \begin{enumerate}
-% \item \textsf{moodle.sty} invokes |\usetikzlibrary{external}|,
-% so that each |tikzpicture| environment is compiled to a freestanding PDF file.
% \item GhostScript (\url{www.ghostscript.com}) is used to convert the PDF output
% from \TikZ\ into a PNG raster graphics file.
% The default command line is presumed to be |gswin64c.exe|
@@ -639,75 +1078,459 @@
% or |gs| (if |\ifwindows| returns false).
% If your system requires a different command line to invoke Ghostscript,
% \DescribeMacro{\ghostscriptcommand}
-% you may change it by invoking |\ghostscriptcommand|\marg{executable filename}.
-% \item When external graphics files such as JPG or GIF are included,
+% you may change it by invoking:
+% \begin{quote}
+% |\ghostscriptcommand|\marg{executable filename}
+% \end{quote}
+% \item When external graphics files such as PDF are included,
% the open-source ImageMagick software (\url{www.imagemagick.org})
% converts each file to PNG format.
% The command line for ImageMagick is the nondescript word |convert|,
% \DescribeMacro{\imagemagickcommand}
% but may be changed by invoking |\imagemagickcommand|\marg{executable filename}.
-% \item Finally, the OpenSSL toolkit (\url{www.openssl.org}) is used to base64-encode
-% the PNG file so that it can be included directly in the text of the XML file.
-% The command line is presumed to be |openssl|, but can be changed with
-% \DescribeMacro{\opensslcommand}
-% |\opensslcommand|\marg{executable filename}.
+% \item OptiPNG (\url{http://optipng.sourceforge.net/}) is used to optimize the PNG images.
+% The command line is presumed to be |optipng|, but can be changed with
+% \DescribeMacro{\optipngcommand} |\optipngcommand|\marg{executable filename}.
% \end{enumerate}
%
% Please note the following vital points to make the graphics handling work:
% \begin{itemize}
% \item As of now, graphics are only supported when compiling directly to a PDF
-% with |pdflatex|. Including PS graphics or using \TikZ\ with the DVI$\to$PS workflow is not
+% with |pdflatex|. Including PS graphics or using \TikZ\ with the DVI$\to$PS workflow is not
% yet supported.
-% \item Filenames should not contains spaces or special characters like |_| or |\|.
-% \item You must have Ghostscript, ImageMagick, and OpenSSL installed on your system
-% to fully use the graphics-handling capabilities of \textsf{moodle.sty}.
+%^^A \item Filenames should not contains spaces or, under windows, special characters like |_| or |\|.
+% \item You must have Ghostscript and ImageMagick installed on your system
+% to fully use the graphics-handling capabilities of \textsf{moodle}.
+% \item If OptiPNG is not installed, the corresponding system calls will fail with otherwise no
+% impact on the compilation process: PNG files are passed unoptimized to the XML output.
% \item \LaTeX\ must be able to call system commands; that is, |\write18| must be enabled.
% For Mik\TeX, this means adding |--enable-write18| to the command line of |pdflatex|;
% for \TeX Live, this means adding |--shell-escape=true|.
+% \item Due to security issues with old versions of Ghostcript, some systems default to a
+% policy that prevents the conversion of PDF and PS to PNG. Assuming that, as a user of
+% \textsf{moodle} which requires shell escape capabilities, you either use a sandboxed
+% environment or trust the files handled at the system-level, you may want to disable this
+% over-zelous security policy. For example,
+% \href{https://stackoverflow.com/a/52661288/14608059}{see this}.
+% \item Users of the |circuitikz| package must enclose their circuits' \TikZ\ code in the
+% |tikzpicture| environment instead of |circuitikz|. That is required,
+% as of \TikZ\ 2.1, by the |external| library.
% \end{itemize}
+%
+% \subsection{Package Option \texttt{svg}}\label{subsec:svg}
+%
+% \paragraph{Important Notice} \emph{The \texttt{svg} option is an experimental feature
+% introduced in \textsf{moodle} v0.8. It has been tested exclusively under Linux, with
+% TeXLive 2020, Inkscape v1.0.1 and Scour 0.38.2.}
+%
+% \DescribeMacro{svg} The \textsf{moodle} package admits an experimental \texttt{svg}
+% option which has the following effects:
+% \begin{itemize}
+% \item |\includegraphics| can be used to import SVG graphic files directly
+% (extension |.svg| or |.SVG|). In this case, the SVG file is passed as-is to the
+% XML output and is converted using \href{https://inkscape.org/}
+% {Inkscape} (must be installed) for inclusion in the PDF output.
+% \item the graphic files in PDF format are converted to the SVG format using
+% \href{https://inkscape.org/}{Inkscape} (must be installed), rather than beeing
+% rasterized. Before inclusion to the XML output, the SVG file is optimized using
+% the \href{https://github.com/scour-project/scour}{Scour} utility. This
+% optimization step is optional in the sense that, if the Scour call fails,
+% the unoptimized SVG file will be passed to the XML output.
+% Two processes benefit from this PDF$\to$SVG conversion:
+% \begin{itemize}
+% \item inclusion of PDF graphics with |\includegraphics|, and
+% \item Tikz pictures that are externalized.
+% \end{itemize}
+% \end{itemize}
+%
+% \DescribeMacro{\PDFtoSVGcommand}\DescribeMacro{\SVGtoPDFcommand}
+% \DescribeMacro{\optiSVGcommand} The call of external tools can be changed using
+% the macros |\PDFtoSVGcommand| \marg{\dots}, |\SVGtoPDFcommand|\marg{\dots} and
+% |\optiSVGcommand|\marg{\dots}.
+%
+% \section{Verbatim Code}
+% Because, for HTML translation, \textsf{moodle} parses the body of questions, the use of
+% verbatim code results in compilation errors. This is why the use of |\verb|,
+% |\begin{verbatim}| and other standard utilities is not supported.
+%
+% However, using the following three utilities, verbatim code can be imported from an external file:
+% \begin{enumerate}
+% \item \DescribeMacro{\verbatiminput}|\verbatiminput|\marg{filename} from the \textsf{verbatim}
+% package inserts verbatim code in both the PDF and the XML for moodle, without fancy additions.
+% \item \DescribeMacro{\VerbatimInput}The macro |\VerbatimInput|\marg{options}\marg{filename} from
+% \textsf{fancyvrb} or \textsf{fvextra} does more, with several options and settings offered
+% (see below).
+% The variants \DescribeMacro{\BVerbatimInput}|\VBerbatimInput| and
+% \DescribeMacro{\LVerbatimInput}|\LVerbatimInput| are also supported, with identical
+% effect on the XML output.
+% The variants with a star are unsupported and result in errors when used.
+% \item \DescribeMacro{\inputminted}On top of that |\inputminted|\oarg{options}\marg{lang}
+% \marg{filename}from the \textsf{minted} package offers syntaxic highlighting tailored to the
+% specified language.
+% \end{enumerate}
+% The \textsf{moodle} package handles these three commands to pass the code in the output XML.
+%
+% With |\VerbatimInput| and |\inputminted|, the options that are taken care of for XML
+% generation are listed in Table~\ref{tab:verbatim-options}. Using |\fvset|\marg{key=value,...},
+% options can be set globally. Equivalently, with \textsf{minted},
+% |\setminted|\oarg{lang}\marg{key=value,...} is available.
+%
+% \begin{table}[tbp]
+% \centering
+% \begin{threeparttable}[b]
+% \caption{Options and corresponding values considered for XML generation of verbatim material
+% with \texttt{VerbatimInput} and \texttt{inputminted}.}
+% \label{tab:verbatim-options}
+% \begin{tabular}{ll}
+% \toprule
+% Option keys & Possible values\\\cmidrule(lr){1-1}\cmidrule(lr){2-2}
+% ^^A\texttt{commentchar} & \meta{character}\\
+% \texttt{gobble} & \meta{integer}\\
+% \texttt{autogobble}\tnote{1} & \texttt{true} or \texttt{false}\\
+% \texttt{tabsize} & \meta{integer}\\
+% \texttt{numbers} & \texttt{none}, \texttt{left}, \texttt{right}, or \texttt{both}\tnote{2}\\
+% \texttt{firstnumber} & \texttt{auto}, \texttt{last}, or \meta{integer}\\
+% \texttt{firstline} & \meta{integer}\\
+% \texttt{lastline} & \meta{integer}\\
+% \texttt{numberblanklines} & \texttt{true} or \texttt{false}\\
+% \texttt{highlightlines}\tnote{2} & \marg{coma-separated list of integers or ranges}\\
+% \texttt{style}\tnote{1} & \meta{string}\\
+% \bottomrule
+% \end{tabular}
+%\begin{tablenotes}
+%\item[1] \texttt{autogobble}, \texttt{numbers=both}, and \texttt{style} are offered only by \textsf{minted}.
+%\item[2] line highlighting is offered only with \textsf{fvextra} or \textsf{minted} loaded.
+%\end{tablenotes}
+%\end{threeparttable}
+%\end{table}
+%
+% In order to define the verbatim code from the \LaTeX\ document itself, it is still possible
+% to use, outside the scope of the \textsf{moodle} questions, the environments |filecontents*| (from the
+% \textsf{filecontents} package or \LaTeX\ kernel itself since 2019) or |VerbatimOut|
+% (from the \textsf{fancyvrb} and \textsf{fvextra} packages).
+%
+% When code decorated with left-side line numbers is placed in question items, the output PDF could
+% show a collision between numbers of the item and the first line. To avoid this, |\LVerbatimInput| or
+% |\BVerbatimInput| can be used. Instead, when \textsf{minted} is used, the ``left-right'' mode can be
+% enforced with the \LaTeX\ command:
+% \begin{quote}
+% |\RecustomVerbatimEnvironment{Verbatim}{LVerbatim}{}|
+% \end{quote}
+%
+% When using utilies from \textsf{fancyvrb}, \textsf{fvextra}, or \textsf{minted}, \textsf{moodle} sets
+% framing options for the display of code in the output PDF:
+% \begin{quote}
+% |\fvset{frame=lines,label={[Beginning of code]End of code},|\\
+% | framesep=3mm,numbersep=9pt}|
+% \end{quote}
+% These settings can be overidden using |\fvset| after the preamble.
+%
+% \section{Calculated Questions}
+% Moodle's calculated questions are not supported by this package.
+%
+% However, as \href{https://github.com/avohns/python-latex-moodle-quiz}{demonstrated by A.
+% Vohns}, an advanced scripting language may be used to generate a series of questions sharing
+% the same prototype.
+%
+% We suggest to apply a specific tag to these questions. After import in Moodle, when creating
+% a quizz, this tag can be selected to narrow down a random selection of question.
+% This would mimic the behavior of calculated questions while bringing the flexibility of your
+% favorite scripting language.
+%
+% Here are two examples inspired from the work of A. Wohns. The first one relies on the
+% native Lua capabilities of \LuaLaTeX.
+% \begin{VerbatimOut}[gobble=1]{minted.doc.out}
+% \begin{quiz}[tags={calculated}]{Example Quiz}
+% \directlua{
+% \end{VerbatimOut}
+% \inputminted[gobble=2,frame=topline]{latex}{minted.doc.out}
+% \begin{VerbatimOut}[gobble=1]{minted.doc.out}
+% function clozenum_print(pair,op,result)
+% tex.print("\\begin{numerical}$"..pair[1].." "..op.." "..pair[2].."
+% =$".."\\item ",result,"\\end{numerical}")
+% end
+% function cloze_print(pair,points)
+% tex.print("\\begin{cloze}[points="..points.."]{Arithmetic Quiz
+% ("..pair[1]..", "..pair[2]..")}Solve the following tasks!\\\\")
+% clozenum_print(pair,"+",pair[1]+pair[2])
+% clozenum_print(pair,"-",pair[1]-pair[2])
+% clozenum_print(pair,"*",pair[1]*pair[2])
+% if pair[1]/pair[2]==math.floor(pair[1]/pair[2]) then
+% clozenum_print(pair,":",math.floor(pair[1]/pair[2]))
+% end
+% tex.print("\\end{cloze}")
+% end
+% for x = 2,4 do
+% for y = 2,4 do
+% if x>y then
+% if x/y==math.floor(x/y) then points=4 else points=3 end
+% cloze_print({x,y},points)
+% end
+% end
+% end
+% \end{VerbatimOut}
+% \inputminted[]{lua}{minted.doc.out}
+% \begin{VerbatimOut}[gobble=1]{minted.doc.out}
+% }
+% \end{quiz}
+% \end{VerbatimOut}
+% \inputminted[gobble=2,frame=bottomline]{latex}{minted.doc.out}
+% The second example makes use of the \textsf{python} package (|\usepackage{python}|).
+% \begin{VerbatimOut}[gobble=1]{minted.doc.out}
+% \begin{quiz}[tags={calculated}]{Example Quiz}
+% \begin{python}
+% \end{VerbatimOut}
+% \inputminted[gobble=2,frame=topline]{latex}{minted.doc.out}
+% \begin{VerbatimOut}[gobble=1]{minted.doc.out}
+% def clozenum_print(pair,op,result):
+% print(rf"""\begin{{numerical}}
+% ${pair[0]} {op} {pair[1]} =$\item {result}
+% \end{{numerical}}""")
+% def cloze_print(pair,points):
+% print(rf"""\begin{{cloze}}[points={points}]{{Arithmetic Quiz
+% {(pair[0],pair[1])}}}Solve the following tasks!\\""")
+% clozenum_print([x,y],"+",x+y)
+% clozenum_print([x,y],"-",x-y)
+% clozenum_print([x,y],"*",x*y)
+% if pair[0]/pair[1] == pair[0]//pair[1]:
+% clozenum_print([x,y],":",x//y)
+% print("\end{cloze}")
+% for x in range(2,5):
+% for y in range(2,5):
+% if x > y:
+% if x/y == x//y:
+% points=4
+% else:
+% points=3
+% cloze_print([x,y],points)
+% \end{VerbatimOut}
+% \inputminted[]{python}{minted.doc.out}
+% \begin{VerbatimOut}[gobble=1]{minted.doc.out}
+% \end{python}
+% \end{quiz}
+% \end{VerbatimOut}
+% \inputminted[gobble=2,frame=bottomline]{latex}{minted.doc.out}
+% These two codes yield the same XML content.
%
-% \newpage
% \section{Known Limitations and Call for Bug Reports}
-% Some features of Moodle quizzes have not yet been implemented in \textsf{moodle.sty}.
+% Table~\ref{tab:support-limitations} lists some different features supported, limitations, and
+% bugs.
+%
+%\begin{table}[tbp]
+%\centering
+%\begin{threeparttable}[b]
+%\caption{Content enrichment (pictures, equations) support after XML import in Moodle v3.5.7,
+% depending on the question type.}
+%\label{tab:support-limitations}
+%\begin{tabular}{lccc}
+% \toprule
+% & \multicolumn{3}{l}{XML rendering in\dots}\\\cmidrule(lr){2-4}
+%Question type & Question & Answer & Feedback\\\cmidrule(lr){1-1}\cmidrule(lr){2-2}
+%\cmidrule(lr){3-3}\cmidrule(lr){4-4}
+% \href{https://docs.moodle.org/35/en/Multiple_Choice_question_type}{Multichoice}
+%& yes & yes & yes \\
+% \href{https://docs.moodle.org/35/en/Numerical_question_type}{Numerical}
+%& yes & no\tnote{1} & yes \\
+% \href{https://docs.moodle.org/35/en/Short-Answer_question_type}{Short Answer}
+% & yes & no\tnote{1} & yes \\
+% Matching (\href{https://docs.moodle.org/35/en/Matching_question_type}{std})
+%& yes & no\tnote{2} & no\tnote{3} \\
+% Matching (\href{https://docs.moodle.org/35/en/Drag_and_drop_matching_question_type}{dd})
+% & yes & yes\tnote{4} & no\tnote{3} \\
+% \href{https://docs.moodle.org/35/en/Essay_question_type}{Essay}
+%& yes & yes\tnote{5,6} & yes\tnote{5} \\
+% \href{https://docs.moodle.org/35/en/True/False_question_type}{True/False}
+%& yes & no & yes \\
+% \href{https://docs.moodle.org/35/en/Description_question_type}{Description}
+%& yes & $\varnothing$ & yes \\
+%\href{https://docs.moodle.org/35/en/Embedded_Answers_(Cloze)_question_type}{Cloze} &
+%yes & $\varnothing$& $\varnothing$ \\\cmidrule(lr){1-1}
+%\hspace{1em}Numerical & yes & no\tnote{1} & yes \\
+%\hspace{1em}Short Answer & yes & no\tnote{1} & yes\tnote{7} \\
+%\hspace{1em}Multi (regular) & yes & no\tnote{2} & yes\tnote{7} \\
+%\hspace{1em}Multi (horizontal) & yes & yes & yes \\
+%\hspace{1em}Multi (vertical) & yes & yes & yes \\\bottomrule
+%\end{tabular}
+%\begin{tablenotes}
+%\item[1] Moodle prompts the student for an answer and then compares it to the
+%solutions provided. This is text-only.
+%\item[2] Moodle uses a dropdown list to let one choose among the possible
+%answers. This forbids either picture inclusion and \LaTeX\ rendering.
+%\item[3] Not supported by Moodle (in this context, answer-specific feedback
+%represents lots of possible combinations).
+%\item[4] The drag-and-drop-matching plugin seems broken before version 1.6
+%20190409. Moodle's XML import fails with a \textsf{dmlwriteexception} when
+%the field content exceeds few hundreds characters. This prevents the inclusion
+%of most base64 images and maybe some complicated equations.
+%\item[5] For this question type and in the context of XML generation, the
+%Answer column represents the ``template" while the Feedback column represents
+%the ``notes for the grader". Obviously, the grading process is not automatic
+%and there is no answer-specific feedback.
+%\item[6] Picture and \LaTeX\ rendering could be done, but only after
+%submission and only if the keyval ``response format" is set to ``html".
+%\item[7] Moodle only reveals the feedback when hovering the checkmark or X
+%mark with the mouse.
+%\end{tablenotes}
+%\end{threeparttable}
+%\end{table}
+%
+% Tables~\ref{tab:diacritical}, \ref{tab:ligatures}, and \ref{tab:other} describe the current
+% support for some special characters, accents and other diacritical marks.
+%
+%\begin{table}[tbp]
+% \centering
+% \caption{Support for diacritical marks
+% in a UTF8-coded \TeX~document compiled with (pdf)\LaTeX\ (packages
+% \texttt{inputenc} with option \texttt{utf8} and \texttt{fontenc} with option \texttt{T1}),
+% \LuaLaTeX\ or \XeLaTeX\ (package \texttt{fontspec}).}
+% \label{tab:diacritical}
+% \begin{threeparttable}[t]
+% \begin{tabular}{*{6}{l}}
+% \toprule
+% \multicolumn{4}{l}{Input type} & \multicolumn{2}{l}{Engine support}\\
+% \cmidrule(lr){1-4}\cmidrule(lr){5-6}
+% \multicolumn{2}{l}{Unicode} & \multicolumn{2}{l}{\LaTeX} & \XeLaTeX\ or \LuaLaTeX & (pdf)\LaTeX \\
+% \cmidrule(lr){1-2}\cmidrule(lr){3-4}\cmidrule(lr){5-5}\cmidrule(lr){6-6}
+% \aa & \AA & \verb|\aa| & \verb|\AA| & Unicode and \LaTeX & Unicode and \LaTeX \\
+% \`a & \`A & \verb|\`a| & \verb|\`A| & Unicode and \LaTeX & Unicode and \LaTeX \\
+% \^a & \^A & \verb|\^a| & \verb|\^A| & Unicode and \LaTeX & Unicode and \LaTeX \\
+% \~a & \~A & \verb|\~a| & \verb|\~A| & Unicode and \LaTeX & Unicode and \LaTeX \\
+% \'e & \'E & \verb|\'e| & \verb|\'E| & Unicode and \LaTeX & Unicode and \LaTeX \\
+% \`e & \`E & \verb|\`e| & \verb|\`E| & Unicode and \LaTeX & Unicode and \LaTeX \\
+% \"e & \"E & \verb|\"e| & \verb|\"E| & Unicode and \LaTeX & Unicode and \LaTeX \\
+% \^e & \^E & \verb|\^e| & \verb|\^E| & Unicode and \LaTeX & Unicode and \LaTeX \\
+% \^i & \^I & \verb|\^i| & \verb|\^I| & Unicode and \LaTeX & Unicode and \LaTeX \\
+% \"i & \"I & \verb|\"i| & \verb|\"I| & Unicode and \LaTeX & Unicode and \LaTeX \\
+% \~n & \~N & \verb|\~n| & \verb|\~N| & Unicode and \LaTeX & Unicode and \LaTeX \\
+% \~o & \~O & \verb|\~o| & \verb|\~O| & Unicode and \LaTeX & Unicode and \LaTeX \\
+% \"o & \"O & \verb|\"o| & \verb|\"O| & Unicode and \LaTeX & Unicode and \LaTeX \\
+% \^o & \^O & \verb|\^o| & \verb|\^O| & Unicode and \LaTeX & Unicode and \LaTeX \\
+% \`u & \`U & \verb|\`u| & \verb|\`U| & Unicode and \LaTeX & Unicode and \LaTeX \\
+% \"u & \"U & \verb|\"u| & \verb|\"U| & Unicode and \LaTeX & Unicode and \LaTeX \\
+% \^u & \^U & \verb|\^u| & \verb|\^U| & Unicode and \LaTeX & Unicode and \LaTeX \\
+% \c{c} & \c{C} & \verb|\c{c}| & \verb|\c{C}| & Unicode and \LaTeX & Unicode and \LaTeX \\
+% \c{s} & \c{S} & \verb|\c{s}| & \verb|\c{S}| & Unicode and \LaTeX & \LaTeX\ only\\
+% \c{t} & \c{T} & \verb|\c{t}| & \verb|\c{T}| & Unicode and \LaTeX & \LaTeX\ only\\
+% \H{o} & \H{O} & \verb|\H{o}| & \verb|\H{O}| & Unicode and \LaTeX & \LaTeX\ only\\
+% \H{u} & \H{U} & \verb|\H{u}| & \verb|\H{U}| & Unicode and \LaTeX & \LaTeX\ only\\
+% \"y & \"Y & \verb|\"y| & \verb|\"Y| & Unicode and \LaTeX & \LaTeX only\\
+% \u{a} & \u{A} & \verb|\u{a}| & \verb|\u{A}| & Unicode and \LaTeX & \LaTeX\ only\\
+% \u{e} & \u{E} & \verb|\u{e}| & \verb|\u{E}| & Unicode and \LaTeX & \LaTeX\ only\\
+% \u{g} & \u{G} & \verb|\u{g}| & \verb|\u{G}| & Unicode and \LaTeX & \LaTeX\ only\\
+% \u{\i} & \u{I} & \verb|\u{\i}| & \verb|\u{I}| & Unicode and \LaTeX & \LaTeX\ only\tnote{1}\\
+% \u{o} & \u{O} & \verb|\u{o}| & \verb|\u{O}| & Unicode and \LaTeX & \LaTeX\ only\\
+% \v{c} & \v{C} & \verb|\v{c}| & \verb|\v{C}| & Unicode and \LaTeX & \LaTeX\ only\\
+% \v{d} & \v{D} & \verb|\v{d}| & \verb|\v{D}| & Unicode and \LaTeX & \LaTeX\ only\\
+% \v{e} & \v{E} & \verb|\v{e}| & \verb|\v{E}| & Unicode and \LaTeX & \LaTeX\ only\\
+% \v{l} & \v{L} & \verb|\v{l}| & \verb|\v{L}| & Unicode and \LaTeX & \LaTeX\ only\\
+% \v{n} & \v{N} & \verb|\v{n}| & \verb|\v{N}| & Unicode and \LaTeX & \LaTeX\ only\\
+% \v{r} & \v{R} & \verb|\v{r}| & \verb|\v{R}| & Unicode and \LaTeX & \LaTeX\ only\\
+% \v{s} & \v{S} & \verb|\v{s}| & \verb|\v{S}| & Unicode and \LaTeX & \LaTeX\ only\\
+% \v{t} & \v{T} & \verb|\v{t}| & \verb|\v{T}| & Unicode and \LaTeX & \LaTeX\ only\\
+% \v{z} & \v{Z} & \verb|\v{z}| & \verb|\v{Z}| & Unicode and \LaTeX & \LaTeX\ only\\
+% \bottomrule
+% \end{tabular}
+% \begin{tablenotes}
+% \item[1] \XeLaTeX\ renders correctly |\u{i}|, that is, without a superscript dot.
+% Instead, with (pdf)\LaTeX\ the rendering of |\u{i}| is flawed by the
+% superposition of the superscript dot and the breve diacritical mark.
+% Both engines render |\u{\i}| as expected.
+% \end{tablenotes}
+% \end{threeparttable}
+% \end{table}
+%
+%\begin{table}[tbp]
+% \centering
+% \begin{threeparttable}[t]
+% \caption{Support for ligatures in a UTF8-coded \TeX~document compiled with (pdf)\LaTeX\ (packages
+% \texttt{inputenc} with option \texttt{utf8}, \texttt{fontenc} with option \texttt{T1}),
+% \LuaLaTeX\ or \XeLaTeX\ (package \texttt{fontspec}).}
+% \label{tab:ligatures}
+% \begin{tabular}{llllll}
+% \toprule
+% \multicolumn{4}{l}{Input type} & \multicolumn{2}{l}{Engine support}\\
+% \cmidrule(lr){1-4}\cmidrule(lr){5-6}
+% \multicolumn{2}{l}{Unicode} & \multicolumn{2}{l}{\LaTeX} & \XeLaTeX \ or \LuaLaTeX& (pdf)\LaTeX \\
+% \cmidrule(lr){1-2}\cmidrule(lr){3-4}\cmidrule(lr){5-6}\cmidrule(lr){6-6}
+% \ae & \AE & \verb|\ae| & \verb|\AE| & Unicode and \LaTeX & \LaTeX\ only\\
+% \oe & \OE & \verb|\oe| & \verb|\OE| & Unicode and \LaTeX & \LaTeX\ only\\
+% \ss & \SS & \verb|\ss| & \verb|\SS| & Unicode and \LaTeX\tnote{1} & \LaTeX\ only\tnote{2}\\
+% \bottomrule
+% \end{tabular}
+% \begin{tablenotes}[b]
+% \item[1] the Libertine font, used in this documentation and available for instance via the
+% package |libertine|, defines the glyph \SS. Most fonts do not define this glyph.
+% \item[2] \LaTeX\ defines the \verb|\SS| macro but (pdf)\LaTeX\ renders it as a doubled capital S.
+% \end{tablenotes}
+% \end{threeparttable}
+% \end{table}
+%
+%\begin{table}[tbp]
+% \centering
+% \begin{threeparttable}[b]
+% \caption{Support for other glyphs and punctuation marks in a UTF8-coded \TeX~document compiled
+% with (pdf)\LaTeX\ (packages \texttt{inputenc} with option \texttt{utf8}, \texttt{fontenc} with
+% option \texttt{T1}), \LuaLaTeX\ or \XeLaTeX\ (package \texttt{fontspec}).}
+% \label{tab:other}
+% \begin{tabular}{llllll}
+% \toprule
+% \multicolumn{4}{l}{Input type} & \multicolumn{2}{l}{Engine support}\\
+% \cmidrule(lr){1-4}\cmidrule(lr){5-6}
+% \multicolumn{2}{l}{Unicode} & \multicolumn{2}{l}{\LaTeX} & \XeLaTeX\ or \LuaLaTeX & (pdf)\LaTeX \\
+% \cmidrule(lr){1-2}\cmidrule(lr){3-4}\cmidrule(lr){5-5}\cmidrule(lr){6-6}
+% \l & \L & \verb|\l| & \verb|\L| & Unicode and \LaTeX & \LaTeX\ only\\
+% \o & \O & \verb|\o| & \verb|\O| & Unicode and \LaTeX & \LaTeX\ only\\
+% « & & \verb|\guillemotleft|\tnote{1} & & Unicode and \LaTeX & \LaTeX\ only\\
+% » & & \verb|\guillemotright|\tnote{1} & & Unicode and \LaTeX & \LaTeX\ only\\
+% ¿ & & \verb|\textquestiondown| & & Unicode and \LaTeX & \LaTeX\ only\\
+% ¡ & & \verb|\textexclamdown| & & Unicode and \LaTeX & \LaTeX\ only\\
+% \bottomrule
+% \end{tabular}
+% \begin{tablenotes}
+% \item[1] the package |babel| loaded with option |french| defines |\og| and |\fg| for
+% the same symbols. These are also supported by \textsf{moodle}.
+% \end{tablenotes}
+% \end{threeparttable}
+% \end{table}
+% Some features of Moodle quizzes have not yet been implemented in \textsf{moodle}.
% Here is a non-exhaustive list.
% \begin{itemize}
% \item Moodle's feature of designating feedback for correct,
% partially correct, and incorrect answers.
-% \item Calculated questions; that is, automatically generated numerical questions
-% using randomly chosen numbers.
+%^^A \item Calculated questions; that is, automatically generated numerical questions
+%^^A using randomly chosen numbers.
% \item Hints
-% \item Keywords
-% \item So-called ``description'' questions.
-% \item Shuffled answers in multiple choice cloze subquestions.
+% \item Multiple keywords (tags) for questions
% \end{itemize}
-% I have used Version 0.5 for one semester's teaching,
-% but if other users adopt this package, I fully expect them to find bugs.
-% \emph{Please} send all bugs you find to \url{anders.hendrickson@snc.edu},
-% so that I can fix them for subsequent versions.
+% The authors have used this package together with a limited number of colleagues
+% for a few semesters of teaching. If other users adopt this package, we fully expect them
+% to find bugs. \emph{Please} send all bugs you find to \url{guerquin-kern@crans.org},
+% so that we can fix them for subsequent versions.
%
% \section{Compatibility}
-% This package has been written for and tested with the implementation of
+% This package has been originally written for and tested with the implementation of
% Moodle 2.9 run by Moodlerooms for St.~Norbert College in January 2016.
-% Future versions of this package will probably include some support for
-% specifying your version of Moodle in the |.tex| file to help ensure compatability.
+% Since then, it has been successfully combined with Moodle 3.5.
+% Future versions of this package might include some support for
+% specifying your version of Moodle in the |.tex| file to help ensure compatibility.
%
% As the ultimate purpose of this package is the generation of XML files,
-% future versions of \textsf{moodle.sty} will attempt to maintain backwards
-% compatability with earlier versions of regarding the XML output, apart from
+% future versions of \textsf{moodle} will attempt to maintain backwards
+% compatability with earlier versions regarding the XML output, apart from
% bug fixes.
% Backwards compatibility of the PDF output is not yet guaranteed, however,
% in case the author or users discover better ways for the PDF to display
% the underlying XML data to be proofread.
%
% In other words, compiling your current |.tex| file with a future version
-% of \textsf{moodle.sty} should produce the same XML file it does now
+% of \textsf{moodle} should produce the same XML file it does now
% (apart from bug fixes),
% but it might produce a more informative, and hence different,
% PDF output.
%
%
% \section{Unrelated Tip: Quality of Moodle \TeX\ Images}
-% This has nothing to do with |moodle.sty|, but is a Frequently Asked Question
+% This has nothing to do with \textsf{moodle}, but is a Frequently Asked Question
% in is own right.
% On some servers, at least, Moodle's default ``\TeX\ Filter'' for
% displaying mathematical notation is of abysmally poor quality, rending mathematics
@@ -716,40 +1539,201 @@
% but turn ``MathJax'' \emph{on}. This forces \TeX\ code to be rendered by MathJax
% instead of Moodle, producing much higher-quality results.
%
+% ^^A\clearpage
+% \changes{v0.5}{2016/01/05}{Initial version}
+% \changes{v0.6}{2019/02/18}{Bux-fixing release}
+% \changes{v0.7}{2020/07/09}{Feature extensions}
+% \changes{v0.8}{2021/01/04}{Bug fixes and feature extensions}
+% \begin{changelog}[title={Version History},author={Matthieu Guerquin-Kern}]
+% \begin{version}[version=0.8,date=2021-01-04]
+% \added
+% \item Support for inclusion of GIF pictures.
+% \item Added package option |svg| to avoid the rasterization of vector graphics.
+% \item New macro |\setsubcategory| to define subcategories, reflected in PDF and XML.
+% \item Package option |handout| for sharing PDF with students.
+% \item Extensions can be omitted when including pictures.
+% \item Description question type.
+% \item \LuaLaTeX\ is now supported (and recommended for UTF8-coded sources).
+% \item Examples of ways to reproduce the behavior of calculated questions.
+% \item Command to trigger the automatic recording of new commands.
+% \item Mechanism to match |fraction| key to values accepted by Moodle.
+% \item A |fractiontol| key to control the tolerance in this mechanism.
+% \item Support for inverted punctuation marks |¿| and |¡|.
+% \item Support for |\_| and |\textbackslash|.
+% \item Support for the wildcard character as an answer in numerical questions.
+% \changed
+% \item Template of Essay questions is now shown in PDF.
+% \item The macro |\setcategory| is reflected by a new section in PDF.
+% \item In matching questions, warnings are raised if the number of items is insufficient.
+% \item Improved display of matching questions in PDF.
+% \item The package \textsf{iftex} is now required.
+% \item An error is thrown when |fraction| is set to an invalid value.
+% \item In numerical questions, the tolerance can be set in exponent form.
+% \item Nicer PDF rendering of numbers in numerical questions if \textsf{siunitx} is loaded.
+% \item Included PNG and JPEG files are now directly converted to base64.
+% \fixed
+% \item TeX's inline math (|$...$|) can now contain escaped dollar signs (|\$|).
+% \item Closing braces escaped in cloze subquestions outside math environment.
+% \item The scope of the |tolerance| key is now respected.
+% \end{version}
+% \begin{version}[version=0.7,date=2020-09-06]
+% \added
+% \item Support for inclusion of verbatim code.
+% \item Package option \texttt{tikz}.
+% \item Support for |\"Y| and |\"y|.
+% \item New commands converted to XML.
+% \item Adding a stamp comment in XML, package option offered to disable
+% this behavior.
+% \item Support for the |\tikz| command.
+% \item A different directory can be specified for picture inclusion.
+% \item Warn user of the \texttt{babel} package set for french that autospacing
+% must be deactivated.
+% \item Square bracket math delimiters are recognized and converted properly.
+% \item Support of breve and caron diacritical marks.
+% \changed
+% \item In multi with multiple answers allowed, choosing all options no longer
+% results in a good grade. An automatic penalty mechanism is introduced.
+% Can be overridden by manually setting fractions.
+% \removed
+% \item Irrelevant \texttt{penalty} tag in cloze subquestions.
+% \fixed
+% \item Non-integer fractions can now be specified in cloze subquestions.
+% \item Signifiantly squeeze PNG images size by skipping ancillary data.
+% \item Enumerate or itemize environment can now be nested in question items.
+% \item Several pictures can be included in a question without being mixed
+% in the XML file.
+% \item management and rendering of fraction in questions.
+% \item Correctly handling a \LaTeX\ starting the last item of a question.
+% \item Closing braces escaped in cloze subquestions. This allows \LaTeX\
+% equations or images to be included.
+% \item Image inclusion with MacOS.
+% \end{version}
+% \begin{version}[version=0.6b,date=2019-11-27]
+% \added
+% \item New package options to set section or subsection at the quiz level.
+% \item True/False question type is now supported.
+% \item Moodle tags can now be specified for questions (and rendered in PDF
+% as well).
+% \item In cloze questions, the \texttt{multiresponse} subquestion type is
+% now supported.
+% \removed
+% \item External dependency on \texttt{OpenSSL}.
+% \item Irrelevant tags were written in XML for matching questions.
+% \fixed
+% \item \TikZ\ externalization now works when using \XeLaTeX.
+% \item It is now possible to set points manually among several correct
+% answers in multichoice questions.
+% \item General feedbacks can now contain backslashes.
+% \item Several quizzes can now be defined in a single source file, each
+% specifying a category for Moodle's question bank.
+% \item Correct encoding information in now written in XML depending on
+% the \LaTeX\ compiler used.
+% \end{version}
+% \begin{version}[version=0.6a,date=2019-06-21]
+% \added
+% \item \XeLaTeX\ is now recommended when using UTF8-encoded sources (support
+% of accents).
+% \item Feedbacks are now displayed in the PDF file produced.
+% \item The \texttt{optipng} utility is used (and required) to reduce the size
+% of images embedded in the XML file.
+% \item Question options and settings are now displayed in the PDF file
+% \item Supporting more \LaTeX\ macros for symbols and accents (mostly
+% diacritical marks and ligatures).
+% \item Introduce shuffle options in cloze-multi subquestions.
+% \item Package option \texttt{final}.
+% \changed
+% \item In draft mode, \TikZ\ externalization in no longer triggered.
+% \fixed
+% \item In the different question types, the feedback fields are now converted
+% for HTML allowing \LaTeX\ equation and images.
+% \item Documentation improvements (limitations and previously undocumented
+% features).
+% \end{version}
+% \shortversion{version=0.5,date=2016-01-05,simple,changes=Initial version,author={Anders O.F. Hendrickson}}
+% \end{changelog}
+%
% \StopEventually{}
%
% \section{Implementation}
% \subsection{Packages, Options, and Utilities}
% \begin{macrocode}
\newif\ifmoodle@draftmode
+\newif\ifmoodle@handout
+\newif\ifmoodle@stampmode
+\newif\ifmoodle@tikz
\newif\ifmoodle@tikzloaded
+\newif\ifmoodle@svg
+\newif\ifmoodle@section
+\newif\ifmoodle@subsection
+\newif\ifmoodle@numbered
%%DECLARATION OF OPTIONS
\DeclareOption{draft}{\moodle@draftmodetrue}
+\DeclareOption{handout}{\moodle@handouttrue}
+\DeclareOption{final}{\moodle@draftmodefalse}
+\DeclareOption{nostamp}{\moodle@stampmodefalse}
+\DeclareOption{tikz}{\moodle@tikztrue}
+\DeclareOption{svg}{\moodle@svgtrue}
+\DeclareOption{section}{\moodle@sectiontrue\moodle@numberedtrue}
+\DeclareOption{section*}{\moodle@sectiontrue\moodle@numberedfalse}
+\DeclareOption{subsection}{\moodle@sectionfalse\moodle@numberedtrue}
+\DeclareOption{subsection*}{\moodle@sectionfalse\moodle@numberedfalse}
\moodle@draftmodefalse
+\moodle@handoutfalse
+\moodle@stampmodetrue
+\moodle@tikzfalse
\moodle@tikzloadedfalse
+\moodle@svgfalse
+\moodle@subsectiontrue
+\moodle@numberedfalse
\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{trimspaces} %To remove extra spaces from strings (loaded by environ)
\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
-
+\@ifpackageloaded{iftex}{}{\RequirePackage{iftex}}
+% iftex already required by recent versions of ifplatform. Needed to know:
+% 1) whether we can convert output from PDF to PNG (ifpdf),
+% 2) when output pdf is latin1-encoded (ifpdf)
+% 3) when output xml is utf8-encoded (if?tex)
+\@ifundefined{ifpdf}{\RequirePackage{ifpdf}}{}% old iftex would not define the conditional
+\RequirePackage{shellesc} %Luatex-compatible way of getting system access
+\RequirePackage{fancybox} %For fancy LaTeX tags
\RequirePackage{getitems} %To gather the header and items
+\ifmoodle@handout
+ \RequirePackage[seed=42]{randomlist} %To randomize answers in matching questions
+\fi
+\ifmoodle@svg
+ \RequirePackage{graphicx} %To include graphics
+\fi
\let\xa=\expandafter
\def\@star{*}%
\def\@hundred{100}%
+\def\@fifty{50}%
\def\@moodle@empty{}%
\def\@relax{\relax}%
+\def\@moodle@par{\par}%
+
+% Taken from https://tex.stackexchange.com/questions/47576/combining-ifxetex-and-ifluatex-with-the-logical-or-operation
+\@ifundefined{ifTUTeX}{
+ \newif\ifTUTeX % a new conditional starts as false
+ \ifnum 0\ifXeTeX 1\fi\ifLuaTeX 1\fi>0%
+ \TUTeXtrue
+ \fi
+}{}%
+\newif\ifpdfoutput % a new conditional starts as false
+\ifnum 0\ifTUTeX 1\fi\ifPDFTeX\ifpdf 1\fi\fi>0%
+ \pdfoutputtrue
+\fi
% \end{macrocode}
% As the package involves a fair bit of file processing,
% we automate the naming of auxiliary files.
@@ -787,9 +1771,42 @@
\newwrite\moodle@outfile
\def\openmoodleout{%
\immediate\openout\moodle@outfile=\outputfilename\relax
- \writetomoodle{<?xml version="1.0" encoding="UTF-8"?>}%
+ \ifPDFTeX % latin1-based engines (pdflatex or latex)
+ \writetomoodle{<?xml version="1.0" encoding="iso-8859-1"?>}%
+ \else
+ \ifTUTeX % UTF8-based engines (XeTeX or LuaTeX)
+ \writetomoodle{<?xml version="1.0" encoding="UTF-8"?>}%
+ \else % what shall we do?
+ \writetomoodle{<?xml version="1.0" encoding="UTF-8"?>}%
+ %\stop
+ \fi
+ \fi
+ \ifmoodle@stampmode
+ \def\moodle@stamp{This file was generated on \the\year-\two@digits\month-\two@digits\day}
+ \ifPDFTeX % pdflatex or latex
+ \ifpdf % pdflatex
+ \g@addto@macro{\moodle@stamp}{ by pdfLaTeX }%
+ \else % latex
+ \g@addto@macro{\moodle@stamp}{ by LaTeX }%
+ \fi
+ \else
+ \ifXeTeX % xetex
+ \g@addto@macro{\moodle@stamp}{ by XeLaTeX }%
+ \else
+ \ifLuaTeX % luatex
+ \g@addto@macro{\moodle@stamp}{ by LuaLaTeX }%
+ \else
+ \g@addto@macro{\moodle@stamp}{ a TeX engine }%
+ \fi
+ \fi
+ \fi
+ \writetomoodle{<!-- \moodle@stamp -->}%
+ \def\moodle@stamp{running on \platformname}%
+ \g@addto@macro{\moodle@stamp}{ with the package moodle v0.8 }%
+ \writetomoodle{<!-- \moodle@stamp -->}%
+ \fi
+ \immediate\write\moodle@outfile{}%
\writetomoodle{<quiz>}%
- \writetomoodle{ }%
}%
\def\closemoodleout{%
\writetomoodle{ }%
@@ -797,6 +1814,7 @@
\immediate\closeout\moodle@outfile
}%
% \end{macrocode}
+%
% To both make this |.sty| file and the XML output more readable,
% we create a mechanism for writing to the output file with indents.
% The macro |\calculateindent|\marg{$n$} globally defines
@@ -836,27 +1854,71 @@
% We now create the main |quiz| environment that will contain
% the questions we write. It outputs to XML as a |<question type="category">| tag.
% \begin{macrocode}
-\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{%
+{\catcode`\$=12\catcode`\ =12% in this context we cannot indent with spaces...
+\gdef\moodle@write@category@xml#1{%
+\@moodle@ifgeneratexml{%
+\writetomoodle{ }%
\writetomoodle{<question type="category">}%
\writetomoodle{ <category>}%
-\writetomoodle{ <text>$module$/#1</text>}%
+\writetomoodle{ <text>$course$/top/#1</text>}%
\writetomoodle{ </category>}%
\writetomoodle{</question>}%
\writetomoodle{ }%
+}{}%
}}%
+\newcommand*\@enumeratename{enumerate}%
+\newenvironment{quiz}[2][]{%
+ \setkeys{moodle}{#1}%
+ \gdef\setcategory##1{%
+ % At first call (end of \begin{quiz}) enumerate is not started yet
+ \ifx\@currenvir\@enumeratename
+ % In case no question is defined between two calls of \setcategory
+ \def\@noitemerr{\@latex@warning{Empty question list}}%
+ \end{enumerate}%
+ \fi
+ \gdef\moodle@currentcategory{##1}%
+ \moodle@write@category@xml{##1}%
+ \ifmoodle@section
+ \ifmoodle@numbered
+ \section{##1}%
+ \else
+ \section*{##1}%
+ \fi
+ \else
+ \ifmoodle@numbered
+ \subsection{##1}%
+ \else
+ \subsection*{##1}%
+ \fi
+ \fi
+ \begin{enumerate}%
+ }%
+ \gdef\setsubcategory##1{%
+ \def\@noitemerr{\@latex@warning{Empty question list}}%
+ \end{enumerate}%
+ \moodle@write@category@xml{\moodle@currentcategory/##1}%
+ \ifmoodle@section
+ \ifmoodle@numbered
+ \subsection{##1}%
+ \else
+ \subsection*{##1}%
+ \fi
+ \else
+ \ifmoodle@numbered
+ \subsubsection{##1}%
+ \else
+ \subsubsection*{##1}%
+ \fi
+ \fi
+ \begin{enumerate}%
+ }%
+ \setcategory{#2}%
+}{%
+ \end{enumerate}%
+ \let\setcategory\relax
+ \let\setsubcategory\relax
+}%
+
% \end{macrocode}
% The next utility takes a single macro control sequence |#1|,
% and allows that macro's current value to persist
@@ -888,6 +1950,19 @@
}%
}
% \end{macrocode}
+% Now the macros |openmoodleout| and |closemoodleout| are triggered at Begin and End Document, respectively
+% \begin{macrocode}
+\AfterEndPreamble{
+ \@moodle@ifgeneratexml{%
+ \openmoodleout%
+ }{}%
+}
+\AtEndDocument{
+ \@moodle@ifgeneratexml{%
+ \closemoodleout%
+ }{}%
+}
+% \end{macrocode}
%
% \subsection{Key-Value Pairs for Quiz Questions}
%
@@ -902,7 +1977,7 @@
% to the output XML file.
%
% The ordinary version |\generate@moodle@write@code| passes its output text |#3|
-% through the HTMLizer, producing HTML code, while the starred version
+% through the HTMLizer, producing HTML code, while the starred variant
% |\generate@moodle@write@code*| passes |#3| verbatim as text.
%
% For example,
@@ -951,6 +2026,23 @@
}%
}%
+\def\generate@moodle@write@html@noptag#1<#2>#3{%
+ % No <P>..</P> introduced
+ % #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[\moodle@htmltowrite]]></text>}%
+ \writetomoodle[2]{ </#2>}%
+ \fi
+ }%
+}%
\def\generate@moodle@write@data*#1<#2>#3{%
% #1 = NAME for \moodle@writeNAME
@@ -961,16 +2053,33 @@
}%
}%
+\def\generate@moodle@write@tags#1{%
+ % #1 = NAME for \moodle@writeNAME
+ % #3 = what, exactly, to write
+ \xa\gdef\csname moodle@writetags\endcsname{%
+ %\xa\xa\xdef\xa\xa\ds\xa\xa{Encountered '\string #1'}\show\ds
+ \xa\xdef\xa\test@iii\xa{\moodle@tags}%
+ \ifx\test@iii\@moodle@empty\relax\else
+ \xa\converttohtmlmacro\xa\moodle@htmltowrite\xa{\moodle@tags}%
+ \writetomoodle[2]{ <tags>}%
+ \writetomoodle[4]{ <tag><text><![CDATA[\moodle@htmltowrite]]></text></tag>}%
+ \writetomoodle[2]{ </tags>}%
+ \fi
+ }%
+}%
+
% \end{macrocode}
% \subsubsection{Keys for all question types}
% \begin{macrocode}
%% QUESTIONNAME
\define@cmdkey{moodle}[moodle@]{questionname}{}%
- \gdef\moodle@writequestionname{%
- \writetomoodle[2]{<name>}%
- \writetomoodle[4]{ <text>\moodle@questionname</text>}%
- \writetomoodle[2]{</name>}%
- }%
+% \gdef\moodle@writequestionname{%
+% \writetomoodle[2]{<name>}%
+% \writetomoodle[4]{ <text>\moodle@questionname</text>}%
+% \writetomoodle[2]{</name>}%
+% }%
+%\generate@moodle@write@code{questionname}<name>{\moodle@questionname}%
+\generate@moodle@write@html@noptag{questionname}<name>{\moodle@questionname}%
%% QUESTIONTEXT
%I tried to use questiontext as a key, but it doesn't seem to work.
@@ -986,9 +2095,9 @@
\generate@moodle@write@code{questiontext}<questiontext>{\moodle@questiontext}%{%
%% PENALTY FOR WRONG ATTEMPT
- \define@cmdkey{moodle}[moodle@]{penalty}[0.1000000]{}%
+ \define@cmdkey{moodle}[moodle@]{penalty}[0.10]{}%
\generate@moodle@write@code*{penalty}<penalty>{\moodle@penalty}%
- \moodleset{penalty}%
+ \moodleset{penalty=0.10}%
%% FEEDBACK
% Moodle allows for feedback tailored to each question,
@@ -1002,7 +2111,7 @@
\define@cmdkey{moodle}[moodle@]{feedback}[]{}%
\generate@moodle@write@code{generalfeedback}<generalfeedback>{\moodle@feedback}%
\generate@moodle@write@code{feedback}<feedback>{\moodle@feedback}%
- \moodleset{feedback}%
+ \moodleset{feedback={}}%
%% DEFAULT GRADE
%The next line creates \moodle@defaultgrade,
@@ -1028,7 +2137,14 @@
\moodle@writehidden%
}%
-% TO DO: 'tags' (i.e., keywords)
+%% TAGS
+ %The next line creates \moodle@tags,
+ %which defines a "tag" (i.e., keyword) for the question.
+ %Key calls like [tags={random}] set \moodle@tags.
+ \define@cmdkey{moodle}[moodle@]{tags}[]{}%
+ \generate@moodle@write@tags{\csname moodle@tags\endcsname}%
+ \moodleset{tags}%
+% TODO: handle multiple 'tags' for one question
% \end{macrocode}
% \subsubsection{Keys for all answers}
@@ -1039,13 +2155,18 @@
%the XML within the answer tag, like <answer fraction="75">.
\moodleset{fraction=100} %This sets the default.
% \end{macrocode}
+% \begin{macrocode}
+%% FRACTIONTOL -- the tolerance for fractions with respect to valid values
+ \define@cmdkey{moodle}[moodle@]{fractiontol}[0.1]{}%
+ \moodleset{fractiontol=0.1} %This sets the default.
+% \end{macrocode}
% \subsubsection{Keys for multiple choice questions}
% \begin{macrocode}
%% 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}%
+ \moodleset{single=true}%
%The key 'multiple' is an antonym to 'single'.
\define@boolkey{moodle}[moodle@]{multiple}[true]{\ifmoodle@multiple\moodle@singlefalse\else\moodle@singletrue\fi}%
@@ -1054,15 +2175,15 @@
\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
+%% TODO: CORRECTFEEDBACK
+%% TODO: PARTIALLYCORRECTFEEDBACK
+%% TODO: INCORRECTFEEDBACK
+%% TODO: 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]{%
+ abc,ABCD,123,iii,IIII,none}[abc]{%
\def\moodle@numbering{#1}%
\def\test@@i{#1}%
\ifx\test@@i\@moodle@alpha
@@ -1070,9 +2191,9 @@
\ifx\test@@i\@moodle@alph
\def\moodle@numbering{abc}\fi
\ifx\test@@i\@moodle@Alpha
- \def\moodle@numbering{ABC}\fi
+ \def\moodle@numbering{ABCD}\fi
\ifx\test@@i\@moodle@Alph
- \def\moodle@numbering{ABC}\fi
+ \def\moodle@numbering{ABCD}\fi
\ifx\test@@i\@moodle@arabic
\def\moodle@numbering{123}\fi
\ifx\test@@i\@moodle@roman
@@ -1094,7 +2215,7 @@
\def\@moodle@roman{roman}%
\def\@moodle@Roman{Roman}%
\def\@moodle@abc{abc}%
- \def\@moodle@ABC{ABC}%
+ \def\@moodle@ABCD{ABCD}%
\def\@moodle@arabicnumbers{123}%
\def\@moodle@iii{iii}%
\def\@moodle@IIII{IIII}%
@@ -1103,7 +2224,7 @@
\ifx\moodle@numbering\@moodle@abc
\renewcommand\theenumii{\alph{enumii}}%
\fi
- \ifx\moodle@numbering\@moodle@ABC
+ \ifx\moodle@numbering\@moodle@ABCD
\renewcommand\theenumii{\Alph{enumii}}%
\fi
\ifx\moodle@numbering\@moodle@arabicnumbers
@@ -1119,7 +2240,7 @@
\renewcommand\labelenumii{$\bullet$~}%
\fi
}
- %TO DO: * In the PDF, how should 'none' in a multi look different from
+ %TODO: * 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.
@@ -1140,7 +2261,7 @@
%tolerance is given within the answer tag,
%like <answer fraction=100 tolerance=0.03>.
-% TO DO: implement unit-handling for numerical questions!
+% TODO: implement unit-handling for numerical questions!
% \end{macrocode}
% \subsubsection{Keys for short answer questions}
% \begin{macrocode}
@@ -1215,7 +2336,7 @@
%% RESPONSE REQUIRED
\define@boolkey{moodle}[moodle@]{response required}[true]{}%
- % TO DO: Make synonym 'required'
+ % TODO: Make synonym 'required'
\generate@moodle@write@code*{responserequired}<responserequired>{\csname ifmoodle@response required\endcsname 1\else 0\fi}%
\moodleset{response required=false}%
@@ -1245,7 +2366,7 @@
%% RESPONSE TEMPLATE
\define@key{moodle}{template}{\long\def\moodle@responsetemplate{#1}}%
- \generate@moodle@write@code{responsetemplate}<responsetemplate>{\moodle@responsetemplate}
+ \generate@moodle@write@html@noptag{responsetemplate}<responsetemplate>{\moodle@responsetemplate}
\moodleset{template={}}%
% \end{macrocode}
% \subsubsection{Hint tags}
@@ -1269,7 +2390,7 @@
}%
\moodleset{clearwrong=false}%
-% TO DO: Implement hints
+% TODO: Implement hints
% \end{macrocode}
%
% \subsection{Answer handling}
@@ -1305,21 +2426,6 @@
% \subsubsection{Not yet implemented}
%
% \begin{macrocode}
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% TRUE/FALSE QUESTIONS %%%%%%%%%%%%%%%%%
-
-% TODO: implement the \writetruefalsequestion
-% and a front-end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% DESCRIPTION 'QUESTIONS' %%%%%%%%%%%%%
-
-% TODO: implement the \writedescription and a suitable front-end.
-% Should this be \begin{description}...\end{description},
-% or should \begin{quiz}...\end{quiz} just scoop up all
-% text outside question environments and package it in descriptions?
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% CALCULATED %%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1354,48 +2460,142 @@
% \end{Verbatim}
%
% \begin{macrocode}
-\def\moodle@makefrontend#1{%
+
+\def\moodle@makelatextagbox#1{%
+% \ifmoodle@tikzloaded
+% \tikzset{external/export next=false}
+% \tikz[baseline]{\node[draw,minimum height=1.2em,rounded corners,fill=black!20] {\tiny #1};}
+% % Fancy but interferes with the tikzexternalize counter
+% \else
+ \Ovalbox{\tiny #1}
+ %\ovalbox{\tiny #1}
+ %\shadowbox{\tiny #1}
+% \fi
+}%
+
+\def\moodle@makelatextag@qtype#1{%
+ \doublebox{\tiny \textsc{#1}}
+}%
+
+\def\moodle@makelatextag@value#1#2{%
+ \moodle@makelatextagbox{\csname moodle@#1\endcsname~#2}
+}%
+
+\def\moodle@makelatextag@key#1{%
+ \moodle@makelatextagbox{\csname moodle@#1\endcsname}
+}%
+
+\def\moodle@marks#1{point\ifdim#1pt=1pt \else s\fi}
+
+\def\moodle@makefrontend#1#2{%
\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
+ \item \textbf{\moodle@questionname}
+ \ifmoodle@handout
+ \moodle@makelatextag@qtype{#1}
+ \else
+ \xa\xdef\xa\test@iii\xa{\moodle@tags}%
+ \ifx\test@iii\@moodle@empty\relax\else
+ \hfill tags: \texttt{\moodle@tags}
+ \fi
+ \par
+ \noindent
+ \moodle@makelatextag@qtype{#1}
+ \moodle@makelatextag@value{default grade}{\moodle@marks{\csname moodle@default grade\endcsname}}
+ \moodle@makelatextag@value{penalty}{penalty}
+ \fi
+ #2\par
\noindent
\moodle@questionheader
+ \edef\moodle@generalfeedback{\expandonce\moodle@feedback}
\csname moodle@#1@latexprocessing\endcsname
%Now, writing information to XML
\@moodle@ifgeneratexml{%
\xa\questiontext\xa{\moodle@questionheader}% Save the question text.
+ \csname write#1question\endcsname
\bgroup
\gdef\moodle@answers@xml{}%
\setkeys{moodle}{feedback={}}%
\xa\loopthroughitemswithcommand\xa{\csname save#1answer\endcsname}%
\passvalueaftergroup{\moodle@answers@xml}%
\egroup
- \csname write#1question\endcsname
+ \moodle@writeanswers%
+ \moodle@writetags%
+ \writetomoodle{</question>}%
}{}%
\egroup
}%
}
% \end{macrocode}
%
-% \subsubsection{Essay Question Front-End}
-% The essay question is the only question type whose front end
+% \subsubsection{Description Question Front-End}
+% Description and essay questions are the only question types whose front end
% is not yet created by |\moodle@makefrontend|.
-% This is because of what it must do with its |\item|'s.
+% This is because of what need to be done with their contents.
+%
+% Description blocks can be empty. In this case, nothing is done.
+%
+% \begin{macrocode}
+\let\description\relax% remove the meaning of existing \description and \enddescription
+\let\enddescription\relax
+\NewEnviron{description}[2][]{%
+ \bgroup
+ \setkeys{moodle}{#1,questionname={#2}}%
+ \let\moodle@questiontext=\BODY
+ \trim@spaces@in\moodle@questiontext
+ \ifx\moodle@questiontext\@empty\relax\else%
+ %First, the LaTeX processing.
+ \item \textbf{\moodle@questionname}
+ \ifmoodle@handout\else
+ \xa\xdef\xa\test@iii\xa{\moodle@tags}%
+ \ifx\test@iii\@moodle@empty\relax\else
+ \hfill tags: \texttt{\moodle@tags}%
+ \fi
+ \par
+ \noindent
+ \fi
+ \moodle@makelatextag@qtype{description}\par
+ \noindent
+ \moodle@questiontext\par
+ \ifmoodle@handout\else
+ \ifx\moodle@feedback\@empty\relax\else
+ \fbox{\parbox{\linewidth}{\emph{\moodle@feedback}}}%
+ \fi
+ \fi
+ %Now, writing information to memory.
+ \@moodle@ifgeneratexml{%
+ \writetomoodle{<question type="description">}%
+ \moodle@writecommondata
+ \moodle@writetags%
+ \writetomoodle{</question>}%
+ }{}%
+ \fi
+ \egroup
+}%
+% \end{macrocode}
+%
+% \subsubsection{Essay Question Front-End}
+% The front end is not yet created by |\moodle@makefrontend| because of
+% what must must be done with the |\item|'s.
%
% \begin{macrocode}
\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.
+ \par\noindent \emph{Notes for grader:}
+ \moodle@questionheader
\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
+ \ifx\moodle@generalfeedback\@empty\relax\else%
+ \fbox{\parbox{\linewidth}{\emph{\moodle@generalfeedback}}}%
+ \fi
}
\NewEnviron{essay}[2][]{%
@@ -1404,13 +2604,35 @@
\expandafter\gatheritems\expandafter{\BODY}%
\let\moodle@questionheader=\gatheredheader
%First, the LaTeX processing.
- \item \textbf{\moodle@questionname}\par
+ \item \textbf{\moodle@questionname}
+ \ifmoodle@handout
+ \moodle@makelatextag@qtype{essay}
+ \else
+ \xa\xdef\xa\test@iii\xa{\moodle@tags}%
+ \ifx\test@iii\@moodle@empty\relax\else
+ \hfill tags: \texttt{\moodle@tags}
+ \fi
+ \par
+ \noindent
+ \moodle@makelatextag@qtype{essay}
+ \moodle@makelatextag@value{default grade}{\moodle@marks{\csname moodle@default grade\endcsname}}
+ \moodle@makelatextag@value{penalty}{penalty}
+ \moodle@makelatextag@key{responseformat}
+ \fi
+ \par
\noindent
- \moodle@questionheader
- \csname moodle@essay@latexprocessing\endcsname
+ \ifx\moodle@responsetemplate\@empty\relax\else%
+ \par\noindent \emph{Template:}
+ \par\fbox{\parbox{\linewidth}{\moodle@responsetemplate}}\par
+ \fi
+ \edef\moodle@generalfeedback{\expandonce\moodle@feedback}
+ \ifmoodle@handout\else
+ \csname moodle@essay@latexprocessing\endcsname
+ \fi
%Now, writing information to memory.
\@moodle@ifgeneratexml{%
\xa\questiontext\xa{\moodle@questionheader}% Save the question text.
+ \writeessayquestion
\bgroup
\gdef\moodle@answers@xml{}%
%
@@ -1430,12 +2652,15 @@
%
\passvalueaftergroup{\moodle@answers@xml}%
\egroup
- \writeessayquestion
+ \moodle@writeanswers% The 'answers' XML really contains the grader info.
+ \moodle@writeresponsetemplate%
+ \moodle@writetags%
+ \writetomoodle{</question>}%
}{}%
\egroup
}%
-%%%% TO DO
+%%%% TODO
%%%% To make essay work will be tough.
%%%% Every line from \ifnum\c@numgathereditems=0\relax through its \else and \fi,
%%%% with the exception of
@@ -1477,9 +2702,6 @@
\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{%
@@ -1488,6 +2710,7 @@
\def\moodle@savegraderinfo#1{%
+ %\def\ds{#1}\show\ds
\bgroup
\moodle@savegraderinfo@int#1\moodle@answer@rdelim
\passvalueaftergroup{\moodle@answers@xml}%
@@ -1498,7 +2721,8 @@
\moodle@savegraderinfo@int@int%
}%
\def\moodle@savegraderinfo@int@int#1\moodle@answer@rdelim{%
- \xa\converttohtmlmacro\xa\moodle@answertext@html\xa{#1}%
+ \def\moodle@answertext{#1}
+ \xa\converttohtmlmacro\xa\moodle@answertext@html\xa{\moodle@answertext}%
%\trim@spaces@in\moodle@answertext
\ifnum\c@numgathereditems>1\relax
\addto@xml[6]{\moodle@answers@xml}{<li>\moodle@answertext@html</li>}%
@@ -1512,17 +2736,21 @@
%
% \begin{macrocode}
\def\blank{\rule{1in}{0.5pt}}%
-% TO DO: Make an optional argument for width? This wouldn't affect Moodle,
+% TODO: Make an optional argument for width? This wouldn't affect Moodle,
% only the appearance in the PDF. It doesn't seem worth it.
-% \NewEnviron{shortanswer}[2][]{%
+%\NewEnviron{shortanswer}[2][]{%
% \bgroup
% \setkeys{moodle}{#1,questionname={#2}}%
% \expandafter\gatheritems\xa{\BODY}%
% \let\moodle@questionheader=\gatheredheader
% %First, the LaTeX processing.
-% \bigskip\par\noindent
-% \fbox{\textbf{\moodle@questionname}}\par
+% \item \textbf{\moodle@questionname}
+% \csname ifmoodle@case sensitive\endcsname
+% \framebox{\tiny Case-Sensitive}\relax
+% \fi
+% \framebox{\tiny\csname moodle@default grade\endcsname~points}
+% \framebox{\tiny\csname moodle@penalty\endcsname~penalty}\par
% \noindent
% \moodle@questionheader
% \csname moodle@shortanswer@latexprocessing\endcsname
@@ -1532,7 +2760,8 @@
% \bgroup
% \gdef\moodle@answers@xml{}%
% \setkeys{moodle}{feedback={}}%
-% \xa\loopthroughitemswithcommand\xa{\csname saveshortansweranswer\endcsname}%
+% \xa\loopthroughitemswithcommand\xa{\csname
+% saveshortansweranswer\endcsname}%
% \passvalueaftergroup{\moodle@answers@xml}%
% \egroup
% \csname writeshortanswerquestion\endcsname
@@ -1540,16 +2769,33 @@
% \egroup
% }%
-\moodle@makefrontend{shortanswer}%
+\moodle@makefrontend{shortanswer}{\moodle@makelatextag@shortanswer}%
% LATEX PROCESSING
-\def\moodle@shortanswer@latexprocessing{%
- \begin{itemize} \setlength\itemsep{0pt}\setlength\parskip{0pt}%
- \loopthroughitemswithcommand{\moodle@print@shortanswer@answer}%
- \end{itemize}%
+
+\def\moodle@makelatextag@shortanswer{%
+ \csname ifmoodle@case sensitive\endcsname
+ \moodle@makelatextagbox{Case-Sensitive}\relax
+ \else
+ \moodle@makelatextagbox{Case-Insensitive}\relax
+ \fi
}
+\ifmoodle@handout
+ \let\moodle@shortanswer@latexprocessing\relax
+\else
+ \def\moodle@shortanswer@latexprocessing{%
+ \begin{itemize} \setlength\itemsep{0pt}\setlength\parskip{0pt}%
+ \loopthroughitemswithcommand{\moodle@print@shortanswer@answer}%
+ \end{itemize}%
+ \ifx\moodle@generalfeedback\@empty\relax\else%
+ \fbox{\parbox{\linewidth}{\emph{\moodle@generalfeedback}}}%
+ \fi
+ }
+\fi
+
\def\moodle@print@shortanswer@answer#1{%
+ \let\moodle@feedback=\@empty
\moodle@print@shortanswer@answer@int#1\@rdelim
}%
\newcommand\moodle@print@shortanswer@answer@int[1][]{%
@@ -1558,9 +2804,13 @@
}%
\def\moodle@print@shortanswer@answer@int@int#1\@rdelim{%
\ifx\moodle@fraction\@hundred
- \item #1\quad$\checkmark$%
+ \item #1$~\checkmark$%
\else
- \item #1\quad (\moodle@fraction\%)%
+ \moodle@checkfraction
+ \item #1$~(\moodle@fraction\%)$%
+ \fi
+ \ifx\moodle@feedback\@empty\relax\else
+ \hfill \emph{$\rightarrow$ \moodle@feedback}
\fi
}%
@@ -1577,10 +2827,14 @@
}%
\def\saveshortansweranswer@int@int#1\moodle@answer@rdelim{%
\def\moodle@answertext{#1}%
+ \trim@spaces@in\moodle@answertext
+ \moodle@checkfraction
\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>}%
+ \trim@spaces@in\moodle@feedback
+ \xa\converttohtmlmacro\xa\moodle@feedback@html\xa{\moodle@feedback}%
+ \addto@xml[4]{\moodle@answers@xml}{ <feedback format="html"><text><![CDATA[<p>\moodle@feedback@html</p>]]></text></feedback>}%
\fi
\addto@xml[2]{\moodle@answers@xml}{</answer>}%
}%
@@ -1590,40 +2844,63 @@
\writetomoodle{<question type="shortanswer">}%
\moodle@writecommondata%
\moodle@writeusecase%
- \moodle@writeanswers%
- \writetomoodle{</question>}%
}%
% \end{macrocode}
%
% \subsubsection{Numerical Question Front-End}
%
% \begin{macrocode}
-\moodle@makefrontend{numerical}%
+\moodle@makefrontend{numerical}{\moodle@makelatextag@numerical}%
% LATEX PROCESSING
-\def\moodle@numerical@latexprocessing{%
- \begin{itemize} \setlength\itemsep{0pt}\setlength\parskip{0pt}%
- \loopthroughitemswithcommand{\moodle@print@numerical@answer}%
- \end{itemize}%
+
+\def\moodle@makelatextag@numerical{}
+
+\AtEndPreamble{
+ \@ifpackageloaded{siunitx}{\def\moodle@printnum{\num[omit-uncertainty,copy-decimal-marker]}}{\let\moodle@printnum\trim@spaces}%
}
+\ifmoodle@handout
+ \let\moodle@numerical@latexprocessing\relax
+\else
+ \def\moodle@numerical@latexprocessing{%
+ \begin{itemize} \setlength\itemsep{0pt}\setlength\parskip{0pt}%
+ \loopthroughitemswithcommand{\moodle@print@numerical@answer}%
+ \end{itemize}%
+ \ifx\moodle@generalfeedback\@empty\relax\else%
+ \fbox{\parbox{\linewidth}{\emph{\moodle@generalfeedback}}}%
+ \fi
+ }
+\fi
+
\def\moodle@print@numerical@answer#1{%
- \moodle@print@numerical@answer@int#1\@rdelim
+ \let\moodle@feedback=\@empty
+ \bgroup
+ \moodle@print@numerical@answer@int#1\@rdelim
+ \egroup
}%
\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{}%
+ \xdef\test@i{\trim@spaces{#1}}%
+ \ifx\test@i\@star
+ \item \test@i
\else
- \edef\moodle@numericalprint@tolerance{\noexpand\pm\moodle@tolerance}%
+ \item \moodle@printnum{#1}%
+ \ifnum\z@=\moodle@tolerance\else
+ $\,\pm\,$\moodle@printnum{\moodle@tolerance}%
+ \fi
\fi
\ifx\moodle@fraction\@hundred
- \item $#1\moodle@numericalprint@tolerance\quad\checkmark$%
+ $~\checkmark$%
\else
- \item $#1\moodle@numericalprint@tolerance$\quad (\moodle@fraction\%)%
+ \moodle@checkfraction
+ $~(\moodle@fraction\%)$%
+ \fi
+ \ifx\moodle@feedback\@empty\relax\else
+ \hfill \emph{$\rightarrow$ \moodle@feedback}%
\fi
}%
@@ -1640,11 +2917,17 @@
}%
\def\savenumericalanswer@int@int#1\moodle@answer@rdelim{%
\def\moodle@answertext{#1}%
+ \trim@spaces@in\moodle@answertext
+ \moodle@checkfraction
\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@answertext\@star\else
+ \addto@xml[4]{\moodle@answers@xml}{ <tolerance>\moodle@tolerance</tolerance>}%
+ \fi
\ifx\moodle@feedback\@empty\relax\else
- \addto@xml[4]{\moodle@answers@xml}{ <feedback format="html"><text><![CDATA[<p>\moodle@feedback</p>]]></text></feedback>}%
+ \trim@spaces@in\moodle@feedback
+ \xa\converttohtmlmacro\xa\moodle@feedback@html\xa{\moodle@feedback}%
+ \addto@xml[4]{\moodle@answers@xml}{ <feedback format="html"><text><![CDATA[<p>\moodle@feedback@html</p>]]></text></feedback>}%
\fi
\addto@xml[2]{\moodle@answers@xml}{</answer>}%
}%
@@ -1654,8 +2937,6 @@
\gdef\writenumericalquestion{%
\writetomoodle{<question type="numerical">}%
\moodle@writecommondata%
- \moodle@writeanswers%
- \writetomoodle{</question>}%
}%
% \end{macrocode}
%
@@ -1670,57 +2951,155 @@
% \item 11
% \end{multi}%
-\moodle@makefrontend{multi}
+\moodle@makefrontend{multi}{\moodle@makelatextag@multi}%
% LATEX PROCESSING
+
+\def\moodle@makelatextag@multi{%
+ \ifmoodle@multiple
+ \moodle@makelatextagbox{Multiple}\relax%
+ \else
+ \moodle@makelatextagbox{Single}\relax%
+ \fi
+ \ifmoodle@handout\else
+ \ifmoodle@shuffle
+ \moodle@makelatextagbox{Shuffle}\relax%
+ \fi
+ \fi
+}
+
\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}%
+ \moodle@countcorrectanswers%
+ \ifmoodle@handout\NewList{answerlist}\fi
+ \begin{enumerate}\moodle@obeynumberingstyle%
+ %\renewcommand{\theenumi}{\alph{enumi}}%
+ \setlength\itemsep{0pt}\setlength\parskip{0pt}%
+ \loopthroughitemswithcommand{\moodle@print@multichoice@answer}%
+ \ifmoodle@handout
+ \ifmoodle@shuffle
+ \let\moodle@multi@loop=\ForEachRandomItem
+ \else
+ \let\moodle@multi@loop=\ForEachFirstItem
+ \fi
+ \moodle@multi@loop{answerlist}{Answer}{\Answer}%
+ \fi
+ \end{enumerate}%
+ \ifmoodle@handout\else
+ \ifx\moodle@generalfeedback\@empty\relax\else%
+ \fbox{\parbox{\linewidth}{\emph{\moodle@generalfeedback}}}%
+ \fi
+ \fi
}
\def\moodle@print@multichoice@answer#1{%
- \moodle@print@multichoice@answer@int#1\@rdelim
+ \let\moodle@feedback=\@empty%
+ \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
+ \let\moodle@fraction\@empty%
+ \setkeys{moodle}{#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$%
+ \def\test@ii{#2}%
+ \def\moodle@answertext{\item }%
+ \ifx\test@i\@star%
+ \g@addto@macro\moodle@answertext{#2}%
+ \ifmoodle@single%
+ \setkeys{moodle}{fraction=100}%
\else
- \item #1#2%
+ \setkeys{moodle}{fraction=\moodle@autopoints}%
\fi
\else
- \ifx\test@i\@star
- \item #2%
- \setkeys{moodle}{fraction=\moodle@autopoints}%
- \else
- \item #1#2%
+ \g@addto@macro\moodle@answertext{#1#2}%
+ \fi
+ \trim@spaces@in\moodle@answertext%
+ \trim@spaces@in\moodle@answertext%
+ \ifmoodle@handout\else
+ \ifmoodle@single%
+ \ifx\moodle@fraction\@empty\relax%
+ \setkeys{moodle}{fraction=0}%
+ \fi
+ \ifx\moodle@fraction\@hundred%
+ \trim@spaces@in\moodle@answertext%
+ \g@addto@macro\moodle@answertext{$~\checkmark$}%
+ \else
+ \moodle@checkfraction
+ \ifdim0pt=\moodle@fraction pt\relax\else%
+ \g@addto@macro\moodle@answertext{$~(\moodle@fraction\%)$}%
+ \fi
+ \fi
+ \else% multiple
+ \ifx\moodle@fraction\@empty\relax%
+ \setkeys{moodle}{fraction=\moodle@autosanctions}%
+ \fi
+ \moodle@checkfraction
+ \g@addto@macro\moodle@answertext{$~(\moodle@fraction\%)$}%
\fi
- $~(\moodle@fraction\%)$
+ \fi
+ \ifmoodle@handout
+ \def\temp{\InsertLastItem{answerlist}}%
+ \xa\temp\xa{\moodle@answertext}%
+ \else
+ \ifx\moodle@feedback\@empty\relax\else%
+ \g@addto@macro\moodle@answertext{\hfill \emph{$\rightarrow$ \moodle@feedback}}%
+ \fi
+ \moodle@answertext
\fi
}%
-% COMMON UTILITY: COUNTING CORRECT ANSWERS
- \newcounter{moodle@numcorrectanswers}%
+% COMMON UTILITY: COUNTING CORRECT ANSWERS (AND A BIT MORE...)
+ \newcounter{moodle@numcorrectanswers}% count the stars
+ \newcounter{moodle@numincorrectanswers}% count the items without fraction key indicated
\newlength{\moodle@pointspercorrect}%
+ \newlength{\moodle@pointsperincorrect}%
+ \newlength{\moodle@sumofpositivefractions}% sums user-set positive fractions
+ \newlength{\moodle@sumofnegativefractions}% sums user-set negative fractions
\def\moodle@countcorrectanswers{%
\setcounter{moodle@numcorrectanswers}{0}%
+ \setcounter{moodle@numincorrectanswers}{0}%
\global\setlength{\moodle@pointspercorrect}{100pt}%
+ \global\setlength{\moodle@pointsperincorrect}{-100pt}%
+ \global\setlength{\moodle@sumofpositivefractions}{0pt}%
+ \global\setlength{\moodle@sumofnegativefractions}{0pt}%
\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}%
+ \global\advance\moodle@pointspercorrect by-\moodle@sumofpositivefractions\relax%
+ \def\ds{\strip@pt\moodle@sumofpositivefractions}%
+ \ifnum0=\c@moodle@numcorrectanswers\relax%
+ % autopoints will never be used but we check if the sum of positive fractions is 100%
+ \ifdim\moodle@pointspercorrect<-\moodle@fractiontol pt\relax%
+ \PackageWarning{moodle}{Positive fractions sum up to more than 100 (here: \ds)}%
+ \else
+ \ifdim\moodle@pointspercorrect>\moodle@fractiontol pt\relax%
+ \PackageError{moodle}{Positive fractions sum up to less than 100 (here: \ds)}%
+ \fi
+ \fi
\else
- \global\divide\moodle@pointspercorrect by \c@moodle@numcorrectanswers\relax
- \edef\moodle@autopoints{\strip@pt\moodle@pointspercorrect}%
+ \ifdim0pt<\moodle@pointspercorrect\relax\else%
+ % we have starred items so the sum of user-set positive fractions must be less than 100%
+ % otherwise, starred items would lead to penalties
+ \PackageError{moodle}{Positive fractions sum up to 100 or more (here: \ds):
+ there is no positive points left to be given to starred items.}%
+ \fi
+ \global\divide\moodle@pointspercorrect by \c@moodle@numcorrectanswers\relax%
\fi
+ \gdef\moodle@autopoints{\strip@pt\moodle@pointspercorrect}%
+ \global\advance\moodle@pointsperincorrect by-\moodle@sumofnegativefractions\relax%
+ \def\ds{\strip@pt\moodle@sumofnegativefractions}%
+ \ifnum0=\c@moodle@numincorrectanswers\relax%
+ % autosanctions will never be used and
+ % we do not care about the sum of negative fractions (might be less than -100)
+ \else
+ \ifdim0pt<\moodle@pointsperincorrect\relax%
+ % we have items without fractions set: to prevent auto sanctions from becoming bonuses,
+ % such items are neutralized.
+ \PackageWarning{moodle}{Negative fractions sum up to -100 or less (here: \ds):
+ items with no fraction key set will be considered as neutral.}%
+ \global\setlength{\moodle@pointsperincorrect}{0pt}%
+ \fi
+ \global\divide\moodle@pointsperincorrect by \c@moodle@numincorrectanswers\relax%
+ \fi
+ \gdef\moodle@autosanctions{\strip@pt\moodle@pointsperincorrect}%
}
\def\moodle@countcorrectanswers@a#1{%
%The grouping is to keep key answer-specific key changes local.
@@ -1729,34 +3108,79 @@
\egroup
}%
\newcommand\moodle@countcorrectanswers@b[1][]{%
- \setkeys{moodle}{fraction=0,#1}%
- \moodle@countcorrectanswers@c%
+ %\ifx&#1&%
+ \let\moodle@fraction\@empty%
+ \setkeys{moodle}{#1}%
+ \moodle@countcorrectanswers@c%
+ %\fi
}%
\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}%
+ \ifx\moodle@fraction\@empty\relax%
+ \stepcounter{moodle@numincorrectanswers}%
+ \else
+ \ifdim0pt<\moodle@fraction pt\relax%
+ \global\addtolength{\moodle@sumofpositivefractions}{\moodle@fraction pt}%
+ \else
+ \global\addtolength{\moodle@sumofnegativefractions}{\moodle@fraction pt}%
+ \fi
+ \fi
\fi
}%
- \def\moodle@setautopoints#1pt{%
- \gdef\moodle@autopoints{#1}%
+ \newlength{\test@fraction}%
+ \newlength{\test@lower}%
+ \newlength{\test@upper}%
+ \def\moodle@fractionerror{%
+ \def\ds{\moodle@fraction}%
+ \PackageError{moodle}{the current fraction is not a valid value (here: \ds)}%
+ }
+ {\catcode`|=3\relax
+ \gdef\moodle@validfractionlist{0|5|10|11.11111|12.5|14.28571|16.66667|20|25|30|33.33333|40|50|60|66.66667|70|75|80|83.33333|90|100}}%
+ \def\moodle@isfractionnear#1{%
+ \setlength{\test@lower}{#1 pt}%
+ \addtolength{\test@lower}{-\moodle@fractiontol pt}%
+ \setlength{\test@upper}{#1 pt}%
+ \addtolength{\test@upper}{\moodle@fractiontol pt}%
+ \ifdim\test@upper>\test@fraction\relax
+ \ifdim\test@lower<\test@fraction\relax
+ \gdef\test@fractionmatched{#1}%
+ \fi
+ \fi
+ }
+ \def\moodle@checkfraction{%
+ %\def\test@i{#1}%
+ \setlength{\test@fraction}{\moodle@fraction pt}%
+ % take the absolute value
+ \ifdim0pt>\test@fraction\relax%
+ \setlength{\test@fraction}{-\moodle@fraction pt}%
+ \fi
+ % test if the fraction is an admissible value
+ \let\test@fractionmatched\@empty
+ \forlistloop{\moodle@isfractionnear}{\moodle@validfractionlist}%
+ \ifx\test@fractionmatched\@empty\relax
+ \moodle@fractionerror%
+ \fi
+ \ifdim\moodle@fraction pt<-\moodle@fractiontol pt\relax%
+ \setkeys{moodle}{fraction=-\test@fractionmatched}%
+ \else
+ \setkeys{moodle}{fraction=\test@fractionmatched}%
+ \fi
}
-
-% TODO: What if rounding errors make the percentages not add to 100%? Will Moodle complain?
-% TODO: Verify that negative scores are handled correctly.
% TODO: Put these macros in same order as other sections'.
% SAVING ANSWERS TO MEMORY
\def\savemultianswer#1{%
\bgroup
- \savemultianswer@int#1\moodle@answer@rdelim
+ \savemultianswer@int#1 \moodle@answer@rdelim
\passvalueaftergroup{\moodle@answers@xml}%
\egroup
}%
\newcommand\savemultianswer@int[1][]{%
- \setkeys{moodle}{fraction=0,#1}%
+ \let\moodle@fraction\@empty%
+ \setkeys{moodle}{#1}%
\savemultianswer@int@int%
}%
\def\savemultianswer@int@int#1#2\moodle@answer@rdelim{%
@@ -1771,12 +3195,23 @@
\else
\def\moodle@answertext{#1#2}%
\fi
+ \ifx\moodle@fraction\@empty\relax%
+ \ifmoodle@single\relax
+ \setkeys{moodle}{fraction=0}%
+ \else% multiple
+ \setkeys{moodle}{fraction=\moodle@autosanctions}%
+ \fi
+ \fi
+ \trim@spaces@in\moodle@answertext
\trim@spaces@in\moodle@answertext
+ \moodle@checkfraction
\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>}%
+ \trim@spaces@in\moodle@feedback
+ \xa\converttohtmlmacro\xa\moodle@feedback@html\xa{\moodle@feedback}%
+ \addto@xml[4]{\moodle@answers@xml}{ <feedback format="html"><text><![CDATA[<p>\moodle@feedback@html</p>]]></text></feedback>}%
\fi
\addto@xml[2]{\moodle@answers@xml}{</answer>}%
}%
@@ -1788,50 +3223,351 @@
\moodle@writesingle%
\moodle@writeshuffle%
\moodle@writeanswernumbering%
- \moodle@writeanswers%
- \writetomoodle{</question>}%
}%
% \end{macrocode}
%
-% \subsubsection{Matching Question Front-End}
+% \subsubsection{True/False Question Front-End}
%
% \begin{macrocode}
-\let\answer=\hfill
+% True/False has structure
+% \begin{truefalse}[options]{name}%
+% This is a matching question.
+% \item[feedback={feedback for student answering incorrectly "true"}] % first item is for true
+% \item* this is an other way of specifying answer-specific feedback
+% \end{truefalse}%
+
+%\moodle@makefrontend{truefalse}{}% We dont use the generic frontend because truefalse has no tunable penalty
-\moodle@makefrontend{matching}
+\NewEnviron{truefalse}[2][]{%
+ \bgroup
+ \setkeys{moodle}{#1,questionname={#2}}%
+ \expandafter\gatheritems\xa{\BODY}%
+ \let\moodle@questionheader=\gatheredheader
+ %First, the LaTeX processing
+ \item \textbf{\moodle@questionname}
+ \ifmoodle@handout
+ \moodle@makelatextag@qtype{truefalse}
+ \else
+ \xa\xdef\xa\test@iii\xa{\moodle@tags}%
+ \ifx\test@iii\@moodle@empty\relax\else
+ \hfill tags: \texttt{\moodle@tags}
+ \fi
+ \par
+ \noindent
+ \moodle@makelatextag@qtype{truefalse}
+ \moodle@makelatextag@value{default grade}{\moodle@marks{\csname moodle@default grade\endcsname}}
+ \fi
+ \par
+ \noindent
+ \moodle@questionheader
+ \edef\moodle@generalfeedback{\expandonce\moodle@feedback}
+ \moodle@truefalse@latexprocessing
+ %Now, writing information to XML
+ \@moodle@ifgeneratexml{%
+ \setkeys{moodle}{penalty=1}%
+ \xa\questiontext\xa{\moodle@questionheader}% Save the question text.
+ \csname writetruefalsequestion\endcsname
+ \bgroup
+ \gdef\moodle@answers@xml{}%
+ \setkeys{moodle}{feedback={}}%
+ \xa\loopthroughitemswithcommand\xa{\xa\savetruefalseanswer}%
+ \ifnum\c@numgathereditems=1\relax%
+ \setcounter{currentitemnumber}{2}%
+ \savetruefalseanswer{}
+ \fi
+ \passvalueaftergroup{\moodle@answers@xml}%
+ \egroup
+ \moodle@writeanswers%
+ \moodle@writetags%
+ \writetomoodle{</question>}%
+ }{}%
+ \egroup
+ }%
% LATEX PROCESSING
-\def\moodle@matching@latexprocessing{%
+
+\def\moodle@truefalse@latexprocessing{%
+% \ifnum\c@numgathereditems>2\relax%
+% \PackageError{moodle}{Expecting at max two answers with truefalse type}
+% \fi
+ \setcounter{moodle@numcorrectanswers}{0}%
+ \begin{itemize} \setlength\itemsep{0pt}\setlength\parskip{0pt}%
+ \loopthroughitemswithcommand{\moodle@print@truefalse@answer}%
+ \ifnum\c@currentitemnumber=2%
+ \item \textbf{False}%
+ \fi
+ \end{itemize}
+ \ifmoodle@handout\else
+ \ifx\moodle@generalfeedback\@empty\relax\else%
+ \fbox{\parbox{\linewidth}{\emph{\moodle@generalfeedback}}}%
+ \fi
+ \fi
+ \ifnum\c@moodle@numcorrectanswers=0\relax%
+ \PackageError{moodle}{No answer is explicitly marked as correct (*). Be sure one answer leads to points.}%
+ \fi
+ \ifnum\c@moodle@numcorrectanswers>1\relax%
+ \PackageError{moodle}{Two answers are explicitly marked as correct (*). Be sure only one answer leads to points.}%
+ \fi
+}
+
+ \def\moodle@print@truefalse@answer#1{% here # is all what comes after "\item", that is "[options]* text"
+ \let\moodle@feedback=\@empty
+ \moodle@print@truefalse@answer@int#1\@rdelim % add an end delimiter:
+ }%
+ \newcommand\moodle@print@truefalse@answer@int[1][]{% with the optional argument, catch options and set them as keys
+ \setkeys{moodle}{#1}%
+ \moodle@print@truefalse@answer@int@int% applies to the rest: "* text\@rdelim"
+ }%
+ \def\moodle@print@truefalse@answer@int@int#1\@rdelim{% this is just to treat appart the case where nothing follows
+ \def\test@i{#1}
+ \trim@spaces@in\test@i
+ \ifx\test@i\@empty\relax
+ \moodle@print@truefalse@answer@int@int@empty
+ \else
+ \moodle@print@truefalse@answer@int@int@int#1\@rdelim
+ \fi
+ }%
+ \def\moodle@print@truefalse@answer@int@int@empty{%
+ \ifnum\c@currentitemnumber=1%
+ \def\moodle@answertext{True}%
+ \fi
+ \ifnum\c@currentitemnumber=2%
+ \def\moodle@answertext{False}%
+ \fi
+ \item \textbf{\moodle@answertext}%
+ \ifmoodle@handout\else
+ \ifx\moodle@feedback\@empty\relax\else
+ ~\hfill \emph{$\rightarrow$ \moodle@feedback}%
+ \fi
+ \fi
+ }%
+ \def\moodle@print@truefalse@answer@int@int@int#1#2\@rdelim{%
+ \ifnum\c@currentitemnumber=1%
+ \def\moodle@answertext{True}%
+ \fi
+ \ifnum\c@currentitemnumber=2%
+ \def\moodle@answertext{False}%
+ \fi
+ \item \textbf{\moodle@answertext}%
+ \ifnum\c@currentitemnumber<3%
+ \def\test@i{#1}%
+ %\trim@spaces@in\test@i
+ \ifx\test@i\@star
+ \ifmoodle@handout\else
+ ~$\checkmark$%
+ \fi
+ \stepcounter{moodle@numcorrectanswers}%
+ \else
+ ~%
+ \fi
+ \ifmoodle@handout\else
+ \ifx\moodle@feedback\@empty\relax
+ \def\test@ii{#2}%
+ \trim@spaces@in\test@ii
+ \ifx\test@ii\@empty\relax\else
+ \ifx\test@i\@star%
+ \hfill \emph{$\rightarrow$ #2}%
+ \else%
+ \hfill \emph{$\rightarrow$ #1#2}%
+ \fi
+ \fi
+ \else
+ \hfill \emph{$\rightarrow$ \moodle@feedback}%
+ \fi
+ \fi
+ \fi
+ }%
+
+% SAVING ANSWERS TO MEMORY
+\def\savetruefalseanswer#1{%
\bgroup
- \let\answer=\hfill
- \begin{enumerate}\renewcommand{\theenumi}{\alph{enumi}}\setlength\itemsep{0pt}\setlength\parskip{0pt}%
- \loopthroughitemswithcommand{\moodle@print@matching@answer}%
- \end{enumerate}%
+ \savetruefalseanswer@int#1\moodle@answer@rdelim
+ \passvalueaftergroup{\moodle@answers@xml}%
\egroup
-}
- \long\def\moodle@print@matching@answer#1{%
- \moodle@print@matching@answer@int#1\@rdelim
+}%
+ \newcommand\savetruefalseanswer@int[1][]{%
+ \setkeys{moodle}{#1}%
+ \savetruefalseanswer@int@int%
}%
- \newcommand\moodle@print@matching@answer@int[1][]{%
- \moodle@print@matching@answer@int@int\relax
+ \def\savetruefalseanswer@int@int#1\moodle@answer@rdelim{%
+ \def\test@i{#1}
+ \trim@spaces@in\test@i
+ \ifx\test@i\@empty\relax
+ \savetruefalseanswer@int@int@empty
+ \else
+ \savetruefalseanswer@int@int@int#1\moodle@answer@rdelim
+ \fi
+ }%
+ \def\savetruefalseanswer@int@int@empty{%
+ \setkeys{moodle}{fraction=0}%
+ \ifnum\c@currentitemnumber=1%
+ \def\moodle@answertext{true}%
+ \fi
+ \ifnum\c@currentitemnumber=2%
+ \def\moodle@answertext{false}%
+ \fi
+ \ifnum\c@currentitemnumber<3%
+ \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
+ \trim@spaces@in\moodle@feedback
+ \xa\converttohtmlmacro\xa\moodle@feedback@html\xa{\moodle@feedback}%
+ \addto@xml[4]{\moodle@answers@xml}{ <feedback format="html"><text><![CDATA[<p>\moodle@feedback@html</p>]]></text></feedback>}%
+ \fi
+ \addto@xml[2]{\moodle@answers@xml}{</answer>}%
+ \fi
}%
- \long\def\moodle@print@matching@answer@int@int#1\answer#2\@rdelim{%
- \item #1\hfill #2%
+ \def\savetruefalseanswer@int@int@int#1#2\moodle@answer@rdelim{%
+ \def\test@i{#1}%
+ \ifx\test@i\@star
+ \setkeys{moodle}{fraction=100}%
+ \else
+ \setkeys{moodle}{fraction=0}%
+ \fi
+ \ifnum\c@currentitemnumber=1%
+ \def\moodle@answertext{true}%
+ \fi
+ \ifnum\c@currentitemnumber=2%
+ \def\moodle@answertext{false}%
+ \fi
+ \ifnum\c@currentitemnumber<3%
+ \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
+ \def\test@ii{#2}
+ \ifx\test@ii\@empty\relax\else
+ \ifx\test@i\@star
+ \xa\converttohtmlmacro\xa\moodle@feedback@html\xa{#2}%
+ \else%
+ \xa\converttohtmlmacro\xa\moodle@feedback@html\xa{#1#2}%
+ \fi%
+ \addto@xml[4]{\moodle@answers@xml}{ <feedback format="html"><text><![CDATA[<p>\moodle@feedback@html</p>]]></text></feedback>}%
+ \fi
+ \else
+ \trim@spaces@in\moodle@feedback
+ \xa\converttohtmlmacro\xa\moodle@feedback@html\xa{\moodle@feedback}%
+ \addto@xml[4]{\moodle@answers@xml}{ <feedback format="html"><text><![CDATA[<p>\moodle@feedback@html</p>]]></text></feedback>}%
+ \fi
+ \addto@xml[2]{\moodle@answers@xml}{</answer>}%
+ \fi
}%
+% WRITING QUESTION TO XML FILE
+\gdef\writetruefalsequestion{%
+ \writetomoodle{<question type="truefalse">}%
+ \moodle@writecommondata%
+}%
+% \end{macrocode}
+%
+% \subsubsection{Matching Question Front-End}
+%
+% \begin{macrocode}
+%\let\answer=\hfill
+
+\moodle@makefrontend{matching}{\moodle@makelatextag@matching}%
+
+% LATEX PROCESSING
+
+\def\moodle@makelatextag@matching{%
+ \ifmoodle@handout\else
+ \ifmoodle@draganddrop
+ \moodle@makelatextagbox{Drag and drop}\relax%
+ \fi
+ \ifmoodle@shuffle
+ \moodle@makelatextagbox{Shuffle}\relax%
+ \fi
+ \fi
+}
+
+\def\moodle@matching@latexprocessing{%
+ \bgroup
+ %\let\answer=\hfill
+ \par%\noindent
+ \ifmoodle@handout
+ \NewList{questionlist}
+ \NewList{answerlist}
+ \fi
+ \def\matching@table@text{}%
+ % \ifnum\c@numgathereditems>2\relax%
+% \PackageError{moodle}{Expecting at max two answers with truefalse type}
+% \fi
+ \setcounter{moodle@numcorrectanswers}{0}% Here this counter is for "questions" (items on the left column)
+ \loopthroughitemswithcommand{\moodle@print@matching@answer}%
+ \ifnum\c@numgathereditems<3%
+ \PackageWarning{moodle}{Moodle expects at least three "answers" with matching type}
+ \fi
+ \ifnum\c@moodle@numcorrectanswers<2%
+ \PackageWarning{moodle}{Moodle expects at least two "questions" with the matching type}
+ \fi
+ \ifmoodle@handout
+ \ifmoodle@shuffle
+ \let\moodle@matching@loop=\ForEachRandomItem
+ \else
+ \let\moodle@matching@loop=\ForEachFirstItem
+ \fi
+ \moodle@matching@loop{questionlist}{Question}{
+ \xdef\test@i{\Question}%
+ \ExtractRandomItem{answerlist}{Answer}%
+ \ifx\test@i\@empty
+ \xdef\matching@table@text{\expandonce\matching@table@text & & $\bullet$~\expandonce\Answer\\}%
+ \else
+ \xdef\matching@table@text{\expandonce\matching@table@text\expandonce\Question~$\bullet$ & & $\bullet$~\expandonce\Answer\\}%
+ \fi
+ }%
+ \fi
+ \begin{tabular}{@{}>{\raggedleft}p{.45\linewidth}p{.1\linewidth}p{.45\linewidth}@{}}%
+ \matching@table@text
+ \end{tabular}%
+ \par
+ \ifmoodle@handout\else
+ \ifx\moodle@generalfeedback\@empty\relax\else%
+ \fbox{\parbox{\linewidth}{\emph{\moodle@generalfeedback}}}%
+ \fi
+ \fi
+ \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
+}%
+\long\def\moodle@print@matching@answer@int@int#1\answer#2\@rdelim{%
+ %\typeout{\string#1 \answer \string#2}%
+ \def\test@i{#1}%
+ \trim@spaces@in\test@i
+ \ifmoodle@handout
+ \ifx\test@i\@empty
+ \InsertLastItem{questionlist}{\@empty}%
+ \else
+ \InsertLastItem{questionlist}{#1}%
+ \fi
+ \InsertLastItem{answerlist}{#2}%
+ \else
+ \ifx\test@i\@empty
+ \g@addto@macro\matching@table@text{&&$\bullet$~#2\\}%
+ \else
+ \stepcounter{moodle@numcorrectanswers}%
+ \xa\g@addto@macro\xa\matching@table@text\xa{\test@i~$\bullet$&\leavevmode\cleaders\hb@xt@.44em{\hss$\cdot$\hss}\hfill\kern\z@&$\bullet$~#2\\}%
+ \fi
+ \fi
+}%
+
% SAVING ANSWERS TO MEMORY
\long\def\savematchinganswer#1{%
\bgroup
- \savematchinganswer@int#1\moodle@answer@rdelim%
+ \savematchinganswer@int#1 \moodle@answer@rdelim%
\passvalueaftergroup{\moodle@answers@xml}%
\egroup
}%
\newcommand\savematchinganswer@int[1][]{%
\setkeys{moodle}{#1}%
- \xa\savematchinganswer@int@int\space%
+ \savematchinganswer@int@int%\space
}%
\long\def\savematchinganswer@int@int#1\answer#2\moodle@answer@rdelim{%
+ %\typeout{\string#1 \answer \string#2}%
% Note that #1 may simply be \relax.
\def\moodle@subquestiontext{#1}%
\def\moodle@subanswertext{#2}%
@@ -1854,9 +3590,12 @@
% \show\moodle@subanswertext
\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
+% \ifx\moodle@feedback\@empty\relax\else
+% \trim@spaces@in\moodle@feedback
+% \xa\converttohtmlmacro\xa\moodle@feedback@html\xa{\moodle@feedback}%
+% \addto@xml[4]{\moodle@answers@xml}{ <feedback
+%format="html"><text><![CDATA[<p>\moodle@feedback@html</p>]]></text></feedback>}%
+% \fi
\addto@xml[2]{\moodle@answers@xml}{</subquestion>}%
}%
@@ -1868,12 +3607,9 @@
\writetomoodle{<question type="matching">}%
\fi
\moodle@writecommondata%
- \moodle@writesingle%
+% \moodle@writesingle% %irrelevant for the matching type
\moodle@writeshuffle%
- \moodle@writeanswernumbering%
- \moodle@writeanswers%
- \writetomoodle{</question>}%
-% \gdef\moodle@answ
+% \moodle@writeanswernumbering% %irrelevant for the matching type
}%
% \end{macrocode}
%
@@ -1896,6 +3632,8 @@
% LATEX PROCESSING
% SAVING ANSWERS TO MEMORY
+\newif\ifmoodle@clozemode
+\moodle@clozemodefalse
\NewEnviron{cloze}[2][]{%
\bgroup
\setkeys{moodle}{default grade=1}%
@@ -1903,9 +3641,30 @@
% 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
+ \item \textbf{\moodle@questionname}
+ \ifmoodle@handout
+ \moodle@makelatextag@qtype{cloze}
+ \else
+ \xa\xdef\xa\test@iii\xa{\moodle@tags}%
+ \ifx\test@iii\@moodle@empty\relax\else
+ \hfill tags: \texttt{\moodle@tags}
+ \fi
+ \par
+ \noindent
+ \moodle@makelatextag@qtype{cloze}
+ \moodle@makelatextag@value{default grade}{\moodle@marks{\csname moodle@default grade\endcsname}}
+ \moodle@makelatextag@value{penalty}{penalty}
+ \fi
+ \par
\noindent
\BODY
+ \edef\moodle@generalfeedback{\expandonce\moodle@feedback}
+ %\csname moodle@cloze@latexprocessing\endcsname
+ \ifmoodle@handout\else
+ \ifx\moodle@generalfeedback\@empty\relax\else%
+ \fbox{\parbox{\linewidth}{\emph{\moodle@generalfeedback}}}%
+ \fi
+ \fi
%Now, writing information to memory.
\@moodle@ifgeneratexml{%
\xa\questiontext\xa{\BODY}% Save the question text as HTML.
@@ -1927,6 +3686,7 @@
\gdef\writeclozequestion{%
\writetomoodle{<question type="cloze">}%
\moodle@writecommondata%
+ \moodle@writetags%
\writetomoodle{</question>}%
}%
% \end{macrocode}
@@ -1934,7 +3694,6 @@
% \subsubsection{Cloze Multiple Choice Questions}
%
% \begin{macrocode}
-% TODO: Guard against [single=false] option
\NewEnviron{clozemulti}[1][]{%
\bgroup
@@ -1947,40 +3706,88 @@
\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:}%
+ \edef\clozemulti@coding{\csname moodle@default grade\endcsname:}%
+ \ifmoodle@multiple
+ \PackageWarning{moodle}{Cloze Multiresponse only supported by Moodle 3.5+}
+ \g@addto@macro{\clozemulti@coding}{MULTIRESPONSE}%
+ \else
+ \g@addto@macro{\clozemulti@coding}{MULTICHOICE}%
+ \fi
\ifcase\moodle@multi@mode\relax
- % Case 0: dropdown box style
- \g@addto@macro{\clozemulti@coding}{MULTICHOICE:}%
+ % Case 0: dropdown box style
+ \ifmoodle@shuffle
+ \g@addto@macro{\clozemulti@coding}{_}%
+ \fi
\or
% Case 1: vertical style
- \g@addto@macro{\clozemulti@coding}{MULTICHOICE_V:}%
+ \ifmoodle@multiple
+ \PackageError{moodle}{Vertical mode (dropdown box) incompatible with multiresponse.}
+ \else
+ \g@addto@macro{\clozemulti@coding}{_V}%
+ \fi
\else
% Case 2: horizontal radio buttons
- \g@addto@macro{\clozemulti@coding}{MULTICHOICE_H:}%
+ \g@addto@macro{\clozemulti@coding}{_H}%
+ \fi
+ \ifmoodle@shuffle
+ \PackageWarning{moodle}{Cloze Multi Shuffling only supported by Moodle 3.0+}
+ \g@addto@macro{\clozemulti@coding}{S:}%
+ \else
+ \g@addto@macro{\clozemulti@coding}{:}%
\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\g@addto@macro\xa\clozemulti@coding\xa{\clozerbrace}%
+ \xa\g@addto@macro\xa\moodle@clozemulti@output\xa{\xa\clozelbrace\clozemulti@coding\clozerbrace}%
+ %\show\moodle@clozemulti@output
\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.
+ \par
+ \noindent
+ \moodle@makelatextag@qtype{multi}
+ \ifmoodle@handout\else
+ \moodle@makelatextag@value{default grade}{\moodle@marks{\csname moodle@default grade\endcsname}}
+ \moodle@makelatextag@multi
+ \fi
\def\cloze@multichoice@table@text{}%
+ \ifmoodle@handout\NewList{answerlist}\fi
+ %\let\moodle@feedback=\@empty
\loopthroughitemswithcommand{\moodle@print@clozemultichoice@answer}%
+ \ifmoodle@handout
+ \ifmoodle@shuffle
+ \let\moodle@clozemult@loop=\ForEachRandomItem
+ \else
+ \let\moodle@clozemult@loop=\ForEachFirstItem
+ \fi
+ \moodle@clozemult@loop{answerlist}{Answer}{
+ \xdef\cloze@multichoice@table@text{\expandonce\cloze@multichoice@table@text\expandonce\Answer}%
+ }%
+ \fi
\ifcase\moodle@multi@mode\relax
%Case 0: dropdown box style
- \begin{tabular}[t]{|l|}\firsthline% (\firsthline is from the array package.)
+ \par\noindent
+ \ifmoodle@handout
+ \begin{tabular}[t]{|p{.45\linewidth}|}
+ \else
+ \begin{tabular}[t]{|p{.45\linewidth}|p{.45\linewidth}|}
+% answer & feedback \\\hline\hline
+ \fi
+ \firsthline% (\firsthline is from the array package.)
\cloze@multichoice@table@text%
\end{tabular}%
+ \par%
\or
%Case 1: vertical style
+ \par\noindent
\begin{itemize}\setlength\itemsep{0pt}\setlength\parskip{0pt}%
\cloze@multichoice@table@text%
\end{itemize}%
+ \par%
\else
%Case 2: horizontal radio buttons
\par{\cloze@multichoice@table@text}\par%
@@ -1994,40 +3801,75 @@
\def\moodle@print@clozemultichoice@answer#1{%
- \moodle@print@clozemultichoice@answer@int#1\@rdelim%
+ \let\moodle@feedback=\@empty
+ \moodle@print@clozemultichoice@answer@int#1 \@rdelim%
}%
\newcommand\moodle@print@clozemultichoice@answer@int[1][]{%
+ \setkeys{moodle}{fraction=0,#1}%
\moodle@print@clozemultichoice@answer@int@int%
}%
\def\moodle@print@clozemultichoice@answer@int@int#1#2\@rdelim{%
+ \def\moodle@answertext{}%
% 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
+ \g@addto@macro\moodle@answertext{\item}% Case 1
\else
- \g@addto@macro\cloze@multichoice@table@text{$\bullet~$}% Case 2
+ \g@addto@macro\moodle@answertext{$\bullet~$}% Case 2
\fi
\def\test@i{#1}%
\ifx\test@i\@star
- \g@addto@macro\cloze@multichoice@table@text{#2$~\checkmark$}%
+ \setkeys{moodle}{fraction=100}%
+ \g@addto@macro\moodle@answertext{#2}%
\else
- \g@addto@macro\cloze@multichoice@table@text{#1#2}%
+ \g@addto@macro\moodle@answertext{#1#2}%
+ \fi
+ \trim@spaces@in\moodle@answertext
+ \trim@spaces@in\moodle@answertext
+ \ifmoodle@handout\else
+ \ifx\moodle@fraction\@hundred
+ \g@addto@macro\moodle@answertext{$~\checkmark$}%
+ \else
+ \moodle@checkfraction
+ \ifdim0pt=\moodle@fraction pt\relax\else
+ \xdef\moodle@answertext{\expandonce\moodle@answertext$~(\moodle@fraction\%)$}%
+ \fi
+ \fi
\fi
\ifcase\moodle@multi@mode\relax
- \g@addto@macro{\cloze@multichoice@table@text}{\\ \hline}% Case 0
- \or
- \relax% Case 1
+ % Case 0
+ \ifmoodle@handout\else
+ \xdef\moodle@answertext{\expandonce\moodle@answertext &\expandonce\emph{\expandonce\moodle@feedback}}%
+ \fi
+ \g@addto@macro\moodle@answertext{\\\hline}
+ \or % Case 1
+ \ifmoodle@handout\else
+ \ifx\moodle@feedback\@empty\relax\else
+ \xdef\moodle@answertext{\expandonce\moodle@answertext \hfill \expandonce\emph{$\rightarrow$ \expandonce\moodle@feedback}}%
+ \fi
+ \fi
+ \else % otherwise
+ \ifmoodle@handout\else
+ \ifx\moodle@feedback\@empty\relax\else
+ \xdef\moodle@answertext{\expandonce\moodle@answertext\,\expandonce\emph{$\rightarrow$ \expandonce\moodle@feedback}}%
+ \fi
+ \fi
+ \g@addto@macro\moodle@answertext{\hfill}% Case 2
+ \fi
+ \ifmoodle@handout
+ \def\temp{\InsertLastItem{answerlist}}%
+ \xa\temp\xa{\moodle@answertext}%
\else
- \g@addto@macro{\cloze@multichoice@table@text}{\hfill}% Case 2
+ \xdef\cloze@multichoice@table@text{\expandonce\cloze@multichoice@table@text\expandonce\moodle@answertext}%
\fi
}%
\def\saveclozemultichoiceanswer#1{%
\bgroup
- \saveclozemultichoiceanswer@int#1\moodle@answer@rdelim
+ \saveclozemultichoiceanswer@int#1 \moodle@answer@rdelim
\egroup
}%
\newcommand\saveclozemultichoiceanswer@int[1][]{%
@@ -2046,17 +3888,18 @@
\def\moodle@answertext{#1#2}%
\fi
\trim@spaces@in\moodle@answertext
+ \trim@spaces@in\moodle@answertext
\ifx\moodle@fraction\@hundred
\g@addto@macro\clozemulti@coding{=}%
- \fi
- \ifnum0<\moodle@fraction\relax
- \ifnum\moodle@fraction<100\relax
+ \else
+ \moodle@checkfraction
+ \ifdim0pt=\moodle@fraction pt\relax\else
\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}%
+ \xdef\clozemulti@coding{\expandonce\clozemulti@coding\otherbackslash\otherhash\expandonce\moodle@feedback}%
\fi
}%
% \end{macrocode}
@@ -2075,23 +3918,35 @@
\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:}%
+ \edef\clozenumerical@coding{\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\g@addto@macro\xa\clozenumerical@coding\xa{\otherrbrace}%
+ \xa\g@addto@macro\xa\moodle@clozenumerical@output\xa{\xa\clozelbrace\clozenumerical@coding\clozerbrace}%
\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}%
+ \par
+ \noindent
+ \moodle@makelatextag@qtype{numerical}
+ \ifmoodle@handout\else
+ \moodle@makelatextag@value{default grade}{\moodle@marks{\csname moodle@default grade\endcsname}}
+ \moodle@makelatextag@numerical
+ \par
+ \noindent
+ \def\cloze@numerical@table@text{}%
+ \loopthroughitemswithcommand{\moodle@print@clozenumerical@answer}%
+ \begin{tabular}[t]{|p{.45\linewidth}|p{.45\linewidth}|}
+ \firsthline% (\firsthline is from the array package.)
+% answer & feedback \\\hline\hline
+ \cloze@numerical@table@text%
+ \end{tabular}%
+ \par%
+ \fi
\def\endclozenumerical@code{\relax}%
\fi
\passvalueaftergroup\endclozenumerical@code%
@@ -2100,6 +3955,7 @@
}[\endclozenumerical@code]%
\def\moodle@print@clozenumerical@answer#1{%
+ \let\moodle@feedback=\@empty
\bgroup
\moodle@print@clozenumerical@answer@int#1\@rdelim
\egroup
@@ -2110,17 +3966,23 @@
}%
\def\moodle@print@clozenumerical@answer@int@int#1\@rdelim{%
\ifx\moodle@fraction\@hundred
- \def\moodle@clozenumericalprint@fraction{$\checkmark$}%
+ \def\moodle@clozenumericalprint@fraction{$~\checkmark$}%
\else
- \edef\moodle@clozenumericalprint@fraction{(\moodle@fraction\%)}%
+ \moodle@checkfraction
+ \edef\moodle@clozenumericalprint@fraction{$(~\moodle@fraction\%)$}%
\fi
- \ifdim0pt=\moodle@tolerance pt\relax
+ \ifnum\z@=\moodle@tolerance
\def\moodle@clozenumericalprint@tolerance{}%
\else
- \edef\moodle@clozenumericalprint@tolerance{\noexpand\pm\moodle@tolerance}%
+ \edef\moodle@clozenumericalprint@tolerance{$\,\pm\,$\moodle@printnum{\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 \\}%
+ \xdef\test@i{\trim@spaces{#1}}%
+ \ifx\test@i\@star
+ \xdef\moodle@clozenumericalprint@line{#1~\moodle@clozenumericalprint@fraction & \expandonce\emph{\expandonce\moodle@feedback}}%
+ \else
+ \xdef\moodle@clozenumericalprint@line{\moodle@printnum{#1}\moodle@clozenumericalprint@tolerance~\moodle@clozenumericalprint@fraction & \expandonce\emph{\expandonce\moodle@feedback}}%
+ \fi
+ \xa\g@addto@macro\xa\cloze@numerical@table@text\xa{\moodle@clozenumericalprint@line \\\hline}%
}%
@@ -2142,15 +4004,20 @@
\trim@spaces@in\moodle@answertext
\ifx\moodle@fraction\@hundred
\g@addto@macro\clozenumerical@coding{=}%
- \fi
- \ifnum0<\moodle@fraction\relax
- \ifnum\moodle@fraction<100\relax
+ \else
+ \moodle@checkfraction
+ \ifdim0pt=\moodle@fraction pt\relax\else
\xdef\clozenumerical@coding{\expandonce\clozenumerical@coding\otherpercent\moodle@fraction\otherpercent}%
\fi
\fi
- \xdef\clozenumerical@coding{\expandonce\clozenumerical@coding\moodle@answertext:\moodle@tolerance}%
+ \ifx\moodle@answertext\@star
+ \xdef\clozenumerical@coding{\expandonce\clozenumerical@coding\moodle@answertext}%
+ \else
+ \xdef\clozenumerical@coding{\expandonce\clozenumerical@coding\moodle@answertext:\moodle@tolerance}%
+ \fi
\ifx\moodle@feedback\@empty\else
- \xdef\clozenumerical@coding{\expandonce\clozenumerical@coding\otherbackslash\otherhash\moodle@feedback}%
+ %\trim@spaces@in\moodle@feedback
+ \xdef\clozenumerical@coding{\expandonce\clozenumerical@coding\otherbackslash\otherhash\expandonce\moodle@feedback}%
\fi
}%
% \end{macrocode}
@@ -2177,29 +4044,38 @@
\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:}%
+ \edef\clozeshortanswer@coding{\csname moodle@default grade\endcsname:SHORTANSWER_C:}%
\else
- \edef\clozeshortanswer@coding{\otherlbrace\csname moodle@default grade\endcsname:SHORTANSWER:}%
+ \edef\clozeshortanswer@coding{\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\g@addto@macro\xa\clozeshortanswer@coding\xa{\otherrbrace}%
+ \xa\g@addto@macro\xa\moodle@clozeshortanswer@output\xa{\xa\clozelbrace\clozeshortanswer@coding\clozerbrace}%
\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)}}%
+ \par
+ \noindent
+ \moodle@makelatextag@qtype{shortanswer}
+ \ifmoodle@handout\else
+ \moodle@makelatextag@value{default grade}{\moodle@marks{\csname moodle@default grade\endcsname}}
+ \moodle@makelatextag@shortanswer
+ \par
+ \noindent
+ \def\cloze@shortanswer@table@text{}%
+ \loopthroughitemswithcommand{\moodle@print@clozeshortanswer@answer}%
+ \begin{tabular}[t]{|p{.45\linewidth}|p{.45\linewidth}|}
+ \firsthline% (\firsthline is from the array package.)
+% answer & feedback \\\hline\hline
+ \cloze@shortanswer@table@text%
+ \end{tabular}%
+ \par%
\fi
- \begin{tabular}[t]{|ll|}\firsthline
- \cloze@shortanswer@table@text\hline%
- \end{tabular}%
\def\endclozeshortanswer@code{\relax}%
\fi
\passvalueaftergroup\endclozeshortanswer@code%
@@ -2208,6 +4084,7 @@
}[\endclozeshortanswer@code]%
\def\moodle@print@clozeshortanswer@answer#1{%
+ \let\moodle@feedback=\@empty
\bgroup
\moodle@print@clozeshortanswer@answer@int#1\@rdelim
\egroup
@@ -2218,12 +4095,13 @@
}%
\def\moodle@print@clozeshortanswer@answer@int@int#1\@rdelim{%
\ifx\moodle@fraction\@hundred
- \def\moodle@clozeshortanswerprint@fraction{$\checkmark$}%
+ \def\moodle@clozeshortanswerprint@fraction{$~\checkmark$}%
\else
- \edef\moodle@clozeshortanswerprint@fraction{(\moodle@fraction\%)}%
+ \moodle@checkfraction
+ \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 \\}%
+ \xdef\moodle@clozeshortanswerprint@line{#1~\moodle@clozeshortanswerprint@fraction & \expandonce\emph{\expandonce\moodle@feedback}}%
+ \xa\g@addto@macro\xa\cloze@shortanswer@table@text\xa{\moodle@clozeshortanswerprint@line \\\hline}%
}%
@@ -2245,15 +4123,15 @@
\trim@spaces@in\moodle@answertext
\ifx\moodle@fraction\@hundred
\g@addto@macro\clozeshortanswer@coding{=}%
- \fi
- \ifnum0<\moodle@fraction\relax
- \ifnum\moodle@fraction<100\relax
+ \else
+ \moodle@checkfraction
+ \ifdim0pt=\moodle@fraction pt\relax\else
\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}%
+ \xdef\clozeshortanswer@coding{\expandonce\clozeshortanswer@coding\otherbackslash\otherhash\expandonce\moodle@feedback}%
\fi
}%
% \end{macrocode}
@@ -2270,15 +4148,20 @@
\catcode`\&=12\gdef\otherampersand{&}%
\catcode`\^=12\gdef\othercaret{^}%
\catcode`\$=12\gdef\otherdollar{$}%
- \catcode`\%=12\gdef\otherpercent{%}}%
+ \catcode`\%=12\gdef\otherpercent{%}
+ \catcode`\%=12\gdef\otherlbracket{[}
+ \catcode`\%=12\gdef\otherrbracket{]}}%
{\catcode`\ =12\gdef\otherspace{ }}%
-{\tt\catcode`\|=0\catcode`\\=12\relax|gdef|otherbackslash{\}}%
+{\ttfamily\catcode`\|=0\catcode`\\=12\relax|gdef|otherbackslash{\}}%
{\catcode`\[=1\catcode`\]=2\catcode`\{=12\catcode`\}=12%
- \gdef\otherlbrace[{]\gdef\otherrbrace[}]]
-
+ \gdef\otherlbrace[{]\gdef\otherrbrace[}]\gdef\clozelbrace[{]\gdef\clozerbrace[}]]%
\edef\@otherlbrace{\otherlbrace}%
\edef\@otherrbrace{\otherrbrace}%
+\edef\@otherlbracket{\otherlbracket}%
+\edef\@otherrbracket{\otherrbracket}%
+\edef\@clozelbrace{\clozelbrace}%
+\edef\@clozerbrace{\clozerbrace}%
\edef\@otherdollar{\otherdollar}%
\edef\@otherbackslash{\otherbackslash}%
\edef\@othertilde{\othertilde}%
@@ -2381,9 +4264,16 @@
% \end{macrocode}
%
% \subsection{Level-Tracking}
+%
+% \subsubsection{TeX groups}
+% While parsing, we'll need to keep track of how deeply nested in \TeX\ groups we are.
+% \begin{macrocode}
+\newcount\grouplevel
+% \end{macrocode}
+%
+% \subsubsection{Math mode}
% While parsing, we'll need to keep track of whether
-% we are in math mode (and how many levels deep the math mode might be nested),
-% and also how deeply nested in \TeX\ groups we are.
+% we are in math mode (and how many levels deep the math mode might be nested).
% \begin{macrocode}
\newcount\moodle@mathmodedepth
\moodle@mathmodedepth=0\relax
@@ -2393,12 +4283,15 @@
\else
#2%
\fi
-}
-
-\newcount\grouplevel
+}%
+% \end{macrocode}
+%
+% \subsubsection{Nested Lists}
+% While parsing, we'll need to keep track levels of nested list.
+% \begin{macrocode}
+\newcount\moodle@listdepth
+\moodle@listdepth=0\relax
-\newif\ifhtmlizer@active
-\htmlizer@activefalse
% \end{macrocode}
%
% \subsection{Separation}
@@ -2436,6 +4329,8 @@
% \subsection{Main Code: the HTMLizer}
%
% \begin{macrocode}
+\newif\ifhtmlizer@active
+\htmlizer@activefalse
\newif\ifhtmlize@actioncs
\newif\ifhtmlize@expandcs
\newif\ifhtmlize@passcs
@@ -2456,7 +4351,7 @@
\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
+ \xa\htmlize@recursive@i\htmlize@texttoscan\@htmlize@stop\@htmlize@stop\@htmlize@stop\htmlize@rdelim@i%
\egroup
\advance\grouplevel by -1\relax
}%
@@ -2502,7 +4397,13 @@
\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}}%
+ \ifmoodle@clozemode
+ \xa\g@addto@macro\xa\htmlize@scrap\xa{\xa{\otherbackslash\otherrbrace}}%
+% \moodle@ifmathmode{\xa\g@addto@macro\xa\htmlize@scrap\xa{\xa{\otherbackslash}}}%
+% {}%
+ \else
+ \xa\g@addto@macro\xa\htmlize@scrap\xa{\xa{\otherrbrace}}%
+ \fi
\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.
@@ -2519,10 +4420,10 @@
\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
+ % We grab everything between $...$, sanitize it, and add it verbatim to
% our output.
\htmlize@inlinemathshift@replace#1#2#3\htmlize@rdelim@iii%
- \fi
+ \fi% \ifx\test@ii\@otherdollar
% 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,
@@ -2647,9 +4548,9 @@
%\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
+ \fi% \ifhtmlize@expandcs
+ \fi% \ifhtmlize@actioncs
+ \fi% \ifx\@htmlize@cs\@@begin@cs
\else%
\ifx\test@i\@othertilde%
% The ~ becomes non-breaking space &nbsp;
@@ -2664,7 +4565,7 @@
\else
\g@addto@macro\htmlize@output{\otherampersand lsquo;}%
\def\htmlize@next@i{\htmlize@recursive@i#2#3\htmlize@rdelim@i}%
- \fi
+ \fi% \ifx\test@ii\@lsinglequote%
\else
\ifx\test@i\@rsinglequote%
\ifx\test@ii\@rsinglequote%
@@ -2674,7 +4575,7 @@
\else
\g@addto@macro\htmlize@output{\otherampersand rsquo;}%
\def\htmlize@next@i{\htmlize@recursive@i#2#3\htmlize@rdelim@i}%
- \fi
+ \fi% \ifx\test@ii\@rsinglequote%
\else
\ifx\test@i\@doublequote
\g@addto@macro\htmlize@output{\otherampersand rdquo;}%
@@ -2689,20 +4590,20 @@
\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
+ \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
+ \fi% \ifx\test@i\@gt
+ \fi% \ifx\test@i\@lt
+ \fi% \ifx\test@i\@doublequote
+ \fi% \ifx\test@i\@rsinglequote%
+ \fi% \ifx\test@i\@lsinglequote%
+ \fi% \ifx\test@i\@othertilde%
+ \fi% \ifx\test@i\@otherbackslash%
+ \fi% \ifx\test@i\@otherdollar%
+ \fi% \ifx\test@i\@otherlbrace%
+ \fi% \ifx\test@i\@@htmlize@stop
\htmlize@next@i
}%
@@ -2721,16 +4622,38 @@
\edef\inlinemathleftdelim{\otherbackslash(}%
\def\inlinemathrightdelim#1{\advancemathmodecounter{-1}%
\g@addto@macro\htmlize@output{\otherbackslash)}}%
-\edef\displaymathleftdelim{<CENTER>\otherbackslash[}%
+\edef\displaymathleftdelim{\otherbackslash[}%
\def\displaymathrightdelim#1{\advancemathmodecounter{-1}%
- \g@addto@macro\htmlize@output{\otherbackslash]</CENTER>}}%
+ \g@addto@macro\htmlize@output{\otherbackslash]}}%
+\long\def\htmlize@inlinemath@recursive@i#1#2#3\htmlize@rdelim@i{%
+ % inspired by \htmlize@recursive@i
+ \def\test@i{#1}%
+ \ifx\test@i\@@htmlize@stop
+ \let\htmlize@next@i=\relax
+ \else
+ \ifx\test@i\@otherbackslash
+ \g@addto@macro\mathtext{#1#2}%
+ \def\htmlize@next@i{\xa\htmlize@inlinemath@recursive@i#3\htmlize@rdelim@i}%
+ \else
+ \ifx\test@i\@otherdollar
+ \let\htmlize@next@i=\relax
+ \g@addto@macro\aftertext{#2#3}%
+ \else
+ \g@addto@macro\mathtext{#1}%
+ \def\htmlize@next@i{\xa\htmlize@inlinemath@recursive@i#2#3\htmlize@rdelim@i}%
+ \fi
+ \fi
+ \fi
+ \htmlize@next@i
+}
{\catcode`\$=12\relax%
- \gdef\htmlize@inlinemathshift@replace$#1$#2\htmlize@rdelim@iii{%
+ \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}%
+ \gdef\mathtext{}%
+ \gdef\aftertext{}%
+ \htmlize@inlinemath@recursive@i#2\htmlize@rdelim@i%
\xdef\htmlize@remaining@text{\expandonce\mathtext%
\otherbackslash inlinemathrightdelim{}%
\expandonce\aftertext}%
@@ -2746,6 +4669,7 @@
\expandonce\aftertext}%
}%
}
+
% \end{macrocode}
%
% \subsection{Engines for Control Sequences}
@@ -2847,6 +4771,25 @@
\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\html@action@newcommand#1[#2][#3]#4{%
+ %\message{>>> Defining #1[#2][#3]{...} ^^J}
+ \ifmoodle@draftmode
+ \else
+ \xa\html@action@def\csname #1\endcsname{\csname moodle@#1@int\endcsname}%
+ \fi
+ % 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.
+ \xa\csdef{moodle@#1@int}##1##2##3{\csname moodle@#1@int@int\endcsname}%
+ % This gobbles up those three spurious tokens,
+ % which we will re-insert after our work is done.
+ \xa\newcommand\csname moodle@#1@int@int\endcsname[#2][#3]{%
+ #4%
+ % Now we re-insert the code to get the HTMLizing going again.
+ \xa\htmlize@proceedwiththerest\htmlize@afteraction@hook
+ }%
+}
% \end{macrocode}
%
% \subsubsection{Engine for expansion control sequences}
@@ -2868,6 +4811,24 @@
}
\let\htmlregister=\htmlize@record@expand
% \end{macrocode}
+% Often users define a list of macros at the end of the preamble.
+% It can be cumbersome to record individually these macros for expansion.
+% By calling |\moodleregisternewcommands| they trigger the automatic
+% expansion of macros defined subsequently using |\newcommand|,
+% |\renewcommand|, |\providecommand| or their starred variants.
+% \begin{macrocode}
+\def\moodleregisternewcommands{%
+ %% INSPIRED FROM
+ %https://tex.stackexchange.com/questions/73271/how-to-redefine-or-patch-the-newcommand-command
+ \newcommand*{\saved@ifdefinable}{}
+ \let\saved@ifdefinable\@ifdefinable
+ \renewcommand{\@ifdefinable}[2]{%
+ \saved@ifdefinable{##1}{##2}%
+ \htmlregister{##1}
+ }%
+ \let\@@ifdefinable\@ifdefinable
+}%
+% \end{macrocode}
% On the other hand, if an alternate version of the macro is
% needed for HTML purposes, you can define its HTML version with
% |\html@def\mymacro...|
@@ -2901,20 +4862,50 @@
\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@save@getitems@state{%
+ \global\xa\xdef\csname moodle@currentitemnumber@level@\the\moodle@listdepth\xa\endcsname\xa{\thecurrentitemnumber}%
+ \global\xa\xdef\csname moodle@numgathereditems@level@\the\moodle@listdepth\xa\endcsname\xa{\thenumgathereditems}%
+ \moodle@saveitems{\thenumgathereditems}%
+}%
+\def\moodle@restore@getitems@state{%
+ \setcounter{numgathereditems}{\csname moodle@numgathereditems@level@\the\moodle@listdepth\endcsname}%
+ \setcounter{currentitemnumber}{\csname moodle@currentitemnumber@level@\the\moodle@listdepth\endcsname}%
+ \moodle@restoreitems{\thenumgathereditems}%
+}%
+\def\moodle@saveitems#1{%
+ \ifnum#1>0%
+ \global\csletcs{moodle@level@\the\moodle@listdepth @item@#1}{getitems@item@#1}%
+ \xa\moodle@saveitems\xa{\number\numexpr#1-1\expandafter}%
+ \fi
+}%
+\def\moodle@restoreitems#1{%
+ \ifnum#1>0%
+ \global\csletcs{getitems@item@#1}{moodle@level@\the\moodle@listdepth @item@#1}%
+ \global\xa\let\csname moodle@level@\the\moodle@listdepth @item@#1\endcsname=\@undefined
+ \xa\moodle@restoreitems\xa{\number\numexpr#1-1\expandafter}%
+ \fi
+}%
+\def\moodle@makelistenv#1#2{%
+ \html@newenvironment{#1}{%
+ \advance\moodle@listdepth by 1\relax
+ \moodle@save@getitems@state%
+ \xa\gatheritems\xa{\BODY}%
+ \gdef\htmlize@afteraction@hook{<#2>}%
+ \loopthroughitemswithcommand{\moodle@itemtoLI}%
+ \g@addto@macro\htmlize@afteraction@hook{</#2>}%
+ \moodle@restore@getitems@state%
+ \advance\moodle@listdepth by -1\relax
+ }%
}%
+
+\moodle@makelistenv{enumerate}{OL}%
+\moodle@makelistenv{itemize}{UL}%
+
\def\moodle@itemtoLI#1{%
- \g@addto@macro\htmlize@afteraction@hook{<LI>#1</LI>}%
+ \g@addto@macro\htmlize@afteraction@hook{<LI>#1}%
+ \trim@spaces@in\htmlize@afteraction@hook%
+ \g@addto@macro\htmlize@afteraction@hook{</LI>}%
}%
% \end{macrocode}
@@ -2925,11 +4916,15 @@
\def\advancemathmodecounter#1{%
\global\advance\moodle@mathmodedepth by #1\relax
}
+\def\openclozemode{%
+ \global\moodle@clozemodetrue\relax
+}
+\def\endclozemode{%
+ \global\moodle@clozemodefalse\relax
+}
\htmlize@record@action{\advancemathmodecounter}%
-
-
-
-
+\htmlize@record@action{\openclozemode}%
+\htmlize@record@action{\endclozemode}%
\htmlize@record@action{\relax}%
\html@action@def\#{\g@addto@macro\htmlize@output{\otherhash}}%
@@ -2942,15 +4937,32 @@
}%
\html@action@def\}{%
\moodle@ifmathmode{\g@addto@macro\htmlize@output{\otherbackslash\otherrbrace}}%
- {\g@addto@macro\htmlize@output{\otherrbrace}}%
+ {\ifmoodle@clozemode\g@addto@macro\htmlize@output{\otherbackslash}\fi
+ \g@addto@macro\htmlize@output{\otherrbrace}}%
+ }%
+\html@action@def\[{%
+ \advancemathmodecounter{1}
+ \g@addto@macro\htmlize@output{\otherbackslash\otherlbracket}%
+ }%
+\html@action@def\]{%
+ \g@addto@macro\htmlize@output{\otherbackslash\otherrbracket}%
+ \advancemathmodecounter{-1}
+ }%
+\html@action@def\({%
+ \advancemathmodecounter{1}
+ \g@addto@macro\htmlize@output{\otherbackslash(}%
+ }%
+\html@action@def\){%
+ \g@addto@macro\htmlize@output{\otherbackslash)}%
+ \advancemathmodecounter{-1}
}%
\html@action@def\ldots{%
\moodle@ifmathmode{\g@addto@macro\htmlize@output{\string\ldots}}%
- {\g@addto@macro\htmlize@output{...}}%
+ {\g@addto@macro\htmlize@output{\otherampersand hellip\othersemicol}}%
}%
\html@action@def\dots{%
\moodle@ifmathmode{\g@addto@macro\htmlize@output{\string\dots}}%
- {\g@addto@macro\htmlize@output{...}}%
+ {\g@addto@macro\htmlize@output{\otherampersand hellip\othersemicol}}%
}%
\html@action@def\ {%
\moodle@ifmathmode{\g@addto@macro\htmlize@output{\otherbackslash\otherspace}}%
@@ -2959,12 +4971,25 @@
\html@action@def\${%
\g@addto@macro\htmlize@output{\otherdollar}%
}%
-
\html@action@def\clozetilde{%
\xa\g@addto@macro\xa\htmlize@output\xa{\othertilde}%
}%
+\html@action@def\clozelbrace{%
+ \openclozemode
+ \xa\g@addto@macro\xa\htmlize@output\xa{\otherlbrace}%
+ }%
+\html@action@def\clozerbrace{%
+ \xa\g@addto@macro\xa\htmlize@output\xa{\otherrbrace}%
+ \endclozemode
+ }%
+\html@action@def\TeX{%
+ \g@addto@macro\htmlize@output{\otherbackslash(\otherbackslash rm\otherbackslash TeX\otherbackslash)}
+ }%
+\html@action@def\LaTeX{%
+ \g@addto@macro\htmlize@output{\otherbackslash(\otherbackslash rm\otherbackslash LaTeX\otherbackslash)}
+ }%
-
+{\catcode`;=12\relax\gdef\othersemicol{;}}
%Diacritical marks over vowels
{\catcode`|=3\relax
@@ -2974,32 +4999,40 @@
\g@addto@macro\htmlize@activate@css{%
\def#1##1{%
\ifinlist{##1}{\htmlize@vowels}%
- {\g@addto@macro\htmlize@output{\otherampersand##1#2;}}%
+ {\g@addto@macro\htmlize@output{\otherampersand##1#2\othersemicol}}%
{\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}%
+%Diaeresis/Tréma/Umlaut
+{\catcode`|=3\relax
+ \gdef\htmlize@diaeresis{a|e|i|o|u|y|A|E|I|O|U|Y|}}
+\html@action@def\"#1{%
+ \ifinlist{#1}{\htmlize@diaeresis}%
+ {\g@addto@macro\htmlize@output{\otherampersand#1uml\othersemicol}}%
+ {\xa\g@addto@macro\htmlize@output\xa{\string\"#1}}%
+}%
+
%Hungarian long-umlaut diacritics
\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;}%
+ \def\toadd{\otherampersand\otherhash336\othersemicol}%
\else
\ifx\test@i\@o
- \def\toadd{\otherampersand\otherhash337;}%
+ \def\toadd{\otherampersand\otherhash337\othersemicol}%
\else
- \ifx\test@i\U
- \def\toadd{\otherampersand\otherhash368;}%
+ \ifx\test@i\@U
+ \def\toadd{\otherampersand\otherhash368\othersemicol}%
\else
- \ifx\test@i\u
- \def\toadd{\otherampersand\otherhash369;}%
+ \ifx\test@i\@u
+ \def\toadd{\otherampersand\otherhash369\othersemicol}%
\else
\def\toadd{\otherbackslash\otherlbrace#1\otherrbrace}%
\fi
@@ -3010,50 +5043,275 @@
\egroup
}%
+%Cedilla
+\def\@c{c}\def\@C{C}\def\@s{s}\def\@S{S}\def\@t{t}\def\@T{T}%
+\html@action@def\c#1{%
+ \bgroup
+ \def\test@i{#1}%
+ \ifx\test@i\@c
+ \def\toadd{\otherampersand ccedil\othersemicol}%
+ \else
+ \ifx\test@i\@C
+ \def\toadd{\otherampersand Ccedil\othersemicol}%
+ \else
+ \ifx\test@i\@s
+ \def\toadd{\otherampersand\otherhash351\othersemicol}%
+ \else
+ \ifx\test@i\@S
+ \def\toadd{\otherampersand\otherhash350\othersemicol}%
+ \else
+ \ifx\test@i\@t
+ \def\toadd{\otherampersand\otherhash355\othersemicol}%
+ \else
+ \ifx\test@i\@T
+ \def\toadd{\otherampersand\otherhash354\othersemicol}%
+ \else
+ \def\toadd{\otherbackslash\otherlbrace#1\otherrbrace}%
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \xa\g@addto@macro\xa\htmlize@output\xa{\toadd}%
+ \egroup
+}%
%Tilde over a, n, o
{\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;}}%
+ {\g@addto@macro\htmlize@output{\otherampersand#1tilde\othersemicol}}%
{\xa\g@addto@macro\htmlize@output\xa{\string\~#1}}%
- }%
+}%
+
+% breve diacritics
+{\catcode`|=3\relax
+ \gdef\htmlize@breve{A|G|U|a|g|u|}}
+\def\@e{e}\def\@E{E}\def\@i{i}\def\@ii{\i}\def\@I{I}\def\@o{o}\def\@O{O}%
+\html@action@def\u#1{%
+ \ifinlist{#1}{\htmlize@breve}%
+ {\g@addto@macro\htmlize@output{\otherampersand#1breve\othersemicol}}%
+ {
+ \bgroup
+ \def\test@i{#1}%
+ \ifx\test@i\@E
+ \def\toadd{\otherampersand\otherhash276\othersemicol}%
+ \else
+ \ifx\test@i\@e
+ \def\toadd{\otherampersand\otherhash277\othersemicol}%
+ \else
+ \ifx\test@i\@I
+ \def\toadd{\otherampersand\otherhash300\othersemicol}%
+ \else
+ \ifx\test@i\@i
+ \def\toadd{\otherampersand\otherhash301\othersemicol}%
+ \else
+ \ifx\test@i\@ii
+ \def\toadd{\otherampersand\otherhash301\othersemicol}%
+ \else
+ \ifx\test@i\@O
+ \def\toadd{\otherampersand\otherhash334\othersemicol}%
+ \else
+ \ifx\test@i\@o
+ \def\toadd{\otherampersand\otherhash335\othersemicol}%
+ \else
+ \def\toadd{\otherbackslash\otherlbrace#1\otherrbrace}%
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \xa\g@addto@macro\xa\htmlize@output\xa{\toadd}%
+ \egroup
+ }%
+}%
+
+% caron diacritics
+{\catcode`|=3\relax
+ \gdef\htmlize@caron{C|D|E|L|N|R|S|T|Z|c|d|e|l|n|r|s|t|z|}}
+\html@action@def\v#1{%
+ \ifinlist{#1}{\htmlize@caron}%
+ {\g@addto@macro\htmlize@output{\otherampersand#1caron\othersemicol}}%
+ {\xa\g@addto@macro\htmlize@output\xa{\string\v#1}}%
+}%
% \end{macrocode}
%
% \subsubsection{Command sequences for Expansion}
%
% \begin{macrocode}
-\html@def\underline#1{<SPAN STYLE="text-decoration: underline;">#1</SPAN>}
+\html@def\underline#1{<SPAN STYLE=\&\#34;text-decoration: underline;\&\#34;>#1</SPAN>}
\html@def\emph#1{<EM>#1</EM>}%
+\html@def\textit#1{<I>#1</I>}%
\html@def\textbf#1{<B>#1</B>}%
+\html@def\texttt#1{<CODE>#1</CODE>}%
+\html@def\textsc#1{<SPAN STYLE=\&\#34;font-variant: small-caps;\&\#34;>#1</SPAN>}
+\html@def\url#1{<A href=\&\#34;#1\&\#34;>#1</A>}%
+\html@def\href#1#2{<A href=\&\#34;#1\&\#34;>#2</A>}%
+\html@def\textsuperscript#1{<SUP>#1</SUP>}%
+\html@def\up#1{<SUP>#1</SUP>}%
+\html@def\fup#1{<SUP>#1</SUP>}%
+\html@def\textsubscript#1{<SUB>#1</SUB>}%
\html@def\blank{____________}%
\html@def\par{</P><P>}%
\html@def\aa{\&aring;}%
\html@def\AA{\&Aring;}%
\html@def\ae{\&aelig;}%
\html@def\AE{\&AElig;}%
+\html@def\oe{\&oelig;}%
+\html@def\OE{\&OElig;}%
\html@def\S{\&sect;}%
\html@def\euro{\&euro;}%
\html@def\texteuro{\&euro;}%
\html@def\o{\&oslash;}%
\html@def\O{\&Oslash;}%
\html@def\ss{\&szlig;}%
+\html@def\SS{\&\#7838;}%
\html@def\l{\&lstrok;}%
\html@def\L{\&Lstrok;}%
+\html@def\og{\&laquo;\&\#8239;}%
+\html@def\guillemotleft{\&laquo;\&\#8239;}%
+\html@def\fg{\&\#8239;\&raquo;}%
+\html@def\guillemotright{\&\#8239;\&raquo;}%
+\html@def\,{\&\#8239;}%
+\html@def\thinspace{\&\#8239;}%
+\html@def\textbackslash{\&\#92;}%
+\html@def\_{\&\#95;}%
+\html@def\textquestiondown{\&iquest;}%
+\html@def\textexclamdown{\&iexcl;}%
% AH CUSTOM MACROS TO EXPAND --- remove these before publishing!
-\htmlize@record@expand{\inv}%
-\htmlize@record@expand{\rec}%
+%\htmlize@record@expand{\inv}%
+%\htmlize@record@expand{\rec}%
\htmlize@record@action\inlinemathrightdelim
\htmlize@record@action\displaymathrightdelim
-
% \end{macrocode}
%
-% \subsection{Graphics via {\tt\string\includegraphics}}
+% \subsection{Graphics via {\ttfamily\string\includegraphics}}
%
+% \subsubsection{Finding Media Files}
+% The following code is adapted from the command |\Ginclude@graphics| as
+% found in |graphics.sty|.
+% Calling |\moodle@media@find|\marg{filename} looks for the file the
+% same way |\includegraphics| does, with or without extension provided,
+% in the current folder and in folders specified with |\graphicspath{}|.
+% The allowed extensions and their relative priorities can be set
+% via |\DeclareGraphicsExtensions{}|.
+% The outcome is that the macros |\moodle@media@base| and |\moodle@media@ext|
+% are set with the basename, including path, and extension, respectively.
+%
+% \begin{macrocode}
+\def\moodle@media@find#1{%
+ \ifx\detokenize\@undefined\else
+ \edef\Gin@extensions{\detokenize\expandafter{\Gin@extensions}}%
+ \fi
+ \begingroup
+ \let\input@path\Ginput@path
+ \set@curr@file{#1}%
+ \expandafter\filename@parse\expandafter{\@curr@file}%
+ \ifx\filename@ext\Gin@gzext
+ \expandafter\filename@parse\expandafter{\filename@base}%
+ \ifx\filename@ext\relax
+ \let\filename@ext\Gin@gzext
+ \else
+ \edef\Gin@ext{\Gin@ext\Gin@sepdefault\Gin@gzext}%
+ \fi
+ \fi
+ \ifx\filename@ext\relax
+ \@for\Gin@temp:=\Gin@extensions\do{%
+ \ifx\Gin@ext\relax
+ \Gin@getbase\Gin@temp
+ \fi}%
+ \else
+ \Gin@getbase{\Gin@sepdefault\filename@ext}%
+ \ifnum0%
+ \ifx\Gin@ext\relax 1%
+ \else \@ifundefined{Gin@rule@\Gin@ext}{1}{0}%
+ \fi >0
+ \let\Gin@ext\relax
+ \let\Gin@savedbase\filename@base
+ \let\Gin@savedext\filename@ext
+ \edef\filename@base{\filename@base\Gin@sepdefault\filename@ext}%
+ \let\filename@ext\relax
+ \@for\Gin@temp:=\Gin@extensions\do{%
+ \ifx\Gin@ext\relax
+ \Gin@getbase\Gin@temp
+ \fi}%
+ \ifx\Gin@ext\relax
+ \let\filename@base\Gin@savedbase
+ \let\filename@ext\Gin@savedext
+ \fi
+ \fi
+ \ifx\Gin@ext\relax
+ \@warning{File `#1' not found}%
+ \def\Gin@base{\filename@area\filename@base}%
+ \edef\Gin@ext{\Gin@sepdefault\filename@ext}%
+ \fi
+ \fi
+ \ifx\Gin@ext\relax
+ \@latex@error{File `#1' not found}%
+ {I could not locate the file with any of these extensions:^^J%
+ \Gin@extensions^^J\@ehc}%
+ \else
+ % begin modified part
+ \xdef\moodle@media@base{\detokenize\xa{\Gin@base}}%
+ \xdef\moodle@media@ext{\detokenize\xa{\Gin@ext}}%
+ % end modfied part
+ \fi
+ \endgroup
+}
+% \end{macrocode}
+% \begin{macrocode}
+%See
+% * https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types
+% * https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Containers
+\def\moodle@media@formats{}
+\newcommand{\DeclareMediaFormat}[3]{%
+ \xdef\moodle@media@formats{\ifx\moodle@media@formats\empty\else\moodle@media@formats,\fi#1}%
+ \csgdef{moodle@media@#1list}{#2}%
+ \csgdef{moodle@media@#1mime}{#3}%
+}%
+% Image Formats
+\DeclareMediaFormat{PNG}{.png,.PNG}{image/png}%
+\DeclareMediaFormat{JPEG}{.jpg,.JPG,.jpeg,.JPEG}{image/jpeg}%
+\DeclareMediaFormat{SVG}{.svg,.SVG}{image/svg+xml}%
+\DeclareMediaFormat{GIF}{.gif}{image/gif}%
+% Audio Formats
+\DeclareMediaFormat{WAV}{.wav,.WAV}{audio/wave}%
+\DeclareMediaFormat{MP3}{.mp3,.MP3}{audio/mpeg}%
+\DeclareMediaFormat{OGG}{.ogg,.opus,.og&}{audio/ogg}%
+%\DeclareMediaFormat{FLAC}{.flac,.FLAC}{audio/flac}%
+% Video Formats
+\DeclareMediaFormat{WEBM}{.webm,.webm}{video/webm}%
+\DeclareMediaFormat{MP4}{.mp4,.MP4,.m4v,.M4V}{video/mp4}%
+\DeclareMediaFormat{OGV}{.ogv,.OGV}{video/ogg}%
+% \end{macrocode}
+% \begin{macrocode}
+\def\moodle@media@mime@identify#1{%
+ \edef\test@i{\detokenize\xa{#1}}%
+ \let\moodle@media@mime@current\relax
+ \edef\moodle@media@formats{\detokenize\xa{\moodle@media@formats}}%
+ \@for\@format:=\moodle@media@formats\do{%
+ \edef\@templist{\csname moodle@media@\@format list\endcsname}%
+ \@for\@ext:=\@templist\do{%
+ \ifx\moodle@media@mime@current\relax
+ \edef\@ext{\detokenize\xa{\@ext}}%
+ \ifx\test@i\@ext
+ \message{<<extension \@ext (\@format) identified>>^^J}%
+ \xdef\moodle@media@mime@current{\csname moodle@media@\@format mime\endcsname}%
+ \xdef\moodle@media@ext@current{#1}%
+ \fi
+ \fi
+ }%
+ }%
+}
+% \end{macrocode}
+%
% \subsubsection{External program command lines}
% We first set up commands for the external programs.
% \begin{macrocode}
@@ -3068,20 +5326,65 @@
\expandafter\def\htmlize@executable@macro{#1}%
}
-\def\ghostscriptcommand{\htmlize@setexecutable\gs}
-\def\opensslcommand{\htmlize@setexecutable\openssl}
-\def\imagemagickcommand{\htmlize@setexecutable\htmlize@imagemagick@convert}
+\def\ghostscriptcommand{\htmlize@setexecutable\gs}%
+\def\baselxivcommand{\htmlize@setexecutable\baselxiv}%
+\def\imagemagickcommand{\htmlize@setexecutable\htmlize@imagemagick@convert}%
+\def\optipngcommand{\htmlize@setexecutable\optipng}%
+\def\PDFtoSVGcommand{\htmlize@setexecutable\PDFtoSVG}%
+\def\SVGtoPDFcommand{\htmlize@setexecutable\SVGtoPDF}%
+\def\optiSVGcommand{\htmlize@setexecutable\optiSVG}%
+\def\DeleteFilecommand{\htmlize@setexecutable\DeleteFiles}%
\ifwindows%
- \ghostscriptcommand{gswin64c.exe}%
+ \ghostscriptcommand{gswin64c.exe -dBATCH -dNOPAUSE -sDEVICE=pngalpha}%
+ \baselxivcommand{certutil}%
+ \DeleteFilecommand{del}%
\else%
- \ghostscriptcommand{gs}%
+ \ghostscriptcommand{gs -dBATCH -dNOPAUSE -sDEVICE=pngalpha}%
+ \baselxivcommand{base64}%
+ \DeleteFilecommand{rm -f}%
\fi%
-\opensslcommand{openssl}%
-\imagemagickcommand{convert}%
+\imagemagickcommand{convert -colorspace RGB}%
+\optipngcommand{optipng -clobber -strip all -quiet}%
+\PDFtoSVGcommand{inkscape --export-type=svg --export-area-page --vacuum-defs}%--pdf-poppler
+% remove the "--pdf-poppler" import option if you want to preserve text (avoid conversion to path)
+\SVGtoPDFcommand{inkscape --export-type=pdf --export-area-page}%
+\optiSVGcommand{scour -q --enable-id-stripping --enable-comment-stripping
+ --shorten-ids --indent=none --remove-descriptive-elements}%
% \end{macrocode}
%
+% \subsubsection{Conversion and inclusion of non-native formats}
+% \begin{macrocode}
+\AtEndPreamble{%
+ \@ifpackageloaded{graphicx}{%
+ \def\@firstofthree#1#2#3{#1}%
+ \def\@secondofthree#1#2#3{#2}%
+ \newcommand{\DeclareGraphicsAlien}[3]{%
+ \edef\Gin@extensions{\Gin@extensions,#1}%
+ \DeclareGraphicsRule{#1}{\@gobble#1}{#1}{}%
+ \csdef{Gread@\@gobble#1}##1{%
+ \edef\SourceFile{\Gin@base\Gin@ext}%
+ \edef\Gin@base{\Gin@base-\@gobble#1-converted-to}%
+ \edef\Gin@ext{#2}%
+ \edef\OutputFile{\Gin@base\Gin@ext}%
+ \edef\targetfmt{\expandafter\expandafter\expandafter
+ \@firstofthree\csname Gin@rule@\Gin@ext\endcsname\relax}%
+ \edef\targetext{\expandafter\expandafter\expandafter
+ \@secondofthree\csname Gin@rule@\Gin@ext\endcsname\relax}%
+ \IfFileExists{\OutputFile}{}{\ShellEscape{#3}}%
+ \csletcs{Ginclude@\@gobble#1}{Ginclude@\targetfmt}%
+ \csname Gread@\targetfmt\endcsname{\Gin@base\targetext}%
+ }%
+ }%
+% Support for GIF files: passed as-is in XML but converted in PNG for PDF output.
+% In case the GIF is animated, we pick up the first frame in this conversion.
+% While the picture will be animated after Moodle import, it will not be in the PDF
+% output, whatever the viewer is.
+ \DeclareGraphicsAlien{.gif}{.png}{\htmlize@imagemagick@convert\otherspace '\SourceFile[0]' \OutputFile}%
+ }{}%
+}%
+% \end{macrocode}
% \subsubsection{Graphics key-handling}
% Next, we get ready to handle keys like |height=4cm| or |width=3cm| or |ppi=72|.
% \begin{macrocode}
@@ -3110,25 +5413,58 @@
% \end{macrocode}
%
% \subsubsection{Graphics conversion to HTML}
+% If the |tikz| option is loaded, we define the |embedaspict| command.
+% Furthermore, |includegraphics| is packed into a TikZ node.
+% This allows externalization with regular options for |includegraphics|.
+% Otherwise, |includegraphics| is redefined with a limited set of options supported.
+%
+% Option SVG
% \begin{macrocode}
-\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][]{%
+\ifmoodle@svg
+ \AtEndPreamble{%
+% Declaring SVG to PDF conversion rule for includegraphics
+% \edef\Gin@extensions{\Gin@extensions,.svg,.SVG}%
+% \DeclareGraphicsRule{.svg}{pdf}{.pdf}{%
+% `\SVGtoPDF\otherspace '#1' \noexpand\Gin@base-svg-converted-to.pdf}%
+% \DeclareGraphicsRule{.SVG}{pdf}{.pdf}{%
+% `\SVGtoPDF\otherspace '#1' \noexpand\Gin@base-SVG-converted-to.pdf}%
+ \DeclareGraphicsAlien{.svg}{.pdf}{%
+ \SVGtoPDF\otherspace '\SourceFile' -o '\OutputFile' 2>/dev/null}%
+ \DeclareGraphicsAlien{.SVG}{.pdf}{%
+ \SVGtoPDF\otherspace '\SourceFile' -o '\OutputFile' 2>/dev/null}%
+ }%
+\fi
+
+\ifmoodle@tikz
+\AfterEndPreamble{%
+ %\htmlize@record@expand{\embedaspict}%
+ \let\oldincludegraphics=\includegraphics
+ % patching includegraphics to trigger externalization
+ \renewcommand{\includegraphics}[2][]{%
+ %\message{moodle.sty: Processing \string\includegraphics[#1]{#2} for HTML^^J}%
+ \tikz{\node[inner sep=0pt]{\oldincludegraphics[#1]{#2}};}%
+ }%
+ % externalized images must be included with the regular command
+ \pgfkeys{/pgf/images/include external/.code={\oldincludegraphics{#1}}}%
+ \html@action@newcommand{includegraphics}[2][]{%
+ \message{moodle.sty: Processing \string\includegraphics[#1]{#2} ^^J}
+ \global\advance\numpicturesread by 1\relax
+ \edef\htmlize@imagetag{<IMG SRC="data:\TikzExportMIME;base64,\csname picbaselxiv@\the\numpicturesread\endcsname">}%
+ \xa\g@addto@macro\xa\htmlize@output\xa{\htmlize@imagetag}%
+ }%
+}%
+\else
+\html@action@newcommand{includegraphics}[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
+ % TODO: Can we modify \includegraphics to accept height or width in
% pixels?
- % TO DO: What about \includegraphics[scale=0.7] ?
+ % TODO: What about \includegraphics[scale=0.7] ?
% Other keys: keepaspectratio=true|false, angle (rotation), clip & trim
+ % -> the package option 'tikz' offers a workaround for this
\ifnum\moodle@graphics@height@pixels=0\relax
\ifnum\moodle@graphics@width@pixels=0\relax
% No size specified. Default to height of 200 pixels.
@@ -3150,28 +5486,89 @@
\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}%
+ %Look for the file, even if no extension is provided
+ \moodle@media@find{#2}%
+ %\message{<<\moodle@media@base>>^^J}
+ %\message{<<\moodle@media@ext>>^^J}
+ %Try to identify corresponding MIME-type
+ \moodle@media@mime@identify{\moodle@media@ext}%
+ \ifx\moodle@media@mime@current\relax
+ % conversion needed
+ \edef\moodle@media@pdf{\detokenize{.pdf}}%
+ \edef\moodle@media@ext{\detokenize\xa{\moodle@media@ext}}%
+ \ifnum0\ifx\moodle@media@ext\moodle@media@pdf1\fi\ifmoodle@svg1\fi=11% PDF file and SVG option active
+ \def\moodle@media@ext@current{.svg}%
+ \edef\moodle@media@mime@current{\moodle@media@SVGmime}%
+ \edef\cmdline{\PDFtoSVG\otherspace "\moodle@media@base\moodle@media@ext" -o "\moodle@media@base\moodle@media@ext@current" 2>/dev/null}%
+ \message{moodle.sty: Converting '#2' to SVG...^^J}%
+ \xa\ShellEscape\xa{\cmdline}%
+ %Next, optimize inline
+ \ifwindows\else
+ \edef\cmdline{\optiSVG < "\moodle@media@base\moodle@media@ext@current" >
+ "\moodle@media@base.tmp.svg" && mv "\moodle@media@base.tmp.svg"
+ "\moodle@media@base\moodle@media@ext@current"}%
+ \message{moodle.sty: Optimizing '\moodle@media@base\moodle@media@ext@current'...^^J}%
+ \xa\ShellEscape\xa{\cmdline}%
+ \fi
+ \else% call ImageMagick
+ \def\moodle@media@ext@current{.png}%
+ \def\moodle@media@mime@current{image/png}%
+ \edef\cmdline{\htmlize@imagemagick@convert\otherspace "\moodle@media@base\moodle@media@ext" -resize \moodle@graphics@geometry\otherspace "\moodle@media@base\moodle@media@ext@current"}%
+ \message{moodle.sty: Converting '#2' to PNG...^^J}%
+ \xa\ShellEscape\xa{\cmdline}%
+ %Next, optimize inline
+ \edef\cmdline{\optipng\otherspace "\moodle@media@base\moodle@media@ext@current"}%
+ \message{moodle.sty: Optimizing '\moodle@media@base\moodle@media@ext@current'...^^J}%
+ \xa\ShellEscape\xa{\cmdline}%
+ \fi
+ \fi
+ %Next, convert the file to base64 encoding
+ \ConvertToBaseLXIV{\moodle@media@base}{\moodle@media@ext@current}%
%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
+ \message{moodle.sty: Reading base64 file '\moodle@media@base.enc'...^^J}%
+ \openin\baseLXIVdatafile="\moodle@media@base.enc"
\savebaselxivdata@recursive
\closein\baseLXIVdatafile
+ %Clean up files
+ \ifx\moodle@media@ext@current\moodle@media@ext
+ \ShellEscape{\DeleteFiles\otherspace "\moodle@media@base.enc"}%
+ \else
+ \ShellEscape{\DeleteFiles\otherspace "\moodle@media@base.enc" "\moodle@media@base\moodle@media@ext@current"}%
+ \fi
\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">}%
+ \edef\htmlize@imagetag{<IMG \moodle@graphics@htmlgeometry\otherspace SRC="data:\moodle@media@mime@current;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
-}
+}%
+\fi
+% \end{macrocode}
+% This macro is in charge of throwing a system call to convert local files to base64.
+% \begin{macrocode}
+\ifwindows
+ \def\ConvertToBaseLXIV#1#2{%
+ \def\cmdline{\baselxiv\otherspace -encode "#1#2"\otherspace tmp.b64 && findstr /vbc:"---" tmp.b64 > "#1" && del tmp.b64"}%
+ \message{moodle.sty: Converting '#1#2' to base64...^^J}%
+ \xa\ShellEscape\xa{\cmdline}%
+ % Starting from Windows 7, CertUtil is included by default. There should be no windows XP still running
+ }%
+\else
+ \ifmacosx
+ \def\ConvertToBaseLXIV#1#2{%
+ \def\cmdline{\baselxiv\otherspace -b 64 -i "#1#2"\otherspace -o "#1.enc"}%
+ \message{moodle.sty: Converting '#1#2' to base64...^^J}%
+ \xa\ShellEscape\xa{\cmdline}%
+ }%
+ \else % Linux, Cygwin
+ \def\ConvertToBaseLXIV#1#2{%
+ \def\cmdline{\baselxiv\otherspace "#1#2"\otherspace > "#1.enc"}%
+ \message{moodle.sty: Converting '#1#2' to base64...^^J}%
+ \xa\ShellEscape\xa{\cmdline}%
+ }%
+ % base64 is part of coreutils, add "-w 64" to get exactly the previous behavior %
+ \fi
+\fi
% \end{macrocode}
% The following code accomplishes the reading of an |.enc| file into memory.
% It is also used by the \TikZ\ code below.
@@ -3201,32 +5598,57 @@
% are undefined.
% Our solution is to wait until |\AtBeginDocument| and then test whether
% \TikZ\ is loaded. If so, we make the appropriate definitions.
+% \begin{macro}{TikZ}
+% \changes{v0.7}{2020/07/14}{Support \emph{tikz}\ command}
% \begin{macrocode}
-\newif\ifmoodle@tikzloaded
-\moodle@tikzloadedfalse
\AtBeginDocument{
\ifx\tikzpicture\@undefined
\moodle@tikzloadedfalse
\else
\moodle@tikzloadedtrue
\fi
+ \ifmoodle@draftmode
+ \long\def\tikzifexternalizing#1#2{#2}%
+ \else
\ifmoodle@tikzloaded
- \usetikzlibrary{external}
+ \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}}%
+ \def\moodle@basename{\tikzexternalrealjob-tikztemp-\the\numconvertedpictures}%
+ \ifmoodle@svg
+ \def\TikzExportExtension{.svg}%
+ \def\TikzExportMIME{image/svg+xml}%
+ \ifpdfoutput% tex engines defaulting to PDF output (pdflatex, xelatex, lualatex)
+ \def\ExportTikz{ \message{moodle.sty: Converting picture '\moodle@basename.pdf' to SVG...^^J}%
+ \edef\cmdline{\PDFtoSVG\otherspace "\moodle@basename.pdf" -o "\moodle@basename\TikzExportExtension" 2>/dev/null}%
+ \xa\ShellEscape\xa{\cmdline}}%
+ \else % latex
+ \def\ExportTikz{ \message{moodle.sty: Converting picture '\moodle@basename.ps' to SVG...^^J}%
+ \edef\cmdline{\PDFtoSVG\otherspace "\moodle@basename.ps" -o "\moodle@basename\TikzExportExtension" 2>/dev/null}%
+ \xa\ShellEscape\xa{\cmdline}}%
+ \fi
+ \def\OptimizeExport{ \message{moodle.sty: Optimizing '\moodle@basename.svg'...^^J}%
+ \edef\cmdline{\optiSVG\otherspace < "\moodle@basename\TikzExportExtension" >
+ "\moodle@basename.tmp.svg" && mv "\moodle@basename.tmp.svg"
+ "\moodle@basename\TikzExportExtension" }%
+ \xa\ShellEscape\xa{\cmdline}}%
\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}}%
+ \def\TikzExportExtension{.png}%
+ \def\TikzExportMIME{image/png}%
+ \ifpdfoutput% tex engines defaulting to PDF output (pdflatex, xelatex, lualatex)
+ \def\ExportTikz{ \message{moodle.sty: Converting picture '\moodle@basename.pdf' to PNG...^^J}%
+ \edef\gscmdline{\gs\otherspace -sOutputFile=\moodle@basename\TikzExportExtension\otherspace -r150 \moodle@basename.pdf}%
+ \xa\ShellEscape\xa{\gscmdline}}%
+ \else % latex
+ \def\ExportTikz{ \message{moodle.sty: Converting picture '\moodle@basename.ps' to PNG...^^J}%
+ \edef\gscmdline{\gs\otherspace -sOutputFile=\moodle@basename\TikzExportExtension\otherspace -r150 \\moodle@basename.ps}%
+ \xa\ShellEscape\xa{\gscmdline}}%
+ \fi
+ \def\OptimizeExport{ \message{moodle.sty: Optimizing '\moodle@basename.png'...^^J}%
+ \edef\cmdline{\optipng\otherspace \moodle@basename\TikzExportExtension}%
+ \xa\ShellEscape\xa{\cmdline}}%
\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
@@ -3238,43 +5660,63 @@
% 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
}
+% The following could replace calls to \pdftopng, \pngoptim and \pngtobaselxiv
+% \tikzset{external/system call/.add={}{;
+% gs -dBATCH -dNOPAUSE -sDEVICE=pngalpha -sOutputFile="\image.png" -r150 "\image.pdf";
+% optipng -clobber -strip all -quiet "\image.png";
+% base64 "\image.png" > "\image.enc"
+% }
+% }
+% With the following mechanism, we could trigger something when the externalized images are included back.
+% \pgfkeys{/pgf/images/include external/.code={\pgfimage{#1}\@moodle@ifgeneratexml{\savebaselxivdata}{}}}
+%
\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
+ \ExportTikz
+ \OptimizeExport
+ \ConvertToBaseLXIV{\moodle@basename}{\TikzExportExtension}%
\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}}
+ \ifmoodle@tikz
+ \tikzset{external/optimize=false}% due to redefinition, includegraphics must not be optimized away
+ \else
+ \tikzset{external/optimize=true}%
+ \tikzset{external/optimize command away={\VerbatimInput}{1}}%
+ \fi
%
% The HTMLizer version of the tikzpicture environment,
% which writes an <IMG> tag to the XML file.
- \htmlize@record@environment{tikzpicture}
+ \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">}%
+ \edef\htmlize@imagetag{<IMG SRC="data:\TikzExportMIME;base64,\csname picbaselxiv@\the\numpicturesread\endcsname">}%
\xa\g@addto@macro\xa\htmlize@output\xa{\htmlize@imagetag}%
}[\htmlize@patchendenvironment]%
}%
+ \html@action@newcommand{tikz}[2][]{%
+% \message{>>> Processing \string\tikz[#1]{...} ^^J}
+ \global\advance\numpicturesread by 1\relax
+ \edef\htmlize@imagetag{<IMG SRC="data:\TikzExportMIME;base64,\csname picbaselxiv@\the\numpicturesread\endcsname">}%
+ \xa\g@addto@macro\xa\htmlize@output\xa{\htmlize@imagetag}%
+ }%
\else
%TikZ not loaded. Provide dummy definitions for commands.
\long\def\tikzifexternalizing#1#2{#2}%
\fi
+ \fi
+ \ifmoodle@tikz
+ \tikzstyle{moodlepict}=[minimum height=1em,inner sep=0pt,execute at begin node={\begin{varwidth}{\linewidth}},execute at end node={\end{varwidth}}]
+ \newcommand\embedaspict[1]{\tikz[baseline=-\the\dimexpr\fontdimen22\textfont2\relax]{\node[moodlepict]{\mbox{#1}};}}
+ \htmlize@record@expand{\embedaspict}
+ \fi
}
\newcount\numconvertedpictures
@@ -3290,27 +5732,464 @@
\xa\global\xa\let\csname picbaselxiv@\the\numconvertedpictures\endcsname=\moodle@newpic@baselxiv%
}
-\def\@moodle@par{\par}%
+\ifmoodle@tikz
+ \ifmoodle@tikzloaded
+ \PackageWarning{moodle}{With package option 'tikz', you should not load TikZ manually.}%
+ \fi
+ \RequirePackage{tikz}%
+ \RequirePackage{varwidth}% for the command |embedaspict|
+\fi
% \end{macrocode}
% Finally, we clean up our mess by deleting the temporary PDF, PNG, and ENC
% files we created.
+% With XeTeX, we cannot clean pictures pdf's because they are actually included in the final pdf afterwards, by xdvipdfmx.
+% With LuaTeX, it looks like |\AtEndDocument| is too early to for this cleaning step.
% \begin{macrocode}
-\AtEndDocument{%
+\AfterEndDocument{%
\ifmoodle@tikzloaded
\@moodle@ifgeneratexml{%
- \ifwindows
- \immediate\write18{del \tikzexternalrealjob-tikztemp-*.*}%
+ \ifXeTeX
+ % we must keep picture pdf's for subsequent linking (xdvipdfmx)
+ \ifwindows
+ \ShellEscape{powershell.exe -noexit "del * -include \tikzexternalrealjob-tikztemp-*.* -exclude *.pdf}%
+ \else
+ \ShellEscape{find . -type f -name "\tikzexternalrealjob-tikztemp-*.*" -not -name "*.pdf" -delete}%
+ \fi
\else
- \immediate\write18{rm \tikzexternalrealjob-tikztemp-*.*}%
+ \ShellEscape{\DeleteFiles\otherspace \tikzexternalrealjob-tikztemp-*.*}%
\fi
}{}%
\fi
}
-
-% TO DO:
+% \end{macrocode}
+% TODO:
% * sizing options for TikZ pictures?
-% * In cloze multi, how to handle HTML or TeX in answers? In particular, what about ~?
+%\end{macro}
+%
+% \subsection{Other Media}
+% Support for other media comes through the |\url|\marg{link} and |\href|\marg{link}\marg{text}
+% commands.
+\AtEndPreamble{%
+ \@ifpackageloaded{hyperref}{%
+ \let\oldhref\href
+ \let\oldurl\url
+ \def\moodle@hyper@readexternallink#1#2#3#4:#5:#6\\#7{%
+% 1) The link type (the string "link" in the cases I observed)
+% 2) The URL fragment (i.e. what comes after # in the end),
+% 3) the text replacement,
+% 4) the URL scheme (http, https, mailto, file, run etc),
+% 5) the URL details (in general, that is whole authority + path + query).
+% If the URL contains a column (specification of a password in userinfo or a
+% port in authority), we get here whatever comes before the first column (:)
+% 6) empty is URL contains no column. Otherwise, filled with whatever follows
+% a first column (:) after the scheme,
+% 7) the whole URL again (fragment removed).
+ \def\filename@ext{}%
+ \def\filename@area{}%
+ \def\filename@base{}%
+ \ifx\\#6\\% if ##6 is empty (the URL contains no column -> no scheme -> local)
+ %\@hyper@linkfile file:#7\\{#3}{#2}{#7}% local file
+ %Local file (##1|##2|##3|##4|##5|##6): ##7\par
+ \filename@parse{#4}%
+ \ConvertToBaseLXIV{\filename@area\filename@base}{.\filename@ext}%
+ \else
+ \ifx\\#4\\%if ##4 is empty (no scheme was specified -> local file)
+% %\@hyper@linkfile file:#7\\{#3}{#2}{#7}% Mac filename ?
+% Local file (Mac? ##1|##2|##3|##4|##5|##6): ##7\par
+ \filename@parse{#4}%
+ \ConvertToBaseLXIV{\filename@area\filename@base}{.\filename@ext}%
+ \else
+ \def\@pdftempa{#4}%
+ \ifx\@pdftempa\@pdftempwordfile% scheme is "file:"
+% %\@hyper@linkfile#7\\{#3}{#2}{#7}% file
+% Local file (no column ##1|##2|##3|##4|##5|##6): ##7\par
+ \filename@parse{#5}%
+ \ConvertToBaseLXIV{\filename@area\filename@base}{.\filename@ext}%
+ \else
+ \ifx\@pdftempa\@pdftempwordrun% scheme is "run:"
+ \ifHy@pdfa
+ \Hy@Error{%
+ PDF/A: Launch action is prohibited%
+ }\@ehc
+ \begingroup
+ \leavevmode
+% ##2%
+ \endgroup
+ \else% not in PDF/A mode -> run is allowed
+ %\@hyper@launch#7\\{#3}{#2}% run local file
+% Run local file (##1|##2|##3|##4|##5|##6): ##7\par
+ \filename@parse{#5}%
+ \ConvertToBaseLXIV{\filename@area\filename@base}{.\filename@ext}%
+ \fi
+ \else% scheme is neither "file" nor "run", assuming it is a web protocol
+ %\hyper@linkurl{#3}{#7\ifx\\#2\\\else\hyper@hash#2\fi}% URL
+% URL (##1|##2|##3|##4|##5|##6): ##7\par
+ \filename@parse{#7}%
+ \fi
+ \fi
+ \fi
+ \fi
+ \xdef\moodle@media@ext{.\filename@ext}%
+ \xdef\moodle@media@base{\filename@area\filename@base}%
+ }%
+% \html@action@newcommand{href}[3][]{%
+% \bgroup% The grouping is to localize the changes caused by \setkeys.
+% \message{moodle.sty: Processing \string\href[#1]{#2}{#3} for HTML...^^J}%
+% the following macro is a modified version of hyperref's |\hyper@readexternallink|
+% \let\@hyper@readexternallink\moodle@hyper@readexternallink
+% \oldhref[#1]{#2}{#3}%
+ %\message{<<\moodle@media@base>>^^J}
+ %\message{<<\moodle@media@ext>>^^J}
+ %Try to identify corresponding MIME-type
+% \moodle@media@mime@identify{\moodle@media@ext}%
+ %\edef\moodle@media@mime@current{\detokenize\xa{\moodle@media@mime@current}}%
+% \xa\message\xa{moodle.sty: \moodle@media@mime@current^^J}%
+% \ifx\moodle@media@mime@current\relax
+% \xa\g@addto@macro\xa\htmlize@output\xa{<A href=\otherampersand\otherhash34;\moodle@media@base\moodle@media@ext\otherampersand\otherhash34;>#3</A>}%
+% \message{moodle.sty: <A> tag inserted.^^J}%
+% \else
+% \filename@parse{\moodle@media@mime@current}%
+% \def\@tmp{audio/}
+% \ifx\filename@area\@tmp
+% \IfFileExists{\moodle@media@base.enc}{%
+% \def\moodle@newpic@baselxiv{}%
+% \openin\baseLXIVdatafile=\moodle@media@base.enc\relax
+% \savebaselxivdata@recursive
+% \closein\baseLXIVdatafile
+% \xa\g@addto@macro\xa\htmlize@output\xa{<audio controls src="data:\moodle@media@mime@current;base64,\moodle@newpic@baselxiv">#3</audio>}%
+% }{%
+% \xa\g@addto@macro\xa\htmlize@output\xa{<audio controls src="\moodle@media@base\moodle@media@ext">#3</audio>}%
+% }%
+% \message{moodle.sty: <audio> tag inserted.^^J}%
+% \else
+% \def\@tmp{video/}
+% \ifx\filename@area\@tmp
+% \IfFileExists{\moodle@media@base.enc}{%
+% \def\moodle@newpic@baselxiv{}%
+% \openin\baseLXIVdatafile=\moodle@media@base.enc\relax
+% \savebaselxivdata@recursive
+% \closein\baseLXIVdatafile
+% \xa\g@addto@macro\xa\htmlize@output\xa{<video controls src="data:\moodle@media@mime@current;base64,\moodle@newpic@baselxiv">#3</video>}%
+% }{%
+% \xa\g@addto@macro\xa\htmlize@output\xa{<video controls src="\moodle@media@base\moodle@media@ext">#3</video>}%
+% }%
+% \message{moodle.sty: <video> tag inserted.^^J}%
+% \else
+% \PackageWarning{moodle}{cannot recognize MIME type of #2. Ignoring it.}%
+% \fi
+% \fi
+% \fi
+% \egroup
+% }%
+% \html@action@def\url#1{%
+% \bgroup% The grouping is to localize the changes caused by \setkeys.
+% \message{moodle.sty: Processing \string\url{#1} for HTML...^^J}%
+% the following macro is a modified version of hyperref's |\hyper@readexternallink|
+% \let\@hyper@readexternallink\moodle@hyper@readexternallink
+% \oldhref{#1}{#1}%
+% \xa\g@addto@macro\xa\htmlize@output\xa{<A href=\otherampersand\otherhash34;\moodle@media@base\moodle@media@ext\otherampersand\otherhash34;>#1</A>}%
+% \message{moodle.sty: <A> tag inserted.^^J}%
+% \egroup
+% }%
+ }{}%
+}%
+%
+% \subsection{Verbatim Code}
+%
+% We start by defining a macro to parameter a style for code box display in Moodle
+% \begin{macrocode}
+\def\xmlDisplayVerbatimBox{border-top: thin solid; border-bottom: thin solid}%
+% \end{macrocode}
+% First, let us handle |\verbatiminput| from the `verbatim' package
+% \begin{macrocode}
+\html@action@def\verbatiminput#1{%
+ \message{moodle.sty: Processing \string\verbatiminput{#1} for HTML ^^J}%
+ \g@addto@macro\htmlize@output{<PRE style="\xmlDisplayVerbatimBox"><CODE>}%
+ %%%%%%%%%%%%%% from verbatim %%%%%%%%%%%%%%%%%
+ \@bsphack
+ \let\do\@makeother\dospecials
+ \catcode`\^^M\active
+ \def\verbatim@processline{\xa\g@addto@macro\xa\htmlize@output\xa{\the\verbatim@line<BR/>}}
+ \verbatim@readfile{#1}%
+ \@esphack
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ \g@addto@macro\htmlize@output{</CODE></PRE>}%
+}%
+% \end{macrocode}
+% Second, we deal with |\VerbatimInput| from `fancyvrb' or `fvextra'
+% \begin{macrocode}
+\@ifpackageloaded{minted}{\PackageError{moodle}{'moodle' should be loaded before 'minted'.}%
+{'moodle' loads 'fancybox' which, unfortunately, redefines verbatim commands.}}{\relax}%
+\@ifpackageloaded{fvextra}{\PackageError{moodle}{'moodle' should be loaded before 'fvextra'.}%
+{'moodle' loads 'fancybox' which, unfortunately, redefines verbatim commands.}}{\relax}%
+\@ifpackageloaded{fancyvrb}{\PackageError{moodle}{'moodle' should be loaded before 'fancyvrb'.}%
+{'moodle' loads 'fancybox' which, unfortunately, redefines verbatim commands.}}{\relax}%
+
+\html@action@newcommand{VerbatimInput}[2][]{%
+ \message{moodle.sty: Processing \string\VerbatimInput[#1]{#2} for HTML ^^J}%
+ \def\FV@KeyValues{#1}%
+ \FV@UseKeyValues% import options defined in #1
+ \moodle@VerbatimInput{#2}%
+}%
+\html@action@newcommand{LVerbatimInput}[2][]{%
+ \message{moodle.sty: Processing \string\LVerbatimInput[#1]{#2} for HTML ^^J}%
+ \def\FV@KeyValues{#1}%
+ \FV@UseKeyValues% import options defined in #1
+ \moodle@VerbatimInput{#2}%
+}%
+\html@action@newcommand{BVerbatimInput}[2][]{%
+ \message{moodle.sty: Processing \string\BVerbatimInput[#1]{#2} for HTML ^^J}%
+ \def\FV@KeyValues{#1}%
+ \FV@UseKeyValues% import options defined in #1
+ \moodle@VerbatimInput{#2}%
+}%
+\def\moodle@VerbatimInput#1{%
+ \g@addto@macro\htmlize@output{<PRE style="\xmlDisplayVerbatimBox"><CODE>}%
+ %%%%%%%% using material from fancyvrb and fvextra %%%%%%%%
+ %\begingroup
+ \def\moodle@verbatim@addlinenumber##1{%
+ \g@addto@macro\htmlize@output{<span style="font-size: 80\otherpercent;
+ background-color: \otherhash f0f0f0; padding: 0 5px 0 5px; display:
+ inline-block; width: 16pt; ##1">}%
+ \if@FV@NumberBlankLines
+ \xa\g@addto@macro\xa\htmlize@output\xa{\the\c@FancyVerbLine</span>}%
+ \else
+ \ifx\FV@Line\empty
+ \xa\g@addto@macro\xa\htmlize@output\xa{\otherampersand nbsp;</span>}%
+ \else
+ \xa\g@addto@macro\xa\htmlize@output\xa{\the\c@FancyVerbLine</span>}%
+ \fi
+ \fi
+ }
+ % redefine the ProcessLine routine ('fancyvrb' and 'fvextra') for XML output
+ \def\FV@ProcessLine##1{%
+ \ifcsname FV@HighlightLine:\number\c@FancyVerbLine\endcsname
+ \xdef\moodle@FV@tagB{<mark>}% fvextra triggered highlighting for this line
+ \xdef\moodle@FV@tagE{</mark>}%
+ \else
+ \xdef\moodle@FV@tagB{}% no highlighting
+ \xdef\moodle@FV@tagE{}%
+ \fi
+ \catcode`\`=12%
+ \def\FV@Line{##1}%
+ \ifx\FV@LeftListNumber\relax
+
+ \else% line numbers displayed on the left side
+ \moodle@verbatim@addlinenumber{text-align: right}%
+ \fi
+ \xa\g@addto@macro\xa\htmlize@output\xa{\moodle@FV@tagB}%
+ \xa\g@addto@macro\xa\htmlize@output\xa{\FV@Line}%
+ \xa\g@addto@macro\xa\htmlize@output\xa{\moodle@FV@tagE}%
+ \ifx\FV@RightListNumber\relax\else% line numbers on the right side
+ \moodle@verbatim@addlinenumber{text-align: left; float: right}%
+ \fi
+ \g@addto@macro\htmlize@output{<BR/>}%linebreak
+ }
+ \global\FV@CodeLineNo\z@% reset codeline counter
+ \frenchspacing% Cancels special punctuation spacing.
+ \FV@DefineWhiteSpace
+ \def\FV@Space{\space}
+ \FV@DefineTabOut% replace tabs with a series a whitespaces
+ \ifdefined\FV@HighlightLinesPrep
+ \FV@HighlightLinesPrep% prepare highlighting if 'fvextra' is loaded
+ \fi
+ \FV@Input{#1}%
+ %\endgroup
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ \g@addto@macro\htmlize@output{</CODE></PRE>}%
+}%
+\AtEndPreamble{%
+ \@ifpackageloaded{fancyvrb}{%
+ % custom settings for display
+ \fvset{frame=lines,label={[Beginning of code]End of code},framesep=3mm,numbersep=9pt}%
+ }{\relax}%
+}
+% \end{macrocode}
+% Third, we patch `minted' so that it also calls pygmentize to generate HTML code.
+% \begin{macrocode}
+\AtEndPreamble{% this definition should prevail because `minted' gets loaded after `moodle'
+\@ifpackageloaded{minted}{%
+ \newcounter{moodle@pygmentizecounter}%
+ \renewcommand{\minted@pygmentize}[2][\minted@outputdir\minted@jobname.pyg]{%
+ \minted@checkstyle{\minted@get@opt{style}{default}}%
+ \stepcounter{minted@pygmentizecounter}%
+ \ifthenelse{\equal{\minted@get@opt{autogobble}{false}}{true}}%
+ {\def\minted@codefile{\minted@outputdir\minted@jobname.pyg}}%
+ {\def\minted@codefile{#1}}%
+ \ifthenelse{\boolean{minted@isinline}}%
+ {\def\minted@optlistcl@inlines{%
+ \minted@optlistcl@g@i
+ \csname minted@optlistcl@lang\minted@lang @i\endcsname}}%
+ {\let\minted@optlistcl@inlines\@empty}%
+ \def\minted@cmdtemplate##1##2{%
+ \ifminted@kpsewhich
+ \ifwindows
+ \detokenize{for /f "usebackq tokens=*"}\space\@percentchar\detokenize{a
+ in (`kpsewhich}\space\minted@codefile\detokenize{`) do}\space
+ \fi
+ \fi
+ \MintedPygmentize\space -l #2 -f ##1 -F tokenmerge
+ \minted@optlistcl@g \csname minted@optlistcl@lang\minted@lang\endcsname
+ \minted@optlistcl@inlines
+ \minted@optlistcl@cmd -o \minted@outputdir##2\space
+ \ifminted@kpsewhich
+ \ifwindows
+ \@percentchar\detokenize{a}%
+ \else
+ \detokenize{`}kpsewhich \minted@codefile\space
+ \detokenize{||} \minted@codefile\detokenize{`}%
+ \fi
+ \else
+ \minted@codefile
+ \fi}%
+ \def\minted@cmd{\minted@cmdtemplate{latex -P commandprefix=PYG}{\minted@infile}}
+ % For debugging, uncomment: %%%%
+ \immediate\typeout{\minted@cmd}%
+ % %%%%
+ \def\minted@cmdHTML{\minted@cmdtemplate{html -P noclasses -P
+ nowrap -P hl_lines="\FV@HighlightLinesList" -P
+ style="\minted@get@opt{style}{default}"}{\csname minted@infileHTML\the\c@minted@pygmentizecounter\endcsname}}%
+ \def\minted@cmdPNG{\minted@cmdtemplate{png -P
+ line_numbers=True}{\minted@infilePNG}}%
+ \def\minted@cmdSVG{\minted@cmdtemplate{svg -P
+ linenos=True}{\minted@infileSVG}}%
+ \ifthenelse{\boolean{minted@cache}}%
+ {%
+ \ifminted@frozencache
+ \else
+ \ifx\XeTeXinterchartoks\minted@undefined
+ \ifthenelse{\equal{\minted@get@opt{autogobble}{false}}{true}}%
+ {\edef\minted@hash{\pdf@filemdfivesum{#1}%
+ \pdf@mdfivesum{\minted@cmd autogobble(\ifx\FancyVerbStartNum\z@
+ 0\else\FancyVerbStartNum\fi-\ifx\FancyVerbStopNum\z@
+ 0\else\FancyVerbStopNum\fi)}}}%
+ {\edef\minted@hash{\pdf@filemdfivesum{#1}%
+ \pdf@mdfivesum{\minted@cmd}}}%
+ \else
+ \ifx\mdfivesum\minted@undefined
+ \immediate\openout\minted@code\minted@jobname.mintedcmd\relax
+ \immediate\write\minted@code{\minted@cmd}%
+ \ifthenelse{\equal{\minted@get@opt{autogobble}{false}}{true}}%
+ {\immediate\write\minted@code{autogobble(\ifx\FancyVerbStartNum\z@
+ 0\else\FancyVerbStartNum\fi-\ifx\FancyVerbStopNum\z@
+ 0\else\FancyVerbStopNum\fi)}}{}%
+ \immediate\closeout\minted@code
+ \edef\minted@argone@esc{#1}%
+ \StrSubstitute{\minted@argone@esc}{\@backslashchar}{\@backslashchar\@backslashchar}[\minted@argone@esc]%
+ \StrSubstitute{\minted@argone@esc}{"}{\@backslashchar"}[\minted@argone@esc]%
+ \edef\minted@tmpfname@esc{\minted@outputdir\minted@jobname}%
+ \StrSubstitute{\minted@tmpfname@esc}{\@backslashchar}{\@backslashchar\@backslashchar}[\minted@tmpfname@esc]%
+ \StrSubstitute{\minted@tmpfname@esc}{"}{\@backslashchar"}[\minted@tmpfname@esc]%
+ %Cheating a little here by using ASCII codes to write `{` and `}`
+ %in the Python code
+ \def\minted@hashcmd{%
+ \detokenize{python -c "import hashlib; import os;
+ hasher = hashlib.sha1();
+ f =
+ open(os.path.expanduser(os.path.expandvars(\"}\minted@tmpfname@esc.mintedcmd\detokenize{\")),
+ \"rb\");
+ hasher.update(f.read());
+ f.close();
+ f =
+ open(os.path.expanduser(os.path.expandvars(\"}\minted@argone@esc\detokenize{\")),
+ \"rb\");
+ hasher.update(f.read());
+ f.close();
+ f =
+ open(os.path.expanduser(os.path.expandvars(\"}\minted@tmpfname@esc.mintedmd5\detokenize{\")),
+ \"w\");
+ macro = \"\\edef\\minted@hash\" + chr(123) + hasher.hexdigest()
+ + chr(125) + \"\";
+ f.write(\"\\makeatletter\" + macro +
+ \"\\makeatother\\endinput\n\");
+ f.close();"}}%
+ \ShellEscape{\minted@hashcmd}%
+ \minted@input{\minted@outputdir\minted@jobname.mintedmd5}%
+ \else
+ \ifthenelse{\equal{\minted@get@opt{autogobble}{false}}{true}}%
+ {\edef\minted@hash{\mdfivesum file {#1}%
+ \mdfivesum{\minted@cmd autogobble(\ifx\FancyVerbStartNum\z@
+ 0\else\FancyVerbStartNum\fi-\ifx\FancyVerbStopNum\z@
+ 0\else\FancyVerbStopNum\fi)}}}%
+ {\edef\minted@hash{\mdfivesum file {#1}%
+ \mdfivesum{\minted@cmd}}}%
+ \fi
+ \fi
+ \edef\minted@infile{\minted@cachedir/\minted@hash.pygtex}%
+ \edef\minted@temp@infileHTML{\minted@cachedir/\minted@hash.html}%
+ \global\cslet{minted@infileHTML\the\c@minted@pygmentizecounter}{\minted@temp@infileHTML}%
+ %\global\edef\minted@infilePNG{\minted@cachedir/\minted@hash.png}%
+ %\global\edef\minted@infileSVG{\minted@cachedir/\minted@hash.svg}%
+ \IfFileExists{\minted@infile}{}{%
+ \ifthenelse{\equal{\minted@get@opt{autogobble}{false}}{true}}{%
+ \minted@autogobble{#1}}{}%
+ \ShellEscape{\minted@cmd}%
+ \ShellEscape{\minted@cmdHTML}%
+ %\ShellEscape{\minted@cmdPNG}%
+ %\ShellEscape{\minted@cmdSVG}%
+ }%
+ \fi
+ \ifthenelse{\boolean{minted@finalizecache}}%
+ {%
+ \edef\minted@cachefilename{listing\arabic{minted@pygmentizecounter}.pygtex}%
+ \edef\minted@actualinfile{\minted@cachedir/\minted@cachefilename}%
+ \ifwindows
+ \StrSubstitute{\minted@infile}{/}{\@backslashchar}[\minted@infile@windows]
+ \StrSubstitute{\minted@actualinfile}{/}{\@backslashchar}[\minted@actualinfile@windows]
+ \ShellEscape{move /y
+ \minted@outputdir\minted@infile@windows\space\minted@outputdir\minted@actualinfile@windows}%
+ \else
+ \ShellEscape{mv -f
+ \minted@outputdir\minted@infile\space\minted@outputdir\minted@actualinfile}%
+ \fi
+ \let\minted@infile\minted@actualinfile
+ \expandafter\minted@addcachefile\expandafter{\minted@cachefilename}%
+ }%
+ {\ifthenelse{\boolean{minted@frozencache}}%
+ {%
+ \edef\minted@cachefilename{listing\arabic{minted@pygmentizecounter}.pygtex}%
+ \edef\minted@infile{\minted@cachedir/\minted@cachefilename}%
+ \expandafter\minted@addcachefile\expandafter{\minted@cachefilename}}%
+ {\expandafter\minted@addcachefile\expandafter{\minted@hash.pygtex}}%
+ }%
+ \minted@inputpyg}%
+ {%
+ \ifthenelse{\equal{\minted@get@opt{autogobble}{false}}{true}}{%
+ \minted@autogobble{#1}}{}%
+ \ShellEscape{\minted@cmd}%
+ \ShellEscape{\minted@cmdHTML}%
+ %\ShellEscape{\minted@cmdPNG}%
+ %\ShellEscape{\minted@cmdSVG}%
+ \minted@inputpyg}%
+ }%
+}{}%
+}%
+\html@action@newcommand{inputminted}[3][]{%
+ \message{moodle.sty: Processing \string\inputminted[#1]{#2}{#3} for HTML ^^J}%
+ % arguments #2 and #3 are thrown away: the job is done previously by minted when
+ % calling pygmentize. The file |\minted@infileHTML| generated with our hack will be used.
+ % Since minted is based upon `fvextra' the macro |\moodle@VerbatimInput| works here.
+ \minted@configlang{#2}% grab options set for this specific language
+ \setkeys{minted@opt@cmd}{#1}% grab options in #1
+ \minted@fvset% import options
+ \stepcounter{moodle@pygmentizecounter}
+ \xa\moodle@VerbatimInput\xa{\csname minted@infileHTML\the\c@moodle@pygmentizecounter\endcsname}%
+}%
% \end{macrocode}
%
+% \subsection{Warning users of \texttt{babel}}
+% Users of the |babel| package loaded with the 'french' option may experience problems
+% related to autospacing when using |pdfLaTeX|. We shall warn them.
+% \begin{macrocode}
+\AtBeginDocument{%
+ \ifPDFTeX % pdflatex or latex
+ \@ifpackagewith{babel}{french}{%
+ \PackageWarning{moodle}{Be careful when using LaTeX, moodle, and the babel package with option 'french'. Autospacing produces in undesired symbols in the XML. You can either 1) compile with xelatex/lualatex or 2) add '\NoAutoSpacing' after '\begin{quiz}'.}%
+ }{\relax}%
+ \fi
+}%
+% \end{macrocode}
+%
+%
% \Finale
\endinput
diff --git a/macros/latex/contrib/moodle/moodle.ins b/macros/latex/contrib/moodle/moodle.ins
index 16afd4503b..b118c1beab 100644
--- a/macros/latex/contrib/moodle/moodle.ins
+++ b/macros/latex/contrib/moodle/moodle.ins
@@ -1,5 +1,6 @@
%% moodle.ins
-%% Copyright 2016 by Anders O.F. Hendrickson
+%% Copyright 2016 by Anders O.F. Hendrickson and 2019-2021
+%% by Matthieu Guerquin-Kern.
%%
%% This work may be distributed and/or modified under the
%% conditions of the LaTeX Project Public License, either version 1.3
@@ -11,7 +12,7 @@
%%
%% This work has the LPPL maintenance status `maintained'.
%%
-%% The Current Maintainer of this work is Anders O.F. Hendrickson.
+%% The Current Maintainer of this work is Matthieu Guerquin-Kern.
%%
%% This work consists of the files moodle.dtx and moodle.ins
%% and the derived file moodle.sty.
@@ -25,7 +26,8 @@
This is a generated file.
-Copyright (C) 2016 by Anders Hendrickson <anders.hendrickson@snc.edu>
+Copyright 2016 by Anders O.F. Hendrickson (anders.o.f.hendrickson AT gmail.com)
+and 2019-2021 by Matthieu Guerquin-Kern (guerquin-kern AT crans.org).
This work may be distributed and/or modified under the
conditions of the LaTeX Project Public License, either version 1.3
diff --git a/macros/latex/contrib/moodle/moodle.pdf b/macros/latex/contrib/moodle/moodle.pdf
index f5dd6cae3c..1c047103cd 100644
--- a/macros/latex/contrib/moodle/moodle.pdf
+++ b/macros/latex/contrib/moodle/moodle.pdf
Binary files differ