"""
novelWriter – HTML Text Converter
=================================
Extends the Tokenizer class to generate HTML output
File History:
Created: 2019-05-07 [0.0.1]
This file is a part of novelWriter
Copyright 2018–2022, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see ",
self.FMT_D_E: "",
}
if self._isNovel and self._genMode != self.M_PREVIEW:
# For story files, we bump the titles one level up
h1Cl = " class='title'"
h1 = "h1"
h2 = "h1"
h3 = "h2"
h4 = "h3"
else:
h1Cl = ""
h1 = "h1"
h2 = "h2"
h3 = "h3"
h4 = "h4"
self._theResult = ""
thisPar = []
parStyle = None
tmpResult = []
for tType, tLine, tText, tFormat, tStyle in self._theTokens:
# Replace < and > with HTML entities
if tFormat:
# If we have formatting, we must recompute the locations
cText = []
i = 0
for c in tText:
if c == "<":
cText.append("<")
tFormat = [[a + 3 if a > i else a, b, c] for a, b, c in tFormat]
i += 4
elif c == ">":
cText.append(">")
tFormat = [[a + 3 if a > i else a, b, c] for a, b, c in tFormat]
i += 4
else:
cText.append(c)
i += 1
tText = "".join(cText)
else:
# If we don't have formatting, we can do a plain replace
tText = tText.replace("<", "<").replace(">", ">")
# Styles
aStyle = []
if tStyle is not None and self._cssStyles:
if tStyle & self.A_LEFT:
aStyle.append("text-align: left;")
elif tStyle & self.A_RIGHT:
aStyle.append("text-align: right;")
elif tStyle & self.A_CENTRE:
aStyle.append("text-align: center;")
elif tStyle & self.A_JUSTIFY:
aStyle.append("text-align: justify;")
if tStyle & self.A_PBB:
aStyle.append("page-break-before: always;")
if tStyle & self.A_PBA:
aStyle.append("page-break-after: always;")
if tStyle & self.A_Z_BTMMRG:
aStyle.append("margin-bottom: 0;")
if tStyle & self.A_Z_TOPMRG:
aStyle.append("margin-top: 0;")
if tStyle & self.A_IND_L:
aStyle.append(f"margin-left: {self.mainConf.tabWidth:d}px;")
if tStyle & self.A_IND_R:
aStyle.append(f"margin-right: {self.mainConf.tabWidth:d}px;")
if len(aStyle) > 0:
stVals = " ".join(aStyle)
hStyle = f" style='{stVals}'"
else:
hStyle = ""
if self._linkHeaders:
aNm = f""
else:
aNm = ""
# Process Text Type
if tType == self.T_EMPTY:
if parStyle is None:
parStyle = ""
if len(thisPar) > 1 and self._cssStyles:
parClass = " class='break'"
else:
parClass = ""
if len(thisPar) > 0:
tTemp = "
".join(thisPar)
tmpResult.append(f"
{tTemp.rstrip()}
\n") thisPar = [] parStyle = None elif tType == self.T_TITLE: tHead = tText.replace(r"\\", "{tText}
\n") elif tType == self.T_SKIP: tmpResult.append(f"\n") elif tType == self.T_TEXT: tTemp = tText if parStyle is None: parStyle = hStyle for xPos, xLen, xFmt in reversed(tFormat): tTemp = tTemp[:xPos] + htmlTags[xFmt] + tTemp[xPos+xLen:] thisPar.append(tTemp.rstrip()) elif tType == self.T_SYNOPSIS and self._doSynopsis: tmpResult.append(self._formatSynopsis(tText)) elif tType == self.T_COMMENT and self._doComments: tmpResult.append(self._formatComments(tText)) elif tType == self.T_KEYWORD and self._doKeywords: tTemp = f"
{self._formatKeywords(tText)}
\n" tmpResult.append(tTemp) self._theResult = "".join(tmpResult) tmpResult = [] if self._genMode != self.M_PREVIEW: self._fullHTML.append(self._theResult) return def saveHTML5(self, savePath): """Save the data to an .html file. """ with open(savePath, mode="w", encoding="utf-8") as outFile: theStyle = self.getStyleSheet() theStyle.append("article {width: 800px; margin: 40px auto;}") bodyText = "".join(self._fullHTML) bodyText = bodyText.replace("\t", " ").rstrip() theHtml = ( "\n" "\n" "\n" "\n" "{sSynop}: {tText}
\n" else: sSynop = self._localLookup("Synopsis") return f"{sSynop}: {tText}
\n" def _formatComments(self, tText): """Apply HTML formatting to comments. """ if self._genMode == self.M_PREVIEW: return f"{tText}
\n" else: sComm = self._localLookup("Comment") return f"{sComm}: {tText}
\n" def _formatKeywords(self, tText): """Apply HTML formatting to keywords. """ isValid, theBits, _ = self.theProject.index.scanThis("@"+tText) if not isValid or not theBits: return "" retText = "" refTags = [] if theBits[0] in nwLabels.KEY_NAME: retText += f" " if len(theBits) > 1: if theBits[0] == nwKeyWords.TAG_KEY: retText += f"{theBits[1]}" else: if self._genMode == self.M_PREVIEW: for tTag in theBits[1:]: refTags.append(f"{tTag}") retText += ", ".join(refTags) else: for tTag in theBits[1:]: refTags.append(f"{tTag}") retText += ", ".join(refTags) return retText # END Class ToHtml