#############################################################################
##
#W GAPDoc2HTML.gi GAPDoc Frank Lübeck
##
##
#Y Copyright (C) 2000, Frank Lübeck, Lehrstuhl D für Mathematik,
#Y RWTH Aachen
##
## The files GAPDoc2HTML.g{d,i} contain a conversion program which
## produces from a GAPDoc XML-document an HTML version for reading the
## document with a Web-browser.
##
## REMARKS:
##
## We add to all nodes of the parse tree an entry .root which points to
## the document root. The toc-, index- and bib-information is collected
## in the root.
##
## The set of elements is partitioned into two subsets - those which
## contain whole paragraphs and those which don't.
##
## The handler of a paragraph containing element (see
## GAPDoc2HTMLProcs.ParEls below) gets a list as argument to which it
## adds entries pairwise: the first of such a pair is the paragraph
## counter (like [3,2,1,5] meaning Chap.3, Sec.2, Subsec.1, Par.5) and
## the second is the formatted text of this paragraph.
##
## Some handlers of paragraph containing elements do the formatting
## themselves (e.g., .List), the others are handled in the main recursion
## function `GAPDoc2HTMLContent'.
##
## We produce a full version of the document in HTML format, including
## title page, abstract and other front matter, table of contents,
## bibliography (via BibTeX-data files) and index. For this we have to
## process a document twice (similar to LaTeX).
##
## Small utility to throw away SGML markup
BindGlobal(
"FilterSGMLMarkup",
function(str)
local p2, p1, res;
p2 := Position(str,
'<');
if p2 = fail
then
return str;
fi;
p1 :=
0;
res :=
"";
while p2 <> fail
do
Append(res, str{[p1+
1..p2-
1]});
p1 := Position(str,
'>', p2);
if p1 = fail
then
return res;
fi;
p2 := Position(str,
'<', p1);
if p2 = fail
then
Append(res, str{[p1+
1..Length(str)]});
return res;
fi;
od;
end);
InstallValue(GAPDoc2HTMLProcs, rec());
## Some text attributes ([begin, end] pairs)
GAPDoc2HTMLProcs.TextAttr := rec();
GAPDoc2HTMLProcs.TextAttr.Heading := [
"<span class=\"Heading\
">",
"</span>"];
GAPDoc2HTMLProcs.TextAttr.Func := [
"<code class=\"func\
">",
"</code>"];
GAPDoc2HTMLProcs.TextAttr.Arg := [
"<var class=\"Arg\
">",
"</var>"];
GAPDoc2HTMLProcs.TextAttr.Example := [
"<div class=\"Example\
">",
"</div>"];
GAPDoc2HTMLProcs.TextAttr.Package := [
"<strong class=\"pkg\
">",
"</strong>"];
GAPDoc2HTMLProcs.TextAttr.URL := [
"<span class=\"URL\
">",
"</span>"];
GAPDoc2HTMLProcs.TextAttr.Mark := [
"<strong class=\"Mark\
">",
"</strong>"];
GAPDoc2HTMLProcs.TextAttr.K := [
"<code class=\"keyw\
">",
"</code>"];
GAPDoc2HTMLProcs.TextAttr.C := [
"<code class=\"code\
">",
"</code>"];
GAPDoc2HTMLProcs.TextAttr.F := [
"<code class=\"file\
">",
"</code>"];
GAPDoc2HTMLProcs.TextAttr.I := [
"<code class=\"i\
">",
"</code>"];
GAPDoc2HTMLProcs.TextAttr.B := [
"<strong class=\"button\
">",
"</strong>"];
GAPDoc2HTMLProcs.TextAttr.Emph := [
"<em>",
"</em>"];
GAPDoc2HTMLProcs.TextAttr.Ref := [
"<span class=\"RefLink\
">",
"</span>"];
GAPDoc2HTMLProcs.TextAttr.M := [
"<span class=\"SimpleMath\
">",
"</span>"];
GAPDoc2HTMLProcs.TextAttr.Math := [
"<span class=\"Math\
">",
"</span>"];
GAPDoc2HTMLProcs.TextAttr.GAPprompt :=
[
"<span class=\"GAPprompt\
">",
"</span>"];
GAPDoc2HTMLProcs.TextAttr.GAPbrkprompt :=
[
"<span class=\"GAPbrkprompt\
">",
"</span>"];
GAPDoc2HTMLProcs.TextAttr.GAPinput :=
[
"<span class=\"GAPinput\
">",
"</span>"];
# like in Text converter, but a heading and an address are not a paragraph here
GAPDoc2HTMLProcs.ParEls :=
[
"Display",
"Example",
"Log",
"Listing",
"List",
"Enum",
"Item",
"Table",
"TitlePage",
"Abstract",
"Copyright",
"Acknowledgements",
"Colophon",
"TableOfContents",
"Bibliography",
"TheIndex",
"Subsection",
"ManSection",
"Description",
"Returns",
"Section",
"Chapter",
"Appendix",
"Body",
"Book",
"WHOLEDOCUMENT",
"Attr",
"Fam",
"Filt",
"Func",
"InfoClass",
"Meth",
"Oper",
"Constr",
"Prop",
"Var",
"Verb"];
## arg: a list of strings
## for now only ??????
SetGapDocHTMLOptions :=
function(arg)
local gdp;
gdp := GAPDoc2HTMLProcs;
return;
end;
GAPDoc2HTMLProcs.Head1 :=
"\
<?xml version=\
"1.0\" encoding=\
"UTF-8\"?>\n\
\n\
<!DOCTYPE html PUBLIC \
"-//W3C//DTD XHTML 1.0 Strict//EN\"\n\
\
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\
\n\
<html xmlns=\
"http://www.w3.org/1999/xhtml\" xml:lang=\
"en\">\n\
<head>\n\
<title>GAP (
";
GAPDoc2HTMLProcs.MathJaxURL :=
"https://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
GAPDoc2HTMLProcs.Head1MathJax :=
"\
<?xml version=\
"1.0\" encoding=\
"UTF-8\"?>\n\
\n\
<!DOCTYPE html PUBLIC \
"-//W3C//DTD XHTML 1.0 Strict//EN\"\n\
\
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\
\n\
<html xmlns=\
"http://www.w3.org/1999/xhtml\" xml:lang=\
"en\">\n\
<head>\n\
<script type=\
"text/javascript\"\n\
src=\
"MATHJAXURL\">\n\
</script>\n\
<title>GAP (
";
GAPDoc2HTMLProcs.Head1Trans :=
"\
<?xml version=\
"1.0\" encoding=\
"UTF-8\"?>\n\
\n\
<!DOCTYPE html PUBLIC \
"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n\
\
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\
\n\
<html xmlns=\
"http://www.w3.org/1999/xhtml\" xml:lang=\
"en\" lang=\
"en\">\n\
<head>\n\
<title>GAP (
";
GAPDoc2HTMLProcs.Head1MML :=
"\
<?xml version=\
"1.0\" encoding=\
"UTF-8\"?>\n\
<?xml-stylesheet type=\
"text/xsl\" href=\
"mathml.xsl\"?>\n\
\n\
<!DOCTYPE html PUBLIC \
"-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN\"\n\
\
"http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd\" [\n\
<!ENTITY mathml \
"https://www.w3.org/1998/Math/MathML\">\n\
] >\n\
\n\
<html xmlns=\
"http://www.w3.org/1999/xhtml\" xml:lang=\
"en\">\n\
<head>\n\
<link rel=\
"stylesheet\" type=\
"text/css\" href=\
"mathml.css\" />\n\
<title>GAP (
";
GAPDoc2HTMLProcs.Head2 :=
"\
</title>\n\
<meta http-equiv=\
"content-type\" content=\
"text/html; charset=UTF-8\" />\n\
<meta name=\
"generator\" content=\
"GAPDoc2HTML\" />\n\
<link rel=\
"stylesheet\" type=\
"text/css\" href=\
"manual.css\" />\n\
<script src=\
"manual.js\" type=\
"text/javascript\"></script>\n\
<script type=\
"text/javascript\">overwriteStyle();</script>\n\
</head>\n<body onload=\
"jscontent()\">\n
";
GAPDoc2HTMLProcs.Tail :=
"\n\
<hr />\n\
<p class=\
"foot\">generated by <a \
href=\
"https://www.math.rwth-aachen.de/~Frank.Luebeck/GAPDoc\">GAPDoc2HTML\
</a></p>\
\n</body>\n</html>\n
";
GAPDoc2HTMLProcs.PutFilesTogether :=
function(l, r)
local files, n, tt, i, chnrs, chlink, prev, next, toplink;
chnrs := Set(List([
2,
4..Length(l)], i-> l[i-
1][
1]));
chnrs := Concatenation(Filtered(chnrs, a-> not a in [
"Bib",
"Ind"]),
Filtered(chnrs, a-> a in [
"Bib",
"Ind"]));
chlink := Concatenation(
"\n<div class=\"chlinktop\
"><span class=\"chlink1\
">",
GAPDocTexts.d.GotoChapter,
": </span>");
for n in chnrs
do
Append(chlink, Concatenation(
"<a href=\"chap
", String(n),
GAPDoc2HTMLProcs.ext,
"\">
"));
if n =
0 then
Append(chlink, GAPDocTexts.d.Top);
else
Append(chlink, String(n));
fi;
Append(chlink,
"</a> ");
od;
Append(chlink,
"</div>\n");
toplink := Concatenation(
" <a href=\"chap0
", GAPDoc2HTMLProcs.ext,
"\">[
", GAPDocTexts.d.TopofBook, "]</a>
",
"<a href=\"chap0
", GAPDoc2HTMLProcs.ext, "#contents",
"\">[
", GAPDocTexts.d.Contents, "]</a>
" );
prev := [];
next := [];
for i in [
1..Length(chnrs)]
do
if i >
1 then
Add(prev, Concatenation(
" <a href=\"chap
", String(chnrs[i-1]),
GAPDoc2HTMLProcs.ext,
"\">[
", GAPDocTexts.d.PreviousChapter,
"]</a> "));
else
Add(prev,
"");
fi;
if i < Length(chnrs)
then
Add(next, Concatenation(
" <a href=\"chap
", String(chnrs[i+1]),
GAPDoc2HTMLProcs.ext,
"\">[
", GAPDocTexts.d.NextChapter,
"]</a> "));
else
Add(next,
"");
fi;
od;
# putting the paragraphs together (one string (file) for each chapter)
files := rec();
for i in [
1..Length(chnrs)]
do
n := chnrs[i];
if r.root.mathmode =
"MathML" then
# this MathML is no longer documented
files.(n) := rec(text :=
ShallowCopy(GAPDoc2HTMLProcs.Head1MML), ssnr := []);
elif r.root.mathmode =
"Tth" then
files.(n) := rec(text :=
ShallowCopy(GAPDoc2HTMLProcs.Head1Trans), ssnr := []);
elif r.root.mathmode =
"MathJax" then
files.(n) := rec(text := SubstitutionSublist(
GAPDoc2HTMLProcs.Head1MathJax,
"MATHJAXURL",
GAPDoc2HTMLProcs.MathJaxURL), ssnr := []);
else
files.(n) := rec(text := ShallowCopy(GAPDoc2HTMLProcs.Head1), ssnr := []);
fi;
tt := Concatenation(r.bookname,
") - ");
if n=
0 then
Append(tt, GAPDocTexts.d.Contents);
elif IsInt(n)
then
Append(tt, Concatenation(GAPDocTexts.d.Chapter,
" ", String(n),
": ",
FilterSGMLMarkup(r.chaptitle.(n))));
elif n=
"Bib" then
Append(tt, GAPDocTexts.d.References);
elif n=
"Ind" then
Append(tt, GAPDocTexts.d.Index);
else
Append(tt, Concatenation(GAPDocTexts.d.Appendix,
" ", n,
": ",
FilterSGMLMarkup(r.chaptitle.(n))));
fi;
Append(files.(n).text, tt);
Append(files.(n).text, GAPDoc2HTMLProcs.Head2);
# allow for chapter-wise CSS config
files.(n).text := SubstitutionSublist(files.(n).text,
"<body",
Concatenation(
"<body class=\"chap
", String(n), "\
" "));
Append(files.(n).text, Concatenation(
"\n", chlink));
Append(files.(n).text, Concatenation(
"\n<div class=\"chlinkprevnexttop\
">",
toplink, prev[i], next[i],
"</div>\n\n"));
if IsBound(r.root.LinkToMathJax)
then
# cross link to same chapter with MathJax enabled
Append(files.(n).text,
Concatenation(
"<p id=\"mathjaxlink\
" ",
"class=\"pcenter\
"><a href=\"chap
",
String(n),
"_mj.html\">[MathJax on]</a></p>\n
"));
elif r.root.mathmode =
"MathJax" then
# cross link to non-MathJax version
Append(files.(n).text,
Concatenation(
"<p id=\"mathjaxlink\
" ",
"class=\"pcenter\
"><a href=\"chap
",
String(n),
".html\">[MathJax off]</a></p>\n
"));
else
# we still want the hook for the [Style] link
Append(files.(n).text,
Concatenation(
"<p id=\"mathjaxlink\
" ",
"class=\"pcenter\
"></p>\n"));
fi;
od;
for i in [
2,
4..Length(l)]
do
n := files.(l[i-
1][
1]);
if Length(n.ssnr)=
0 or l[i-
1]{[
1..
3]} <> n.ssnr[Length(n.ssnr)]
then
Add(n.ssnr, l[i-
1]{[
1..
3]});
tt := GAPDoc2HTMLProcs.SectionLabel(r, l[i-
1],
"Subsection")[
2];
Append(n.text, Concatenation(
"<p><a id=\"", tt, "\
" name=\"", tt,
"\"></a></p>\n
"));
fi;
Append(n.text, l[i]);
od;
for i in [
1..Length(chnrs)]
do
n := chnrs[i];
Append(files.(n).text, Concatenation(
"\n<div class=\"chlinkprevnextbot\
">",
toplink, prev[i], next[i],
"</div>\n\n"));
Append(files.(n).text, SubstitutionSublist(chlink,
"chlinktop",
"chlinkbot", false));
Append(files.(n).text, GAPDoc2HTMLProcs.Tail);
od;
# finally tell result the file extensions
files.ext := GAPDoc2HTMLProcs.ext;
return files;
end;
##
## <#GAPDoc Label="GAPDoc2HTML">
## <ManSection >
## <Func Arg="tree[, bibpath[, gaproot]][, mtrans]" Name="GAPDoc2HTML" />
## <Returns>record containing HTML files as strings and other
## information</Returns>
## <Description>
## <Index Key="MathJax"><Package>MathJax</Package></Index>
## The argument <A>tree</A> for this function is a tree
## describing a &GAPDoc; XML document as returned by <Ref
## Func="ParseTreeXMLString" /> (probably also checked with <Ref
## Func="CheckAndCleanGapDocTree" />). Without an <A>mtrans</A>
## argument this function produces an HTML version of the document
## which can be read with any Web-browser and also be used with
## &GAP;'s online help (see <Ref BookName="Ref" Func="SetHelpViewer"
## />). It includes title page, bibliography, and index. The
## bibliography is made from &BibTeX; databases. Their location must
## be given with the argument <A>bibpath</A> (as string or directory
## object, if not given the current directory is used). If the third
## argument <A>gaproot</A> is given and is a string then this string
## is interpreted as relative path to &GAP;'s main root directory.
## Reference-URLs to external HTML-books which begin with the &GAP;
## root path are then rewritten to start with the given relative
## path. This makes the HTML-documentation portable provided a
## package is installed in some standard location below the &GAP;
## root.<P/>
##
## The output is a record with one component for each chapter
## (with names <C>"0"</C>, <C>"1"</C>, ..., <C>"Bib"</C>, and
## <C>"Ind"</C>). Each such component is again a record with
## the following components:
##
## <List >
## <Mark><C>text</C></Mark>
## <Item>the text of an HTML file containing the whole chapter (as a
## string)</Item>
## <Mark><C>ssnr</C></Mark>
## <Item>list of subsection numbers in this chapter (like <C>[3, 2,
## 1]</C> for chapter 3, section 2, subsection 1)
## </Item>
## </List>
##
## <Emph>Standard output format without</Emph> <A>mtrans</A>
## <Emph>argument</Emph><P/>
##
## The HTML code produced with this converter conforms
## to the W3C specification <Q>XHTML 1.0 strict</Q>, see
## <URL>https://www.w3.org/TR/xhtml1</URL>. First, this means that
## the HTML files are valid XML files. Secondly, the
## extension <Q>strict</Q> says in particular that the code
## doesn't contain any explicit font or color information.<P/>
##
## Mathematical formulae are handled as in the text converter
## <Ref Func="GAPDoc2Text"/>. We don't want to assume that the
## browser can use symbol fonts. Some &GAP; users like to browse
## the online help with <C>lynx</C>, see <Ref BookName="Ref"
## Func="SetHelpViewer" />, which runs inside the same terminal
## windows as &GAP;.<P/>
##
## To view the generated files in graphical browsers, stylesheet files
## with layout configuration should be copied into the directory
## with the generated HTML files, see <Ref Subsect="StyleSheets"/>.
## <P/>
##
## <Label Name="mtransarg"/>
## <Emph>Output format with</Emph> <A>mtrans</A> argument <P/>
##
## Currently, there are three variants of this converter available
## which handle mathematical formulae differently. They are accessed
## via the optional last <A>mtrans</A> argument.<P/>
##
## If <A>mtrans</A> is set to <C>"MathJax"</C> the formulae
## are essentially translated as for &LaTeX; documents (there
## is no processing of <C><M></C> elements as decribed
## in <Ref Subsect="M"/>). Inline formulae are delimited by
## <C>\(</C> and <C>\)</C> and displayed formulae by <C>\[</C>
## and <C>\]</C>. With <Package>MathJax</Package> webpages
## can contain nicely formatted scalable and searchable
## formulae. The resulting files link by default to <URL
## Text="https://www.jsdelivr.com/">https://www.jsdelivr.com/</URL>
## to get the <Package>MathJax</Package> script and fonts. This
## means that they can only be used on computers with internet
## access. An alternative URL can be set by overwriting
## <C>GAPDoc2HTMLProcs.MathJaxURL</C> before building the HTML
## version of a manual. This way a local installation
## of <Package>MathJax</Package> could be used. See <URL
## Text="https://www.mathjax.org/">https://www.mathjax.org/</URL>
## for more details.<P/>
##
## The following possibilities for <A>mtrans</A> are still supported,
## but since the <Package>MathJax</Package> approach seems much better,
## their use is deprecated.<P/>
##
## If the argument <A>mtrans</A> is set to <C>"Tth"</C> it is
## assumed that you have installed the &LaTeX; to HTML translation
## program <C>tth</C>. This is used to translate the contents of the
## <C>M</C>, <C>Math</C> and <C>Display</C> elements into HTML
## code. Note that the resulting code is not compliant with any
## standard. Formally it is <Q>XHTML 1.0 Transitional</Q>, it
## contains explicit font specifications and the characters of
## mathematical symbols are included via their position in a
## <Q>Symbol</Q> font. Some graphical browsers can be configured
## to display this in a useful manner, check <URL Text="the
## Tth homepage">http://hutchinson.belmont.ma.us/tth/</URL> for more
## details.<P/>
##
## This function works by running recursively through the document
## tree and calling a handler function for each &GAPDoc;
## XML element. Many of these handler functions (usually in
## <C>GAPDoc2TextProcs.<ElementName></C>) are not difficult to
## understand (the greatest complications are some commands for index
## entries, labels or the output of page number information). So it
## should be easy to adjust certain details to your own taste by slight
## modifications of the program. <P/>
##
## The result of this converter can be written to files with the
## command <Ref Func="GAPDoc2HTMLPrintHTMLFiles" />.<P/>
##
## There are two user preferences for reading the HTML manuals produced by
## &GAPDoc;. A user can choose among several style files which determine the
## appearance of the manual pages with
## <C>SetUserPreference("GAPDoc", "HTMLStyle", [...]);</C> where the list in
## the third argument are arguments for <Ref Func="SetGAPDocHTMLStyle"/>.
## The second preference is set by
## <C>SetUserPreference("GAPDoc", "UseMathJax", ...);</C> where the third
## argument is <K>true</K> or <K>false</K> (default). If this is set to
## <K>true</K>, the &GAP; help system displays the <Package>MathJax</Package>
## version of the HTML manuals.
## </Description>
## </ManSection>
## <#/GAPDoc>
##
## <#GAPDoc Label="HTMLStyleSheets">
## <Subsection Label="StyleSheets">
## <Heading>Stylesheet files</Heading>
## <Index>CSS stylesheets</Index>
##
## For graphical browsers the layout of the generated HTML manuals can be
## highly configured by cascading stylesheet (CSS) and javascript
## files. Such files are provided in the <F>styles</F> directory of the
## &GAPDoc; package.<P/>
##
## We recommend that these files are copied into each manual directory
## (such that each of them is selfcontained). There is a utility
## function <Ref Func="CopyHTMLStyleFiles" /> which does this. Of
## course, these files may be changed or new styles may be added. New
## styles may also be sent to the &GAPDoc; authors for possible
## inclusion in future versions.<P/>
##
## The generated HTML files refer to the file <F>manual.css</F>
## which conforms to the W3C specification CSS 2.0, see
## <URL>https://www.w3.org/TR/REC-CSS2</URL>, and the javascript file
## <F>manual.js</F> (only in browsers which support CSS or javascript,
## respectively; but the HTML files are also readable without
## any of them). To add a style <C>mystyle</C> one or both of
## <F>mystyle.css</F> and <F>mystyle.js</F> must be provided; these can
## overwrite default settings and add new javascript functions. For
## more details see the comments in <F>manual.js</F>.<P/>
## </Subsection>
## <ManSection >
## <Func Arg="dir" Name="CopyHTMLStyleFiles" />
## <Returns>nothing</Returns>
## <Description>
## This utility function copies the <F>*.css</F> and <F>*.js</F> files
## from the <F>styles</F> directory of the &GAPDoc; package into the
## directory
## <A>dir</A>.
## </Description>
## </ManSection>
## <#/GAPDoc>
##
## the basic call, used recursively with a result r from GetElement
## and a string str or list l to which the output should be appended
# arg: r[, bibpath] (then a list is returned, only for whole document)
# or: r, str (then the output is appended to string or list str)
InstallGlobalFunction(GAPDoc2HTML,
function(arg)
local r, str, linelength, name;
r := arg[
1];
# first check for the mode
if arg[Length(arg)] in [
"MathML",
"Tth",
"MathJax"]
then
r.mathmode := arg[Length(arg)];
arg := arg{[
1..Length(arg)-
1]};
else
r.mathmode :=
"Text";
fi;
if Length(arg) >
1 then
str := arg[
2];
else
str := [];
fi;
if r.name =
"WHOLEDOCUMENT" then
# choose different file name conventions such that these
# conversions can coexist
if r.mathmode =
"MathML" then
GAPDoc2HTMLProcs.ext :=
"_mml.xml";
elif r.mathmode =
"Tth" then
GAPDoc2HTMLProcs.ext :=
"_sym.html";
elif r.mathmode =
"MathJax" then
GAPDoc2HTMLProcs.ext :=
"_mj.html";
else
GAPDoc2HTMLProcs.ext :=
".html";
fi;
if IsDirectory(str)
then
r.bibpath := str;
else
if Length(str) =
0 then
str :=
".";
fi;
r.bibpath := Directory(str);
fi;
str := [];
if Length(arg) >
2 and IsString(arg[
3])
then
GAPDoc2HTMLProcs.RelPath := arg[
3];
GAPInfo.MainRootPath := Filtered(GAPInfo.RootPaths, a->
Filename([Directory(a)],
"lib/init.g")<>fail)[
1];
else
Unbind(GAPDoc2HTMLProcs.RelPath);
fi;
fi;
name := r.name;
if not IsBound(GAPDoc2HTMLProcs.(name))
then
Info(InfoGAPDoc,
1,
"#W WARNING: Don't know how to process element ", name,
" ---- ignored\n");
else
GAPDoc2HTMLProcs.(r.name)(r, str);
fi;
if r.name =
"WHOLEDOCUMENT" then
# put final record together and return it
return GAPDoc2HTMLProcs.PutFilesTogether(str, r);
fi;
return str;
end);
## recursion through the tree and collecting paragraphs
BindGlobal(
"GAPDoc2HTMLContent",
function(r, l)
local par, cont, i, count, s, a;
# utility: append counter and formatted paragraph to l
par :=
function(s)
if Length(s)>
0 then
s := NormalizedWhitespace(s);
if Length(s)>
0 then
Add(l, count);
Add(l, Concatenation(
"<p>", s,
"</p>\n\n"));
fi;
fi;
end;
# if not containing paragraphs, then l is string to append to
if not r.name in GAPDoc2HTMLProcs.ParEls
then
for a in r.content
do
GAPDoc2HTML(a, l);
od;
return;
fi;
# otherwise we have to collect text and paragraphs
cont := r.content;
# checking for alternatives
i :=
1;
while i < Length(cont)
do
if cont[i].name =
"Alt" and GAPDoc2HTMLProcs.AltYes(cont[i])
then
cont := Concatenation(cont{[
1..i-
1]}, cont[i].content,
cont{[i+
1..Length(cont)]});
else
i := i +
1;
fi;
od;
count := r.count;
s :=
"";
for a in cont
do
if a.count <> count
then
par(s);
count := a.count;
s :=
"";
fi;
if a.name in GAPDoc2HTMLProcs.ParEls
then
# recursively collect paragraphs
GAPDoc2HTML(a, l);
else
# collect text for current paragraph
GAPDoc2HTML(a, s);
fi;
od;
if Length(s)>
0 then
par(s);
fi;
end);
## write head and foot of HTML file.
GAPDoc2HTMLProcs.WHOLEDOCUMENT :=
function(r, par)
local i, pi, t, el, remdiv, math, pos, pos1, str, dat, datbt, bib, b,
keys, need, labels, tmp, j, diff, text, a, k, l, ind, opts;
## add paragraph numbers to all nodes of the document
AddParagraphNumbersGapDocTree(r);
if not IsBound(r.six)
then
Info(InfoGAPDoc,
1,
"#W WARNING: Using labels from section numbers, \n",
"#W consider running the converter for the text version first!\n");
fi;
## add a link .root to the root of the document to all nodes
## (then we can collect information about indexing and so on
## there)
AddRootParseTree(r);
r.index := [];
r.toc :=
"";
r.labels := rec();
r.labeltexts := rec();
if not IsBound(r.bibkeys)
then
r.bibkeys := [];
fi;
r.chaptitle := rec();
r.chapsectlinks := rec();
## checking for processing instructions before the book starts
## example: <?HTML option1="value1" ?>
i :=
1;
pi := rec();
while not r.content[i].name =
"Book" do
if r.content[i].name =
"XMLPI" then
t := r.content[i].content;
if Length(t) >
4 and t{[
1..
5]} =
"HTML " then
el := GetSTag(Concatenation(
"<", t,
">"),
2);
for a in NamesOfComponents(el.attributes)
do
pi.(a) := el.attributes.(a);
od;
fi;
fi;
i := i+
1;
od;
# setup for external conversion of maths (MathML with ttm, tth, ...)
if r.mathmode in [
"MathML",
"Tth"]
then
r.ConvInput :=
"";
r.MathCount :=
0;
fi;
## Now the actual work starts, we give the processing instructions found
## so far to the Book handler.
## We call the Book handler twice and produce index, bibliography, toc
## in between.
Info(InfoGAPDoc,
1,
"#I First run, collecting cross references, ",
"index, toc, bib and so on . . .\n");
# with this flag we avoid unresolved references warnings in first run
GAPDoc2HTMLProcs.FirstRun := true;
GAPDoc2HTMLProcs.Book(r.content[i], [], pi);
GAPDoc2HTMLProcs.FirstRun := false;
# now the toc is ready
Info(InfoGAPDoc,
1,
"#I Table of contents complete.\n");
r.toctext := r.toc;
r.chapsectlinkstext := r.chapsectlinks;
# utility to remove <div> tags
remdiv :=
function(s)
local pos, pos1;
pos := PositionSublist(s,
"<div");
while pos <> fail
do
pos1 := Position(s,
'>', pos);
s := Concatenation(s{[
1..pos-
1]}, s{[pos1+
1..Length(s)]});
pos := PositionSublist(s,
"<div");
od;
pos := PositionSublist(s,
"</div");
while pos <> fail
do
pos1 := Position(s,
'>', pos);
s := Concatenation(s{[
1..pos-
1]}, s{[pos1+
1..Length(s)]});
pos := PositionSublist(s,
"</div");
od;
return s;
end;
# MathML or Tth translation
if r.mathmode in [
"MathML",
"Tth"]
then
Info(InfoGAPDoc,
1,
"#I translating formulae with \c");
FileString(
"tempCONV.tex", r.ConvInput);
if r.mathmode =
"MathML" then
Info(InfoGAPDoc,
1,
"ttm.\n");
Exec(
"rm -f tempCONV.html; ttm -L -r tempCONV.tex > tempCONV.html");
elif r.mathmode =
"Tth" then
Info(InfoGAPDoc,
1,
"tth.\n");
Exec(
"rm -f tempCONV.html; tth -w2 -r -u tempCONV.tex > tempCONV.html");
fi;
math := StringFile(
"tempCONV.html");
# correct the <var> tags
math := SubstitutionSublist(math,
"< var >",
"<var>");
math := SubstitutionSublist(math,
"< /var >",
"</var>");
math := SubstitutionSublist(math,
"<mo><</mo><mi>var</mi><mo>></mo>",
"<var>");
math := SubstitutionSublist(math,
"<mo><</mo><mo>/</mo><mi>var</mi><mo>></mo>",
"</var>");
r.MathList := [];
pos := PositionSublist(math,
"TeXFormulaeDelim");
while pos <> fail
do
pos1 := PositionSublist(math,
"TeXFormulaeDelim", pos);
if pos1 <> fail
then
Add(r.MathList, remdiv(math{[pos+
16..pos1-
1]}));
else
Add(r.MathList, remdiv(math{[pos+
16..Length(math)]}));
fi;
pos := pos1;
od;
fi;
# .index has entries of form [sorttext, subsorttext, numbertext,
# entrytext, url[, subtext]]
Info(InfoGAPDoc,
1,
"#I Producing the index . . .\n");
SortBy(r.index, a-> [a[
1],STRING_LOWER(a[
2]),
List(SplitString(a[
3],
".-",
""), Int)]);
str :=
"";
ind := r.index;
k :=
1;
while k <= Length(ind)
do
if k >
1 and ind[k][
4] = ind[k-
1][
4]
then
Append(str,
" ");
else
Append(str, ind[k][
4]);
fi;
if IsBound(ind[k][
6])
then
if k =
1 or ind[k][
4] <> ind[k-
1][
4]
then
Append(str,
", ");
fi;
Append(str, ind[k][
6]);
elif Length(ind[k][
2]) >
0 then
if k =
1 or ind[k][
4] <> ind[k-
1][
4]
then
Append(str,
", ");
fi;
Append(str, ind[k][
2]);
fi;
l := k;
while l <= Length(ind) and ind[l][
4] = ind[k][
4] and
((IsBound(ind[k][
6]) and IsBound(ind[l][
6])
and ind[k][
6] = ind[l][
6]) or
(not IsBound(ind[k][
6]) and not IsBound(ind[l][
6])
and ind[k][
2] = ind[l][
2]))
do
Append(str, Concatenation(
" <a href=\"", ind[l][5], "\
">",
ind[l][
3],
"</a> "));
l := l+
1;
od;
Append(str,
"<br />\n");
k := l;
od;
r.indextext := str;
if Length(r.bibkeys) >
0 then
GAPDocAddBibData(r);
Info(InfoGAPDoc,
1,
"#I Writing bibliography . . .\n");
if r.root.mathmode =
"MathJax" then
opts := rec(MathJax := true);
else
opts := rec();
fi;
need := List(r.bibentries, a-> RecBibXMLEntry(a,
"HTML", r.bibstrings,
opts));
# copy the unique labels
for a in [
1..Length(need)]
do
need[a].key := r.biblabels[a];
od;
text :=
"";
for a in need
do
# an anchor for links from the citations
Append(text, Concatenation(
"\n<p><a id=\"biB
", a.Label,
"\" name=\
"biB", a.Label,
"\"></a></p>\n
"));
Append(text, StringBibAsHTML(a, false));
od;
r.bibtext := text;
fi;
# second run
r.index := [];
Info(InfoGAPDoc,
1,
"#I Second run through document . . .\n");
GAPDoc2HTMLProcs.Book(r.content[i], par, pi);
for a in [
"MathList",
"MathCount",
"index",
"toc"]
do
Unbind(r.(a));
od;
## remove the links to the root ???
## RemoveRootParseTree(r);
end;
## comments and processing instructions are in general ignored
GAPDoc2HTMLProcs.XMLPI :=
function(r, str)
return;
end;
GAPDoc2HTMLProcs.XMLCOMMENT :=
function(r, str)
return;
end;
# two utilities for attribute values like labels or text with special
# XML (or LaTeX) characters which gets printed
GAPDoc2HTMLProcs.EscapeAttrVal :=
function(str)
str := SubstitutionSublist(str,
"&",
"&");
str := SubstitutionSublist(str,
"<",
"<");
str := SubstitutionSublist(str,
">",
">");
# for MathJax
str := SubstitutionSublist(str,
"\\[",
"<span>\\</span>[");
str := SubstitutionSublist(str,
"\\]",
"<span>\\</span>]");
str := SubstitutionSublist(str,
"\\(",
"<span>\\</span>(");
str := SubstitutionSublist(str,
"\\)",
"<span>\\</span>)");
return str;
end;
# do nothing with Ignore
GAPDoc2HTMLProcs.Ignore :=
function(arg)
end;
# just process content
GAPDoc2HTMLProcs.Book :=
function(r, par, pi)
# copy the name of the book to the root
r.root.bookname := r.attributes.Name;
GAPDoc2HTMLContent(r, par);
end;
## Body is sectioning element
GAPDoc2HTMLProcs.Body := GAPDoc2HTMLContent;
## the title page, the most complicated looking function
GAPDoc2HTMLProcs.TitlePage :=
function(r, par)
local strn, l, s, a, aa, cont, ss;
strn :=
"<div class=\"pcenter\
">\n";
# title
l := Filtered(r.content, a-> a.name =
"Title");
s :=
"";
GAPDoc2HTMLContent(l[
1], s);
s := Concatenation(
"\n<h1>", NormalizedWhitespace(s),
"</h1>\n\n");
Append(strn, s);
# subtitle
l := Filtered(r.content, a-> a.name =
"Subtitle");
if Length(l)>
0 then
s :=
"";
GAPDoc2HTMLContent(l[
1], s);
s := Concatenation(
"\n<h2>", NormalizedWhitespace(s),
"</h2>\n\n");
Append(strn, s);
fi;
# version
l := Filtered(r.content, a-> a.name =
"Version");
if Length(l)>
0 then
s :=
"<p>";
GAPDoc2HTMLContent(l[
1], s);
while Length(s)>
0 and s[Length(s)] in WHITESPACE
do
Unbind(s[Length(s)]);
od;
Append(s,
"</p>\n\n");
Append(strn, s);
fi;
# date
l := Filtered(r.content, a-> a.name =
"Date");
if Length(l)>
0 then
s :=
"<p>";
GAPDoc2HTMLContent(l[
1], s);
Append(strn, s);
Append(strn,
"</p>\n\n");
fi;
Append(strn,
"</div>\n");
# an extra comment
l := Filtered(r.content, a-> a.name =
"TitleComment");
if Length(l) >
0 then
s :=
"<p>";
GAPDoc2HTMLContent(l[
1], s);
Append(s,
"</p>\n");
Append(strn, s);
fi;
# author name(s)
l := Filtered(r.content, a-> a.name =
"Author");
for a in l
do
s :=
"<p><b>";
aa := ShallowCopy(a);
aa.content := Filtered(a.content,
b-> not b.name in [
"Email",
"Homepage",
"Address"]);
GAPDoc2HTMLContent(aa, s);
Append(strn, s);
Append(strn,
"</b>\n");
cont := List(a.content, b-> b.name);
if "Email" in cont
then
s :=
"";
GAPDoc2HTML(a.content[Position(cont,
"Email")], s);
s := NormalizedWhitespace(s);
Append(strn, Concatenation(
"<br />", GAPDocTexts.d.Email,
": ", s,
"\n"));
fi;
if "Homepage" in cont
then
s :=
"";
GAPDoc2HTML(a.content[Position(cont,
"Homepage")], s);
s := NormalizedWhitespace(s);
Append(strn, Concatenation(
"<br />", GAPDocTexts.d.Homepage,
": ", s,
"\n"));
fi;
if "Address" in cont
then
s :=
"";
GAPDoc2HTMLContent(a.content[Position(cont,
"Address")], s);
s := NormalizedWhitespace(s);
Append(strn, Concatenation(
"<br />", GAPDocTexts.d.Address,
": <br />", s,
"\n"));
fi;
Append(strn,
"</p>");
od;
Append(strn,
"\n\n");
Add(par, r.count);
Add(par, strn);
# an Address element in title page
l := Filtered(r.content, a-> a.name =
"Address");
if Length(l) >
0 then
s :=
"";
GAPDoc2HTMLContent(l[
1], s);
s := NormalizedWhitespace(s);
Append(strn, Concatenation(
"<p><b>", GAPDocTexts.d.Address,
":</b><br />\n", s,
"</p>\n"));
fi;
# abstract, copyright page, acknowledgements, colophon
for ss in [
"Abstract",
"Copyright",
"Acknowledgements",
"Colophon" ]
do
l := Filtered(r.content, a-> a.name = ss);
if Length(l)>
0 then
Add(par, l[
1].count);
Add(par, Concatenation(
"<h3>", GAPDocTexts.d.(ss),
"</h3>\n"));
GAPDoc2HTMLContent(l[
1], par);
fi;
od;
end;
## these produce text for an URL
## arg: r, str[, pre]
GAPDoc2HTMLProcs.Link := GAPDoc2HTMLContent;
GAPDoc2HTMLProcs.LinkText := GAPDoc2HTMLContent;
GAPDoc2HTMLProcs.URL :=
function(arg)
local r, str, pre, rr, txt, s;
r := arg[
1];
str := arg[
2];
if Length(arg)>
2 then
pre := arg[
3];
else
pre :=
"";
fi;
rr := First(r.content, a-> a.name =
"LinkText");
if rr <> fail
then
txt :=
"";
GAPDoc2HTML(rr, txt);
rr := First(r.content, a-> a.name =
"Link");
if rr = fail
then
Info(InfoGAPDoc,
1,
"#W missing <Link> element for text ", txt, "\n");
s :=
"MISSINGLINK";
else
s :=
"";
GAPDoc2HTMLContent(rr, s);
fi;
else
s :=
"";
GAPDoc2HTMLContent(r, s);
if IsBound(r.attributes.Text)
then
txt := r.attributes.Text;
else
txt := s;
fi;
fi;
Append(str, Concatenation(GAPDoc2HTMLProcs.TextAttr.URL[
1],
"<a href=\"", pre, s, "\
">", txt,
"</a>"));
Append(str, GAPDoc2HTMLProcs.TextAttr.URL[
2]);
end;
GAPDoc2HTMLProcs.Homepage := GAPDoc2HTMLProcs.URL;
GAPDoc2HTMLProcs.Email :=
function(r, str)
# we add the `mailto:' phrase
GAPDoc2HTMLProcs.URL(r, str,
"mailto:");
end;
## utility: generate a chapter or (sub)section-number string
GAPDoc2HTMLProcs.SectionNumber :=
function(count, sect)
local res;
res :=
"";
if IsString(count[
1]) or count[
1]>
0 then
Append(res, String(count[
1]));
fi;
if sect=
"Chapter" or sect=
"Appendix" then
return res;
fi;
Add(res,
'.');
if count[
2]>
0 then
Append(res, String(count[
2]));
fi;
if sect=
"Section" then
return res;
fi;
if count[
3]>
0 then
Append(res, Concatenation(
"-", String(count[
3])));
fi;
return res;
end;
## utility: generate a chapter or (sub)section-number string
GAPDoc2HTMLProcs.SectionLabel :=
function(r, count, sect)
local res, a;
if IsString(count[
1]) or count[
1]>
0 then
res := Concatenation(
"chap", String(count[
1]), GAPDoc2HTMLProcs.ext);
else
res := Concatenation(
"chap0", GAPDoc2HTMLProcs.ext);
fi;
res := [res,
""];
if not IsBound(r.root.six)
then
if sect=
"Chapter" then
return res;
fi;
Append(res[
2], Concatenation(
"s", String(count[
2])));
Append(res[
2], Concatenation(
"ss", String(count[
3])));
return res;
else
## a := First(r.root.six, a-> a[3] = count{[1..3]});
a := PositionSet(r.root.sixcount, count{[
1..
3]});
if a <> fail
then
a := r.root.six[r.root.sixindex[a]];
fi;
if a = fail or not IsBound(a[
7])
then
return GAPDoc2HTMLProcs.SectionLabel(rec(root:=rec()), count, sect);
else
Append(res[
2], a[
7]);
return res;
fi;
fi;
end;
## the sectioning commands are just translated and labels are
## generated, if given as attribute
GAPDoc2HTMLProcs.ChapSect :=
function(r, par, sect)
local num, posh, s, ind, strn, lab, lb, types, nrs, hord, a, pos, l, i;
types := [
"Chapter",
"Appendix",
"Section",
"Subsection"];
nrs := [
"3",
"3",
"4",
"5"];
hord := nrs[Position(types, sect)];
Add(par, r.count);
# if available, start with links to sections in chapter/appendix
if sect in [
"Chapter",
"Appendix"]
then
if IsBound(r.root.chapsectlinkstext) and
IsBound(r.root.chapsectlinkstext.(r.count[
1]))
then
Add(par, r.root.chapsectlinkstext.(r.count[
1]));
fi;
fi;
if par[Length(par)] = r.count
then
Add(par,
"");
fi;
# section number as string
num := GAPDoc2HTMLProcs.SectionNumber(r.count, sect);
# and as anchor
lab := GAPDoc2HTMLProcs.SectionLabel(r, r.count,
"Subsection");
lab := Concatenation(lab[
1],
"#", lab[2]);
# the heading
posh := Position(List(r.content, a-> a.name),
"Heading");
if posh <> fail
then
s :=
"";
# first the .six entry
GAPDoc2HTMLProcs.Heading1(r.content[posh], s);
if hord =
"3" then
r.root.chaptitle.(r.count[
1]) := s;
fi;
# label entry, if present
if IsBound(r.attributes.Label)
then
lb := NormalizedWhitespace(r.attributes.Label);
r.root.labels.(lb) := [num, lab];
r.root.labeltexts.(lb) := s;
fi;
# the heading text
Append(par[Length(par)],
Concatenation(
"\n<h", hord,
">", num,
" ", s,
"</h", hord,
">\n\n"));
# table of contents entry
s := Concatenation( num,
" ", s);
if sect in [
"Chapter",
"Appendix"]
then
if r.count[
1] >=
1 then
ind :=
"<div class=\"ContChap\
">";
fi;
elif sect=
"Section" then
ind :=
"";
if r.count[
2] >=
1 then
Append(ind,
"<div class=\"ContSect\
">");
fi;
Append(ind,
"<span class=\"tocline\
"><span class=\"nocss\
"> </span>");
elif sect=
"Subsection" then
ind :=
"<span class=\"ContSS\
"><br /><span class=\"nocss\
"> </span>";
else
ind :=
"";
fi;
Append(r.root.toc, Concatenation(ind,
"<a href=\"",
lab,
"\">
", s, "</a>\n
"));
if sect=
"Section" then
Append(r.root.toc,
"</span>\n<div class=\"ContSSBlock\
">\n");
fi;
fi;
# the actual content
GAPDoc2HTMLContent(r, par);
# possibly close <div> or <span> in content
if posh <> fail
then
if sect in [
"Chapter",
"Appendix" ]
then
Append(r.root.toc,
"</div>\n");
elif sect=
"Section" then
# remove last line if no subsections
l := Length(r.root.toc);
if r.root.toc{[l-
25..l]} =
"<div class=\"ContSSBlock\
">\n" then
for i in [
0..
25]
do Unbind(r.root.toc[l-i]); od;
Append(r.root.toc,
"</div>\n");
else
Append(r.root.toc,
"</div></div>\n");
fi;
elif sect=
"Subsection" then
Append(r.root.toc,
"</span>\n");
fi;
fi;
# if in chapter, also use the section links in top of page
if sect in [
"Chapter",
"Appendix"]
then
a := Reversed(r.root.toc);
pos := PositionSublist(a, Reversed(
"<div class=\"ContChap\
">"));
a := Reversed(a{[
1..pos-
1]});
r.root.chapsectlinks.(r.count[
1]) := Concatenation(
"<div class=\"ChapSects\
">", a);
fi;
end;
## this really produces the content of the heading
GAPDoc2HTMLProcs.Heading1 :=
function(r, str)
GAPDoc2HTMLProcs.WrapAttr(r, str,
"Heading");
end;
## and this ignores the heading (for simpler recursion)
GAPDoc2HTMLProcs.Heading :=
function(r, str)
end;
GAPDoc2HTMLProcs.Chapter :=
function(r, par)
GAPDoc2HTMLProcs.ChapSect(r, par,
"Chapter");
end;
GAPDoc2HTMLProcs.Appendix :=
function(r, par)
GAPDoc2HTMLProcs.ChapSect(r, par,
"Appendix");
end;
GAPDoc2HTMLProcs.Section :=
function(r, par)
GAPDoc2HTMLProcs.ChapSect(r, par,
"Section");
end;
GAPDoc2HTMLProcs.Subsection :=
function(r, par)
GAPDoc2HTMLProcs.ChapSect(r, par,
"Subsection");
end;
## table of contents, just puts "TOC" in first run
GAPDoc2HTMLProcs.TableOfContents :=
function(r, par)
Add(par, r.count);
if IsBound(r.root.toctext)
then
Add(par, Concatenation(
"\n<div class=\"contents\
">\n<h3>",
GAPDocTexts.d.Contents,
"<a id=\"contents\
" name=\"contents\
"></a></h3>\n\n",
r.root.toctext,
"<br />\n</div>\n"));
else
Add(par,
"<p>TOC\n-----------</p>\n\n");
fi;
end;
## bibliography, just "BIB" in first run, store databases in root
GAPDoc2HTMLProcs.Bibliography :=
function(r, par)
local s;
# add references to TOC
Append(r.root.toc, Concatenation(
"<div class=\"ContChap\
"><a href=\"chapBib
",
GAPDoc2HTMLProcs.ext,
"\"><span class=\
"Heading\">
",
GAPDocTexts.d.References,
"</span></a></div>\n"));
r.root.bibdata := r.attributes.Databases;
if IsBound(r.attributes.Style)
then
r.root.bibstyle := r.attributes.Style;
fi;
Add(par, r.count);
if IsBound(r.root.bibtext)
then
Add(par, Concatenation(
"\n<h3>", GAPDocTexts.d.References,
"</h3>\n\n",
r.root.bibtext,
"<p> </p>\n\n"));
else
Add(par,
"<p>BIB\n-----------</p>\n");
fi;
end;
GAPDoc2HTMLProcs.PCDATAFILTER :=
function(r, str)
local s, a;
s := r.content;
if not IsBound(r.HTML) and (Position(s,
'<') <> fail or
Position(s,
'&') <> fail or Position(s,
'>') <> fail)
then
for a in s
do
if a=
'<' then
Append(str,
"<");
elif a=
'&' then
Append(str,
"&");
elif a=
'>' then
Append(str,
">");
else
Add(str, a);
fi;
od;
else
Append(str, s);
fi;
end;
# and without filter (e.g., for collecting formulae
GAPDoc2HTMLProcs.PCDATANOFILTER :=
function(r, str)
Append(str, r.content);
end;
GAPDoc2HTMLProcs.PCDATAFILTER;
## default is with filter
GAPDoc2HTMLProcs.PCDATA := GAPDoc2HTMLProcs.PCDATAFILTER;
## end of paragraph (end with double newline)
GAPDoc2HTMLProcs.P :=
function(r, str)
# nothing to do, the "<p>" are added in main loop (GAPDoc2HTML)
end;
GAPDoc2HTMLProcs.Br :=
function(r, str)
Append(str,
"<br />\n");
end;
## wrapping text attributes
GAPDoc2HTMLProcs.WrapAttr :=
function(r, str, a)
local s, tt;
s :=
"";
GAPDoc2HTMLContent(r, s);
tt := GAPDoc2HTMLProcs.TextAttr.(a);
Append(str, Concatenation(tt[
1], s, tt[
2]));
end;
## GAP keywords
GAPDoc2HTMLProcs.K :=
function(r, str)
GAPDoc2HTMLProcs.WrapAttr(r, str,
"K");
end;
## buttons
GAPDoc2HTMLProcs.B :=
function(r, str)
GAPDoc2HTMLProcs.WrapAttr(r, str,
"B");
end;
## verbatim GAP code
GAPDoc2HTMLProcs.C :=
function(r, str)
GAPDoc2HTMLProcs.WrapAttr(r, str,
"C");
end;
## file names
GAPDoc2HTMLProcs.F :=
function(r, str)
GAPDoc2HTMLProcs.WrapAttr(r, str,
"F");
end;
## argument names (same as Arg)
GAPDoc2HTMLProcs.A :=
function(r, str)
GAPDoc2HTMLProcs.WrapAttr(r, str,
"Arg");
end;
GAPDoc2HTMLProcs.MathConvHelper :=
function(r, str, db, de)
local s, x;
if IsBound(r.root.MathList)
then
# conversion already available
r.root.MathCount := r.root.MathCount +
1;
Append(str, r.root.MathList[r.root.MathCount]);
else
# add to input for converter
if IsString(r.content)
then
s := r.content;
else
s :=
"";
GAPDoc2HTMLProcs.PCDATA := GAPDoc2HTMLProcs.PCDATANOFILTER;
for x in r.content
do
GAPDoc2HTML(x, s);
od;
GAPDoc2HTMLProcs.PCDATA := GAPDoc2HTMLProcs.PCDATAFILTER;
fi;
s := Concatenation(
"TeXFormulaeDelim", db, s, de);
Append(r.root.ConvInput, s);
Append(str,
"FORMULA");
fi;
end;
## simple maths, here we try to substitute TeX command to something which
## looks ok in text mode
GAPDoc2HTMLProcs.M :=
function(r, str)
local s, ss, save;
if r.root.mathmode in [
"MathML",
"Tth"]
then
GAPDoc2HTMLProcs.MathConvHelper(r, str,
"$",
"$");
return;
fi;
s :=
"";
GAPDoc2HTMLProcs.PCDATA := GAPDoc2HTMLProcs.PCDATANOFILTER;
# a hack, since we want to allow <A> in formulae
save := GAPDoc2HTMLProcs.TextAttr.Arg;
GAPDoc2HTMLProcs.TextAttr.Arg := [
"TEXTaTTRvARBEGIN",
"TEXTaTTRvAREND"];
GAPDoc2HTMLContent(r, s);
GAPDoc2HTMLProcs.TextAttr.Arg := save;
GAPDoc2HTMLProcs.PCDATA := GAPDoc2HTMLProcs.PCDATAFILTER;
ss :=
"";
if r.root.mathmode =
"MathJax" then
s := Concatenation(
"\\(",s,
"\\)");
GAPDoc2HTMLProcs.PCDATAFILTER(rec(content := s), ss);
ss := SubstitutionSublist(ss,
"TEXTaTTRvARBEGIN",
"\\textit{");
ss := SubstitutionSublist(ss,
"TEXTaTTRvAREND",
"}");
else
s := TextM(s);
GAPDoc2HTMLProcs.PCDATAFILTER(rec(content := s), ss);
ss := SubstitutionSublist(ss,
"TEXTaTTRvARBEGIN", save[
1]);
ss := SubstitutionSublist(ss,
"TEXTaTTRvAREND", save[
2]);
fi;
Append(str, WrapTextAttribute(ss, GAPDoc2HTMLProcs.TextAttr.M));
end;
## in HTML this is shown in TeX format
GAPDoc2HTMLProcs.Math :=
function(r, str)
local s;
if r.root.mathmode in [
"MathML",
"Tth"]
then
GAPDoc2HTMLProcs.MathConvHelper(r, str,
"$",
"$");
return;
fi;
if r.root.mathmode =
"MathJax" then
s :=
"";
GAPDoc2HTMLProcs.M(r, s);
Append(str, s);
return;
fi;
s :=
"";
GAPDoc2HTMLContent(r, s);
Append(str, WrapTextAttribute(s, GAPDoc2HTMLProcs.TextAttr.Math));
end;
## displayed maths (also in TeX format, but centered paragraph in itself)
GAPDoc2HTMLProcs.Display :=
function(r, par)
local s, a, str;
if r.root.mathmode in [
"MathML",
"Tth"]
then
str :=
"";
GAPDoc2HTMLProcs.MathConvHelper(r, str,
"\n\\[",
"\\]\n\n");
Add(par, r.count);
Add(par, Concatenation(
"<table class=\"display\
"><tr>",
"<td class=\"display\
">",
str,
"</td></tr></table>\n"));
return;
fi;
s :=
"";
for a in r.content
do
GAPDoc2HTML(a, s);
od;
if r.root.mathmode =
"MathJax" then
Add(par, r.count);
Add(par, Concatenation(
"<p class=\"center\
">\\[",
s,
"\\]</p>\n\n"));
return;
fi;
if IsBound(r.attributes.Mode) and r.attributes.Mode =
"M" then
s := TextM(s);
fi;
s := Concatenation(
"<p class=\"pcenter\
">", s,
"</p>\n\n");
Add(par, r.count);
Add(par, s);
end;
## emphazised text
GAPDoc2HTMLProcs.Emph :=
function(r, str)
GAPDoc2HTMLProcs.WrapAttr(r, str,
"Emph");
end;
## quoted text
GAPDoc2HTMLProcs.Q :=
function(r, str)
Append(str,
"<q>");
GAPDoc2HTMLContent(r, str);
Append(str,
"</q>");
end;
## Package names
GAPDoc2HTMLProcs.Package :=
function(r, str)
GAPDoc2HTMLProcs.WrapAttr(r, str,
"Package");
end;
## menu items
GAPDoc2HTMLProcs.I :=
function(r, str)
GAPDoc2HTMLProcs.WrapAttr(r, str,
"I");
end;
GAPDoc2HTMLProcs.AddColorPromptMarkup :=
function(cont)
local patt, batt, iatt, res, pos, s, rows;
patt := GAPDoc2HTMLProcs.TextAttr.GAPprompt;
batt := GAPDoc2HTMLProcs.TextAttr.GAPbrkprompt;
iatt := GAPDoc2HTMLProcs.TextAttr.GAPinput;
res :=
"";
rows := SplitString(cont,
"\n",
"");
for s in rows
do
if Length(s) >
7 and s{[
1..
8]} =
"gap> " then
Append(res, Concatenation(WrapTextAttribute(
"gap>", patt),
" ", WrapTextAttribute(s{[
9..Length(s)]}, iatt)));
elif Length(s) >
4 and s{[
1..
5]} =
"> " then
Append(res, Concatenation(WrapTextAttribute(
">", patt),
" ", WrapTextAttribute(s{[
6..Length(s)]}, iatt)));
elif Length(s) >
2 and s{[
1..
3]} =
"brk" then
pos := Position(s,
' ');
if pos <> fail
then
Append(res, Concatenation(WrapTextAttribute(s{[
1..pos-
1]}, batt),
" ", WrapTextAttribute(s{[pos+
1..Length(s)]}, iatt)));
else
Append(res, WrapTextAttribute(s, batt));
fi;
else
Append(res, WrapTextAttribute(s, [
"",
""]));
fi;
Add(res,
'\n');
od;
if Length(cont) >
0 and cont[Length(cont)] <>
'\n' then
Unbind(res[Length(res)]);
fi;
return res;
end;
GAPDoc2HTMLProcs.ExampleLike :=
function(r, par, label, colorpr)
local str, cont, a, s;
str :=
"\n<div class=\"example\
"><pre>";
cont :=
"";
for a in r.content
do
# here we try to avoid reformatting
if IsString(a.content)
then
GAPDoc2HTMLProcs.PCDATA(a, cont);
else
s :=
"";
GAPDoc2HTML(a, s);
Append(cont, s);
fi;
od;
if colorpr
then
cont := GAPDoc2HTMLProcs.AddColorPromptMarkup(cont);
fi;
Append(str, cont);
Append(str,
"</pre></div>\n\n");
Add(par, r.count);
Add(par, str);
end;
## log of session and GAP code is typeset the same way as <Example>
GAPDoc2HTMLProcs.Example :=
function(r, par)
GAPDoc2HTMLProcs.ExampleLike(r, par,
"Example", true);
end;
GAPDoc2HTMLProcs.Log :=
function(r, par)
GAPDoc2HTMLProcs.ExampleLike(r, par,
"Log", true);
end;
GAPDoc2HTMLProcs.Listing :=
function(r, par)
GAPDoc2HTMLProcs.ExampleLike(r, par,
"Code", true);
end;
GAPDoc2HTMLProcs.Verb :=
function(r, par)
local str, cont, a, s;
str :=
"\n<pre class=\"normal\
">\n";
cont :=
"";
for a in r.content
do
# here we try to avoid reformatting
if IsString(a.content)
then
GAPDoc2HTMLProcs.PCDATA(a, cont);
else
s :=
"";
GAPDoc2HTML(a, s);
Append(cont, s);
fi;
od;
Append(str, cont);
Append(str,
"\n</pre>\n\n");
Add(par, r.count);
Add(par, str);
end;
## explicit labels
GAPDoc2HTMLProcs.Label :=
function(r, str)
local num, lab, lb;
num := GAPDoc2HTMLProcs.SectionNumber(r.count,
"Subsection");
lab := GAPDoc2HTMLProcs.SectionLabel(r, r.count,
"Subsection");
lb := NormalizedWhitespace(r.attributes.Name);
r.root.labels.(lb) := [num, Concatenation(lab[
1],
"#",lab[2])];
end;
## citations
GAPDoc2HTMLProcs.Cite :=
function(r, str)
local key, pos;
key := r.attributes.Key;
pos := Position(r.root.bibkeys, key);
if pos = fail
then
Add(r.root.bibkeys, key);
Append(str, Concatenation(
"[?", key,
"?]"));
elif not IsBound(r.root.biblabels)
then
Append(str, Concatenation(
"[?", key,
"?]"));
else
# here we include a link to the corresponding entry in bibliography
Append(str, Concatenation(
"<a href=\"chapBib
", GAPDoc2HTMLProcs.ext,
"#biB", key, "\">[", r.root.biblabels[pos]));
if IsBound(r.attributes.Where)
then
Append(str,
", ");
Append(str, r.attributes.Where);
fi;
Append(str,
"]</a>");
fi;
end;
## explicit index entries
GAPDoc2HTMLProcs.Subkey := GAPDoc2HTMLContent;
GAPDoc2HTMLProcs.Index :=
function(r, str)
local s, sub, entry, url, a;
s :=
"";
sub :=
"";
for a in r.content
do
if a.name =
"Subkey" then
GAPDoc2HTML(a, sub);
else
GAPDoc2HTML(a, s);
fi;
od;
NormalizeWhitespace(s);
NormalizeWhitespace(sub);
if IsBound(r.attributes.Key)
then
entry := [STRING_LOWER(r.attributes.Key)];
else
entry := [STRING_LOWER(s)];
fi;
if IsBound(r.attributes.Subkey)
then
Add(entry, r.attributes.Subkey);
else
Add(entry, sub);
fi;
Add(entry, GAPDoc2HTMLProcs.SectionNumber(r.count,
"Subsection"));
Add(entry, s);
url := GAPDoc2HTMLProcs.SectionLabel(r, r.count,
"Subsection");
Add(entry, Concatenation(url[
1],
"#",url[2]));
if Length(sub) >
0 then
Add(entry, sub);
fi;
Add(r.root.index, entry);
end;
## helper to add markup to the args
GAPDoc2HTMLProcs.WrapArgs :=
function(argstr)
local res, noletter, c;
res :=
"";
noletter := true;
for c in argstr
do
if noletter
then
if not c in
", []" then
noletter := false;
Append(res, GAPDoc2HTMLProcs.TextAttr.Arg[
1]);
fi;
elif c in
", []" then
noletter := true;
Append(res, GAPDoc2HTMLProcs.TextAttr.Arg[
2]);
fi;
Add(res, c);
od;
if not noletter
then
Append(res, GAPDoc2HTMLProcs.TextAttr.Arg[
2]);
fi;
return res;
end;
## this produces an implicit index entry and a label entry
GAPDoc2HTMLProcs.LikeFunc :=
function(r, par, typ)
local attr, s, name, lab, url;
attr := GAPDoc2HTMLProcs.TextAttr.Func;
name := GAPDoc2HTMLProcs.EscapeAttrVal(r.attributes.Name);
s := Concatenation(attr[
1],
"‣ ", name, attr[2]);
if IsBound(r.attributes.Arg)
then
Append(s, Concatenation(
"( ", GAPDoc2HTMLProcs.WrapArgs(
GAPDoc2HTMLProcs.EscapeAttrVal(
NormalizedArgList(r.attributes.Arg))),
" )"));
fi;
# index entry
attr := GAPDoc2HTMLProcs.TextAttr.Func;
url := GAPDoc2HTMLProcs.SectionLabel(r, r.count,
"Subsection");
url := Concatenation(url[
1],
"#",url[2]);
if IsBound(r.attributes.Label)
then
lab := NormalizedWhitespace(r.attributes.Label);
else
lab :=
"";
fi;
Add(r.root.index, [STRING_LOWER(r.attributes.Name), lab,
GAPDoc2HTMLProcs.SectionNumber(r.count,
"Subsection"),
Concatenation(attr[
1], name, attr[
2]),
url]);
# label (if not given, the default is the Name)
if IsBound(r.attributes.Label)
then
if IsBound(r.attributes.Name)
then
lab := Concatenation(r.attributes.Name,
" (",
NormalizedWhitespace(r.attributes.Label),
")");
else
lab := r.attributes.Label;
fi;
else
lab := r.attributes.Name;
fi;
GAPDoc2HTMLProcs.Label(rec(count := r.count, attributes := rec(Name
:= lab), root := r.root), par);
# adding hint about the type of the variable
s := Concatenation(
"<div class=\"func\
"><table class=\"func\
" ",
"width=\"100%\
">",
"<tr><td class=\"tdleft\
">", s,
"</td><td class=\"tdright\
">( ", typ,
" )</td></tr></table></div>\n");
Add(par, r.count);
Add(par, s);
end;
GAPDoc2HTMLProcs.Func :=
function(r, str)
GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Func);
end;
GAPDoc2HTMLProcs.Oper :=
function(r, str)
GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Oper);
end;
GAPDoc2HTMLProcs.Constr :=
function(r, str)
GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Constr);
end;
GAPDoc2HTMLProcs.Meth :=
function(r, str)
GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Meth);
end;
GAPDoc2HTMLProcs.Filt :=
function(r, str)
# r.attributes.Type could be "representation", "category", ...
if IsBound(r.attributes.Type)
then
GAPDoc2HTMLProcs.LikeFunc(r, str, LowercaseString(r.attributes.Type));
else
GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Filt);
fi;
end;
GAPDoc2HTMLProcs.Prop :=
function(r, str)
GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Prop);
end;
GAPDoc2HTMLProcs.Attr :=
function(r, str)
GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Attr);
end;
GAPDoc2HTMLProcs.Var :=
function(r, str)
GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Var);
end;
GAPDoc2HTMLProcs.Fam :=
function(r, str)
GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Fam);
end;
GAPDoc2HTMLProcs.InfoClass :=
function(r, str)
GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.InfoClass);
end;
## using the HelpData(.., .., "ref") interface
GAPDoc2HTMLProcs.ResolveExternalRef :=
function(bookname, label, nr)
local info, match, res;
info := HELP_BOOK_INFO(bookname);
if info = fail
then
return fail;
fi;
match := Concatenation(HELP_GET_MATCHES(info, SIMPLE_STRING(label), true));
if Length(match) < nr
then
return fail;
fi;
res := GetHelpDataRef(info, match[nr][
2]);
res[
1] := SubstitutionSublist(res[
1],
" (not loaded): ",
": ",
"one");
return res;
end;
## helper for external URLs, remove GAPDocStyle part and maybe add "_mj"
GAPDoc2HTMLProcs.AdjustExtURL :=
function(r, url)
local pos, pos2, res, fnam, mjnam;
pos := PositionSublist(url,
"?GAPDocStyle=");
if pos <> fail
then
pos2 := Position(url,
'#', pos);
if pos2 = fail
then
pos2 := Length(url)+
1;
fi;
res := url{[
1..pos-
1]};
Append(res, url{[pos2..Length(url)]});
else
res :=url;
fi;
if r.root.mathmode =
"MathJax" then
pos := Position(res,
'#');
if pos <> fail
then
fnam := res{[
1..pos-
1]};
else
pos := Length(res)+
1;
fnam := res;
fi;
if Length(fnam) >=
5 and fnam{[Length(fnam)-
4..Length(fnam)]} =
".html" then
mjnam := Concatenation(fnam{[
1..Length(fnam)-
5]},
"_mj.html");
if IsExistingFile(mjnam)
then
res := Concatenation(mjnam, res{[pos..Length(res)]});
fi;
fi;
fi;
return res;
end;
## a try to make it somewhat shorter than for the Text and LaTeX conversions
GAPDoc2HTMLProcs.Ref :=
function(r, str)
local int, txt, ref, lab, attr, sectlike, rattr;
rattr := GAPDoc2HTMLProcs.TextAttr.Ref;
int := Difference(NamesOfComponents(r.attributes), [
"BookName",
"Label",
"Style"]);
if Length(int)>
0 and int[
1] <>
"Text" then
lab := r.attributes.(int[
1]);
else
lab :=
"";
fi;
if IsBound(r.attributes.Label)
then
if Length(lab) >
0 then
lab := Concatenation(lab,
" (", r.attributes.Label,
")");
else
lab := r.attributes.Label;
fi;
fi;
lab := NormalizedWhitespace(lab);
if IsBound(r.attributes.BookName)
then
ref := GAPDoc2HTMLProcs.ResolveExternalRef(r.attributes.BookName, lab,
1);
if ref <> fail and ref[
6] <> fail
then
ref[
6] := GAPDoc2HTMLProcs.AdjustExtURL(r, ref[
6]);
if IsBound(GAPDoc2HTMLProcs.RelPath) and
PositionSublist(ref[
6], GAPInfo.MainRootPath) =
1 then
ref[
6] := Concatenation(GAPDoc2HTMLProcs.RelPath,
"/",
ref[
6]{[Length(GAPInfo.MainRootPath)+
1..Length(ref[
6])]});
fi;
if IsBound(r.attributes.Style) and r.attributes.Style =
"Number" then
ref := Concatenation(
"<a href=\"", ref[6], "\
">",rattr[
1],
r.attributes.BookName,
" ", ref[
2], rattr[
2],
"</a>");
elif IsBound(r.attributes.Text)
then
ref := Concatenation(
"<a href=\"", ref[6], "\
">", rattr[
1],
r.attributes.Text, rattr[
2],
"</a>");
else
ref := Concatenation(
"<a href=\"", ref[6], "\
">", rattr[
1],
GAPDoc2HTMLProcs.EscapeAttrVal(ref[
1]),
rattr[
2],
"</a>");
fi;
elif ref <> fail
then
ref := Concatenation(rattr[
1], ref[
1], rattr[
2]);
else
if GAPDoc2HTMLProcs.FirstRun <> true
then
Info(InfoGAPDoc,
1,
"#W WARNING: non resolved reference: ",
r.attributes,
"\n");
fi;
ref := Concatenation(rattr[
1],
"???", rattr[
2]);
fi;
else
if IsBound(r.root.labels.(lab))
then
if not IsBound(r.attributes.Text)
then
ref := Concatenation(
"<a href=\"", r.root.labels.(lab)[2], "\
">",
rattr[
1], r.root.labels.(lab)[
1], rattr[
2],
"</a>");
else
ref := Concatenation(
"<a href=\"", r.root.labels.(lab)[2], "\
">",
rattr[
1], r.attributes.Text, rattr[
2],
"</a>");
fi;
else
if GAPDoc2HTMLProcs.FirstRun <> true
then
Info(InfoGAPDoc,
1,
"#W WARNING: non resolved reference: ",
r.attributes,
"\n");
fi;
ref := Concatenation(rattr[
1],
"???", rattr[
2]);
fi;
fi;
if Length(int)>
0 and int[
1] in [
"Func",
"Oper",
"Constr",
"Meth",
"Filt",
"Prop",
"Attr",
"Var",
"Fam",
"InfoClass" ]
then
attr := GAPDoc2HTMLProcs.TextAttr.Func;
txt := Concatenation(attr[
1],
GAPDoc2HTMLProcs.EscapeAttrVal(r.attributes.(int[
1])), attr[
2]);
# avoid reference to current subsection
if IsBound(r.attributes.BookName) or not IsBound(r.root.labels.(lab))
or GAPDoc2HTMLProcs.SectionNumber(r.count,
"Subsection") <>
r.root.labels.(lab)[
1]
then
Append(txt, Concatenation(
" (", ref,
")"));
fi;
elif Length(int)>
0 and
int[
1] in [
"Sect",
"Subsect",
"Chap",
"Appendix"] and
IsBound(r.attributes.Style) and
r.attributes.Style =
"Text" then
if IsBound(r.root.labeltexts.(lab))
then
txt := Concatenation(
"<a href=\"",r.root.labels.(lab)[2],
"\">
",rattr[1],r.root.labeltexts.(lab),rattr[2],"</a>
");
else
if GAPDoc2HTMLProcs.FirstRun <> true
then
Info(InfoGAPDoc,
1,
"#W WARNING: non resolved reference: ",
r.attributes,
"\n");
fi;
txt := Concatenation(rattr[
1],
"???", rattr[
2]);
fi;
else
txt := ref;
fi;
Append(str, txt);
end;
GAPDoc2HTMLProcs.Description := GAPDoc2HTMLContent;
GAPDoc2HTMLProcs.Returns :=
function(r, par)
local l;
l := [];
GAPDoc2HTMLContent(r, l);
if Length(l) >
0 then
l[
2] := Concatenation(
"<p>", GAPDocTexts.d.Returns,
": ", l[
2]{[
4..Length(l[
2])]});
fi;
Append(par, l);
end;
GAPDoc2HTMLProcs.ManSection :=
function(r, par)
local strn, funclike, i, num, s, lab, lb, ind;
# if there is a Heading then handle as subsection
if ForAny(r.content, a-> IsRecord(a) and a.name =
"Heading")
then
GAPDoc2HTMLProcs.ChapSect(r, par,
"Subsection");
return;
fi;
strn :=
"";
# function like elements
funclike := [
"Func",
"Oper",
"Constr",
"Meth",
"Filt",
"Prop",
"Attr",
"Var",
"Fam",
"InfoClass" ];
# heading comes from name of first function like element
i :=
1;
while not r.content[i].name in funclike
do
i := i+
1;
od;
num := GAPDoc2HTMLProcs.SectionNumber(r.count,
"Subsection");
s := Concatenation(num,
" ",
GAPDoc2HTMLProcs.EscapeAttrVal(r.content[i].attributes.Name));
Add(par, r.count);
# avoid MathJax interpretation in \(, \[ outside <code>
if '\\' in s
then
s := Concatenation(
"<code>",s,
"</code>");
fi;
Add(par, Concatenation(
"\n<h5>", s,
"</h5>\n\n"));
# append to TOC as subsection
lab := GAPDoc2HTMLProcs.SectionLabel(r, r.count,
"Subsection");
lab := Concatenation(lab[
1],
"#", lab[2]);
ind :=
"<span class=\"ContSS\
"><br /><span class=\"nocss\
"> </span>";
Append(r.root.toc, Concatenation(ind,
"<a href=\"", lab, "\
">", s,
"</a></span>\n"));
# label entry, if present
if IsBound(r.attributes.Label)
then
lb := NormalizedWhitespace(r.attributes.Label);
r.root.labels.(lb) := [num, lab];
r.root.labeltexts.(lb) := s;
fi;
GAPDoc2HTMLContent(r, par);
end;
GAPDoc2HTMLProcs.Mark :=
function(r, str)
GAPDoc2HTMLProcs.WrapAttr(r, str,
"Mark");
end;
GAPDoc2HTMLProcs.Item :=
function(r, str)
GAPDoc2HTMLContent(r, str);
end;
# must do the complete formatting
GAPDoc2HTMLProcs.List :=
function(r, par)
local s, a, ss, i;
s :=
"\n";
if "Mark" in List(r.content, a-> a.name)
then
# a <dl> list
Append(s,
"<dl>\n");
for a in r.content
do
if a.name =
"Mark" then
ss :=
"";
GAPDoc2HTMLProcs.Mark(a, ss);
Append(s, Concatenation(
"<dt>", ss,
"</dt>\n"));
elif a.name =
"Item" then
ss :=
"";
GAPDoc2HTMLProcs.Item(a, ss);
ss := Concatenation(Filtered(ss, IsString));
ss := Concatenation(
"<dd>", ss,
"</dd>\n");
Append(s, ss);
fi;
od;
Append(s,
"</dl>\n");
else
# a <ul> list
Append(s,
"<ul>\n");
for a in r.content
do
if a.name =
"Item" then
ss :=
"";
GAPDoc2HTMLProcs.Item(a, ss);
ss := Concatenation(Filtered(ss, IsString));
Append(s, Concatenation(
"<li>", ss,
"</li>\n"));
fi;
od;
Append(s,
"</ul>\n");
fi;
Add(par, r.count);
Add(par, s);
end;
## and this is an <ol> list
GAPDoc2HTMLProcs.Enum :=
function(r, par)
local s, i, a, ss, num;
s :=
"";
# a <ul> list
Append(s,
"<ol>\n");
for a in r.content
do
if a.name =
"Item" then
ss :=
"";
GAPDoc2HTMLProcs.Item(a, ss);
if not IsString(ss)
then
ss := Concatenation(Filtered(ss, IsString));
fi;
Append(s, Concatenation(
"<li>", ss,
"</li>\n"));
fi;
od;
Append(s,
"</ol>\n");
Add(par, r.count);
Add(par, s);
end;
GAPDoc2HTMLProcs.TheIndex :=
function(r, par)
local s;
# add index to TOC
Append(r.root.toc, Concatenation(
"<div class=\"ContChap\
"><a href=\"chapInd
",
GAPDoc2HTMLProcs.ext,
"\"><span class=\
"Heading\">
",
GAPDocTexts.d.Index,
"</span></a></div>\n"));
# the text, if available
Add(par, r.count);
if IsBound(r.root.indextext)
then
Add(par, Concatenation(
"\n<div class=\"index\
">\n<h3>",
GAPDocTexts.d.Index,
"</h3>\n\n",
r.root.indextext,
"<p> </p>\n</div>\n"));
else
Add(par,
"<p>INDEX\n-----------</p>\n\n");
fi;
end;
GAPDoc2HTMLProcs.AltYes :=
function(r)
local mark, mj, l;
# recursively mark text as HTML code (no escaping of HTML markup)
mark :=
function(r)
local a;
if IsString(r.content)
then
r.HTML := true;
elif IsList(r.content)
then
for a in r.content
do
mark(a);
od;
fi;
end;
mj := r.root.mathmode=
"MathJax";
if IsBound(r.attributes.Only)
then
l := SplitString(r.attributes.Only,
"",
"\n\r\t ,");
if "HTML" in l
then
if "MathJax" in l
then
if mj
then
mark(r);
return true;
else
return false;
fi;
elif "noMathJax" in l
then
if not mj
then
mark(r);
return true;
else
return false;
fi;
else
mark(r);
return true;
fi;
else
return false;
fi;
elif IsBound(r.attributes.Not)
then
# here, even if it is used, it is not HTML specific, so we not 'mark'
l := SplitString(r.attributes.Not,
"",
"\n\r\t ,");
if "HTML" in l
then
if "MathJax" in l
then
if mj
then
return false;
else
return true;
fi;
elif "noMathJax" in l
then
if not mj
then
return false;
else
return true;
fi;
else
return false;
fi;
else
return true;
fi;
fi;
return true;
end;
GAPDoc2HTMLProcs.Alt :=
function(r, str)
if GAPDoc2HTMLProcs.AltYes(r)
then
GAPDoc2HTMLContent(r, str);
fi;
end;
# nothing special to do
GAPDoc2HTMLProcs.Address :=
function(r, str)
GAPDoc2HTMLContent(r, str);
end;
# copy a few entries with two element names
GAPDoc2HTMLProcs.E := GAPDoc2HTMLProcs.Emph;
GAPDoc2HTMLProcs.Keyword := GAPDoc2HTMLProcs.K;
GAPDoc2HTMLProcs.Code := GAPDoc2HTMLProcs.C;
GAPDoc2HTMLProcs.File := GAPDoc2HTMLProcs.F;
GAPDoc2HTMLProcs.Button := GAPDoc2HTMLProcs.B;
GAPDoc2HTMLProcs.Arg := GAPDoc2HTMLProcs.A;
GAPDoc2HTMLProcs.Quoted := GAPDoc2HTMLProcs.Q;
GAPDoc2HTMLProcs.Par := GAPDoc2HTMLProcs.P;
# tables and utilities, not so nice since | and <Horline/> cannot be handled
GAPDoc2HTMLProcs.Table :=
function(r, s)
local str, cap, al, a, i;
str :=
"";
if not GAPDoc2HTMLProcs.AltYes(r)
then
return;
fi;
# label
if IsBound(r.attributes.Label)
then
GAPDoc2HTMLProcs.Label(rec(count := r.count, root := r.root, attributes :=
rec(Name := NormalizedWhitespace(r.attributes.Label))), str);
fi;
# alignments, table has borders and lines everywhere if any | or HorLine
# is specified
Append(str,
"<div class=\"pcenter\
"><table class=\"GAPDocTable
");
if not
'|' in r.attributes.Align and
Length(XMLElements(r,
"HorLine")) =
0 then
Append(str,
"noborder");
fi;
Append(str,
"\">\n
");
# the caption, if given
cap := Filtered(r.content, a-> a.name =
"Caption");
if Length(cap) >
0 then
GAPDoc2HTMLProcs.Caption1(cap[
1], str);
fi;
al := Filtered(r.attributes.Align, x-> x <>
'|');
for i in [
1..Length(al)]
do
if al[i] =
'c' then
al[i] :=
"\"tdcenter\
"";
elif al[i] =
'l' then
al[i] :=
"\"tdleft\
"";
else
al[i] :=
"\"tdright\
"";
fi;
od;
# the rows of the table
for a in r.content
do
if a.name =
"Row" then
GAPDoc2HTMLProcs.Row(a, str, al);
fi;
od;
Append(str,
"</table><br />\n");
Append(str,
"</div>\n\n");
Add(s, r.count);
Add(s, str);
end;
# do nothing, we call .Caption1 directly in .Table
GAPDoc2HTMLProcs.Caption :=
function(r, str)
return;
end;
# here the caption text is produced
GAPDoc2HTMLProcs.Caption1 :=
function(r, str)
Append(str, Concatenation(
"<caption class=\"GAPDocTable\
"><b>",
GAPDocTexts.d.Table,
": </b>"));
GAPDoc2HTMLContent(r, str);
Append(str,
"</caption>\n");
end;
# cannot be chosen in HTML
GAPDoc2HTMLProcs.HorLine :=
function(r, str)
end;
GAPDoc2HTMLProcs.Row :=
function(r, str, al)
local s, i, l;
Append(str,
"<tr>\n");
l := Filtered(r.content, a-> a.name =
"Item");
for i in [
1..Length(l)]
do
s :=
"";
GAPDoc2HTMLContent(l[i], s);
if not IsString(s)
then
s := Concatenation(Filtered(s, IsString));
fi;
# throw away <p> tags in table entries
if Length(s) >
5 and s{[
1..
3]} =
"<p>" and
s{[Length(s)-
5..Length(s)]} =
"</p>\n\n" then
s := s{[
4..Length(s)-
6]};
fi;
Append(str, Concatenation(
"<td class=", al[i],
">", s,
"</td>\n"));
od;
while i < Length(al)
do
Append(str,
"<td> </td>\n");
i := i+
1;
od;
Append(str,
"</tr>\n");
end;
##
## <#GAPDoc Label="GAPDoc2HTMLPrintHTMLFiles">
## <ManSection >
## <Func Arg="t[, path]" Name="GAPDoc2HTMLPrintHTMLFiles" />
## <Returns>nothing</Returns>
## <Description>
## The first argument must be a result returned by <Ref
## Func="GAPDoc2HTML"/>. The second argument is a path for the files
## to write, it can be given as string or directory object. The text
## of each chapter is written into a separate file with name
## <F>chap0.html</F>, <F>chap1.html</F>, ..., <F>chapBib.html</F>,
## and <F>chapInd.html</F>.<P/>
##
## The <Package>MathJax</Package> versions are written to files
## <F>chap0_mj.html</F>, ..., <F>chapInd_mj.html</F>. <P/>
##
## The experimental version which is produced with <C>tth</C>
## uses different names for the files, namely
## <F>chap0_sym.html</F>, and so on for files which need
## symbol fonts.
## <P/>
##
## You should also add stylesheet files to the directory with the HTML
## files, see <Ref Subsect="StyleSheets"/>.
## </Description>
## </ManSection>
## <#/GAPDoc>
##
## Finally a function to print the text files:
InstallGlobalFunction(GAPDoc2HTMLPrintHTMLFiles,
function(t, path)
local a;
if IsString(path)
then
path := Directory(path);
fi;
for a in NamesOfComponents(t)
do
if IsRecord(t.(a)) and IsBound(t.(a).text)
then
FileString(Filename(path, Concatenation(
"chap", a, t.ext)), t.(a).text);
fi;
od;
end);
InstallGlobalFunction(CopyHTMLStyleFiles,
function(dir)
local d, todo, l, s, e, f;
if not IsDirectory(dir)
then
dir := Directory(dir);
fi;
d := DirectoriesPackageLibrary(
"GAPDoc",
"styles")[
1];
todo := [];
for f in DirectoryContents(d)
do
if f =
"chooser.html" then
Add(todo, f);
else
l := Length(f);
if l >
3 and f{[l-
2..l]} =
".js" then
Add(todo, f);
elif l >
4 and f{[l-
3..l]} =
".css" then
Add(todo, f);
fi;
fi;
od;
for f in todo
do
s := StringFile(Filename(d,f));
if s = fail
then
Info(InfoGAPDoc,
1,
"Cannot read file ", Filename(d,f),
"\n");
else
e := FileString(Filename(dir,f), s);
if e = fail
then
Info(InfoGAPDoc,
1,
"Cannot write file ", Filename(dir,f),
"\n");
fi;
fi;
od;
end);