From dcc53885d4c85cdb4d4578da75cc8b9ac9f85396 Mon Sep 17 00:00:00 2001 From: M66B Date: Fri, 6 Nov 2020 19:39:31 +0100 Subject: [PATCH] Revised newlines (draft) --- .../java/eu/faircode/email/HtmlHelper.java | 198 +++++++----------- 1 file changed, 71 insertions(+), 127 deletions(-) diff --git a/app/src/main/java/eu/faircode/email/HtmlHelper.java b/app/src/main/java/eu/faircode/email/HtmlHelper.java index 4692fa9102..cca713bf77 100644 --- a/app/src/main/java/eu/faircode/email/HtmlHelper.java +++ b/app/src/main/java/eu/faircode/email/HtmlHelper.java @@ -77,7 +77,6 @@ import com.steadystate.css.parser.selectors.ClassConditionImpl; import com.steadystate.css.parser.selectors.ConditionalSelectorImpl; import com.steadystate.css.parser.selectors.ElementSelectorImpl; -import org.jsoup.internal.StringUtil; import org.jsoup.nodes.Attribute; import org.jsoup.nodes.Comment; import org.jsoup.nodes.Document; @@ -442,7 +441,6 @@ public class HtmlHelper { // Limit length if (view && truncate(parsed, true)) { parsed.body() - .appendElement("br") .appendElement("p") .appendElement("em") .text(context.getString(R.string.title_too_large)); @@ -741,34 +739,18 @@ public class HtmlHelper { } } - if (element.isBlock()) + if (element.isBlock() && + !"true".equals(element.attr("x-inline"))) element.attr("x-block", "true"); } - // Remove trailing br from div - for (Element div : document.select("div")) { - boolean inline = Boolean.parseBoolean(div.attr("x-inline")); - if (!inline && hasVisibleContent(div, true)) { - Element last = div.lastElementSibling(); - if (last != null && "br".equals(last.tagName())) - last.remove(); - } - } - // Replace headings - for (Element h : document.select("h1,h2,h3,h4,h5,h6")) { - if (!"false".equals(h.attr("x-line-after"))) - h.appendElement("br"); - if (!text_size) { - h.appendElement("br"); - h.tagName("strong"); - } - } + if (!text_size) + document.select("h1,h2,h3,h4,h5,h6").tagName("strong"); // Paragraphs for (Element p : document.select("p")) { - if (!"false".equals(p.attr("x-line-after"))) - p.appendElement("br"); + p.attr("x-paragraph", "true"); p.tagName("div"); } @@ -816,13 +798,11 @@ public class HtmlHelper { // Descriptions // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl document.select("dl").tagName("div"); - for (Element dt : document.select("dt")) { + for (Element dt : document.select("dt")) dt.tagName("strong"); - dt.appendElement("br"); - } for (Element dd : document.select("dd")) { dd.tagName("em"); - dd.appendElement("br").appendElement("br"); + dd.attr("x-line-after", "true"); } // Abbreviations @@ -839,10 +819,7 @@ public class HtmlHelper { // Tables // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table for (Element col : document.select("th,td")) { - // separate columns - if (hasVisibleContent(col, false)) - if (col.nextElementSibling() != null) - col.append(" "); + col.attr("x-col", "true"); if ("th".equals(col.tagName())) col.tagName("strong"); @@ -850,18 +827,8 @@ public class HtmlHelper { col.tagName("span"); } - for (Element row : document.select("tr")) { - row.tagName("span"); - if (hasVisibleContent(row, true)) { - Element next = row.nextElementSibling(); - if (next != null && "tr".equals(next.tagName())) - if (text_separators && view) - row.appendElement("hr") - .attr("x-dashed", "true"); - else - row.appendElement("br"); - } - } + for (Element row : document.select("tr")) + row.tagName("span").attr("x-row", "true"); document.select("caption").tagName("div"); @@ -1014,29 +981,8 @@ public class HtmlHelper { } // Selective new lines - for (Element div : document.select("div")) { - boolean inline = Boolean.parseBoolean(div.attr("x-inline")); - if (!inline && hasVisibleContent(div, true)) - div.attr("x-line-after", "true"); + for (Element div : document.select("div")) div.tagName("span"); - } - - for (Element e : document.select("*[x-line-before],*[x-line-after]")) { - if ("true".equals(e.attr("x-line-before"))) { - Element prev = e.previousElementSibling(); - if (prev == null || !"br".equals(prev.tagName())) - e.prependElement("br"); - } - - if ("true".equals(e.attr("x-line-after"))) { - Element next = e.nextElementSibling(); - if (next == null || !"br".equals(next.tagName())) - e.appendElement("br"); - } - - e.removeAttr("x-line-before"); - e.removeAttr("x-line-after"); - } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) for (Element span : document.select("span")) @@ -1369,30 +1315,6 @@ public class HtmlHelper { return (color & 0xFFFFFF); } - private static boolean hasVisibleContent(Element root, boolean block) { - for (Node node : root.childNodes()) - if (node instanceof TextNode) { - String text = ((TextNode) node).getWholeText(); - for (int i = 0; i < text.length(); i++) { - char kar = text.charAt(i); - if (!StringUtil.isWhitespace(kar) && kar != '\u00a0' /* nbsp */) - return true; - } - } else if (node instanceof Element) { - Element element = (Element) node; - if (element.hasText()) - return true; - if (block && "true".equals(element.attr("x-block"))) - return false; - if (element.selectFirst("img[src~=.+]") != null) - return true; - for (Element a : element.select("a[href~=.+]")) - if (a.childNodes().size() > 0) - return true; - } - return false; - } - // https://tools.ietf.org/html/rfc3676 static String flow(String text) { boolean continuation = false; @@ -2061,12 +1983,39 @@ public class HtmlHelper { NodeTraversor.traverse(new NodeVisitor() { private Element element; private TextNode tnode; + private int rows = 0; + private int cols = 0; @Override public void head(Node node, int depth) { if (node instanceof Element) { element = (Element) node; + + if (rows == 0) { + if ("true".equals(element.attr("x-block"))) + if (ssb.length() > 1 && ssb.charAt(ssb.length() - 1) != '\n') + ssb.append('\n'); + if ("true".equals(element.attr("x-paragraph"))) + if (ssb.length() > 2 && + (ssb.charAt(ssb.length() - 2) != '\n' || + ssb.charAt(ssb.length() - 1) != '\n')) + ssb.append('\n'); + } + + if ("true".equals(element.attr("x-row"))) { + rows++; + if (ssb.length() > 1 && ssb.charAt(ssb.length() - 1) != '\n') + ssb.append('\n'); + } + if ("true".equals(element.attr("x-col"))) + cols++; + + if ("true".equals(element.attr("x-line-before")) && + ssb.length() > 0 && ssb.charAt(ssb.length() - 1) == '\n') + ssb.append('\n'); + element.attr("start-index", Integer.toString(ssb.length())); + if (debug) ssb.append("[" + element.tagName() + ":" + element.attr("style") + "]"); } else if (node instanceof TextNode) { @@ -2085,8 +2034,6 @@ public class HtmlHelper { if (node instanceof Element) { element = (Element) node; int start = Integer.parseInt(element.attr("start-index")); - if (debug) - ssb.append("[/" + element.tagName() + "]"); // Apply style String style = element.attr("style"); @@ -2131,19 +2078,8 @@ public class HtmlHelper { setSpan(ssb, new StrikethroughSpan(), start, ssb.length()); break; case "text-align": - boolean table = false; - Element e = element; - while (e != null) { - if ("table".equals(e.tagName()) || - "true".equals(e.attr("x-table"))) { - table = true; - break; - } - e = e.parent(); - } - // https://developer.mozilla.org/en-US/docs/Web/CSS/text-align - if (!table) { + if (rows == 0) { Layout.Alignment alignment = null; switch (value) { case "left": @@ -2207,12 +2143,10 @@ public class HtmlHelper { setSpan(ssb, new QuoteSpan(colorPrimary, dp3, dp6), start, ssb.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); break; case "br": - newline(ssb.length()); + ssb.append('\n'); break; case "div": // compose case "p": // compose - newline(ssb.length()); - newline(ssb.length()); break; case "i": case "em": @@ -2232,8 +2166,6 @@ public class HtmlHelper { int level = element.tagName().charAt(1) - '1'; setSpan(ssb, new RelativeSizeSpan(HEADING_SIZES[level]), start, ssb.length()); setSpan(ssb, new StyleSpan(Typeface.BOLD), start, ssb.length()); - newline(start); - newline(ssb.length()); break; case "hr": if (text_separators) { @@ -2365,6 +2297,37 @@ public class HtmlHelper { } catch (Throwable ex) { Log.e(ex); } + + if (rows == 0) { + if ("true".equals(element.attr("x-block"))) + if (ssb.length() > 1 && ssb.charAt(ssb.length() - 1) != '\n') + ssb.append('\n'); + if ("true".equals(element.attr("x-paragraph"))) + if (ssb.length() > 2 && + (ssb.charAt(ssb.length() - 2) != '\n' || + ssb.charAt(ssb.length() - 1) != '\n')) + ssb.append('\n'); + } + + if ("true".equals(element.attr("x-col"))) { + cols--; + if (ssb.length() > 0 && + ssb.charAt(ssb.length() - 1) != '\n' && + ssb.charAt(ssb.length() - 1) != '\u2003') + ssb.append('\u2003'); // emsp + } + if ("true".equals(element.attr("x-row"))) { + rows--; + if (ssb.length() > 1 && ssb.charAt(ssb.length() - 1) != '\n') + ssb.append('\n'); + } + + if ("true".equals(element.attr("x-line-after")) && + ssb.length() > 0 && ssb.charAt(ssb.length() - 1) == '\n') + ssb.append('\n'); + + if (debug) + ssb.append("[/" + element.tagName() + "]"); } } @@ -2381,25 +2344,6 @@ public class HtmlHelper { else Log.e("Invalid span " + start + "..." + end + " len=" + len + " type=" + span.getClass().getName()); } - - private void newline(int index) { - int count = 0; - - if (compress) { - int i = Math.min(index, ssb.length() - 1); - while (i >= 0) { - char kar = ssb.charAt(i); - if (kar == '\n') - count++; - else if (kar != ' ' && kar != '\u00A0') - break; - i--; - } - } - - if (count < 2) - ssb.insert(index, "\n"); - } }, document.body()); if (debug)