/*
* Copyright (C) 2019 Red Hat (www.redhat.com)
*
* This library is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation.
*
* This library 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see .
*/
'use strict';
/* semi-convention: private functions start with lower-case letter,
public functions start with upper-case letter. */
var EvoConvert = {
MIN_PARAGRAPH_WIDTH : 5, // in characters
MIN_OL_WIDTH : 6, // includes ". " at the end
TAB_WIDTH : 8, // in characters
ALIGN_LEFT : 0,
ALIGN_CENTER : 1,
ALIGN_RIGHT : 2,
ALIGN_JUSTIFY : 3,
NOWRAP_CHAR_START : "\x01",
NOWRAP_CHAR_END : "\x02",
E_HTML_LINK_TO_TEXT_NONE : 0,
E_HTML_LINK_TO_TEXT_INLINE : 1,
E_HTML_LINK_TO_TEXT_REFERENCE : 2,
E_HTML_LINK_TO_TEXT_REFERENCE_WITHOUT_LABEL : 3,
};
/* EvoConvert.linkRequiresReference() function is added in the C code */
EvoConvert.processAnchor = function(node, context)
{
var str;
if (!node.innerText.includes(" ") && !node.innerText.includes("\n"))
str = EvoConvert.NOWRAP_CHAR_START + node.innerText + EvoConvert.NOWRAP_CHAR_END;
else
str = node.innerText;
if (context && node.href && EvoConvert.linkRequiresReference(node.href, node.innerText)) {
if (context.link_to_text == EvoConvert.E_HTML_LINK_TO_TEXT_INLINE) {
str += " <" + EvoConvert.NOWRAP_CHAR_START + node.href + EvoConvert.NOWRAP_CHAR_END + ">";
} else if (context.link_to_text == EvoConvert.E_HTML_LINK_TO_TEXT_REFERENCE) {
var index;
for (index = 0; index < context.append_refs.length; index++) {
if (context.append_refs[index].href == node.href)
break;
}
if (index == context.append_refs.length)
context.append_refs[context.append_refs.length] = { label : node.innerText, href : node.href };
str += " [" + (index + 1) + "]";
} else if (context.link_to_text == EvoConvert.E_HTML_LINK_TO_TEXT_REFERENCE_WITHOUT_LABEL) {
var index;
for (index = 0; index < context.append_refs.length; index++) {
if (context.append_refs[index].href == node.href)
break;
}
if (index == context.append_refs.length)
context.append_refs[context.append_refs.length] = { href : node.href };
str += " [" + (index + 1) + "]";
}
}
return str;
}
EvoConvert.GetOLMaxLetters = function(type, levels)
{
if (type && type.toUpperCase() == "I") {
if (levels < 2)
return 1;
if (levels < 3)
return 2;
if (levels < 8)
return 3;
if (levels < 18)
return 4;
if (levels < 28)
return 5;
if (levels < 38)
return 6;
if (levels < 88)
return 7
if (levels < 188)
return 8;
if (levels < 288)
return 9;
if (levels < 388)
return 10;
if (levels < 888)
return 11;
return 12;
} else if (type && type.toUpperCase() == "A") {
if (levels < 27)
return 1;
if (levels < 703)
return 2;
if (levels < 18279)
return 3;
return 4;
} else {
if (levels < 10)
return 1;
if (levels < 100)
return 2;
if (levels < 1000)
return 3;
if (levels < 10000)
return 4;
return 5;
}
}
EvoConvert.getOLIndexValue = function(type, value)
{
var str = "";
if (type == "A" || type == "a") { // alpha
var add = type.charCodeAt(0);
do {
str = String.fromCharCode(((value - 1) % 26) + add) + str;
value = Math.floor((value - 1) / 26);
} while (value);
} else if (type == "I" || type == "i") { // roman
var base = "IVXLCDM";
var b, r, add = 0;
if (value > 3999) {
str = "?";
} else {
if (type == "i")
base = base.toLowerCase();
for (b = 0; value > 0 && b < 7 - 1; b += 2, value = Math.floor(value / 10)) {
r = value % 10;
if (r != 0) {
if (r < 4) {
for (; r; r--)
str = String.fromCharCode(base.charCodeAt(b) + add) + str;
} else if (r == 4) {
str = String.fromCharCode(base.charCodeAt(b + 1) + add) + str;
str = String.fromCharCode(base.charCodeAt(b) + add) + str;
} else if (r == 5) {
str = String.fromCharCode(base.charCodeAt(b + 1) + add) + str;
} else if (r < 9) {
for (; r > 5; r--)
str = String.fromCharCode(base.charCodeAt(b) + add) + str;
str = String.fromCharCode(base.charCodeAt(b + 1) + add) + str;
} else if (r == 9) {
str = String.fromCharCode(base.charCodeAt(b + 2) + add) + str;
str = String.fromCharCode(base.charCodeAt(b) + add) + str;
}
}
}
}
} else { // numeric
str = "" + value;
}
return str;
}
EvoConvert.getComputedOrNodeStyle = function(node)
{
if (!node)
return null;
var parent = node;
while (parent && !(parent === document.body)) {
parent = parent.parentElement;
}
if (parent)
return window.getComputedStyle(node);
return node.style;
}
EvoConvert.replaceList = function(element, tagName, normalDivWidth, context)
{
var ll, lists, type = null;
if (tagName == "OL")
type = "";
lists = element.getElementsByTagName(tagName);
for (ll = lists.length - 1; ll >= 0; ll--) {
var list;
list = lists.item(ll);
if (!list)
continue;
var style = EvoConvert.getComputedOrNodeStyle(list), ltr, ii, prefixSuffix, indent;
if (!style)
style = list.style;
ltr = !style || style.direction != "rtl";
if (type == null) {
var level = 0, parent = list;
for (parent = list.parentElement; parent; parent = parent.parentElement) {
if (parent.tagName == "UL" || parent.tagName == "OL")
level++;
}
switch (level % 3) {
default:
case 0:
prefixSuffix = " * ";
break;
case 1:
prefixSuffix = " - ";
break;
case 2:
prefixSuffix = " + ";
break;
}
indent = 3;
} else {
type = list.getAttribute("type");
if (!type)
type = "";
var nChildren = 0, child;
for (ii = 0; ii < list.children.length; ii++) {
child = list.children.item(ii);
if (child.tagName == "LI")
nChildren++;
}
prefixSuffix = ltr ? ". " : " .";
indent = EvoConvert.GetOLMaxLetters(type, nChildren) + prefixSuffix.length;
if (indent < EvoConvert.MIN_OL_WIDTH)
indent = EvoConvert.MIN_OL_WIDTH;
}
if (list.hasAttribute("x-evo-extra-indent")) {
var tmp = list.getAttribute("x-evo-extra-indent");
if (tmp) {
tmp = parseInt(tmp);
if (!Number.isInteger(tmp))
tmp = 0;
} else {
tmp = 0;
}
indent += tmp;
}
var liCount = 0;
for (ii = 0; ii < list.children.length; ii++) {
var child = list.children.item(ii), node;
if (!child)
continue;
// nested lists
if (child.tagName == "DIV" && child.hasAttribute("x-evo-extra-indent") && child.hasAttribute("x-evo-li-text")) {
node = child.cloneNode(true);
var tmp = child.getAttribute("x-evo-extra-indent");
if (tmp) {
tmp = parseInt(tmp);
if (!Number.isInteger(tmp))
tmp = 0;
} else {
tmp = 0;
}
node.setAttribute("x-evo-extra-indent", indent + tmp);
tmp = node.getAttribute("x-evo-li-text");
if (ltr)
tmp = " ".repeat(indent) + tmp;
else
tmp = tmp + " ".repeat(indent);
node.setAttribute("x-evo-li-text", tmp);
} else if (child.tagName == "LI") {
liCount++;
var anchors = child.getElementsByTagName("A"), jj;
for (jj = anchors.length - 1; jj >= 0; jj--) {
var anchor = anchors[jj], str;
str = EvoConvert.processAnchor(anchor, context);
anchor.parentNode.insertBefore(document.createTextNode(str), anchor);
anchor.remove();
}
node = document.createElement("DIV");
if (list.style.width.endsWith("ch")) {
var width = parseInt(list.style.width.slice(0, -2));
if (Number.isInteger(width))
node.style.width = "" + width + "ch";
} else if (normalDivWidth > 0) {
var width, needs;
if (tagName == "UL") {
needs = 3;
} else {
needs = EvoConvert.GetOLMaxLetters(list.getAttribute("type"), list.children.length) + 2; // length of ". " suffix
if (needs < EvoConvert.MIN_OL_WIDTH)
needs = EvoConvert.MIN_OL_WIDTH;
}
width = normalDivWidth - needs;
if (width < EvoConvert.MIN_PARAGRAPH_WIDTH)
width = EvoConvert.MIN_PARAGRAPH_WIDTH;
node.style.width = "" + width + "ch";
}
node.style.textAlign = list.style.testAlign;
node.style.direction = list.style.direction;
node.style.marginLeft = list.style.marginLeft;
node.style.marginRight = list.style.marginRight;
node.setAttribute("x-evo-extra-indent", indent);
node.innerText = child.innerText;
if (type == null) {
node.setAttribute("x-evo-li-text", prefixSuffix);
} else {
var prefix;
prefix = EvoConvert.getOLIndexValue(type, liCount);
while (prefix.length + 2 /* prefixSuffix.length */ < indent) {
prefix = ltr ? " " + prefix : prefix + " ";
}
node.setAttribute("x-evo-li-text", ltr ? prefix + prefixSuffix : prefixSuffix + prefix);
}
} else {
node = child.cloneNode(true);
if (node.tagName == "UL" || node.tagName == "OL") {
var tmp = child.getAttribute("x-evo-extra-indent");
if (tmp) {
tmp = parseInt(tmp);
if (!Number.isInteger(tmp))
tmp = 0;
} else {
tmp = 0;
}
node.setAttribute("x-evo-extra-indent", indent + tmp);
}
}
list.parentNode.insertBefore(node, list);
}
list.parentNode.removeChild(list);
}
}
EvoConvert.calcLineLetters = function(line)
{
var len;
if (line.search("\t") >= 0) {
var jj;
len = 0;
for (jj = 0; jj < line.length; jj++) {
if (line.charAt(jj) == "\t") {
len = len - (len % EvoConvert.TAB_SIZE) + EvoConvert.TAB_SIZE;
} else {
len++;
}
}
} else {
len = line.length;
}
return len;
}
EvoConvert.getQuotePrefix = function(quoteLevel, ltr)
{
var prefix = "";
if (quoteLevel > 0) {
prefix = ltr ? "> " : " <";
prefix = prefix.repeat(quoteLevel);
}
return prefix;
}
EvoConvert.formatParagraph = function(str, ltr, align, indent, whiteSpace, wrapWidth, extraIndent, liText, quoteLevel)
{
if (!str || str == "")
return liText ? liText : str;
var lines = [], ii;
// wrap the string first
if (wrapWidth > 0) {
var worker = {
collapseWhiteSpace : whiteSpace != "pre" && whiteSpace != "pre-wrap",
collapseEndingWhiteSpace : whiteSpace != "pre",
canWrap : whiteSpace != "nowrap",
charWrap : whiteSpace == "pre",
inAnchor : 0,
ignoreLineLetters : 0, // used for EvoConvert.NOWRAP_CHAR_START and EvoConvert.NOWRAP_CHAR_END, which should be skipped in width calculation
useWrapWidth : wrapWidth,
spacesFrom : -1, // in 'str'
lastWrapableChar : -1, // in this->line
lineLetters : 0,
line : "",
maybeRecalcIgnoreLineLetters : function() {
if (this.ignoreLineLetters) {
var ii, len = this.line.length, chr;
this.ignoreLineLetters = 0;
for (ii = 0; ii < len; ii++) {
chr = this.line[ii];
if (chr == EvoConvert.NOWRAP_CHAR_START || chr == EvoConvert.NOWRAP_CHAR_END)
this.ignoreLineLetters++;
}
}
},
mayConsumeWhitespaceAfterWrap : function(str, ii) {
return ii > 0 && this.line == "" && str[ii - 1] == EvoConvert.NOWRAP_CHAR_END;
},
isInUnwrapPart : function() {
if (this.inAnchor)
return true;
if (this.line[0] == EvoConvert.NOWRAP_CHAR_START)
return this.line.indexOf(EvoConvert.NOWRAP_CHAR_END) < 0;
return false;
},
shouldWrap : function(nextChar) {
return this.canWrap && (!this.collapseWhiteSpace || nextChar != '\n') &&
(!this.isInUnwrapPart() || this.lastWrapableChar != -1) && (this.lineLetters - this.ignoreLineLetters > this.useWrapWidth || (
((!this.charWrap && (nextChar == " " || nextChar == "\t") && this.lineLetters - this.ignoreLineLetters > this.useWrapWidth) ||
((this.charWrap || (nextChar != " " && nextChar != "\t")) && this.lineLetters - this.ignoreLineLetters == this.useWrapWidth)) && (
this.lastWrapableChar == -1/* || this.lastWrapableChar == this.line.length*/)));
},
commitSpaces : function(ii) {
if (this.spacesFrom != -1 && (!this.canWrap || this.line.length - this.ignoreLineLetters <= this.useWrapWidth)) {
var spaces;
spaces = ii - this.spacesFrom;
if (this.canWrap && this.line.length - this.ignoreLineLetters + spaces > this.useWrapWidth)
spaces = this.useWrapWidth - this.line.length + this.ignoreLineLetters;
if (!this.canWrap || (this.line.length - this.ignoreLineLetters + spaces <= this.useWrapWidth) && spaces >= 0) {
if (this.collapseWhiteSpace && (!extraIndent || lines.length))
this.line += " ";
else
this.line += " ".repeat(spaces);
}
this.spacesFrom = -1;
this.lastWrapableChar = this.line.length;
} else if (this.spacesFrom != -1) {
this.lastWrapableChar = this.line.length;
}
},
commit : function(ii, force) {
this.commitSpaces(ii);
var didWrap = false;
if (this.canWrap && this.lastWrapableChar != -1 && this.lineLetters - this.ignoreLineLetters > this.useWrapWidth) {
lines[lines.length] = this.line.substr(0, this.lastWrapableChar);
this.line = this.line.substr(this.lastWrapableChar);
this.maybeRecalcIgnoreLineLetters();
didWrap = true;
} else if (!this.isInUnwrapPart() && this.useWrapWidth != -1 && this.lineLetters - this.ignoreLineLetters > this.useWrapWidth) {
var jj;
if (this.charWrap) {
var subLineLetters = 0, ignoreSubLineLetters = 0, chr;
for(jj = 0; jj < this.line.length; jj++) {
chr = this.line.charAt(jj);
if (chr == "\t") {
subLineLetters = subLineLetters - ((subLineLetters - ignoreSubLineLetters) % EvoConvert.TAB_SIZE) + EvoConvert.TAB_SIZE;
} else {
subLineLetters++;
}
if (chr == EvoConvert.NOWRAP_CHAR_START || chr == EvoConvert.NOWRAP_CHAR_END)
ignoreSubLineLetters++;
if (subLineLetters - ignoreSubLineLetters >= this.useWrapWidth)
break;
}
} else {
jj = this.line.length;
}
lines[lines.length] = this.line.substr(0, jj);
this.line = this.line.substr(jj);
this.maybeRecalcIgnoreLineLetters();
didWrap = true;
} else {
lines[lines.length] = this.line;
this.line = "";
this.ignoreLineLetters = 0;
}
if (this.canWrap && this.collapseEndingWhiteSpace && didWrap && lines[lines.length - 1].endsWith(" ")) {
if (lines[lines.length - 1].length == 1)
lines.length = lines.length - 1;
else
lines[lines.length - 1] = lines[lines.length - 1].substr(0, lines[lines.length - 1].length - 1);
}
if (force && this.line) {
lines[lines.length] = this.line;
this.line = "";
this.ignoreLineLetters = 0;
}
this.lineLetters = this.canWrap ? EvoConvert.calcLineLetters(this.line) : this.line.length;
this.spacesFrom = -1;
this.lastWrapableChar = -1;
}
};
if (worker.useWrapWidth < EvoConvert.MIN_PARAGRAPH_WIDTH)
worker.useWrapWidth = EvoConvert.MIN_PARAGRAPH_WIDTH;
var chr, isHighSurrogate = false;
for (ii = 0; ii < str.length; ii += 1 + (isHighSurrogate ? 1 : 0)) {
// surrogate are two characters "high+low"; high: 0xD800 - 0xDBFF; low: 0xDC00 - 0xDFFF
// and cannot split after the high surrogate, because that would break the character encoding
isHighSurrogate = str.charCodeAt(ii) >= 0xd800 && str.charCodeAt(ii) <= 0xdbff;
if (isHighSurrogate)
chr = str.substr(ii, 2);
else
chr = str.charAt(ii);
if (chr == EvoConvert.NOWRAP_CHAR_START)
worker.inAnchor++;
if (chr == "\n") {
if (!worker.mayConsumeWhitespaceAfterWrap(str, ii))
worker.commit(ii, true);
} else if (!worker.charWrap && !worker.collapseWhiteSpace && chr == "\t") {
if (worker.shouldWrap(str[ii + 1]))
worker.commit(ii, false);
else
worker.commitSpaces(ii);
var add = chr; // this expands the tab, instead of leaving it '\t'... " ".repeat(EvoConvert.TAB_WIDTH - ((worker.lineLetters - worker.ignoreLineLetters) % EvoConvert.TAB_WIDTH));
worker.lineLetters = worker.lineLetters - ((worker.lineLetters - worker.ignoreLineLetters) % EvoConvert.TAB_WIDTH) + EvoConvert.TAB_WIDTH;
if (worker.shouldWrap(str[ii + 1]))
worker.commit(ii, false);
worker.line += add;
worker.lineLetters += add.length;
} else if (!worker.charWrap && (chr == " " || chr == "\t")) {
var setSpacesFrom = false;
if (chr == "\t") {
worker.lineLetters = worker.lineLetters - ((worker.lineLetters - worker.ignoreLineLetters) % EvoConvert.TAB_WIDTH) + EvoConvert.TAB_WIDTH;
setSpacesFrom = true;
} else if ((worker.spacesFrom == -1 && worker.line != "") || (!worker.collapseWhiteSpace && !worker.mayConsumeWhitespaceAfterWrap(str, ii))) {
worker.lineLetters++;
setSpacesFrom = true;
}
// all spaces at the end of paragraph line are ignored
if (setSpacesFrom && worker.spacesFrom == -1)
worker.spacesFrom = ii;
} else {
worker.commitSpaces(ii);
worker.line += chr;
if (chr == "\t")
worker.lineLetters = worker.lineLetters - ((worker.lineLetters - worker.ignoreLineLetters) % EvoConvert.TAB_WIDTH) + EvoConvert.TAB_WIDTH;
else
worker.lineLetters += chr.length;
if (chr == EvoConvert.NOWRAP_CHAR_START || chr == EvoConvert.NOWRAP_CHAR_END)
worker.ignoreLineLetters++;
if (chr == EvoConvert.NOWRAP_CHAR_END && worker.inAnchor)
worker.inAnchor--;
if (worker.shouldWrap(str[ii + 1]))
worker.commit(ii, false);
if (chr == "-" && worker.line.length && !worker.inAnchor)
worker.lastWrapableChar = worker.line.length;
else if (chr == EvoConvert.NOWRAP_CHAR_START && quoteLevel > 0 && worker.lastWrapableChar < 0 && worker.inAnchor <= 1 && worker.line.length > 1) {
worker.lastWrapableChar = worker.line.length;
}
}
}
while (worker.line.length || worker.spacesFrom != -1 || !lines.length) {
worker.commit(ii, false);
}
} else {
if (str.endsWith("\n"))
str = str.substr(0, str.length - 1);
lines = str.split("\n");
}
var extraIndentStr = extraIndent > 0 ? " ".repeat(extraIndent) : null;
if (wrapWidth <= 0) {
for (ii = 0; ii < lines.length; ii++) {
var len = EvoConvert.calcLineLetters(lines[ii]);
if (wrapWidth < len)
wrapWidth = len;
}
}
str = "";
for (ii = 0; ii < lines.length; ii++) {
var line = lines[ii];
if ((!ltr && align == EvoConvert.ALIGN_LEFT) ||
(ltr && align == EvoConvert.ALIGN_RIGHT)) {
var len = EvoConvert.calcLineLetters(line);
if (len < wrapWidth) {
var add = " ".repeat(wrapWidth - len);
if (ltr)
line = add + line;
else
line = line + add;
}
} else if (align == EvoConvert.ALIGN_CENTER) {
var len = EvoConvert.calcLineLetters(line);
if (len < wrapWidth) {
var add = " ".repeat((wrapWidth - len) / 2);
if (ltr)
line = add + line;
else
line = line + add;
}
} else if (align == EvoConvert.ALIGN_JUSTIFY && ii + 1 < lines.length) {
var len = EvoConvert.calcLineLetters(line);
if (len < wrapWidth) {
var words = line.split(" ");
if (words.length > 1) {
var nAdd = (wrapWidth - len);
var add = " ".repeat(nAdd / (words.length - 1) >= 1 ? nAdd / (words.length - 1) : nAdd), jj;
for (jj = 0; jj < words.length - 1 && nAdd > 0; jj++) {
words[jj] = words[jj] + add;
nAdd -= add.length;
if (nAdd > 0 && jj + 2 >= words.length) {
words[jj] = " ".repeat(nAdd) + words[jj];
}
}
line = words[0];
for (jj = 1; jj < words.length; jj++) {
line = line + " " + words[jj];
}
}
}
}
if (!ii && liText) {
if (ltr)
line = liText + line;
else
line = line + liText;
} else if (extraIndentStr && ii > 0) {
if (ltr)
line = extraIndentStr + line;
else
line = line + extraIndentStr;
}
if (indent != "") {
if (ltr && align != EvoConvert.ALIGN_RIGHT)
line = indent + line;
else
line = line + indent;
}
str += line + "\n";
}
return str;
}
EvoConvert.ImgToText = function(img)
{
if (!img)
return "";
var txt;
txt = img.alt;
return txt ? txt : "";
}
EvoConvert.appendNodeText = function(node, str, text)
{
/* This breaks "--
", thus disable it for now. Cannot distinguish from test 70 of /EWebView/ConvertToPlain.
if (node && node.parentElement && text.startsWith('\n') && str.endsWith(" ")) {
var whiteSpace = "normal";
if (node.parentElement)
whiteSpace = window.getComputedStyle(node.parentElement).whiteSpace;
if (!whiteSpace || whiteSpace == "normal") {
return str.substr(0, str.length - 1) + text;
}
} */
return str + text;
}
EvoConvert.extractElemText = function(elem, normalDivWidth, quoteLevel, context)
{
if (!elem)
return "";
if (!elem.childNodes.length)
return elem.innerText;
var str = "", ii;
for (ii = 0; ii < elem.childNodes.length; ii++) {
var node = elem.childNodes.item(ii);
if (!node)
continue;
str = EvoConvert.appendNodeText(node, str, EvoConvert.processNode(node, normalDivWidth, quoteLevel, context));
}
return str;
}
EvoConvert.mergeConsecutiveSpaces = function(str)
{
if (str.indexOf(" ") >= 0) {
var words = str.split(" "), ii, word;
str = "";
for (ii = 0; ii < words.length; ii++) {
word = words[ii];
if (word) {
if (ii)
str += " ";
str += word;
}
}
if (!words[words.length - 1])
str += " ";
}
return str;
}
EvoConvert.RemoveInsignificantNewLines = function(node, stripSingleSpace)
{
var str = "";
if (node && node.nodeType == node.TEXT_NODE) {
var has_rnt;
str = node.nodeValue;
has_rnt = str.indexOf("\r") >= 0 ||
str.indexOf("\n") >= 0 ||
str.indexOf("\t") >= 0;
if (has_rnt || str.indexOf(" ") >= 0) {
var whiteSpace = "normal";
if (node.parentElement)
whiteSpace = window.getComputedStyle(node.parentElement).whiteSpace;
if (whiteSpace == "pre-line") {
str = EvoConvert.mergeConsecutiveSpaces(str.replace(/\t/g, " "));
} else if (!whiteSpace || whiteSpace == "normal" || whiteSpace == "nowrap") {
if (str == "\n" || str == "\r" || str == "\r\n") {
var previousSibling = node.previousElementSibling;
if (stripSingleSpace || (previousSibling && (previousSibling.tagName == "BR" ||
previousSibling.tagName == "DIV" || previousSibling.tagName == "P" ||
previousSibling.tagName == "BODY")))
str = "";
} else if (has_rnt) {
if ((!node.previousSibling || node.previousSibling.tagName) && (str[0] == '\r' || str[0] == '\n')) {
var ii;
for (ii = 0; str[ii] == '\n' || str[ii] == '\r'; ii++) {
// do nothing, just skip all leading insignificant new lines
}
str = str.substr(ii);
}
if (str.length > 0 && (!node.nextSibling || node.nextSibling.tagName) && (str[str.length - 1] == '\r' || str[str.length - 1] == '\n')) {
var ii;
for (ii = str.length - 1; ii >= 0 && (str[ii] == '\n' || str[ii] == '\r'); ii--) {
// do nothing, just skip all trailing insignificant new lines
}
str = str.substr(0, ii + 1);
}
if (str.length == 0 && stripSingleSpace === false)
str = " ";
str = EvoConvert.mergeConsecutiveSpaces(str.replace(/\t/g, " ").replace(/\r/g, " ").replace(/\n/g, " "));
if ((!whiteSpace || whiteSpace == "normal") && str == " ") {
if (stripSingleSpace || (!node.previousElementSibling && !node.nextElementSibling &&
node.parentElement && (node.parentElement.tagName == "DIV" ||
node.parentElement.tagName == "DIV" || node.parentElement.tagName == "P" ||
node.parentElement.tagName == "PRE" || node.parentElement.tagName == "BODY"))) {
str = "";
}
}
}
}
}
}
return str;
}
EvoConvert.processNode = function(node, normalDivWidth, quoteLevel, context)
{
var str = "";
if (node.nodeType == node.TEXT_NODE) {
str = EvoConvert.RemoveInsignificantNewLines(node, false);
} else if (node.nodeType == node.ELEMENT_NODE) {
if (node.hidden ||
node.tagName == "STYLE" ||
node.tagName == "META" ||
(node.tagName == "SPAN" && node.classList.contains("-x-evo-quoted")))
return str;
var style = EvoConvert.getComputedOrNodeStyle(node), ltr, align, indent, whiteSpace;
if (!style)
style = node.style;
ltr = !style || style.direction != "rtl";
align = style ? style.textAlign : "";
if (!align || align == "")
align = node.style.textAlign;
if (align)
align = align.toLowerCase();
if (!align)
align = "";
if (align == "" || align == "start")
align = ltr ? "left" : "right";
if (align == "center")
align = EvoConvert.ALIGN_CENTER;
else if (align == "right")
align = EvoConvert.ALIGN_RIGHT;
else if (align == "justify")
align = EvoConvert.ALIGN_JUSTIFY;
else
align = EvoConvert.ALIGN_LEFT;
// mixed indent and opposite text align does nothing
if ((ltr && align == EvoConvert.ALIGN_RIGHT) ||
(!ltr && align == EvoConvert.ALIGN_LEFT)) {
indent = "";
} else {
// computed style's 'indent' uses pixels, not characters
indent = ltr ? node.style.marginLeft : node.style.marginRight;
}
if (indent && indent.endsWith("ch")) {
indent = parseInt(indent.slice(0, -2));
if (!Number.isInteger(indent) || indent < 0)
indent = 0;
} else {
indent = 0;
}
if (indent > 0)
indent = " ".repeat(indent);
else
indent = "";
whiteSpace = style ? style.whiteSpace.toLowerCase() : "";
if (node.tagName == "DIV" || node.tagName == "P") {
var liText, extraIndent, width, useDefaultWidth = false;
liText = node.getAttribute("x-evo-li-text");
if (!liText)
liText = "";
extraIndent = node.getAttribute("x-evo-extra-indent");
extraIndent = extraIndent ? parseInt(extraIndent, 10) : 0;
if (!Number.isInteger(extraIndent)) {
extraIndent = 0;
}
width = node.style.width;
if (width && width.endsWith("ch")) {
width = parseInt(width.slice(0, -2));
if (!Number.isInteger(width) || width < 0)
useDefaultWidth = true;
} else {
useDefaultWidth = true;
}
var childrenWillWrap = true;
if (!node.classList.contains("gmail_quote")) {
childrenWillWrap = node.childNodes.length > 0 && liText == "";
var ii;
for (ii = 0; childrenWillWrap && ii < node.childNodes.length; ii++) {
var child = node.childNodes.item(ii);
childrenWillWrap = (child.nodeType == child.ELEMENT_NODE &&
((child.tagName == "DIV" && !child.getAttribute("x-evo-li-text")) ||
child.tagName == "P" ||
child.tagName == "PRE" ||
child.tagName == "BLOCKQUOTE" ||
child.tagName == "BR")) ||
(child.nodeType == child.TEXT_NODE &&
EvoConvert.RemoveInsignificantNewLines(child, true).trim().length == 0);
}
}
if (childrenWillWrap) {
width = -1;
} else if (useDefaultWidth && normalDivWidth > 0) {
width = normalDivWidth - (quoteLevel * 2);
if (width < EvoConvert.MIN_PARAGRAPH_WIDTH)
width = EvoConvert.MIN_PARAGRAPH_WIDTH;
}
str = EvoConvert.formatParagraph(EvoConvert.extractElemText(node, normalDivWidth, quoteLevel, context), ltr, align, indent, whiteSpace, width, extraIndent, liText, quoteLevel);
if (!liText && node.parentElement && (node.parentElement.tagName == "DIV" || node.parentElement.tagName == "P") &&
style.display == "block" && str != "" && node.previousSibling &&
((node.previousSibling.nodeType == node.ELEMENT_NODE && node.previousSibling.tagName != "DIV" && node.previousSibling.tagName != "P" && node.previousSibling.tagName != "BR") ||
(node.previousSibling.nodeType == node.TEXT_NODE && EvoConvert.RemoveInsignificantNewLines(node.previousSibling, true) != ""))) {
str = "\n" + str;
}
} else if (node.tagName == "PRE") {
str = EvoConvert.formatParagraph(EvoConvert.extractElemText(node, normalDivWidth, quoteLevel, context), ltr, align, indent, "pre", -1, 0, "", quoteLevel);
} else if (node.tagName == "BR") {
// ignore new-lines added by wrapping, treat them as spaces
if (node.classList.contains("-x-evo-wrap-br")) {
if (node.hasAttribute("x-evo-is-space"))
str += " ";
} else {
str = "\n";
}
} else if (node.tagName == "IMG") {
str = EvoConvert.ImgToText(node);
} else if (node.tagName == "A") {
str = EvoConvert.processAnchor(node, context);
} else {
var isBlockquote = node.tagName == "BLOCKQUOTE";
str = EvoConvert.extractElemText(node, normalDivWidth, quoteLevel + (isBlockquote ? 1 : 0), context);
if (isBlockquote) {
var ii, lines = str.split("\n"), prefix, suffix;
prefix = ltr ? EvoConvert.getQuotePrefix(1, ltr) : "";
suffix = ltr ? "" : EvoConvert.getQuotePrefix(1, ltr);
str = "";
for (ii = 0; ii < lines.length; ii++) {
if (ii + 1 == lines.length && !lines[ii])
break;
str += prefix + lines[ii] + suffix + "\n";
}
}
if ((!isBlockquote || !str.endsWith("\n")) &&
str != "\n" && ((style && style.display == "block") || node.tagName == "ADDRESS" || node.tagName == "TR")) {
str += "\n";
}
}
}
return str;
}
/*
* Converts element and its children to plain text. Any
,
,, as an immediate child
* of the element, is wrapped to upto normalDivWidth characters, if it's defined and greater
* than EvoConvert.MIN_PARAGRAPH_WIDTH.
*
* The link_to_text should be one of EvoConvert.E_HTML_LINK_TO_TEXT_... constants, if not
* defined the 'EvoConvert.E_HTML_LINK_TO_TEXT_NONE' is assumed.
*/
EvoConvert.ToPlainText = function(element, normalDivWidth, link_to_text)
{
if (!element)
return null;
if (element.tagName == "HTML") {
var bodys;
bodys = element.getElementsByTagName("BODY");
if (bodys.length == 1)
element = bodys.item(0);
}
if (!element)
return null;
if (!normalDivWidth)
normalDivWidth = -1;
var disconnectFromHead = false;
if (!element.isConnected) {
// this is needed to be able to use window.getComputedStyle()
document.head.appendChild(element);
disconnectFromHead = true;
}
var context = {
link_to_text : link_to_text,
append_refs : []
};
try {
var uls, ols, str = "", ii;
uls = element.getElementsByTagName("UL");
ols = element.getElementsByTagName("OL");
if (uls.length > 0 || ols.length > 0) {
element = element.cloneNode(true);
if (uls.length)
EvoConvert.replaceList(element, "UL", normalDivWidth, context);
if (ols.length)
EvoConvert.replaceList(element, "OL", normalDivWidth, context);
}
for (ii = 0; ii < element.childNodes.length; ii++) {
var node = element.childNodes.item(ii);
if (!node)
continue;
str = EvoConvert.appendNodeText(node, str, EvoConvert.processNode(node, normalDivWidth, 0, context));
}
if (context.append_refs.length > 0) {
if (!str.endsWith("\n"))
str += "\n";
str += "\n";
for (ii = 0; ii < context.append_refs.length; ii++) {
var prefix = "[" + (ii + 1) + "] ";
if (context.append_refs[ii].label) {
var indent = prefix.length;
prefix += context.append_refs[ii].label.replace(/\r/g, "").replace(/\n/g, " ");
if (normalDivWidth && normalDivWidth > 0 &&
normalDivWidth < (prefix.length + 1 + context.append_refs[ii].href.length)) {
prefix += "\n" + " ".repeat(indent);
} else {
prefix += " ";
}
}
str += prefix + context.append_refs[ii].href + "\n";
}
}
} finally {
if (disconnectFromHead)
document.head.removeChild(element);
}
// remove EvoConvert.NOWRAP_CHAR_START and EvoConvert.NOWRAP_CHAR_END from the result
return str.replace(/\x01/g, "").replace(/\x02/g, "");
}