% ----------------------------------------------------------------------- % webquiz.cls | webquiz latex class file % ----------------------------------------------------------------------- % % Copyright (C) Andrew Mathas, University of Sydney % % Distributed under the terms of the GNU General Public License (GPL) % http://www.gnu.org/licenses/ % % This file is part of the WebQuiz system. % % % ---------------------------------------------------------------------- \NeedsTeXFormat{LaTeX2e}[1996/12/01] % load webquiz-ini style \input{webquiz-ini.code} % ---------------------------------------------------------------------- \ProvidesClass{webquiz}[\webquiz{release date} Version \webquiz{version}] % initialise and then process document class options usng pgfopts \RequirePackage{etoolbox} \RequirePackage{pgfopts} \def\unknown@options{}% unknown options are passed to article.cls \def\WQ@HideSideMenu{DeFaUlT}% side menu visible by default \newif\ifWQ@Tikz\WQ@Tikzfalse% true if tikz a document class option \newif\ifWQ@Debugging % for the debugging class option % Process the documentclass options using pgfkeys and \ProcessPgfOptions \pgfkeys{/WQ@ClassOptions/.is family, /WQ@ClassOptions, % turn debugging on debugging/.code = {\WQ@Debuggingtrue}, % pst2pdf pst2pdf/.style = {pst2pdf value=true}, pst2pdf value/.initial = false, % languaage language/.initial = DeFaUlT, % one page onepage/.style = {onepage value=true}, separatepages/.style = {onepage value=false}, onepage value/.initial = DeFaUlT, % side menu showsidemenu/.style = {hidesidemenu value=false}, hidesidemenu/.style = {hidesidemenu value=true}, hidesidemenu value/.initial= DeFaUlT, % random order of quiz questions randomorder/.style = {randomorder value=true}, fixedorder/.style = {randomorder value=false}, randomorder value/.initial = DeFaUlT, % theme theme/.initial = DeFaUlT, % tikz tikz/.code = {\global\WQ@Tikztrue}, % unknown options => passed to article class .unknown/.code={\edef\unknown@options{\unknown@options,\pgfkeyscurrentname}} } \newcommand\WQ@ClassOption[1]{\pgfkeysvalueof{/WQ@ClassOptions/#1}} % Use pgfkeys to check for valid options for the choice environment and the % answer comparisons. As \ERROR is not defined an error message is % generated by the unknown handlers below \pgfkeys{/webquiz checker/.is family, /webquiz checker, mode/.initial = single, columns value/.initial = 1, columns/.style = {columns value=#1}, single/.style = {mode=single}, multiple/.style = {mode=multiple}, .unknown/.code = {\ERROR: invalid choice type: use single or multiple} comparison/.is choice, comparison/complex/.code = \relax, comparison/integer/.code = \relax, comparison/lowercase/.code = \relax, comparison/number/.code = \relax, comparison/string/.code = \relax, comparison/.unknown/.code = {\ERROR: invalid input type: use integer, string or eval} } % now process the options \ProcessPgfOptions{/WQ@ClassOptions}% process options \LoadClass[\unknown@options]{article}% load article class with options %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage{xparse} \RequirePackage{pgffor} % load Michal Hoftich's new tikz driver for tex4ht \ifWQ@Tikz \ifdefined\HCode \def\pgfsysdriver{pgfsys-dvisvgm4ht.def} \fi \fi \def\WQ@Error{\PackageError{webquiz}} \def\WQ@Debugging#1{\ifWQ@Debugging\typeout{Debugging: #1}\fi} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \RequirePackage{amsfonts,amsmath} \RequirePackage{bbding} \setlength{\parindent}{0pt} \setlength{\parskip}{10pt} % Macro to define a picture variant of \. The latex version does % nothing but the cfg version converts \ into an image \newcommand\DisplayAsImage[2][]{\relax} % Need to declare possible graphics extensions: see https://tex.stackexchange.com/questions/213461 % This is just placeholder - the real definition is used in the cfg file %\newcommand\DeclareGraphicsExtensions[1]{} % Macros for defining the university and department \newcommand*{\DepartmentURL}[1]{\def\WQ@departmentURL{#1}} \newcommand*{\Department}[1]{\def\WQ@department{#1}} % University/instution - university included for backwards compatibility \newcommand*{\InstitutionURL}[1]{\def\WQ@institutionURL{#1}} \newcommand*{\Institution}[1]{\def\WQ@institution{#1}} \newcommand*{\UniversityURL}[1]{\def\WQ@institutionURL{#1}} \newcommand*{\University}[1]{\def\WQ@institution{#1}} % Macros for defining the quiz web breadcrumbs using the unit code, name and % URL. The names of these macros are chosen so as to be compatible with the % in-house SMS package sms-uos.sty that specifies these for all units. \newcommand*\UnitCode[1]{\def\uos@code{#1}} \newcommand*\UnitName[1]{\def\uos@name{#1}} \newcommand*\UnitURL[1]{\def\uos@url{#1}} \newcommand*\QuizzesURL[1]{\def\WQ@quizzesUrl{#1}} \newcommand*\BreadCrumb[1]{\def\WQ@breadcrumb{#1}} \newcommand*\BreadCrumbs[1]{\def\WQ@breadcrumbs{#1}} % Default values - the university and department defaults can also be % set in the webquizrc file. The main purpose of these defaults is % to remind the user to set them. \UnitCode{Unit code?} \UnitName{Unit name?} \UnitURL{} \QuizzesURL{DeFaUlT} \BreadCrumb{} \BreadCrumbs{DeFaUlT} \Department{DeFaUlT} \DepartmentURL{DeFaUlT} \University{DeFaUlT} \UniversityURL{DeFaUlT} % Define page header and footer for the printable version of the quiz % to show the unit code information. \def\ps@quiz{\ps@empty \def\@oddhead{\hbox to\textwidth{% \uos@code\hss\textsc{\@title}\hss Page \thepage}}% \let\@evenhead=\@oddhead } \def\ps@firstpage{\ps@empty} \pagestyle{quiz} \def\@title{} \def\maketitle{\vspace*{10mm} \begin{center} {\large\textsc{\@title}}% \end{center} } \AtBeginDocument{ \maketitle% \def\title{\WQ@Error{\noexpand\title can only be used in the preamble}\@ehc} \thispagestyle{firstpage}% \ifdefined\HCode\else \textsc{WebQuiz} will process this quiz using \textbf{pst2pdf}. \fi \RequirePackage{tikz} } % ----------------------------------------------------------------------- % WebQuiz macros % Define \WQ@XXXStart and \WQ@XXXEnd macros to avoid code duplication % in webquiz.cfg. The following switches are used for syntax checking % ----------------------------------------------------------------------- % These are all for error checking... \newif\ifWQ@InFeedback \newif\ifWQ@InAnswer \newif\ifWQ@InChoice \newif\ifWQ@InDiscussion \newif\ifWQ@InItem \newif\ifWQ@InQuestion \newif\ifWQ@InQuizIndex \newif\ifWQ@InWhenright \newif\ifWQ@InWhenwrong % ----------------------------------------------------------------------- % the quizindex environment and \quiz macro % ----------------------------------------------------------------------- % the quiz counter keeps track of the question numbers in a quizindex environement \newcounter{quiz} \renewcommand\thequiz{\arabic{quiz}} \def\WQ@QuizStart{% \WQ@Debugging{Starting \noexpand\quiz...}% \ifWQ@InQuizIndex\else\WQ@Error{\noexpand\quiz must appear inside a quizindex environment}\fi% \refstepcounter{quiz}% increment the quiz counter for the URLs } \NewDocumentCommand\quiz{som}{% \WQ@QuizStart% \IfBooleanTF{#1}{\def\WQ@Quiz{}}{\def\WQ@Quiz{Quiz~\thequiz.\space}}% \IfNoValueTF{#2}{\def\WQ@url{quiz\thequiz.html}}{\def\WQ@url{#2}}% \leavevmode\medskip\newline% \WQ@Quiz #3\newline% \phantom{Quiz 10}\textit{URL}:\quad \WQ@url% } \def\WQ@QuizIndexStart{% \WQ@Debugging{Starting quizindex...}% \ifWQ@InQuestion\WQ@Error{quizindex cannot appear in a question environment}\fi% \ifWQ@InDiscussion\WQ@Error{quizindex environments cannot be inside a discussion environment}\fi \ifWQ@InQuizIndex\WQ@Error{quizindex environments cannot be nested}\fi% \global\WQ@InQuizIndextrue% here, and below, using \global is probably overkill... } \def\WQ@QuizIndexEnd{\global\WQ@InQuizIndexfalse\WQ@Debugging{Ending quizindex...}} \newenvironment{quizindex}{\WQ@QuizIndexStart\bigskip}{\WQ@QuizIndexEnd} % ----------------------------------------------------------------------- % discussion environment % ----------------------------------------------------------------------- \newcounter{discussion} % \begin{dicussion}[short title][title -default-> Discussion] \def\WQ@DiscussionStart{% \WQ@Debugging{Starting discussion...}% \ifWQ@InDiscussion\WQ@Error{discussion environments cannot be nested}\fi% \ifWQ@InQuestion\WQ@Error{discussion environments cannot be inside a question environment}\fi% \ifWQ@InQuizIndex\WQ@Error{discussion environments cannot be inside a quizindex environment}\fi% \global\WQ@InDiscussiontrue% \refstepcounter{discussion}% } \def\WQ@DiscussionEnd{\global\WQ@InDiscussionfalse\WQ@Debugging{Ending discussion...}} \NewDocumentEnvironment{discussion}{O{Discussion}O{#1}} {\WQ@DiscussionStart\textbf{#1} (#2)}{\WQ@DiscussionEnd\par\bigskip} % --------------------------------------------------------------------------- % Cross referencing question and discussion environments % --------------------------------------------------------------------------- % \WQ@Ref{+ or -}[optional *][optional text]{mandatory label} \NewDocumentCommand\WQ@ref{ m s o m }{% \fbox{\IfBooleanTF{#2}{link}{button} to \IfNoValueTF{#3}{to #1 \ref{#4}}{ to ``#3'' (#1 \ref{#4})}}% } \newcommand\dref{\WQ@ref{discussion}} \newcommand\qref{\WQ@ref{question}} \newcommand\Qref{\WQ@ref{question number}} % ----------------------------------------------------------------------- % question environment % ----------------------------------------------------------------------- % the question counter keeps track of the quiz question numbers \newcounter{question} \def\WQ@QuestionStart{% \WQ@Debugging{Starting question...}% \ifWQ@InDiscussion\WQ@Error{question environments cannot be inside a discussion environment}\fi% \ifWQ@InQuizIndex\WQ@Error{question environments cannot be inside a quizindex environment}\fi% \ifWQ@InQuestion\WQ@Error{question environments cannot be nested!}\fi% \global\WQ@InAnswerfalse% \global\WQ@InChoicefalse% \global\WQ@InChoicefalse% \global\WQ@InItemfalse% \global\WQ@InQuestiontrue% \global\WQ@InFeedbackfalse% \global\WQ@InWhenrightfalse% \global\WQ@InWhenwrongfalse% \refstepcounter{question}% } \def\WQ@QuestionEnd{ \ifWQ@InChoice\else\ifWQ@InAnswer\else% \WQ@Error{Each question must contain a choice environment or an \noexpand\answer!}% \fi\fi% \global\WQ@InQuestionfalse% \WQ@Debugging{Ending question...}% } \newenvironment{question}{\WQ@QuestionStart\bigskip\textbf{Question \arabic{question}.\newline}} {\par\bigskip\WQ@QuestionEnd} % ----------------------------------------------------------------------- % choice environment, \correct and \incorrect choices and \feedback % ----------------------------------------------------------------------- % the choice counter keeps track of the choices in a choice environment \newcounter{choice} \renewcommand\thechoice{(\alph{choice})} \def\WQ@ChoiceStart#1{% \WQ@Debugging{Starting choice...}% \ifWQ@InQuestion\relax% Give a warning if we are not inside a question \else\WQ@Error{Choice environments must be contained in a question}% \fi% \ifWQ@InAnswer\WQ@Error{choice environments cannot contain an \noexpand\answer!}\fi% \ifWQ@InChoice\WQ@Error{choice environments cannot be nested}\fi% \global\WQ@InChoicetrue% \global\WQ@InItemfalse% \pgfkeys{/webquiz checker, #1}% \setcounter{choice}{0}% reset choice counter } \def\WQ@ChoiceEnd{% \ifWQ@InItem\else\WQ@Error{Choice environment with no choices!}\fi% \WQ@InChoicefalse% \WQ@Debugging{Ending choice...}% } % \begin{choice}[choice type, number of columns] ... \end{choice} The % allowed choice types are "single" or "multiple". The type and number % of columns is allowed to appear in either order, so most of the fun % and games below is sanity checking of the argunments. \NewDocumentEnvironment{choice}{O{single}}{% \WQ@ChoiceStart{#1}% \leavevmode\newline% % (\textit{The choices will be printed in \pgfkeys{/webquiz checker/columns value} columns in the HTML version of the quiz})% \par% \setcounter{choice}{0}% }{\WQ@ChoiceEnd} \def\WQ@ItemStart{% \WQ@Debugging{Starting item...}% \ifWQ@InChoice\relax% \else\WQ@Error{\noexpand\correct and \noexpand\incorrect must be inside a choice environment}% \fi% \global\WQ@InItemtrue\global% \WQ@InFeedbackfalse% \refstepcounter{choice}% } \def\WQ@Item#1{\WQ@ItemStart\par\bigskip #1\quad\textit{Option} \thequestion\thechoice:\qquad} \def\correct{\WQ@Item\CheckmarkBold} \def\incorrect{\WQ@Item\XSolidBrush} \def\WQ@FeedbackStart{% \WQ@Debugging{Starting feedback...}% \ifWQ@InItem\relax% \else\WQ@Error{Missing \noexpand\correct or \noexpand\incorrect}% \fi% \ifWQ@InFeedback\WQ@Error{Only one feedback per option is allowed!}\fi% \WQ@InFeedbacktrue% } \def\feedback{\WQ@FeedbackStart\leavevmode\medskip\newline\textit{Feedback:}\space} % ----------------------------------------------------------------------- % The \answer macro and the feedback macros \whenRight, \whenWrong % ----------------------------------------------------------------------- % supported answer comparisons \def\WQ@AnswerStart#1{% \WQ@Debugging{Starting answer...}% \ifWQ@InQuestion\relax% \else\WQ@Error{\noexpand\answer\ must be contained in a question}% \fi% \ifWQ@InChoice\WQ@Error{You cannot have \noexpand\answer inside a choice environment}\fi% \ifWQ@InAnswer\WQ@Error{Each question can contain only one \noexpand\answer command}\fi% \pgfkeys{/webquiz checker/comparison/#1}% \global\WQ@InAnswertrue% \global\WQ@InWhenrightfalse% \global\WQ@InWhenwrongfalse% } \NewDocumentCommand\answer{s O{string} m}{% \WQ@AnswerStart{#2}% \leavevmode\bigskip\newline% \IfBooleanTF{#1}{\fbox{\textit{(#2 comparison):}\quad#3}}% {\fbox{\textit{Answer (#2 comparison):}\quad#3}}% } \def\WQ@WhenStart#1{% \WQ@Debugging{Starting when#1...}% \ifWQ@InAnswer\relax\else\WQ@Error{missing \noexpand\answer}\fi% \ifbool{WQ@InWhen#1}{% \WQ@Error{Only one \noexpand\when#1 per question is allowed!}% }{}% \global\booltrue{WQ@InWhen#1}% } \def\WQ@When#1{\WQ@WhenStart{#1}\leavevmode\medskip\newline\textit{Feedback when #1:}\space} \def\whenRight{\WQ@When{right}} \def\whenWrong{\WQ@When{wrong}} \endinput %% End of file `webquiz.cls'.