From af6b35cc43fb58d973463e48b3f930bd62053a8f Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Sat, 14 Jun 2025 15:28:51 +0200 Subject: [PATCH 1/2] Improve handling of CSS styles, and add viewport meta tag (#2358) --- novelwriter/formats/tohtml.py | 88 ++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/novelwriter/formats/tohtml.py b/novelwriter/formats/tohtml.py index c7bf7b17..404c6d09 100644 --- a/novelwriter/formats/tohtml.py +++ b/novelwriter/formats/tohtml.py @@ -159,34 +159,33 @@ class ToHtml(Tokenizer): # If we don't have formatting, we can do a plain replace tText = tText.replace("<", "<").replace(">", ">") - # Styles + # Inline Styles aStyle = [] - if self._cssStyles: - if tStyle & BlockFmt.LEFT: - aStyle.append("text-align: left;") - elif tStyle & BlockFmt.RIGHT: - aStyle.append("text-align: right;") - elif tStyle & BlockFmt.CENTRE: - aStyle.append("text-align: center;") - elif tStyle & BlockFmt.JUSTIFY: - aStyle.append("text-align: justify;") + if tStyle & BlockFmt.LEFT: + aStyle.append("text-align: left;") + elif tStyle & BlockFmt.RIGHT: + aStyle.append("text-align: right;") + elif tStyle & BlockFmt.CENTRE: + aStyle.append("text-align: center;") + elif tStyle & BlockFmt.JUSTIFY: + aStyle.append("text-align: justify;") - if tStyle & BlockFmt.PBB: - aStyle.append("page-break-before: always;") - if tStyle & BlockFmt.PBA: - aStyle.append("page-break-after: always;") + if tStyle & BlockFmt.PBB: + aStyle.append("page-break-before: always;") + if tStyle & BlockFmt.PBA: + aStyle.append("page-break-after: always;") - if tStyle & BlockFmt.Z_BTM: - aStyle.append("margin-bottom: 0;") - if tStyle & BlockFmt.Z_TOP: - aStyle.append("margin-top: 0;") + if tStyle & BlockFmt.Z_BTM: + aStyle.append("margin-bottom: 0;") + if tStyle & BlockFmt.Z_TOP: + aStyle.append("margin-top: 0;") - if tStyle & BlockFmt.IND_L: - aStyle.append(f"margin-left: {self._blockIndent:.2f}em;") - if tStyle & BlockFmt.IND_R: - aStyle.append(f"margin-right: {self._blockIndent:.2f}em;") - if tStyle & BlockFmt.IND_T: - aStyle.append(f"text-indent: {self._firstWidth:.2f}em;") + if tStyle & BlockFmt.IND_L: + aStyle.append(f"margin-left: {self._blockIndent:.2f}em;") + if tStyle & BlockFmt.IND_R: + aStyle.append(f"margin-right: {self._blockIndent:.2f}em;") + if tStyle & BlockFmt.IND_T: + aStyle.append(f"text-indent: {self._firstWidth:.2f}em;") if aStyle: stVals = " ".join(aStyle) @@ -288,26 +287,25 @@ class ToHtml(Tokenizer): json.dump(data, fObj, indent=2) else: + html = [] + html.append("") + html.append("") + html.append("") + html.append(f"{self._project.data.name:s}") + html.append("") + if self._cssStyles: + html.append("") + html.append("") + html.append("") + html.append("") + html.append(("".join(self._pages)).replace("\t", " ").rstrip()) + html.append("") + html.append("\n") + with open(path, mode="w", encoding="utf-8") as fObj: - fObj.write(( - "\n" - "\n" - "\n" - "\n" - "{title:s}\n" - "\n" - "\n" - "\n" - "{body:s}\n" - "\n" - "\n" - ).format( - title=self._project.data.name, - style="\n".join(self.getStyleSheet()), - body=("".join(self._pages)).replace("\t", " ").rstrip(), - )) + fObj.write("\n".join(html)) logger.info("Wrote file: %s", path) @@ -410,7 +408,11 @@ class ToHtml(Tokenizer): # isn't already open, and only closed if it has previously been opened. tags: list[tuple[int, str]] = [] state = dict.fromkeys(HTML_OPENER, False) + plain = not self._cssStyles for pos, fmt, data in tFmt: + if plain and fmt in (TextFmt.COL_B, TextFmt.COL_E): + # We ignore colour tags if CSS is off + continue if m := HTML_OPENER.get(fmt): if not state.get(fmt, True): if fmt == TextFmt.COL_B and (color := self._classes.get(data)): From 307e80bac9b0e7a7f7a43b78d775022d1a30ad21 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Sat, 14 Jun 2025 15:29:11 +0200 Subject: [PATCH 2/2] Update tests --- .../mBuildDocBuild_HTML5_Lorem_Ipsum.htm | 3 +- tests/test_formats/test_fmt_tohtml.py | 112 +++++++++++++----- 2 files changed, 87 insertions(+), 28 deletions(-) diff --git a/tests/reference/mBuildDocBuild_HTML5_Lorem_Ipsum.htm b/tests/reference/mBuildDocBuild_HTML5_Lorem_Ipsum.htm index f605b0fa..92482cd8 100644 --- a/tests/reference/mBuildDocBuild_HTML5_Lorem_Ipsum.htm +++ b/tests/reference/mBuildDocBuild_HTML5_Lorem_Ipsum.htm @@ -1,8 +1,9 @@ - Lorem Ipsum + + \n" "\n" "\n" - "{bodyText:s}\n" + "{body}\n" "\n" "\n" ).format( - htmlStyle="\n".join(hStyle), - bodyText="".join(resText).rstrip() + style="\n".join(hStyle), + body="".join(resText).rstrip() ) saveFile = fncPath / "outFile.htm" html.saveDocument(saveFile) - assert saveFile.read_text(encoding="utf-8") == htmlDoc + assert saveFile.read_text(encoding="utf-8") == htmlDocCSS - # JSON + HTML + # HTML wo/Styles + html.setStyles(False) + htmlDocCSS = ( + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "{body}\n" + "\n" + "\n" + ).format( + body="".join(resText).rstrip() + ) + + saveFile = fncPath / "outFile.htm" + html.saveDocument(saveFile) + assert saveFile.read_text(encoding="utf-8") == htmlDocCSS + + # JSON + HTML w/Styles + html.setStyles(True) saveFile = fncPath / "outFile.json" html.saveDocument(saveFile) data = json.loads(saveFile.read_text(encoding="utf-8"))