1############################################################################# 2## 3#W GAPDoc2HTML.gi GAPDoc Frank Lübeck 4## 5## 6#Y Copyright (C) 2000, Frank Lübeck, Lehrstuhl D für Mathematik, 7#Y RWTH Aachen 8## 9## The files GAPDoc2HTML.g{d,i} contain a conversion program which 10## produces from a GAPDoc XML-document an HTML version for reading the 11## document with a Web-browser. 12## 13 14## REMARKS: 15## 16## We add to all nodes of the parse tree an entry .root which points to 17## the document root. The toc-, index- and bib-information is collected 18## in the root. 19## 20## The set of elements is partitioned into two subsets - those which 21## contain whole paragraphs and those which don't. 22## 23## The handler of a paragraph containing element (see 24## GAPDoc2HTMLProcs.ParEls below) gets a list as argument to which it 25## adds entries pairwise: the first of such a pair is the paragraph 26## counter (like [3,2,1,5] meaning Chap.3, Sec.2, Subsec.1, Par.5) and 27## the second is the formatted text of this paragraph. 28## 29## Some handlers of paragraph containing elements do the formatting 30## themselves (e.g., .List), the others are handled in the main recursion 31## function `GAPDoc2HTMLContent'. 32## 33## We produce a full version of the document in HTML format, including 34## title page, abstract and other front matter, table of contents, 35## bibliography (via BibTeX-data files) and index. For this we have to 36## process a document twice (similar to LaTeX). 37## 38 39## Small utility to throw away SGML markup 40BindGlobal("FilterSGMLMarkup", function(str) 41 local p2, p1, res; 42 p2 := Position(str, '<'); 43 if p2 = fail then 44 return str; 45 fi; 46 p1 := 0; 47 res := ""; 48 while p2 <> fail do 49 Append(res, str{[p1+1..p2-1]}); 50 p1 := Position(str, '>', p2); 51 if p1 = fail then 52 return res; 53 fi; 54 p2 := Position(str, '<', p1); 55 if p2 = fail then 56 Append(res, str{[p1+1..Length(str)]}); 57 return res; 58 fi; 59 od; 60end); 61 62 63 64InstallValue(GAPDoc2HTMLProcs, rec()); 65 66## Some text attributes ([begin, end] pairs) 67GAPDoc2HTMLProcs.TextAttr := rec(); 68GAPDoc2HTMLProcs.TextAttr.Heading := ["<span class=\"Heading\">", "</span>"]; 69 70GAPDoc2HTMLProcs.TextAttr.Func := ["<code class=\"func\">", "</code>"]; 71GAPDoc2HTMLProcs.TextAttr.Arg := ["<var class=\"Arg\">", "</var>"]; 72GAPDoc2HTMLProcs.TextAttr.Example := ["<div class=\"Example\">", "</div>"]; 73GAPDoc2HTMLProcs.TextAttr.Package := ["<strong class=\"pkg\">", "</strong>"]; 74GAPDoc2HTMLProcs.TextAttr.URL := ["<span class=\"URL\">", "</span>"]; 75GAPDoc2HTMLProcs.TextAttr.Mark := ["<strong class=\"Mark\">", "</strong>"]; 76 77GAPDoc2HTMLProcs.TextAttr.K := ["<code class=\"keyw\">", "</code>"]; 78GAPDoc2HTMLProcs.TextAttr.C := ["<code class=\"code\">", "</code>"]; 79GAPDoc2HTMLProcs.TextAttr.F := ["<code class=\"file\">", "</code>"]; 80GAPDoc2HTMLProcs.TextAttr.I := ["<code class=\"i\">", "</code>"]; 81GAPDoc2HTMLProcs.TextAttr.B := ["<strong class=\"button\">", "</strong>"]; 82GAPDoc2HTMLProcs.TextAttr.Emph := ["<em>", "</em>"]; 83GAPDoc2HTMLProcs.TextAttr.Ref := ["<span class=\"RefLink\">", "</span>"]; 84GAPDoc2HTMLProcs.TextAttr.M := ["<span class=\"SimpleMath\">", "</span>"]; 85GAPDoc2HTMLProcs.TextAttr.Math := ["<span class=\"Math\">", "</span>"]; 86GAPDoc2HTMLProcs.TextAttr.GAPprompt := 87 ["<span class=\"GAPprompt\">", "</span>"]; 88GAPDoc2HTMLProcs.TextAttr.GAPbrkprompt := 89 ["<span class=\"GAPbrkprompt\">", "</span>"]; 90GAPDoc2HTMLProcs.TextAttr.GAPinput := 91 ["<span class=\"GAPinput\">", "</span>"]; 92 93# like in Text converter, but a heading and an address are not a paragraph here 94GAPDoc2HTMLProcs.ParEls := 95[ "Display", "Example", "Log", "Listing", "List", "Enum", "Item", "Table", 96 "TitlePage", "Abstract", "Copyright", "Acknowledgements", 97 "Colophon", "TableOfContents", "Bibliography", "TheIndex", 98 "Subsection", "ManSection", "Description", "Returns", "Section", 99 "Chapter", "Appendix", "Body", "Book", "WHOLEDOCUMENT", "Attr", "Fam", 100 "Filt", "Func", "InfoClass", "Meth", "Oper", "Constr", "Prop", "Var", "Verb"]; 101 102## arg: a list of strings 103## for now only ?????? 104SetGapDocHTMLOptions := function(arg) 105 local gdp; 106 gdp := GAPDoc2HTMLProcs; 107 return; 108end; 109 110GAPDoc2HTMLProcs.Head1 := "\ 111<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\ 112\n\ 113<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n\ 114 \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\ 115\n\ 116<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n\ 117<head>\n\ 118<title>GAP ("; 119 120GAPDoc2HTMLProcs.MathJaxURL := "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML"; 121 122GAPDoc2HTMLProcs.Head1MathJax := "\ 123<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\ 124\n\ 125<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n\ 126 \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\ 127\n\ 128<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n\ 129<head>\n\ 130<script type=\"text/javascript\"\n\ 131 src=\"MATHJAXURL\">\n\ 132</script>\n\ 133<title>GAP ("; 134 135GAPDoc2HTMLProcs.Head1Trans := "\ 136<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\ 137\n\ 138<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n\ 139 \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\ 140\n\ 141<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n\ 142<head>\n\ 143<title>GAP ("; 144 145GAPDoc2HTMLProcs.Head1MML := "\ 146<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\ 147<?xml-stylesheet type=\"text/xsl\" href=\"mathml.xsl\"?>\n\ 148\n\ 149<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN\"\n\ 150 \"http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd\" [\n\ 151 <!ENTITY mathml \"http://www.w3.org/1998/Math/MathML\">\n\ 152 ] >\n\ 153\n\ 154<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n\ 155<head>\n\ 156<link rel=\"stylesheet\" type=\"text/css\" href=\"mathml.css\" />\n\ 157<title>GAP ("; 158 159GAPDoc2HTMLProcs.Head2 := "\ 160</title>\n\ 161<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\" />\n\ 162<meta name=\"generator\" content=\"GAPDoc2HTML\" />\n\ 163<link rel=\"stylesheet\" type=\"text/css\" href=\"manual.css\" />\n\ 164<script src=\"manual.js\" type=\"text/javascript\"></script>\n\ 165<script type=\"text/javascript\">overwriteStyle();</script>\n\ 166</head>\n<body onload=\"jscontent()\">\n"; 167 168GAPDoc2HTMLProcs.Tail := "\n\ 169<hr />\n\ 170<p class=\"foot\">generated by <a \ 171href=\"http://www.math.rwth-aachen.de/~Frank.Luebeck/GAPDoc\">GAPDoc2HTML\ 172</a></p>\ 173\n</body>\n</html>\n"; 174 175GAPDoc2HTMLProcs.PutFilesTogether := function(l, r) 176 local files, n, tt, i, chnrs, chlink, prev, next, toplink; 177 178 chnrs := Set(List([2,4..Length(l)], i-> l[i-1][1])); 179 chnrs := Concatenation(Filtered(chnrs, a-> not a in ["Bib", "Ind"]), 180 Filtered(chnrs, a-> a in ["Bib", "Ind"])); 181 chlink := Concatenation("\n<div class=\"chlinktop\"><span class=\"chlink1\">", 182 GAPDocTexts.d.GotoChapter, ": </span>"); 183 for n in chnrs do 184 Append(chlink, Concatenation("<a href=\"chap", String(n), 185 GAPDoc2HTMLProcs.ext, "\">")); 186 if n = 0 then 187 Append(chlink, GAPDocTexts.d.Top); 188 else 189 Append(chlink, String(n)); 190 fi; 191 Append(chlink,"</a> "); 192 od; 193 Append(chlink, "</div>\n"); 194 195 toplink := Concatenation( " <a href=\"chap0", GAPDoc2HTMLProcs.ext, 196 "\">[", GAPDocTexts.d.TopofBook, "]</a> ", 197 "<a href=\"chap0", GAPDoc2HTMLProcs.ext, "#contents", 198 "\">[", GAPDocTexts.d.Contents, "]</a> " ); 199 prev := []; 200 next := []; 201 for i in [1..Length(chnrs)] do 202 if i > 1 then 203 Add(prev, Concatenation(" <a href=\"chap", String(chnrs[i-1]), 204 GAPDoc2HTMLProcs.ext, "\">[", GAPDocTexts.d.PreviousChapter, 205 "]</a> ")); 206 else 207 Add(prev, ""); 208 fi; 209 if i < Length(chnrs) then 210 Add(next, Concatenation(" <a href=\"chap", String(chnrs[i+1]), 211 GAPDoc2HTMLProcs.ext, "\">[", GAPDocTexts.d.NextChapter, 212 "]</a> ")); 213 else 214 Add(next, ""); 215 fi; 216 od; 217 # putting the paragraphs together (one string (file) for each chapter) 218 files := rec(); 219 for i in [1..Length(chnrs)] do 220 n := chnrs[i]; 221 if r.root.mathmode = "MathML" then 222 # this MathML is no longer documented 223 files.(n) := rec(text := 224 ShallowCopy(GAPDoc2HTMLProcs.Head1MML), ssnr := []); 225 elif r.root.mathmode = "Tth" then 226 files.(n) := rec(text := 227 ShallowCopy(GAPDoc2HTMLProcs.Head1Trans), ssnr := []); 228 elif r.root.mathmode = "MathJax" then 229 files.(n) := rec(text := SubstitutionSublist( 230 GAPDoc2HTMLProcs.Head1MathJax, "MATHJAXURL", 231 GAPDoc2HTMLProcs.MathJaxURL), ssnr := []); 232 else 233 files.(n) := rec(text := ShallowCopy(GAPDoc2HTMLProcs.Head1), ssnr := []); 234 fi; 235 tt := Concatenation(r.bookname, ") - "); 236 if n=0 then 237 Append(tt, GAPDocTexts.d.Contents); 238 elif IsInt(n) then 239 Append(tt, Concatenation(GAPDocTexts.d.Chapter, " ", String(n), ": ", 240 FilterSGMLMarkup(r.chaptitle.(n)))); 241 elif n="Bib" then 242 Append(tt, GAPDocTexts.d.References); 243 elif n="Ind" then 244 Append(tt, GAPDocTexts.d.Index); 245 else 246 Append(tt, Concatenation(GAPDocTexts.d.Appendix, " ", n, ": ", 247 FilterSGMLMarkup(r.chaptitle.(n)))); 248 fi; 249 Append(files.(n).text, tt); 250 Append(files.(n).text, GAPDoc2HTMLProcs.Head2); 251 # allow for chapter-wise CSS config 252 files.(n).text := SubstitutionSublist(files.(n).text, "<body", 253 Concatenation("<body class=\"chap", String(n), "\" ")); 254 Append(files.(n).text, Concatenation("\n", chlink)); 255 Append(files.(n).text, Concatenation( 256 "\n<div class=\"chlinkprevnexttop\">", 257 toplink, prev[i], next[i], "</div>\n\n")); 258 if IsBound(r.root.LinkToMathJax) then 259 # cross link to same chapter with MathJax enabled 260 Append(files.(n).text, 261 Concatenation("<p id=\"mathjaxlink\" ", 262 "class=\"pcenter\"><a href=\"chap", 263 String(n), "_mj.html\">[MathJax on]</a></p>\n")); 264 elif r.root.mathmode = "MathJax" then 265 # cross link to non-MathJax version 266 Append(files.(n).text, 267 Concatenation("<p id=\"mathjaxlink\" ", 268 "class=\"pcenter\"><a href=\"chap", 269 String(n), ".html\">[MathJax off]</a></p>\n")); 270 else 271 # we still want the hook for the [Style] link 272 Append(files.(n).text, 273 Concatenation("<p id=\"mathjaxlink\" ", 274 "class=\"pcenter\"></p>\n")); 275 fi; 276 od; 277 for i in [2,4..Length(l)] do 278 n := files.(l[i-1][1]); 279 if Length(n.ssnr)=0 or l[i-1]{[1..3]} <> n.ssnr[Length(n.ssnr)] then 280 Add(n.ssnr, l[i-1]{[1..3]}); 281 tt := GAPDoc2HTMLProcs.SectionLabel(r, l[i-1], "Subsection")[2]; 282 Append(n.text, Concatenation("<p><a id=\"", tt, "\" name=\"", tt, 283 "\"></a></p>\n")); 284 fi; 285 286 Append(n.text, l[i]); 287 od; 288 289 for i in [1..Length(chnrs)] do 290 n := chnrs[i]; 291 Append(files.(n).text, Concatenation( 292 "\n<div class=\"chlinkprevnextbot\">", 293 toplink, prev[i], next[i], "</div>\n\n")); 294 Append(files.(n).text, SubstitutionSublist(chlink, "chlinktop", 295 "chlinkbot", false)); 296 Append(files.(n).text, GAPDoc2HTMLProcs.Tail); 297 od; 298 # finally tell result the file extensions 299 files.ext := GAPDoc2HTMLProcs.ext; 300 return files; 301end; 302 303## 304## <#GAPDoc Label="GAPDoc2HTML"> 305## <ManSection > 306## <Func Arg="tree[, bibpath[, gaproot]][, mtrans]" Name="GAPDoc2HTML" /> 307## <Returns>record containing HTML files as strings and other 308## information</Returns> 309## <Description> 310## <Index Key="MathJax"><Package>MathJax</Package></Index> 311## The argument <A>tree</A> for this function is a tree 312## describing a &GAPDoc; XML document as returned by <Ref 313## Func="ParseTreeXMLString" /> (probably also checked with <Ref 314## Func="CheckAndCleanGapDocTree" />). Without an <A>mtrans</A> 315## argument this function produces an HTML version of the document 316## which can be read with any Web-browser and also be used with 317## &GAP;'s online help (see <Ref BookName="Ref" Func="SetHelpViewer" 318## />). It includes title page, bibliography, and index. The 319## bibliography is made from &BibTeX; databases. Their location must 320## be given with the argument <A>bibpath</A> (as string or directory 321## object, if not given the current directory is used). If the third 322## argument <A>gaproot</A> is given and is a string then this string 323## is interpreted as relative path to &GAP;'s main root directory. 324## Reference-URLs to external HTML-books which begin with the &GAP; 325## root path are then rewritten to start with the given relative 326## path. This makes the HTML-documentation portable provided a 327## package is installed in some standard location below the &GAP; 328## root.<P/> 329## 330## The output is a record with one component for each chapter 331## (with names <C>"0"</C>, <C>"1"</C>, ..., <C>"Bib"</C>, and 332## <C>"Ind"</C>). Each such component is again a record with 333## the following components: 334## 335## <List > 336## <Mark><C>text</C></Mark> 337## <Item>the text of an HTML file containing the whole chapter (as a 338## string)</Item> 339## <Mark><C>ssnr</C></Mark> 340## <Item>list of subsection numbers in this chapter (like <C>[3, 2, 341## 1]</C> for chapter 3, section 2, subsection 1) 342## </Item> 343## </List> 344## 345## <Emph>Standard output format without</Emph> <A>mtrans</A> 346## <Emph>argument</Emph><P/> 347## 348## The HTML code produced with this converter conforms 349## to the W3C specification <Q>XHTML 1.0 strict</Q>, see 350## <URL>http://www.w3.org/TR/xhtml1</URL>. First, this means that 351## the HTML files are valid XML files. Secondly, the 352## extension <Q>strict</Q> says in particular that the code 353## doesn't contain any explicit font or color information.<P/> 354## 355## Mathematical formulae are handled as in the text converter 356## <Ref Func="GAPDoc2Text"/>. We don't want to assume that the 357## browser can use symbol fonts. Some &GAP; users like to browse 358## the online help with <C>lynx</C>, see <Ref BookName="Ref" 359## Func="SetHelpViewer" />, which runs inside the same terminal 360## windows as &GAP;.<P/> 361## 362## To view the generated files in graphical browsers, stylesheet files 363## with layout configuration should be copied into the directory 364## with the generated HTML files, see <Ref Subsect="StyleSheets"/>. 365## <P/> 366## 367## <Label Name="mtransarg"/> 368## <Emph>Output format with</Emph> <A>mtrans</A> argument <P/> 369## 370## Currently, there are three variants of this converter available 371## which handle mathematical formulae differently. They are accessed 372## via the optional last <A>mtrans</A> argument.<P/> 373## 374## If <A>mtrans</A> is set to <C>"MathJax"</C> the formulae 375## are essentially translated as for &LaTeX; documents (there 376## is no processing of <C><M></C> elements as decribed 377## in <Ref Subsect="M"/>). Inline formulae are delimited by 378## <C>\(</C> and <C>\)</C> and displayed formulae by <C>\[</C> 379## and <C>\]</C>. With <Package>MathJax</Package> webpages 380## can contain nicely formatted scalable and searchable 381## formulae. The resulting files link by default to <URL 382## Text="http://cdn.mathjax.org">http://cdn.mathjax.org</URL> to get 383## the <Package>MathJax</Package> script and fonts. This means 384## that they can only be used on computers with internet 385## access. An alternative URL can be set by overwriting 386## <C>GAPDoc2HTMLProcs.MathJaxURL</C> before building the HTML 387## version of a manual. This way a local installation 388## of <Package>MathJax</Package> could be used. See <URL 389## Text="http://www.mathjax.org/">http://www.mathjax.org/</URL> for 390## more details.<P/> 391## 392## The following possibilities for <A>mtrans</A> are still supported, 393## but since the <Package>MathJax</Package> approach seems much better, 394## their use is deprecated.<P/> 395## 396## If the argument <A>mtrans</A> is set to <C>"Tth"</C> it is 397## assumed that you have installed the &LaTeX; to HTML translation 398## program <C>tth</C>. This is used to translate the contents of the 399## <C>M</C>, <C>Math</C> and <C>Display</C> elements into HTML 400## code. Note that the resulting code is not compliant with any 401## standard. Formally it is <Q>XHTML 1.0 Transitional</Q>, it 402## contains explicit font specifications and the characters of 403## mathematical symbols are included via their position in a 404## <Q>Symbol</Q> font. Some graphical browsers can be configured 405## to display this in a useful manner, check <URL Text="the 406## Tth homepage">http://hutchinson.belmont.ma.us/tth/</URL> for more 407## details.<P/> 408## 409## This function works by running recursively through the document 410## tree and calling a handler function for each &GAPDoc; 411## XML element. Many of these handler functions (usually in 412## <C>GAPDoc2TextProcs.<ElementName></C>) are not difficult to 413## understand (the greatest complications are some commands for index 414## entries, labels or the output of page number information). So it 415## should be easy to adjust certain details to your own taste by slight 416## modifications of the program. <P/> 417## 418## The result of this converter can be written to files with the 419## command <Ref Func="GAPDoc2HTMLPrintHTMLFiles" />.<P/> 420## 421## There are two user preferences for reading the HTML manuals produced by 422## &GAPDoc;. A user can choose among several style files which determine the 423## appearance of the manual pages with 424## <C>SetUserPreference("GAPDoc", "HTMLStyle", [...]);</C> where the list in 425## the third argument are arguments for <Ref Func="SetGAPDocHTMLStyle"/>. 426## The second preference is set by 427## <C>SetUserPreference("GAPDoc", "UseMathJax", ...);</C> where the third 428## argument is <K>true</K> or <K>false</K> (default). If this is set to 429## <K>true</K>, the &GAP; help system displays the <Package>MathJax</Package> 430## version of the HTML manuals. 431## </Description> 432## </ManSection> 433## <#/GAPDoc> 434## 435## <#GAPDoc Label="HTMLStyleSheets"> 436## <Subsection Label="StyleSheets"> 437## <Heading>Stylesheet files</Heading> 438## <Index>CSS stylesheets</Index> 439## 440## For graphical browsers the layout of the generated HTML manuals can be 441## highly configured by cascading stylesheet (CSS) and javascript 442## files. Such files are provided in the <F>styles</F> directory of the 443## &GAPDoc; package.<P/> 444## 445## We recommend that these files are copied into each manual directory 446## (such that each of them is selfcontained). There is a utility 447## function <Ref Func="CopyHTMLStyleFiles" /> which does this. Of 448## course, these files may be changed or new styles may be added. New 449## styles may also be sent to the &GAPDoc; authors for possible 450## inclusion in future versions.<P/> 451## 452## The generated HTML files refer to the file <F>manual.css</F> 453## which conforms to the W3C specification CSS 2.0, see 454## <URL>http://www.w3.org/TR/REC-CSS2</URL>, and the javascript file 455## <F>manual.js</F> (only in browsers which support CSS or javascript, 456## respectively; but the HTML files are also readable without 457## any of them). To add a style <C>mystyle</C> one or both of 458## <F>mystyle.css</F> and <F>mystyle.js</F> must be provided; these can 459## overwrite default settings and add new javascript functions. For 460## more details see the comments in <F>manual.js</F>.<P/> 461## </Subsection> 462## <ManSection > 463## <Func Arg="dir" Name="CopyHTMLStyleFiles" /> 464## <Returns>nothing</Returns> 465## <Description> 466## This utility function copies the <F>*.css</F> and <F>*.js</F> files 467## from the <F>styles</F> directory of the &GAPDoc; package into the 468## directory 469## <A>dir</A>. 470## </Description> 471## </ManSection> 472## <#/GAPDoc> 473## 474## the basic call, used recursively with a result r from GetElement 475## and a string str or list l to which the output should be appended 476# arg: r[, bibpath] (then a list is returned, only for whole document) 477# or: r, str (then the output is appended to string or list str) 478InstallGlobalFunction(GAPDoc2HTML, function(arg) 479 local r, str, linelength, name; 480 r := arg[1]; 481 # first check for the mode 482 if arg[Length(arg)] in ["MathML", "Tth", "MathJax"] then 483 r.mathmode := arg[Length(arg)]; 484 arg := arg{[1..Length(arg)-1]}; 485 else 486 r.mathmode := "Text"; 487 fi; 488 489 if Length(arg) > 1 then 490 str := arg[2]; 491 else 492 str := []; 493 fi; 494 if r.name = "WHOLEDOCUMENT" then 495 # choose different file name conventions such that these 496 # conversions can coexist 497 if r.mathmode = "MathML" then 498 GAPDoc2HTMLProcs.ext := "_mml.xml"; 499 elif r.mathmode = "Tth" then 500 GAPDoc2HTMLProcs.ext := "_sym.html"; 501 elif r.mathmode = "MathJax" then 502 GAPDoc2HTMLProcs.ext := "_mj.html"; 503 else 504 GAPDoc2HTMLProcs.ext := ".html"; 505 fi; 506 if IsDirectory(str) then 507 r.bibpath := str; 508 else 509 if Length(str) = 0 then 510 str := "."; 511 fi; 512 r.bibpath := Directory(str); 513 fi; 514 str := []; 515 if Length(arg) > 2 and IsString(arg[3]) then 516 GAPDoc2HTMLProcs.RelPath := arg[3]; 517 GAPInfo.MainRootPath := Filtered(GAPInfo.RootPaths, a-> 518 Filename([Directory(a)], "lib/init.g")<>fail)[1]; 519 else 520 Unbind(GAPDoc2HTMLProcs.RelPath); 521 fi; 522 fi; 523 524 name := r.name; 525 if not IsBound(GAPDoc2HTMLProcs.(name)) then 526 Info(InfoGAPDoc, 1, "#W WARNING: Don't know how to process element ", name, 527 " ---- ignored\n"); 528 else 529 GAPDoc2HTMLProcs.(r.name)(r, str); 530 fi; 531 532 if r.name ="WHOLEDOCUMENT" then 533 # put final record together and return it 534 return GAPDoc2HTMLProcs.PutFilesTogether(str, r); 535 fi; 536 537 return str; 538end); 539 540## recursion through the tree and collecting paragraphs 541BindGlobal("GAPDoc2HTMLContent", function(r, l) 542 local par, cont, i, count, s, a; 543 544 # utility: append counter and formatted paragraph to l 545 par := function(s) 546 if Length(s)>0 then 547 s := NormalizedWhitespace(s); 548 if Length(s)>0 then 549 Add(l, count); 550 Add(l, Concatenation("<p>", s, "</p>\n\n")); 551 fi; 552 fi; 553 end; 554 555 # if not containing paragraphs, then l is string to append to 556 if not r.name in GAPDoc2HTMLProcs.ParEls then 557 for a in r.content do 558 GAPDoc2HTML(a, l); 559 od; 560 return; 561 fi; 562 563 # otherwise we have to collect text and paragraphs 564 cont := r.content; 565 # checking for alternatives 566 i := 1; 567 while i < Length(cont) do 568 if cont[i].name = "Alt" and GAPDoc2HTMLProcs.AltYes(cont[i]) then 569 cont := Concatenation(cont{[1..i-1]}, cont[i].content, 570 cont{[i+1..Length(cont)]}); 571 else 572 i := i + 1; 573 fi; 574 od; 575 count := r.count; 576 s := ""; 577 for a in cont do 578 if a.count <> count then 579 par(s); 580 count := a.count; 581 s := ""; 582 fi; 583 if a.name in GAPDoc2HTMLProcs.ParEls then 584 # recursively collect paragraphs 585 GAPDoc2HTML(a, l); 586 else 587 # collect text for current paragraph 588 GAPDoc2HTML(a, s); 589 fi; 590 od; 591 if Length(s)>0 then 592 par(s); 593 fi; 594end); 595 596 597## write head and foot of HTML file. 598GAPDoc2HTMLProcs.WHOLEDOCUMENT := function(r, par) 599 local i, pi, t, el, remdiv, math, pos, pos1, str, dat, datbt, bib, b, 600 keys, need, labels, tmp, j, diff, text, a, k, l, ind, opts; 601 602 ## add paragraph numbers to all nodes of the document 603 AddParagraphNumbersGapDocTree(r); 604 605 if not IsBound(r.six) then 606 Info(InfoGAPDoc, 1, "#W WARNING: Using labels from section numbers, \n", 607 "#W consider running the converter for the text version first!\n"); 608 fi; 609 610 ## add a link .root to the root of the document to all nodes 611 ## (then we can collect information about indexing and so on 612 ## there) 613 AddRootParseTree(r); 614 r.index := []; 615 r.toc := ""; 616 r.labels := rec(); 617 r.labeltexts := rec(); 618 if not IsBound(r.bibkeys) then 619 r.bibkeys := []; 620 fi; 621 r.chaptitle := rec(); 622 r.chapsectlinks := rec(); 623 624 ## checking for processing instructions before the book starts 625 ## example: <?HTML option1="value1" ?> 626 i := 1; 627 pi := rec(); 628 while not r.content[i].name = "Book" do 629 if r.content[i].name = "XMLPI" then 630 t := r.content[i].content; 631 if Length(t) > 4 and t{[1..5]} = "HTML " then 632 el := GetSTag(Concatenation("<", t, ">"), 2); 633 for a in NamesOfComponents(el.attributes) do 634 pi.(a) := el.attributes.(a); 635 od; 636 fi; 637 fi; 638 i := i+1; 639 od; 640 641 # setup for external conversion of maths (MathML with ttm, tth, ...) 642 if r.mathmode in ["MathML", "Tth"] then 643 r.ConvInput := ""; 644 r.MathCount := 0; 645 fi; 646 647 ## Now the actual work starts, we give the processing instructions found 648 ## so far to the Book handler. 649 ## We call the Book handler twice and produce index, bibliography, toc 650 ## in between. 651 Info(InfoGAPDoc, 1, "#I First run, collecting cross references, ", 652 "index, toc, bib and so on . . .\n"); 653 # with this flag we avoid unresolved references warnings in first run 654 GAPDoc2HTMLProcs.FirstRun := true; 655 GAPDoc2HTMLProcs.Book(r.content[i], [], pi); 656 GAPDoc2HTMLProcs.FirstRun := false; 657 658 # now the toc is ready 659 Info(InfoGAPDoc, 1, "#I Table of contents complete.\n"); 660 r.toctext := r.toc; 661 r.chapsectlinkstext := r.chapsectlinks; 662 663 # utility to remove <div> tags 664 remdiv := function(s) 665 local pos, pos1; 666 pos := PositionSublist(s, "<div"); 667 while pos <> fail do 668 pos1 := Position(s, '>', pos); 669 s := Concatenation(s{[1..pos-1]}, s{[pos1+1..Length(s)]}); 670 pos := PositionSublist(s, "<div"); 671 od; 672 pos := PositionSublist(s, "</div"); 673 while pos <> fail do 674 pos1 := Position(s, '>', pos); 675 s := Concatenation(s{[1..pos-1]}, s{[pos1+1..Length(s)]}); 676 pos := PositionSublist(s, "</div"); 677 od; 678 return s; 679 end; 680 681 # MathML or Tth translation 682 if r.mathmode in ["MathML", "Tth"] then 683 Info(InfoGAPDoc, 1, "#I translating formulae with \c"); 684 FileString("tempCONV.tex", r.ConvInput); 685 if r.mathmode = "MathML" then 686 Info(InfoGAPDoc, 1, "ttm.\n"); 687 Exec("rm -f tempCONV.html; ttm -L -r tempCONV.tex > tempCONV.html"); 688 elif r.mathmode = "Tth" then 689 Info(InfoGAPDoc, 1, "tth.\n"); 690 Exec("rm -f tempCONV.html; tth -w2 -r -u tempCONV.tex > tempCONV.html"); 691 fi; 692 math := StringFile("tempCONV.html"); 693 # correct the <var> tags 694 math := SubstitutionSublist(math, "< var >", "<var>"); 695 math := SubstitutionSublist(math, "< /var >", "</var>"); 696 math := SubstitutionSublist(math, 697 "<mo><</mo><mi>var</mi><mo>></mo>", "<var>"); 698 math := SubstitutionSublist(math, 699 "<mo><</mo><mo>/</mo><mi>var</mi><mo>></mo>", "</var>"); 700 r.MathList := []; 701 pos := PositionSublist(math, "TeXFormulaeDelim"); 702 while pos <> fail do 703 pos1 := PositionSublist(math, "TeXFormulaeDelim", pos); 704 if pos1 <> fail then 705 Add(r.MathList, remdiv(math{[pos+16..pos1-1]})); 706 else 707 Add(r.MathList, remdiv(math{[pos+16..Length(math)]})); 708 fi; 709 pos := pos1; 710 od; 711 fi; 712 713 # .index has entries of form [sorttext, subsorttext, numbertext, 714 # entrytext, url[, subtext]] 715 Info(InfoGAPDoc, 1, "#I Producing the index . . .\n"); 716 SortBy(r.index, a-> [a[1],STRING_LOWER(a[2]), 717 List(SplitString(a[3],".-",""), Int)]); 718 str := ""; 719 ind := r.index; 720 k := 1; 721 while k <= Length(ind) do 722 if k > 1 and ind[k][4] = ind[k-1][4] then 723 Append(str, " "); 724 else 725 Append(str, ind[k][4]); 726 fi; 727 if IsBound(ind[k][6]) then 728 if k = 1 or ind[k][4] <> ind[k-1][4] then 729 Append(str, ", "); 730 fi; 731 Append(str, ind[k][6]); 732 elif Length(ind[k][2]) > 0 then 733 if k = 1 or ind[k][4] <> ind[k-1][4] then 734 Append(str, ", "); 735 fi; 736 Append(str, ind[k][2]); 737 fi; 738 l := k; 739 while l <= Length(ind) and ind[l][4] = ind[k][4] and 740 ((IsBound(ind[k][6]) and IsBound(ind[l][6]) 741 and ind[k][6] = ind[l][6]) or 742 (not IsBound(ind[k][6]) and not IsBound(ind[l][6]) 743 and ind[k][2] = ind[l][2])) do 744 Append(str, Concatenation(" <a href=\"", ind[l][5], "\">", 745 ind[l][3], "</a> ")); 746 l := l+1; 747 od; 748 Append(str, "<br />\n"); 749 k := l; 750 od; 751 r.indextext := str; 752 753 if Length(r.bibkeys) > 0 then 754 GAPDocAddBibData(r); 755 Info(InfoGAPDoc, 1, "#I Writing bibliography . . .\n"); 756 if r.root.mathmode = "MathJax" then 757 opts := rec(MathJax := true); 758 else 759 opts := rec(); 760 fi; 761 need := List(r.bibentries, a-> RecBibXMLEntry(a, "HTML", r.bibstrings, 762 opts)); 763 # copy the unique labels 764 for a in [1..Length(need)] do 765 need[a].key := r.biblabels[a]; 766 od; 767 text := ""; 768 for a in need do 769 # an anchor for links from the citations 770 Append(text, Concatenation("\n<p><a id=\"biB", a.Label, 771 "\" name=\"biB", a.Label, "\"></a></p>\n")); 772 Append(text, StringBibAsHTML(a, false)); 773 od; 774 r.bibtext := text; 775 fi; 776 777 # second run 778 r.index := []; 779 Info(InfoGAPDoc, 1, "#I Second run through document . . .\n"); 780 GAPDoc2HTMLProcs.Book(r.content[i], par, pi); 781 782 for a in ["MathList", "MathCount", "index", "toc"] do 783 Unbind(r.(a)); 784 od; 785 ## remove the links to the root ??? 786## RemoveRootParseTree(r); 787end; 788 789## comments and processing instructions are in general ignored 790GAPDoc2HTMLProcs.XMLPI := function(r, str) 791 return; 792end; 793GAPDoc2HTMLProcs.XMLCOMMENT := function(r, str) 794 return; 795end; 796 797# two utilities for attribute values like labels or text with special 798# XML (or LaTeX) characters which gets printed 799GAPDoc2HTMLProcs.EscapeAttrVal := function(str) 800 str := SubstitutionSublist(str, "&", "&"); 801 str := SubstitutionSublist(str, "<", "<"); 802 str := SubstitutionSublist(str, ">", ">"); 803 return str; 804end; 805 806# do nothing with Ignore 807GAPDoc2HTMLProcs.Ignore := function(arg) 808end; 809 810# just process content 811GAPDoc2HTMLProcs.Book := function(r, par, pi) 812 # copy the name of the book to the root 813 r.root.bookname := r.attributes.Name; 814 GAPDoc2HTMLContent(r, par); 815end; 816 817## Body is sectioning element 818GAPDoc2HTMLProcs.Body := GAPDoc2HTMLContent; 819 820## the title page, the most complicated looking function 821GAPDoc2HTMLProcs.TitlePage := function(r, par) 822 local strn, l, s, a, aa, cont, ss; 823 824 strn := "<div class=\"pcenter\">\n"; 825 # title 826 l := Filtered(r.content, a-> a.name = "Title"); 827 s := ""; 828 GAPDoc2HTMLContent(l[1], s); 829 s := Concatenation("\n<h1>", NormalizedWhitespace(s), "</h1>\n\n"); 830 Append(strn, s); 831 832 # subtitle 833 l := Filtered(r.content, a-> a.name = "Subtitle"); 834 if Length(l)>0 then 835 s := ""; 836 GAPDoc2HTMLContent(l[1], s); 837 s := Concatenation("\n<h2>", NormalizedWhitespace(s), "</h2>\n\n"); 838 Append(strn, s); 839 fi; 840 841 # version 842 l := Filtered(r.content, a-> a.name = "Version"); 843 if Length(l)>0 then 844 s := "<p>"; 845 GAPDoc2HTMLContent(l[1], s); 846 while Length(s)>0 and s[Length(s)] in WHITESPACE do 847 Unbind(s[Length(s)]); 848 od; 849 Append(s, "</p>\n\n"); 850 Append(strn, s); 851 fi; 852 853 # date 854 l := Filtered(r.content, a-> a.name = "Date"); 855 if Length(l)>0 then 856 s := "<p>"; 857 GAPDoc2HTMLContent(l[1], s); 858 Append(strn, s); 859 Append(strn, "</p>\n\n"); 860 fi; 861 Append(strn, "</div>\n"); 862 863 # an extra comment 864 l := Filtered(r.content, a-> a.name = "TitleComment"); 865 if Length(l) > 0 then 866 s := "<p>"; 867 GAPDoc2HTMLContent(l[1], s); 868 Append(s, "</p>\n"); 869 Append(strn, s); 870 fi; 871 872 # author name(s) 873 l := Filtered(r.content, a-> a.name = "Author"); 874 for a in l do 875 s := "<p><b>"; 876 aa := ShallowCopy(a); 877 aa.content := Filtered(a.content, 878 b-> not b.name in ["Email", "Homepage", "Address"]); 879 GAPDoc2HTMLContent(aa, s); 880 Append(strn, s); 881 Append(strn, "</b>\n"); 882 cont := List(a.content, b-> b.name); 883 if "Email" in cont then 884 s := ""; 885 GAPDoc2HTML(a.content[Position(cont, "Email")], s); 886 s := NormalizedWhitespace(s); 887 Append(strn, Concatenation("<br />", GAPDocTexts.d.Email, ": ", s, "\n")); 888 fi; 889 if "Homepage" in cont then 890 s := ""; 891 GAPDoc2HTML(a.content[Position(cont, "Homepage")], s); 892 s := NormalizedWhitespace(s); 893 Append(strn, Concatenation("<br />", GAPDocTexts.d.Homepage, 894 ": ", s, "\n")); 895 fi; 896 if "Address" in cont then 897 s := ""; 898 GAPDoc2HTMLContent(a.content[Position(cont, "Address")], s); 899 s := NormalizedWhitespace(s); 900 Append(strn, Concatenation("<br />", GAPDocTexts.d.Address, 901 ": <br />", s, "\n")); 902 fi; 903 Append(strn, "</p>"); 904 od; 905 Append(strn, "\n\n"); 906 907 Add(par, r.count); 908 Add(par, strn); 909 910 # an Address element in title page 911 l := Filtered(r.content, a-> a.name = "Address"); 912 if Length(l) > 0 then 913 s := ""; 914 GAPDoc2HTMLContent(l[1], s); 915 s := NormalizedWhitespace(s); 916 Append(strn, Concatenation("<p><b>", GAPDocTexts.d.Address, 917 ":</b><br />\n", s, "</p>\n")); 918 fi; 919 920 # abstract, copyright page, acknowledgements, colophon 921 for ss in ["Abstract", "Copyright", "Acknowledgements", "Colophon" ] do 922 l := Filtered(r.content, a-> a.name = ss); 923 if Length(l)>0 then 924 Add(par, l[1].count); 925 Add(par, Concatenation("<h3>", GAPDocTexts.d.(ss), "</h3>\n")); 926 GAPDoc2HTMLContent(l[1], par); 927 fi; 928 od; 929end; 930 931## these produce text for an URL 932## arg: r, str[, pre] 933GAPDoc2HTMLProcs.Link := GAPDoc2HTMLContent; 934GAPDoc2HTMLProcs.LinkText := GAPDoc2HTMLContent; 935GAPDoc2HTMLProcs.URL := function(arg) 936 local r, str, pre, rr, txt, s; 937 r := arg[1]; 938 str := arg[2]; 939 if Length(arg)>2 then 940 pre := arg[3]; 941 else 942 pre := ""; 943 fi; 944 rr := First(r.content, a-> a.name = "LinkText"); 945 if rr <> fail then 946 txt := ""; 947 GAPDoc2HTML(rr, txt); 948 rr := First(r.content, a-> a.name = "Link"); 949 if rr = fail then 950 Info(InfoGAPDoc, 1, "#W missing <Link> element for text ", txt, "\n"); 951 s := "MISSINGLINK"; 952 else 953 s := ""; 954 GAPDoc2HTMLContent(rr, s); 955 fi; 956 else 957 s := ""; 958 GAPDoc2HTMLContent(r, s); 959 if IsBound(r.attributes.Text) then 960 txt := r.attributes.Text; 961 else 962 txt := s; 963 fi; 964 fi; 965 Append(str, Concatenation(GAPDoc2HTMLProcs.TextAttr.URL[1], 966 "<a href=\"", pre, s, "\">", txt, "</a>")); 967 Append(str, GAPDoc2HTMLProcs.TextAttr.URL[2]); 968end; 969 970GAPDoc2HTMLProcs.Homepage := GAPDoc2HTMLProcs.URL; 971 972GAPDoc2HTMLProcs.Email := function(r, str) 973 # we add the `mailto:' phrase 974 GAPDoc2HTMLProcs.URL(r, str, "mailto:"); 975end; 976 977## utility: generate a chapter or (sub)section-number string 978GAPDoc2HTMLProcs.SectionNumber := function(count, sect) 979 local res; 980 res := ""; 981 if IsString(count[1]) or count[1]>0 then 982 Append(res, String(count[1])); 983 fi; 984 if sect="Chapter" or sect="Appendix" then 985 return res; 986 fi; 987 Add(res, '.'); 988 if count[2]>0 then 989 Append(res, String(count[2])); 990 fi; 991 if sect="Section" then 992 return res; 993 fi; 994 if count[3]>0 then 995 Append(res, Concatenation("-", String(count[3]))); 996 fi; 997 return res; 998end; 999 1000## utility: generate a chapter or (sub)section-number string 1001GAPDoc2HTMLProcs.SectionLabel := function(r, count, sect) 1002 local res, a; 1003 if IsString(count[1]) or count[1]>0 then 1004 res := Concatenation("chap", String(count[1]), GAPDoc2HTMLProcs.ext); 1005 else 1006 res := Concatenation("chap0", GAPDoc2HTMLProcs.ext); 1007 fi; 1008 res := [res, ""]; 1009 if not IsBound(r.root.six) then 1010 if sect="Chapter" then 1011 return res; 1012 fi; 1013 Append(res[2], Concatenation("s", String(count[2]))); 1014 Append(res[2], Concatenation("ss", String(count[3]))); 1015 return res; 1016 else 1017## a := First(r.root.six, a-> a[3] = count{[1..3]}); 1018 a := PositionSet(r.root.sixcount, count{[1..3]}); 1019 if a <> fail then 1020 a := r.root.six[r.root.sixindex[a]]; 1021 fi; 1022 if a = fail or not IsBound(a[7]) then 1023 return GAPDoc2HTMLProcs.SectionLabel(rec(root:=rec()), count, sect); 1024 else 1025 Append(res[2], a[7]); 1026 return res; 1027 fi; 1028 fi; 1029end; 1030 1031## the sectioning commands are just translated and labels are 1032## generated, if given as attribute 1033GAPDoc2HTMLProcs.ChapSect := function(r, par, sect) 1034 local num, posh, s, ind, strn, lab, types, nrs, hord, a, pos, l, i; 1035 1036 types := ["Chapter", "Appendix", "Section", "Subsection"]; 1037 nrs := ["3", "3", "4", "5"]; 1038 hord := nrs[Position(types, sect)]; 1039 1040 Add(par, r.count); 1041 # if available, start with links to sections in chapter/appendix 1042 if sect in ["Chapter", "Appendix"] then 1043 if IsBound(r.root.chapsectlinkstext) and 1044 IsBound(r.root.chapsectlinkstext.(r.count[1])) then 1045 Add(par, r.root.chapsectlinkstext.(r.count[1])); 1046 fi; 1047 fi; 1048 if par[Length(par)] = r.count then 1049 Add(par, ""); 1050 fi; 1051 1052 # section number as string 1053 num := GAPDoc2HTMLProcs.SectionNumber(r.count, sect); 1054 # and as anchor 1055 lab := GAPDoc2HTMLProcs.SectionLabel(r, r.count, "Subsection"); 1056 lab := Concatenation(lab[1], "#", lab[2]); 1057 1058 # the heading 1059 posh := Position(List(r.content, a-> a.name), "Heading"); 1060 if posh <> fail then 1061 s := ""; 1062 # first the .six entry 1063 GAPDoc2HTMLProcs.Heading1(r.content[posh], s); 1064 if hord = "3" then 1065 r.root.chaptitle.(r.count[1]) := s; 1066 fi; 1067 1068 # label entry, if present 1069 if IsBound(r.attributes.Label) then 1070 r.root.labels.(r.attributes.Label) := [num, lab]; 1071 r.root.labeltexts.(r.attributes.Label) := s; 1072 fi; 1073 1074 # the heading text 1075 Append(par[Length(par)], 1076 Concatenation("\n<h", hord, ">", num, " ", s, "</h", hord, ">\n\n")); 1077 1078 # table of contents entry 1079 s := Concatenation( num, " ", s); 1080 if sect in ["Chapter", "Appendix"] then 1081 if r.count[1] >= 1 then 1082 ind := "<div class=\"ContChap\">"; 1083 fi; 1084 elif sect="Section" then 1085 ind := ""; 1086 if r.count[2] >= 1 then 1087 Append(ind, "<div class=\"ContSect\">"); 1088 fi; 1089 Append(ind, "<span class=\"tocline\"><span class=\"nocss\"> </span>"); 1090 elif sect="Subsection" then 1091 ind := "<span class=\"ContSS\"><br /><span class=\"nocss\"> </span>"; 1092 else 1093 ind := ""; 1094 fi; 1095 Append(r.root.toc, Concatenation(ind, "<a href=\"", 1096 lab, "\">", s, "</a>\n")); 1097 if sect="Section" then 1098 Append(r.root.toc, "</span>\n<div class=\"ContSSBlock\">\n"); 1099 fi; 1100 fi; 1101 1102 # the actual content 1103 GAPDoc2HTMLContent(r, par); 1104 1105 # possibly close <div> or <span> in content 1106 if posh <> fail then 1107 if sect in ["Chapter", "Appendix" ] then 1108 Append(r.root.toc, "</div>\n"); 1109 elif sect="Section" then 1110 # remove last line if no subsections 1111 l := Length(r.root.toc); 1112 if r.root.toc{[l-25..l]} = "<div class=\"ContSSBlock\">\n" then 1113 for i in [0..25] do Unbind(r.root.toc[l-i]); od; 1114 Append(r.root.toc, "</div>\n"); 1115 else 1116 Append(r.root.toc, "</div></div>\n"); 1117 fi; 1118 elif sect="Subsection" then 1119 Append(r.root.toc, "</span>\n"); 1120 fi; 1121 fi; 1122 # if in chapter, also use the section links in top of page 1123 if sect in ["Chapter", "Appendix"] then 1124 a := Reversed(r.root.toc); 1125 pos := PositionSublist(a, Reversed("<div class=\"ContChap\">")); 1126 a := Reversed(a{[1..pos-1]}); 1127 r.root.chapsectlinks.(r.count[1]) := Concatenation( 1128 "<div class=\"ChapSects\">", a); 1129 fi; 1130end; 1131 1132 1133## this really produces the content of the heading 1134GAPDoc2HTMLProcs.Heading1 := function(r, str) 1135 GAPDoc2HTMLProcs.WrapAttr(r, str, "Heading"); 1136end; 1137## and this ignores the heading (for simpler recursion) 1138GAPDoc2HTMLProcs.Heading := function(r, str) 1139end; 1140 1141GAPDoc2HTMLProcs.Chapter := function(r, par) 1142 GAPDoc2HTMLProcs.ChapSect(r, par, "Chapter"); 1143end; 1144 1145GAPDoc2HTMLProcs.Appendix := function(r, par) 1146 GAPDoc2HTMLProcs.ChapSect(r, par, "Appendix"); 1147end; 1148 1149GAPDoc2HTMLProcs.Section := function(r, par) 1150 GAPDoc2HTMLProcs.ChapSect(r, par, "Section"); 1151end; 1152 1153GAPDoc2HTMLProcs.Subsection := function(r, par) 1154 GAPDoc2HTMLProcs.ChapSect(r, par, "Subsection"); 1155end; 1156 1157## table of contents, just puts "TOC" in first run 1158GAPDoc2HTMLProcs.TableOfContents := function(r, par) 1159 Add(par, r.count); 1160 if IsBound(r.root.toctext) then 1161 Add(par, Concatenation("\n<div class=\"contents\">\n<h3>", 1162 GAPDocTexts.d.Contents, 1163 "<a id=\"contents\" name=\"contents\"></a></h3>\n\n", 1164 r.root.toctext, "<br />\n</div>\n")); 1165 else 1166 Add(par,"<p>TOC\n-----------</p>\n\n"); 1167 fi; 1168end; 1169 1170## bibliography, just "BIB" in first run, store databases in root 1171GAPDoc2HTMLProcs.Bibliography := function(r, par) 1172 local s; 1173 # add references to TOC 1174 Append(r.root.toc, Concatenation("<div class=\"ContChap\"><a href=\"chapBib", 1175 GAPDoc2HTMLProcs.ext, "\"><span class=\"Heading\">", 1176 GAPDocTexts.d.References, "</span></a></div>\n")); 1177 r.root.bibdata := r.attributes.Databases; 1178 if IsBound(r.attributes.Style) then 1179 r.root.bibstyle := r.attributes.Style; 1180 fi; 1181 Add(par, r.count); 1182 if IsBound(r.root.bibtext) then 1183 Add(par, Concatenation("\n<h3>", GAPDocTexts.d.References, "</h3>\n\n", 1184 r.root.bibtext, "<p> </p>\n\n")); 1185 else 1186 Add(par,"<p>BIB\n-----------</p>\n"); 1187 fi; 1188end; 1189 1190GAPDoc2HTMLProcs.PCDATAFILTER := function(r, str) 1191 local s, a; 1192 s := r.content; 1193 if not IsBound(r.HTML) and (Position(s, '<') <> fail or 1194 Position(s, '&') <> fail or Position(s, '>') <> fail) then 1195 for a in s do 1196 if a='<' then 1197 Append(str, "<"); 1198 elif a='&' then 1199 Append(str, "&"); 1200 elif a='>' then 1201 Append(str, ">"); 1202 else 1203 Add(str, a); 1204 fi; 1205 od; 1206 else 1207 Append(str, s); 1208 fi; 1209end; 1210# and without filter (e.g., for collecting formulae 1211GAPDoc2HTMLProcs.PCDATANOFILTER := function(r, str) 1212 Append(str, r.content); 1213end; 1214 1215GAPDoc2HTMLProcs.PCDATAFILTER; 1216## default is with filter 1217GAPDoc2HTMLProcs.PCDATA := GAPDoc2HTMLProcs.PCDATAFILTER; 1218 1219## end of paragraph (end with double newline) 1220GAPDoc2HTMLProcs.P := function(r, str) 1221# nothing to do, the "<p>" are added in main loop (GAPDoc2HTML) 1222end; 1223 1224GAPDoc2HTMLProcs.Br := function(r, str) 1225 Append(str, "<br />\n"); 1226end; 1227 1228## wrapping text attributes 1229GAPDoc2HTMLProcs.WrapAttr := function(r, str, a) 1230 local s, tt; 1231 s := ""; 1232 GAPDoc2HTMLContent(r, s); 1233 tt := GAPDoc2HTMLProcs.TextAttr.(a); 1234 Append(str, Concatenation(tt[1], s, tt[2])); 1235end; 1236 1237## GAP keywords 1238GAPDoc2HTMLProcs.K := function(r, str) 1239 GAPDoc2HTMLProcs.WrapAttr(r, str, "K"); 1240end; 1241 1242## buttons 1243GAPDoc2HTMLProcs.B := function(r, str) 1244 GAPDoc2HTMLProcs.WrapAttr(r, str, "B"); 1245end; 1246 1247## verbatim GAP code 1248GAPDoc2HTMLProcs.C := function(r, str) 1249 GAPDoc2HTMLProcs.WrapAttr(r, str, "C"); 1250end; 1251 1252## file names 1253GAPDoc2HTMLProcs.F := function(r, str) 1254 GAPDoc2HTMLProcs.WrapAttr(r, str, "F"); 1255end; 1256 1257## argument names (same as Arg) 1258GAPDoc2HTMLProcs.A := function(r, str) 1259 GAPDoc2HTMLProcs.WrapAttr(r, str, "Arg"); 1260end; 1261 1262GAPDoc2HTMLProcs.MathConvHelper := function(r, str, db, de) 1263 local s, x; 1264 if IsBound(r.root.MathList) then 1265 # conversion already available 1266 r.root.MathCount := r.root.MathCount + 1; 1267 Append(str, r.root.MathList[r.root.MathCount]); 1268 else 1269 # add to input for converter 1270 if IsString(r.content) then 1271 s := r.content; 1272 else 1273 s := ""; 1274 GAPDoc2HTMLProcs.PCDATA := GAPDoc2HTMLProcs.PCDATANOFILTER; 1275 for x in r.content do 1276 GAPDoc2HTML(x, s); 1277 od; 1278 GAPDoc2HTMLProcs.PCDATA := GAPDoc2HTMLProcs.PCDATAFILTER; 1279 fi; 1280 s := Concatenation("TeXFormulaeDelim", db, s, de); 1281 Append(r.root.ConvInput, s); 1282 Append(str, "FORMULA"); 1283 fi; 1284end; 1285 1286 1287## simple maths, here we try to substitute TeX command to something which 1288## looks ok in text mode 1289GAPDoc2HTMLProcs.M := function(r, str) 1290 local s, ss, save; 1291 if r.root.mathmode in ["MathML", "Tth"] then 1292 GAPDoc2HTMLProcs.MathConvHelper(r, str, "$", "$"); 1293 return; 1294 fi; 1295 s := ""; 1296 GAPDoc2HTMLProcs.PCDATA := GAPDoc2HTMLProcs.PCDATANOFILTER; 1297 # a hack, since we want to allow <A> in formulae 1298 save := GAPDoc2HTMLProcs.TextAttr.Arg; 1299 GAPDoc2HTMLProcs.TextAttr.Arg := ["TEXTaTTRvARBEGIN", "TEXTaTTRvAREND"]; 1300 GAPDoc2HTMLContent(r, s); 1301 GAPDoc2HTMLProcs.TextAttr.Arg := save; 1302 GAPDoc2HTMLProcs.PCDATA := GAPDoc2HTMLProcs.PCDATAFILTER; 1303 ss := ""; 1304 if r.root.mathmode = "MathJax" then 1305 s := Concatenation("\\(",s,"\\)"); 1306 GAPDoc2HTMLProcs.PCDATAFILTER(rec(content := s), ss); 1307 ss := SubstitutionSublist(ss, "TEXTaTTRvARBEGIN", "\\textit{"); 1308 ss := SubstitutionSublist(ss, "TEXTaTTRvAREND", "}"); 1309 else 1310 s := TextM(s); 1311 GAPDoc2HTMLProcs.PCDATAFILTER(rec(content := s), ss); 1312 ss := SubstitutionSublist(ss, "TEXTaTTRvARBEGIN", save[1]); 1313 ss := SubstitutionSublist(ss, "TEXTaTTRvAREND", save[2]); 1314 fi; 1315 Append(str, WrapTextAttribute(ss, GAPDoc2HTMLProcs.TextAttr.M)); 1316end; 1317 1318## in HTML this is shown in TeX format 1319GAPDoc2HTMLProcs.Math := function(r, str) 1320 local s; 1321 if r.root.mathmode in ["MathML", "Tth"] then 1322 GAPDoc2HTMLProcs.MathConvHelper(r, str, "$", "$"); 1323 return; 1324 fi; 1325 if r.root.mathmode = "MathJax" then 1326 s := ""; 1327 GAPDoc2HTMLProcs.M(r, s); 1328 Append(str, s); 1329 return; 1330 fi; 1331 s := ""; 1332 GAPDoc2HTMLContent(r, s); 1333 Append(str, WrapTextAttribute(s, GAPDoc2HTMLProcs.TextAttr.Math)); 1334end; 1335 1336## displayed maths (also in TeX format, but centered paragraph in itself) 1337GAPDoc2HTMLProcs.Display := function(r, par) 1338 local s, a, str; 1339 if r.root.mathmode in ["MathML", "Tth"] then 1340 str := ""; 1341 GAPDoc2HTMLProcs.MathConvHelper(r, str, "\n\\[", "\\]\n\n"); 1342 Add(par, r.count); 1343 Add(par, Concatenation("<table class=\"display\"><tr>", 1344 "<td class=\"display\">", 1345 str, "</td></tr></table>\n")); 1346 return; 1347 fi; 1348 s := ""; 1349 for a in r.content do 1350 GAPDoc2HTML(a, s); 1351 od; 1352 if r.root.mathmode = "MathJax" then 1353 Add(par, r.count); 1354 Add(par, Concatenation("<p class=\"center\">\\[", 1355 s, "\\]</p>\n\n")); 1356 return; 1357 fi; 1358 if IsBound(r.attributes.Mode) and r.attributes.Mode = "M" then 1359 s := TextM(s); 1360 fi; 1361 s := Concatenation("<p class=\"pcenter\">", s, "</p>\n\n"); 1362 Add(par, r.count); 1363 Add(par, s); 1364end; 1365 1366## emphazised text 1367GAPDoc2HTMLProcs.Emph := function(r, str) 1368 GAPDoc2HTMLProcs.WrapAttr(r, str, "Emph"); 1369end; 1370 1371## quoted text 1372GAPDoc2HTMLProcs.Q := function(r, str) 1373 Append(str, "\""); 1374 GAPDoc2HTMLContent(r, str); 1375 Append(str, "\""); 1376end; 1377 1378## Package names 1379GAPDoc2HTMLProcs.Package := function(r, str) 1380 GAPDoc2HTMLProcs.WrapAttr(r, str, "Package"); 1381end; 1382 1383## menu items 1384GAPDoc2HTMLProcs.I := function(r, str) 1385 GAPDoc2HTMLProcs.WrapAttr(r, str, "I"); 1386end; 1387 1388GAPDoc2HTMLProcs.AddColorPromptMarkup := function(cont) 1389 local patt, batt, iatt, res, pos, s, rows; 1390 patt := GAPDoc2HTMLProcs.TextAttr.GAPprompt; 1391 batt := GAPDoc2HTMLProcs.TextAttr.GAPbrkprompt; 1392 iatt := GAPDoc2HTMLProcs.TextAttr.GAPinput; 1393 res := ""; 1394 rows := SplitString(cont, "\n", ""); 1395 for s in rows do 1396 if Length(s) > 7 and s{[1..8]} = "gap> " then 1397 Append(res, Concatenation(WrapTextAttribute("gap>", patt), 1398 " ", WrapTextAttribute(s{[9..Length(s)]}, iatt))); 1399 elif Length(s) > 4 and s{[1..5]} = "> " then 1400 Append(res, Concatenation(WrapTextAttribute(">", patt), 1401 " ", WrapTextAttribute(s{[6..Length(s)]}, iatt))); 1402 elif Length(s) > 2 and s{[1..3]} = "brk" then 1403 pos := Position(s, ' '); 1404 if pos <> fail then 1405 Append(res, Concatenation(WrapTextAttribute(s{[1..pos-1]}, batt), 1406 " ", WrapTextAttribute(s{[pos+1..Length(s)]}, iatt))); 1407 else 1408 Append(res, WrapTextAttribute(s, batt)); 1409 fi; 1410 else 1411 Append(res, WrapTextAttribute(s, ["",""])); 1412 fi; 1413 Add(res, '\n'); 1414 od; 1415 if Length(cont) > 0 and cont[Length(cont)] <> '\n' then 1416 Unbind(res[Length(res)]); 1417 fi; 1418 return res; 1419end; 1420 1421GAPDoc2HTMLProcs.ExampleLike := function(r, par, label, colorpr) 1422 local str, cont, a, s; 1423 str := "\n<div class=\"example\"><pre>"; 1424 cont := ""; 1425 for a in r.content do 1426 # here we try to avoid reformatting 1427 if IsString(a.content) then 1428 GAPDoc2HTMLProcs.PCDATA(a, cont); 1429 else 1430 s := ""; 1431 GAPDoc2HTML(a, s); 1432 Append(cont, s); 1433 fi; 1434 od; 1435 if colorpr then 1436 cont := GAPDoc2HTMLProcs.AddColorPromptMarkup(cont); 1437 fi; 1438 Append(str, cont); 1439 Append(str, "</pre></div>\n\n"); 1440 Add(par, r.count); 1441 Add(par, str); 1442end; 1443 1444## log of session and GAP code is typeset the same way as <Example> 1445GAPDoc2HTMLProcs.Example := function(r, par) 1446 GAPDoc2HTMLProcs.ExampleLike(r, par, "Example", true); 1447end; 1448GAPDoc2HTMLProcs.Log := function(r, par) 1449 GAPDoc2HTMLProcs.ExampleLike(r, par, "Log", true); 1450end; 1451GAPDoc2HTMLProcs.Listing := function(r, par) 1452 GAPDoc2HTMLProcs.ExampleLike(r, par, "Code", false); 1453end; 1454 1455GAPDoc2HTMLProcs.Verb := function(r, par) 1456 local str, cont, a, s; 1457 str := "\n<pre class=\"normal\">\n"; 1458 cont := ""; 1459 for a in r.content do 1460 # here we try to avoid reformatting 1461 if IsString(a.content) then 1462 GAPDoc2HTMLProcs.PCDATA(a, cont); 1463 else 1464 s := ""; 1465 GAPDoc2HTML(a, s); 1466 Append(cont, s); 1467 fi; 1468 od; 1469 Append(str, cont); 1470 Append(str, "\n</pre>\n\n"); 1471 Add(par, r.count); 1472 Add(par, str); 1473end; 1474 1475## explicit labels 1476GAPDoc2HTMLProcs.Label := function(r, str) 1477 local num, lab; 1478 num := GAPDoc2HTMLProcs.SectionNumber(r.count, "Subsection"); 1479 lab := GAPDoc2HTMLProcs.SectionLabel(r, r.count, "Subsection"); 1480 r.root.labels.(r.attributes.Name) := [num, Concatenation(lab[1],"#",lab[2])]; 1481end; 1482 1483## citations 1484GAPDoc2HTMLProcs.Cite := function(r, str) 1485 local key, pos; 1486 key := r.attributes.Key; 1487 pos := Position(r.root.bibkeys, key); 1488 if pos = fail then 1489 Add(r.root.bibkeys, key); 1490 Append(str, Concatenation("[?", key, "?]")); 1491 elif not IsBound(r.root.biblabels) then 1492 Append(str, Concatenation("[?", key, "?]")); 1493 else 1494 # here we include a link to the corresponding entry in bibliography 1495 Append(str, Concatenation("<a href=\"chapBib", GAPDoc2HTMLProcs.ext, 1496 "#biB", key, "\">[", r.root.biblabels[pos])); 1497 if IsBound(r.attributes.Where) then 1498 Append(str, ", "); 1499 Append(str, r.attributes.Where); 1500 fi; 1501 Append(str, "]</a>"); 1502 fi; 1503end; 1504 1505## explicit index entries 1506GAPDoc2HTMLProcs.Subkey := GAPDoc2HTMLContent; 1507GAPDoc2HTMLProcs.Index := function(r, str) 1508 local s, sub, entry, url, a; 1509 1510 s := ""; 1511 sub := ""; 1512 for a in r.content do 1513 if a.name = "Subkey" then 1514 GAPDoc2HTML(a, sub); 1515 else 1516 GAPDoc2HTML(a, s); 1517 fi; 1518 od; 1519 NormalizeWhitespace(s); 1520 NormalizeWhitespace(sub); 1521 if IsBound(r.attributes.Key) then 1522 entry := [STRING_LOWER(r.attributes.Key)]; 1523 else 1524 entry := [STRING_LOWER(s)]; 1525 fi; 1526 if IsBound(r.attributes.Subkey) then 1527 Add(entry, r.attributes.Subkey); 1528 else 1529 Add(entry, sub); 1530 fi; 1531 Add(entry, GAPDoc2HTMLProcs.SectionNumber(r.count, "Subsection")); 1532 Add(entry, s); 1533 url := GAPDoc2HTMLProcs.SectionLabel(r, r.count, "Subsection"); 1534 Add(entry, Concatenation(url[1],"#",url[2])); 1535 if Length(sub) > 0 then 1536 Add(entry, sub); 1537 fi; 1538 Add(r.root.index, entry); 1539end; 1540 1541## helper to add markup to the args 1542GAPDoc2HTMLProcs.WrapArgs := function(argstr) 1543 local res, noletter, c; 1544 res := ""; 1545 noletter := true; 1546 for c in argstr do 1547 if noletter then 1548 if not c in ", []" then 1549 noletter := false; 1550 Append(res, GAPDoc2HTMLProcs.TextAttr.Arg[1]); 1551 fi; 1552 elif c in ", []" then 1553 noletter := true; 1554 Append(res, GAPDoc2HTMLProcs.TextAttr.Arg[2]); 1555 fi; 1556 Add(res, c); 1557 od; 1558 if not noletter then 1559 Append(res, GAPDoc2HTMLProcs.TextAttr.Arg[2]); 1560 fi; 1561 return res; 1562end; 1563 1564## this produces an implicit index entry and a label entry 1565GAPDoc2HTMLProcs.LikeFunc := function(r, par, typ) 1566 local attr, s, name, lab, url; 1567 attr := GAPDoc2HTMLProcs.TextAttr.Func; 1568 name := GAPDoc2HTMLProcs.EscapeAttrVal(r.attributes.Name); 1569 s := Concatenation(attr[1], "‣ ", name, attr[2]); 1570 if IsBound(r.attributes.Arg) then 1571 Append(s, Concatenation("( ", GAPDoc2HTMLProcs.WrapArgs( 1572 GAPDoc2HTMLProcs.EscapeAttrVal( 1573 NormalizedArgList(r.attributes.Arg))), " )")); 1574 fi; 1575 # index entry 1576 attr := GAPDoc2HTMLProcs.TextAttr.Func; 1577 url := GAPDoc2HTMLProcs.SectionLabel(r, r.count, "Subsection"); 1578 url := Concatenation(url[1],"#",url[2]); 1579 if IsBound(r.attributes.Label) then 1580 lab := r.attributes.Label; 1581 else 1582 lab := ""; 1583 fi; 1584 Add(r.root.index, [STRING_LOWER(name), lab, 1585 GAPDoc2HTMLProcs.SectionNumber(r.count, "Subsection"), 1586 Concatenation(attr[1], name, attr[2]), 1587 url]); 1588 # label (if not given, the default is the Name) 1589 if IsBound(r.attributes.Label) then 1590 if IsBound(r.attributes.Name) then 1591 lab := Concatenation(r.attributes.Name, " (", r.attributes.Label, ")"); 1592 else 1593 lab := r.attributes.Label; 1594 fi; 1595 else 1596 lab := r.attributes.Name; 1597 fi; 1598 GAPDoc2HTMLProcs.Label(rec(count := r.count, attributes := rec(Name 1599 := lab), root := r.root), par); 1600 # adding hint about the type of the variable 1601 s := Concatenation("<div class=\"func\"><table class=\"func\" ", 1602 "width=\"100%\">", 1603 "<tr><td class=\"tdleft\">", s, 1604 "</td><td class=\"tdright\">( ", typ, 1605 " )</td></tr></table></div>\n"); 1606 Add(par, r.count); 1607 Add(par, s); 1608end; 1609 1610GAPDoc2HTMLProcs.Func := function(r, str) 1611 GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Func); 1612end; 1613 1614GAPDoc2HTMLProcs.Oper := function(r, str) 1615 GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Oper); 1616end; 1617 1618GAPDoc2HTMLProcs.Constr := function(r, str) 1619 GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Constr); 1620end; 1621 1622GAPDoc2HTMLProcs.Meth := function(r, str) 1623 GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Meth); 1624end; 1625 1626GAPDoc2HTMLProcs.Filt := function(r, str) 1627 # r.attributes.Type could be "representation", "category", ... 1628 if IsBound(r.attributes.Type) then 1629 GAPDoc2HTMLProcs.LikeFunc(r, str, LowercaseString(r.attributes.Type)); 1630 else 1631 GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Filt); 1632 fi; 1633end; 1634 1635GAPDoc2HTMLProcs.Prop := function(r, str) 1636 GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Prop); 1637end; 1638 1639GAPDoc2HTMLProcs.Attr := function(r, str) 1640 GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Attr); 1641end; 1642 1643GAPDoc2HTMLProcs.Var := function(r, str) 1644 GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Var); 1645end; 1646 1647GAPDoc2HTMLProcs.Fam := function(r, str) 1648 GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.Fam); 1649end; 1650 1651GAPDoc2HTMLProcs.InfoClass := function(r, str) 1652 GAPDoc2HTMLProcs.LikeFunc(r, str, GAPDocTexts.d.InfoClass); 1653end; 1654 1655## using the HelpData(.., .., "ref") interface 1656GAPDoc2HTMLProcs.ResolveExternalRef := function(bookname, label, nr) 1657 local info, match, res; 1658 info := HELP_BOOK_INFO(bookname); 1659 if info = fail then 1660 return fail; 1661 fi; 1662 match := Concatenation(HELP_GET_MATCHES(info, SIMPLE_STRING(label), true)); 1663 if Length(match) < nr then 1664 return fail; 1665 fi; 1666 res := GetHelpDataRef(info, match[nr][2]); 1667 res[1] := SubstitutionSublist(res[1], " (not loaded): ", ": ", "one"); 1668 return res; 1669end; 1670 1671## helper for external URLs, remove GAPDocStyle part and maybe add "_mj" 1672GAPDoc2HTMLProcs.AdjustExtURL := function(r, url) 1673 local pos, pos2, res, fnam, mjnam; 1674 pos := PositionSublist(url, "?GAPDocStyle="); 1675 if pos <> fail then 1676 pos2 := Position(url, '#', pos); 1677 if pos2 = fail then 1678 pos2 := Length(url)+1; 1679 fi; 1680 res := url{[1..pos-1]}; 1681 Append(res, url{[pos2..Length(url)]}); 1682 else 1683 res :=url; 1684 fi; 1685 if r.root.mathmode = "MathJax" then 1686 pos := Position(res, '#'); 1687 if pos <> fail then 1688 fnam := res{[1..pos-1]}; 1689 else 1690 pos := Length(res)+1; 1691 fnam := res; 1692 fi; 1693 if Length(fnam) >= 5 and fnam{[Length(fnam)-4..Length(fnam)]} = ".html" then 1694 mjnam := Concatenation(fnam{[1..Length(fnam)-5]}, "_mj.html"); 1695 if IsExistingFile(mjnam) then 1696 res := Concatenation(mjnam, res{[pos..Length(res)]}); 1697 fi; 1698 fi; 1699 fi; 1700 return res; 1701end; 1702 1703## a try to make it somewhat shorter than for the Text and LaTeX conversions 1704GAPDoc2HTMLProcs.Ref := function(r, str) 1705 local int, txt, ref, lab, attr, sectlike, rattr; 1706 1707 rattr := GAPDoc2HTMLProcs.TextAttr.Ref; 1708 int := Difference(NamesOfComponents(r.attributes), ["BookName", "Label", 1709 "Style"]); 1710 if Length(int)>0 and int[1] <> "Text" then 1711 lab := r.attributes.(int[1]); 1712 else 1713 lab := ""; 1714 fi; 1715 if IsBound(r.attributes.Label) then 1716 if Length(lab) > 0 then 1717 lab := Concatenation(lab, " (", r.attributes.Label, ")"); 1718 else 1719 lab := r.attributes.Label; 1720 fi; 1721 fi; 1722 if IsBound(r.attributes.BookName) then 1723 ref := GAPDoc2HTMLProcs.ResolveExternalRef(r.attributes.BookName, lab, 1); 1724 if ref <> fail and ref[6] <> fail then 1725 ref[6] := GAPDoc2HTMLProcs.AdjustExtURL(r, ref[6]); 1726 if IsBound(GAPDoc2HTMLProcs.RelPath) and 1727 PositionSublist(ref[6], GAPInfo.MainRootPath) = 1 then 1728 ref[6] := Concatenation(GAPDoc2HTMLProcs.RelPath, "/", 1729 ref[6]{[Length(GAPInfo.MainRootPath)+1..Length(ref[6])]}); 1730 fi; 1731 if IsBound(r.attributes.Style) and r.attributes.Style = "Number" then 1732 ref := Concatenation("<a href=\"", ref[6], "\">",rattr[1], 1733 r.attributes.BookName, " ", ref[2], rattr[2],"</a>"); 1734 elif IsBound(r.attributes.Text) then 1735 ref := Concatenation("<a href=\"", ref[6], "\">", rattr[1], 1736 r.attributes.Text, rattr[2], "</a>"); 1737 else 1738 ref := Concatenation("<a href=\"", ref[6], "\">", rattr[1], ref[1], 1739 rattr[2], "</a>"); 1740 fi; 1741 elif ref <> fail then 1742 ref := Concatenation(rattr[1], ref[1], rattr[2]); 1743 else 1744 if GAPDoc2HTMLProcs.FirstRun <> true then 1745 Info(InfoGAPDoc, 1, "#W WARNING: non resolved reference: ", 1746 r.attributes, "\n"); 1747 fi; 1748 ref := Concatenation(rattr[1], "???", rattr[2]); 1749 fi; 1750 else 1751 if IsBound(r.root.labels.(lab)) then 1752 if not IsBound(r.attributes.Text) then 1753 ref := Concatenation("<a href=\"", r.root.labels.(lab)[2], "\">", 1754 rattr[1], r.root.labels.(lab)[1], rattr[2], 1755 "</a>"); 1756 else 1757 ref := Concatenation("<a href=\"", r.root.labels.(lab)[2], "\">", 1758 rattr[1], r.attributes.Text, rattr[2], "</a>"); 1759 fi; 1760 else 1761 if GAPDoc2HTMLProcs.FirstRun <> true then 1762 Info(InfoGAPDoc, 1, "#W WARNING: non resolved reference: ", 1763 r.attributes, "\n"); 1764 fi; 1765 ref := Concatenation(rattr[1], "???", rattr[2]); 1766 fi; 1767 fi; 1768 if Length(int)>0 and int[1] in [ "Func", "Oper", "Constr", "Meth", "Filt", 1769 "Prop", "Attr", "Var", "Fam", "InfoClass" ] then 1770 attr := GAPDoc2HTMLProcs.TextAttr.Func; 1771 txt := Concatenation(attr[1], 1772 GAPDoc2HTMLProcs.EscapeAttrVal(r.attributes.(int[1])), attr[2]); 1773 # avoid reference to current subsection 1774 if IsBound(r.attributes.BookName) or not IsBound(r.root.labels.(lab)) 1775 or GAPDoc2HTMLProcs.SectionNumber(r.count, "Subsection") <> 1776 r.root.labels.(lab)[1] then 1777 Append(txt, Concatenation(" (", ref, ")")); 1778 fi; 1779 elif Length(int)>0 and 1780 int[1] in [ "Sect", "Subsect", "Chap", "Appendix"] and 1781 IsBound(r.attributes.Style) and 1782 r.attributes.Style = "Text" then 1783 if IsBound(r.root.labeltexts.(lab)) then 1784 txt := Concatenation("<a href=\"",r.root.labels.(lab)[2], 1785 "\">",rattr[1],r.root.labeltexts.(lab),rattr[2],"</a>"); 1786 else 1787 if GAPDoc2HTMLProcs.FirstRun <> true then 1788 Info(InfoGAPDoc, 1, "#W WARNING: non resolved reference: ", 1789 r.attributes, "\n"); 1790 fi; 1791 txt := Concatenation(rattr[1], "???", rattr[2]); 1792 fi; 1793 else 1794 txt := ref; 1795 fi; 1796 Append(str, txt); 1797end; 1798 1799GAPDoc2HTMLProcs.Description := GAPDoc2HTMLContent; 1800 1801GAPDoc2HTMLProcs.Returns := function(r, par) 1802 local l; 1803 l := []; 1804 GAPDoc2HTMLContent(r, l); 1805 if Length(l) > 0 then 1806 l[2] := Concatenation("<p>", GAPDocTexts.d.Returns, 1807 ": ", l[2]{[4..Length(l[2])]}); 1808 fi; 1809 Append(par, l); 1810end; 1811 1812GAPDoc2HTMLProcs.ManSection := function(r, par) 1813 local strn, funclike, i, num, s, lab, ind; 1814 1815 # if there is a Heading then handle as subsection 1816 if ForAny(r.content, a-> IsRecord(a) and a.name = "Heading") then 1817 GAPDoc2HTMLProcs.ChapSect(r, par, "Subsection"); 1818 return; 1819 fi; 1820 strn := ""; 1821 # function like elements 1822 funclike := [ "Func", "Oper", "Constr", "Meth", "Filt", "Prop", "Attr", 1823 "Var", "Fam", "InfoClass" ]; 1824 1825 # heading comes from name of first function like element 1826 i := 1; 1827 while not r.content[i].name in funclike do 1828 i := i+1; 1829 od; 1830 1831 num := GAPDoc2HTMLProcs.SectionNumber(r.count, "Subsection"); 1832 s := Concatenation(num, " ", 1833 GAPDoc2HTMLProcs.EscapeAttrVal(r.content[i].attributes.Name)); 1834 Add(par, r.count); 1835 # avoid MathJax interpretation in \(, \[ outside <code> 1836 if '\\' in s then 1837 s := Concatenation("<code>",s,"</code>"); 1838 fi; 1839 Add(par, Concatenation("\n<h5>", s, "</h5>\n\n")); 1840 1841 # append to TOC as subsection 1842 lab := GAPDoc2HTMLProcs.SectionLabel(r, r.count, "Subsection"); 1843 lab := Concatenation(lab[1], "#", lab[2]); 1844 ind := "<span class=\"ContSS\"><br /><span class=\"nocss\"> </span>"; 1845 Append(r.root.toc, Concatenation(ind, "<a href=\"", lab, "\">", s, 1846 "</a></span>\n")); 1847 1848 # label entry, if present 1849 if IsBound(r.attributes.Label) then 1850 r.root.labels.(r.attributes.Label) := [num, lab]; 1851 r.root.labeltexts.(r.attributes.Label) := s; 1852 fi; 1853 1854 GAPDoc2HTMLContent(r, par); 1855end; 1856 1857GAPDoc2HTMLProcs.Mark := function(r, str) 1858 GAPDoc2HTMLProcs.WrapAttr(r, str, "Mark"); 1859end; 1860 1861GAPDoc2HTMLProcs.Item := function(r, str) 1862 GAPDoc2HTMLContent(r, str); 1863end; 1864 1865# must do the complete formatting 1866GAPDoc2HTMLProcs.List := function(r, par) 1867 local s, a, ss, i; 1868 s := "\n"; 1869 if "Mark" in List(r.content, a-> a.name) then 1870 # a <dl> list 1871 Append(s, "<dl>\n"); 1872 for a in r.content do 1873 if a.name = "Mark" then 1874 ss := ""; 1875 GAPDoc2HTMLProcs.Mark(a, ss); 1876 Append(s, Concatenation("<dt>", ss, "</dt>\n")); 1877 elif a.name = "Item" then 1878 ss := ""; 1879 GAPDoc2HTMLProcs.Item(a, ss); 1880 ss := Concatenation(Filtered(ss, IsString)); 1881 ss := Concatenation("<dd>", ss, "</dd>\n"); 1882 Append(s, ss); 1883 fi; 1884 od; 1885 Append(s, "</dl>\n"); 1886 else 1887 # a <ul> list 1888 Append(s, "<ul>\n"); 1889 for a in r.content do 1890 if a.name = "Item" then 1891 ss := ""; 1892 GAPDoc2HTMLProcs.Item(a, ss); 1893 ss := Concatenation(Filtered(ss, IsString)); 1894 Append(s, Concatenation("<li>", ss, "</li>\n")); 1895 fi; 1896 od; 1897 Append(s, "</ul>\n"); 1898 fi; 1899 Add(par, r.count); 1900 Add(par, s); 1901end; 1902 1903## and this is an <ol> list 1904GAPDoc2HTMLProcs.Enum := function(r, par) 1905 local s, i, a, ss, num; 1906 s := ""; 1907 # a <ul> list 1908 Append(s, "<ol>\n"); 1909 for a in r.content do 1910 if a.name = "Item" then 1911 ss := ""; 1912 GAPDoc2HTMLProcs.Item(a, ss); 1913 if not IsString(ss) then 1914 ss := Concatenation(Filtered(ss, IsString)); 1915 fi; 1916 Append(s, Concatenation("<li>", ss, "</li>\n")); 1917 fi; 1918 od; 1919 Append(s, "</ol>\n"); 1920 Add(par, r.count); 1921 Add(par, s); 1922end; 1923 1924GAPDoc2HTMLProcs.TheIndex := function(r, par) 1925 local s; 1926 1927 # add index to TOC 1928 Append(r.root.toc, Concatenation("<div class=\"ContChap\"><a href=\"chapInd", 1929 GAPDoc2HTMLProcs.ext, "\"><span class=\"Heading\">", 1930 GAPDocTexts.d.Index, "</span></a></div>\n")); 1931 # the text, if available 1932 Add(par, r.count); 1933 if IsBound(r.root.indextext) then 1934 Add(par, Concatenation("\n<div class=\"index\">\n<h3>", 1935 GAPDocTexts.d.Index, "</h3>\n\n", 1936 r.root.indextext, "<p> </p>\n</div>\n")); 1937 else 1938 Add(par,"<p>INDEX\n-----------</p>\n\n"); 1939 fi; 1940end; 1941 1942GAPDoc2HTMLProcs.AltYes := function(r) 1943 local mark, mj, l; 1944 # recursively mark text as HTML code (no escaping of HTML markup) 1945 mark := function(r) 1946 local a; 1947 if IsString(r.content) then 1948 r.HTML := true; 1949 elif IsList(r.content) then 1950 for a in r.content do 1951 mark(a); 1952 od; 1953 fi; 1954 end; 1955 mj := r.root.mathmode="MathJax"; 1956 if IsBound(r.attributes.Only) then 1957 l := SplitString(r.attributes.Only, "", "\n\r\t ,"); 1958 if "HTML" in l then 1959 if "MathJax" in l then 1960 if mj then 1961 mark(r); 1962 return true; 1963 else 1964 return false; 1965 fi; 1966 elif "noMathJax" in l then 1967 if not mj then 1968 mark(r); 1969 return true; 1970 else 1971 return false; 1972 fi; 1973 else 1974 mark(r); 1975 return true; 1976 fi; 1977 else 1978 return false; 1979 fi; 1980 elif IsBound(r.attributes.Not) then 1981 # here, even if it is used, it is not HTML specific, so we not 'mark' 1982 l := SplitString(r.attributes.Not, "", "\n\r\t ,"); 1983 if "HTML" in l then 1984 if "MathJax" in l then 1985 if mj then 1986 return false; 1987 else 1988 return true; 1989 fi; 1990 elif "noMathJax" in l then 1991 if not mj then 1992 return false; 1993 else 1994 return true; 1995 fi; 1996 else 1997 return false; 1998 fi; 1999 else 2000 return true; 2001 fi; 2002 fi; 2003 return true; 2004end; 2005 2006GAPDoc2HTMLProcs.Alt := function(r, str) 2007 if GAPDoc2HTMLProcs.AltYes(r) then 2008 GAPDoc2HTMLContent(r, str); 2009 fi; 2010end; 2011 2012# nothing special to do 2013GAPDoc2HTMLProcs.Address := function(r, str) 2014 GAPDoc2HTMLContent(r, str); 2015end; 2016 2017# copy a few entries with two element names 2018GAPDoc2HTMLProcs.E := GAPDoc2HTMLProcs.Emph; 2019GAPDoc2HTMLProcs.Keyword := GAPDoc2HTMLProcs.K; 2020GAPDoc2HTMLProcs.Code := GAPDoc2HTMLProcs.C; 2021GAPDoc2HTMLProcs.File := GAPDoc2HTMLProcs.F; 2022GAPDoc2HTMLProcs.Button := GAPDoc2HTMLProcs.B; 2023GAPDoc2HTMLProcs.Arg := GAPDoc2HTMLProcs.A; 2024GAPDoc2HTMLProcs.Quoted := GAPDoc2HTMLProcs.Q; 2025GAPDoc2HTMLProcs.Par := GAPDoc2HTMLProcs.P; 2026 2027# tables and utilities, not so nice since | and <Horline/> cannot be handled 2028GAPDoc2HTMLProcs.Table := function(r, s) 2029 local str, cap, al, a, i; 2030 str := ""; 2031 if not GAPDoc2HTMLProcs.AltYes(r) then 2032 return; 2033 fi; 2034 # label 2035 if IsBound(r.attributes.Label) then 2036 GAPDoc2HTMLProcs.Label(rec(count := r.count, root := r.root, 2037 attributes := rec(Name := r.attributes.Label)), str); 2038 fi; 2039 # alignments, table has borders and lines everywhere if any | or HorLine 2040 # is specified 2041 Append(str, "<div class=\"pcenter\"><table class=\"GAPDocTable"); 2042 if not '|' in r.attributes.Align and 2043 Length(XMLElements(r, "HorLine")) = 0 then 2044 Append(str, "noborder"); 2045 fi; 2046 Append(str, "\">\n"); 2047 # the caption, if given 2048 cap := Filtered(r.content, a-> a.name = "Caption"); 2049 if Length(cap) > 0 then 2050 GAPDoc2HTMLProcs.Caption1(cap[1], str); 2051 fi; 2052 2053 al := Filtered(r.attributes.Align, x-> x <> '|'); 2054 for i in [1..Length(al)] do 2055 if al[i] = 'c' then 2056 al[i] := "\"tdcenter\""; 2057 elif al[i] = 'l' then 2058 al[i] := "\"tdleft\""; 2059 else 2060 al[i] := "\"tdright\""; 2061 fi; 2062 od; 2063 # the rows of the table 2064 for a in r.content do 2065 if a.name = "Row" then 2066 GAPDoc2HTMLProcs.Row(a, str, al); 2067 fi; 2068 od; 2069 Append(str, "</table><br /><p> </p><br />\n"); 2070 Append(str, "</div>\n\n"); 2071 Add(s, r.count); 2072 Add(s, str); 2073end; 2074 2075# do nothing, we call .Caption1 directly in .Table 2076GAPDoc2HTMLProcs.Caption := function(r, str) 2077 return; 2078end; 2079 2080# here the caption text is produced 2081GAPDoc2HTMLProcs.Caption1 := function(r, str) 2082 Append(str, Concatenation("<caption class=\"GAPDocTable\"><b>", 2083 GAPDocTexts.d.Table, ": </b>")); 2084 GAPDoc2HTMLContent(r, str); 2085 Append(str, "</caption>\n"); 2086end; 2087 2088# cannot be chosen in HTML 2089GAPDoc2HTMLProcs.HorLine := function(r, str) 2090end; 2091 2092GAPDoc2HTMLProcs.Row := function(r, str, al) 2093 local s, i, l; 2094 Append(str, "<tr>\n"); 2095 l := Filtered(r.content, a-> a.name = "Item"); 2096 for i in [1..Length(l)] do 2097 s := ""; 2098 GAPDoc2HTMLContent(l[i], s); 2099 if not IsString(s) then 2100 s := Concatenation(Filtered(s, IsString)); 2101 fi; 2102 # throw away <p> tags in table entries 2103 if Length(s) > 5 and s{[1..3]} = "<p>" and 2104 s{[Length(s)-5..Length(s)]} = "</p>\n\n" then 2105 s := s{[4..Length(s)-6]}; 2106 fi; 2107 Append(str, Concatenation("<td class=", al[i], ">", s, "</td>\n")); 2108 od; 2109 while i < Length(al) do 2110 Append(str, "<td> </td>\n"); 2111 i := i+1; 2112 od; 2113 Append(str, "</tr>\n"); 2114end; 2115 2116 2117## 2118## <#GAPDoc Label="GAPDoc2HTMLPrintHTMLFiles"> 2119## <ManSection > 2120## <Func Arg="t[, path]" Name="GAPDoc2HTMLPrintHTMLFiles" /> 2121## <Returns>nothing</Returns> 2122## <Description> 2123## The first argument must be a result returned by <Ref 2124## Func="GAPDoc2HTML"/>. The second argument is a path for the files 2125## to write, it can be given as string or directory object. The text 2126## of each chapter is written into a separate file with name 2127## <F>chap0.html</F>, <F>chap1.html</F>, ..., <F>chapBib.html</F>, 2128## and <F>chapInd.html</F>.<P/> 2129## 2130## The <Package>MathJax</Package> versions are written to files 2131## <F>chap0_mj.html</F>, ..., <F>chapInd_mj.html</F>. <P/> 2132## 2133## The experimental version which is produced with <C>tth</C> 2134## uses different names for the files, namely 2135## <F>chap0_sym.html</F>, and so on for files which need 2136## symbol fonts. 2137## <P/> 2138## 2139## You should also add stylesheet files to the directory with the HTML 2140## files, see <Ref Subsect="StyleSheets"/>. 2141## </Description> 2142## </ManSection> 2143## <#/GAPDoc> 2144## 2145## Finally a function to print the text files: 2146InstallGlobalFunction(GAPDoc2HTMLPrintHTMLFiles, function(t, path) 2147 local a; 2148 if IsString(path) then 2149 path := Directory(path); 2150 fi; 2151 for a in NamesOfComponents(t) do 2152 if IsRecord(t.(a)) and IsBound(t.(a).text) then 2153 FileString(Filename(path, Concatenation("chap", a, t.ext)), t.(a).text); 2154 fi; 2155 od; 2156end); 2157 2158InstallGlobalFunction(CopyHTMLStyleFiles, function(dir) 2159 local d, todo, l, s, e, f; 2160 if not IsDirectory(dir) then 2161 dir := Directory(dir); 2162 fi; 2163 d := DirectoriesPackageLibrary("GAPDoc","styles")[1]; 2164 todo := []; 2165 for f in DirectoryContents(d) do 2166 if f = "chooser.html" then 2167 Add(todo, f); 2168 else 2169 l := Length(f); 2170 if l > 3 and f{[l-2..l]} = ".js" then 2171 Add(todo, f); 2172 elif l > 4 and f{[l-3..l]} = ".css" then 2173 Add(todo, f); 2174 fi; 2175 fi; 2176 od; 2177 for f in todo do 2178 s := StringFile(Filename(d,f)); 2179 if s = fail then 2180 Info(InfoGAPDoc, 1, "Cannot read file ", Filename(d,f), "\n"); 2181 else 2182 e := FileString(Filename(dir,f), s); 2183 if e = fail then 2184 Info(InfoGAPDoc, 1, "Cannot write file ", Filename(dir,f), "\n"); 2185 fi; 2186 fi; 2187 od; 2188end); 2189 2190