%\iffalse % makeindex -s gglo.ist -o pmdb.gls pmdb.glo % makeindex -s gind.ist -o pmdb.ind pmdb.idx %<*copyright> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% pmdb.sty package,, %% %% Copyright (C) 2019 D. P. Story %% %% dpstory@uakron.edu dpstory@acrotex.net %% %% %% %% This program can redistributed and/or modified under %% %% the terms of the LaTeX Project Public License %% %% Distributed from CTAN archives in directory %% %% macros/latex/base/lppl.txt; either version 1.2 of the %% %% License, or (at your option) any later version. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %\NeedsTeXFormat{LaTeX2e} %\ProvidesPackage{pmdb} % \ProvidesPackage{pmdb}[2019/12/09 v0.4 Mark for input files] %<*driver> \documentclass{ltxdoc} \usepackage[colorlinks,hyperindex=false,linktocpage,bookmarksnumbered]{hyperref} \usepackage{calc} %\def\texorpdfstring#1#2{#1} %\pdfstringdefDisableCommands{\let\\\textbackslash} \OnlyDescription % comment out for implementation details \EnableCrossrefs \CodelineIndex \RecordChanges \gdef\brpr#1{\texttt{\char123\relax#1\char125\relax}} \let\darg\brpr \let\env\texttt \let\opt\texttt \let\app\textsf \let\pkg\textsf \let\uif\textsf \let\tops\texorpdfstring \def\EXCL{!} \def\nmpsep#1{\hskip-\marginparsep\texttt{#1}} \def\visispace{\symbol{32}} \def\ameta#1{\ensuremath{\langle\textit{\texttt{#1}}\rangle}} \def\meta#1{\textsl{\texttt{#1}}} \def\SUB#1{\ensuremath{{}_{\mbox{\scriptsize\ttfamily#1}}}} \def\CMD#1{\textbackslash#1} \makeatletter \renewcommand{\paragraph} {\@startsection{paragraph}{4}{0pt}{6pt}{-3pt}{\bfseries}} \renewcommand{\subparagraph} {\@startsection{subparagraph}{5}{\parindent}{6pt}{-3pt}% {\normalfont\normalsize\bfseries}} \makeatother \InputIfFileExists{aebdocfmt.def}{\PackageInfo{pmdb}{Inputting aebdocfmt.def}} {\def\IndexOpt{\DescribeMacro}\def\IndexKey{\DescribeMacro}\let\setupFullwidth\relax \PackageInfo{pmdb}{aebdocfmt.def cannot be found}} \begin{document} \addtolength{\marginparwidth}{3pt} \GetFileInfo{pmdb.sty} \title{The \textsf{pmdb} Package} \author{D. P. Story\\ Email: \texttt{dpstory@acrotex.net}} \date{processed \today} \maketitle \setcounter{secnumdepth}{5} \setcounter{tocdepth}{5} \bgroup \value{secnumdepth}=3 \value{tocdepth}=3 \tableofcontents \egroup \DocInput{pmdb.dtx} \IfFileExists{\jobname.ind}{\newpage\setupFullwidth\par\PrintIndex} {\paragraph*{Index} The index goes here. Execute \begin{quote}\texttt{makeindex -s gind.ist -o pmdb.ind pmdb.idx}\end{quote} on the command line and recompile \texttt{pmdb.dtx}.} \IfFileExists{\jobname.gls}{\PrintChanges} {\paragraph*{Change History} The list of changes goes here. Execute \begin{quote} \texttt{makeindex -s gglo.ist -o pmdb.gls pmdb.glo} \end{quote} on the command line and recompile \texttt{pmdb.dtx}.} \end{document} % % \fi % \MakeShortVerb{|} % \InputIfFileExists{aebdonotindex.def}{\PackageInfo{web}{Inputting aebdonotindex.def}} % {\PackageInfo{web}{cannot find aebdonotindex.def}} % \begin{macrocode} %<*package> % \end{macrocode} % % \section{Introduction} % This package addresses the issue of a poor-man's database. Educators who use {\LaTeX} to construct % exams and homework sometimes have a collection of problems. Each problem is in its own TEX file. The educator % creates a document and \cs{inputs} several of these packaged questions. This package attempts to provide some % ``user interface'' to the questions and provides a mechanism of selecting which questions are to be included in the % document. % %\paragraph*{What does this package do?} For a document that inputs content using the {\LaTeX} command \cs{input}, %the same content can be input using the command \cs{pmInput} (capitalized). When content is input by \cs{pmInput}, a check %box is created in the margin at the insertion point of the content. The check boxes so created can be checked or cleared. %When the user clicks on push button provided by this package, a list of all \emph{selected} \cs{input} statements are listed %in the JavaScript console. This list can then be copied and pasted into another document the author is developing. If you %\uif{Ctrl+Click} on a check box, the associated content is opened in the default TEX editor. In this way, the document author %can see a typeset of the content and decide whether the content should be included in the developing document. % %\paragraph*{The DB stage:} When you have a collection of questions (or content) in various files and want to use %this package to \cs{input} them into your document, the following comments are apropos: % %\subparagraph*{PDF creators:} Any PDF creator current in the {\LaTeX} world is valid for use with this package. % %\subparagraph*{PDF viewers:} %The ideal viewer is \app{Acrobat}, however, \app{Adobe Reader} and \app{PDF-XChange Editor} can also be used. %In the case of \app{Adobe Reader}, there is an annoying security dialog box that appears each time you use the %\uif{Ctrl+Click} feature of the check box; the \uif{Ctrl+Click} feature does not WORK with \app{PDF-XChange Editor}. % %\paragraph*{The production stage:} After the document has been assembled (using \pkg{pmdb}), and you build your final document %(perhaps an \pkg{exerquiz} quiz), the end user can use an appropriate PDF reader. If an \pkg{exerquiz} quiz is used, then %a minimum of \app{Adobe Acrobat Reader} is required. % \section{The main code} % \begin{macrocode} \edef\th@dquoteCat{\the\catcode`\"} \catcode`\"=12\relax \newif\ifpmdbmode \pmdbmodetrue % \end{macrocode} %\subsection{Package options and package requirements} % %\leavevmode\IndexOpt{dbmode} The default option is \opt{dbmode}. When in effect, check boxes %appear in the margins at each \cs{pmInput} point. % \begin{macrocode} \DeclareOption{dbmode}{\pmdbmodetrue} % \end{macrocode} %\leavevmode\IndexOpt[\protect\EXCL]{!dbmode} A convenient way to turn off the creation of the check boxes %is to simply place an exclamation point (!) in front of the \opt{dbmode} option. % \begin{macrocode} \DeclareOption{!dbmode}{\pmdbmodefalse} % \end{macrocode} %\leavevmode\IndexOpt{tight} When this option is taken, the checkboxes are tight against the text box %area. % \begin{macrocode} \newif\ifpmdbtight \pmdbtightfalse \DeclareOption{tight}{\pmdbtighttrue} % \end{macrocode} %\leavevmode\IndexOpt[\protect\EXCL]{!tight} The default for the package, the checkboxes are placed %to extreme left (or right) in the margins. % \begin{macrocode} \DeclareOption{!tight}{\pmdbtightfalse} \ProcessOptions \RequirePackage{eforms} % \end{macrocode} %\subsection{Special attention to Thor} % One motivation for this package is to support the \pkg{thorshammer} package, to that end % we make the following assignment, if Thor is not present. % This is to prevent stoppage: % if your are inputting a \cs{RespBoxEssay} question that is accompanied by the % \cs{essayQ} command, defined in \pkg{thorshammer}.\medskip % \begin{macrocode} \def\pmdb@ckThor{\@ifundefined{essayQ}{\let\essayQ\@gobble}{}} \AtBeginDocument{\pmdb@ckThor} % \end{macrocode} %\subsection{Form field creation} % \textbf{Some Booleans and counters} % \begin{macrocode} \newif\ifpmdbFP \pmdbFPfalse \newif\ifpmdbDQs \pmdbDQsfalse \newcount\pmdb@Cnt % \end{macrocode} % %\subsubsection{Check box creation} % %\DescribeMacro\cbSelectInput\nmpsep{\darg{\ameta{path}}} creates a check box with a tool tip of \ameta{path} %The mouse up action \cs{ccBoxMU} fixes up relative paths, and defines a \uif{Ctrl+Click} action. When the check box %is so clicked, the \ameta{path} is opened in the default TEX editor. The \ameta{path} can be relative or absolute. %This command is used within \cs{insertCkBx}; its \ameta{path} argument is passed to it from \cs{insertCkBx}. % \begin{macrocode} \def\pmCBPresets#1{\def\pm@CBPresets{#1}} \pmCBPresets{} \def\cbSelectInput#1{\checkBox[\TU{#1}\presets{\pm@CBPresets} \cmd{\bParams{#1}{\the\pmdb@Cnt}\eParams} \AAmouseup{\ccBoxMU} ]{pmdbCkBx.\the\pmdb@Cnt}{11bp}{11bp}{On}% \global\advance\pmdb@Cnt\@ne} % \end{macrocode} %\leavevmode\DescribeMacro\insertCkBx\nmpsep{\darg{\ameta{method}}} The argument of this macro describes the method %of inserting the checkbox. The default definition works well for a straightforward document, where you are inputting %ordinary {\LaTeX} code (such as sections or chapters).\smallskip % \begin{macrocode} \def\insertCkBx#1{\def\@insertCkBx##1{#1}} % \end{macrocode} % Placement of check boxes in the margin. \DescribeMacro\pmAlignCB\cs{pmAlignCB} controls the marginpar placement. % \DescribeMacro\normalCBMargins\cs{normalCBMargins} places it according to the rules of \cs{marginpar}; % \DescribeMacro\altCBMargins\cs{altCBMargins} alternates the margin placement, forces the check box to the % extreme left (on odd pages) and extreme right (on even pages). % \begin{macrocode} \def\setCBsMarg{% \ifpmdbtight \if@reversemargin \def\pmAlignCBAlt{\ifodd\value{page}\leavevmode\hfill\else\fi}\else \def\pmAlignCBAlt{\ifodd\value{page}\else\hfill\fi}\fi \else \if@reversemargin \def\pmAlignCBAlt{\ifodd\value{page}\hfil\else\hfil\fi}\else \def\pmAlignCBAlt{\ifodd\value{page}\hfill\else\fi}\fi \fi } \def\altCBMargins{\let\pmAlignCB\pmAlignCBAlt} \def\pmAlignCB{% \if@reversemargin \ifpmdbtight\hfill\else\fi \else \ifpmdbtight\else\hfill\fi \fi } \@ifundefined{chapter}{}{\AtBeginDocument{\setCBsMarg\altCBMargins}} % \end{macrocode} % This is the default declaration. It works well when you are inputting content % that goes into horizontal mode. We insert the check box at the beginning of the % first paragraph. When you are inputting files that come into a list environment, this method % does not work satisfactory.\medskip\par\noindent %\DescribeMacro\InputParas declares that the next \cs{pmInput} macros are for paragraph content. %This is the default state of the package. %\par\medskip %\paragraph*{pmInput states} % \begin{macrocode} \def\InputParas{%\let\pmAlignCB\relax \insertCkBx{\ifpmdbmode \everypar{\marginpar{\pmAlignCB\cbSelectInput{##1}}\global\everypar{}}\fi}} \InputParas % \end{macrocode} %\leavevmode %\DescribeMacro\InputQuizItems declares that the next \cs{pmInput} macros are for items in %a \env{quiz} environment of \pkg{exerquiz} %\changes{v0.4}{2019/12/09}{Modified to work when no points are specified} % \begin{macrocode} \newcount\saveQNo \saveQNo\z@ \def\pmHook@qzItems{% \let\item@pmOld\item \def\item@pnNew{\item@pmOld\itemhook\let\item\item@pmOld}% \let\item\item@pnNew} \def\InputQuizItems{\let\pmHook\pmHook@qzItems \saveQNo\z@ \insertCkBx{\def\cbInQzMargin{\cbSelectInput{##1}}}% \ItemHook{\leavevmode\ifpmdbmode \ifnum\saveQNo<\value{eqquestionnoi}% \marginpar{\pmAlignCB\cbInQzMargin}\fi \saveQNo=\arabic{eqquestionnoi}\fi}} % \end{macrocode} %\leavevmode %\DescribeMacro\InputItems declares that the next \cs{pmInput} macros are for items in %an list environment 2019/12/09 v0.4 %\changes{v0.4}{2019/12/09}{Added \string\cs{InputItems}} % \begin{macrocode} \def\pmHook@item{\let\item@pmOld\item \def\item@pmNew{% \ifx\pmiarg\@empty \ifx\pm@Brk\ef@YES \def\pm@next{\item@pmOld[]}\else \let\pm@next\item@pmOld \fi \else \def\pm@next{\item@pmOld[\pmiarg]}% \fi\pm@next\itemhook\let\item\item@pmOld}% \let\item\item@pmNew } \def\ItemHook#1{\def\itemhook{#1}} \def\InputItems{\let\pmHook\pmHook@item \insertCkBx{\def\cbInQzMargin{\cbSelectInput{##1}}}% \ItemHook{\leavevmode\ifpmdbmode \marginpar{\pmAlignCB\cbInQzMargin}\fi}} % \end{macrocode} %\paragraph*{Place check box and input \ameta{path}}\leavevmode\par\medskip %\noindent %\DescribeMacro\ckBxInput\nmpsep{\darg{\ameta{path}}} Places the check box and inputs the \ameta{path}. % \begin{macrocode} \let\pmHook\relax \def\ckBxInput#1{\@insertCkBx{#1}% \ifpmdbDQs\def\donext{\pmHook\input{"#1"}}\else \def\donext{\pmHook\input{#1}}\fi \donext} % \end{macrocode} %\subsubsection{Push button creation} %This package provides two form fields that are used for the DB step.\par\medskip %\noindent %\DescribeMacro\displayChoices\nmpsep{[\ameta{options}]\darg{\ameta{wd}}\darg{\ameta{ht}}} inserts a push button %whose action is to display the selections in the console window. The argument \ameta{wd} can be empty, in which %case, the width of the field is determined from the \cs{CA} key. % \begin{macrocode} \def\displayChoiceCA#1{\def\displayChoice@CA{#1}} \def\displayChoiceTU#1{\def\displayChoice@TU{#1}} \displayChoiceCA{Display Choices} \displayChoiceTU{Lists all choices in the console window} \newcommand{\displayChoices}[3][]{\pushButton[\TU{\displayChoice@TU} \CA{\displayChoice@CA}#1\AAmouseup{\sldInputs}\protect\AA ]{sldInputs}{#2}{#3}} % \end{macrocode} %\DescribeMacro\clrChoices\nmpsep{[\ameta{options}]\darg{\ameta{wd}}\darg{\ameta{ht}}} inserts a push button % whose action is to clear all check boxes (and underlying JavaScript variables) created by this package. % The argument \ameta{wd} can be empty, in which % case, the width of the field is determined from the \cs{CA} key. % \begin{macrocode} \def\clrChoicesCA#1{\def\clrChoices@CA{#1}} \def\clrChoicesTU#1{\def\clrChoices@TU{#1}} \clrChoicesCA{Clear Choices} \clrChoicesTU{Clears all check boxes created by pmdb} \newcommand{\clrChoices}[3][]{\pushButton[\TU{\clrChoices@TU} \CA{\clrChoices@CA}#1\AAmouseup{\clrAction}\protect\AA ]{sldInputs}{#2}{#3}} % \end{macrocode} % %\subsection{Defining the \cs{pmInput} command} % %\DescribeMacro\pmInput\nmpsep{[\ameta{arg}]\darg{\ameta{path}}} is the main user-interface for inputting a file; here, %the macros name is \cs{pmInput}, ultimately it calls \cs{input} with the same path. Paths with spaces %must be enclosed in double quotes (|\pmInput{my cool problem.tex}|) and the extensions must always be used. % \begin{macrocode} \def\pmInput{\@ifnextchar[%] {\let\pm@Brk\ef@YES\inputConta} {\let\pm@Brk\ef@NO\inputConta}} \let\pm@Brk\ef@NO \def\inputConta{\bgroup\@makeother\"\inputContb} \newcommand\inputContb[2][]{\egroup\def\pmiarg{#1}\inputConti#2;;} % \end{macrocode} % Determine if double quotation marks are used. % \begin{macrocode} \def\inputConti{\@ifnextchar"% {\global\pmdbDQstrue\removedqs} {\global\pmdbDQsfalse\removesemis}} \def\removedqs"#1";;{\inputContii{#1}} \def\removesemis#1;;{\inputContii{#1}} % \end{macrocode} % Determine if this is a full path, we do this by searching for a colon (\texttt:). % Following the search for the colon, pass on to the final step of \cs{doinput}. % \begin{macrocode} \def\inputContii#1{\isItFullPath#1:\@nil\doinput{#1}} % \end{macrocode} % A command to detect presence of a colon. % \begin{macrocode} \def\isItFullPath#1:#2\@nil{% \def\@rgii{#2}\ifx\@rgii\@empty \global\pmdbFPfalse\else \global\pmdbFPtrue\fi} % \end{macrocode} % Final step, if the switch \cs{ifpmdbmode} is true, we insert the check box % \cs{ckBxInput}; otherwise, we pass \ameta{path} to \cs{input}. % \begin{macrocode} \def\doinput#1{\ifpmdbmode\def\donext{\ckBxInput{#1}}\else \ifpmdbDQs\def\donext{\input{"#1"}}\else \def\donext{\input{#1}}\fi\fi \donext} % \end{macrocode} % During the development of this package, the original command name used was \cs{Input}. % There are a few users that use this old definition; the command \cs{Input} is defined % in other package, in particular in the \pkg{srcltx}. So we allow the use of \cs{Input} % if \cs{Input} is not otherwise defined. % \begin{macrocode} \def\pmInputWarni{\PackageWarningNoLine{pmdb}{The command \string\Input\space is already defined.\MessageBreak The checkboxes may not appear in the margins.\MessageBreak Use the supported command \string\pmInput\space instead}} \def\pmInputWarnii{\PackageWarningNoLine{pmdb}{Letting \string\Input\space to \string\pmInput. You are \MessageBreak encouraged to use the supported\MessageBreak command \string\pmInput\space instead}} \def\pmInputChk{\@ifundefined{Input}{\let\Input\pmInput\pmInputWarnii} {\pmInputWarni}} \AtBeginDocument{\pmInputChk} % \end{macrocode} % % \section{Field JavaScript} % \leavevmode %\DescribeMacro\ccBoxMU % This is the JavaScript action of the check box, used in \cs{cbSelectInput} % \begin{macrocode} \begin{defineJS}[\makeesc\@\catcode`\%=14\relax]{\ccBoxMU} @ifpmdbFP% event.target.userName=("@p(1)"); @else% % \end{macrocode} % This part of the code is Windows specific. Don't know enough about Mac OS % to form the proper path. % \begin{macrocode} // device independent path var pos=this.path.lastIndexOf("/"); var thispath=this.path.substring(0,pos+1); % \end{macrocode} % \enspace\verb|//user/documents/.../myfolder/| % \begin{macrocode} pos=this.path.indexOf("/",1); var drive=thispath.substring(0,pos); var platform=app.platform; if (platform=="WIN") % \end{macrocode} % \hskip\parindent\enspace\verb|/:/user/documents/.../myfolder/| % \begin{macrocode} thispath=drive+":/"+thispath.substring(pos+1); event.target.userName=thispath+("@p(1)"); @fi% if (event.modifier){ var _to=app.setTimeOut("_restoreCCState('pmdbCkBx.@p(2)');",.05); try { aebTrustedFunctions(this,aebLaunchURL, {cURL: "file://"+event.target.userName}); } catch(e) { console.show(); console.println("The Ctrl+Click action is not supported, % installation of aeb\_pro.js is required."); } } else { if (event.target.isBoxChecked(0)){ _oSPaths["pmdbCkBx.@p(2)"]=% [("@p(1)"),@ifpmdbDQs true@else false@fi]; _aInputs[@p(2)]=true; _numInputs++; }else{ _oSPaths["pmdbCkBx.@p(2)"]=null; _aInputs[@p(2)]=false; _numInputs--; } event.target["_boxState"]=!!event.target.isBoxChecked(0); } \end{defineJS} % \end{macrocode} %\leavevmode %\DescribeMacro\sldInputs % This is the mouse up action for a push button. It lists all selected content % and displays them in the console window of \app{Acrobat/Reader}, used in % \cs{displayChoices}. % \begin{macrocode} \begin{defineJS}[\catcode`\%=14\relax]{\sldInputs} console.clear();console.show(); if (_numInputs==0) console.println("No inputs selected"); else { for(var i=0;i<_aInputs.length;i++){ if (!!_aInputs[i]){ if(_oSPaths["pmdbCkBx."+i][1]) console.println(% '\\\\input\{\\"'+(_oSPaths["pmdbCkBx."+i][0])+'\\"\}'); else console.println(% '\\\\input\{'+(_oSPaths["pmdbCkBx."+i][0])+'\}'); } } } \end{defineJS} % \end{macrocode} %\leavevmode %\DescribeMacro\clrAction % Mouse up action to clear the check boxes and to re-initialize internal % internal JS variables. Used in \cs{clrChoices}. % \begin{macrocode} \begin{defineJS}{\clrAction} var _oSPaths=new Object; var _aInputs=new Array; var _numInputs=0; this.resetForm("pmdbCkBx"); \end{defineJS} % \end{macrocode} % \section{Document JavaScript} % \begin{macrocode} \begin{insDLJS}{mrki}{Supporting JavaScript for pmdb} var _oSPaths=new Object; var _aInputs=new Array; var _numInputs=0; function _restoreCCState(fName){ var f=this.getField(fName); var _ccState=% (typeof f["_boxState"]=="undefined")?false:f["_boxState"]; f["_boxState"]=_ccState; return f.checkThisBox(0,_ccState); } \end{insDLJS} % \end{macrocode} % \begin{macrocode} \catcode`\"=\th@dquoteCat % % \end{macrocode} %\Finale