[evolution] EWebKitEditor: Switch to JavaScriptCore API
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution] EWebKitEditor: Switch to JavaScriptCore API
- Date: Mon, 27 Apr 2020 13:08:28 +0000 (UTC)
commit fcd4768b2ef888e01705ed6256cc7bb7e0dbd16e
Author: Milan Crha <mcrha redhat com>
Date: Mon Apr 27 15:06:56 2020 +0200
EWebKitEditor: Switch to JavaScriptCore API
The C DOM API had been deprecated since WebKitGTK 2.22. This is
the editor rewrite to use the new API.
CMakeLists.txt | 2 +-
data/webkit/CMakeLists.txt | 3 +
data/webkit/e-convert.js | 949 +-
data/webkit/e-editor.js | 5840 ++++++
data/webkit/e-selection.js | 435 +
data/webkit/e-undo-redo.js | 940 +
data/webkit/e-web-view.js | 21 +-
.../evolution-util/evolution-util-docs.sgml.in | 1 -
src/composer/e-composer-actions.c | 36 +-
src/composer/e-composer-private.c | 2 +
src/composer/e-composer-private.h | 3 +
src/composer/e-msg-composer.c | 661 +-
src/composer/e-msg-composer.h | 2 +
src/e-util/CMakeLists.txt | 3 +-
src/e-util/e-content-editor.c | 838 +-
src/e-util/e-content-editor.h | 226 +-
src/e-util/e-html-editor-actions.c | 223 +-
src/e-util/e-html-editor-actions.h | 10 +-
src/e-util/e-html-editor-cell-dialog.c | 4 +-
src/e-util/e-html-editor-find-dialog.c | 4 +-
src/e-util/e-html-editor-hrule-dialog.c | 34 +-
src/e-util/e-html-editor-image-dialog.c | 4 +-
src/e-util/e-html-editor-link-dialog.c | 17 +-
src/e-util/e-html-editor-manager.ui | 8 +-
src/e-util/e-html-editor-page-dialog.c | 70 +-
src/e-util/e-html-editor-paragraph-dialog.c | 10 +
src/e-util/e-html-editor-private.h | 11 +-
src/e-util/e-html-editor-replace-dialog.c | 4 +-
src/e-util/e-html-editor-spell-check-dialog.c | 18 +-
src/e-util/e-html-editor-table-dialog.c | 43 +-
src/e-util/e-html-editor.c | 531 +-
src/e-util/e-html-editor.h | 26 +-
src/e-util/e-mail-signature-editor.c | 178 +-
src/e-util/e-misc-utils.c | 270 -
src/e-util/e-misc-utils.h | 35 -
src/e-util/e-spell-checker.c | 4 +
src/e-util/e-util-enums.h | 83 +-
src/e-util/e-util.h | 1 -
src/e-util/e-web-extension-container.c | 1280 --
src/e-util/e-web-extension-container.h | 103 -
src/e-util/e-web-view.c | 1 -
src/e-util/test-html-editor-units-bugs.c | 618 +-
src/e-util/test-html-editor-units-bugs.h | 2 +
src/e-util/test-html-editor-units-utils.c | 320 +-
src/e-util/test-html-editor-units-utils.h | 4 +-
src/e-util/test-html-editor-units.c | 5664 +++++-
src/e-util/test-html-editor.c | 207 +-
src/e-util/test-web-view-jsc.c | 1025 +-
src/mail/e-cid-request.c | 68 +-
src/mail/e-cid-request.h | 37 +
src/mail/e-mail-display.c | 70 +-
src/mail/e-mail-notes.c | 171 +-
.../composer-to-meeting/e-composer-to-meeting.c | 120 +-
src/modules/webkit-editor/e-webkit-editor.c | 5516 +++---
.../webkit-editor/web-extension/CMakeLists.txt | 32 +-
.../web-extension/e-composer-dom-functions.c | 610 -
.../web-extension/e-composer-dom-functions.h | 46 -
.../web-extension/e-dialogs-dom-functions.c | 1489 --
.../web-extension/e-dialogs-dom-functions.h | 134 -
.../webkit-editor/web-extension/e-dom-utils.c | 621 -
.../webkit-editor/web-extension/e-dom-utils.h | 91 -
.../web-extension/e-editor-dom-functions.c | 18336 -------------------
.../web-extension/e-editor-dom-functions.h | 393 -
.../webkit-editor/web-extension/e-editor-page.c | 1047 --
.../webkit-editor/web-extension/e-editor-page.h | 223 -
.../web-extension/e-editor-undo-redo-manager.c | 2990 ---
.../web-extension/e-editor-undo-redo-manager.h | 184 -
.../web-extension/e-editor-web-extension-main.c | 45 -
.../web-extension/e-editor-web-extension-names.h | 25 -
.../web-extension/e-editor-web-extension.c | 2851 +--
.../web-extension/e-editor-web-extension.h | 12 -
src/plugins/external-editor/external-editor.c | 75 +-
src/web-extensions/CMakeLists.txt | 1 +
src/web-extensions/e-web-extension.c | 26 +-
74 files changed, 19707 insertions(+), 36280 deletions(-)
---
diff --git a/CMakeLists.txt b/CMakeLists.txt
index edc7a280cc..678e822cb4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -82,7 +82,7 @@ set(gsettings_desktop_schemas_minimum_version 2.91.92)
set(libpst_minimum_version 0.6.54)
set(libxml_minimum_version 2.7.3)
set(shared_mime_info_minimum_version 0.22)
-set(webkit2gtk_minimum_version 2.24.0)
+set(webkit2gtk_minimum_version 2.28.0)
# Optional Packages
set(champlain_minimum_version 0.12)
diff --git a/data/webkit/CMakeLists.txt b/data/webkit/CMakeLists.txt
index 37832ac9df..3397bd03c7 100644
--- a/data/webkit/CMakeLists.txt
+++ b/data/webkit/CMakeLists.txt
@@ -1,5 +1,8 @@
set(DATA_FILES
e-convert.js
+ e-editor.js
+ e-selection.js
+ e-undo-redo.js
e-web-view.js
webview.css
webview-print.css
diff --git a/data/webkit/e-convert.js b/data/webkit/e-convert.js
index 4e67b92dc2..7f7056e45a 100644
--- a/data/webkit/e-convert.js
+++ b/data/webkit/e-convert.js
@@ -1,12 +1,957 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
'use strict';
/* semi-convention: private functions start with lower-case letter,
public functions start with upper-case letter. */
-function EvoConvertToPlainText(element)
+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"
+};
+
+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)
+{
+ 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++;
+
+ 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";
+ }
+ 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'
+ lastSpace : -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.lastSpace != -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.lastSpace == -1/* || this.lastSpace == 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.lastSpace = this.line.length;
+ } else if (this.spacesFrom != -1) {
+ this.lastSpace = this.line.length;
+ }
+ },
+
+ commit : function(ii, force) {
+ this.commitSpaces(ii);
+
+ var didWrap = false;
+
+ if (this.canWrap && this.lastSpace != -1 && this.lineLetters -
this.ignoreLineLetters > this.useWrapWidth) {
+ lines[lines.length] = this.line.substr(0, this.lastSpace);
+ this.line = this.line.substr(this.lastSpace);
+ 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.lastSpace = -1;
+ }
+ };
+
+ if (worker.useWrapWidth < EvoConvert.MIN_PARAGRAPH_WIDTH)
+ worker.useWrapWidth = EvoConvert.MIN_PARAGRAPH_WIDTH;
+
+ var chr;
+
+ for (ii = 0; ii < str.length; ii++) {
+ 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++;
+
+ 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);
+ }
+ }
+
+ 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;
+ }
+
+ if (quoteLevel > 0) {
+ if (ltr)
+ line = EvoConvert.getQuotePrefix(quoteLevel, ltr) + line;
+ else
+ line = line + EvoConvert.getQuotePrefix(quoteLevel, ltr);
+ }
+
+ str += line + "\n";
+ }
+
+ return str;
+}
+
+EvoConvert.ImgToText = function(img)
+{
+ if (!img)
+ return "";
+
+ var txt;
+
+ txt = img.alt;
+
+ return txt ? txt : "";
+}
+
+EvoConvert.extractElemText = function(elem, normalDivWidth, quoteLevel)
+{
+ 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.processNode(node, normalDivWidth, quoteLevel);
+ }
+
+ 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.processNode = function(node, normalDivWidth, quoteLevel)
+{
+ var str = "";
+
+ if (node.nodeType == node.TEXT_NODE) {
+ str = node.nodeValue;
+
+ if (str.indexOf("\r") >= 0 ||
+ str.indexOf("\n") >= 0 ||
+ str.indexOf("\t") >= 0 ||
+ 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") {
+ str = "";
+ } else {
+ 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);
+ }
+
+ str = EvoConvert.mergeConsecutiveSpaces(str.replace(/\t/g, "
").replace(/\r/g, " ").replace(/\n/g, " "));
+ }
+ }
+ }
+ } 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;
+ }
+
+ 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), ltr, align, indent, whiteSpace, width, extraIndent, liText, quoteLevel);
+ } else if (node.tagName == "PRE") {
+ str = EvoConvert.formatParagraph(EvoConvert.extractElemText(node, normalDivWidth,
quoteLevel), 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"))
+ str += " ";
+ else
+ str = "\n";
+ } else if (node.tagName == "IMG") {
+ str = EvoConvert.ImgToText(node);
+ } else if (node.tagName == "A" && !node.innerText.includes(" ") &&
!node.innerText.includes("\n")) {
+ str = EvoConvert.NOWRAP_CHAR_START + node.innerText + EvoConvert.NOWRAP_CHAR_END;
+ } else {
+ var isBlockquote = node.tagName == "BLOCKQUOTE";
+
+ str = EvoConvert.extractElemText(node, normalDivWidth, quoteLevel + (isBlockquote ? 1
: 0));
+
+ if ((!isBlockquote || !str.endsWith("\n")) &&
+ str != "\n" && ((style && style.display == "block") || node.tagName ==
"ADDRESS")) {
+ str += "\n";
+ }
+ }
+ }
+
+ return str;
+}
+
+/*
+ * Converts element and its children to plain text. Any <div>,<ul>,<ol>, as an immediate child
+ * of the element, is wrapped to upto normalDivWidth characters, if it's defined and greater
+ * than EvoConvert.MIN_PARAGRAPH_WIDTH.
+ */
+EvoConvert.ToPlainText = function(element, normalDivWidth)
{
if (!element)
return null;
- return element.innerText;
+ 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;
+ }
+
+ 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");
+
+ if (ols.length)
+ EvoConvert.replaceList(element, "OL");
+ }
+
+ for (ii = 0; ii < element.childNodes.length; ii++) {
+ var node = element.childNodes.item(ii);
+
+ if (!node)
+ continue;
+
+ str += EvoConvert.processNode(node, normalDivWidth, 0);
+ }
+ } 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, "");
}
diff --git a/data/webkit/e-editor.js b/data/webkit/e-editor.js
new file mode 100644
index 0000000000..9054f8f1c5
--- /dev/null
+++ b/data/webkit/e-editor.js
@@ -0,0 +1,5840 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+'use strict';
+
+/* semi-convention: private functions start with lower-case letter,
+ public functions start with upper-case letter. */
+
+var EvoEditor = {
+ CURRENT_ELEMENT_ATTR : "x-evo-dialog-current-element",
+ BLOCKQUOTE_STYLE : "margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex",
+
+ E_CONTENT_EDITOR_ALIGNMENT_NONE : -1,
+ E_CONTENT_EDITOR_ALIGNMENT_LEFT : 0,
+ E_CONTENT_EDITOR_ALIGNMENT_CENTER : 1,
+ E_CONTENT_EDITOR_ALIGNMENT_RIGHT : 2,
+ E_CONTENT_EDITOR_ALIGNMENT_JUSTIFY : 3,
+
+ E_CONTENT_EDITOR_BLOCK_FORMAT_NONE : 0,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH : 1,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_PRE : 2,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_ADDRESS : 3,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_H1 : 4,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_H2 : 5,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_H3 : 6,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_H4 : 7,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_H5 : 8,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_H6 : 9,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_UNORDERED_LIST : 10,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST : 11,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ROMAN : 12,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ALPHA : 13,
+
+ E_CONTENT_EDITOR_GET_INLINE_IMAGES : 1 << 0,
+ E_CONTENT_EDITOR_GET_RAW_BODY_HTML : 1 << 1,
+ E_CONTENT_EDITOR_GET_RAW_BODY_PLAIN : 1 << 2,
+ E_CONTENT_EDITOR_GET_RAW_BODY_STRIPPED : 1 << 3,
+ E_CONTENT_EDITOR_GET_RAW_DRAFT : 1 << 4,
+ E_CONTENT_EDITOR_GET_TO_SEND_HTML : 1 << 5,
+ E_CONTENT_EDITOR_GET_TO_SEND_PLAIN : 1 << 6,
+
+ E_CONTENT_EDITOR_NODE_UNKNOWN : 0,
+ E_CONTENT_EDITOR_NODE_IS_ANCHOR : 1 << 0,
+ E_CONTENT_EDITOR_NODE_IS_H_RULE : 1 << 1,
+ E_CONTENT_EDITOR_NODE_IS_IMAGE : 1 << 2,
+ E_CONTENT_EDITOR_NODE_IS_TABLE : 1 << 3,
+ E_CONTENT_EDITOR_NODE_IS_TABLE_CELL : 1 << 4,
+ E_CONTENT_EDITOR_NODE_IS_TEXT : 1 << 5,
+ E_CONTENT_EDITOR_NODE_IS_TEXT_COLLAPSED : 1 << 6,
+
+ E_CONTENT_EDITOR_SCOPE_CELL : 0,
+ E_CONTENT_EDITOR_SCOPE_ROW : 1,
+ E_CONTENT_EDITOR_SCOPE_COLUMN : 2,
+ E_CONTENT_EDITOR_SCOPE_TABLE : 3,
+
+ /* Flags for ClaimAffectedContent() */
+ CLAIM_CONTENT_FLAG_NONE : 0,
+ CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE : 1 << 0,
+ CLAIM_CONTENT_FLAG_SAVE_HTML : 1 << 1,
+
+ TEXT_INDENT_SIZE : 3, // in characters
+ NORMAL_PARAGRAPH_WIDTH : 71,
+ MAGIC_LINKS : true,
+ MAGIC_SMILEYS : false,
+ UNICODE_SMILEYS : false,
+ WRAP_QUOTED_TEXT_IN_REPLIES : true,
+ START_BOTTOM : false,
+ TOP_SIGNATURE : false,
+
+ FORCE_NO : 0,
+ FORCE_YES : 1,
+ FORCE_MAYBE : 2,
+
+ MODE_PLAIN_TEXT : 0,
+ MODE_HTML : 1,
+
+ mode : 1, // one of the MODE constants
+ storedSelection : null,
+ propertiesSelection : null, // dedicated to Properties dialogs
+ contextMenuNode : null, // the last target node for context menu
+ inheritThemeColors : false,
+ checkInheritFontsOnChange : false,
+ forceFormatStateUpdate : false,
+ formattingState : {
+ mode : -1,
+ anchorElement : null, // to avoid often notifications when just moving within the same node
+ bold : false,
+ italic : false,
+ underline : false,
+ strikethrough : false,
+ script : 0, // -1..subscript, 0..normal, +1..superscript
+ blockFormat : -1,
+ alignment : -1,
+ fgColor : null,
+ bgColor : null,
+ fontSize : null,
+ fontFamily : null,
+ indentLevel : 0,
+ bodyFgColor : null,
+ bodyBgColor : null,
+ bodyLinkColor : null,
+ bodyVlinkColor : null,
+ bodyFontFamily : null
+ }
+};
+
+EvoEditor.maybeUpdateFormattingState = function(force)
+{
+ var anchorElem = null;
+
+ if (!document.getSelection().isCollapsed) {
+ var commonParent;
+
+ commonParent = EvoEditor.GetCommonParent(document.getSelection().anchorNode,
document.getSelection().focusNode, true);
+ if (commonParent) {
+ var child1, child2;
+
+ child1 = EvoEditor.GetDirectChild(commonParent, document.getSelection().anchorNode);
+ child2 = EvoEditor.GetDirectChild(commonParent, document.getSelection().focusNode);
+
+ if (child1 && (!child2 || (child2 && EvoEditor.GetChildIndex(commonParent, child1) <=
EvoEditor.GetChildIndex(commonParent, child2)))) {
+ anchorElem = document.getSelection().focusNode;
+ }
+ }
+ }
+
+ if (!anchorElem)
+ anchorElem = document.getSelection().anchorNode;
+ if (!anchorElem)
+ anchorElem = document.body ? document.body.firstElementChild : null;
+
+ if (anchorElem && anchorElem.nodeType == anchorElem.TEXT_NODE)
+ anchorElem = anchorElem.parentElement;
+
+ if (force == EvoEditor.FORCE_NO && EvoEditor.formattingState.anchorElement === anchorElem &&
EvoEditor.mode == EvoEditor.formattingState.mode) {
+ return;
+ }
+
+ force = force == EvoEditor.FORCE_YES;
+
+ EvoEditor.formattingState.anchorElement = anchorElem;
+
+ var changes = {}, nchanges = 0, value, tmp;
+
+ value = EvoEditor.mode;
+ if (value != EvoEditor.formattingState.mode) {
+ EvoEditor.formattingState.mode = value;
+ changes["mode"] = value;
+ nchanges++;
+ }
+
+ value = document.body ? document.body.style.fontFamily : "";
+ if (force || value != EvoEditor.formattingState.bodyFontFamily) {
+ EvoEditor.formattingState.bodyFontFamily = value;
+ changes["bodyFontFamily"] = value;
+ nchanges++;
+ }
+
+ value = document.body ? document.body.text : "";
+ if (force || value != EvoEditor.formattingState.bodyFgColor) {
+ EvoEditor.formattingState.bodyFgColor = value;
+ changes["bodyFgColor"] = value;
+ nchanges++;
+ }
+
+ value = document.body.bgColor;
+ if (force || value != EvoEditor.formattingState.bodyBgColor) {
+ EvoEditor.formattingState.bodyBgColor = value;
+ changes["bodyBgColor"] = value;
+ nchanges++;
+ }
+
+ value = document.body.link;
+ if (force || value != EvoEditor.formattingState.bodyLinkColor) {
+ EvoEditor.formattingState.bodyLinkColor = value;
+ changes["bodyLinkColor"] = value;
+ nchanges++;
+ }
+
+ value = document.body.vLink;
+ if (force || value != EvoEditor.formattingState.bodyVlinkColor) {
+ EvoEditor.formattingState.bodyVlinkColor = value;
+ changes["bodyVlinkColor"] = value;
+ nchanges++;
+ }
+
+ var parent, obj = {
+ script : 0,
+ blockFormat : null,
+ indentLevel : 0,
+ fontFamily : null,
+ fontSize : null,
+ fgColor : null,
+ bgColor : null,
+ bold : null,
+ italic : null,
+ underline : null,
+ strikethrough : null,
+ textAlign : null
+ };
+
+ for (parent = anchorElem; parent && !(parent === document.body); parent = parent.parentElement) {
+ if (obj.script == 0) {
+ if (parent.tagName == "SUB")
+ obj.script = -1;
+ else if (parent.tagName == "SUP")
+ obj.script = +1;
+ }
+
+ if (obj.blockFormat === null) {
+ if (parent.tagName == "DIV")
+ obj.blockFormat = EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH;
+ else if (parent.tagName == "PRE")
+ obj.blockFormat = EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_PRE;
+ else if (parent.tagName == "ADDRESS")
+ obj.blockFormat = EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_ADDRESS;
+ else if (parent.tagName == "H1")
+ obj.blockFormat = EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_H1;
+ else if (parent.tagName == "H2")
+ obj.blockFormat = EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_H2;
+ else if (parent.tagName == "H3")
+ obj.blockFormat = EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_H3;
+ else if (parent.tagName == "H4")
+ obj.blockFormat = EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_H4;
+ else if (parent.tagName == "H5")
+ obj.blockFormat = EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_H5;
+ else if (parent.tagName == "H6")
+ obj.blockFormat = EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_H6;
+ else if (parent.tagName == "UL")
+ obj.blockFormat = EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_UNORDERED_LIST;
+ else if (parent.tagName == "OL") {
+ obj.blockFormat = EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST;
+
+ var typeAttr = parent.getAttribute("type");
+
+ if (typeAttr && typeAttr.toUpperCase() == "I")
+ obj.blockFormat =
EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ROMAN;
+ else if (typeAttr && typeAttr.toUpperCase() == "A")
+ obj.blockFormat =
EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ALPHA;
+ }
+ }
+
+ if ((obj.fontSize === null || obj.fontFamily === null || obj.fgColor === null) &&
+ parent.tagName == "FONT") {
+ if (obj.fontSize === null && parent.hasAttribute("size")) {
+ value = parent.getAttribute("size");
+ value = value ? parseInt(value, 10) : 0;
+ if (Number.isInteger(value) && value >= 1 && value <= 7) {
+ obj.fontSize = value;
+ }
+ }
+
+ if (obj.fontFamily === null && parent.hasAttribute("face"))
+ obj.fontFamily = parent.getAttribute("face");
+
+ if (obj.fgColor === null && parent.hasAttribute("color"))
+ obj.fgColor = parent.getAttribute("color");
+ }
+
+ var dir = window.getComputedStyle(parent).direction;
+
+ if (dir == "rtl") {
+ tmp = parent.style.marginRight;
+ if (tmp && tmp.endsWith("ch")) {
+ tmp = parseInt(tmp.slice(0, -2));
+ } else {
+ tmp = "";
+ }
+ } else { // "ltr" or other
+ tmp = parent.style.marginLeft;
+ if (tmp && tmp.endsWith("ch")) {
+ tmp = parseInt(tmp.slice(0, -2));
+ } else {
+ tmp = "";
+ }
+ }
+
+ if (Number.isInteger(tmp) && tmp > 0) {
+ obj.indentLevel += tmp / EvoEditor.TEXT_INDENT_SIZE;
+ }
+
+ if (parent.tagName == "UL" || parent.tagName == "OL")
+ obj.indentLevel++;
+
+ if (obj.bgColor === null && parent.style.backgroundColor)
+ obj.bgColor = parent.style.backgroundColor;
+
+ if (obj.bold === null && parent.tagName == "B")
+ obj.bold = true;
+
+ if (obj.italic === null && parent.tagName == "I")
+ obj.italic = true;
+
+ if (obj.underline === null && parent.tagName == "U")
+ obj.underline = true;
+
+ if (obj.strikethrough === null && (parent.tagName == "S" || parent.tagName == "STRIKE"))
+ obj.strikethrough = true;
+
+ if (obj.textAlign === null && parent.style.textAlign)
+ obj.textAlign = parent.style.textAlign;
+ }
+
+ value = obj.script;
+ if (force || value != EvoEditor.formattingState.script) {
+ EvoEditor.formattingState.script = value;
+ changes["script"] = value;
+ nchanges++;
+ }
+
+ value = obj.blockFormat === null ? EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH :
obj.blockFormat;
+ if (force || value != EvoEditor.formattingState.blockFormat) {
+ EvoEditor.formattingState.blockFormat = value;
+ changes["blockFormat"] = value;
+ nchanges++;
+ }
+
+ value = obj.fontSize === null ? 3 /* E_CONTENT_EDITOR_FONT_SIZE_NORMAL */ : obj.fontSize;
+ if (force || value != EvoEditor.formattingState.fontSize) {
+ EvoEditor.formattingState.fontSize = value;
+ changes["fontSize"] = value;
+ nchanges++;
+ }
+
+ value = obj.indentLevel;
+ if (force || value != EvoEditor.formattingState.indentLevel) {
+ EvoEditor.formattingState.indentLevel = value;
+ changes["indentLevel"] = value;
+ nchanges++;
+ }
+
+ value = obj.fgColor ? obj.fgColor : "";
+ if (force || value != EvoEditor.formattingState.fgColor) {
+ EvoEditor.formattingState.fgColor = value;
+ changes["fgColor"] = value;
+ nchanges++;
+ }
+
+ value = obj.bgColor ? obj.bgColor : "";
+ if (force || value != EvoEditor.formattingState.bgColor) {
+ EvoEditor.formattingState.bgColor = value;
+ changes["bgColor"] = value;
+ nchanges++;
+ }
+
+ value = obj.bold ? true : false;
+ if (value != EvoEditor.formattingState.bold) {
+ EvoEditor.formattingState.bold = value;
+ changes["bold"] = value;
+ nchanges++;
+ }
+
+ value = obj.italic ? true : false;
+ if (force || value != EvoEditor.formattingState.italic) {
+ EvoEditor.formattingState.italic = value;
+ changes["italic"] = value;
+ nchanges++;
+ }
+
+ value = obj.underline ? true : false;
+ if (force || value != EvoEditor.formattingState.underline) {
+ EvoEditor.formattingState.underline = value;
+ changes["underline"] = value;
+ nchanges++;
+ }
+
+ value = obj.strikethrough ? true : false;
+ if (force || value != EvoEditor.formattingState.strikethrough) {
+ EvoEditor.formattingState.strikethrough = value;
+ changes["strikethrough"] = value;
+ nchanges++;
+ }
+
+ value = obj.fontFamily ? obj.fontFamily : "";
+ // dequote the font name, if needed
+ if (value.length > 1 && value.charAt(0) == '\"' && value.charAt(value.length - 1) == '\"')
+ value = value.substr(1, value.length - 2);
+ if (force || value != EvoEditor.formattingState.fontFamily) {
+ EvoEditor.formattingState.fontFamily = value;
+ changes["fontFamily"] = (!document.body || window.getComputedStyle(document.body).fontFamily
== value) ? "" : value;
+ nchanges++;
+ }
+
+ tmp = (obj.textAlign ? obj.textAlign : "").toLowerCase();
+ if (tmp == "left" || tmp == "start")
+ value = EvoEditor.E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+ else if (tmp == "right")
+ value = EvoEditor.E_CONTENT_EDITOR_ALIGNMENT_RIGHT;
+ else if (tmp == "center")
+ value = EvoEditor.E_CONTENT_EDITOR_ALIGNMENT_CENTER;
+ else if (tmp == "justify")
+ value = EvoEditor.E_CONTENT_EDITOR_ALIGNMENT_JUSTIFY;
+ else if ((anchorElem ? window.getComputedStyle(anchorElem).direction : "").toLowerCase() == "rtl")
+ value = EvoEditor.E_CONTENT_EDITOR_ALIGNMENT_RIGHT;
+ else
+ value = EvoEditor.E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+
+ if (force || value != EvoEditor.formattingState.alignment) {
+ EvoEditor.formattingState.alignment = value;
+ changes["alignment"] = value;
+ nchanges++;
+ }
+
+ if (force) {
+ changes["forced"] = true;
+ nchanges++;
+ }
+
+ if (nchanges > 0)
+ window.webkit.messageHandlers.formattingChanged.postMessage(changes);
+}
+
+EvoEditor.IsBlockNode = function(node)
+{
+ if (!node || !node.tagName) {
+ return false;
+ }
+
+ return node.tagName == "BLOCKQUOTE" ||
+ node.tagName == "DIV" ||
+ node.tagName == "P" ||
+ node.tagName == "PRE" ||
+ node.tagName == "ADDRESS" ||
+ node.tagName == "H1" ||
+ node.tagName == "H2" ||
+ node.tagName == "H3" ||
+ node.tagName == "H4" ||
+ node.tagName == "H5" ||
+ node.tagName == "H6" ||
+ node.tagName == "TD" ||
+ node.tagName == "TH" ||
+ node.tagName == "UL" ||
+ node.tagName == "OL";
+}
+
+EvoEditor.foreachChildRecur = function(topParent, parent, firstChildIndex, lastChildIndex, traversar)
+{
+ if (!parent) {
+ return false;
+ }
+
+ if (firstChildIndex >= parent.children.length) {
+ return true;
+ }
+
+ var ii, child, next;
+
+ ii = lastChildIndex - firstChildIndex;
+ child = parent.children.item(firstChildIndex);
+
+ while (child && ii >= 0) {
+ next = child.nextElementSibling;
+
+ if (child.children.length > 0 &&
+ !traversar.flat &&
+ !EvoEditor.foreachChildRecur(topParent, child, 0, child.children.length - 1, traversar)) {
+ return false;
+ }
+
+ if (!traversar.onlyBlockElements || EvoEditor.IsBlockNode(child)) {
+ if (!traversar.exec(topParent, child)) {
+ return false;
+ }
+ }
+
+ child = next;
+ ii--;
+ }
+
+ return true;
+}
+
+/*
+ Traverses children of the 'parent', between the 'firstChildIndex' and
+ the 'lastChildIndex', where both indexes are meant inclusive.
+
+ The 'traversar' is an object, which should contain at least function:
+
+ bool exec(parent, element);
+
+ which does its work in the 'element' and returns true, when the traversar
+ should continue. The 'parent' is the one with which the funcion had been
+ called with. The 'traversar' can also contain properties:
+
+ bool flat;
+ bool onlyBlockElements;
+
+ the 'flat', if set to true, traverses only direct children of the parent,
+ otherwise it dives into the hierarchy;
+
+ the 'onlyBlockElements', if set to true, calls exec() only on elements,
+ which are block elements (as of EvoEditor.IsBlockNode()), otherwise it
+ is called for each element on the way.
+*/
+EvoEditor.ForeachChild = function(parent, firstChildIndex, lastChildIndex, traversar)
+{
+ return EvoEditor.foreachChildRecur(parent, parent, firstChildIndex, lastChildIndex, traversar);
+}
+
+EvoEditor.GetParentBlockNode = function(node)
+{
+ while (node && !EvoEditor.IsBlockNode(node) && node.tagName != "BODY") {
+ node = node.parentElement;
+ }
+
+ return node;
+}
+
+EvoEditor.GetCommonParent = function(firstNode, secondNode, longPath)
+{
+ if (!firstNode || !secondNode) {
+ return null;
+ }
+
+ if (firstNode.nodeType == firstNode.TEXT_NODE) {
+ firstNode = firstNode.parentElement;
+ }
+
+ if (secondNode.nodeType == secondNode.TEXT_NODE) {
+ secondNode = secondNode.parentElement;
+ }
+
+ if (!firstNode || !secondNode) {
+ return null;
+ }
+
+ if (firstNode === document.body || secondNode === document.body) {
+ return document.body;
+ }
+
+ var commonParent, secondParent;
+
+ for (commonParent = (longPath ? firstNode : firstNode.parentElement); commonParent; commonParent =
commonParent.parentElement) {
+ if (commonParent === document.body) {
+ break;
+ }
+
+ for (secondParent = (longPath ? secondNode : secondNode.parentElement); secondParent;
secondParent = secondParent.parentElement) {
+ if (secondParent === document.body) {
+ break;
+ }
+
+ if (secondParent === commonParent) {
+ return commonParent;
+ }
+ }
+ }
+
+ return document.body;
+}
+
+EvoEditor.GetDirectChild = function(parent, child)
+{
+ if (!parent || !child || parent === child) {
+ return null;
+ }
+
+ while (child && !(child.parentElement === parent)) {
+ child = child.parentElement;
+ }
+
+ return child;
+}
+
+EvoEditor.GetChildIndex = function(parent, child)
+{
+ if (!parent || !child)
+ return -1;
+
+ var ii;
+
+ for (ii = 0; ii < parent.children.length; ii++) {
+ if (child === parent.children.item(ii))
+ return ii;
+ }
+
+ return -1;
+}
+
+EvoEditor.ClaimAffectedContent = function(startNode, endNode, flags)
+{
+ var commonParent, startChild, endChild;
+ var firstChildIndex = -1, html = "", ii;
+ var withHtml = (flags & EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML) != 0;
+ var currentElemsArray = null;
+
+ if (!startNode) {
+ startNode = document.getSelection().anchorNode;
+ endNode = document.getSelection().focusNode;
+
+ if (!startNode) {
+ startNode = document.body;
+ }
+ }
+
+ if (!endNode) {
+ endNode = document.getSelection().focusNode;
+
+ if (!endNode)
+ endNode = startNode;
+ }
+
+ if ((flags & EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE) != 0) {
+ while (startNode && !(startNode === document.body)) {
+ if (EvoEditor.IsBlockNode(startNode)) {
+ break;
+ }
+
+ startNode = startNode.parentElement;
+ }
+ }
+
+ if (withHtml) {
+ var node = startNode;
+
+ // cannot store only part of the HTML in a TABLE, only whole, because restoring
+ // for example only "<td>text</td>" into a floating element drops the <td/>
+ if (!node.tagName)
+ node = node.parentElement;
+
+ if (node.tagName == "TH" || node.tagName == "TD" || node.tagName == "TR") {
+ node = EvoEditor.getParentElement("TABLE", node, true);
+ if (node)
+ startNode = node;
+ }
+
+ currentElemsArray = EvoEditor.RemoveCurrentElementAttr();
+ }
+
+ commonParent = EvoEditor.GetCommonParent(startNode, endNode, false);
+ startChild = EvoEditor.GetDirectChild(commonParent, startNode);
+ endChild = EvoEditor.GetDirectChild(commonParent, endNode);
+
+ for (ii = 0 ; ii < commonParent.children.length; ii++) {
+ var child = commonParent.children.item(ii);
+
+ if (firstChildIndex == -1) {
+ /* The selection can be made both from the top to the bottom and
+ from the bottom to the top, thus cover both cases. */
+ if (child === startChild) {
+ firstChildIndex = ii;
+ } else if (child === endChild) {
+ endChild = startChild;
+ startChild = child;
+ firstChildIndex = ii;
+ }
+ }
+
+ if (firstChildIndex != -1) {
+ if (withHtml) {
+ html += child.outerHTML;
+ }
+
+ if (child === endChild) {
+ ii++;
+ break;
+ }
+ }
+ }
+
+ var affected = {};
+
+ affected.path = EvoSelection.GetChildPath(document.body, commonParent);
+ affected.firstChildIndex = firstChildIndex;
+ affected.restChildrenCount = commonParent.children.length - ii;
+
+ if (withHtml) {
+ if (firstChildIndex == -1)
+ affected.html = commonParent.innerHTML;
+ else
+ affected.html = html;
+
+ EvoEditor.RestoreCurrentElementAttr(currentElemsArray);
+ }
+
+ return affected;
+}
+
+/* Calls EvoEditor.ForeachChild() on a content described by 'affected',
+ which is result of EvoEditor.ClaimAffectedContent(). */
+EvoEditor.ForeachChildInAffectedContent = function(affected, traversar)
+{
+ if (!affected || !traversar) {
+ throw "EvoEditor.ForeachChildInAffectedContent: No 'affected' or 'traversar'";
+ }
+
+ var parent, firstChildIndex, lastChildIndex;
+
+ parent = EvoSelection.FindElementByPath(document.body, affected.path);
+ if (!parent) {
+ throw "EvoEditor.ForeachChildInAffectedContent: Cannot find parent";
+ }
+
+ firstChildIndex = affected.firstChildIndex;
+ /* Cannot subtract one, when none left, because the child index is inclusive */
+ lastChildIndex = parent.children.length - affected.restChildrenCount + (affected.restChildrenCount ?
-1 : 0);
+
+ return EvoEditor.ForeachChild(parent, firstChildIndex, lastChildIndex, traversar);
+}
+
+EvoEditor.EmitContentChanged = function()
+{
+ if (window.webkit.messageHandlers.contentChanged)
+ window.webkit.messageHandlers.contentChanged.postMessage(null);
+}
+
+EvoEditor.StoreSelection = function()
+{
+ EvoEditor.storedSelection = EvoSelection.Store(document);
+}
+
+EvoEditor.RestoreSelection = function()
+{
+ if (EvoEditor.storedSelection) {
+ EvoSelection.Restore(document, EvoEditor.storedSelection);
+ EvoEditor.storedSelection = null;
+ }
+}
+
+EvoEditor.removeEmptyStyleAttribute = function(element)
+{
+ if (element && !element.style.length)
+ element.removeAttribute("style");
+}
+
+EvoEditor.applySetAlignment = function(record, isUndo)
+{
+ if (record.changes) {
+ var ii, parent, child;
+
+ parent = EvoSelection.FindElementByPath(document.body, record.path);
+ if (!parent) {
+ throw "EvoEditor.applySetAlignment: Cannot find parent at path " + record.path;
+ }
+
+ for (ii = 0; ii < record.changes.length; ii++) {
+ var change = record.changes[isUndo ? (record.changes.length - ii - 1) : ii];
+
+ child = EvoSelection.FindElementByPath(parent, change.path);
+ if (!child) {
+ throw "EvoEditor.applySetAlignment: Cannot find child";
+ }
+
+ if (isUndo) {
+ child.style.textAlign = change.before;
+ } else if ((record.applyValueAfter == "left" && child.style.direction != "rtl" &&
window.getComputedStyle(child).direction != "rtl") ||
+ (record.applyValueAfter == "right" && (child.style.direction == "rtl" ||
window.getComputedStyle(child).direction == "rtl"))) {
+ child.style.textAlign = "";
+ } else {
+ child.style.textAlign = record.applyValueAfter;
+ }
+
+ EvoEditor.removeEmptyStyleAttribute(child);
+ }
+ }
+}
+
+EvoEditor.SetAlignment = function(alignment)
+{
+ var traversar = {
+ record : null,
+ toSet : null,
+ anyChanged : false,
+
+ flat : false,
+ onlyBlockElements : true,
+
+ exec : function(parent, element) {
+ if (window.getComputedStyle(element, null).textAlign != traversar.toSet) {
+ if (traversar.record) {
+ if (!traversar.record.changes)
+ traversar.record.changes = [];
+
+ var change = {};
+
+ change.path = EvoSelection.GetChildPath(parent, element);
+ change.before = element.style.textAlign;
+
+ traversar.record.changes[traversar.record.changes.length] = change;
+ }
+
+ traversar.anyChanged = true;
+
+ if ((traversar.toSet == "left" && element.style.direction != "rtl" &&
window.getComputedStyle(element).direction != "rtl") ||
+ (traversar.toSet == "right" && (element.style.direction == "rtl" ||
window.getComputedStyle(element).direction == "rtl"))) {
+ element.style.textAlign = "";
+ } else {
+ element.style.textAlign = traversar.toSet;
+ }
+
+ EvoEditor.removeEmptyStyleAttribute(element);
+ }
+
+ return true;
+ }
+ };
+
+ var affected = EvoEditor.ClaimAffectedContent(null, null,
EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE);
+
+ switch (alignment) {
+ case EvoEditor.E_CONTENT_EDITOR_ALIGNMENT_NONE:
+ traversar.toSet = "";
+ break;
+ case EvoEditor.E_CONTENT_EDITOR_ALIGNMENT_LEFT:
+ traversar.toSet = "left";
+ break;
+ case EvoEditor.E_CONTENT_EDITOR_ALIGNMENT_CENTER:
+ traversar.toSet = "center";
+ break;
+ case EvoEditor.E_CONTENT_EDITOR_ALIGNMENT_RIGHT:
+ traversar.toSet = "right";
+ break;
+ case EvoEditor.E_CONTENT_EDITOR_ALIGNMENT_JUSTIFY:
+ traversar.toSet = "justify";
+ break;
+ default:
+ throw "EvoEditor.SetAlignment: Unknown alignment value: '" + alignment + "'";
+ }
+
+ traversar.record = EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "setAlignment", null,
null, EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE);
+
+ try {
+ EvoEditor.ForeachChildInAffectedContent(affected, traversar);
+
+ if (traversar.record) {
+ traversar.record.applyValueAfter = traversar.toSet;
+ traversar.record.apply = EvoEditor.applySetAlignment;
+ }
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "setAlignment");
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+
+ if (traversar.anyChanged)
+ EvoEditor.EmitContentChanged();
+ }
+}
+
+EvoEditor.storeAttributes = function(element)
+{
+ if (!element || !element.attributes.length)
+ return null;
+
+ var attributes = [], ii;
+
+ for (ii = 0; ii < element.attributes.length; ii++) {
+ var attr = {
+ name : element.attributes.item(ii).name,
+ value : element.attributes.item(ii).value
+ };
+
+ attributes[attributes.length] = attr;
+ }
+
+ return attributes;
+}
+
+EvoEditor.restoreAttributes = function(element, attributes)
+{
+ if (!element)
+ return;
+
+ while (element.attributes.length) {
+ element.removeAttribute(element.attributes.item(element.attributes.length - 1).name);
+ }
+
+ if (!attributes)
+ return;
+
+ var ii;
+
+ for (ii = 0; ii < attributes.length; ii++) {
+ element.setAttribute(attributes[ii].name, attributes[ii].value);
+ }
+}
+
+EvoEditor.storeElement = function(element)
+{
+ if (!element)
+ return null;
+
+ var elementRecord = {
+ tagName : element.tagName,
+ attributes : EvoEditor.storeAttributes(element)
+ };
+
+ return elementRecord;
+}
+
+EvoEditor.restoreElement = function(parentElement, beforeElement, tagName, attributes)
+{
+ if (!parentElement)
+ throw "EvoEditor.restoreElement: parentElement cannot be null";
+
+ if (!tagName)
+ throw "EvoEditor.restoreElement: tagName cannot be null";
+
+ var node;
+
+ node = parentElement.ownerDocument.createElement(tagName);
+
+ EvoEditor.restoreAttributes(node, attributes);
+
+ parentElement.insertBefore(node, beforeElement);
+
+ return node;
+}
+
+EvoEditor.moveChildren = function(fromElement, toElement, beforeElement, prepareParent, selectionUpdater)
+{
+ if (!fromElement)
+ throw "EvoEditor.moveChildren: fromElement cannot be null";
+
+ if (beforeElement && toElement && !(beforeElement.parentElement === toElement))
+ throw "EvoEditor.moveChildren: beforeElement is not a direct child of toElement";
+
+ var node;
+
+ for (node = toElement; node; node = node.parentElement) {
+ if (node === fromElement)
+ throw "EvoEditor.moveChildren: toElement cannot be child of fromElement";
+ }
+
+ var firstElement = toElement;
+
+ while (fromElement.firstChild) {
+ if (prepareParent && fromElement.firstChild.tagName && fromElement.firstChild.tagName ==
"LI") {
+ var toParent = prepareParent.exec();
+
+ if (toElement) {
+ toElement.parentElement.insertBefore(toParent, toElement.nextElementSibling);
+ }
+
+ if (!firstElement) {
+ firstElement = toParent;
+ }
+
+ var li = fromElement.firstChild, replacedBy = li.firstChild;
+
+ while (li.firstChild) {
+ toParent.append(li.firstChild);
+ }
+
+ if (selectionUpdater)
+ selectionUpdater.beforeRemove(fromElement.firstChild);
+
+ fromElement.removeChild(fromElement.firstChild);
+
+ if (selectionUpdater)
+ selectionUpdater.afterRemove(replacedBy);
+ } else {
+ if (!toElement && prepareParent) {
+ toElement = prepareParent.exec();
+
+ // trying to move other than LI into UL/OL, thus do not enclose it into LI
+ if (prepareParent.tagName == "LI" && (fromElement.tagName == "UL" ||
fromElement.tagName == "OL")) {
+ var toParent = toElement.parentElement;
+ toParent.removeChild(toElement);
+ toElement = toParent;
+ }
+ }
+
+ if (!firstElement) {
+ firstElement = toElement;
+ }
+
+ toElement.insertBefore(fromElement.firstChild, beforeElement);
+ }
+ }
+
+ return firstElement;
+}
+
+EvoEditor.renameElement = function(element, tagName, attributes, targetElement, selectionUpdater)
+{
+ var prepareParent = {
+ element : element,
+ tagName : tagName,
+ attributes : attributes,
+ targetElement : targetElement,
+
+ exec : function() {
+ if (this.targetElement)
+ return EvoEditor.restoreElement(this.targetElement, null, this.tagName,
this.attributes);
+ else
+ return EvoEditor.restoreElement(this.element.parentElement, this.element,
this.tagName, this.attributes);
+ }
+ };
+ var newElement;
+
+ newElement = EvoEditor.moveChildren(element, null, null, prepareParent, selectionUpdater);
+
+ element.remove();
+
+ return newElement;
+}
+
+EvoEditor.getBlockquoteLevel = function(node)
+{
+ if (!node || node.tagName == "BODY")
+ return 0;
+
+ var blockquoteLevel = 0, parent = node;
+
+ while (parent && parent.tagName != "BODY") {
+ if (parent.tagName == "BLOCKQUOTE")
+ blockquoteLevel++;
+
+ parent = parent.parentElement;
+ }
+
+ return blockquoteLevel;
+}
+
+EvoEditor.SetBlockFormat = function(format)
+{
+ var traversar = {
+ toSet : null,
+ createParent : null,
+ firstLI : true,
+ targetElement : null,
+ selectionUpdater : null,
+
+ flat : true,
+ onlyBlockElements : true,
+
+ exec : function(parent, element) {
+ var newElement;
+
+ if (this.toSet.tagName != "LI" && (element.tagName == "UL" || element.tagName ==
"OL")) {
+ var affected = [];
+
+ if (!EvoEditor.allChildrenInSelection(element, true, affected)) {
+ var elemParent = element.parentElement, insBefore, jj;
+
+ if (affected.length > 0 && !(affected[0] ===
element.firstElementChild)) {
+ insBefore = EvoEditor.splitList(element, 1, affected);
+ } else {
+ insBefore = element;
+ }
+
+ for (jj = 0; jj < affected.length; jj++) {
+ EvoEditor.insertListChildBefore(affected[jj],
this.toSet.tagName, insBefore ? insBefore.parentElement : elemParent, insBefore, this.selectionUpdater);
+ }
+
+ if (!element.childElementCount) {
+ this.selectionUpdater.beforeRemove(element);
+
+ element.remove();
+
+ this.selectionUpdater.afterRemove(insBefore ?
insBefore.previousElementSibling : elemParent.lastElementChild);
+ }
+
+ return true;
+ }
+ }
+
+ if (this.firstLI) {
+ if (this.createParent) {
+ this.targetElement = EvoEditor.restoreElement(parent, element,
this.createParent.tagName, this.createParent.attributes);
+ }
+
+ this.firstLI = false;
+ }
+
+ newElement = EvoEditor.renameElement(element, this.toSet.tagName,
this.toSet.attributes, this.targetElement, this.selectionUpdater);
+
+ if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT && (this.toSet.tagName == "DIV" ||
this.toSet.tagName == "PRE")) {
+ var blockquoteLevel = EvoEditor.getBlockquoteLevel(newElement);
+
+ if (blockquoteLevel > 0) {
+ var width = -1;
+
+ if (this.toSet.tagName == "DIV" && blockquoteLevel * 2 <
EvoEditor.NORMAL_PARAGRAPH_WIDTH)
+ width = EvoEditor.NORMAL_PARAGRAPH_WIDTH - blockquoteLevel *
2;
+
+ EvoEditor.quoteParagraph(newElement, blockquoteLevel, width);
+ }
+ }
+
+ if (this.selectionUpdater) {
+ this.selectionUpdater.beforeRemove(element);
+ this.selectionUpdater.afterRemove(newElement);
+ }
+
+ return true;
+ }
+ };
+
+ traversar.selectionUpdater = EvoSelection.CreateUpdaterObject();
+
+ var affected = EvoEditor.ClaimAffectedContent(null, null,
EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE);
+
+ switch (format) {
+ case EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH:
+ traversar.toSet = { tagName : "DIV" };
+ break;
+ case EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_PRE:
+ traversar.toSet = { tagName : "PRE" };
+ break;
+ case EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_ADDRESS:
+ traversar.toSet = { tagName : "ADDRESS" };
+ break;
+ case EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_H1:
+ traversar.toSet = { tagName : "H1" };
+ break;
+ case EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_H2:
+ traversar.toSet = { tagName : "H2" };
+ break;
+ case EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_H3:
+ traversar.toSet = { tagName : "H3" };
+ break;
+ case EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_H4:
+ traversar.toSet = { tagName : "H4" };
+ break;
+ case EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_H5:
+ traversar.toSet = { tagName : "H5" };
+ break;
+ case EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_H6:
+ traversar.toSet = { tagName : "H6" };
+ break;
+ case EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_UNORDERED_LIST:
+ traversar.toSet = { tagName : "LI" };
+ traversar.createParent = { tagName : "UL" };
+ break;
+ case EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST:
+ traversar.toSet = { tagName : "LI" };
+ traversar.createParent = { tagName : "OL" };
+ break;
+ case EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ROMAN:
+ traversar.toSet = { tagName : "LI" };
+ traversar.createParent = { tagName : "OL", attributes : [ { name : "type", value : "I" } ] };
+ break;
+ case EvoEditor.E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ALPHA:
+ traversar.toSet = { tagName : "LI" };
+ traversar.createParent = { tagName : "OL", attributes : [ { name : "type", value : "A" } ] };
+ break;
+ default:
+ throw "EvoEditor.SetBlockFormat: Unknown block format value: '" + format + "'";
+ }
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "setBlockFormat", null, null,
+ EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE | EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+
+ try {
+ EvoEditor.ForeachChildInAffectedContent(affected, traversar);
+
+ traversar.selectionUpdater.restore();
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "setBlockFormat");
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+}
+
+EvoEditor.allChildrenInSelection = function(element, allowPartial, affected)
+{
+ if (!element || !element.firstChild)
+ return false;
+
+ var selection = document.getSelection(), all;
+
+ all = selection.containsNode(element.firstElementChild, allowPartial) &&
+ selection.containsNode(element.lastElementChild, allowPartial);
+
+ var node;
+
+ affected.length = 0;
+
+ for (node = element.firstElementChild; node; node = node.nextElementSibling) {
+ if (all || selection.containsNode(node, allowPartial))
+ affected[affected.length] = node;
+ }
+
+ return all;
+}
+
+EvoEditor.splitList = function(element, nParents, onlyAffected)
+{
+ var parent, from = null;
+
+ if (onlyAffected && onlyAffected.length)
+ from = onlyAffected[onlyAffected.length - 1].nextElementSibling;
+
+ if (!from)
+ from = element.nextElementSibling;
+
+ if (nParents == -1) {
+ nParents = 0;
+
+ for (parent = from; parent && parent.tagName != "BODY"; parent = parent.parentElement) {
+ nParents++;
+ }
+ }
+
+ var nextFrom, clone;
+
+ parent = from ? from.parentElement : element.parentElement;
+
+ if (!from && parent) {
+ from = parent.nextElementSibling;
+ nextFrom = from;
+ nParents--;
+ parent = parent.parentElement;
+ }
+
+ while (nParents > 0 && parent && parent.tagName != "HTML") {
+ nParents--;
+ nextFrom = null;
+
+ if (from) {
+ clone = from.parentElement.cloneNode(false);
+ from.parentElement.parentElement.insertBefore(clone,
from.parentElement.nextElementSibling);
+
+ nextFrom = clone;
+
+ while (from.nextElementSibling) {
+ clone.appendChild(from.nextElementSibling);
+ }
+
+ clone.insertBefore(from, clone.firstElementChild);
+ }
+
+ from = nextFrom;
+ parent = parent.parentElement;
+ }
+
+ if (nextFrom)
+ return nextFrom;
+
+ return parent.nextElementSibling;
+}
+
+EvoEditor.insertListChildBefore = function(child, tagName, parent, insBefore, selectionUpdater)
+{
+ if (child.tagName == "LI") {
+ var node = document.createElement(tagName);
+
+ while(child.firstChild)
+ node.appendChild(child.firstChild);
+
+ parent.insertBefore(node, insBefore);
+
+ if (selectionUpdater)
+ selectionUpdater.beforeRemove(child);
+
+ child.remove();
+
+ if (selectionUpdater)
+ selectionUpdater.afterRemove(node);
+ } else {
+ parent.insertBefore(child, insBefore);
+ }
+}
+
+EvoEditor.applyIndent = function(record, isUndo)
+{
+ if (record.changes) {
+ var ii, parent, child;
+
+ parent = EvoSelection.FindElementByPath(document.body, record.path);
+ if (!parent) {
+ throw "EvoEditor.applyIndent: Cannot find parent at path " + record.path;
+ }
+
+ for (ii = 0; ii < record.changes.length; ii++) {
+ var change = record.changes[isUndo ? (record.changes.length - ii - 1) : ii];
+
+ child = EvoSelection.FindElementByPath(change.pathIsFromBody ? document.body :
parent, change.path);
+ if (!child) {
+ throw "EvoEditor.applyIndent: Cannot find child";
+ }
+
+ if (change.isList) {
+ EvoUndoRedo.RestoreChildren(change, child, isUndo);
+ continue;
+ }
+
+ if (isUndo) {
+ child.style.marginLeft = change.beforeMarginLeft;
+ child.style.marginRight = change.beforeMarginRight;
+ child.style.width = change.beforeWidth;
+ } else {
+ child.style.marginLeft = change.afterMarginLeft;
+ child.style.marginRight = change.afterMarginRight;
+ child.style.width = change.afterWidth;
+ }
+
+ EvoEditor.removeEmptyStyleAttribute(child);
+ }
+ }
+}
+
+EvoEditor.Indent = function(increment)
+{
+ var traversar = {
+ record : null,
+ selectionUpdater : null,
+ increment : increment,
+
+ flat : true,
+ onlyBlockElements : true,
+
+ exec : function(parent, element) {
+ var change = null, isList = element.tagName == "UL" || element.tagName == "OL";
+ var isNested = isList && (element.parentElement.tagName == "UL" ||
element.parentElement.tagName == "OL");
+
+ if (traversar.record) {
+ if (!traversar.record.changes)
+ traversar.record.changes = [];
+
+ change = {};
+
+ change.pathIsFromBody = false;
+
+ if (isList) {
+ change.isList = isList;
+ change.path = EvoSelection.GetChildPath(parent, element);
+ } else {
+ change.path = EvoSelection.GetChildPath(parent, element);
+ change.beforeMarginLeft = element.style.marginLeft;
+ change.beforeMarginRight = element.style.marginRight;
+ change.beforeWidth = element.style.width;
+ }
+
+ traversar.record.changes[traversar.record.changes.length] = change;
+ }
+
+ if (isList) {
+ var elemParent = null, all, affected = [], jj;
+
+ all = EvoEditor.allChildrenInSelection(element, true, affected);
+
+ if (this.increment) {
+ var clone;
+
+ clone = element.cloneNode(false);
+
+ if (all) {
+ if (change) {
+ var childIndex =
EvoEditor.GetChildIndex(element.parentElement, element);
+ EvoUndoRedo.BackupChildrenBefore(change,
element.parentElement, childIndex, childIndex);
+ change.path = EvoSelection.GetChildPath(parent,
element.parentElement);
+ }
+
+ element.parentElement.insertBefore(clone, element);
+ clone.appendChild(element);
+
+ if (change)
+ EvoUndoRedo.BackupChildrenAfter(change,
clone.parentElement);
+ } else if (affected.length > 0) {
+ if (change) {
+ EvoUndoRedo.BackupChildrenBefore(change, element,
+ EvoEditor.GetChildIndex(element, affected[0]),
+ EvoEditor.GetChildIndex(element,
affected[affected.length - 1]));
+ }
+
+ element.insertBefore(clone, affected[0]);
+
+ for (jj = 0; jj < affected.length; jj++) {
+ clone.appendChild(affected[jj]);
+ }
+
+ if (change)
+ EvoUndoRedo.BackupChildrenAfter(change, element);
+ }
+ } else {
+ var insBefore = null;
+
+ elemParent = element.parentElement;
+
+ // decrease indent in nested lists of the same type will merge items
into one list
+ if (isNested && elemParent.tagName == element.tagName &&
+ elemParent.getAttribute("type") == element.getAttribute("type")) {
+ if (change) {
+ var childIndex = EvoEditor.GetChildIndex(elemParent,
element);
+ EvoUndoRedo.BackupChildrenBefore(change, elemParent,
childIndex, childIndex);
+ change.path = EvoSelection.GetChildPath(parent,
elemParent);
+ }
+
+ if (!all && affected.length > 0 && !(affected[0] ===
element.firstElementChild)) {
+ insBefore = EvoEditor.splitList(element, 1, affected);
+ } else {
+ insBefore = element;
+ }
+
+ for (jj = 0; jj < affected.length; jj++) {
+ elemParent.insertBefore(affected[jj], insBefore);
+ }
+
+ if (!element.childElementCount) {
+ this.selectionUpdater.beforeRemove(element);
+
+ element.remove();
+
+ this.selectionUpdater.afterRemove(affected[0]);
+ }
+
+ if (change)
+ EvoUndoRedo.BackupChildrenAfter(change, elemParent);
+ } else {
+ var tmpElement = element;
+
+ if (isNested) {
+ tmpElement = elemParent;
+ elemParent = elemParent.parentElement;
+ }
+
+ if (change) {
+ var childIndex = EvoEditor.GetChildIndex(elemParent,
tmpElement);
+ EvoUndoRedo.BackupChildrenBefore(change, elemParent,
childIndex, childIndex);
+ if (isNested) {
+ change.pathIsFromBody = true;
+ change.path =
EvoSelection.GetChildPath(document.body, elemParent);
+ } else {
+ change.path =
EvoSelection.GetChildPath(parent, elemParent);
+ }
+ }
+
+ if (isNested) {
+ var clone;
+
+ insBefore = EvoEditor.splitList(element, 1, affected);
+
+ clone = element.cloneNode(false);
+ if (insBefore)
+ insBefore.parentElement.insertBefore(clone,
insBefore);
+ else
+ elemParent.insertBefore(clone, insBefore);
+
+ for (jj = 0; jj < affected.length; jj++) {
+ clone.appendChild(affected[jj]);
+ }
+ } else {
+ if (!all && affected.length > 0 &&
affected[affected.length - 1] === element.lastElementChild) {
+ insBefore = element.nextElementSibling;
+ } else if (!all && affected.length > 0 &&
!(affected[0] === element.firstElementChild)) {
+ insBefore = EvoEditor.splitList(element, 1,
affected);
+ } else {
+ insBefore = element;
+ }
+
+ for (jj = 0; jj < affected.length; jj++) {
+ EvoEditor.insertListChildBefore(affected[jj],
"DIV", insBefore ? insBefore.parentElement : elemParent, insBefore, this.selectionUpdater);
+ }
+ }
+
+ while (element && !(element === elemParent) &&
!element.childElementCount) {
+ tmpElement = element.parentElement;
+
+ this.selectionUpdater.beforeRemove(element);
+
+ element.remove();
+
+ this.selectionUpdater.afterRemove(insBefore ?
insBefore.previousElementSibling : elemParent.lastElementChild);
+
+ element = tmpElement;
+ }
+
+ if (change)
+ EvoUndoRedo.BackupChildrenAfter(change, elemParent);
+ }
+ }
+ } else {
+ var currValue = null, dir, width;
+
+ dir = window.getComputedStyle(element).direction;
+
+ if (dir == "rtl") {
+ if (element.style.marginRight.endsWith("ch"))
+ currValue = element.style.marginRight;
+ } else { // "ltr" or other
+ if (element.style.marginLeft.endsWith("ch"))
+ currValue = element.style.marginLeft;
+ }
+
+ if (!currValue) {
+ currValue = 0;
+ } else {
+ currValue = parseInt(currValue.slice(0, -2));
+ if (!Number.isInteger(currValue))
+ currValue = 0;
+ }
+
+ width = 0;
+ if (element.style.width.endsWith("ch")) {
+ width = parseInt(element.style.width.slice(0, -2));
+ if (!Number.isInteger(width))
+ width = 0;
+ }
+
+ if (traversar.increment) {
+ if (width && width - EvoEditor.TEXT_INDENT_SIZE > 0)
+ width = width - EvoEditor.TEXT_INDENT_SIZE;
+ currValue = (currValue + EvoEditor.TEXT_INDENT_SIZE) + "ch";
+ } else if (currValue > EvoEditor.TEXT_INDENT_SIZE) {
+ if (width)
+ width = width + EvoEditor.TEXT_INDENT_SIZE;
+ currValue = (currValue - EvoEditor.TEXT_INDENT_SIZE) + "ch";
+ } else {
+ if (width)
+ width = width + currValue;
+ currValue = "";
+ }
+
+ if (dir == "rtl") {
+ element.style.marginRight = currValue;
+ } else { // "ltr" or other
+ element.style.marginLeft = currValue;
+ }
+
+ if (width)
+ element.style.width = width + "ch";
+
+ if (change) {
+ change.afterMarginLeft = element.style.marginLeft;
+ change.afterMarginRight = element.style.marginRight;
+ change.afterWidth = element.style.width;
+ }
+
+ EvoEditor.removeEmptyStyleAttribute(element);
+ }
+
+ return true;
+ }
+ };
+
+ var affected = EvoEditor.ClaimAffectedContent(null, null,
EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE);
+
+ traversar.record = EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, increment ? "Indent" :
"Outdent", null, null, EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE);
+ traversar.selectionUpdater = EvoSelection.CreateUpdaterObject();
+
+ try {
+ EvoEditor.ForeachChildInAffectedContent(affected, traversar);
+
+ if (traversar.record) {
+ traversar.record.apply = EvoEditor.applyIndent;
+ }
+
+ traversar.selectionUpdater.restore();
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, increment ? "Indent" : "Outdent");
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+}
+
+EvoEditor.applyDivNormalize = function(record, isUndo)
+{
+ var element = EvoSelection.FindElementByPath(document.body, record.path);
+
+ if (!element)
+ throw "EvoEditor.applyDivNormalize: Path not found";
+
+ var value;
+
+ if (isUndo)
+ value = record.beforeValue;
+ else
+ value = record.afterValue;
+
+ if (record.isWidthStyle) {
+ element.style.width = value;
+ EvoEditor.removeEmptyStyleAttribute(element);
+ } else {
+ element.innerHTML = value;
+ }
+}
+
+EvoEditor.correctParagraphsAfterInsertContent = function(opType)
+{
+ var node, list, ii;
+
+ list = document.body.getElementsByTagName("DIV");
+
+ for (ii = 0; ii < list.length; ii++) {
+ node = list[ii];
+
+ if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT) {
+ var beforeValue = node.style.width;
+ EvoEditor.maybeUpdateParagraphWidth(node);
+
+ if (node.style.width != beforeValue) {
+ var record = EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, opType +
"::divWidths", node, node, EvoEditor.CLAIM_CONTENT_FLAG_NONE);
+ try {
+ if (record) {
+ record.path = EvoSelection.GetChildPath(document.body, node);
+ record.beforeValue = beforeValue;
+ record.afterValue = node.style.width;
+ record.isWidthStyle = true;
+ record.apply = EvoEditor.applyDivNormalize;
+ }
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, opType +
"::divWidths");
+ }
+ }
+ }
+
+ if (!node.firstChild) {
+ var record = EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, opType +
"::divBR", node, node, EvoEditor.CLAIM_CONTENT_FLAG_NONE);
+ try {
+ beforeValue = node.innerHTML;
+ node.appendChild(document.createElement("BR"));
+
+ if (record) {
+ record.path = EvoSelection.GetChildPath(document.body, node);
+ record.beforeValue = beforeValue;
+ record.afterValue = node.innerHTML;
+ record.apply = EvoEditor.applyDivNormalize;
+ }
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, opType + "::divBR");
+ }
+ }
+ }
+}
+
+EvoEditor.InsertHTML = function(opType, html)
+{
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_GROUP, opType);
+ try {
+ document.execCommand("insertHTML", false, html);
+
+ var node, list, ii;
+
+ list = document.body.getElementsByTagName("BLOCKQUOTE");
+
+ for (ii = 0; ii < list.length; ii++) {
+ node = list[ii];
+
+ EvoEditor.setAttributeWithUndoRedo("InsertHTML::fixBlockquote", node, "class", null);
+ EvoEditor.setAttributeWithUndoRedo("InsertHTML::fixBlockquote", node, "style", null);
+ }
+
+ EvoEditor.correctParagraphsAfterInsertContent(opType);
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_GROUP, opType);
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+}
+
+EvoEditor.InsertText = function(opType, text)
+{
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_GROUP, opType);
+ try {
+ document.execCommand("insertText", false, text);
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_GROUP, opType);
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+}
+
+EvoEditor.SetBodyAttribute = function(name, value)
+{
+ EvoEditor.setAttributeWithUndoRedo("SetBodyAttribute", document.body, name, value);
+}
+
+EvoEditor.applySetBodyFontName = function(record, isUndo)
+{
+ EvoEditor.UpdateStyleSheet("x-evo-body-fontname", isUndo ? record.beforeCSS : record.afterCSS);
+
+ if (record.beforeStyle != record.afterStyle) {
+ document.body.style.fontFamily = isUndo ? record.beforeStyle : record.afterStyle;
+ EvoEditor.removeEmptyStyleAttribute(body.document);
+ }
+}
+
+EvoEditor.SetBodyFontName = function(name)
+{
+ var record;
+
+ record = EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "setBodyFontName", document.body,
document.body, EvoEditor.CLAIM_CONTENT_FLAG_NONE);
+
+ try {
+ var beforeCSS, css, beforeStyle;
+
+ if (name)
+ css = "body { font-family: " + name + "; }";
+ else
+ css = null;
+
+ beforeStyle = document.body.style.fontFamily;
+ beforeCSS = EvoEditor.UpdateStyleSheet("x-evo-body-fontname", css);
+
+ if (name != document.body.style.fontFamily)
+ document.body.style.fontFamily = name ? name : "";
+
+ if (record) {
+ record.apply = EvoEditor.applySetBodyFontName;
+ record.beforeCSS = beforeCSS;
+ record.afterCSS = css;
+ record.beforeStyle = beforeStyle;
+ record.afterStyle = document.body.style.fontFamily;
+
+ if (record.beforeCSS == record.afterCSS && record.beforeStyle == record.afterStyle)
+ record.ignore = true;
+ }
+
+ EvoEditor.removeEmptyStyleAttribute(document.body);
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "setBodyFontName");
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_YES);
+
+ if (!record || !record.ignore)
+ EvoEditor.EmitContentChanged();
+ }
+}
+
+EvoEditor.emptyParagraphAsHtml = function()
+{
+ if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT) {
+ return "<div style=\"width:" + EvoEditor.NORMAL_PARAGRAPH_WIDTH + "ch;\"><br></div>";
+ } else {
+ return "<div><br></div>";
+ }
+}
+
+EvoEditor.initializeContent = function()
+{
+ // for backward compatibility
+ document.execCommand("StyleWithCSS", false, "false");
+
+ if (document.body) {
+ // attach on body, thus it runs before EvoUndoRedo.beforeInputCb()
+ document.body.onbeforeinput = EvoEditor.beforeInputCb;
+
+ if (!document.body.firstChild) {
+ EvoUndoRedo.Disable();
+ try {
+ document.body.innerHTML = EvoEditor.emptyParagraphAsHtml();
+ } finally {
+ EvoUndoRedo.Enable();
+ }
+ }
+
+ // make sure there is a selection
+ if (!document.getSelection().anchorNode || document.getSelection().anchorNode.tagName ==
"HTML") {
+ document.getSelection().setPosition(document.body.firstChild ?
document.body.firstChild : document.body, 0);
+ }
+ }
+}
+
+EvoEditor.getNextNodeInHierarchy = function(node, upToNode)
+{
+ if (!node)
+ return null;
+
+ var next;
+
+ next = node.firstChild;
+
+ if (!next)
+ next = node.nextSibling;
+
+ if (!next) {
+ next = node.parentElement;
+
+ if (next === upToNode || next === document.body)
+ next = null;
+
+ while (next) {
+ if (next.nextSibling) {
+ next = next.nextSibling;
+ break;
+ } else {
+ next = next.parentElement;
+
+ if (next === upToNode || next === document.body)
+ next = null;
+ }
+ }
+ }
+
+ return next;
+}
+
+// it already knows the line is too long; the node is where the text length exceeded
+EvoEditor.quoteParagraphWrap = function(node, lineLength, wrapWidth, prefixHtml)
+{
+ if (node.nodeType == node.ELEMENT_NODE) {
+ var br = document.createElement("BR");
+ br.className = "-x-evo-wrap-br";
+
+ node.insertAdjacentElement("beforebegin", br);
+ node.insertAdjacentHTML("beforebegin", prefixHtml);
+
+ return node.innerText.length;
+ }
+
+ var words = node.nodeValue.split(" "), ii, offset = 0, inc;
+
+ for (ii = 0; ii < words.length; ii++) {
+ var word = words[ii], wordLen = word.length;
+
+ if (lineLength + wordLen > wrapWidth) {
+ if (offset > 0) {
+ node.splitText(offset - 1);
+ node = node.nextSibling;
+
+ // erase the space at the end of the line
+ node.splitText(1);
+ var next = node.nextSibling;
+ node.remove();
+ node = next;
+
+ var br = document.createElement("BR");
+ br.className = "-x-evo-wrap-br";
+
+ node.parentElement.insertBefore(br, node);
+ br.insertAdjacentHTML("afterend", prefixHtml);
+ }
+
+ offset = 0;
+ lineLength = 0;
+ }
+
+ inc = wordLen + (ii + 1 < words.length ? 1 : 0);
+
+ lineLength += inc;
+ offset += inc;
+ }
+
+ return lineLength;
+}
+
+EvoEditor.getBlockquotePrefixHtml = function(blockquoteLevel)
+{
+ var prefixHtml;
+
+ prefixHtml = "<span class='-x-evo-quote-character'>> </span>".repeat(blockquoteLevel);
+ prefixHtml = "<span class='-x-evo-quoted'>" + prefixHtml + "</span>";
+
+ return prefixHtml;
+}
+
+EvoEditor.quoteParagraph = function(paragraph, blockquoteLevel, wrapWidth)
+{
+ if (!paragraph || !(blockquoteLevel > 0))
+ return;
+
+ EvoEditor.removeQuoteMarks(paragraph);
+
+ if (paragraph.tagName == "PRE")
+ wrapWidth = -1;
+
+ var node = paragraph.firstChild, next, lineLength = 0;
+ var prefixHtml = EvoEditor.getBlockquotePrefixHtml(blockquoteLevel);
+
+ while (node) {
+ next = EvoEditor.getNextNodeInHierarchy(node, paragraph);
+
+ if (node.nodeType == node.TEXT_NODE) {
+ if (wrapWidth > 0 && lineLength + node.nodeValue.length > wrapWidth) {
+ lineLength = EvoEditor.quoteParagraphWrap(node, lineLength, wrapWidth,
prefixHtml);
+ } else {
+ lineLength += node.nodeValue.length;
+ }
+ } else if (node.nodeType == node.ELEMENT_NODE) {
+ if (node.tagName == "BR") {
+ if (node.classList.contains("-x-evo-wrap-br")) {
+ node.remove();
+ } else {
+ if (node.parentElement.childNodes.length != 1)
+ node.insertAdjacentHTML("afterend", prefixHtml);
+
+ lineLength = 0;
+ }
+ } else if (node.tagName == "A") {
+ var len = node.innerText.length;
+
+ if (wrapWidth > 0 && lineLength + len > wrapWidth && (!next || next.tagName
!= "BR")) {
+ lineLength = EvoEditor.quoteParagraphWrap(node, lineLength,
wrapWidth, prefixHtml);
+ } else {
+ lineLength += len;
+ }
+
+ // do not traverse into the anchor element
+ next = node.nextSibling;
+ }
+ }
+
+ node = next;
+ }
+
+ paragraph.insertAdjacentHTML("afterbegin", prefixHtml);
+}
+
+EvoEditor.reBlockquotePlainText = function(plainText, usePreTag)
+{
+ var lines = plainText.replace(/\&/g, "&").split("\n"), ii, html = "", level = 0;
+
+ for (ii = 0; ii < lines.length; ii++) {
+ var line = lines[ii], newLevel = 0, skip = 0;
+
+ // Conversion to Plain Text adds empty line at the end
+ if (ii + 1 >= lines.length && !line[0])
+ break;
+
+ while (line[skip] == '>') {
+ newLevel++;
+ skip++;
+ if (line[skip] == ' ')
+ skip++;
+ }
+
+ while (newLevel > level) {
+ html += "<blockquote type='cite'>";
+ level++;
+ }
+
+ while (newLevel < level) {
+ html += "</blockquote>";
+ level--;
+ }
+
+ html += usePreTag ? "<pre>" : "<div>";
+
+ while (line[skip] == ' ') {
+ skip++;
+ html += " ";
+ }
+
+ if (skip)
+ line = line.substr(skip);
+
+ html += (line[0] ? line.replace(/</g, "<").replace(/>/g, ">") : "<br>");
+ html += usePreTag ? "</pre>" : "</div>";
+ }
+
+ while (0 < level) {
+ html += "</blockquote>";
+ level--;
+ }
+
+ return html;
+}
+
+EvoEditor.convertParagraphs = function(parent, blockquoteLevel, wrapWidth, canChangeQuoteParagraphs)
+{
+ if (!parent)
+ return;
+
+ var ii;
+
+ for (ii = 0; ii < parent.children.length; ii++) {
+ var child = parent.children.item(ii);
+
+ if (child.tagName == "DIV") {
+ if (wrapWidth == -1 || (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT &&
blockquoteLevel > 0)) {
+ child.style.width = "";
+ EvoEditor.removeEmptyStyleAttribute(child);
+ } else {
+ child.style.width = wrapWidth + "ch";
+ child.removeAttribute("x-evo-width");
+ }
+
+ if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT && blockquoteLevel > 0)
+ EvoEditor.quoteParagraph(child, blockquoteLevel, wrapWidth);
+ } else if (child.tagName == "PRE") {
+ if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT && blockquoteLevel > 0) {
+ var prefixHtml = EvoEditor.getBlockquotePrefixHtml(blockquoteLevel);
+ var lines, jj, text;
+
+ text = child.innerText;
+
+ if (text == "\n" || text == "\r\n")
+ lines = [ "" ];
+ else
+ lines = text.split("\n");
+
+ text = "";
+
+ for (jj = 0; jj < lines.length; jj++) {
+ text += prefixHtml + lines[jj].replace(/\&/g, "&").replace(/</g,
"<").replace(/>/g, ">");
+
+ if (!lines[jj])
+ text += "<BR>";
+
+ if (jj + 1 < lines.length)
+ text += "\n";
+ }
+
+ if (!lines.length)
+ text += prefixHtml;
+
+ child.innerHTML = text;
+ } else {
+ EvoEditor.convertParagraphs(child, blockquoteLevel, wrapWidth,
canChangeQuoteParagraphs);
+ }
+ } else if (child.tagName == "BLOCKQUOTE") {
+ var innerWrapWidth = wrapWidth;
+
+ if (innerWrapWidth > 0) {
+ innerWrapWidth -= 2; // length of "> "
+
+ if (innerWrapWidth < EvoConvert.MIN_PARAGRAPH_WIDTH)
+ innerWrapWidth = EvoConvert.MIN_PARAGRAPH_WIDTH;
+ }
+
+ // replace blockquote content with pure plain text and then re-blockquote it
+ // and do it only on the top level, not recursively (nested citations)
+ if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT && !blockquoteLevel) {
+ child.innerHTML =
EvoEditor.reBlockquotePlainText(EvoConvert.ToPlainText(child, -1),
+ (child.firstElementChild && child.firstElementChild.tagName == "PRE"
&& (
+ !canChangeQuoteParagraphs ||
!EvoEditor.WRAP_QUOTED_TEXT_IN_REPLIES)));
+ }
+
+ EvoEditor.convertParagraphs(child, blockquoteLevel + 1, innerWrapWidth,
canChangeQuoteParagraphs);
+ } else if (child.tagName == "UL") {
+ if (wrapWidth == -1) {
+ child.style.width = "";
+ EvoEditor.removeEmptyStyleAttribute(child);
+ } else {
+ var innerWrapWidth = wrapWidth;
+
+ innerWrapWidth -= 3; // length of " * " prefix
+
+ if (innerWrapWidth < EvoConvert.MIN_PARAGRAPH_WIDTH)
+ innerWrapWidth = EvoConvert.MIN_PARAGRAPH_WIDTH;
+
+ child.style.width = innerWrapWidth + "ch";
+ }
+ } else if (child.tagName == "OL") {
+ if (wrapWidth == -1) {
+ child.style.width = "";
+ child.style.paddingInlineStart = "";
+ EvoEditor.removeEmptyStyleAttribute(child);
+ } else {
+ var innerWrapWidth = wrapWidth, olNeedWidth;
+
+ olNeedWidth = EvoConvert.GetOLMaxLetters(child.getAttribute("type"),
child.children.length) + 2; // length of ". " suffix
+
+ if (olNeedWidth < EvoConvert.MIN_OL_WIDTH)
+ olNeedWidth = EvoConvert.MIN_OL_WIDTH;
+
+ innerWrapWidth -= olNeedWidth;
+
+ if (innerWrapWidth < EvoConvert.MIN_PARAGRAPH_WIDTH)
+ innerWrapWidth = EvoConvert.MIN_PARAGRAPH_WIDTH;
+
+ child.style.width = innerWrapWidth + "ch";
+ child.style.paddingInlineStart = olNeedWidth + "ch";
+ }
+ }
+ }
+}
+
+EvoEditor.SetNormalParagraphWidth = function(value)
+{
+ if (EvoEditor.NORMAL_PARAGRAPH_WIDTH != value) {
+ EvoEditor.NORMAL_PARAGRAPH_WIDTH = value;
+
+ if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT)
+ EvoEditor.convertParagraphs(document.body, 0, EvoEditor.NORMAL_PARAGRAPH_WIDTH,
false);
+ }
+}
+
+EvoEditor.moveNodeContent = function(node, intoNode)
+{
+ if (!node || !node.parentElement)
+ return;
+
+ var parent = node.parentElement;
+
+ while (node.firstChild) {
+ if (intoNode) {
+ intoNode.append(node.firstChild);
+ } else {
+ parent.insertBefore(node.firstChild, node);
+ }
+ }
+}
+
+EvoEditor.convertTags = function()
+{
+ var ii, list;
+
+ for (ii = document.images.length - 1; ii >= 0; ii--) {
+ var img = document.images[ii];
+
+ img.outerText = EvoConvert.ImgToText(img);
+ }
+
+ list = document.getElementsByTagName("A");
+
+ for (ii = list.length - 1; ii >= 0; ii--) {
+ var anchor = list[ii];
+
+ EvoEditor.moveNodeContent(anchor);
+
+ anchor.remove();
+ }
+
+ list = document.getElementsByTagName("TABLE");
+
+ for (ii = list.length - 1; ii >= 0; ii--) {
+ var table = list[ii], textNode;
+
+ textNode = document.createTextNode(table.innerText);
+ table.parentElement.insertBefore(textNode, table);
+ table.remove();
+ }
+
+ list = document.getElementsByTagName("BLOCKQUOTE");
+
+ for (ii = list.length - 1; ii >= 0; ii--) {
+ var blockquoteNode = list[ii];
+
+ blockquoteNode.removeAttribute("class");
+ blockquoteNode.removeAttribute("style");
+ }
+
+ var node = document.body.firstChild, next;
+
+ while (node) {
+ var removeNode = false;
+
+ if (node.nodeType == node.ELEMENT_NODE) {
+ if (node.tagName != "DIV" &&
+ node.tagName != "PRE" &&
+ node.tagName != "BLOCKQUOTE" &&
+ node.tagName != "UL" &&
+ node.tagName != "OL" &&
+ node.tagName != "LI" &&
+ node.tagName != "BR") {
+ removeNode = true;
+
+ // convert P into DIV
+ if (node.tagName == "P") {
+ var div = document.createElement("DIV");
+ EvoEditor.moveNodeContent(node, div);
+ node.parentElement.insertBefore(div, node.nextSibling);
+ } else {
+ EvoEditor.moveNodeContent(node);
+ }
+ }
+ }
+
+ // skip the signature wrapper
+ if (!removeNode && node.tagName == "DIV" && node.className == "-x-evo-signature-wrapper")
+ next = node.nextSibling;
+ else
+ next = EvoEditor.getNextNodeInHierarchy(node, document.body);
+
+ if (removeNode)
+ node.remove();
+
+ node = next;
+ }
+
+ document.body.normalize();
+}
+
+EvoEditor.removeQuoteMarks = function(element)
+{
+ var ii, list;
+
+ if (!element)
+ element = document;
+
+ list = element.querySelectorAll("SPAN.-x-evo-quoted");
+
+ for (ii = list.length - 1; ii >= 0; ii--) {
+ var node = list[ii];
+
+ node.remove();
+ }
+
+ list = element.querySelectorAll("BR.-x-evo-wrap-br");
+
+ for (ii = list.length - 1; ii >= 0; ii--) {
+ var node = list[ii];
+
+ node.insertAdjacentText("beforebegin", " ");
+ node.remove();
+ }
+
+ if (element === document)
+ document.body.normalize();
+ else
+ element.normalize();
+}
+
+EvoEditor.SetMode = function(mode)
+{
+ if (EvoEditor.mode != mode) {
+ var opType = "setMode::" + (mode == EvoEditor.MODE_PLAIN_TEXT ? "PlainText" : "HTML"), record;
+
+ record = EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_DOCUMENT, opType, null, null);
+
+ if (record) {
+ record.modeBefore = EvoEditor.mode;
+ record.modeAfter = mode;
+ record.apply = function(record, isUndo) {
+ var useMode = isUndo ? record.modeBefore : record.modeAfter;
+
+ if (EvoEditor.mode != useMode) {
+ EvoEditor.mode = useMode;
+ }
+ }
+ }
+
+ EvoUndoRedo.Disable();
+ try {
+ EvoEditor.mode = mode;
+
+ EvoEditor.removeQuoteMarks(null);
+
+ if (mode == EvoEditor.MODE_PLAIN_TEXT) {
+ EvoEditor.convertTags();
+ EvoEditor.convertParagraphs(document.body, 0,
EvoEditor.NORMAL_PARAGRAPH_WIDTH, false);
+ } else {
+ EvoEditor.convertParagraphs(document.body, 0, -1, false);
+ }
+ } finally {
+ EvoUndoRedo.Enable();
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_DOCUMENT, opType);
+
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_YES);
+ }
+ }
+}
+
+EvoEditor.applyFontReset = function(record, isUndo)
+{
+ if (record.changes) {
+ var ii;
+
+ for (ii = 0; ii < record.changes.length; ii++) {
+ var change = record.changes[isUndo ? (record.changes.length - ii - 1) : ii];
+ var parent = EvoSelection.FindElementByPath(document.body, change.parentPath);
+
+ if (!parent) {
+ throw "EvoEditor.applyFontReset: Cannot find node at path " + change.path;
+ }
+
+ parent.innerHTML = isUndo ? change.htmlBefore : change.htmlAfter;
+ }
+ }
+}
+
+EvoEditor.replaceInheritFonts = function(undoRedoRecord, selectionUpdater, nodes)
+{
+ var ii;
+
+ if (!nodes)
+ nodes = document.querySelectorAll("FONT[face=inherit]");
+
+ for (ii = nodes.length - 1; ii >= 0; ii--) {
+ var node = nodes.item(ii);
+
+ if (!node || (!undoRedoRecord && !document.getSelection().containsNode(node, true)))
+ continue;
+
+ var parent, change = null;
+
+ parent = node.parentElement;
+
+ if (undoRedoRecord) {
+ if (!undoRedoRecord.changes)
+ undoRedoRecord.changes = [];
+
+ change = {
+ parentPath : EvoSelection.GetChildPath(document.body, parent),
+ htmlBefore : parent.innerHTML,
+ htmlAfter : ""
+ };
+
+ undoRedoRecord.changes[undoRedoRecord.changes.length] = change;
+ }
+
+ if (node.attributes.length == 1) {
+ var child;
+
+ while (node.firstChild) {
+ var child = node.firstChild;
+
+ selectionUpdater.beforeRemove(child);
+
+ parent.insertBefore(child, node);
+
+ selectionUpdater.afterRemove(child);
+ }
+
+ node.remove();
+ } else {
+ node.removeAttribute("face");
+ }
+
+ if (change)
+ change.htmlAfter = parent.innerHTML;
+ }
+
+ if (undoRedoRecord && undoRedoRecord.changes)
+ undoRedoRecord.apply = EvoEditor.applyFontReset;
+}
+
+EvoEditor.maybeReplaceInheritFonts = function()
+{
+ var nodes = document.querySelectorAll("FONT[face=inherit]");
+
+ if (nodes.length <= 0)
+ return;
+
+ var record, selectionUpdater;
+
+ selectionUpdater = EvoSelection.CreateUpdaterObject();
+
+ record = EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "UnsetFontName", null, null,
EvoEditor.CLAIM_CONTENT_FLAG_NONE);
+ try {
+ EvoEditor.replaceInheritFonts(record, selectionUpdater, nodes);
+
+ selectionUpdater.restore();
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "UnsetFontName");
+
+ if (record)
+ EvoUndoRedo.GroupTopRecords(2);
+ }
+}
+
+EvoEditor.SetFontName = function(name)
+{
+ if (!name || name == "")
+ name = "inherit";
+
+ var record, selectionUpdater = EvoSelection.CreateUpdaterObject(), bodyFontFamily;
+
+ // to workaround https://bugs.webkit.org/show_bug.cgi?id=204622
+ bodyFontFamily = document.body.style.fontFamily;
+
+ record = EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_GROUP, "SetFontName");
+ try {
+ if (!document.getSelection().isCollapsed && bodyFontFamily)
+ document.body.style.fontFamily = "";
+
+ document.execCommand("FontName", false, name);
+
+ if (document.getSelection().isCollapsed) {
+ if (name == "inherit")
+ EvoEditor.checkInheritFontsOnChange = true;
+
+ /* Format change on collapsed selection is not applied immediately */
+ if (record)
+ record.ignore = true;
+ } else if (name == "inherit") {
+ var subrecord;
+
+ subrecord = EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "SetFontName",
null, null, EvoEditor.CLAIM_CONTENT_FLAG_NONE);
+ try {
+ EvoEditor.replaceInheritFonts(subrecord, selectionUpdater);
+ selectionUpdater.restore();
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "SetFontName");
+ }
+ }
+ } finally {
+ if (bodyFontFamily && document.body.style.fontFamily != bodyFontFamily)
+ document.body.style.fontFamily = bodyFontFamily;
+
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_GROUP, "SetFontName");
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+
+ EvoEditor.removeEmptyStyleAttribute(document.body);
+ }
+}
+
+EvoEditor.convertHtmlToSend = function()
+{
+ var html, bgcolor, text, link, vlink;
+ var unsetBgcolor = false, unsetText = false, unsetLink = false, unsetVlink = false;
+ var themeCss, inheritThemeColors = EvoEditor.inheritThemeColors;
+ var ii, styles, styleNode = null, topSignatureSpacers, elems;
+
+ themeCss = EvoEditor.UpdateThemeStyleSheet(null);
+ bgcolor = document.documentElement.getAttribute("x-evo-bgcolor");
+ text = document.documentElement.getAttribute("x-evo-text");
+ link = document.documentElement.getAttribute("x-evo-link");
+ vlink = document.documentElement.getAttribute("x-evo-vlink");
+
+ document.documentElement.removeAttribute("x-evo-bgcolor");
+ document.documentElement.removeAttribute("x-evo-text");
+ document.documentElement.removeAttribute("x-evo-link");
+ document.documentElement.removeAttribute("x-evo-vlink");
+
+ topSignatureSpacers = document.querySelectorAll(".-x-evo-top-signature-spacer");
+
+ for (ii = topSignatureSpacers.length - 1; ii >= 0; ii--) {
+ topSignatureSpacers[ii].removeAttribute("class");
+ }
+
+ if (inheritThemeColors) {
+ if (bgcolor && !document.body.getAttribute("bgcolor")) {
+ document.body.setAttribute("bgcolor", bgcolor);
+ unsetBgcolor = true;
+ }
+
+ if (text && !document.body.getAttribute("text")) {
+ document.body.setAttribute("text", text);
+ unsetText = true;
+ }
+
+ if (link && !document.body.getAttribute("link")) {
+ document.body.setAttribute("link", link);
+ unsetLink = true;
+ }
+
+ if (vlink && !document.body.getAttribute("vlink")) {
+ document.body.setAttribute("vlink", vlink);
+ unsetVlink = true;
+ }
+ }
+
+ styles = document.head.getElementsByTagName("style");
+
+ for (ii = 0; ii < styles.length; ii++) {
+ if (styles[ii].id == "x-evo-body-fontname") {
+ styleNode = styles[ii];
+ styleNode.id = "";
+ break;
+ }
+ }
+
+ if (EvoEditor.mode == EvoEditor.MODE_HTML) {
+ elems = document.getElementsByTagName("BLOCKQUOTE");
+
+ for (ii = 0; ii < elems.length; ii++) {
+ elems[ii].setAttribute("style", EvoEditor.BLOCKQUOTE_STYLE);
+ }
+ }
+
+ html = document.documentElement.outerHTML;
+
+ if (EvoEditor.mode == EvoEditor.MODE_HTML) {
+ elems = document.getElementsByTagName("BLOCKQUOTE");
+
+ for (ii = 0; ii < elems.length; ii++) {
+ elems[ii].removeAttribute("style");
+ }
+ }
+
+ if (styleNode)
+ styleNode.id = "x-evo-body-fontname";
+
+ if (bgcolor)
+ document.documentElement.setAttribute("x-evo-bgcolor", bgcolor);
+ if (text)
+ document.documentElement.setAttribute("x-evo-text", text);
+ if (link)
+ document.documentElement.setAttribute("x-evo-link", link);
+ if (vlink)
+ document.documentElement.setAttribute("x-evo-vlink", vlink);
+
+ if (inheritThemeColors) {
+ if (unsetBgcolor)
+ document.body.removeAttribute("bgcolor");
+
+ if (unsetText)
+ document.body.removeAttribute("text");
+
+ if (unsetLink)
+ document.body.removeAttribute("link");
+
+ if (unsetVlink)
+ document.body.removeAttribute("vlink");
+ }
+
+ for (ii = topSignatureSpacers.length - 1; ii >= 0; ii--) {
+ var elem = topSignatureSpacers[ii];
+
+ if (elem.previousSibling && elem.previousSibling.tagName == "DIV" &&
elem.previousSibling.className == "-x-evo-signature-wrapper") {
+ elem.className = "-x-evo-top-signature-spacer";
+ break;
+ }
+ }
+
+ if (themeCss)
+ EvoEditor.UpdateThemeStyleSheet(themeCss);
+
+ return html;
+}
+
+EvoEditor.GetContent = function(flags, cid_uid_prefix)
+{
+ var content_data = {};
+
+ if (!document.body)
+ return content_data;
+
+ var img_elems = [], data_names = [], bkg_elems = [], elems, ii, jj, currentElemsArray = null;
+ var scrollX = window.scrollX, scrollY = window.scrollY;
+
+ EvoUndoRedo.Disable();
+
+ try {
+ currentElemsArray = EvoEditor.RemoveCurrentElementAttr();
+
+ // For safety, to not export with empty 'style' attributes; these do not need Undo
+ elems = document.querySelectorAll("[style='']");
+ for (ii = 0; ii < elems.length; ii++) {
+ EvoEditor.removeEmptyStyleAttribute(elems[ii]);
+ }
+
+ if ((flags & EvoEditor.E_CONTENT_EDITOR_GET_RAW_BODY_STRIPPED) != 0) {
+ var hidden_elems = [];
+
+ try {
+ elems = document.getElementsByClassName("-x-evo-signature-wrapper");
+ if (elems && elems.length) {
+ for (ii = 0; ii < elems.length; ii++) {
+ var elem = elems.item(ii);
+
+ if (elem && !elem.hidden) {
+ hidden_elems[hidden_elems.length] = elem;
+ elem.hidden = true;
+ }
+ }
+ }
+
+ elems = document.getElementsByTagName("BLOCKQUOTE");
+ if (elems && elems.length) {
+ for (ii = 0; ii < elems.length; ii++) {
+ var elem = elems.item(ii);
+
+ if (elem && !elem.hidden) {
+ hidden_elems[hidden_elems.length] = elem;
+ elem.hidden = true;
+ }
+ }
+ }
+
+ content_data["raw-body-stripped"] = document.body.innerText;
+ } finally {
+ for (ii = 0; ii < hidden_elems.length; ii++) {
+ hidden_elems[ii].hidden = false;
+ }
+ }
+ }
+
+ // Do these before changing image sources
+ if ((flags & EvoEditor.E_CONTENT_EDITOR_GET_RAW_BODY_HTML) != 0)
+ content_data["raw-body-html"] = document.body.innerHTML;
+
+ if ((flags & EvoEditor.E_CONTENT_EDITOR_GET_RAW_BODY_PLAIN) != 0)
+ content_data["raw-body-plain"] = document.body.innerText;
+
+ if (EvoEditor.mode == EvoEditor.MODE_HTML &&
+ (flags & EvoEditor.E_CONTENT_EDITOR_GET_INLINE_IMAGES) != 0) {
+ var images = [];
+
+ for (ii = 0; ii < document.images.length; ii++) {
+ var elem = document.images.item(ii);
+ var src = (elem && elem.src) ? elem.src.toLowerCase() : "";
+
+ if (elem && (
+ src.startsWith("data:") ||
+ src.startsWith("file://") ||
+ src.startsWith("evo-file://"))) {
+ for (jj = 0; jj < img_elems.length; jj++) {
+ if (elem.src == img_elems[jj].orig_src) {
+ img_elems[jj].subelems[img_elems[jj].subelems.length]
= elem;
+ elem.src = img_elems[jj].cid;
+ break;
+ }
+ }
+
+ if (jj >= img_elems.length) {
+ var img_obj = {
+ subelems : [ elem ],
+ cid : "cid:" + cid_uid_prefix + "-" +
img_elems.length,
+ orig_src : elem.src
+ };
+
+ if (elem.src.toLowerCase().startsWith("cid:"))
+ img_obj.cid = elem.src;
+
+ img_elems[img_elems.length] = img_obj;
+ images[images.length] = {
+ cid : img_obj.cid,
+ src : elem.src
+ };
+ elem.src = img_obj.cid;
+
+ if (elem.hasAttribute("data-name"))
+ images[images.length - 1].name =
elem.getAttribute("data-name");
+ }
+ } else if (elem && src.startsWith("cid:")) {
+ images[images.length] = {
+ cid : elem.src,
+ src : elem.src
+ };
+ }
+
+ if (elem) {
+ // just remove the attribute used by the old editor
+ elem.removeAttribute("data-inline");
+
+ if (elem.hasAttribute("data-name")) {
+ data_names[data_names.length] = {
+ elem : elem,
+ name : elem.getAttribute("data-name")
+ };
+
+ elem.removeAttribute("data-name");
+ }
+ }
+ }
+
+ var backgrounds = document.querySelectorAll("[background]");
+ for (ii = 0; ii < backgrounds.length; ii++) {
+ var elem = backgrounds[ii];
+ var src = elem ? elem.getAttribute("background").toLowerCase() : "";
+
+ if (elem && (
+ src.startsWith("data:") ||
+ src.startsWith("file://") ||
+ src.startsWith("evo-file://"))) {
+ var bkg = elem.getAttribute("background");
+
+ for (jj = 0; jj < bkg_elems.length; jj++) {
+ if (bkg == bkg_elems[jj].orig_src) {
+ bkg_elems[jj].subelems[bkg_elems[jj].subelems.length]
= elem;
+ elem.setAttribute("background", bkg_elems[jj].cid);
+ break;
+ }
+ }
+
+ if (jj >= bkg_elems.length) {
+ var bkg_obj = {
+ subelems : [ elem ],
+ cid : "cid:" + cid_uid_prefix + "-" +
bkg_elems.length,
+ orig_src : bkg
+ };
+
+ // re-read, because it could change
+ if
(elem.getAttribute("background").toLowerCase().startsWith("cid:"))
+ bkg_obj.cid = elem.getAttribute("background");
+
+ bkg_elems[bkg_elems.length] = bkg_obj;
+ images[images.length] = {
+ cid : bkg_obj.cid,
+ src : elem.getAttribute("background")
+ };
+ elem.setAttribute("background", bkg_obj.cid);
+
+ if (elem.hasAttribute("data-name"))
+ images[images.length - 1].name =
elem.getAttribute("data-name");
+ }
+ } else if (elem && src.startsWith("cid:")) {
+ images[images.length] = {
+ cid : elem.getAttribute("background"),
+ src : elem.getAttribute("background")
+ };
+ }
+
+ if (elem) {
+ if (elem.hasAttribute("data-name")) {
+ data_names[data_names.length] = {
+ elem : elem,
+ name : elem.getAttribute("data-name")
+ };
+
+ elem.removeAttribute("data-name");
+ }
+ }
+ }
+
+ if (images.length)
+ content_data["images"] = images;
+ }
+
+ // Draft should have replaced images as well
+ if ((flags & EvoEditor.E_CONTENT_EDITOR_GET_RAW_DRAFT) != 0) {
+ document.head.setAttribute("x-evo-selection",
EvoSelection.ToString(EvoSelection.Store(document)));
+ try {
+ content_data["raw-draft"] = document.documentElement.innerHTML;
+ } finally {
+ document.head.removeAttribute("x-evo-selection");
+ }
+ }
+
+ if ((flags & EvoEditor.E_CONTENT_EDITOR_GET_TO_SEND_HTML) != 0)
+ content_data["to-send-html"] = EvoEditor.convertHtmlToSend();
+
+ if ((flags & EvoEditor. E_CONTENT_EDITOR_GET_TO_SEND_PLAIN) != 0) {
+ content_data["to-send-plain"] = EvoConvert.ToPlainText(document.body,
EvoEditor.NORMAL_PARAGRAPH_WIDTH);
+ }
+ } finally {
+ try {
+ for (ii = 0; ii < img_elems.length; ii++) {
+ var img_obj = img_elems[ii];
+
+ for (jj = 0; jj < img_obj.subelems.length; jj++) {
+ img_obj.subelems[jj].src = img_obj.orig_src;
+ }
+ }
+
+ for (ii = 0; ii < data_names.length; ii++) {
+ data_names[ii].elem.setAttribute("data-name", data_names[ii].name);
+ }
+
+ for (ii = 0; ii < bkg_elems.length; ii++) {
+ var bkg_obj = bkg_elems[ii];
+
+ for (jj = 0; jj < bkg_obj.subelems.length; jj++) {
+ bkg_obj.subelems[jj].setAttribute("background", bkg_obj.orig_src);
+ }
+ }
+
+ EvoEditor.RestoreCurrentElementAttr(currentElemsArray);
+ } finally {
+ EvoUndoRedo.Enable();
+ }
+ }
+
+ // the above changes can cause change of the scroll offset, thus restore it
+ window.scrollTo(scrollX, scrollY);
+
+ return content_data;
+}
+
+EvoEditor.UpdateStyleSheet = function(id, css)
+{
+ var styles, ii, res = null;
+
+ styles = document.head.getElementsByTagName("style");
+
+ for (ii = 0; ii < styles.length; ii++) {
+ if (styles[ii].id == id) {
+ res = styles[ii].innerHTML;
+
+ if (css)
+ styles[ii].innerHTML = css;
+ else
+ document.head.removeChild(styles[ii]);
+
+ return res;
+ }
+ }
+
+ if (css) {
+ var style;
+
+ style = document.createElement("STYLE");
+ style.id = id;
+ style.innerHTML = css;
+ document.head.append(style);
+ }
+
+ return res;
+}
+
+EvoEditor.UpdateThemeStyleSheet = function(css)
+{
+ return EvoEditor.UpdateStyleSheet("x-evo-theme-sheet", css);
+}
+
+EvoEditor.findSmileys = function(text, unicodeSmileys)
+{
+ /* Based on original use_pictograms() from GtkHTML */
+ var emoticons_chars = [
+ /* 0 */ "D", "O", ")", "(", "|", "/", "P", "Q", "*", "!",
+ /* 10 */ "S", null, ":", "-", null, ":", null, ":", "-", null,
+ /* 20 */ ":", null, ":", ";", "=", "-", "\"", null, ":", ";",
+ /* 30 */ "B", "\"", "|", null, ":", "-", "'", null, ":", "X",
+ /* 40 */ null, ":", null, ":", "-", null, ":", null, ":", "-",
+ /* 50 */ null, ":", null, ":", "-", null, ":", null, ":", "-",
+ /* 60 */ null, ":", null, ":", null, ":", "-", null, ":", null,
+ /* 70 */ ":", "-", null, ":", null, ":", "-", null, ":", null ];
+ var emoticons_states = [
+ /* 0 */ 12, 17, 22, 34, 43, 48, 53, 58, 65, 70,
+ /* 10 */ 75, 0, -15, 15, 0, -15, 0, -17, 20, 0,
+ /* 20 */ -17, 0, -14, -20, -14, 28, 63, 0, -14, -20,
+ /* 30 */ -3, 63, -18, 0, -12, 38, 41, 0, -12, -2,
+ /* 40 */ 0, -4, 0, -10, 46, 0, -10, 0, -19, 51,
+ /* 50 */ 0, -19, 0, -11, 56, 0, -11, 0, -13, 61,
+ /* 60 */ 0, -13, 0, -6, 0, 68, -7, 0, -7, 0,
+ /* 70 */ -16, 73, 0, -16, 0, -21, 78, 0, -21, 0 ];
+ var emoticons_icon_names = [
+ "face-angel",
+ "face-angry",
+ "face-cool",
+ "face-crying",
+ "face-devilish",
+ "face-embarrassed",
+ "face-kiss",
+ "face-laugh", /* not used */
+ "face-monkey", /* not used */
+ "face-plain",
+ "face-raspberry",
+ "face-sad",
+ "face-sick",
+ "face-smile",
+ "face-smile-big",
+ "face-smirk",
+ "face-surprise",
+ "face-tired",
+ "face-uncertain",
+ "face-wink",
+ "face-worried"
+ ];
+ var res = null, pos, state, start, uc;
+
+ start = text.length - 1;
+
+ if (start < 1)
+ return res;
+
+ pos = start;
+ while (pos >= 0) {
+ state = 0;
+ while (pos >= 0) {
+ uc = text[pos];
+ var relative = 0;
+ while (emoticons_chars[state + relative] != null) {
+ if (emoticons_chars[state + relative] == uc) {
+ break;
+ }
+ relative++;
+ }
+ state = emoticons_states[state + relative];
+ /* 0 .. not found, -n .. found n-th */
+ if (state <= 0)
+ break;
+ pos--;
+ }
+
+ /* Special case needed to recognize angel and devilish. */
+ if (pos > 0 && state == -14) {
+ uc = text[pos - 1];
+ if (uc == 'O') {
+ state = -1;
+ pos--;
+ } else if (uc == '>') {
+ state = -5;
+ pos--;
+ }
+ }
+
+ if (state < 0) {
+ if (pos > 0) {
+ uc = text[pos - 1];
+
+ if (uc != ' ') {
+ return res;
+ }
+ }
+
+ var obj = EvoEditor.lookupEmoticon(emoticons_icon_names[- state - 1], unicodeSmileys);
+
+ if (obj) {
+ obj.start = pos;
+ obj.end = start + 1;
+
+ if (!res)
+ res = [];
+
+ res[res.length] = obj;
+ }
+
+ pos--;
+ start = pos;
+ } else {
+ break;
+ }
+ }
+
+ return res;
+}
+
+EvoEditor.maybeUpdateParagraphWidth = function(topNode)
+{
+ if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT) {
+ var node = topNode, citeLevel = 0;
+
+ while (node && node.tagName != "BODY") {
+ if (node.tagName == "BLOCKQUOTE")
+ citeLevel++;
+
+ node = node.parentElement;
+ }
+
+ if (citeLevel * 2 < EvoEditor.NORMAL_PARAGRAPH_WIDTH) {
+ topNode.style.width = (EvoEditor.NORMAL_PARAGRAPH_WIDTH - citeLevel * 2) + "ch";
+ }
+ }
+}
+
+EvoEditor.splitAtChild = function(parent, childNode)
+{
+ var newNode, node, next, ii;
+
+ newNode = parent.ownerDocument.createElement(parent.tagName);
+
+ for (ii = 0; ii < parent.attributes.length; ii++) {
+ newNode.setAttribute(parent.attributes[ii].nodeName, parent.attributes[ii].nodeValue);
+ }
+
+ node = childNode;
+ while (node) {
+ next = node.nextSibling;
+ newNode.appendChild(node);
+ node = next;
+ }
+
+ parent.parentElement.insertBefore(newNode, parent.nextSibling);
+
+ return newNode;
+}
+
+EvoEditor.hasElementWithTagNameAsParent = function(node, tagName)
+{
+ if (!node)
+ return false;
+
+ for (node = node.parentElement; node; node = node.parentElement) {
+ if (node.tagName == tagName)
+ return true;
+ }
+
+ return false;
+}
+
+EvoEditor.requoteNodeParagraph = function(node)
+{
+ while (node && node.tagName != "BODY" && !EvoEditor.IsBlockNode(node)) {
+ node = node.parentElement;
+ }
+
+ if (!node || node.tagName == "BODY")
+ return null;
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "requote", node, node,
+ EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+
+ try {
+ var blockquoteLevel = EvoEditor.getBlockquoteLevel(node);
+
+ EvoEditor.quoteParagraph(node, blockquoteLevel, EvoEditor.NORMAL_PARAGRAPH_WIDTH - (2 *
blockquoteLevel));
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "requote");
+ }
+
+ return node;
+}
+
+EvoEditor.replaceMatchWithNode = function(opType, node, match, newNode, canEmit, withUndo)
+{
+ if (withUndo) {
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, opType, node.parentElement,
node.parentElement,
+ EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ }
+
+ try {
+ var selection = document.getSelection();
+ var offset = selection.anchorOffset, updateSelection = selection.anchorNode === node,
newAnchorNode;
+
+ node.splitText(match.end);
+ newAnchorNode = node.nextSibling;
+ node.splitText(match.start);
+
+ node = node.nextSibling;
+
+ node.parentElement.insertBefore(newNode, node);
+ if (newNode.tagName == "A")
+ newNode.appendChild(node);
+ else
+ node.remove();
+
+ if (updateSelection && newAnchorNode && offset - match.end >= 0)
+ selection.setPosition(newAnchorNode, offset - match.end);
+ } finally {
+ if (withUndo) {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, opType);
+
+ if (canEmit) {
+ EvoUndoRedo.GroupTopRecords(2);
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+ }
+ }
+
+ return node;
+}
+
+EvoEditor.linkifyText = function(anchorNode, withUndo)
+{
+ if (!anchorNode)
+ return false;
+
+ var text = anchorNode.nodeValue, tmpNode;
+
+ if (!text)
+ return false;
+
+ for (tmpNode = anchorNode; tmpNode && tmpNode.tagName != "BODY"; tmpNode = tmpNode.parentElement) {
+ if (tmpNode.tagName == "A") {
+ return false;
+ }
+ }
+
+ var parts, ii;
+
+ parts = EvoEditor.splitTextWithLinks(text);
+
+ if (!parts)
+ return false;
+
+ if (withUndo) {
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "magicLink",
anchorNode.parentElement, anchorNode.parentElement,
+ EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ }
+
+ try {
+ var selection = document.getSelection(), matchEnd = 0, insBefore, parent;
+ var offset = selection.anchorOffset, updateSelection = selection.anchorNode === anchorNode,
newAnchorNode = null;
+
+ insBefore = anchorNode;
+ parent = anchorNode.parentElement;
+
+ for (ii = 0; ii < parts.length; ii++) {
+ var part = parts[ii], node, isLast = ii + 1 >= parts.length;
+
+ if (part.href) {
+ node = document.createElement("A");
+ node.href = part.href;
+ node.innerText = part.text;
+ } else if (isLast) {
+ node = null;
+ // it can be a space, which cannot be added after the element, thus
workaround it this way
+ newAnchorNode = anchorNode.splitText(matchEnd);
+ } else {
+ node = document.createTextNode(part.text);
+ }
+
+ if (node)
+ parent.insertBefore(node, insBefore);
+
+ if (!isLast) {
+ matchEnd += part.text.length;
+ } else if (node) {
+ newAnchorNode = node;
+ }
+ }
+
+ if (anchorNode)
+ anchorNode.remove();
+
+ if (updateSelection && newAnchorNode && offset - matchEnd >= 0)
+ selection.setPosition(newAnchorNode, offset - matchEnd);
+ } finally {
+ if (withUndo) {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "magicLink");
+
+ EvoUndoRedo.GroupTopRecords(2);
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+ }
+
+ return true;
+}
+
+EvoEditor.maybeRemoveQuotationMark = function(node)
+{
+ if (!node || node.nodeType != node.ELEMENT_NODE || node.tagName != "SPAN" ||
+ node.className != "-x-evo-quoted")
+ return false;
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "removeQuotationMark", node, node,
+ EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML | EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE);
+ try {
+ node.remove();
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "removeQuotationMark");
+ }
+
+ return true;
+}
+
+EvoEditor.removeEmptyElements = function(tagName)
+{
+ var nodes, node, ii, didRemove = 0;
+
+ nodes = document.getElementsByTagName(tagName);
+
+ for (ii = nodes.length - 1; ii >= 0; ii--) {
+ node = nodes[ii];
+
+ // more than one child element means it's not empty
+ if (node.childElementCount > 1)
+ continue;
+
+ // the first element is not quotation mark
+ if (node.firstElementChild && (node.firstElementChild.tagName != "SPAN" ||
+ node.firstElementChild.className != "-x-evo-quoted"))
+ continue;
+
+ // the text inside is not empty, possibly on either of the two sides of the quotation mark
+ if ((node.firstChild && (node.firstChild.nodeType == node.TEXT_NODE &&
node.firstChild.nodeValue)) ||
+ (node.lastChild && !(node.lastChild === node.firstChild) && (node.lastChild.nodeType ==
node.TEXT_NODE && node.lastChild.nodeValue)))
+ continue;
+
+ // it's either completely empty or it contains only the quotation mark and nothing else
+ didRemove++;
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "removeEmptyElem::" + tagName,
node.parentElement, node.parentElement,
+ EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML |
EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE);
+ try {
+ node.remove();
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "removeEmptyElem::" + tagName);
+ }
+ }
+
+ return didRemove;
+}
+
+EvoEditor.beforeInputCb = function(inputEvent)
+{
+ if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT && inputEvent && (
+ inputEvent.inputType == "deleteContentForward" || inputEvent.inputType ==
"deleteContentBackward")) {
+ var selection = document.getSelection();
+
+ // workaround WebKit bug https://bugs.webkit.org/show_bug.cgi?id=209605
+ if (selection.anchorNode && selection.anchorNode.nodeType ==
selection.anchorNode.ELEMENT_NODE &&
+ selection.isCollapsed && EvoEditor.IsBlockNode(selection.anchorNode) &&
selection.anchorNode.firstChild.tagName == "BR" &&
+ !selection.anchorNode.firstChild.nextSibling) {
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_EVENT, inputEvent.inputType,
selection.anchorNode, selection.anchorNode,
+ EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML |
EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE);
+ try {
+ var next = selection.anchorNode.nextSibling;
+
+ if (!next)
+ next = selection.anchorNode.previousSibling;
+ if (!next)
+ next = selection.anchorNode.parentElement;
+
+ selection.anchorNode.remove();
+
+ selection.setPosition(next, 0);
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_EVENT, inputEvent.inputType);
+ }
+
+ inputEvent.stopImmediatePropagation();
+ inputEvent.stopPropagation();
+ inputEvent.preventDefault();
+
+ return;
+ }
+ }
+
+ if (EvoUndoRedo.disabled ||
+ !inputEvent ||
+ inputEvent.inputType != "insertText" ||
+ !inputEvent.data ||
+ inputEvent.data.length != 1 ||
+ inputEvent.data == " " ||
+ inputEvent.data == "\t")
+ return;
+
+ var selection = document.getSelection();
+
+ // when writing at the end of the anchor, then write into the anchor, not out (WebKit writes out)
+ if (!selection ||
+ !selection.isCollapsed ||
+ !selection.anchorNode ||
+ selection.anchorNode.nodeType != selection.anchorNode.TEXT_NODE ||
+ selection.anchorOffset != selection.anchorNode.nodeValue.length ||
+ !selection.anchorNode.parentElement ||
+ selection.anchorNode.parentElement.tagName != "A")
+ return;
+
+ var node = selection.anchorNode;
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_EVENT, "insertText", selection.anchorNode,
selection.anchorNode,
+ EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML | EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE);
+
+ try {
+ node.nodeValue += inputEvent.data;
+ selection.setPosition(node, node.nodeValue.length);
+
+ if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT)
+ node.parentElement.href = node.nodeValue;
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_EVENT, "insertText");
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+
+ // it will add the text, if anything breaks before it gets here
+ inputEvent.stopImmediatePropagation();
+ inputEvent.stopPropagation();
+ inputEvent.preventDefault();
+}
+
+EvoEditor.AfterInputEvent = function(inputEvent, isWordDelim)
+{
+ var isInsertParagraph = inputEvent.inputType == "insertParagraph";
+ var selection = document.getSelection();
+
+ if (isInsertParagraph && selection.isCollapsed && selection.anchorNode &&
selection.anchorNode.tagName == "BODY") {
+ document.execCommand("insertHTML", false, EvoEditor.emptyParagraphAsHtml());
+ EvoUndoRedo.GroupTopRecords(2, "insertParagraph::withFormat");
+ return;
+ }
+
+ // make sure there's always a DIV in the body (like after 'select all' followed by 'delete')
+ if (!document.body.childNodes.length || (document.body.childNodes.length == 1 &&
document.body.childNodes[0].tagName == "BR")) {
+ document.execCommand("insertHTML", false, EvoEditor.emptyParagraphAsHtml());
+ EvoUndoRedo.GroupTopRecords(2, inputEvent.inputType + "::fillEmptyBody");
+ return;
+ }
+
+ if (isInsertParagraph && selection.isCollapsed && selection.anchorNode &&
selection.anchorNode.tagName == "SPAN" &&
+ selection.anchorNode.children.length == 1 && selection.anchorNode.firstElementChild.tagName ==
"BR" &&
+ selection.anchorNode.parentElement.tagName == "DIV") {
+ // new paragraph in UL/OL creates: <div><span style='white-space: normal;'><br></span><div>
+ // thus avoid the <span />, which is not expected in the EvoEditor
+ var node = selection.anchorNode;
+
+ while (node.firstChild) {
+ node.parentElement.insertBefore(node.firstChild, node);
+ }
+
+ selection.setPosition(node.parentElement, 0);
+ node.remove();
+ }
+
+ if (isInsertParagraph && selection.isCollapsed && selection.anchorNode &&
selection.anchorNode.tagName == "DIV") {
+ // for example when moving away from ul/ol, the newly created
+ // paragraph can inherit styles from it, which is also negative text-indent
+ selection.anchorNode.style.textIndent = "";
+ EvoEditor.removeEmptyStyleAttribute(selection.anchorNode);
+ EvoEditor.maybeUpdateParagraphWidth(selection.anchorNode);
+
+ // it can be inherited, which is not desired when the user edits the content of it
+ if (selection.anchorNode.className == "-x-evo-top-signature-spacer")
+ selection.anchorNode.removeAttribute("class");
+ }
+
+ // inserting paragraph in BLOCKQUOTE creates a new BLOCKQUOTE without <DIV> inside it
+ if (isInsertParagraph && selection.isCollapsed && selection.anchorNode &&
(selection.anchorNode.tagName == "BLOCKQUOTE" ||
+ (selection.anchorNode.nodeType == selection.anchorNode.TEXT_NODE &&
selection.anchorNode.parentElement &&
+ selection.anchorNode.parentElement.tagName == "BLOCKQUOTE"))) {
+ var blockquoteNode = selection.anchorNode;
+
+ if (blockquoteNode.nodeType == blockquoteNode.TEXT_NODE)
+ blockquoteNode = blockquoteNode.parentElement;
+
+ if (!blockquoteNode.firstChild || !EvoEditor.IsBlockNode(blockquoteNode.firstChild)) {
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "blockquoteFix",
blockquoteNode, blockquoteNode,
+ EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+
+ try {
+ var divNode = document.createElement("DIV");
+
+ while (blockquoteNode.firstChild) {
+ divNode.appendChild(blockquoteNode.firstChild);
+ }
+
+ blockquoteNode.appendChild(divNode);
+ EvoEditor.maybeUpdateParagraphWidth(divNode);
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "blockquoteFix");
+ EvoUndoRedo.GroupTopRecords(2, "insertParagraph::blockquoteFix");
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+ }
+ }
+
+ // special editing of blockquotes
+ if (selection.isCollapsed && (inputEvent.inputType.startsWith("insert") ||
inputEvent.inputType.startsWith("delete"))) {
+ if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT && inputEvent.inputType.startsWith("delete"))
{
+ var didRemove = 0;
+
+ didRemove += EvoEditor.removeEmptyElements("DIV");
+ didRemove += EvoEditor.removeEmptyElements("PRE");
+
+ if (didRemove)
+ EvoUndoRedo.GroupTopRecords(didRemove + 1, inputEvent.inputType +
"::removeEmptyElems");
+ }
+
+ if (EvoEditor.hasElementWithTagNameAsParent(selection.anchorNode, "BLOCKQUOTE")) {
+ // insertParagraph should split the blockquote into two
+ if (isInsertParagraph) {
+ var node = selection.anchorNode, childNode = node, parent, removeNode = null;
+
+ for (parent = node.parentElement; parent && parent.tagName != "BODY"; parent
= parent.parentElement) {
+ if (parent.tagName == "BLOCKQUOTE") {
+ childNode = parent;
+ }
+ }
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "blockquoteSplit",
childNode, childNode,
+ EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+
+ try {
+ if (node.nodeType == node.ELEMENT_NODE && node.childNodes.length == 1
&& node.firstChild.tagName == "BR")
+ removeNode = node;
+ else if (node.nodeType == node.ELEMENT_NODE && node.childNodes.length
1 && node.firstChild.tagName == "BR")
+ removeNode = node.firstChild;
+
+ childNode = node;
+
+ for (parent = node.parentElement; parent && parent.tagName != "BODY";
parent = parent.parentElement) {
+ if (parent.tagName == "BLOCKQUOTE") {
+ childNode = EvoEditor.splitAtChild(parent, childNode);
+ parent = childNode;
+ } else {
+ childNode = parent;
+ }
+ }
+
+ if (parent) {
+ var divNode = document.createElement("DIV");
+ divNode.appendChild(document.createElement("BR"));
+ parent.insertBefore(divNode, childNode);
+ document.getSelection().setPosition(divNode, 0);
+ EvoEditor.maybeUpdateParagraphWidth(divNode);
+ }
+
+ while (removeNode && removeNode.tagName != "BODY") {
+ node = removeNode.parentElement;
+ node.removeChild(removeNode);
+
+ if (node.childNodes.length)
+ break;
+
+ removeNode = node;
+ }
+
+ if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT) {
+ node = document.getSelection().anchorNode;
+
+ if (node && node.nextElementSibling) {
+ var blockquoteLevel =
(node.nextElementSibling.tagName == "BLOCKQUOTE" ? 1 : 0);
+
+ EvoEditor.removeQuoteMarks(node.nextElementSibling);
+ EvoEditor.convertParagraphs(node.nextElementSibling,
blockquoteLevel,
+ EvoEditor.NORMAL_PARAGRAPH_WIDTH -
(blockquoteLevel * 2), false);
+ }
+
+ if (node && node.previousElementSibling) {
+ var blockquoteLevel =
(node.previousElementSibling.tagName == "BLOCKQUOTE" ? 1 : 0);
+
+
EvoEditor.removeQuoteMarks(node.previousElementSibling);
+
EvoEditor.convertParagraphs(node.previousElementSibling, blockquoteLevel,
+ EvoEditor.NORMAL_PARAGRAPH_WIDTH -
(blockquoteLevel * 2), false);
+ }
+ }
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM,
"blockquoteSplit");
+ EvoUndoRedo.GroupTopRecords(2, "insertParagraph::blockquoteSplit");
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+ // insertLineBreak should re-quote text in the Plain Text mode
+ } else if (inputEvent.inputType == "insertLineBreak") {
+ if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT) {
+ var selNode = document.getSelection().anchorNode, node = selNode,
parent;
+
+ while (node && node.tagName != "BODY" &&
!EvoEditor.IsBlockNode(node)) {
+ node = node.parentElement;
+ }
+
+ if (node && node.tagName != "BODY" && selNode.previousSibling &&
selNode.previousSibling.nodeValue == "\n") {
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM,
"requote", node, node,
+ EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+
+ try {
+ var blockquoteLevel;
+
+ // the "\n" is replaced with full paragraph
+
selNode.parentElement.removeChild(selNode.previousSibling);
+
+ parent = selNode.parentElement;
+
+ var childNode = selNode;
+
+ while (parent && parent.tagName != "BODY") {
+ childNode = EvoEditor.splitAtChild(parent,
childNode);
+
+ if (childNode === node ||
EvoEditor.IsBlockNode(parent))
+ break;
+
+ parent = childNode.parentElement;
+ }
+
+ blockquoteLevel =
EvoEditor.getBlockquoteLevel(parent);
+
+ EvoEditor.quoteParagraph(childNode, blockquoteLevel,
EvoEditor.NORMAL_PARAGRAPH_WIDTH - (2 * blockquoteLevel));
+
+ document.getSelection().setPosition(childNode, 0);
+ } finally {
+
EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "requote");
+ EvoUndoRedo.GroupTopRecords(2,
"insertLineBreak::requote");
+
EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+ }
+ }
+ // it's an insert or delete in the blockquote, which means to recalculate where
quotation marks should be
+ } else if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT) {
+ var node = document.getSelection().anchorNode;
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_GROUP, "requote::group");
+ try {
+ var selection = EvoSelection.Store(document);
+
+ EvoEditor.removeEmptyElements("DIV");
+ EvoEditor.removeEmptyElements("PRE");
+
+ node = EvoEditor.requoteNodeParagraph(node);
+
+ if (node && inputEvent.inputType.startsWith("delete")) {
+ if (node.nextSiblingElement)
+
EvoEditor.requoteNodeParagraph(node.nextSiblingElement);
+ if (node.previousSiblingElement)
+
EvoEditor.requoteNodeParagraph(node.previousSiblingElement);
+ }
+
+ EvoSelection.Restore(document, selection);
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_GROUP,
"requote::group");
+ EvoUndoRedo.GroupTopRecords(2, inputEvent.inputType + "::requote");
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+ }
+ }
+ }
+
+ if ((!isInsertParagraph && inputEvent.inputType != "insertText") ||
+ (!(EvoEditor.MAGIC_LINKS && (isWordDelim || isInsertParagraph)) &&
+ !EvoEditor.MAGIC_SMILEYS)) {
+ return;
+ }
+
+ if (!selection.isCollapsed || !selection.anchorNode)
+ return;
+
+ var anchorNode = selection.anchorNode, parentElem;
+
+ if (anchorNode.nodeType != anchorNode.ELEMENT_NODE) {
+ parentElem = anchorNode.parentElement;
+
+ if (!parentElem)
+ return;
+ } else {
+ parentElem = anchorNode;
+ }
+
+ if (isInsertParagraph) {
+ parentElem = parentElem.previousElementSibling;
+
+ if (!parentElem)
+ return;
+
+ anchorNode = parentElem.lastChild;
+
+ if (!anchorNode || anchorNode.nodeType != anchorNode.TEXT_NODE)
+ return;
+ }
+
+ if (!anchorNode.nodeValue)
+ return;
+
+ var canLinks;
+
+ canLinks = EvoEditor.MAGIC_LINKS && (isWordDelim || isInsertParagraph);
+
+ var text = anchorNode.nodeValue, covered = false;
+
+ if (canLinks)
+ covered = EvoEditor.linkifyText(anchorNode, true);
+
+ if (!covered && EvoEditor.MAGIC_SMILEYS) {
+ var matches;
+
+ // the replace call below replaces (0xA0) with regular space
+ matches = EvoEditor.findSmileys(text.replace(/ /g, " "), EvoEditor.UNICODE_SMILEYS);
+ if (matches) {
+ var ii, sz = matches.length, node, tmpElement = null;
+
+ if (sz > 1)
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_GROUP, "magicSmiley");
+
+ try {
+ // they are ordered from the end already
+ for (ii = 0; ii < sz; ii++) {
+ var match = matches[ii];
+
+ if (!match.imageUri || EvoEditor.UNICODE_SMILEYS || EvoEditor.mode !=
EvoEditor.MODE_HTML) {
+ node = document.createTextNode(match.text);
+ } else {
+ if (!tmpElement)
+ tmpElement = document.createElement("SPAN");
+
+ tmpElement.innerHTML =
EvoEditor.createEmoticonHTML(match.text, match.imageUri, match.width, match.height);
+ node = tmpElement.firstChild;
+ }
+
+ anchorNode = EvoEditor.replaceMatchWithNode("magicSmiley",
anchorNode, match, node, sz == 1, true);
+ }
+ } finally {
+ if (sz > 1) {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_GROUP, "magicSmiley");
+ EvoUndoRedo.GroupTopRecords(2);
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+ }
+ }
+ }
+}
+
+EvoEditor.getParentElement = function(tagName, fromNode, canClimbUp)
+{
+ var node = fromNode;
+
+ if (!node)
+ node = document.getSelection().focusNode;
+
+ if (!node)
+ node = document.getSelection().anchorNode;
+
+ while (node && node.nodeType != node.ELEMENT_NODE) {
+ node = node.parentElement;
+ }
+
+ if (canClimbUp) {
+ while (node && node.tagName != tagName) {
+ node = node.parentElement;
+ }
+ }
+
+ if (node && node.tagName == tagName)
+ return node;
+
+ return null;
+}
+
+EvoEditor.storePropertiesSelection = function()
+{
+ EvoEditor.propertiesSelection = EvoSelection.Store(document);
+}
+
+EvoEditor.restorePropertiesSelection = function()
+{
+ if (EvoEditor.propertiesSelection) {
+ var selection = EvoEditor.propertiesSelection;
+
+ EvoEditor.propertiesSelection = null;
+
+ try {
+ // Ignore any errors here
+ EvoSelection.Restore(document, selection);
+ } catch (exception) {
+ }
+ }
+}
+
+// returns an array with affected elements, which can be passed to EvoEditor.RestoreCurrentElementAttr()
+EvoEditor.RemoveCurrentElementAttr = function()
+{
+ var nodes, ii, len, elems = [];
+
+ nodes = document.querySelectorAll("[" + EvoEditor.CURRENT_ELEMENT_ATTR + "]");
+ len = nodes ? nodes.length : 0;
+
+ for (ii = 0; ii < len; ii++) {
+ var elem = nodes[len - ii - 1];
+
+ elems[elems.length] = elem;
+ elem.removeAttribute(EvoEditor.CURRENT_ELEMENT_ATTR);
+ }
+
+ return elems;
+}
+
+EvoEditor.RestoreCurrentElementAttr = function(elemsArray)
+{
+ if (elemsArray) {
+ var ii;
+
+ for (ii = 0; ii < elemsArray.length; ii++) {
+ elemsArray[ii].setAttribute(EvoEditor.CURRENT_ELEMENT_ATTR, "1");
+ }
+ }
+}
+
+EvoEditor.getCurrentElement = function()
+{
+ return document.querySelector("[" + EvoEditor.CURRENT_ELEMENT_ATTR + "]");
+}
+
+EvoEditor.setCurrentElement = function(element)
+{
+ EvoEditor.RemoveCurrentElementAttr();
+
+ if (element)
+ element.setAttribute(EvoEditor.CURRENT_ELEMENT_ATTR, "1");
+}
+
+EvoEditor.OnDialogOpen = function(name)
+{
+ EvoEditor.propertiesSelection = null;
+
+ EvoEditor.RemoveCurrentElementAttr();
+
+ var node = null;
+
+ if (name == "link" || name == "cell" || name == "page") {
+ EvoEditor.storePropertiesSelection();
+
+ if (name == "cell") {
+ var tdnode, thnode;
+
+ tdnode = (EvoEditor.contextMenuNode && EvoEditor.contextMenuNode.tagName == "TD") ?
EvoEditor.contextMenuNode : EvoEditor.getParentElement("TD", null, false);
+ thnode = (EvoEditor.contextMenuNode && EvoEditor.contextMenuNode.tagName == "TH") ?
EvoEditor.contextMenuNode : EvoEditor.getParentElement("TH", null, false);
+
+ if (tdnode === EvoEditor.contextMenuNode) {
+ node = tdnode;
+ } else if (thnode === EvoEditor.contextMenuNode) {
+ node = thnode;
+ } else if (tdnode && thnode) {
+ for (node = thnode; node; node = node.parentElement) {
+ if (node === tdnode) {
+ // TH is a child of TD
+ node = thnode;
+ break;
+ }
+ }
+
+ if (!node)
+ node = tdnode;
+ } else {
+ node = tdnode ? tdnode : thnode;
+ }
+
+ if (node)
+ EvoEditor.setCurrentElement(node);
+ }
+
+ if (name == "cell" || name == "page")
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_GROUP, "Dialog::" + name);
+ } else if (name == "hrule" || name == "image" || name == "table") {
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_GROUP, "Dialog::" + name);
+
+ if (name == "hrule") {
+ node = (EvoEditor.contextMenuNode && EvoEditor.contextMenuNode.tagName == "HR") ?
EvoEditor.contextMenuNode : EvoEditor.getParentElement("HR", null, false);
+ } else if (name == "image") {
+ node = (EvoEditor.contextMenuNode && EvoEditor.contextMenuNode.tagName == "IMG") ?
EvoEditor.contextMenuNode : EvoEditor.getParentElement("IMG", null, false);
+ } else if (name == "table") {
+ node = (EvoEditor.contextMenuNode && EvoEditor.contextMenuNode.tagName == "TABLE") ?
EvoEditor.contextMenuNode : EvoEditor.getParentElement("TABLE", null, true);
+ }
+
+ if (node) {
+ EvoEditor.setCurrentElement(node);
+ } else {
+ if (name == "hrule")
+ EvoEditor.InsertHTML("CreateHRule", "<HR " + EvoEditor.CURRENT_ELEMENT_ATTR +
"=\"1\">");
+ else if (name == "image")
+ EvoEditor.InsertHTML("CreateImage", "<IMG " + EvoEditor.CURRENT_ELEMENT_ATTR
+ "=\"1\">");
+ else if (name == "table")
+ EvoEditor.InsertHTML("CreateTable", "<TABLE " +
EvoEditor.CURRENT_ELEMENT_ATTR + "=\"1\"></TABLE>");
+ }
+ }
+
+ node = EvoEditor.getCurrentElement();
+
+ if (node && name != "table" && name != "cell" && name != "image") {
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_EVENT, "Dialog::" + name + "::event", node,
node,
+ EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ EvoUndoRedo.Disable();
+ }
+}
+
+EvoEditor.OnDialogClose = function(name)
+{
+ if (name == "link" || name == "cell")
+ EvoEditor.restorePropertiesSelection();
+ else
+ EvoEditor.propertiesSelection = null;
+
+ EvoEditor.contextMenuNode = null;
+
+ var node = EvoEditor.getCurrentElement();
+
+ EvoEditor.RemoveCurrentElementAttr();
+
+ if (node && name != "table" && name != "cell" && name != "image") {
+ EvoUndoRedo.Enable();
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_EVENT, "Dialog::" + name + "::event");
+ }
+
+ if (name == "hrule" || name == "image" || name == "table" || name == "cell" || name == "page")
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_GROUP, "Dialog::" + name);
+}
+
+EvoEditor.applySetAttribute = function(record, isUndo)
+{
+ var element = EvoSelection.FindElementByPath(document.body, record.path);
+
+ if (!element)
+ throw "EvoEditor.applySetAttribute: Path not found";
+
+ var value;
+
+ if (isUndo)
+ value = record.beforeValue;
+ else
+ value = record.afterValue;
+
+ if (value == null)
+ element.removeAttribute(record.attrName);
+ else
+ element.setAttribute(record.attrName, value);
+}
+
+EvoEditor.setAttributeWithUndoRedo = function(opTypePrefix, element, name, value)
+{
+ if (!element)
+ return false;
+
+ if ((value == null && !element.hasAttribute(name)) ||
+ (value != null && value == element.getAttribute(name)))
+ return false;
+
+ var record = EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, opTypePrefix + "::" + name,
element, element, EvoEditor.CLAIM_CONTENT_FLAG_NONE);
+
+ try {
+ if (record) {
+ record.path = EvoSelection.GetChildPath(document.body, element);
+ record.attrName = name;
+ record.beforeValue = element.hasAttribute(name) ? element.getAttribute(name) : null;
+ record.afterValue = value;
+ record.apply = EvoEditor.applySetAttribute;
+ }
+
+ if (value == null) {
+ element.removeAttribute(name);
+ } else {
+ element.setAttribute(name, value);
+ }
+
+ if (record && record.beforeValue == record.afterValue) {
+ record.ignore = true;
+ }
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, opTypePrefix + "::" + name);
+
+ if (!EvoUndoRedo.IsRecording()) {
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+ }
+
+ return true;
+}
+
+EvoEditor.addElementWithUndoRedo = function(opType, tagName, fillNodeFunc, parent, insertBefore,
contentArray)
+{
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, opType, parent, parent,
EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ try {
+ var selectionUpdater = EvoSelection.CreateUpdaterObject(), node;
+
+ node = document.createElement(tagName);
+
+ if (fillNodeFunc)
+ fillNodeFunc(node);
+
+ parent.insertBefore(node, insertBefore);
+
+ if (contentArray) {
+ var ii;
+
+ for (ii = 0; ii < contentArray.length; ii++) {
+ node.append(contentArray[ii]);
+ }
+ }
+
+ selectionUpdater.restore();
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, opType);
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+}
+
+EvoEditor.removeElementWithUndoRedo = function(opType, element)
+{
+ if (element) {
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, opType, element.parentElement,
element.parentElement, EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ try {
+ var selectionUpdater = EvoSelection.CreateUpdaterObject(), firstChild;
+
+ firstChild = element.firstChild;
+
+ while (element.firstChild) {
+ element.parentElement.insertBefore(element.firstChild, element);
+ }
+
+ selectionUpdater.beforeRemove(element);
+ element.remove();
+ selectionUpdater.afterRemove(firstChild);
+
+ selectionUpdater.restore();
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, opType);
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+ }
+}
+
+// 'value' can be 'null', to remove the attribute
+EvoEditor.DialogUtilsSetAttribute = function(selector, name, value)
+{
+ var element;
+
+ if (selector)
+ element = document.querySelector(selector);
+ else
+ element = EvoEditor.getCurrentElement();
+
+ if (element) {
+ EvoEditor.setAttributeWithUndoRedo("DlgUtilsSetAttribute", element, name, value);
+ }
+}
+
+EvoEditor.DialogUtilsGetAttribute = function(selector, name)
+{
+ var element;
+
+ if (selector)
+ element = document.querySelector(selector);
+ else
+ element = EvoEditor.getCurrentElement();
+
+ if (element && element.hasAttribute(name))
+ return element.getAttribute(name);
+
+ return null;
+}
+
+EvoEditor.DialogUtilsHasAttribute = function(name)
+{
+ var element = EvoEditor.getCurrentElement();
+
+ return element && element.hasAttribute(name);
+}
+
+EvoEditor.LinkGetProperties = function()
+{
+ var res = null, anchor = EvoEditor.getParentElement("A", null, false);
+
+ if (anchor) {
+ res = [];
+ res["href"] = anchor.href;
+ res["text"] = anchor.innerText;
+ } else if (!document.getSelection().isCollapsed && document.getSelection().rangeCount > 0) {
+ var range;
+
+ range = document.getSelection().getRangeAt(0);
+
+ if (range) {
+ res = [];
+ res["text"] = range.toString();
+ }
+ }
+
+ return res;
+}
+
+EvoEditor.LinkSetProperties = function(href, text)
+{
+ // The properties dialog can discard selection, thus restore it before doing changes
+ EvoEditor.restorePropertiesSelection();
+
+ var anchor = EvoEditor.getParentElement("A", null, false);
+
+ if (anchor && (anchor.href != href || anchor.innerText != text)) {
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "SetLinkValues", anchor, anchor,
EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ try {
+ if (anchor.href != href)
+ anchor.href = href;
+ if (anchor.innerText != text) {
+ var selection = EvoSelection.Store(document);
+ anchor.innerText = text;
+ EvoSelection.Restore(document, selection);
+ }
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "SetLinkValues");
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+ } else if (!anchor && href != "" && text != "") {
+ text = text.replace(/\&/g, "&").replace(/</g, "<").replace(/>/g, ">");
+ href = href.replace(/\&/g, "&").replace(/\"/g, """);
+
+ EvoEditor.InsertHTML("CreateLink", "<A href=\"" + href + "\">" + text + "</A>");
+ }
+}
+
+EvoEditor.Unlink = function()
+{
+ // The properties dialog can discard selection, thus restore it before doing changes
+ EvoEditor.restorePropertiesSelection();
+
+ var anchor = EvoEditor.getParentElement("A", null, false);
+
+ EvoEditor.removeElementWithUndoRedo("Unlink", anchor);
+}
+
+EvoEditor.ReplaceImageSrc = function(selector, uri)
+{
+ if (!selector)
+ selector = "#x-evo-dialog-current-element";
+
+ var element = document.querySelector(selector);
+
+ if (element) {
+ if (uri) {
+ var attrName;
+
+ if (element.tagName == "IMG")
+ attrName = "src";
+ else
+ attrName = "background";
+
+ EvoEditor.setAttributeWithUndoRedo("ReplaceImageSrc", element, attrName, uri);
+ } else {
+ if (element.tagName == "IMG") {
+ EvoEditor.removeElementWithUndoRedo("ReplaceImageSrc", element);
+ } else {
+ EvoEditor.setAttributeWithUndoRedo("ReplaceImageSrc", element, "background",
null);
+ }
+ }
+ }
+}
+
+EvoEditor.DialogUtilsSetImageUrl = function(href)
+{
+ var element = EvoEditor.getCurrentElement();
+
+ if (element && element.tagName == "IMG") {
+ var anchor = EvoEditor.getParentElement("A", element, true);
+
+ if (anchor) {
+ if (href && anchor.href != href) {
+ EvoEditor.setAttributeWithUndoRedo("DialogUtilsSetImageUrl", anchor, "href",
href);
+ } else if (!href) {
+ EvoEditor.removeElementWithUndoRedo("DialogUtilsSetImageUrl::unset", element);
+ }
+ } else if (href) {
+ var fillHref = function(node) {
+ node.href = href;
+ };
+
+ EvoEditor.addElementWithUndoRedo("DialogUtilsSetImageUrl", "A", fillHref,
element.parentElement, element, [ element ]);
+ }
+ }
+}
+
+EvoEditor.DialogUtilsGetImageUrl = function()
+{
+ var element = EvoEditor.getCurrentElement(), res = null;
+
+ if (element && element.tagName == "IMG") {
+ var anchor = EvoEditor.getParentElement("A", element, true);
+
+ if (anchor)
+ res = anchor.href;
+ }
+
+ return res;
+}
+
+EvoEditor.DialogUtilsGetImageWidth = function(natural)
+{
+ var element = EvoEditor.getCurrentElement(), res = -1;
+
+ if (element && element.tagName == "IMG") {
+ if (natural)
+ res = element.naturalWidth;
+ else
+ res = element.width;
+ }
+
+ return res;
+}
+
+EvoEditor.DialogUtilsGetImageHeight = function(natural)
+{
+ var element = EvoEditor.getCurrentElement(), res = -1;
+
+ if (element && element.tagName == "IMG") {
+ if (natural)
+ res = element.naturalHeight;
+ else
+ res = element.height;
+ }
+
+ return res;
+}
+
+EvoEditor.dialogUtilsForeachTableScope = function(scope, traversar, opType)
+{
+ var cell = EvoEditor.getCurrentElement();
+
+ if (!cell)
+ throw "EvoEditor.dialogUtilsForeachTableScope: Current cell not found";
+
+ traversar.selectionUpdater = EvoSelection.CreateUpdaterObject();
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_GROUP, opType);
+
+ try {
+ var table = EvoEditor.getParentElement("TABLE", cell, true);
+
+ var rowFunc = function(row, traversar) {
+ var jj, length = row.cells.length;
+
+ for (jj = 0; jj < length; jj++) {
+ var cell = row.cells[length - jj - 1];
+
+ if (cell && !traversar.exec(cell))
+ return false;
+ }
+
+ return true;
+ };
+
+ if (scope == EvoEditor.E_CONTENT_EDITOR_SCOPE_CELL) {
+ traversar.exec(cell);
+ } else if (scope == EvoEditor.E_CONTENT_EDITOR_SCOPE_COLUMN) {
+ if (table) {
+ var length = table.rows.length, ii, cellIndex = cell.cellIndex;
+
+ for (ii = 0; ii < length; ii++) {
+ var row = table.rows[length - ii - 1];
+
+ if (row && cellIndex < row.cells.length &&
+ !traversar.exec(row.cells[cellIndex]))
+ break;
+ }
+ }
+ } else if (scope == EvoEditor.E_CONTENT_EDITOR_SCOPE_ROW) {
+ var row = EvoEditor.getParentElement("TR", cell, true);
+
+ if (row)
+ rowFunc(row, traversar);
+ } else if (scope == EvoEditor.E_CONTENT_EDITOR_SCOPE_TABLE) {
+ if (table) {
+ var length = table.rows.length, ii;
+
+ for (ii = 0; ii < length; ii++) {
+ if (!rowFunc(table.rows[length - ii - 1], traversar))
+ break;
+ }
+ }
+ }
+
+ try {
+ traversar.selectionUpdater.restore();
+ } catch (ex) {
+ }
+
+ EvoEditor.dialogUtilsTableEnsureCurrentElement(table);
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_GROUP, opType);
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+
+ if (traversar.anyChanged)
+ EvoEditor.EmitContentChanged();
+ }
+
+ traversar.selectionUpdater = null;
+}
+
+EvoEditor.DialogUtilsTableSetAttribute = function(scope, attrName, attrValue)
+{
+ var traversar = {
+ attrName : attrName,
+ attrValue : attrValue,
+ anyChanged : false,
+
+ exec : function(cell) {
+ if (EvoEditor.setAttributeWithUndoRedo("", cell, this.attrName, this.attrValue))
+ this.anyChanged = true;
+
+ return true;
+ }
+ };
+
+ EvoEditor.dialogUtilsForeachTableScope(scope, traversar, "TableSetAttribute::" + attrName);
+}
+
+EvoEditor.DialogUtilsTableGetCellIsHeader = function()
+{
+ var element = EvoEditor.getCurrentElement();
+
+ return element && element.tagName == "TH";
+}
+
+EvoEditor.DialogUtilsTableSetHeader = function(scope, isHeader)
+{
+ var traversar = {
+ isHeader : isHeader,
+ selectionUpdater : null,
+ anyChanged : false,
+
+ exec : function(cell) {
+ if ((!this.isHeader && cell.tagName == "TD") ||
+ (this.isHeader && cell.tagName == "TH"))
+ return;
+
+ this.anyChanged = true;
+
+ var opType = this.isHeader ? "unsetheader" : "setheader";
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, opType, cell, cell,
+ EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE |
EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ try {
+ var node = document.createElement(this.isHeader ? "TH" : "TD");
+
+ while(cell.firstChild) {
+ node.append(cell.firstChild);
+ }
+
+ var ii;
+
+ for (ii = 0; ii < cell.attributes.length; ii++) {
+ node.setAttribute(cell.attributes[ii].name,
cell.attributes[ii].value);
+ }
+
+ cell.parentElement.insertBefore(node, cell);
+
+ if (this.selectionUpdater)
+ this.selectionUpdater.beforeRemove(cell);
+
+ cell.remove();
+
+ if (this.selectionUpdater)
+ this.selectionUpdater.afterRemove(node);
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, opType);
+ }
+
+ return true;
+ }
+ };
+
+ EvoEditor.dialogUtilsForeachTableScope(scope, traversar, "DialogUtilsTableSetHeader");
+}
+
+EvoEditor.DialogUtilsTableGetRowCount = function()
+{
+ var element = EvoEditor.getCurrentElement();
+
+ if (!element)
+ return 0;
+
+ element = EvoEditor.getParentElement("TABLE", element, true);
+
+ if (!element)
+ return 0;
+
+ return element.rows.length;
+}
+
+EvoEditor.dialogUtilsTableEnsureCurrentElement = function(table)
+{
+ if (table && !EvoEditor.getCurrentElement() && table.rows.length > 0) {
+ EvoEditor.setCurrentElement(table.rows[0].cells.length > 0 ? table.rows[0].cells[0] : table);
+ }
+}
+
+EvoEditor.DialogUtilsTableSetRowCount = function(rowCount)
+{
+ var currentElem = EvoEditor.getCurrentElement();
+
+ if (!currentElem)
+ return;
+
+ var table = EvoEditor.getParentElement("TABLE", currentElem, true);
+
+ if (!table || table.rows.length == rowCount)
+ return;
+
+ var selectionUpdater = EvoSelection.CreateUpdaterObject();
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "DialogUtilsTableSetRowCount", table, table,
EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+
+ try {
+ var ii;
+
+ if (table.rows.length < rowCount) {
+ var jj, nCells = table.rows.length ? table.rows[0].cells.length : 1;
+
+ for (ii = table.rows.length; ii < rowCount; ii++) {
+ var row;
+
+ row = table.insertRow(-1);
+
+ for (jj = 0; jj < nCells; jj++) {
+ row.insertCell(-1);
+ }
+ }
+ } else if (table.rows.length > rowCount) {
+ for (ii = table.rows.length; ii > rowCount; ii--) {
+ table.deleteRow(ii - 1);
+ }
+ }
+
+ try {
+ // it can fail, due to removed rows
+ selectionUpdater.restore();
+ } catch (ex) {
+ }
+
+ EvoEditor.dialogUtilsTableEnsureCurrentElement(table);
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "DialogUtilsTableSetRowCount");
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+}
+
+EvoEditor.DialogUtilsTableGetColumnCount = function()
+{
+ var element = EvoEditor.getCurrentElement();
+
+ if (!element)
+ return 0;
+
+ element = EvoEditor.getParentElement("TABLE", element, true);
+
+ if (!element || !element.rows.length)
+ return 0;
+
+ return element.rows[0].cells.length;
+}
+
+EvoEditor.DialogUtilsTableSetColumnCount = function(columnCount)
+{
+ var currentElem = EvoEditor.getCurrentElement();
+
+ if (!currentElem)
+ return;
+
+ var table = EvoEditor.getParentElement("TABLE", currentElem, true);
+
+ if (!table || !table.rows.length || table.rows[0].cells.length == columnCount)
+ return;
+
+ var selectionUpdater = EvoSelection.CreateUpdaterObject();
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "DialogUtilsTableSetColumnCount", table,
table, EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+
+ try {
+ var ii, jj;
+
+ for (jj = 0; jj < table.rows.length; jj++) {
+ var row = table.rows[jj];
+
+ if (row.cells.length < columnCount) {
+ for (ii = row.cells.length; ii < columnCount; ii++) {
+ row.insertCell(-1);
+ }
+ } else if (row.cells.length > columnCount) {
+ for (ii = row.cells.length; ii > columnCount; ii--) {
+ row.deleteCell(ii - 1);
+ }
+ }
+ }
+
+ try {
+ // it can fail, due to removed columns
+ selectionUpdater.restore();
+ } catch (ex) {
+ }
+
+ EvoEditor.dialogUtilsTableEnsureCurrentElement(table);
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "DialogUtilsTableSetColumnCount");
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+}
+
+EvoEditor.DialogUtilsTableDeleteCellContent = function()
+{
+ var traversar = {
+ anyChanged : false,
+
+ exec : function(cell) {
+ if (cell.firstChild) {
+ this.anyChanged = true;
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM,
"subdeletecellcontent", cell, cell, EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ try {
+ while (cell.firstChild) {
+ if (this.selectionUpdater)
+ this.selectionUpdater.beforeRemove(cell.firstChild);
+
+ cell.removeChild(cell.firstChild);
+
+ if (this.selectionUpdater)
+ this.selectionUpdater.afterRemove(cell);
+ }
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM,
"subdeletecellcontent");
+ }
+ }
+
+ return true;
+ }
+ };
+
+ EvoEditor.dialogUtilsForeachTableScope(EvoEditor.E_CONTENT_EDITOR_SCOPE_CELL, traversar,
"TableDeleteCellContent");
+}
+
+EvoEditor.DialogUtilsTableDeleteColumn = function()
+{
+ var traversar = {
+ anyChanged : false,
+
+ exec : function(cell) {
+ this.anyChanged = true;
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "subdeletecolumn", cell, cell,
+ EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE |
EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ try {
+ if (this.selectionUpdater) {
+ this.selectionUpdater.beforeRemove(cell);
+ this.selectionUpdater.afterRemove(cell.nextElementSibling ?
cell.nextElementSibling : cell.previousElementSibling);
+ }
+
+ cell.remove();
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "subdeletecolumn");
+ }
+
+ return true;
+ }
+ };
+
+ EvoEditor.dialogUtilsForeachTableScope(EvoEditor.E_CONTENT_EDITOR_SCOPE_COLUMN, traversar,
"TableDeleteColumn");
+}
+
+EvoEditor.DialogUtilsTableDeleteRow = function()
+{
+ var traversar = {
+ anyChanged : false,
+
+ exec : function(cell) {
+ this.anyChanged = true;
+
+ var row = cell.parentElement;
+
+ if (!row)
+ return false;
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "subdeleterow", row, row,
+ EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ try {
+ row.parentElement.deleteRow(row.rowIndex);
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "subdeleterow");
+ }
+
+ return false;
+ }
+ };
+
+ EvoEditor.dialogUtilsForeachTableScope(EvoEditor.E_CONTENT_EDITOR_SCOPE_ROW, traversar,
"TableDeleteColumn");
+}
+
+EvoEditor.DialogUtilsTableDelete = function()
+{
+ var element = EvoEditor.getCurrentElement();
+
+ if (!element)
+ return;
+
+ element = EvoEditor.getParentElement("TABLE", element, true);
+
+ if (!element)
+ return;
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "TableDelete", element, element,
+ EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE | EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ try {
+ element.remove();
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "TableDelete");
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+}
+
+// 'what' can be "column" or "row",
+// 'where' can be lower than 0 for before/above, higher than 0 for after/below
+EvoEditor.DialogUtilsTableInsert = function(what, where)
+{
+ if (what != "column" && what != "row")
+ throw "EvoEditor.DialogUtilsTableInsert: 'what' (" + what + ") can be only 'column' or 'row'";
+ if (!where)
+ throw "EvoEditor.DialogUtilsTableInsert: 'where' cannot be zero";
+
+ var cell, table;
+
+ cell = EvoEditor.getCurrentElement();
+
+ if (!cell)
+ return;
+
+ table = EvoEditor.getParentElement("TABLE", cell, true);
+
+ if (!table)
+ return;
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "TableInsert::" + what, table, table,
+ EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE | EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ try {
+ var index, ii;
+
+ if (what == "column") {
+ index = cell.cellIndex;
+
+ if (where > 0)
+ index++;
+
+ for (ii = 0; ii < table.rows.length; ii++) {
+ table.rows[ii].insertCell(index <= table.rows[ii].cells.length ? index : -1);
+ }
+ } else { // what == "row"
+ var row = EvoEditor.getParentElement("TR", cell, true);
+
+ if (row) {
+ index = row.rowIndex;
+
+ if (where > 0)
+ index++;
+
+ row = table.insertRow(index <= table.rows.length ? index : -1);
+
+ for (ii = 0; ii < table.rows[0].cells.length; ii++) {
+ row.insertCell(-1);
+ }
+ }
+ }
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "TableInsert::" + what);
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+}
+
+EvoEditor.GetCaretWord = function()
+{
+ if (document.getSelection().rangeCount < 1)
+ return null;
+
+ var range = document.getSelection().getRangeAt(0);
+
+ if (!range)
+ return null;
+
+ range = range.cloneRange();
+ range.expand("word");
+
+ return range.toString();
+}
+
+EvoEditor.replaceSelectionWord = function(opType, expandWord, replacement)
+{
+ if (!expandWord && document.getSelection().isCollapsed)
+ return;
+
+ if (document.getSelection().rangeCount < 1)
+ return;
+
+ var range = document.getSelection().getRangeAt(0);
+
+ if (!range)
+ return;
+
+ if (expandWord)
+ range.expand("word");
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_EVENT, opType, null, null,
EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE | EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ try {
+ var fragment = range.extractContents(), node;
+
+ /* Get the text node to replace and leave other formatting nodes
+ * untouched (font color, boldness, ...). */
+ fragment.normalize();
+
+ for (node = fragment.firstChild; node && node.nodeType != node.TEXT_NODE; node =
node.firstChild) {
+ ;
+ }
+
+ if (node && node.nodeType == node.TEXT_NODE && replacement) {
+ var text;
+
+ /* Replace the word */
+ text = document.createTextNode(replacement);
+ node.parentNode.replaceChild(text, node);
+
+ /* Insert the word on current location. */
+ range.insertNode(fragment);
+
+ document.getSelection().setPosition(text, replacement ? replacement.length : 0);
+ }
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_EVENT, opType);
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+}
+
+EvoEditor.ReplaceCaretWord = function(replacement)
+{
+ EvoEditor.replaceSelectionWord("ReplaceCaretWord", true, replacement);
+}
+
+EvoEditor.ReplaceSelection = function(replacement)
+{
+ EvoEditor.replaceSelectionWord("ReplaceSelection", false, replacement);
+}
+
+EvoEditor.SpellCheckContinue = function(fromCaret, directionNext)
+{
+ var selection, storedSelection = null;
+
+ selection = document.getSelection();
+
+ if (fromCaret) {
+ storedSelection = EvoSelection.Store(document);
+ } else {
+ if (directionNext) {
+ selection.modify("move", "left", "documentboundary");
+ } else {
+ selection.modify ("move", "right", "documentboundary");
+ selection.modify ("extend", "backward", "word");
+ }
+ }
+
+ var selectWord = function(selection, directionNext) {
+ var anchorNode, anchorOffset;
+
+ anchorNode = selection.anchorNode;
+ anchorOffset = selection.anchorOffset;
+
+ if (directionNext) {
+ var focusNode, focusOffset;
+
+ focusNode = selection.focusNode;
+ focusOffset = selection.focusOffset;
+
+ /* Jump _behind_ next word */
+ selection.modify("move", "forward", "word");
+ /* Jump before the word */
+ selection.modify("move", "backward", "word");
+ /* Select it */
+ selection.modify("extend", "forward", "word");
+
+ /* If the selection didn't change, then we have most probably reached the end of the
document. */
+ return !((anchorNode === selection.anchorNode) &&
+ (anchorOffset == selection.anchorOffset) &&
+ (focusNode === selection.focusNode) &&
+ (focusOffset == selection.focusOffset));
+ } else {
+ /* Jump on the beginning of current word */
+ selection.modify("move", "backward", "word");
+ /* Jump before previous word */
+ selection.modify("move", "backward", "word");
+ /* Select it */
+ selection.modify("extend", "forward", "word");
+
+ /* If the selection start didn't change, then we have most probably reached the
beginning of the document. */
+ return (!(anchorNode === selection.anchorNode)) ||
+ (anchorOffset != selection.anchorOffset);
+ }
+ };
+
+ while (selectWord(selection, directionNext)) {
+ if (selection.rangeCount < 1)
+ break;
+
+ var range = selection.getRangeAt(0);
+
+ if (!range)
+ break;
+
+ var word = range.toString();
+
+ if (!EvoEditor.SpellCheckWord(word)) {
+ /* Found misspelled word */
+ return word;
+ }
+ }
+
+ /* Restore the selection to contain the last misspelled word. This is
+ * reached only when we reach the beginning/end of the document */
+ if (storedSelection)
+ EvoSelection.Restore(document, storedSelection);
+
+ return null;
+}
+
+EvoEditor.MoveSelectionToPoint = function(xx, yy, cancel_if_not_collapsed)
+{
+ if (!cancel_if_not_collapsed || document.getSelection().isCollapsed) {
+ var range = document.caretRangeFromPoint(xx, yy);
+
+ document.getSelection().removeAllRanges();
+ document.getSelection().addRange(range);
+ }
+}
+
+EvoEditor.createEmoticonHTML = function(text, imageUri, width, height)
+{
+ if (imageUri.toLowerCase().startsWith("file:"))
+ imageUri = "evo-" + imageUri;
+
+ if (imageUri && EvoEditor.mode == EvoEditor.MODE_HTML && !EvoEditor.UNICODE_SMILEYS)
+ return "<img src=\"" + imageUri + "\" alt=\"" +
+ text.replace(/\&/g, "&").replace(/\"/g, """).replace(/\'/g, "'") +
+ "\" width=\"" + width + "px\" height=\"" + height + "px\">";
+
+ return text;
+}
+
+EvoEditor.InsertEmoticon = function(text, imageUri, width, height)
+{
+ EvoEditor.InsertHTML("InsertEmoticon", EvoEditor.createEmoticonHTML(text, imageUri, width, height));
+}
+
+EvoEditor.InsertImage = function(imageUri, width, height)
+{
+ if (imageUri.toLowerCase().startsWith("file:"))
+ imageUri = "evo-" + imageUri;
+
+ var html = "<img src=\"" + imageUri + "\"";
+
+ if (width > 0 && height > 0) {
+ html += " width=\"" + width + "px\" height=\"" + height + "px\"";
+ }
+
+ html += ">";
+
+ EvoEditor.InsertHTML("InsertImage", html);
+}
+
+EvoEditor.GetCurrentSignatureUid = function()
+{
+ var elem = document.querySelector(".-x-evo-signature[id]");
+
+ if (elem)
+ return elem.id;
+
+ return "";
+}
+
+EvoEditor.removeUnwantedTags = function(parent)
+{
+ if (!parent)
+ return;
+
+ var child, next = null;
+
+ for (child = parent.firstChild; child; child = next) {
+ next = child.nextSibling;
+
+ if (child.tagName == "STYLE" ||
+ child.tagName == "META")
+ child.remove();
+ }
+}
+
+EvoEditor.InsertSignature = function(content, isHTML, uid, fromMessage, checkChanged, ignoreNextChange,
startBottom, topSignature, addDelimiter)
+{
+ var sigSpan, node, scrollX, scrollY;
+
+ scrollX = window.scrollX;
+ scrollY = window.scrollY;
+
+ sigSpan = document.createElement("SPAN");
+ sigSpan.className = "-x-evo-signature";
+ sigSpan.id = uid;
+
+ if (content) {
+ if (isHTML && EvoEditor.mode != EvoEditor.MODE_HTML) {
+ node = document.createElement("SPAN");
+ node.innerHTML = content;
+
+ EvoEditor.removeUnwantedTags(node);
+
+ content = EvoConvert.ToPlainText(node, EvoEditor.NORMAL_PARAGRAPH_WIDTH);
+ if (content != "") {
+ content = "<PRE>" + content.replace(/\&/g, "&").replace(/</g,
"<").replace(/>/g, ">") + "</PRE>";
+ }
+
+ isHTML = false;
+ }
+
+ /* The signature dash convention ("-- \n") is specified
+ * in the "Son of RFC 1036", section 4.3.2.
+ * http://www.chemie.fu-berlin.de/outerspace/netnews/son-of-1036.html
+ */
+ if (addDelimiter) {
+ var found;
+
+ if (isHTML) {
+ found = content.substr(0, 8).toUpperCase().startsWith("-- <BR>") ||
content.match(/\n-- <BR>/i) != null;
+ } else {
+ found = content.startsWith("-- \n") || content.match(/\n-- \n/i) != null;
+ }
+
+ /* Skip the delimiter if the signature already has one. */
+ if (!found) {
+ /* Always use the HTML delimiter as we are never in anything
+ * like a strict plain text mode. */
+ node = document.createElement("PRE");
+ node.innerHTML = "-- <BR>";
+ sigSpan.appendChild(node);
+ }
+ }
+
+ sigSpan.insertAdjacentHTML("beforeend", content);
+
+ node = sigSpan.querySelector("[data-evo-signature-plain-text-mode]");
+ if (node)
+ node.removeAttribute("[data-evo-signature-plain-text-mode]");
+
+ node = sigSpan.querySelector("#-x-evo-selection-start-marker");
+ if (node)
+ node.remove();
+
+ node = sigSpan.querySelector("#-x-evo-selection-end-marker");
+ if (node)
+ node.remove();
+
+ EvoEditor.removeUnwantedTags(sigSpan);
+ }
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_GROUP, "InsertSignature");
+ try {
+ var signatures, ii, done = false, useWrapper = null;
+
+ signatures = document.getElementsByClassName("-x-evo-signature-wrapper");
+ for (ii = signatures.length; ii-- && !done;) {
+ var wrapper, signature;
+
+ wrapper = signatures[ii];
+ signature = wrapper.firstElementChild;
+
+ /* When we are editing a message with signature, we need to unset the
+ * active signature id as if the signature in the message was edited
+ * by the user we would discard these changes. */
+ if (fromMessage && content && signature) {
+ if (checkChanged) {
+ /* Normalize the signature that we want to insert as the one in the
+ * message already is normalized. */
+ webkit_dom_node_normalize (WEBKIT_DOM_NODE (signature_to_insert));
+ if (!webkit_dom_node_is_equal_node (WEBKIT_DOM_NODE
(signature_to_insert), signature)) {
+ /* Signature in the body is different than the one with the
+ * same id, so set the active signature to None and leave
+ * the signature that is in the body. */
+ uid = "none";
+ ignoreNextChange = true;
+ }
+
+ checkChanged = false;
+ fromMessage = false;
+ } else {
+ /* Old messages will have the signature id in the name attribute,
correct it. */
+ if (signature.hasAttribute("name")) {
+ id = signature.getAttribute("name");
+ signature.id = id;
+ signature.removeAttribute(name);
+ } else {
+ id = signature.id;
+ }
+
+ /* Keep the signature and check if is it the same
+ * as the signature in body or the user previously
+ * changed it. */
+ checkChanged = true;
+ }
+
+ done = true;
+ } else {
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM,
"InsertSignature::old-changes", wrapper, wrapper,
+ EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML |
EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE);
+ try {
+ /* If the top signature was set we have to remove the newline
+ * that was inserted after it */
+ if (topSignature) {
+ node = document.querySelector(".-x-evo-top-signature-spacer");
+ if (node && (!node.firstChild || !node.textContent ||
+ (node.childNodes.length == 1 && node.firstChild.tagName
== "BR"))) {
+ node.remove();
+ }
+ }
+
+ /* Leave just one signature wrapper there as it will be reused. */
+ if (ii) {
+ wrapper.remove();
+ } else {
+ wrapper.removeChild(signature);
+ useWrapper = wrapper;
+ }
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM,
"InsertSignature::old-changes");
+ }
+ }
+ }
+
+ if (!done) {
+ if (useWrapper) {
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM,
"InsertSignature::new-changes", useWrapper, useWrapper, EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ try {
+ useWrapper.appendChild(sigSpan);
+
+ /* Insert a spacer below the top signature */
+ if (topSignature && content) {
+ node = document.createElement("DIV");
+ node.appendChild(document.createElement("BR"));
+ node.className = "-x-evo-top-signature-spacer";
+
+ document.body.insertBefore(node, useWrapper.nextSibling);
+
+ EvoEditor.maybeUpdateParagraphWidth(node);
+ }
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM,
"InsertSignature::new-changes");
+ }
+ } else {
+ useWrapper = document.createElement("DIV");
+ useWrapper.className = "-x-evo-signature-wrapper";
+ useWrapper.appendChild(sigSpan);
+
+ EvoEditor.maybeUpdateParagraphWidth(useWrapper);
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM,
"InsertSignature::new-changes", document.body, document.body, EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ try {
+ if (topSignature) {
+ document.body.insertBefore(useWrapper,
document.body.firstChild);
+
+ node = document.createElement("DIV");
+ node.appendChild(document.createElement("BR"));
+ node.className = "-x-evo-top-signature-spacer";
+
+ document.body.insertBefore(node, useWrapper.nextSibling);
+ } else {
+ document.body.appendChild(useWrapper);
+ }
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM,
"InsertSignature::new-changes");
+ }
+ }
+
+ fromMessage = false;
+
+ // Position the caret and scroll to it
+ if (startBottom) {
+ if (topSignature) {
+ document.getSelection().setPosition(document.body.lastChild, 0);
+ } else if (useWrapper.previousSibling) {
+ document.getSelection().setPosition(useWrapper.previousSibling, 0);
+ } else {
+ document.getSelection().setPosition(useWrapper, 0);
+ }
+ } else {
+ document.getSelection().setPosition(document.body.firstChild, 0);
+ }
+
+ node = document.getSelection().anchorNode;
+
+ if (node) {
+ if (node.nodeType != node.ELEMENT_NODE)
+ node = node.parentElement;
+
+ if (node && node.scrollIntoViewIfNeeded != undefined)
+ node.scrollIntoViewIfNeeded();
+ }
+ }
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_GROUP, "InsertSignature");
+ }
+
+ // the above changes can cause change of the scroll offset, thus restore it
+ window.scrollTo(scrollX, scrollY);
+
+ var res = [];
+
+ res["fromMessage"] = fromMessage;
+ res["checkChanged"] = checkChanged;
+ res["ignoreNextChange"] = ignoreNextChange;
+ res["newUid"] = uid;
+
+ return res;
+}
+
+EvoEditor.isEmptyParagraph = function(node)
+{
+ if (!node || !EvoEditor.IsBlockNode(node))
+ return false;
+
+ return !node.children.length || (node.children.length == 1 && node.children[0].tagName == "BR");
+}
+
+// replaces current selection with the plain text or HTML, quoted or normal DIV
+EvoEditor.InsertContent = function(text, isHTML, quote)
+{
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_GROUP, "InsertContent");
+ try {
+ if (!document.getSelection().isCollapsed) {
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "InsertContent::sel-remove",
null, null,
+ EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE |
EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ try {
+ document.getSelection().deleteFromDocument();
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM,
"InsertContent::sel-remove");
+ }
+ }
+
+ var wasPlain = !isHTML;
+ var content = document.createElement(quote ? "BLOCKQUOTE" : "DIV");
+
+ if (quote) {
+ content.setAttribute("type", "cite");
+ }
+
+ if (isHTML) {
+ content.innerHTML = text;
+
+ // paste can contain <meta> elements, like the one with Content-Type, which can be
removed
+ while (content.firstElementChild && content.firstElementChild.tagName == "META") {
+ content.removeChild(content.firstElementChild);
+ }
+
+ // remove comments at the beginning, like the Evolution's "<!-- text/html -->"
+ while (content.firstChild && content.firstChild.nodeType ==
content.firstChild.COMMENT_NODE) {
+ content.removeChild(content.firstChild);
+ }
+
+ // convert P into DIV
+ var node = content.firstChild, next;
+
+ while (node) {
+ var removeNode = false;
+
+ if (node.nodeType == node.ELEMENT_NODE && node.tagName == "P") {
+ removeNode = true;
+
+ if (node.tagName == "P") {
+ var div = document.createElement("DIV");
+ EvoEditor.moveNodeContent(node, div);
+ node.parentElement.insertBefore(div, node.nextSibling);
+ } else {
+ EvoEditor.moveNodeContent(node);
+ }
+ }
+
+ next = EvoEditor.getNextNodeInHierarchy(node, content);
+
+ if (removeNode)
+ node.remove();
+
+ node = next;
+ }
+
+ if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT) {
+ EvoEditor.convertParagraphs(content, quote ? 1 : 0,
EvoEditor.NORMAL_PARAGRAPH_WIDTH, quote);
+ content.innerText = EvoConvert.ToPlainText(content,
EvoEditor.NORMAL_PARAGRAPH_WIDTH);
+ } else {
+ EvoEditor.convertParagraphs(content, quote ? 1 : 0, -1, quote);
+ }
+ } else {
+ var lines = text.split("\n");
+
+ if (lines.length == 1 || (lines.length == 2 && !lines[1])) {
+ content.innerText = lines[0];
+ } else {
+ var ii, line, divNode;
+
+ for (ii = 0; ii < lines.length; ii++) {
+ line = lines[ii];
+ divNode = document.createElement("DIV");
+
+ content.appendChild(divNode);
+
+ if (!line.length) {
+ divNode.appendChild(document.createElement("BR"));
+ } else {
+ divNode.innerText = line;
+ }
+ }
+
+ isHTML = true;
+ }
+ }
+
+ if (EvoEditor.MAGIC_LINKS) {
+ var node, next, covered = false;
+
+ for (node = content.firstChild; node; node = next) {
+ next = EvoEditor.getNextNodeInHierarchy(node, content);
+
+ if (node.nodeType == node.TEXT_NODE)
+ covered = EvoEditor.linkifyText(node, false) || covered;
+ }
+
+ if (covered && !isHTML) {
+ EvoEditor.convertParagraphs(content, quote ? 1 : 0, EvoEditor.mode ==
EvoEditor.MODE_PLAIN_TEXT ? EvoEditor.NORMAL_PARAGRAPH_WIDTH : -1, quote);
+ isHTML = true;
+ }
+ }
+
+ if (quote) {
+ if (!isHTML)
+ EvoEditor.convertParagraphs(content, quote ? 1 : 0, EvoEditor.mode ==
EvoEditor.MODE_PLAIN_TEXT ? EvoEditor.NORMAL_PARAGRAPH_WIDTH : -1, quote);
+
+ var anchorNode = document.getSelection().anchorNode, intoBody = false;
+
+ if (!content.firstElementChild || (content.firstElementChild.tagName != "DIV" &&
content.firstElementChild.tagName != "P" &&
+ content.firstElementChild.tagName != "PRE")) {
+ // enclose quoted text into DIV
+ var node = document.createElement("DIV");
+
+ while (content.firstChild) {
+ node.appendChild(content.firstChild);
+ }
+
+ content.appendChild(node);
+ }
+
+ if (anchorNode) {
+ var node, parentBlock = null;
+
+ if (anchorNode.nodeType == anchorNode.ELEMENT_NODE) {
+ node = anchorNode;
+ } else {
+ node = anchorNode.parentElement;
+ }
+
+ while (node && node.tagName != "BODY" && !EvoEditor.IsBlockNode(node)) {
+ parentBlock = node;
+
+ node = node.parentElement;
+ }
+
+ if (node && node.tagName != "BLOCKQUOTE")
+ parentBlock = node;
+ else if (!parentBlock)
+ parentBlock = node;
+
+ if (!parentBlock) {
+ intoBody = true;
+ } else {
+ var willSplit = parentBlock.tagName == "DIV" || parentBlock.tagName
== "P" || parentBlock.tagName == "PRE";
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM,
"InsertContent::text", parentBlock, parentBlock,
+ (willSplit ?
EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE : 0) | EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ try {
+ if (willSplit) {
+ // need to split the content up to the parent block
node
+ if (anchorNode.nodeType == anchorNode.TEXT_NODE) {
+
anchorNode.splitText(document.getSelection().anchorOffset);
+ }
+
+ var from = anchorNode.nextSibling, parent, nextFrom =
null;
+
+ parent = from ? from.parentElement :
anchorNode.parentElement;
+
+ if (!from && parent) {
+ from = parent.nextElementSibling;
+ nextFrom = from;
+ parent = parent.parentElement;
+ }
+
+ while (parent && parent.tagName != "BODY") {
+ nextFrom = null;
+
+ if (from) {
+ var clone;
+
+ clone =
from.parentElement.cloneNode(false);
+
from.parentElement.parentElement.insertBefore(clone, from.parentElement.nextSibling);
+
+ nextFrom = clone;
+
+ while (from.nextSibling) {
+
clone.appendChild(from.nextSibling);
+ }
+
+ clone.insertBefore(from,
clone.firstChild);
+ }
+
+ if (parent === parentBlock.parentElement ||
(parent.parentElement && parent.parentElement.tagName == "BLOCKQUOTE")) {
+ break;
+ }
+
+ from = nextFrom;
+ parent = parent.parentElement;
+ }
+ }
+
+ parentBlock.insertAdjacentElement("afterend", content);
+
+ if (content.nextSibling)
+
document.getSelection().setPosition(content.nextSibling, 0);
+ else if (content.lastChild) {
+ node = content.lastChild;
+
+ while (node.lastChild)
+ node = node.lastChild;
+
+ document.getSelection().setPosition(node,
node.nodeType == node.TEXT_NODE ? node.nodeValue.length : 0);
+ } else
+ document.getSelection().setPosition(content, 0);
+
+ if (anchorNode.nodeType == anchorNode.ELEMENT_NODE &&
anchorNode.parentElement &&
+ EvoEditor.isEmptyParagraph(anchorNode)) {
+ anchorNode.remove();
+ } else {
+ anchorNode = parentBlock.nextSibling.nextSibling;
+
+ if (anchorNode && anchorNode.nodeType ==
anchorNode.ELEMENT_NODE && anchorNode.parentElement &&
+ EvoEditor.isEmptyParagraph(anchorNode)) {
+ anchorNode.remove();
+ }
+ }
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM,
"InsertContent::text");
+ }
+ }
+ } else {
+ intoBody = true;
+ }
+
+ if (intoBody) {
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM,
"InsertContent::text", document.body, document.body,
+ EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE |
EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ try {
+ document.body.insertAdjacentElement("afterbegin", content);
+ EvoEditor.maybeUpdateParagraphWidth(content);
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM,
"InsertContent::text");
+ }
+ }
+
+ if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT) {
+ var ii;
+
+ for (ii = 0; ii < content.children.length; ii++) {
+ EvoEditor.requoteNodeParagraph(content.children[ii]);
+ }
+ }
+ } else if (isHTML) {
+ var list, ii;
+
+ list = content.getElementsByTagName("BLOCKQUOTE");
+
+ for (ii = 0; ii < list.length; ii++) {
+ var node = list[ii];
+
+ node.removeAttribute("class");
+ node.removeAttribute("style");
+ }
+
+ var selection = document.getSelection();
+
+ var useOuterHTML = !list.length &&
+ !content.getElementsByTagName("DIV").length &&
+ !content.getElementsByTagName("PRE").length;
+
+ if (!useOuterHTML && selection.isCollapsed && selection.focusNode &&
EvoEditor.isEmptyParagraph(selection.focusNode)) {
+ var node = selection.focusNode, lastNode = null;
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM,
"InsertContent::replaceEmptyBlock", node, node,
+ EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE |
EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ try {
+ if (useOuterHTML) {
+ lastNode = content;
+ node.parentElement.insertBefore(content, node);
+ } else {
+ while (content.firstChild) {
+ lastNode = content.firstChild;
+ node.parentElement.insertBefore(content.firstChild,
node);
+ }
+ }
+
+ node.remove();
+
+ if (lastNode) {
+ while (lastNode.lastChild) {
+ lastNode = lastNode.lastChild;
+ }
+
+ selection.setPosition(lastNode, lastNode.nodeType ==
lastNode.TEXT_NODE ? lastNode.nodeValue.length : 0);
+ }
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM,
"InsertContent::replaceEmptyBlock");
+ }
+
+ EvoEditor.correctParagraphsAfterInsertContent("InsertContent::inEmptyBlock");
+ } else {
+ useOuterHTML = useOuterHTML && !wasPlain;
+
+ EvoEditor.InsertHTML("InsertContent::text", useOuterHTML ? content.outerHTML
: content.innerHTML);
+ }
+ } else {
+ EvoEditor.InsertText("InsertContent::text", content.innerText);
+ }
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_GROUP, "InsertContent");
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+}
+
+EvoEditor.splitPreTexts = function(node, isInPre, newNodes)
+{
+ if (!node)
+ return;
+
+ isInPre = isInPre || node.tagName == "PRE";
+
+ var currPre = null, child, childIsPre, next;
+
+ for (child = node.firstChild; child; child = next) {
+ childIsPre = child.tagName == "PRE";
+ next = child.nextSibling;
+
+ if (childIsPre || child.tagName == "BLOCKQUOTE") {
+ currPre = null;
+
+ var list = [], ii, clone = null;
+
+ EvoEditor.splitPreTexts(child, isInPre, list);
+
+ for (ii = 0; ii < list.length; ii++) {
+ if (childIsPre) {
+ newNodes[newNodes.length] = list[ii];
+ } else {
+ if (!clone) {
+ clone = child.cloneNode(false);
+ newNodes[newNodes.length] = clone;
+ }
+
+ clone.appendChild(list[ii]);
+ }
+ }
+ } else if (isInPre && child.nodeType == node.TEXT_NODE) {
+ var text = child.nodeValue, pre, ii, lines;
+
+ lines = text.split("\n");
+
+ for (ii = 0; ii < lines.length; ii++) {
+ var line = lines[ii].replace(/\r/g, "");
+
+ // <pre> is shown as a block, thus adding a new line at the end behaves like
two <br>-s
+ if (!line && ii + 1 >= lines.length) {
+ if (ii > 0)
+ currPre = null;
+ break;
+ }
+
+ if (ii == 0 && currPre) {
+ if (line)
+ currPre.appendChild(document.createTextNode(line));
+ if (lines.length > 1)
+ currPre = null;
+ continue;
+ }
+
+ pre = document.createElement("PRE");
+
+ if (line) {
+ pre.innerText = line;
+ } else {
+ pre.appendChild(document.createElement("BR"));
+ }
+
+ currPre = pre;
+ newNodes[newNodes.length] = pre;
+ }
+ } else if (currPre && child.tagName == "BR") {
+ currPre = null;
+ } else {
+ child.remove();
+
+ if (currPre) {
+ currPre.appendChild(child);
+ } else if (isInPre) {
+ currPre = document.createElement("PRE");
+ currPre.appendChild(child);
+
+ newNodes[newNodes.length] = currPre;
+ } else {
+ newNodes[newNodes.length] = child;
+ }
+ }
+ }
+}
+
+EvoEditor.processLoadedContent = function()
+{
+ if (!document.body)
+ return;
+
+ var node, didCite, ii, list;
+
+ if (!document.body.hasAttribute("data-evo-draft") && document.querySelector("PRE")) {
+ var next, replacement;
+
+ document.body.normalize();
+
+ for (node = document.body.firstChild; node; node = next) {
+ next = node.nextSibling;
+
+ if (node.tagName == "PRE" || node.tagName == "BLOCKQUOTE") {
+ list = [];
+
+ EvoEditor.splitPreTexts(node, false, list);
+
+ for (ii = 0; ii < list.length; ii++) {
+ node.parentElement.insertBefore(list[ii], node);
+ }
+
+ node.remove();
+ }
+ }
+ }
+
+ node = document.querySelector("SPAN.-x-evo-cite-body");
+
+ didCite = node;
+
+ if (node)
+ node.remove();
+
+ if (didCite) {
+ didCite = document.createElement("BLOCKQUOTE");
+ didCite.setAttribute("type", "cite");
+
+ while (document.body.firstChild) {
+ didCite.appendChild(document.body.firstChild);
+ }
+
+ var next;
+
+ // Evolution builds HTML with insignificant "\n", thus remove them first
+ for (node = didCite.firstChild; node; node = next) {
+ next = EvoEditor.getNextNodeInHierarchy(node, didCite);
+
+ if (node.nodeType == node.TEXT_NODE && node.nodeValue && node.nodeValue.charAt(0) ==
'\n' && (
+ (node.previousSibling && EvoEditor.IsBlockNode(node.previousSibling)) ||
+ (!node.previousSibling && node.parentElement.tagName == "BLOCKQUOTE" &&
!(node.parentElement === didCite)))) {
+ node.nodeValue = node.nodeValue.substr(1);
+ }
+ }
+
+ document.body.appendChild(didCite);
+ }
+
+ list = document.querySelectorAll("STYLE[id]");
+
+ for (ii = list.length - 1; ii >= 0; ii--) {
+ node = list[ii];
+
+ if (node.id && node.id.startsWith("-x-evo-"))
+ node.remove();
+ }
+
+ list = document.querySelectorAll("DIV[data-headers]");
+
+ for (ii = list.length - 1; ii >= 0; ii--) {
+ node = list[ii];
+
+ node.removeAttribute("data-headers");
+
+ document.body.insertAdjacentElement("afterbegin", node);
+ }
+
+ list = document.querySelectorAll("SPAN.-x-evo-to-body[data-credits]");
+
+ for (ii = list.length - 1; ii >= 0; ii--) {
+ node = list[ii];
+
+ var credits = node.getAttribute("data-credits");
+ if (credits) {
+ var elem;
+
+ elem = document.createElement("DIV");
+ elem.innerText = credits;
+
+ document.body.insertAdjacentElement("afterbegin", elem);
+ EvoEditor.maybeUpdateParagraphWidth(elem);
+ }
+
+ node.remove();
+ }
+
+ list = document.querySelectorAll(".-x-evo-paragraph");
+
+ for (ii = list.length - 1; ii >= 0; ii--) {
+ node = list[ii];
+ node.removeAttribute("class");
+ }
+
+ list = document.querySelectorAll("[data-evo-paragraph]");
+
+ for (ii = list.length - 1; ii >= 0; ii--) {
+ list[ii].removeAttribute("data-evo-paragraph");
+ }
+
+ // require blocks under BLOCKQUOTE and style them properly
+ list = document.getElementsByTagName("BLOCKQUOTE");
+
+ for (ii = list.length - 1; ii >= 0; ii--) {
+ var blockquoteNode = list[ii], addingTo = null, next;
+
+ for (node = blockquoteNode.firstChild; node; node = next) {
+ next = node.nextSibling;
+
+ if (!EvoEditor.IsBlockNode(node) && (node.nodeType == node.ELEMENT_NODE ||
(node.nodeValue && node.nodeValue != "\n" && node.nodeValue != "\r\n"))) {
+ if (!addingTo) {
+ addingTo =
document.createElement(EvoEditor.hasElementWithTagNameAsParent(node, "PRE") ? "PRE" : "DIV");
+ blockquoteNode.insertBefore(addingTo, node);
+ EvoEditor.maybeUpdateParagraphWidth(addingTo);
+ }
+
+ addingTo.appendChild(node);
+ } else {
+ addingTo = null;
+ }
+ }
+
+ blockquoteNode.removeAttribute("class");
+ blockquoteNode.removeAttribute("style");
+ }
+
+ if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT) {
+ EvoEditor.convertParagraphs(document.body, 0, EvoEditor.NORMAL_PARAGRAPH_WIDTH, didCite);
+
+ if (EvoEditor.MAGIC_LINKS) {
+ var next;
+
+ for (node = document.body.firstChild; node; node = next) {
+ next = EvoEditor.getNextNodeInHierarchy(node, null);
+
+ if (node.nodeType == node.TEXT_NODE)
+ EvoEditor.linkifyText(node, false);
+ }
+ }
+ }
+
+ // remove comments at the beginning, like the Evolution's "<!-- text/html -->"
+ while (document.documentElement.firstChild && document.documentElement.firstChild.nodeType ==
document.documentElement.firstChild.COMMENT_NODE) {
+ document.documentElement.removeChild(document.documentElement.firstChild);
+ }
+
+ document.body.removeAttribute("data-evo-draft");
+ document.body.removeAttribute("data-evo-plain-text");
+ document.body.removeAttribute("spellcheck");
+
+ list = document.querySelectorAll("[id=-x-evo-input-start]");
+
+ for (ii = list.length - 1; ii >= 0; ii--) {
+ node = list[ii];
+ node.removeAttribute("id");
+
+ document.getSelection().setPosition(node, 0);
+ node.scrollIntoView();
+ }
+
+ if (EvoEditor.START_BOTTOM) {
+ var node = document.createElement("DIV");
+
+ node.appendChild(document.createElement("BR"));
+ document.body.appendChild(node);
+ EvoEditor.maybeUpdateParagraphWidth(node);
+
+ document.getSelection().setPosition(node, 0);
+ node.scrollIntoView();
+ }
+}
+
+EvoEditor.LoadHTML = function(html)
+{
+ EvoUndoRedo.Disable();
+ try {
+ document.documentElement.innerHTML = html;
+
+ EvoEditor.processLoadedContent();
+ EvoEditor.initializeContent();
+ } finally {
+ EvoUndoRedo.Enable();
+ EvoUndoRedo.Clear();
+ }
+}
+
+EvoEditor.wrapParagraph = function(paragraphNode, maxLetters, currentPar, usedLetters, wasNestedElem)
+{
+ var child = paragraphNode.firstChild, nextChild, appendBR;
+
+ while (child) {
+ appendBR = false;
+
+ if (child.nodeType == child.TEXT_NODE) {
+ var text = child.nodeValue;
+
+ // merge consecutive text nodes into one (similar to paragraphNode.normalize())
+ while (child.nextSibling && child.nextSibling.nodeType == child.TEXT_NODE) {
+ nextChild = child.nextSibling;
+ text += nextChild.nodeValue;
+
+ child.remove();
+
+ child = nextChild;
+ }
+
+ while (text.length + usedLetters > maxLetters) {
+ var spacePos = text.lastIndexOf(" ", maxLetters - usedLetters);
+
+ if (spacePos < 0)
+ spacePos = text.indexOf(" ");
+
+ if (spacePos > 0 && (!usedLetters || usedLetters + spacePos <= maxLetters)) {
+ var textNode = document.createTextNode(((usedLetters > 0 &&
!wasNestedElem) ? " " : "") +
+ text.substr(0, spacePos));
+
+ if (currentPar)
+ currentPar.appendChild(textNode);
+ else
+ child.parentElement.insertBefore(textNode, child);
+
+ text = text.substr(spacePos + 1);
+ }
+
+ if (currentPar)
+ currentPar.appendChild(document.createElement("BR"));
+ else
+ child.parentElement.insertBefore(document.createElement("BR"), child);
+
+ usedLetters = 0;
+
+ if (spacePos == 0)
+ text = text.substr(1);
+ else if (spacePos < 0)
+ break;
+ }
+
+ child.nodeValue = ((usedLetters > 0 && !wasNestedElem) ? " " : "") + text;
+ usedLetters += ((usedLetters > 0 && !wasNestedElem) ? 1 : 0) + text.length;
+
+ if (usedLetters > maxLetters)
+ appendBR = true;
+
+ wasNestedElem = false;
+ } else if (child.tagName == "BR") {
+ wasNestedElem = false;
+
+ if (!child.nextSibling) {
+ return -1;
+ }
+
+ if (child.nextSibling.tagName == "BR") {
+ usedLetters = 0;
+
+ if (currentPar) {
+ var nextSibling = child.nextSibling;
+
+ nextChild = child.nextSibling.nextSibling;
+
+ currentPar.appendChild(child);
+
+ if (usedLetters) {
+ currentPar.appendChild(nextSibling);
+ } else {
+ nextSibling.remove();
+ }
+
+ child = nextChild;
+ continue;
+ }
+ } else {
+ nextChild = child.nextSibling;
+
+ child.remove();
+
+ child = nextChild;
+ continue;
+ }
+ } else if (child.tagName == "IMG") {
+ // just skip it, do not count it into the line length
+ wasNestedElem = false;
+ } else if (child.tagName == "B" ||
+ child.tagName == "I" ||
+ child.tagName == "U" ||
+ child.tagName == "S" ||
+ child.tagName == "SUB" ||
+ child.tagName == "SUP" ||
+ child.tagName == "FONT" ||
+ child.tagName == "SPAN" ||
+ child.tagName == "A") {
+ usedLetters = EvoEditor.wrapParagraph(child, maxLetters, null, usedLetters, true);
+ if (usedLetters == -1)
+ usedLetters = 0;
+ wasNestedElem = true;
+ } else if (child.nodeType == child.ELEMENT_NODE) {
+ // everything else works like a line stopper, with a new line added after it
+ appendBR = true;
+ wasNestedElem = false;
+ }
+
+ nextChild = child.nextSibling;
+
+ if (currentPar)
+ currentPar.appendChild(child);
+
+ if (appendBR) {
+ usedLetters = 0;
+
+ if (nextChild) {
+ if (currentPar)
+ currentPar.appendChild(document.createElement("BR"));
+ else
+ nextChild.parentElement.insertBefore(document.createElement("BR"),
nextChild);
+ }
+ }
+
+ child = nextChild;
+ }
+
+ return usedLetters;
+}
+
+EvoEditor.WrapSelection = function()
+{
+ var nodeFrom, nodeTo;
+
+ nodeFrom = EvoEditor.GetParentBlockNode(document.getSelection().anchorNode);
+ nodeTo = EvoEditor.GetParentBlockNode(document.getSelection().focusNode);
+
+ if (!nodeFrom || !nodeTo) {
+ return;
+ }
+
+ if (nodeFrom != nodeTo) {
+ // selection can go from top to bottom, but also from bottom to top; normalize the path order
+ var commonParent = EvoEditor.GetCommonParent(nodeFrom, nodeTo, true), childFrom, childTo, ii,
sz;
+
+ childFrom = nodeFrom;
+ while (childFrom && childFrom != commonParent && childFrom.parentElement != commonParent) {
+ childFrom = childFrom.parentElement;
+ }
+
+ childTo = nodeTo;
+ while (childTo && childTo != commonParent && childTo.parentElement != commonParent) {
+ childTo = childTo.parentElement;
+ }
+
+ if (!childFrom || !childTo) {
+ throw "EvoEditor.WrapSelection: Should not be reached (childFrom and childTo cannot
be null)";
+ }
+
+ sz = commonParent.children.length;
+ for (ii = 0; ii < sz; ii++) {
+ if (commonParent.children[ii] === childFrom) {
+ nodeFrom = childFrom;
+ nodeTo = childTo;
+ break;
+ } else if (commonParent.children[ii] === childTo) {
+ nodeFrom = childTo;
+ nodeTo = childFrom;
+ break;
+ }
+ }
+ }
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "WrapSelection", nodeFrom, nodeTo,
EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE | EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ try {
+ var maxLetters, usedLetters, currentPar, lastParTagName = nodeFrom.tagName;
+
+ maxLetters = EvoEditor.NORMAL_PARAGRAPH_WIDTH;
+ usedLetters = 0;
+ currentPar = null;
+
+ while (nodeFrom) {
+ EvoEditor.removeQuoteMarks(nodeFrom);
+
+ if (lastParTagName != nodeFrom.tagName) {
+ lastParTagName = nodeFrom.tagName;
+ currentPar = null;
+ usedLetters = 0;
+ }
+
+ if (nodeFrom.tagName == "DIV" || nodeFrom.tagName == "P" || nodeFrom.tagName ==
"PRE") {
+ if (nodeFrom.childNodes.length == 1 && nodeFrom.childNodes[0].tagName ==
"BR") {
+ currentPar = null;
+ usedLetters = 0;
+ } else {
+ var blockquoteLevel = 0;
+
+ if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT)
+ blockquoteLevel = EvoEditor.getBlockquoteLevel(nodeFrom);
+
+ usedLetters = EvoEditor.wrapParagraph(nodeFrom, maxLetters - (2 *
blockquoteLevel), currentPar, usedLetters, false);
+
+ if (blockquoteLevel)
+ EvoEditor.requoteNodeParagraph(nodeFrom);
+
+ if (usedLetters == -1) {
+ currentPar = null;
+ usedLetters = 0;
+ } else if (!currentPar) {
+ currentPar = nodeFrom;
+ }
+ }
+ }
+
+ // cannot break the cycle now, because want to delete the last empty paragraph
+ var done = nodeFrom === nodeTo;
+
+ if (!nodeFrom.childNodes.length) {
+ var node = nodeFrom;
+
+ nodeFrom = nodeFrom.nextSibling;
+
+ if (node.parentElement)
+ node.remove();
+ } else {
+ nodeFrom = nodeFrom.nextSibling;
+ }
+
+ if (done)
+ break;
+ }
+
+ // Place the cursor at the end of the wrapped paragraph(s)
+ if (currentPar)
+ nodeTo = currentPar;
+
+ while (nodeTo.lastChild) {
+ nodeTo = nodeTo.lastChild;
+ }
+
+ document.getSelection().setPosition(nodeTo, nodeTo.nodeType == nodeTo.TEXT_NODE ?
nodeTo.nodeValue.length : 0);
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "WrapSelection");
+ }
+}
+
+EvoEditor.onContextMenu = function(event)
+{
+ var node = event.target;
+
+ if (!node)
+ node = document.getSelection().focusNode;
+ if (!node)
+ node = document.getSelection().anchorNode;
+
+ EvoEditor.contextMenuNode = node;
+
+ var nodeFlags = EvoEditor.E_CONTENT_EDITOR_NODE_UNKNOWN, res;
+
+ while (node && node.tagName != "BODY") {
+ if (node.tagName == "A")
+ nodeFlags |= EvoEditor.E_CONTENT_EDITOR_NODE_IS_ANCHOR;
+ else if (node.tagName == "HR")
+ nodeFlags |= EvoEditor.E_CONTENT_EDITOR_NODE_IS_H_RULE;
+ else if (node.tagName == "IMG")
+ nodeFlags |= EvoEditor.E_CONTENT_EDITOR_NODE_IS_IMAGE;
+ else if (node.tagName == "TABLE")
+ nodeFlags |= EvoEditor.E_CONTENT_EDITOR_NODE_IS_TABLE;
+ else if (node.tagName == "TD" || node.tagName == "TH")
+ nodeFlags |= EvoEditor.E_CONTENT_EDITOR_NODE_IS_TABLE_CELL;
+
+ node = node.parentElement;
+ }
+
+ if (!nodeFlags && EvoEditor.contextMenuNode)
+ nodeFlags |= EvoEditor.E_CONTENT_EDITOR_NODE_IS_TEXT;
+
+ if (document.getSelection().isCollapsed)
+ nodeFlags |= EvoEditor.E_CONTENT_EDITOR_NODE_IS_TEXT_COLLAPSED;
+
+ res = [];
+
+ res["nodeFlags"] = nodeFlags;
+ res["caretWord"] = EvoEditor.GetCaretWord();
+
+ window.webkit.messageHandlers.contextMenuRequested.postMessage(res);
+}
+
+document.oncontextmenu = EvoEditor.onContextMenu;
+document.onload = EvoEditor.initializeContent;
+
+document.onselectionchange = function() {
+ if (EvoEditor.checkInheritFontsOnChange) {
+ EvoEditor.checkInheritFontsOnChange = false;
+ EvoEditor.maybeReplaceInheritFonts();
+ }
+
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.forceFormatStateUpdate ? EvoEditor.FORCE_YES :
EvoEditor.FORCE_MAYBE);
+ EvoEditor.forceFormatStateUpdate = false;
+
+ window.webkit.messageHandlers.selectionChanged.postMessage(document.getSelection().isCollapsed);
+};
+
+EvoEditor.initializeContent();
diff --git a/data/webkit/e-selection.js b/data/webkit/e-selection.js
new file mode 100644
index 0000000000..76a0d9fd7b
--- /dev/null
+++ b/data/webkit/e-selection.js
@@ -0,0 +1,435 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+'use strict';
+
+/* semi-convention: private functions start with lower-case letter,
+ public functions start with upper-case letter. */
+
+var EvoSelection = {
+};
+
+/* The node path is described as an array of child indexes between parent
+ and the childNode (in this order). */
+EvoSelection.GetChildPath = function(parent, childNode)
+{
+ if (!childNode) {
+ return null;
+ }
+
+ var array = [], node;
+
+ if (childNode.nodeType == childNode.TEXT_NODE) {
+ childNode = childNode.parentElement;
+ }
+
+ for (node = childNode; node && !(node === parent); node = node.parentElement) {
+ var child, index = 0;
+
+ for (child = node.previousElementSibling; child; child = child.previousElementSibling) {
+ index++;
+ }
+
+ array[array.length] = index;
+ }
+
+ return array.reverse();
+}
+
+/* Finds the element (not node) referenced by the 'path', which had been created
+ by EvoSelection.GetChildPath(). There should be used the same 'parent' element
+ in both calls. */
+EvoSelection.FindElementByPath = function(parent, path)
+{
+ if (!parent || !path) {
+ return null;
+ }
+
+ var ii, child = parent;
+
+ for (ii = 0; ii < path.length; ii++) {
+ var idx = path[ii];
+
+ if (idx < 0 || idx >= child.children.length) {
+ throw "EvoSelection.FindElementByPath:: Index '" + idx + "' out of range '" +
child.children.length + "'";
+ }
+
+ child = child.children.item(idx);
+ }
+
+ return child;
+}
+
+/* This is when the text nodes are split, then the text length of
+ the previous text node influences offset of the next node. */
+EvoSelection.GetOverallTextOffset = function(node)
+{
+ if (!node) {
+ return 0;
+ }
+
+ var text_offset = 0, sibling;
+
+ for (sibling = node.previousSibling; sibling; sibling = sibling.previousSibling) {
+ if (sibling.nodeType == sibling.TEXT_NODE) {
+ text_offset += sibling.textContent.length;
+ }
+ }
+
+ return text_offset;
+}
+
+/* Traverses direct text nodes under element until it reaches the first within
+ the textOffset. */
+EvoSelection.GetTextOffsetNode = function(element, textOffset)
+{
+ if (!element) {
+ return null;
+ }
+
+ var node, adept = null;
+
+ for (node = element.firstChild; node; node = node.nextSibling) {
+ if (node.nodeType == node.TEXT_NODE) {
+ var txt_len = node.textContent.length;
+
+ if (textOffset > txt_len) {
+ textOffset -= txt_len;
+ adept = node;
+ } else {
+ break;
+ }
+ }
+ }
+
+ return node ? node : (adept ? adept : element);
+}
+
+/* Returns an object, where the current selection in the doc is stored */
+EvoSelection.Store = function(doc)
+{
+ if (!doc || !doc.getSelection()) {
+ return null;
+ }
+
+ var selection = {}, sel = doc.getSelection();
+
+ selection.anchorElem = sel.anchorNode ? EvoSelection.GetChildPath(doc.body, sel.anchorNode) : [];
+ selection.anchorOffset = sel.anchorOffset + EvoSelection.GetOverallTextOffset(sel.anchorNode);
+
+ if (sel.anchorNode && sel.anchorNode.nodeType == sel.anchorNode.ELEMENT_NODE) {
+ selection.anchorIsElement = true;
+ }
+
+ if (!sel.isCollapsed) {
+ selection.focusElem = EvoSelection.GetChildPath(doc.body, sel.focusNode);
+ selection.focusOffset = sel.focusOffset + EvoSelection.GetOverallTextOffset(sel.focusNode);
+
+ if (sel.focusNode && sel.focusNode.nodeType == sel.focusNode.ELEMENT_NODE) {
+ selection.focusIsElement = true;
+ }
+ }
+
+ return selection;
+}
+
+/* Restores selection in the doc according to the information stored in 'selection',
+ obtained by EvoSelection.Store(). */
+EvoSelection.Restore = function(doc, selection)
+{
+ if (!doc || !selection || !doc.getSelection()) {
+ return;
+ }
+
+ var anchorNode, anchorOffset, focusNode, focusOffset;
+
+ anchorNode = EvoSelection.FindElementByPath(doc.body, selection.anchorElem);
+ anchorOffset = selection.anchorOffset;
+
+ if (!anchorNode) {
+ return;
+ }
+
+ if (!anchorOffset) {
+ anchorOffset = 0;
+ }
+
+ if (!selection.anchorIsElement) {
+ anchorNode = EvoSelection.GetTextOffsetNode(anchorNode, anchorOffset);
+ anchorOffset -= EvoSelection.GetOverallTextOffset(anchorNode);
+ }
+
+ focusNode = EvoSelection.FindElementByPath(doc.body, selection.focusElem);
+ focusOffset = selection.focusOffset;
+
+ if (focusNode) {
+ if (!selection.focusIsElement) {
+ focusNode = EvoSelection.GetTextOffsetNode(focusNode, focusOffset);
+ focusOffset -= EvoSelection.GetOverallTextOffset(focusNode);
+ }
+ }
+
+ if (focusNode)
+ doc.getSelection().setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);
+ else
+ doc.getSelection().setPosition(anchorNode, anchorOffset);
+}
+
+/* Encodes selection information to a string */
+EvoSelection.ToString = function(selection)
+{
+ if (!selection) {
+ return "";
+ }
+
+ var utils = {
+ arrayToString : function(array) {
+ var ii, str = "[";
+
+ if (!array) {
+ return str + "]";
+ }
+
+ for (ii = 0; ii < array.length; ii++) {
+ if (ii) {
+ str += ",";
+ }
+ str += array[ii];
+ }
+
+ return str + "]";
+ }
+ };
+
+ var str = "", anchorElem, anchorOffset, focusElem, focusOffset;
+
+ anchorElem = selection.anchorElem;
+ anchorOffset = selection.anchorOffset;
+ focusElem = selection.focusElem;
+ focusOffset = selection.focusOffset;
+
+ str += "anchorElem=" + utils.arrayToString(anchorElem);
+ str += " anchorOffset=" + (anchorOffset ? anchorOffset : 0);
+
+ if (selection.anchorIsElement) {
+ str += " anchorIsElement=1";
+ }
+
+ if (focusElem) {
+ str += " focusElem=" + utils.arrayToString(focusElem);
+ str += " focusOffset=" + (focusOffset ? focusOffset : 0);
+
+ if (selection.focusIsElement) {
+ str += " focusIsElement=1";
+ }
+ }
+
+ return str;
+}
+
+/* Decodes selection information from a string */
+EvoSelection.FromString = function(str)
+{
+ if (!str) {
+ return null;
+ }
+
+ var utils = {
+ arrayFromString : function(str) {
+ if (!str || !str.startsWith("[") || !str.endsWith("]")) {
+ return null;
+ }
+
+ var ii, array;
+
+ array = str.substr(1, str.length - 2).split(",");
+
+ if (!array) {
+ return null;
+ }
+
+ if (array.length == 1 && array[0] == "") {
+ array.length = 0;
+ } else {
+ for (ii = 0; ii < array.length; ii++) {
+ array[ii] = parseInt(array[ii], 10);
+
+ if (!Number.isInteger(array[ii])) {
+ return null;
+ }
+ }
+ }
+
+ return array;
+ }
+ };
+
+ var selection = {}, ii, split_str;
+
+ split_str = str.split(" ");
+
+ if (!split_str || !split_str.length) {
+ return null;
+ }
+
+ for (ii = 0; ii < split_str.length; ii++) {
+ var name;
+
+ name = "anchorElem";
+ if (split_str[ii].startsWith(name + "=")) {
+ selection[name] = utils.arrayFromString(split_str[ii].slice(name.length + 1));
+ continue;
+ }
+
+ name = "anchorOffset";
+ if (split_str[ii].startsWith(name + "=")) {
+ var value;
+
+ value = parseInt(split_str[ii].slice(name.length + 1), 10);
+ if (Number.isInteger(value)) {
+ selection[name] = value;
+ }
+ continue;
+ }
+
+ name = "anchorIsElement";
+ if (split_str[ii].startsWith(name + "=")) {
+ var value;
+
+ value = parseInt(split_str[ii].slice(name.length + 1), 10);
+ if (Number.isInteger(value) && value == 1) {
+ selection[name] = true;
+ }
+ continue;
+ }
+
+ name = "focusElem";
+ if (split_str[ii].startsWith(name + "=")) {
+ selection[name] = utils.arrayFromString(split_str[ii].slice(name.length + 1));
+ continue;
+ }
+
+ name = "focusOffset";
+ if (split_str[ii].startsWith(name + "=")) {
+ var value;
+
+ value = parseInt(split_str[ii].slice(name.length + 1), 10);
+ if (Number.isInteger(value)) {
+ selection[name] = value;
+ }
+ }
+
+ name = "focusIsElement";
+ if (split_str[ii].startsWith(name + "=")) {
+ var value;
+
+ value = parseInt(split_str[ii].slice(name.length + 1), 10);
+ if (Number.isInteger(value) && value == 1) {
+ selection[name] = true;
+ }
+ continue;
+ }
+ }
+
+ /* The "anchorElem" is required, the rest is optional */
+ if (!selection.anchorElem)
+ return null;
+
+ return selection;
+}
+
+/* The so-called updater object has several methods to work with when removing
+ elements from the structure, which tries to preserve selection in the new
+ document structure. The methods are:
+
+ beforeRemove(node) - called before going to remove the 'node'
+ afterRemove(newNode) - with what the 'node' from beforeRemove() had been replaced
+ restore() - called at the end, to restore the selection
+ */
+EvoSelection.CreateUpdaterObject = function()
+{
+ var obj = {
+ selectionBefore : null,
+ selectionAnchorNode : null,
+ selectionAnchorOffset : -1,
+ selectionFocusNode : null,
+ selectionFocusOffset : -1,
+ changeAnchor : false,
+ changeFocus : false,
+
+ beforeRemove : function(node) {
+ this.changeAnchor = false;
+ this.changeFocus = false;
+
+ if (this.selectionAnchorNode) {
+ this.changeAnchor = node === this.selectionAnchorNode ||
+ (this.selectionAnchorNode.noteType ==
this.selectionAnchorNode.TEXT_NODE &&
+ this.selectionAnchorNode.parentElement === node);
+ }
+
+ if (this.selectionFocusNode) {
+ this.changeFocus = node === this.selectionFocusNode ||
+ (this.selectionFocusNode.noteType ==
this.selectionFocusNode.TEXT_NODE &&
+ this.selectionFocusNode.parentElement === node);
+ }
+ },
+
+ afterRemove : function(newNode) {
+ if (this.changeAnchor) {
+ this.selectionAnchorNode = newNode;
+ this.selectionAnchorOffset += EvoSelection.GetOverallTextOffset(newNode);
+ }
+
+ if (this.changeFocus) {
+ this.selectionFocusNode = newNode;
+ this.selectionFocusOffset += EvoSelection.GetOverallTextOffset(newNode);
+ }
+
+ this.changeAnchor = false;
+ this.changeFocus = false;
+ },
+
+ restore : function() {
+ if (this.selectionAnchorNode && this.selectionAnchorNode.parentElement) {
+ var selection = {
+ anchorElem : EvoSelection.GetChildPath(document.body,
this.selectionAnchorNode),
+ anchorOffset : this.selectionAnchorOffset
+ };
+
+ if (this.selectionFocusNode) {
+ selection.focusElem = EvoSelection.GetChildPath(document.body,
this.selectionFocusNode);
+ selection.focusOffset = this.selectionFocusOffset;
+ }
+
+ EvoSelection.Restore(document, selection);
+ } else {
+ EvoSelection.Restore(document, this.selectionBefore);
+ }
+ }
+ };
+
+ obj.selectionBefore = EvoSelection.Store(document);
+ obj.selectionAnchorNode = document.getSelection().anchorNode;
+ obj.selectionAnchorOffset = document.getSelection().anchorOffset +
EvoSelection.GetOverallTextOffset(obj.selectionAnchorNode);
+
+ if (!document.getSelection().isCollapsed) {
+ obj.selectionFocusNode = document.getSelection().focusNode;
+ obj.selectionFocusOffset = document.getSelection().focusOffset +
EvoSelection.GetOverallTextOffset(obj.selectionFocusNode);
+ }
+
+ return obj;
+}
diff --git a/data/webkit/e-undo-redo.js b/data/webkit/e-undo-redo.js
new file mode 100644
index 0000000000..2092004f7b
--- /dev/null
+++ b/data/webkit/e-undo-redo.js
@@ -0,0 +1,940 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+'use strict';
+
+/* semi-convention: private functions start with lower-case letter,
+ public functions start with upper-case letter. */
+
+var EvoUndoRedo = {
+ E_UNDO_REDO_STATE_NONE : 0,
+ E_UNDO_REDO_STATE_CAN_UNDO : 1 << 0,
+ E_UNDO_REDO_STATE_CAN_REDO : 1 << 1,
+
+ stack : {
+ // to not claim changes when none being made
+ state : -1,
+ undoOpType : "",
+ redoOpType : "",
+
+ maybeStateChanged : function() {
+ var undoRecord, redoRecord, undoAvailable, undoOpType, redoAvailable, redoOpType;
+
+ undoRecord = EvoUndoRedo.stack.getCurrentUndoRecord();
+ redoRecord = EvoUndoRedo.stack.getCurrentRedoRecord();
+ undoAvailable = undoRecord != null;
+ undoOpType = undoRecord ? undoRecord.opType : "";
+ redoAvailable = redoRecord != null;
+ redoOpType = redoRecord ? redoRecord.opType : "";
+
+ var state = EvoUndoRedo.E_UNDO_REDO_STATE_NONE;
+
+ if (undoAvailable) {
+ state |= EvoUndoRedo.E_UNDO_REDO_STATE_CAN_UNDO;
+ }
+
+ if (redoAvailable) {
+ state |= EvoUndoRedo.E_UNDO_REDO_STATE_CAN_REDO;
+ }
+
+ if (EvoUndoRedo.state != state ||
+ EvoUndoRedo.undoOpType != (undoAvailable ? undoOpType : "") ||
+ EvoUndoRedo.redoOpType != (redoAvailable ? redoOpType : "")) {
+ EvoUndoRedo.state = state;
+ EvoUndoRedo.undoOpType = (undoAvailable ? undoOpType : "");
+ EvoUndoRedo.redoOpType = (redoAvailable ? redoOpType : "");
+
+ var params = {};
+
+ params.state = EvoUndoRedo.state;
+ params.undoOpType = EvoUndoRedo.undoOpType;
+ params.redoOpType = EvoUndoRedo.redoOpType;
+
+ window.webkit.messageHandlers.undoRedoStateChanged.postMessage(params);
+ }
+ },
+
+ MAX_DEPTH : 10000 + 1, /* it's one item less, due to the 'bottom' being always ignored */
+
+ array : [],
+ bottom : 0,
+ top : 0,
+ current : 0,
+
+ clampIndex : function(index) {
+ index = (index) % EvoUndoRedo.stack.MAX_DEPTH;
+
+ if (index < 0)
+ index += EvoUndoRedo.stack.MAX_DEPTH;
+
+ return index;
+ },
+
+ /* Returns currently active record for Undo operation, or null */
+ getCurrentUndoRecord : function() {
+ if (EvoUndoRedo.stack.current == EvoUndoRedo.stack.bottom ||
!EvoUndoRedo.stack.array.length ||
+ EvoUndoRedo.stack.current < 0 || EvoUndoRedo.stack.current >
EvoUndoRedo.stack.array.length) {
+ return null;
+ }
+
+ return EvoUndoRedo.stack.array[EvoUndoRedo.stack.current];
+ },
+
+ /* Returns currently active record for Redo operation, or null */
+ getCurrentRedoRecord : function() {
+ if (EvoUndoRedo.stack.current == EvoUndoRedo.stack.top) {
+ return null;
+ }
+
+ var idx = EvoUndoRedo.stack.clampIndex(EvoUndoRedo.stack.current + 1);
+
+ if (idx < 0 || idx > EvoUndoRedo.stack.array.length) {
+ return null;
+ }
+
+ return EvoUndoRedo.stack.array[idx];
+ },
+
+ /* Clears the undo stack */
+ clear : function() {
+ EvoUndoRedo.stack.array.length = 0;
+ EvoUndoRedo.stack.bottom = 0;
+ EvoUndoRedo.stack.top = 0;
+ EvoUndoRedo.stack.current = 0;
+
+ EvoUndoRedo.stack.maybeStateChanged();
+ },
+
+ /* Adds a new record into the stack; if any undo had been made, then
+ those records are freed. It can also overwrite old undo steps, if
+ the stack size would overflow MAX_DEPTH. */
+ push : function(record) {
+ if (!EvoUndoRedo.stack.array.length) {
+ EvoUndoRedo.stack.array[0] = null;
+ }
+
+ var next = EvoUndoRedo.stack.clampIndex(EvoUndoRedo.stack.current + 1);
+
+ if (EvoUndoRedo.stack.current != EvoUndoRedo.stack.top) {
+ var tt, bb, cc;
+
+ tt = EvoUndoRedo.stack.top;
+ bb = EvoUndoRedo.stack.bottom;
+ cc = EvoUndoRedo.stack.current;
+
+ if (bb > tt) {
+ tt += EvoUndoRedo.stack.MAX_DEPTH;
+ cc += EvoUndoRedo.stack.MAX_DEPTH;
+ }
+
+ while (cc + 1 <= tt) {
+ EvoUndoRedo.stack.array[EvoUndoRedo.stack.clampIndex(cc + 1)] = null;
+ cc++;
+ }
+ }
+
+ if (next == EvoUndoRedo.stack.bottom) {
+ EvoUndoRedo.stack.bottom =
EvoUndoRedo.stack.clampIndex(EvoUndoRedo.stack.bottom + 1);
+ EvoUndoRedo.stack.array[EvoUndoRedo.stack.bottom] = null;
+ }
+
+ EvoUndoRedo.stack.current = next;
+ EvoUndoRedo.stack.top = next;
+ EvoUndoRedo.stack.array[next] = record;
+
+ EvoUndoRedo.stack.maybeStateChanged();
+ },
+
+ /* Moves the 'current' index in the stack and returns the undo record
+ to be undone; or 'null', when there's no undo record available. */
+ undo : function() {
+ var record = EvoUndoRedo.stack.getCurrentUndoRecord();
+
+ if (record) {
+ EvoUndoRedo.stack.current =
EvoUndoRedo.stack.clampIndex(EvoUndoRedo.stack.current - 1);
+ }
+
+ EvoUndoRedo.stack.maybeStateChanged();
+
+ return record;
+ },
+
+ /* Moves the 'current' index in the stack and returns the redo record
+ to be redone; or 'null', when there's no redo record available. */
+ redo : function() {
+ var record = EvoUndoRedo.stack.getCurrentRedoRecord();
+
+ if (record) {
+ EvoUndoRedo.stack.current =
EvoUndoRedo.stack.clampIndex(EvoUndoRedo.stack.current + 1);
+ }
+
+ EvoUndoRedo.stack.maybeStateChanged();
+
+ return record;
+ },
+
+ pathMatches : function(path1, path2) {
+ if (!path1)
+ return !path2;
+ else if (!path2 || path1.length != path2.length)
+ return false;
+
+ var ii;
+
+ for (ii = 0; ii < path1.length; ii++) {
+ if (path1[ii] != path2[ii])
+ return false;
+ }
+
+ return true;
+ },
+
+ topInsertTextAtSamePlace : function() {
+ if (EvoUndoRedo.stack.current != EvoUndoRedo.stack.top ||
+ EvoUndoRedo.stack.current == EvoUndoRedo.stack.bottom) {
+ return false;
+ }
+
+ var curr, prev;
+
+ curr = EvoUndoRedo.stack.array[EvoUndoRedo.stack.current];
+ prev = EvoUndoRedo.stack.array[EvoUndoRedo.stack.clampIndex(EvoUndoRedo.stack.current
- 1)];
+
+ return curr && prev &&
+ curr.kind == EvoUndoRedo.RECORD_KIND_EVENT &&
+ curr.opType == "insertText" &&
+ !curr.selectionBefore.focusElem &&
+ prev.kind == EvoUndoRedo.RECORD_KIND_EVENT &&
+ prev.opType == "insertText" &&
+ !prev.selectionBefore.focusElem &&
+ curr.firstChildIndex == prev.firstChildIndex &&
+ curr.restChildrenCount == prev.restChildrenCount &&
+ curr.selectionBefore.anchorOffset == prev.selectionAfter.anchorOffset &&
+ EvoUndoRedo.stack.pathMatches(curr.path, prev.path) &&
+ EvoUndoRedo.stack.pathMatches(curr.selectionBefore.anchorElem,
prev.selectionAfter.anchorElem);
+ },
+
+ maybeMergeConsecutive : function(skipFirst, opType) {
+ if (EvoUndoRedo.stack.current != EvoUndoRedo.stack.top ||
+ EvoUndoRedo.stack.current == EvoUndoRedo.stack.bottom) {
+ return;
+ }
+
+ var ii, from, curr, keep = null;
+
+ from = EvoUndoRedo.stack.current;
+ curr = EvoUndoRedo.stack.array[from];
+
+ if (skipFirst) {
+ keep = curr;
+ from = EvoUndoRedo.stack.clampIndex(from - 1);
+ curr = EvoUndoRedo.stack.array[from];
+ }
+
+ if (!curr ||
+ curr.kind != EvoUndoRedo.RECORD_KIND_EVENT ||
+ curr.opType != opType ||
+ curr.selectionBefore.focusElem) {
+ return;
+ }
+
+ for (ii = EvoUndoRedo.stack.clampIndex(from - 1);
+ ii != EvoUndoRedo.stack.bottom;
+ ii = EvoUndoRedo.stack.clampIndex(ii - 1)) {
+ var prev;
+
+ prev = EvoUndoRedo.stack.array[ii];
+
+ if (prev.kind != EvoUndoRedo.RECORD_KIND_EVENT ||
+ prev.opType != opType ||
+ prev.selectionBefore.focusElem ||
+ curr.firstChildIndex != prev.firstChildIndex ||
+ curr.restChildrenCount != prev.restChildrenCount ||
+ curr.selectionBefore.anchorOffset != prev.selectionAfter.anchorOffset ||
+ !EvoUndoRedo.stack.pathMatches(curr.path, prev.path) ||
+ !EvoUndoRedo.stack.pathMatches(curr.selectionBefore.anchorElem,
prev.selectionAfter.anchorElem)) {
+ break;
+ }
+
+ if (opType == "insertText")
+ prev.opType = opType + "::merged";
+ prev.selectionAfter = curr.selectionAfter;
+ prev.htmlAfter = curr.htmlAfter;
+
+ curr = prev;
+ EvoUndoRedo.stack.array[EvoUndoRedo.stack.clampIndex(ii + 1)] = keep;
+ if (keep) {
+ EvoUndoRedo.stack.array[EvoUndoRedo.stack.clampIndex(ii + 2)] = null;
+ }
+
+ EvoUndoRedo.stack.top = ii + (keep ? 1 : 0);
+ EvoUndoRedo.stack.current = EvoUndoRedo.stack.top;
+ }
+
+ EvoUndoRedo.stack.maybeStateChanged();
+ },
+
+ maybeMergeInsertText : function(skipFirst) {
+ EvoUndoRedo.stack.maybeMergeConsecutive(skipFirst, "insertText");
+ EvoUndoRedo.stack.maybeMergeConsecutive(skipFirst, "insertText::WordDelim");
+ },
+
+ maybeMergeDragDrop : function() {
+ if (EvoUndoRedo.stack.current != EvoUndoRedo.stack.top ||
+ EvoUndoRedo.stack.current == EvoUndoRedo.stack.bottom ||
+ EvoUndoRedo.stack.clampIndex(EvoUndoRedo.stack.current - 1) ==
EvoUndoRedo.stack.bottom) {
+ return;
+ }
+
+ var curr, prev;
+
+ curr = EvoUndoRedo.stack.array[EvoUndoRedo.stack.current];
+ prev = EvoUndoRedo.stack.array[EvoUndoRedo.stack.clampIndex(EvoUndoRedo.stack.current
- 1)];
+
+ if (curr && prev &&
+ curr.kind == EvoUndoRedo.RECORD_KIND_EVENT &&
+ prev.kind == EvoUndoRedo.RECORD_KIND_EVENT &&
+ curr.opType == "insertFromDrop" &&
+ prev.opType == "deleteByDrag") {
+ EvoUndoRedo.GroupTopRecords(2, "dragDrop::merged");
+ }
+ }
+ },
+
+ RECORD_KIND_EVENT : 1, /* managed by EvoUndoRedo itself, in DOM events */
+ RECORD_KIND_DOCUMENT : 2, /* saving whole document */
+ RECORD_KIND_GROUP : 3, /* not saving anything, just grouping several records together */
+ RECORD_KIND_CUSTOM : 4, /* custom record */
+
+ /*
+ Record {
+ int kind; // RECORD_KIND_...
+ string opType; // operation type, like the one from oninput
+ Array path; // path to the common parent of the affteded elements
+ int firstChildIndex; // the index of the first children affeted/recorded
+ int restChildrenCount; // the Undo/Redo affects only some children, these are those which
are unaffected after the path
+ Object selectionBefore; // stored selection as it was before the change
+ string htmlBefore; // affected children before the change; can be null, when inserting
new nodes
+ Object selectionAfter; // stored selection as it was after the change
+ string htmlAfter; // affected children before the change; can be null, when removed old
nodes
+
+ Array records; // nested records; can be null or undefined
+ }
+
+ The path, firstChildIndex and restChildrenCount together describe where the changes happened.
+ That is, for example when changing node 'b' into 'x' and 'y':
+ <body> | <body>
+ <a/> | <a/>
+ <b/> | <x/>
+ <c/> | <y/>
+ <d/> | <c/>
+ </body> | <d/>
+ | </body>
+ the 'path' points to 'body', the firstChildIndex=1 and restChildrenCount=2. Then undo/redo can
+ delete all nodes between index >= firstChildIndex && index < children.length - restChildrenCount.
+ */
+
+ dropTarget : null, // passed from dropCb() into beforeInputCb()/inputCb() for "insertFromDrop" event
+ disabled : 0,
+ ongoingRecordings : [] // the recordings can be nested
+};
+
+EvoUndoRedo.Attach = function()
+{
+ if (document.documentElement) {
+ document.documentElement.onbeforeinput = EvoUndoRedo.beforeInputCb;
+ document.documentElement.oninput = EvoUndoRedo.inputCb;
+ document.documentElement.ondrop = EvoUndoRedo.dropCb;
+ }
+}
+
+EvoUndoRedo.Detach = function()
+{
+ if (document.documentElement) {
+ document.documentElement.onbeforeinput = null;
+ document.documentElement.oninput = null;
+ document.documentElement.ondrop = null;
+ }
+}
+
+EvoUndoRedo.Enable = function()
+{
+ if (!EvoUndoRedo.disabled) {
+ throw "EvoUndoRedo:: Cannot Enable, when not disabled";
+ }
+
+ EvoUndoRedo.disabled--;
+}
+
+EvoUndoRedo.Disable = function()
+{
+ EvoUndoRedo.disabled++;
+
+ if (!EvoUndoRedo.disabled) {
+ throw "EvoUndoRedo:: Overflow in Disable";
+ }
+}
+
+EvoUndoRedo.isWordDelimEvent = function(inputEvent)
+{
+ return inputEvent.inputType == "insertText" &&
+ inputEvent.data &&
+ inputEvent.data.length == 1 &&
+ (inputEvent.data == " " || inputEvent.data == "\t");
+}
+
+EvoUndoRedo.beforeInputCb = function(inputEvent)
+{
+ if (EvoUndoRedo.disabled) {
+ return;
+ }
+
+ var opType = inputEvent.inputType, record, startNode = null, endNode = null;
+
+ if (EvoUndoRedo.isWordDelimEvent(inputEvent))
+ opType += "::WordDelim";
+
+ if (opType == "insertFromDrop")
+ startNode = EvoUndoRedo.dropTarget;
+
+ if (document.getSelection().isCollapsed) {
+ if (opType == "deleteWordBackward") {
+ var sel = EvoSelection.Store(document);
+ document.getSelection().modify("move", "backward", "word");
+ startNode = document.getSelection().anchorNode;
+ EvoSelection.Restore(document, sel);
+ } else if (opType == "deleteWordForward") {
+ var sel = EvoSelection.Store(document);
+ document.getSelection().modify("move", "forward", "word");
+ startNode = document.getSelection().anchorNode;
+ EvoSelection.Restore(document, sel);
+ } else if (opType == "deleteSoftLineBackward") {
+ var sel = EvoSelection.Store(document);
+ document.getSelection().modify("move", "backward", "line");
+ startNode = document.getSelection().anchorNode;
+ EvoSelection.Restore(document, sel);
+ } else if (opType == "deleteSoftLineForward") {
+ var sel = EvoSelection.Store(document);
+ document.getSelection().modify("move", "forward", "line");
+ startNode = document.getSelection().anchorNode;
+ EvoSelection.Restore(document, sel);
+ } else if (opType == "deleteEntireSoftLine") {
+ var sel = EvoSelection.Store(document);
+ document.getSelection().modify("move", "backward", "line");
+ startNode = document.getSelection().anchorNode;
+ document.getSelection().modify("move", "forward", "line");
+ endNode = document.getSelection().anchorNode;
+ EvoSelection.Restore(document, sel);
+ } else if (opType == "deleteHardLineBackward") {
+ var sel = EvoSelection.Store(document);
+ document.getSelection().modify("move", "backward", "paragraph");
+ startNode = document.getSelection().anchorNode;
+ EvoSelection.Restore(document, sel);
+ } else if (opType == "deleteHardLineForward") {
+ var sel = EvoSelection.Store(document);
+ document.getSelection().modify("move", "forward", "paragraph");
+ startNode = document.getSelection().anchorNode;
+ EvoSelection.Restore(document, sel);
+ } else if (opType == "deleteContentBackward") {
+ var sel = EvoSelection.Store(document);
+ document.getSelection().modify("move", "backward", "paragraph");
+ startNode = document.getSelection().anchorNode;
+ EvoSelection.Restore(document, sel);
+ } else if (opType == "deleteContentForward") {
+ var sel = EvoSelection.Store(document);
+ document.getSelection().modify("move", "forward", "paragraph");
+ startNode = document.getSelection().anchorNode;
+ EvoSelection.Restore(document, sel);
+ }
+ }
+
+ record = EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_EVENT, opType, startNode, endNode,
+ EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML | EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE);
+
+ /* Changing format with collapsed selection doesn't change HTML structure immediately */
+ if (record && opType.startsWith("format") && document.getSelection().isCollapsed) {
+ record.ignore = true;
+ }
+}
+
+EvoUndoRedo.inputCb = function(inputEvent)
+{
+ var isWordDelim = EvoUndoRedo.isWordDelimEvent(inputEvent);
+
+ if (EvoUndoRedo.disabled) {
+ EvoEditor.EmitContentChanged();
+ EvoEditor.AfterInputEvent(inputEvent, isWordDelim);
+ return;
+ }
+
+ var opType = inputEvent.inputType;
+
+ if (isWordDelim)
+ opType += "::WordDelim";
+
+ if (EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_EVENT, opType)) {
+ EvoEditor.EmitContentChanged();
+
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ }
+
+ if (!EvoUndoRedo.ongoingRecordings.length && opType == "insertText" &&
+ !EvoUndoRedo.stack.topInsertTextAtSamePlace()) {
+ EvoUndoRedo.stack.maybeMergeInsertText(true);
+ }
+
+ EvoEditor.forceFormatStateUpdate = EvoEditor.forceFormatStateUpdate || opType == "" ||
opType.startsWith("format");
+
+ if (opType == "insertFromDrop") {
+ EvoUndoRedo.dropTarget = null;
+ EvoUndoRedo.stack.maybeMergeDragDrop();
+ }
+
+ EvoEditor.AfterInputEvent(inputEvent, isWordDelim);
+}
+
+EvoUndoRedo.dropCb = function(event)
+{
+ EvoUndoRedo.dropTarget = event.toElement;
+}
+
+EvoUndoRedo.applyRecord = function(record, isUndo, withSelection)
+{
+ if (!record) {
+ return;
+ }
+
+ var kind = record.kind;
+
+ if (kind == EvoUndoRedo.RECORD_KIND_GROUP) {
+ var ii, records;
+
+ records = record.records;
+
+ if (records && records.length) {
+ for (ii = 0; ii < records.length; ii++) {
+ EvoUndoRedo.applyRecord(records[isUndo ? (records.length - ii - 1) : ii],
isUndo, false);
+ }
+ }
+
+ if (withSelection) {
+ EvoSelection.Restore(document, isUndo ? record.selectionBefore :
record.selectionAfter);
+ }
+
+ return;
+ }
+
+ EvoUndoRedo.Disable();
+
+ try {
+ if (kind == EvoUndoRedo.RECORD_KIND_DOCUMENT) {
+ if (isUndo) {
+ document.documentElement.innerHTML = record.htmlBefore;
+ } else {
+ document.documentElement.innerHTML = record.htmlAfter;
+ }
+
+ if (record.apply != null) {
+ record.apply(record, isUndo);
+ }
+ } else if (kind == EvoUndoRedo.RECORD_KIND_CUSTOM && record.apply != null) {
+ record.apply(record, isUndo);
+ } else {
+ var commonParent;
+
+ commonParent = EvoSelection.FindElementByPath(document.body, record.path);
+ if (!commonParent) {
+ throw "EvoUndoRedo::applyRecord: Cannot find parent at path " + record.path;
+ }
+
+ EvoUndoRedo.RestoreChildren(record, commonParent, isUndo);
+ }
+
+ if (withSelection) {
+ EvoSelection.Restore(document, isUndo ? record.selectionBefore :
record.selectionAfter);
+ }
+ } finally {
+ EvoUndoRedo.Enable();
+ }
+}
+
+EvoUndoRedo.StartRecord = function(kind, opType, startNode, endNode, flags)
+{
+ if (EvoUndoRedo.disabled) {
+ return null;
+ }
+
+ var record = {};
+
+ record.kind = kind;
+ record.opType = opType;
+ record.selectionBefore = EvoSelection.Store(document);
+
+ if (kind == EvoUndoRedo.RECORD_KIND_DOCUMENT) {
+ record.htmlBefore = document.documentElement.innerHTML;
+ } else if (kind != EvoUndoRedo.RECORD_KIND_GROUP) {
+ var affected;
+
+ affected = EvoEditor.ClaimAffectedContent(startNode, endNode, flags);
+
+ record.path = affected.path;
+ record.firstChildIndex = affected.firstChildIndex;
+ record.restChildrenCount = affected.restChildrenCount;
+
+ if ((flags & EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML) != 0)
+ record.htmlBefore = affected.html;
+ }
+
+ EvoUndoRedo.ongoingRecordings[EvoUndoRedo.ongoingRecordings.length] = record;
+
+ return record;
+}
+
+EvoUndoRedo.StopRecord = function(kind, opType)
+{
+ if (EvoUndoRedo.disabled) {
+ return false;
+ }
+
+ if (!EvoUndoRedo.ongoingRecordings.length) {
+ // Workaround WebKitGTK+ bug not sending beforeInput event when deleting with backspace
+ // https://bugs.webkit.org/show_bug.cgi?id=206341
+ if (opType == "deleteContentBackward")
+ return false;
+
+ throw "EvoUndoRedo:StopRecord: Nothing is recorded for kind:" + kind + " opType:'" + opType +
"'";
+ }
+
+ var record = EvoUndoRedo.ongoingRecordings[EvoUndoRedo.ongoingRecordings.length - 1];
+
+ // Events can overlap sometimes, like when doing drag&drop inside web view
+ if (record.kind != kind || record.opType != opType) {
+ var ii;
+
+ for (ii = EvoUndoRedo.ongoingRecordings.length - 2; ii >= 0; ii--) {
+ record = EvoUndoRedo.ongoingRecordings[ii];
+
+ if (record.kind == kind && record.opType == opType) {
+ var jj;
+
+ for (jj = ii + 1; jj < EvoUndoRedo.ongoingRecordings.length; jj++) {
+ EvoUndoRedo.ongoingRecordings[jj - 1] =
EvoUndoRedo.ongoingRecordings[jj];
+ }
+
+ EvoUndoRedo.ongoingRecordings[EvoUndoRedo.ongoingRecordings.length - 1] =
record;
+ break;
+ }
+ }
+ }
+
+ if (record.kind != kind || record.opType != opType) {
+ // The "InsertContent", especially when inserting plain text, can receive multiple 'input'
events
+ // with "insertParagraph", "insertText" and similar, which do not have its counterpart
beforeInput event,
+ // thus ignore those
+
+ if (record.opType == "InsertContent" && opType.startsWith("insert"))
+ return;
+
+ throw "EvoUndoRedo:StopRecord: Mismatch in record kind, expected " + record.kind + " (" +
record.opType + "), but received " +
+ kind + "(" + opType + "); ongoing recordings:" + EvoUndoRedo.ongoingRecordings.length;
+ }
+
+ EvoUndoRedo.ongoingRecordings.length = EvoUndoRedo.ongoingRecordings.length - 1;
+
+ // ignore empty group records
+ if (kind == EvoUndoRedo.RECORD_KIND_GROUP && (!record.records || !record.records.length)) {
+ record.ignore = true;
+ }
+
+ if (record.ignore) {
+ if (!EvoUndoRedo.ongoingRecordings.length &&
+ (record.kind != EvoUndoRedo.RECORD_KIND_EVENT || record.opType != "insertText")) {
+ EvoUndoRedo.stack.maybeMergeInsertText(false);
+ }
+
+ return false;
+ }
+
+ if (kind == EvoUndoRedo.RECORD_KIND_DOCUMENT) {
+ record.htmlAfter = document.documentElement.innerHTML;
+ } else if (record.htmlBefore != window.undefined) {
+ var commonParent;
+
+ commonParent = EvoSelection.FindElementByPath(document.body, record.path);
+
+ if (!commonParent) {
+ throw "EvoUndoRedo.StopRecord:: Failed to stop '" + opType + "', cannot find common
parent";
+ }
+
+ EvoUndoRedo.BackupChildrenAfter(record, commonParent);
+
+ // some formatting commands do not change HTML structure immediately, thus ignore those
+ if (kind == EvoUndoRedo.RECORD_KIND_EVENT && record.htmlBefore == record.htmlAfter) {
+ if (!EvoUndoRedo.ongoingRecordings.length && record.opType != "insertText") {
+ EvoUndoRedo.stack.maybeMergeInsertText(false);
+ }
+
+ return false;
+ }
+ }
+
+ record.selectionAfter = EvoSelection.Store(document);
+
+ if (EvoUndoRedo.ongoingRecordings.length &&
EvoUndoRedo.ongoingRecordings[EvoUndoRedo.ongoingRecordings.length - 1].kind ==
EvoUndoRedo.RECORD_KIND_GROUP) {
+ var parentRecord = EvoUndoRedo.ongoingRecordings[EvoUndoRedo.ongoingRecordings.length - 1];
+ var records = parentRecord.records;
+
+ if (!records) {
+ records = [];
+ }
+
+ records[records.length] = record;
+ parentRecord.records = records;
+ } else {
+ EvoUndoRedo.stack.push(record);
+
+ if (record.kind == EvoUndoRedo.RECORD_KIND_EVENT && record.opType == "insertText::WordDelim")
{
+ EvoUndoRedo.stack.maybeMergeConsecutive(true, "insertText");
+ EvoUndoRedo.stack.maybeMergeConsecutive(false, "insertText::WordDelim");
+ } else if (record.kind != EvoUndoRedo.RECORD_KIND_EVENT || record.opType != "insertText") {
+ EvoUndoRedo.stack.maybeMergeInsertText(true);
+ }
+ }
+
+ return true;
+}
+
+EvoUndoRedo.IsRecording = function()
+{
+ return !EvoUndoRedo.disabled && EvoUndoRedo.ongoingRecordings.length > 0;
+}
+
+EvoUndoRedo.Undo = function()
+{
+ var record = EvoUndoRedo.stack.undo();
+
+ if (!record)
+ return;
+
+ EvoUndoRedo.applyRecord(record, true, true);
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_YES);
+ EvoEditor.EmitContentChanged();
+}
+
+EvoUndoRedo.Redo = function()
+{
+ var record = EvoUndoRedo.stack.redo();
+
+ if (!record)
+ return;
+
+ EvoUndoRedo.applyRecord(record, false, true);
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_YES);
+ EvoEditor.EmitContentChanged();
+}
+
+EvoUndoRedo.Clear = function()
+{
+ EvoUndoRedo.stack.clear();
+}
+
+EvoUndoRedo.GroupTopRecords = function(nRecords, opType)
+{
+ if (EvoUndoRedo.disabled)
+ return;
+
+ if (EvoUndoRedo.ongoingRecordings.length)
+ throw "EvoUndoRedo.GroupTopRecords: Cannot be called when there are ongoing recordings";
+
+ var group = {};
+
+ group.kind = EvoUndoRedo.RECORD_KIND_GROUP;
+ group.opType = opType;
+ group.selectionBefore = null;
+ group.selectionAfter = null;
+ group.records = [];
+
+ while (nRecords >= 1) {
+ nRecords--;
+
+ var record = EvoUndoRedo.stack.undo();
+
+ if (!record)
+ break;
+
+ group.records[group.records.length] = record;
+ group.selectionBefore = record.selectionBefore;
+
+ if (!group.selectionAfter)
+ group.selectionAfter = record.selectionAfter;
+
+ if (!group.opType)
+ group.opType = record.opType + "::Grouped";
+ }
+
+ if (group.records.length) {
+ group.records = group.records.reverse();
+
+ EvoUndoRedo.stack.push(group);
+ }
+
+ EvoUndoRedo.stack.maybeStateChanged();
+}
+
+/* Backs up all the children elements between firstChildIndex and lastChildIndex inclusive,
+ saving their HTML content into record.htmlBefore; it stores only element children,
+ not text or other nodes. Use also EvoUndoRedo.BackupChildrenAfter() to save all data
+ needed by EvoUndoRedo.RestoreChildren(), which is used to restore saved data.
+ The firstChildIndex can be -1, to back up parent's innerHTML.
+*/
+EvoUndoRedo.BackupChildrenBefore = function(record, parent, firstChildIndex, lastChildIndex)
+{
+ var currentElemsArray = EvoEditor.RemoveCurrentElementAttr();
+
+ try {
+ record.firstChildIndex = firstChildIndex;
+
+ if (firstChildIndex == -1) {
+ record.htmlBefore = parent.innerHTML;
+ } else {
+ record.htmlBefore = "";
+
+ var ii;
+
+ for (ii = firstChildIndex; ii < parent.children.length; ii++) {
+ record.htmlBefore += parent.children[ii].outerHTML;
+
+ if (ii == lastChildIndex) {
+ ii++;
+ break;
+ }
+ }
+
+ record.restChildrenCount = parent.children.length - ii;
+ }
+ } finally {
+ EvoEditor.RestoreCurrentElementAttr(currentElemsArray);
+ }
+}
+
+EvoUndoRedo.BackupChildrenAfter = function(record, parent)
+{
+ if (record.firstChildIndex == undefined)
+ throw "EvoUndoRedo.BackupChildrenAfter: 'record' doesn't contain 'firstChildIndex' property";
+ if (record.firstChildIndex != -1 && record.restChildrenCount == undefined)
+ throw "EvoUndoRedo.BackupChildrenAfter: 'record' doesn't contain 'restChildrenCount'
property";
+ if (record.htmlBefore == undefined)
+ throw "EvoUndoRedo.BackupChildrenAfter: 'record' doesn't contain 'htmlBefore' property";
+
+ var currentElemsArray = EvoEditor.RemoveCurrentElementAttr();
+
+ try {
+ if (record.firstChildIndex == -1) {
+ record.htmlAfter = parent.innerHTML;
+ } else {
+ record.htmlAfter = "";
+
+ var ii, first, last;
+
+ first = record.firstChildIndex;
+
+ // it can equal to the children.length, when the node had been removed
+ if (first < 0 || first > parent.children.length) {
+ throw "EvoUndoRedo.BackupChildrenAfter: firstChildIndex (" + first + ") out
of bounds (" + parent.children.length + ")";
+ }
+
+ last = parent.children.length - record.restChildrenCount;
+ if (last < 0 || last < first) {
+ throw "EvoUndoRedo::BackupChildrenAfter: restChildrenCount (" +
record.restChildrenCount + ") out of bounds (length:" +
+ parent.children.length + " first:" + first + " last:" + last + ")";
+ }
+
+ for (ii = first; ii < last; ii++) {
+ if (ii >= 0 && ii < parent.children.length) {
+ record.htmlAfter += parent.children[ii].outerHTML;
+ }
+ }
+ }
+ } finally {
+ EvoEditor.RestoreCurrentElementAttr(currentElemsArray);
+ }
+}
+
+// restores content of 'parent' based on the information saved by EvoUndoRedo.BackupChildrenBefore()
+// and EvoUndoRedo.BackupChildrenAfter()
+EvoUndoRedo.RestoreChildren = function(record, parent, isUndo)
+{
+ var first, last, ii;
+
+ if (record.firstChildIndex == undefined)
+ throw "EvoUndoRedo.RestoreChildren: 'record' doesn't contain 'firstChildIndex' property";
+ if (record.firstChildIndex != -1 && record.restChildrenCount == undefined)
+ throw "EvoUndoRedo.RestoreChildren: 'record' doesn't contain 'restChildrenCount' property";
+ if (record.htmlBefore == undefined)
+ throw "EvoUndoRedo.RestoreChildren: 'record' doesn't contain 'htmlBefore' property";
+ if (record.htmlAfter == undefined)
+ throw "EvoUndoRedo.RestoreChildren: 'record' doesn't contain 'htmlAfter' property";
+
+ first = record.firstChildIndex;
+
+ if (first == -1) {
+ if (isUndo) {
+ parent.innerHTML = record.htmlBefore;
+ } else {
+ parent.innerHTML = record.htmlAfter;
+ }
+ } else {
+ // it can equal to the children.length, when the node had been removed
+ if (first < 0 || first > parent.children.length) {
+ throw "EvoUndoRedo::RestoreChildren: firstChildIndex (" + first + ") out of bounds ("
+ parent.children.length + ")";
+ }
+
+ last = parent.children.length - record.restChildrenCount;
+ if (last < 0 || last < first) {
+ throw "EvoUndoRedo::RestoreChildren: restChildrenCount (" + record.restChildrenCount
+ ") out of bounds (length:" +
+ parent.children.length + " first:" + first + " last:" + last + ")";
+ }
+
+ for (ii = last - 1; ii >= first; ii--) {
+ if (ii >= 0 && ii < parent.children.length) {
+ parent.removeChild(parent.children[ii]);
+ }
+ }
+
+ var tmpNode = document.createElement("evo-tmp");
+
+ if (isUndo) {
+ tmpNode.innerHTML = record.htmlBefore;
+ } else {
+ tmpNode.innerHTML = record.htmlAfter;
+ }
+
+ if (first < parent.children.length) {
+ first = parent.children[first];
+
+ while(tmpNode.firstElementChild) {
+ parent.insertBefore(tmpNode.firstElementChild, first);
+ }
+ } else {
+ while(tmpNode.firstElementChild) {
+ parent.appendChild(tmpNode.firstElementChild);
+ }
+ }
+ }
+}
+
+EvoUndoRedo.Attach();
diff --git a/data/webkit/e-web-view.js b/data/webkit/e-web-view.js
index 771d35139b..0aa006f603 100644
--- a/data/webkit/e-web-view.js
+++ b/data/webkit/e-web-view.js
@@ -1,3 +1,20 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
'use strict';
/* semi-convention: private functions start with lower-case letter,
@@ -405,12 +422,12 @@ Evo.getElementContent = function(node, format, useOuterHTML)
var data;
if (format == 1) {
- data = EvoConvertToPlainText(node);
+ data = EvoConvert.ToPlainText(node);
} else if (format == 2) {
data = useOuterHTML ? node.outerHTML : node.innerHTML;
} else if (format == 3) {
data = {};
- data["plain"] = EvoConvertToPlainText(node);
+ data["plain"] = EvoConvert.ToPlainText(node);
data["html"] = useOuterHTML ? node.outerHTML : node.innerHTML;
}
diff --git a/docs/reference/evolution-util/evolution-util-docs.sgml.in
b/docs/reference/evolution-util/evolution-util-docs.sgml.in
index 95d3f63fc7..24df1d465b 100644
--- a/docs/reference/evolution-util/evolution-util-docs.sgml.in
+++ b/docs/reference/evolution-util/evolution-util-docs.sgml.in
@@ -315,7 +315,6 @@
<xi:include href="xml/e-tree-view-frame.xml"/>
<xi:include href="xml/e-url-entry.xml"/>
<xi:include href="xml/e-util-enums.xml"/>
- <xi:include href="xml/e-web-extension-container.xml"/>
<xi:include href="xml/e-webdav-browser.xml"/>
<xi:include href="xml/e-widget-undo.xml"/>
</chapter>
diff --git a/src/composer/e-composer-actions.c b/src/composer/e-composer-actions.c
index 6990e19023..5cb03cab94 100644
--- a/src/composer/e-composer-actions.c
+++ b/src/composer/e-composer-actions.c
@@ -162,6 +162,30 @@ action_print_preview_cb (GtkAction *action,
e_msg_composer_print (composer, print_action);
}
+static void
+action_save_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EMsgComposer *composer = user_data;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+ g_return_if_fail (E_IS_HTML_EDITOR (source_object));
+
+ if (!e_html_editor_save_finish (E_HTML_EDITOR (source_object), result, &error)) {
+ e_alert_submit (
+ E_ALERT_SINK (composer),
+ E_ALERT_NO_SAVE_FILE,
+ e_html_editor_get_filename (E_HTML_EDITOR (source_object)), error ? error->message :
_("Unknown error"), NULL);
+ } else {
+ composer_set_content_editor_changed (composer);
+ }
+
+ g_object_unref (composer);
+ g_clear_error (&error);
+}
+
static void
action_save_cb (GtkAction *action,
EMsgComposer *composer)
@@ -169,7 +193,6 @@ action_save_cb (GtkAction *action,
EHTMLEditor *editor;
const gchar *filename;
gint fd;
- GError *error = NULL;
editor = e_msg_composer_get_editor (composer);
filename = e_html_editor_get_filename (editor);
@@ -202,16 +225,7 @@ action_save_cb (GtkAction *action,
} else
close (fd);
- if (!e_html_editor_save (editor, filename, TRUE, &error)) {
- e_alert_submit (
- E_ALERT_SINK (composer),
- E_ALERT_NO_SAVE_FILE,
- filename, error->message, NULL);
- g_error_free (error);
- return;
- }
-
- composer_set_content_editor_changed (composer);
+ e_html_editor_save (editor, filename, TRUE, NULL, action_save_ready_cb, g_object_ref (composer));
}
static void
diff --git a/src/composer/e-composer-private.c b/src/composer/e-composer-private.c
index 8b6b8b4625..e4a1c17924 100644
--- a/src/composer/e-composer-private.c
+++ b/src/composer/e-composer-private.c
@@ -552,6 +552,8 @@ e_composer_private_finalize (EMsgComposer *composer)
g_free (composer->priv->mime_type);
g_free (composer->priv->mime_body);
g_free (composer->priv->previous_identity_uid);
+
+ g_clear_pointer (&composer->priv->content_hash, e_content_editor_util_free_content_hash);
}
gchar *
diff --git a/src/composer/e-composer-private.h b/src/composer/e-composer-private.h
index 4a2e2e3e06..c415974cbc 100644
--- a/src/composer/e-composer-private.h
+++ b/src/composer/e-composer-private.h
@@ -121,6 +121,9 @@ struct _EMsgComposerPrivate {
gulong drag_data_received_handler_id;
gchar *previous_identity_uid;
+
+ guint content_hash_ref_count; /* when reaches 0, the content_hash is freed; to be able to reuse it */
+ EContentEditorContentHash *content_hash;
};
void e_composer_private_constructed (EMsgComposer *composer);
diff --git a/src/composer/e-msg-composer.c b/src/composer/e-msg-composer.c
index 1c6db9adb1..41a9f0a71f 100644
--- a/src/composer/e-msg-composer.c
+++ b/src/composer/e-msg-composer.c
@@ -180,6 +180,19 @@ async_context_free (AsyncContext *context)
g_slice_free (AsyncContext, context);
}
+static void
+e_msg_composer_unref_content_hash (EMsgComposer *composer)
+{
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+ g_return_if_fail (composer->priv->content_hash_ref_count > 0);
+
+ composer->priv->content_hash_ref_count--;
+
+ if (!composer->priv->content_hash_ref_count) {
+ g_clear_pointer (&composer->priv->content_hash, e_content_editor_util_free_content_hash);
+ }
+}
+
static void
e_msg_composer_inc_soft_busy (EMsgComposer *composer)
{
@@ -1425,7 +1438,7 @@ composer_build_message (EMsgComposer *composer,
type = camel_content_type_decode (priv->mime_type);
} else {
- gchar *text;
+ const gchar *text;
EHTMLEditor *editor;
EContentEditor *cnt_editor;
@@ -1433,23 +1446,19 @@ composer_build_message (EMsgComposer *composer,
cnt_editor = e_html_editor_get_content_editor (editor);
data = g_byte_array_new ();
- text = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_TEXT_PLAIN |
- E_CONTENT_EDITOR_GET_PROCESSED,
- NULL, NULL);
+ text = e_content_editor_util_get_content_data (e_msg_composer_get_content_hash (composer),
+ E_CONTENT_EDITOR_GET_TO_SEND_PLAIN);
if (!text) {
g_warning ("%s: Failed to retrieve text/plain processed content", G_STRFUNC);
- text = g_strdup ("");
+ text = "";
last_error = e_content_editor_dup_last_error (cnt_editor);
}
g_byte_array_append (data, (guint8 *) text, strlen (text));
- if (!g_str_has_suffix (text, "\r\n"))
+ if (!g_str_has_suffix (text, "\r\n") && !g_str_has_suffix (text, "\n"))
g_byte_array_append (data, (const guint8 *) "\r\n", 2);
- g_free (text);
type = camel_content_type_new ("text", "plain");
charset = best_charset (
@@ -1509,16 +1518,11 @@ composer_build_message (EMsgComposer *composer,
if ((flags & COMPOSER_FLAG_HTML_CONTENT) != 0 ||
(flags & COMPOSER_FLAG_SAVE_DRAFT) != 0) {
- gchar *text;
+ const gchar *text;
gsize length;
gboolean pre_encode;
- EHTMLEditor *editor;
- EContentEditor *cnt_editor;
GSList *inline_images_parts = NULL, *link;
- editor = e_msg_composer_get_editor (composer);
- cnt_editor = e_html_editor_get_content_editor (editor);
-
data = g_byte_array_new ();
if ((flags & COMPOSER_FLAG_SAVE_DRAFT) != 0) {
/* X-Evolution-Format */
@@ -1529,39 +1533,31 @@ composer_build_message (EMsgComposer *composer,
composer_add_evolution_composer_mode_header (
CAMEL_MEDIUM (context->message), composer);
- text = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_TEXT_HTML |
- E_CONTENT_EDITOR_GET_INLINE_IMAGES,
- from_domain, &inline_images_parts);
+ text = e_content_editor_util_get_content_data (e_msg_composer_get_content_hash
(composer),
+ E_CONTENT_EDITOR_GET_RAW_DRAFT);
if (!text) {
g_warning ("%s: Failed to retrieve draft content", G_STRFUNC);
- text = g_strdup ("");
+ text = "";
}
} else {
- text = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_TEXT_HTML |
- E_CONTENT_EDITOR_GET_PROCESSED |
- E_CONTENT_EDITOR_GET_INLINE_IMAGES,
- from_domain, &inline_images_parts);
+ text = e_content_editor_util_get_content_data (e_msg_composer_get_content_hash
(composer),
+ E_CONTENT_EDITOR_GET_TO_SEND_HTML);
if (!text) {
g_warning ("%s: Failed to retrieve HTML processed content", G_STRFUNC);
- text = g_strdup ("");
+ text = "";
}
}
- if (!last_error)
- last_error = e_content_editor_dup_last_error (cnt_editor);
+ inline_images_parts = e_content_editor_util_get_content_data (e_msg_composer_get_content_hash
(composer),
+ E_CONTENT_EDITOR_GET_INLINE_IMAGES);
length = strlen (text);
g_byte_array_append (data, (guint8 *) text, (guint) length);
- if (!g_str_has_suffix (text, "\r\n"))
+ if (!g_str_has_suffix (text, "\r\n") && !g_str_has_suffix (text, "\n"))
g_byte_array_append (data, (const guint8 *) "\r\n", 2);
pre_encode = text_requires_quoted_printable (text, length);
- g_free (text);
mem_stream = camel_stream_mem_new_with_byte_array (data);
stream = camel_stream_filter_new (mem_stream);
@@ -1633,7 +1629,7 @@ composer_build_message (EMsgComposer *composer,
for (link = inline_images_parts; link; link = g_slist_next (link)) {
CamelMimePart *part = link->data;
- camel_multipart_add_part (html_with_images, part);
+ camel_multipart_add_part (html_with_images, g_object_ref (part));
}
context->top_level_part =
@@ -1642,7 +1638,6 @@ composer_build_message (EMsgComposer *composer,
context->top_level_part =
CAMEL_DATA_WRAPPER (body);
}
- g_slist_free_full (inline_images_parts, g_object_unref);
}
view = e_msg_composer_get_attachment_view (composer);
@@ -3167,7 +3162,6 @@ add_attachments_handle_mime_part (EMsgComposer *composer,
CamelContentType *content_type;
CamelDataWrapper *wrapper;
EHTMLEditor *editor;
- EContentEditor *cnt_editor;
if (!mime_part)
return;
@@ -3175,7 +3169,6 @@ add_attachments_handle_mime_part (EMsgComposer *composer,
content_type = camel_mime_part_get_content_type (mime_part);
wrapper = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
editor = e_msg_composer_get_editor (composer);
- cnt_editor = e_html_editor_get_content_editor (editor);
if (CAMEL_IS_MULTIPART (wrapper)) {
/* another layer of multipartness... */
@@ -3186,10 +3179,9 @@ add_attachments_handle_mime_part (EMsgComposer *composer,
if (camel_content_type_is (content_type, "image", "*") && (
camel_mime_part_get_content_id (mime_part) ||
camel_mime_part_get_content_location (mime_part)))
- e_content_editor_insert_image_from_mime_part (
- cnt_editor, mime_part);
+ e_html_editor_add_cid_part (editor, mime_part);
} else if (related && camel_content_type_is (content_type, "image", "*")) {
- e_content_editor_insert_image_from_mime_part (cnt_editor, mime_part);
+ e_html_editor_add_cid_part (editor, mime_part);
} else if (camel_content_type_is (content_type, "text", "*") &&
camel_mime_part_get_filename (mime_part) == NULL) {
/* Do nothing if this is a text/anything without a
@@ -3609,12 +3601,10 @@ handle_multipart (EMsgComposer *composer,
camel_mime_part_get_content_location (mime_part))) {
/* special in-line attachment */
EHTMLEditor *editor;
- EContentEditor *cnt_editor;
editor = e_msg_composer_get_editor (composer);
- cnt_editor = e_html_editor_get_content_editor (editor);
- e_content_editor_insert_image_from_mime_part (cnt_editor, mime_part);
+ e_html_editor_add_cid_part (editor, mime_part);
/* Add it to both, to not lose attachments not referenced in HTML body.
The inserted images are not included in the message when not referenced. */
@@ -4250,40 +4240,200 @@ e_msg_composer_get_shell (EMsgComposer *composer)
return E_SHELL (composer->priv->shell);
}
+/**
+ * e_msg_composer_get_content_hash:
+ * @composer: an #EMsgComposer
+ *
+ * Returns current #EContentEditorContentHash with content
+ * of the composer. It's valid, and available, only during
+ * operations/signals, which construct message from the @composer
+ * content. The @composer precaches the content, thus it can
+ * be accessed in a synchronous way (in constrast to EContentEditor,
+ * which allows getting the content only asynchronously).
+ * The content hash is owned by the @composer and it is freed
+ * as soon as the respective operation is finished.
+ *
+ * Returns: (transfer none) (nullable): an #EContentEditorContentHash
+ * with current content data, or %NULL, when it is not loaded.
+ *
+ * Since: 3.38
+ **/
+EContentEditorContentHash *
+e_msg_composer_get_content_hash (EMsgComposer *composer)
+{
+ g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL);
+
+ /* Calling the function out of expected place should warn that something goes wrong */
+ g_warn_if_fail (composer->priv->content_hash != NULL);
+
+ return composer->priv->content_hash;
+}
+
+typedef void (* PrepareContentHashCallback) (EMsgComposer *composer,
+ gpointer user_data,
+ const GError *error);
+
+typedef struct _PrepareContentHashData {
+ EMsgComposer *composer;
+ PrepareContentHashCallback callback;
+ gpointer user_data;
+} PrepareContentHashData;
+
+static PrepareContentHashData *
+prepare_content_hash_data_new (EMsgComposer *composer,
+ PrepareContentHashCallback callback,
+ gpointer user_data)
+{
+ PrepareContentHashData *pchd;
+
+ pchd = g_slice_new (PrepareContentHashData);
+ pchd->composer = g_object_ref (composer);
+ pchd->callback = callback;
+ pchd->user_data = user_data;
+
+ return pchd;
+}
+
+static void
+prepare_content_hash_data_free (gpointer ptr)
+{
+ PrepareContentHashData *pchd = ptr;
+
+ if (pchd) {
+ g_clear_object (&pchd->composer);
+ g_slice_free (PrepareContentHashData, pchd);
+ }
+}
+
+static void
+e_msg_composer_prepare_content_hash_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ PrepareContentHashData *pchd = user_data;
+ EContentEditorContentHash *content_hash;
+ GError *error = NULL;
+
+ g_return_if_fail (pchd != NULL);
+ g_return_if_fail (E_IS_CONTENT_EDITOR (source_object));
+
+ content_hash = e_content_editor_get_content_finish (E_CONTENT_EDITOR (source_object), result, &error);
+
+ if (content_hash) {
+ g_warn_if_fail (pchd->composer->priv->content_hash == NULL);
+ g_warn_if_fail (pchd->composer->priv->content_hash_ref_count == 0);
+
+ pchd->composer->priv->content_hash = content_hash;
+ pchd->composer->priv->content_hash_ref_count = 1;
+ }
+
+ pchd->callback (pchd->composer, pchd->user_data, error);
+
+ prepare_content_hash_data_free (pchd);
+ g_clear_error (&error);
+}
+
+static void
+e_msg_composer_prepare_content_hash (EMsgComposer *composer,
+ GCancellable *cancellable,
+ EActivity *activity,
+ PrepareContentHashCallback callback,
+ gpointer user_data)
+{
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ CamelInternetAddress *from;
+ PrepareContentHashData *pchd;
+ const gchar *from_domain = NULL;
+
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+ g_return_if_fail (callback != NULL);
+
+ /* Cannot use e_msg_composer_get_content_hash() here, because it prints
+ a runtime warning when the content_hash is NULL. */
+ if (composer->priv->content_hash) {
+ composer->priv->content_hash_ref_count++;
+
+ callback (composer, user_data, NULL);
+ return;
+ }
+
+ if (activity)
+ e_activity_set_text (activity, _("Reading text content…"));
+
+ pchd = prepare_content_hash_data_new (composer, callback, user_data);
+ editor = e_msg_composer_get_editor (composer);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ from = e_msg_composer_get_from (composer);
+
+ if (from && camel_internet_address_get (from, 0, NULL, &from_domain)) {
+ const gchar *at = strchr (from_domain, '@');
+
+ if (at)
+ from_domain = at + 1;
+ else
+ from_domain = NULL;
+ }
+
+ if (!from_domain || !*from_domain)
+ from_domain = "localhost";
+
+ e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_ALL, from_domain, cancellable,
+ e_msg_composer_prepare_content_hash_ready_cb, pchd);
+
+ g_clear_object (&from);
+}
+
+static gboolean
+e_msg_composer_claim_no_build_message_error (EMsgComposer *composer,
+ EActivity *activity,
+ const GError *error,
+ gboolean unref_content_hash_on_error)
+{
+ g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), FALSE);
+
+ if (error) {
+ if (!e_activity_handle_cancellation (activity, error)) {
+ EAlertSink *alert_sink;
+
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ e_alert_submit (
+ alert_sink,
+ "mail-composer:no-build-message",
+ error->message, NULL);
+ }
+
+ if (e_msg_composer_is_exiting (composer)) {
+ gtk_window_present (GTK_WINDOW (composer));
+ composer->priv->application_exiting = FALSE;
+ }
+
+ gtk_window_present (GTK_WINDOW (composer));
+
+ if (unref_content_hash_on_error)
+ e_msg_composer_unref_content_hash (composer);
+ }
+
+ return error != NULL;
+}
+
static void
msg_composer_send_cb (EMsgComposer *composer,
GAsyncResult *result,
AsyncContext *context)
{
CamelMimeMessage *message;
- EAlertSink *alert_sink;
EHTMLEditor *editor;
EContentEditor *cnt_editor;
GError *error = NULL;
- alert_sink = e_activity_get_alert_sink (context->activity);
-
message = e_msg_composer_get_message_finish (composer, result, &error);
- if (e_activity_handle_cancellation (context->activity, error)) {
- g_warn_if_fail (message == NULL);
- async_context_free (context);
- g_error_free (error);
-
- gtk_window_present (GTK_WINDOW (composer));
- return;
- }
-
- if (error != NULL) {
+ if (e_msg_composer_claim_no_build_message_error (composer, context->activity, error, TRUE)) {
g_warn_if_fail (message == NULL);
- e_alert_submit (
- alert_sink,
- "mail-composer:no-build-message",
- error->message, NULL);
async_context_free (context);
- g_error_free (error);
-
- gtk_window_present (GTK_WINDOW (composer));
+ g_clear_error (&error);
return;
}
@@ -4304,9 +4454,47 @@ msg_composer_send_cb (EMsgComposer *composer,
g_object_unref (message);
+ e_msg_composer_unref_content_hash (composer);
async_context_free (context);
}
+static void
+e_msg_composer_send_content_hash_ready_cb (EMsgComposer *composer,
+ gpointer user_data,
+ const GError *error)
+{
+ AsyncContext *context = user_data;
+ gboolean proceed_with_send = TRUE;
+
+ g_return_if_fail (context != NULL);
+
+ if (e_msg_composer_claim_no_build_message_error (composer, context->activity, error, FALSE)) {
+ async_context_free (context);
+ return;
+ }
+
+ /* This gives the user a chance to abort the send. */
+ g_signal_emit (composer, signals[PRESEND], 0, &proceed_with_send);
+
+ if (!proceed_with_send) {
+ gtk_window_present (GTK_WINDOW (composer));
+ e_msg_composer_unref_content_hash (composer);
+
+ if (e_msg_composer_is_exiting (composer)) {
+ gtk_window_present (GTK_WINDOW (composer));
+ composer->priv->application_exiting = FALSE;
+ }
+
+ async_context_free (context);
+ return;
+ }
+
+ e_msg_composer_get_message (
+ composer, G_PRIORITY_DEFAULT, e_activity_get_cancellable (context->activity),
+ (GAsyncReadyCallback) msg_composer_send_cb,
+ context);
+}
+
/**
* e_msg_composer_send:
* @composer: an #EMsgComposer
@@ -4319,18 +4507,9 @@ e_msg_composer_send (EMsgComposer *composer)
EHTMLEditor *editor;
AsyncContext *context;
GCancellable *cancellable;
- gboolean proceed_with_send = TRUE;
g_return_if_fail (E_IS_MSG_COMPOSER (composer));
- /* This gives the user a chance to abort the send. */
- g_signal_emit (composer, signals[PRESEND], 0, &proceed_with_send);
-
- if (!proceed_with_send) {
- gtk_window_present (GTK_WINDOW (composer));
- return;
- }
-
editor = e_msg_composer_get_editor (composer);
context = g_slice_new0 (AsyncContext);
@@ -4338,10 +4517,8 @@ e_msg_composer_send (EMsgComposer *composer)
cancellable = e_activity_get_cancellable (context->activity);
- e_msg_composer_get_message (
- composer, G_PRIORITY_DEFAULT, cancellable,
- (GAsyncReadyCallback) msg_composer_send_cb,
- context);
+ e_msg_composer_prepare_content_hash (composer, cancellable, context->activity,
+ e_msg_composer_send_content_hash_ready_cb, context);
}
static void
@@ -4374,43 +4551,16 @@ msg_composer_save_to_drafts_cb (EMsgComposer *composer,
AsyncContext *context)
{
CamelMimeMessage *message;
- EAlertSink *alert_sink;
EHTMLEditor *editor;
EContentEditor *cnt_editor;
GError *error = NULL;
- alert_sink = e_activity_get_alert_sink (context->activity);
-
- message = e_msg_composer_get_message_draft_finish (
- composer, result, &error);
-
- if (e_activity_handle_cancellation (context->activity, error)) {
- g_warn_if_fail (message == NULL);
- async_context_free (context);
- g_error_free (error);
-
- if (e_msg_composer_is_exiting (composer)) {
- gtk_window_present (GTK_WINDOW (composer));
- composer->priv->application_exiting = FALSE;
- }
+ message = e_msg_composer_get_message_draft_finish (composer, result, &error);
- return;
- }
-
- if (error != NULL) {
+ if (e_msg_composer_claim_no_build_message_error (composer, context->activity, error, TRUE)) {
g_warn_if_fail (message == NULL);
- e_alert_submit (
- alert_sink,
- "mail-composer:no-build-message",
- error->message, NULL);
async_context_free (context);
- g_error_free (error);
-
- if (e_msg_composer_is_exiting (composer)) {
- gtk_window_present (GTK_WINDOW (composer));
- composer->priv->application_exiting = FALSE;
- }
-
+ g_clear_error (&error);
return;
}
@@ -4432,9 +4582,34 @@ msg_composer_save_to_drafts_cb (EMsgComposer *composer,
G_OBJECT (context->activity),
msg_composer_save_to_drafts_done_cb, composer);
+ e_msg_composer_unref_content_hash (composer);
async_context_free (context);
}
+static void
+e_msg_composer_save_to_drafts_content_hash_ready_cb (EMsgComposer *composer,
+ gpointer user_data,
+ const GError *error)
+{
+ AsyncContext *context = user_data;
+
+ g_return_if_fail (context != NULL);
+
+ if (e_msg_composer_claim_no_build_message_error (composer, context->activity, error, FALSE)) {
+ if (e_msg_composer_is_exiting (composer)) {
+ gtk_window_present (GTK_WINDOW (composer));
+ composer->priv->application_exiting = FALSE;
+ }
+ async_context_free (context);
+ return;
+ }
+
+ e_msg_composer_get_message_draft (
+ composer, G_PRIORITY_DEFAULT, e_activity_get_cancellable (context->activity),
+ (GAsyncReadyCallback) msg_composer_save_to_drafts_cb,
+ context);
+}
+
/**
* e_msg_composer_save_to_drafts:
* @composer: an #EMsgComposer
@@ -4458,10 +4633,8 @@ e_msg_composer_save_to_drafts (EMsgComposer *composer)
cancellable = e_activity_get_cancellable (context->activity);
- e_msg_composer_get_message_draft (
- composer, G_PRIORITY_DEFAULT, cancellable,
- (GAsyncReadyCallback) msg_composer_save_to_drafts_cb,
- context);
+ e_msg_composer_prepare_content_hash (composer, cancellable, context->activity,
+ e_msg_composer_save_to_drafts_content_hash_ready_cb, context);
}
static void
@@ -4470,30 +4643,16 @@ msg_composer_save_to_outbox_cb (EMsgComposer *composer,
AsyncContext *context)
{
CamelMimeMessage *message;
- EAlertSink *alert_sink;
EHTMLEditor *editor;
EContentEditor *cnt_editor;
GError *error = NULL;
- alert_sink = e_activity_get_alert_sink (context->activity);
-
message = e_msg_composer_get_message_finish (composer, result, &error);
- if (e_activity_handle_cancellation (context->activity, error)) {
- g_warn_if_fail (message == NULL);
- async_context_free (context);
- g_error_free (error);
- return;
- }
-
- if (error != NULL) {
+ if (e_msg_composer_claim_no_build_message_error (composer, context->activity, error, TRUE)) {
g_warn_if_fail (message == NULL);
- e_alert_submit (
- alert_sink,
- "mail-composer:no-build-message",
- error->message, NULL);
async_context_free (context);
- g_error_free (error);
+ g_clear_error (&error);
return;
}
@@ -4505,11 +4664,49 @@ msg_composer_save_to_outbox_cb (EMsgComposer *composer,
g_object_unref (message);
- async_context_free (context);
-
editor = e_msg_composer_get_editor (composer);
cnt_editor = e_html_editor_get_content_editor (editor);
e_content_editor_set_changed (cnt_editor, TRUE);
+
+ async_context_free (context);
+}
+
+static void
+e_msg_composer_save_to_outbox_content_hash_ready_cb (EMsgComposer *composer,
+ gpointer user_data,
+ const GError *error)
+{
+ AsyncContext *context = user_data;
+
+ g_return_if_fail (context != NULL);
+
+ if (e_msg_composer_claim_no_build_message_error (composer, context->activity, error, FALSE)) {
+ async_context_free (context);
+ return;
+ }
+
+ if (!composer->priv->is_sending_message) {
+ gboolean proceed_with_save = TRUE;
+
+ /* This gives the user a chance to abort the save. */
+ g_signal_emit (composer, signals[PRESEND], 0, &proceed_with_save);
+
+ if (!proceed_with_save) {
+ if (e_msg_composer_is_exiting (composer)) {
+ gtk_window_present (GTK_WINDOW (composer));
+ composer->priv->application_exiting = FALSE;
+ }
+
+ e_msg_composer_unref_content_hash (composer);
+ async_context_free (context);
+ return;
+ }
+ }
+
+ e_msg_composer_get_message (
+ composer, G_PRIORITY_DEFAULT, e_activity_get_cancellable (context->activity),
+ (GAsyncReadyCallback) msg_composer_save_to_outbox_cb,
+ context);
}
/**
@@ -4527,16 +4724,6 @@ e_msg_composer_save_to_outbox (EMsgComposer *composer)
g_return_if_fail (E_IS_MSG_COMPOSER (composer));
- if (!composer->priv->is_sending_message) {
- gboolean proceed_with_save = TRUE;
-
- /* This gives the user a chance to abort the save. */
- g_signal_emit (composer, signals[PRESEND], 0, &proceed_with_save);
-
- if (!proceed_with_save)
- return;
- }
-
editor = e_msg_composer_get_editor (composer);
context = g_slice_new0 (AsyncContext);
@@ -4544,10 +4731,8 @@ e_msg_composer_save_to_outbox (EMsgComposer *composer)
cancellable = e_activity_get_cancellable (context->activity);
- e_msg_composer_get_message (
- composer, G_PRIORITY_DEFAULT, cancellable,
- (GAsyncReadyCallback) msg_composer_save_to_outbox_cb,
- context);
+ e_msg_composer_prepare_content_hash (composer, cancellable, context->activity,
+ e_msg_composer_save_to_outbox_content_hash_ready_cb, context);
}
static void
@@ -4556,29 +4741,14 @@ msg_composer_print_cb (EMsgComposer *composer,
AsyncContext *context)
{
CamelMimeMessage *message;
- EAlertSink *alert_sink;
GError *error = NULL;
- alert_sink = e_activity_get_alert_sink (context->activity);
-
- message = e_msg_composer_get_message_print_finish (
- composer, result, &error);
+ message = e_msg_composer_get_message_print_finish (composer, result, &error);
- if (e_activity_handle_cancellation (context->activity, error)) {
+ if (e_msg_composer_claim_no_build_message_error (composer, context->activity, error, TRUE)) {
g_warn_if_fail (message == NULL);
async_context_free (context);
- g_error_free (error);
- return;
- }
-
- if (error != NULL) {
- g_warn_if_fail (message == NULL);
- async_context_free (context);
- e_alert_submit (
- alert_sink,
- "mail-composer:no-build-message",
- error->message, NULL);
- g_error_free (error);
+ g_clear_error (&error);
return;
}
@@ -4593,6 +4763,26 @@ msg_composer_print_cb (EMsgComposer *composer,
async_context_free (context);
}
+static void
+e_msg_composer_print_content_hash_ready_cb (EMsgComposer *composer,
+ gpointer user_data,
+ const GError *error)
+{
+ AsyncContext *context = user_data;
+
+ g_return_if_fail (context != NULL);
+
+ if (e_msg_composer_claim_no_build_message_error (composer, context->activity, error, FALSE)) {
+ async_context_free (context);
+ return;
+ }
+
+ e_msg_composer_get_message_print (
+ composer, G_PRIORITY_DEFAULT, e_activity_get_cancellable (context->activity),
+ (GAsyncReadyCallback) msg_composer_print_cb,
+ context);
+}
+
/**
* e_msg_composer_print:
* @composer: an #EMsgComposer
@@ -4618,10 +4808,8 @@ e_msg_composer_print (EMsgComposer *composer,
cancellable = e_activity_get_cancellable (context->activity);
- e_msg_composer_get_message_print (
- composer, G_PRIORITY_DEFAULT, cancellable,
- (GAsyncReadyCallback) msg_composer_print_cb,
- context);
+ e_msg_composer_prepare_content_hash (composer, cancellable, context->activity,
+ e_msg_composer_print_content_hash_ready_cb, context);
}
static GList *
@@ -5346,9 +5534,86 @@ composer_get_message_ready (EMsgComposer *composer,
g_simple_async_result_complete (simple);
+ e_msg_composer_unref_content_hash (composer);
+
g_object_unref (simple);
}
+typedef struct _BuildMessageWrapperData {
+ EMsgComposer *composer;
+ ComposerFlags flags;
+ gint io_priority;
+ GCancellable *cancellable;
+ GSimpleAsyncResult *simple;
+} BuildMessageWrapperData;
+
+static BuildMessageWrapperData *
+build_message_wrapper_data_new (EMsgComposer *composer,
+ ComposerFlags flags,
+ gint io_priority,
+ GCancellable *cancellable,
+ GSimpleAsyncResult *simple)
+{
+ BuildMessageWrapperData *bmwd;
+
+ bmwd = g_slice_new (BuildMessageWrapperData);
+ bmwd->composer = g_object_ref (composer);
+ bmwd->flags = flags;
+ bmwd->io_priority = io_priority;
+ bmwd->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+ bmwd->simple = g_object_ref (simple);
+
+ return bmwd;
+}
+
+static void
+build_message_wrapper_data_free (gpointer ptr)
+{
+ BuildMessageWrapperData *bmwd = ptr;
+
+ if (bmwd) {
+ g_clear_object (&bmwd->composer);
+ g_clear_object (&bmwd->cancellable);
+ g_clear_object (&bmwd->simple);
+ g_slice_free (BuildMessageWrapperData, bmwd);
+ }
+}
+
+static void
+composer_build_message_wrapper_content_hash_ready_cb (EMsgComposer *composer,
+ gpointer user_data,
+ const GError *error)
+{
+ BuildMessageWrapperData *bmwd = user_data;
+
+ g_return_if_fail (bmwd != NULL);
+
+ if (error) {
+ g_simple_async_result_set_from_error (bmwd->simple, error);
+ g_simple_async_result_complete (bmwd->simple);
+ } else {
+ composer_build_message (composer, bmwd->flags, bmwd->io_priority,
+ bmwd->cancellable, (GAsyncReadyCallback)
+ composer_get_message_ready, bmwd->simple);
+ }
+
+ build_message_wrapper_data_free (bmwd);
+}
+
+static void
+composer_build_message_wrapper (EMsgComposer *composer,
+ ComposerFlags flags,
+ gint io_priority,
+ GCancellable *cancellable,
+ GSimpleAsyncResult *simple)
+{
+ BuildMessageWrapperData *bmwd;
+
+ bmwd = build_message_wrapper_data_new (composer, flags, io_priority, cancellable, simple);
+
+ e_msg_composer_prepare_content_hash (composer, cancellable, NULL,
composer_build_message_wrapper_content_hash_ready_cb, bmwd);
+}
+
/**
* e_msg_composer_get_message:
* @composer: an #EMsgComposer
@@ -5410,10 +5675,7 @@ e_msg_composer_get_message (EMsgComposer *composer,
flags |= COMPOSER_FLAG_SMIME_ENCRYPT;
#endif
- composer_build_message (
- composer, flags, io_priority,
- cancellable, (GAsyncReadyCallback)
- composer_get_message_ready, simple);
+ composer_build_message_wrapper (composer, flags, io_priority, cancellable, simple);
}
CamelMimeMessage *
@@ -5461,10 +5723,7 @@ e_msg_composer_get_message_print (EMsgComposer *composer,
flags |= COMPOSER_FLAG_HTML_CONTENT;
flags |= COMPOSER_FLAG_SAVE_OBJECT_DATA;
- composer_build_message (
- composer, flags, io_priority,
- cancellable, (GAsyncReadyCallback)
- composer_get_message_ready, simple);
+ composer_build_message_wrapper (composer, flags, io_priority, cancellable, simple);
}
CamelMimeMessage *
@@ -5546,10 +5805,7 @@ e_msg_composer_get_message_draft (EMsgComposer *composer,
flags |= COMPOSER_FLAG_SMIME_ENCRYPT;
#endif
- composer_build_message (
- composer, flags, io_priority,
- cancellable, (GAsyncReadyCallback)
- composer_get_message_ready, simple);
+ composer_build_message_wrapper (composer, flags, io_priority, cancellable, simple);
}
CamelMimeMessage *
@@ -5667,32 +5923,32 @@ e_msg_composer_get_reply_to (EMsgComposer *composer)
GByteArray *
e_msg_composer_get_raw_message_text_without_signature (EMsgComposer *composer)
{
- EHTMLEditor *editor;
- EContentEditor *cnt_editor;
- gchar *content;
+ EContentEditorContentHash *content_hash;
+ const gchar *content;
+ gsize content_length;
GByteArray *bytes;
gboolean needs_crlf;
g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL);
- editor = e_msg_composer_get_editor (composer);
- cnt_editor = e_html_editor_get_content_editor (editor);
+ content_hash = e_msg_composer_get_content_hash (composer);
+ g_return_val_if_fail (content_hash != NULL, NULL);
- content = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_BODY |
- E_CONTENT_EDITOR_GET_TEXT_PLAIN |
- E_CONTENT_EDITOR_GET_EXCLUDE_SIGNATURE,
- NULL, NULL);
+ content = e_content_editor_util_get_content_data (content_hash,
E_CONTENT_EDITOR_GET_RAW_BODY_STRIPPED);
if (!content) {
g_warning ("%s: Failed to retrieve content", G_STRFUNC);
- content = g_strdup ("");
+
+ content = "";
}
- needs_crlf = !g_str_has_suffix (content, "\r\n");
+ needs_crlf = !g_str_has_suffix (content, "\r\n") && !g_str_has_suffix (content, "\n");
- bytes = g_byte_array_new_take ((guint8 *) content, strlen (content));
+ content_length = strlen (content);
+
+ bytes = g_byte_array_sized_new (content_length + 3);
+
+ g_byte_array_append (bytes, (const guint8 *) content, content_length);
if (needs_crlf)
g_byte_array_append (bytes, (const guint8 *) "\r\n", 2);
@@ -5708,31 +5964,32 @@ e_msg_composer_get_raw_message_text_without_signature (EMsgComposer *composer)
GByteArray *
e_msg_composer_get_raw_message_text (EMsgComposer *composer)
{
- EHTMLEditor *editor;
- EContentEditor *cnt_editor;
- gchar *content;
+ EContentEditorContentHash *content_hash;
+ const gchar *content;
+ gsize content_length;
GByteArray *bytes;
gboolean needs_crlf;
g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL);
- editor = e_msg_composer_get_editor (composer);
- cnt_editor = e_html_editor_get_content_editor (editor);
+ content_hash = e_msg_composer_get_content_hash (composer);
+ g_return_val_if_fail (content_hash != NULL, NULL);
- content = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_BODY |
- E_CONTENT_EDITOR_GET_TEXT_PLAIN,
- NULL, NULL);
+ content = e_content_editor_util_get_content_data (content_hash, E_CONTENT_EDITOR_GET_RAW_BODY_PLAIN);
if (!content) {
g_warning ("%s: Failed to retrieve content", G_STRFUNC);
- content = g_strdup ("");
+
+ content = "";
}
- needs_crlf = !g_str_has_suffix (content, "\r\n");
+ needs_crlf = !g_str_has_suffix (content, "\r\n") && !g_str_has_suffix (content, "\n");
+
+ content_length = strlen (content);
+
+ bytes = g_byte_array_sized_new (content_length + 3);
- bytes = g_byte_array_new_take ((guint8 *) content, strlen (content));
+ g_byte_array_append (bytes, (const guint8 *) content, content_length);
if (needs_crlf)
g_byte_array_append (bytes, (const guint8 *) "\r\n", 2);
diff --git a/src/composer/e-msg-composer.h b/src/composer/e-msg-composer.h
index e62ca84297..f385889ba4 100644
--- a/src/composer/e-msg-composer.h
+++ b/src/composer/e-msg-composer.h
@@ -108,6 +108,8 @@ EFocusTracker * e_msg_composer_get_focus_tracker
CamelSession * e_msg_composer_ref_session (EMsgComposer *composer);
EShell * e_msg_composer_get_shell (EMsgComposer *composer);
+EContentEditorContentHash *
+ e_msg_composer_get_content_hash (EMsgComposer *composer);
void e_msg_composer_send (EMsgComposer *composer);
void e_msg_composer_save_to_drafts (EMsgComposer *composer);
void e_msg_composer_save_to_outbox (EMsgComposer *composer);
diff --git a/src/e-util/CMakeLists.txt b/src/e-util/CMakeLists.txt
index 62d8f48ed5..19632d07f2 100644
--- a/src/e-util/CMakeLists.txt
+++ b/src/e-util/CMakeLists.txt
@@ -271,7 +271,6 @@ set(SOURCES
e-url-entry.c
e-util-private.h
e-webdav-browser.c
- e-web-extension-container.c
e-web-view.c
e-web-view-jsc-utils.c
e-web-view-preview.c
@@ -544,7 +543,6 @@ set(HEADERS
e-url-entry.h
e-util-enums.h
e-webdav-browser.h
- e-web-extension-container.h
e-web-view.h
e-web-view-jsc-utils.h
e-web-view-preview.h
@@ -748,6 +746,7 @@ macro(add_private_program _name _sources)
target_compile_definitions(${_name} PRIVATE
-DG_LOG_DOMAIN=\"${_name}\"
+ -DEVOLUTION_ICONDIR=\"${icondir}\"
-DEVOLUTION_LOCALEDIR=\"${LOCALE_INSTALL_DIR}\"
-DEVOLUTION_MODULEDIR=\"${moduledir}\"
-DEVOLUTION_TESTGIOMODULESDIR=\"${CMAKE_CURRENT_BINARY_DIR}/test-gio-modules\"
diff --git a/src/e-util/e-content-editor.c b/src/e-util/e-content-editor.c
index 64a066cb6d..9f69638c39 100644
--- a/src/e-util/e-content-editor.c
+++ b/src/e-util/e-content-editor.c
@@ -23,6 +23,7 @@
#include "e-html-editor.h"
#include "e-util-enumtypes.h"
+#include "e-misc-utils.h"
#include "e-content-editor.h"
G_DEFINE_INTERFACE (EContentEditor, e_content_editor, GTK_TYPE_WIDGET);
@@ -36,6 +37,7 @@ enum {
REPLACE_ALL_DONE,
DROP_HANDLED,
CONTENT_CHANGED,
+ REF_MIME_PART,
LAST_SIGNAL
};
@@ -297,18 +299,18 @@ e_content_editor_default_init (EContentEditorInterface *iface)
G_PARAM_STATIC_STRINGS));
/**
- * EContentEditor:indented
+ * EContentEditor:indent-level
*
- * Holds whether current paragraph is indented. This does not include
+ * Holds current paragraph indent level. This does not include
* citations.
*/
g_object_interface_install_property (
iface,
- g_param_spec_boolean (
- "indented",
+ g_param_spec_int (
+ "indent-level",
NULL,
NULL,
- FALSE,
+ 0, E_HTML_EDITOR_MAX_INDENT_LEVEL, 0,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
@@ -328,22 +330,6 @@ e_content_editor_default_init (EContentEditorInterface *iface)
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
- /**
- * EContentEditor:monospaced
- *
- * Holds whether current selection or letter at current cursor position
- * is monospaced.
- */
- g_object_interface_install_property (
- iface,
- g_param_spec_boolean (
- "monospaced",
- NULL,
- NULL,
- FALSE,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
-
/**
* EContentEditor:strikethrough
*
@@ -562,10 +548,11 @@ e_content_editor_default_init (EContentEditorInterface *iface)
E_TYPE_CONTENT_EDITOR,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (EContentEditorInterface, context_menu_requested),
- g_signal_accumulator_true_handled, NULL,
+ NULL, NULL,
NULL,
- G_TYPE_BOOLEAN, 2,
+ G_TYPE_NONE, 3,
G_TYPE_INT,
+ G_TYPE_STRING,
GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/**
@@ -630,6 +617,26 @@ e_content_editor_default_init (EContentEditorInterface *iface)
NULL, NULL,
NULL,
G_TYPE_NONE, 0);
+
+ /**
+ * EContentEditor:ref-mime-part
+ *
+ * This is used by the content editor, when it wants to get
+ * a #CamelMimePart of given URI (aka "cid:..."). The returned
+ * object, if not %NULL, should be freed with g_object_unref(),
+ * when no longer needed.
+ *
+ * Since: 3.38
+ */
+ signals[REF_MIME_PART] = g_signal_new (
+ "ref-mime-part",
+ E_TYPE_CONTENT_EDITOR,
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EContentEditorInterface, ref_mime_part),
+ NULL, NULL,
+ NULL,
+ CAMEL_TYPE_MIME_PART, 1,
+ G_TYPE_STRING);
}
ESpellChecker *
@@ -717,24 +724,24 @@ e_content_editor_can_redo (EContentEditor *editor)
}
/**
- * e_content_editor_is_indented:
+ * e_content_editor_indent_level:
* @editor: an #EContentEditor
*
- * Returns whether the current paragraph is indented. This does not include
- * citations.
+ * Returns the indent level for the current selection/caret position.
+ * This does not include citations.
*
- * Returns: %TRUE when current paragraph is indented, %FALSE otherwise.
+ * Returns: the indent level.
*
- * Since: 3.22
+ * Since: 3.38
**/
-gboolean
-e_content_editor_is_indented (EContentEditor *editor)
+gint
+e_content_editor_indent_level (EContentEditor *editor)
{
- gboolean value = FALSE;
+ gint value = 0;
- g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
- g_object_get (G_OBJECT (editor), "indented", &value, NULL);
+ g_object_get (G_OBJECT (editor), "indent-level", &value, NULL);
return value;
}
@@ -1162,48 +1169,6 @@ e_content_editor_is_italic (EContentEditor *editor)
return value;
}
-/**
- * e_content_editor_set_monospaced:
- * @editor: an #EContentEditor
- * @monospaced: %TRUE to enable monospaced, %FALSE to disable
- *
- * Changes monospaced formatting of current selection or letter
- * at current cursor position.
- *
- * Since: 3.22
- **/
-void
-e_content_editor_set_monospaced (EContentEditor *editor,
- gboolean monospaced)
-{
- g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
-
- g_object_set (G_OBJECT (editor), "monospaced", monospaced, NULL);
-}
-
-/**
- * e_content_editor_is_monospaced:
- * @editor: an #EContentEditor
- *
- * Returns whether current selection or letter at current cursor position
- * is monospaced.
- *
- * Returns: %TRUE when selection is monospaced, %FALSE otherwise.
- *
- * Since: 3.22
- **/
-gboolean
-e_content_editor_is_monospaced (EContentEditor *editor)
-{
- gboolean value = FALSE;
-
- g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
-
- g_object_get (G_OBJECT (editor), "monospaced", &value, NULL);
-
- return value;
-}
-
/**
* e_content_editor_set_strikethrough:
* @editor: an #EContentEditor
@@ -1574,41 +1539,351 @@ e_content_editor_insert_content (EContentEditor *editor,
iface->insert_content (editor, content, flags);
}
-gchar *
+/*
+ Finish the operation with e_content_editor_get_content_finish().
+ */
+void
e_content_editor_get_content (EContentEditor *editor,
- EContentEditorGetContentFlags flags,
+ guint32 flags,
const gchar *inline_images_from_domain,
- GSList **inline_images_parts /* newly created CamelMimePart * */)
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ if ((flags & E_CONTENT_EDITOR_GET_INLINE_IMAGES))
+ g_return_if_fail (inline_images_from_domain != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->get_content != NULL);
+
+ iface->get_content (editor, flags, inline_images_from_domain, cancellable, callback, user_data);
+}
+
+/*
+ Finishes previous call of e_content_editor_get_content(). The implementation
+ creates the GHashTable with e_content_editor_util_new_content_hash() and fills
+ it with e_content_editor_util_put_content_data(), e_content_editor_util_take_content_data()
+ or e_content_editor_util_take_content_data_images(). The caller can access
+ the members with e_content_editor_util_get_content_data().
+
+ The returned pointer should be freed with e_content_editor_util_free_content_hash(),
+ when done with it.
+ */
+EContentEditorContentHash *
+e_content_editor_get_content_finish (EContentEditor *editor,
+ GAsyncResult *result,
+ GError **error)
{
EContentEditorInterface *iface;
g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
- if ((flags & E_CONTENT_EDITOR_GET_INLINE_IMAGES)) {
- g_return_val_if_fail (inline_images_from_domain != NULL, NULL);
- g_return_val_if_fail (inline_images_parts != NULL, NULL);
- }
iface = E_CONTENT_EDITOR_GET_IFACE (editor);
g_return_val_if_fail (iface != NULL, NULL);
g_return_val_if_fail (iface->get_content != NULL, NULL);
- return iface->get_content (editor, flags, inline_images_from_domain, inline_images_parts);
+ return iface->get_content_finish (editor, result, error);
+}
+
+typedef struct _ContentHashData {
+ gpointer data;
+ GDestroyNotify destroy_data;
+} ContentHashData;
+
+static ContentHashData *
+content_hash_data_new (gpointer data,
+ GDestroyNotify destroy_data)
+{
+ ContentHashData *chd;
+
+ chd = g_slice_new (ContentHashData);
+ chd->data = data;
+ chd->destroy_data = destroy_data;
+
+ return chd;
+}
+
+static void
+content_hash_data_free (gpointer ptr)
+{
+ ContentHashData *chd = ptr;
+
+ if (ptr) {
+ if (chd->destroy_data && chd->data)
+ chd->destroy_data (chd->data);
+
+ g_slice_free (ContentHashData, chd);
+ }
+}
+
+static void
+content_data_free_obj_slist (gpointer ptr)
+{
+ GSList *lst = ptr;
+
+ g_slist_free_full (lst, g_object_unref);
+}
+
+EContentEditorContentHash *
+e_content_editor_util_new_content_hash (void)
+{
+ return (EContentEditorContentHash *) g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
content_hash_data_free);
}
void
-e_content_editor_insert_image_from_mime_part (EContentEditor *editor,
- CamelMimePart *part)
+e_content_editor_util_free_content_hash (EContentEditorContentHash *content_hash)
{
- EContentEditorInterface *iface;
+ if (content_hash)
+ g_hash_table_unref ((GHashTable *) content_hash);
+}
- g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
- g_return_if_fail (part != NULL);
+void
+e_content_editor_util_put_content_data (EContentEditorContentHash *content_hash,
+ EContentEditorGetContentFlags flag,
+ const gchar *data)
+{
+ g_return_if_fail (content_hash != NULL);
+ g_return_if_fail (flag != E_CONTENT_EDITOR_GET_ALL);
+ g_return_if_fail (data != NULL);
- iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->insert_image_from_mime_part != NULL);
+ e_content_editor_util_take_content_data (content_hash, flag, g_strdup (data), g_free);
+}
+
+void
+e_content_editor_util_take_content_data (EContentEditorContentHash *content_hash,
+ EContentEditorGetContentFlags flag,
+ gpointer data,
+ GDestroyNotify destroy_data)
+{
+ g_return_if_fail (content_hash != NULL);
+ g_return_if_fail (flag != E_CONTENT_EDITOR_GET_ALL);
+ g_return_if_fail (data != NULL);
+
+ g_hash_table_insert ((GHashTable *) content_hash, GUINT_TO_POINTER (flag), content_hash_data_new
(data, destroy_data));
+}
+
+void
+e_content_editor_util_take_content_data_images (EContentEditorContentHash *content_hash,
+ GSList *image_parts) /* CamelMimePart * */
+{
+ g_return_if_fail (content_hash != NULL);
+ g_return_if_fail (image_parts != NULL);
- iface->insert_image_from_mime_part (editor, part);
+ g_hash_table_insert ((GHashTable *) content_hash, GUINT_TO_POINTER
(E_CONTENT_EDITOR_GET_INLINE_IMAGES),
+ content_hash_data_new (image_parts, content_data_free_obj_slist));
+}
+
+/* The actual data type depends on the @flag. The E_CONTENT_EDITOR_GET_INLINE_IMAGES returns
+ a GSList of CamelMimePart-s of inline images. All the other flags return plain strings.
+
+ The returned pointer is owned by content_hash and cannot be freed
+ neither modified. It's freed together with the content_hash, or
+ when its key is overwritten.
+ */
+gpointer
+e_content_editor_util_get_content_data (EContentEditorContentHash *content_hash,
+ EContentEditorGetContentFlags flag)
+{
+ ContentHashData *chd;
+
+ g_return_val_if_fail (content_hash != NULL, NULL);
+ g_return_val_if_fail (flag != E_CONTENT_EDITOR_GET_ALL, NULL);
+
+ chd = g_hash_table_lookup ((GHashTable *) content_hash, GUINT_TO_POINTER (flag));
+
+ return chd ? chd->data : NULL;
+}
+
+/* The same rules apply as with e_content_editor_util_get_content_data(). The difference is
+ that after calling this function the data is stoled from the content_hash and the caller
+ is responsible to free it. Any following calls with the same flag will return %NULL.
+ */
+gpointer
+e_content_editor_util_steal_content_data (EContentEditorContentHash *content_hash,
+ EContentEditorGetContentFlags flag,
+ GDestroyNotify *out_destroy_data)
+{
+ ContentHashData *chd;
+ gpointer data;
+
+ if (out_destroy_data)
+ *out_destroy_data = NULL;
+
+ g_return_val_if_fail (content_hash != NULL, NULL);
+ g_return_val_if_fail (flag != E_CONTENT_EDITOR_GET_ALL, NULL);
+
+ chd = g_hash_table_lookup ((GHashTable *) content_hash, GUINT_TO_POINTER (flag));
+
+ if (!chd)
+ return NULL;
+
+ data = chd->data;
+
+ if (out_destroy_data)
+ *out_destroy_data = chd->destroy_data;
+
+ chd->data = NULL;
+ chd->destroy_data = NULL;
+
+ return data;
+}
+
+/**
+ * e_content_editor_util_create_data_mimepart:
+ * @uri: a file:// or data: URI of the data to convert to MIME part
+ * @cid: content ID to use for the MIME part, should start with "cid:"; can be %NULL
+ * @as_inline: whether to use "inline" content disposition; will use "attachment", if set to %FALSE
+ * @prefer_filename: preferred file name to use, can be %NULL
+ * @prefer_mime_type: preferred MIME type for the part, can be %NULL
+ * @cancellable: optional #GCancellable object, or %NULL
+ *
+ * Converts URI into a #CamelMimePart. Supports file:// and data: URIs.
+ * The @prefer_filename can override the file name from the @uri.
+ *
+ * Free the returned pointer, if not %NULL, with g_object_unref(), when
+ * no longer needed.
+ *
+ * Returns: (transfer full) (nullable): a new #CamelMimePart containing
+ * the referenced data, or %NULL, when cannot be converted (due to
+ * unsupported URI, file not found or such).
+ *
+ * Since: 3.38
+ **/
+CamelMimePart *
+e_content_editor_util_create_data_mimepart (const gchar *uri,
+ const gchar *cid,
+ gboolean as_inline,
+ const gchar *prefer_filename,
+ const gchar *prefer_mime_type,
+ GCancellable *cancellable)
+{
+ CamelMimePart *mime_part = NULL;
+ GInputStream *input_stream = NULL;
+ GFileInfo *file_info = NULL;
+ gchar *mime_type = NULL;
+ guchar *data = NULL;
+ gsize data_length = 0;
+
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ /* base64-encoded "data:" URIs */
+ if (g_ascii_strncasecmp (uri, "data:", 5) == 0) {
+ /* data:[<mime type>][;charset=<charset>][;base64],<encoded data> */
+ const gchar *ptr, *from;
+ gboolean is_base64 = FALSE;
+
+ ptr = uri + 5;
+ from = ptr;
+ while (*ptr && *ptr != ',') {
+ ptr++;
+
+ if (*ptr == ',' || *ptr == ';') {
+ if (g_ascii_strncasecmp (from, "base64", ptr - from) == 0)
+ is_base64 = TRUE;
+
+ if (from == uri + 5 && *ptr == ';' && !prefer_mime_type)
+ mime_type = g_strndup (from, ptr - from);
+
+ from = ptr + 1;
+ }
+ }
+
+ if (is_base64 && *ptr == ',') {
+ data = g_base64_decode (ptr + 1, &data_length);
+
+ if (data && data_length && !mime_type && !prefer_mime_type) {
+ gchar *content_type;
+
+ content_type = g_content_type_guess (NULL, data, data_length, NULL);
+
+ if (content_type) {
+ mime_type = g_content_type_get_mime_type (content_type);
+ g_free (content_type);
+ }
+ }
+ }
+
+ /* files on the disk */
+ } else if (g_ascii_strncasecmp (uri, "file://", 7) == 0 ||
+ g_ascii_strncasecmp (uri, "evo-file://", 11) == 0) {
+ GFileInputStream *file_stream;
+ GFile *file;
+
+ if (g_ascii_strncasecmp (uri, "evo-", 4) == 0)
+ uri += 4;
+
+ file = g_file_new_for_uri (uri);
+ file_stream = g_file_read (file, NULL, NULL);
+
+ if (file_stream) {
+ if (!prefer_filename) {
+ file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
G_FILE_QUERY_INFO_NONE, cancellable, NULL);
+
+ if (file_info)
+ prefer_filename = g_file_info_get_display_name (file_info);
+ }
+
+ if (!prefer_mime_type)
+ mime_type = e_util_guess_mime_type (uri, TRUE);
+
+ input_stream = (GInputStream *) file_stream;
+ }
+
+ g_clear_object (&file);
+ }
+
+ if (data || input_stream) {
+ if (!prefer_mime_type)
+ prefer_mime_type = mime_type;
+
+ if (!prefer_mime_type)
+ prefer_mime_type = "application/octet-stream";
+
+ if (input_stream) {
+ CamelDataWrapper *wrapper;
+
+ wrapper = camel_data_wrapper_new ();
+
+ if (camel_data_wrapper_construct_from_input_stream_sync (wrapper, input_stream,
cancellable, NULL)) {
+ camel_data_wrapper_set_mime_type (wrapper, prefer_mime_type);
+
+ mime_part = camel_mime_part_new ();
+ camel_medium_set_content (CAMEL_MEDIUM (mime_part), wrapper);
+ }
+
+ g_object_unref (wrapper);
+ } else {
+ mime_part = camel_mime_part_new ();
+ camel_mime_part_set_content (mime_part, (const gchar *) data, data_length,
prefer_mime_type);
+ }
+
+ if (mime_part) {
+ camel_mime_part_set_disposition (mime_part, as_inline ? "inline" : "attachment");
+
+ if (cid && g_ascii_strncasecmp (cid, "cid:", 4) == 0)
+ cid += 4;
+
+ if (cid && *cid)
+ camel_mime_part_set_content_id (mime_part, cid);
+
+ if (prefer_filename && *prefer_filename)
+ camel_mime_part_set_filename (mime_part, prefer_filename);
+
+ camel_mime_part_set_encoding (mime_part, CAMEL_TRANSFER_ENCODING_BASE64);
+ }
+ }
+
+ g_clear_object (&input_stream);
+ g_clear_object (&file_info);
+ g_free (mime_type);
+ g_free (data);
+
+ return mime_part;
}
/**
@@ -1799,30 +2074,6 @@ e_content_editor_select_all (EContentEditor *editor)
iface->select_all (editor);
}
-/**
- * e_content_editor_get_selected_text:
- * @editor: an #EContentEditor
- *
- * Returns currently selected string.
- *
- * Returns: (transfer-full): A newly allocated string with the content of current selection.
- *
- * Since: 3.22
- **/
-gchar *
-e_content_editor_get_selected_text (EContentEditor *editor)
-{
- EContentEditorInterface *iface;
-
- g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
-
- iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_val_if_fail (iface != NULL, NULL);
- g_return_val_if_fail (iface->get_selected_text != NULL, NULL);
-
- return iface->get_selected_text (editor);
-}
-
/**
* e_content_editor_get_caret_word:
* @editor: an #EContentEditor
@@ -1901,31 +2152,6 @@ e_content_editor_selection_unindent (EContentEditor *editor)
iface->selection_unindent (editor);
}
-/**
- * e_content_editor_selection_create_link:
- * @editor: an #EContentEditor
- * @uri: destination of the new link
- *
- * Converts current selection into a link pointing to @url.
- *
- * Since: 3.22
- **/
-void
-e_content_editor_selection_create_link (EContentEditor *editor,
- const gchar *uri)
-{
- EContentEditorInterface *iface;
-
- g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
- g_return_if_fail (uri != NULL);
-
- iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->selection_create_link != NULL);
-
- iface->selection_create_link (editor, uri);
-}
-
/**
* e_content_editor_selection_unlink:
* @editor: an #EContentEditor
@@ -2119,34 +2345,6 @@ e_content_editor_selection_wrap (EContentEditor *editor)
iface->selection_wrap (editor);
}
-guint
-e_content_editor_get_caret_position (EContentEditor *editor)
-{
- EContentEditorInterface *iface;
-
- g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
-
- iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_val_if_fail (iface != NULL, 0);
- g_return_val_if_fail (iface->get_caret_position != NULL, 0);
-
- return iface->get_caret_position (editor);
-}
-
-guint
-e_content_editor_get_caret_offset (EContentEditor *editor)
-{
- EContentEditorInterface *iface;
-
- g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
-
- iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_val_if_fail (iface != NULL, 0);
- g_return_val_if_fail (iface->get_caret_offset != NULL, 0);
-
- return iface->get_caret_offset (editor);
-}
-
gchar *
e_content_editor_get_current_signature_uid (EContentEditor *editor)
{
@@ -2337,22 +2535,24 @@ e_content_editor_insert_row_below (EContentEditor *editor)
iface->insert_row_below (editor);
}
-gboolean
-e_content_editor_on_h_rule_dialog_open (EContentEditor *editor)
+void
+e_content_editor_on_dialog_open (EContentEditor *editor,
+ const gchar *name)
{
EContentEditorInterface *iface;
- g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_val_if_fail (iface != NULL, FALSE);
- g_return_val_if_fail (iface->on_h_rule_dialog_open != NULL, FALSE);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->on_dialog_open != NULL);
- return iface->on_h_rule_dialog_open (editor);
+ iface->on_dialog_open (editor, name);
}
void
-e_content_editor_on_h_rule_dialog_close (EContentEditor *editor)
+e_content_editor_on_dialog_close (EContentEditor *editor,
+ const gchar *name)
{
EContentEditorInterface *iface;
@@ -2360,9 +2560,9 @@ e_content_editor_on_h_rule_dialog_close (EContentEditor *editor)
iface = E_CONTENT_EDITOR_GET_IFACE (editor);
g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->on_h_rule_dialog_close != NULL);
+ g_return_if_fail (iface->on_dialog_close != NULL);
- iface->on_h_rule_dialog_close (editor);
+ iface->on_dialog_close (editor, name);
}
void
@@ -2484,34 +2684,6 @@ e_content_editor_h_rule_get_no_shade (EContentEditor *editor)
return iface->h_rule_get_no_shade (editor);
}
-void
-e_content_editor_on_image_dialog_open (EContentEditor *editor)
-{
- EContentEditorInterface *iface;
-
- g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
-
- iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->on_image_dialog_open != NULL);
-
- iface->on_image_dialog_open (editor);
-}
-
-void
-e_content_editor_on_image_dialog_close (EContentEditor *editor)
-{
- EContentEditorInterface *iface;
-
- g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
-
- iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->on_image_dialog_close != NULL);
-
- iface->on_image_dialog_close (editor);
-}
-
void
e_content_editor_image_set_width_follow (EContentEditor *editor,
gboolean value)
@@ -2834,21 +3006,9 @@ e_content_editor_image_set_height_follow (EContentEditor *editor,
}
void
-e_content_editor_on_link_dialog_open (EContentEditor *editor)
-{
- EContentEditorInterface *iface;
-
- g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
-
- iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->on_link_dialog_open != NULL);
-
- iface->on_link_dialog_open (editor);
-}
-
-void
-e_content_editor_on_link_dialog_close (EContentEditor *editor)
+e_content_editor_link_get_properties (EContentEditor *editor,
+ gchar **href,
+ gchar **text)
{
EContentEditorInterface *iface;
@@ -2856,15 +3016,15 @@ e_content_editor_on_link_dialog_close (EContentEditor *editor)
iface = E_CONTENT_EDITOR_GET_IFACE (editor);
g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->on_link_dialog_close != NULL);
+ g_return_if_fail (iface->link_get_properties != NULL);
- iface->on_link_dialog_close (editor);
+ iface->link_get_properties (editor, href, text);
}
void
-e_content_editor_link_get_values (EContentEditor *editor,
- gchar **href,
- gchar **text)
+e_content_editor_link_set_properties (EContentEditor *editor,
+ const gchar *href,
+ const gchar *text)
{
EContentEditorInterface *iface;
@@ -2872,53 +3032,9 @@ e_content_editor_link_get_values (EContentEditor *editor,
iface = E_CONTENT_EDITOR_GET_IFACE (editor);
g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->link_get_values != NULL);
+ g_return_if_fail (iface->link_set_properties != NULL);
- return iface->link_get_values (editor, href, text);
-}
-
-void
-e_content_editor_link_set_values (EContentEditor *editor,
- const gchar *href,
- const gchar *text)
-{
- EContentEditorInterface *iface;
-
- g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
-
- iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->link_set_values != NULL);
-
- iface->link_set_values (editor, href, text);
-}
-
-void
-e_content_editor_on_page_dialog_open (EContentEditor *editor)
-{
- EContentEditorInterface *iface;
-
- g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
-
- iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->on_page_dialog_open != NULL);
-
- iface->on_page_dialog_open (editor);
-}
-
-void
-e_content_editor_on_page_dialog_close (EContentEditor *editor)
-{
- EContentEditorInterface *iface;
-
- g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
-
- iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->on_page_dialog_close != NULL);
-
- iface->on_page_dialog_close (editor);
+ iface->link_set_properties (editor, href, text);
}
void
@@ -3049,10 +3165,9 @@ e_content_editor_page_get_visited_link_color (EContentEditor *editor,
return iface->page_get_visited_link_color (editor, value);
}
-/* uri could be NULL -> removes the current image */
void
-e_content_editor_page_set_background_image_uri (EContentEditor *editor,
- const gchar *uri)
+e_content_editor_page_set_font_name (EContentEditor *editor,
+ const gchar *value)
{
EContentEditorInterface *iface;
@@ -3060,13 +3175,13 @@ e_content_editor_page_set_background_image_uri (EContentEditor *editor,
iface = E_CONTENT_EDITOR_GET_IFACE (editor);
g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->page_set_background_image_uri != NULL);
+ g_return_if_fail (iface->page_set_font_name != NULL);
- iface->page_set_background_image_uri (editor, uri);
+ iface->page_set_font_name (editor, value);
}
-gchar *
-e_content_editor_page_get_background_image_uri (EContentEditor *editor)
+const gchar *
+e_content_editor_page_get_font_name (EContentEditor *editor)
{
EContentEditorInterface *iface;
@@ -3074,13 +3189,15 @@ e_content_editor_page_get_background_image_uri (EContentEditor *editor)
iface = E_CONTENT_EDITOR_GET_IFACE (editor);
g_return_val_if_fail (iface != NULL, NULL);
- g_return_val_if_fail (iface->page_get_background_image_uri != NULL, NULL);
+ g_return_val_if_fail (iface->page_get_font_name != NULL, NULL);
- return iface->page_get_background_image_uri (editor);
+ return iface->page_get_font_name (editor);
}
+/* uri could be NULL -> removes the current image */
void
-e_content_editor_on_cell_dialog_open (EContentEditor *editor)
+e_content_editor_page_set_background_image_uri (EContentEditor *editor,
+ const gchar *uri)
{
EContentEditorInterface *iface;
@@ -3088,23 +3205,23 @@ e_content_editor_on_cell_dialog_open (EContentEditor *editor)
iface = E_CONTENT_EDITOR_GET_IFACE (editor);
g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->on_cell_dialog_open != NULL);
+ g_return_if_fail (iface->page_set_background_image_uri != NULL);
- iface->on_cell_dialog_open (editor);
+ iface->page_set_background_image_uri (editor, uri);
}
-void
-e_content_editor_on_cell_dialog_close (EContentEditor *editor)
+gchar *
+e_content_editor_page_get_background_image_uri (EContentEditor *editor)
{
EContentEditorInterface *iface;
- g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->on_cell_dialog_close != NULL);
+ g_return_val_if_fail (iface != NULL, NULL);
+ g_return_val_if_fail (iface->page_get_background_image_uri != NULL, NULL);
- iface->on_cell_dialog_close (editor);
+ return iface->page_get_background_image_uri (editor);
}
void
@@ -3648,62 +3765,6 @@ e_content_editor_table_set_background_color (EContentEditor *editor,
iface->table_set_background_color (editor, value);
}
-gboolean
-e_content_editor_on_table_dialog_open (EContentEditor *editor)
-{
- EContentEditorInterface *iface;
-
- g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
-
- iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_val_if_fail (iface != NULL, FALSE);
- g_return_val_if_fail (iface->on_table_dialog_open != NULL, FALSE);
-
- return iface->on_table_dialog_open (editor);
-}
-
-void
-e_content_editor_on_table_dialog_close (EContentEditor *editor)
-{
- EContentEditorInterface *iface;
-
- g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
-
- iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->on_table_dialog_close != NULL);
-
- iface->on_table_dialog_close (editor);
-}
-
-void
-e_content_editor_on_spell_check_dialog_open (EContentEditor *editor)
-{
- EContentEditorInterface *iface;
-
- g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
-
- iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->on_spell_check_dialog_close != NULL);
-
- iface->on_spell_check_dialog_close (editor);
-}
-
-void
-e_content_editor_on_spell_check_dialog_close (EContentEditor *editor)
-{
- EContentEditorInterface *iface;
-
- g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
-
- iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->on_spell_check_dialog_close != NULL);
-
- iface->on_spell_check_dialog_close (editor);
-}
-
gchar *
e_content_editor_spell_check_next_word (EContentEditor *editor,
const gchar *word)
@@ -3734,62 +3795,6 @@ e_content_editor_spell_check_prev_word (EContentEditor *editor,
return iface->spell_check_prev_word (editor, word);
}
-void
-e_content_editor_on_replace_dialog_open (EContentEditor *editor)
-{
- EContentEditorInterface *iface;
-
- g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
-
- iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->on_replace_dialog_open != NULL);
-
- iface->on_replace_dialog_open (editor);
-}
-
-void
-e_content_editor_on_replace_dialog_close (EContentEditor *editor)
-{
- EContentEditorInterface *iface;
-
- g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
-
- iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->on_replace_dialog_close != NULL);
-
- iface->on_replace_dialog_close (editor);
-}
-
-void
-e_content_editor_on_find_dialog_open (EContentEditor *editor)
-{
- EContentEditorInterface *iface;
-
- g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
-
- iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->on_find_dialog_open != NULL);
-
- iface->on_find_dialog_open (editor);
-}
-
-void
-e_content_editor_on_find_dialog_close (EContentEditor *editor)
-{
- EContentEditorInterface *iface;
-
- g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
-
- iface = E_CONTENT_EDITOR_GET_IFACE (editor);
- g_return_if_fail (iface != NULL);
- g_return_if_fail (iface->on_find_dialog_close != NULL);
-
- iface->on_find_dialog_close (editor);
-}
-
void
e_content_editor_emit_load_finished (EContentEditor *editor)
{
@@ -3822,18 +3827,15 @@ e_content_editor_emit_paste_primary_clipboard (EContentEditor *editor)
return handled;
}
-gboolean
+void
e_content_editor_emit_context_menu_requested (EContentEditor *editor,
- EContentEditorNodeFlags flags,
- GdkEvent *event)
+ EContentEditorNodeFlags flags,
+ const gchar *caret_word,
+ GdkEvent *event)
{
- gboolean handled = FALSE;
-
- g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
-
- g_signal_emit (editor, signals[CONTEXT_MENU_REQUESTED], 0, flags, event, &handled);
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
- return handled;
+ g_signal_emit (editor, signals[CONTEXT_MENU_REQUESTED], 0, flags, caret_word, event, NULL);
}
void
@@ -3869,3 +3871,17 @@ e_content_editor_emit_content_changed (EContentEditor *editor)
g_signal_emit (editor, signals[CONTENT_CHANGED], 0);
}
+
+CamelMimePart *
+e_content_editor_emit_ref_mime_part (EContentEditor *editor,
+ const gchar *uri)
+{
+ CamelMimePart *mime_part = NULL;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ g_signal_emit (editor, signals[REF_MIME_PART], 0, uri, &mime_part);
+
+ return mime_part;
+}
diff --git a/src/e-util/e-content-editor.h b/src/e-util/e-content-editor.h
index f1630522a2..ae00b147f4 100644
--- a/src/e-util/e-content-editor.h
+++ b/src/e-util/e-content-editor.h
@@ -33,6 +33,16 @@
#define DEFAULT_CONTENT_EDITOR_NAME "WebKit"
+#define E_CONTENT_EDITOR_DIALOG_HRULE "hrule"
+#define E_CONTENT_EDITOR_DIALOG_IMAGE "image"
+#define E_CONTENT_EDITOR_DIALOG_LINK "link"
+#define E_CONTENT_EDITOR_DIALOG_PAGE "page"
+#define E_CONTENT_EDITOR_DIALOG_CELL "cell"
+#define E_CONTENT_EDITOR_DIALOG_TABLE "table"
+#define E_CONTENT_EDITOR_DIALOG_SPELLCHECK "spellcheck"
+#define E_CONTENT_EDITOR_DIALOG_FIND "find"
+#define E_CONTENT_EDITOR_DIALOG_REPLACE "replace"
+
G_BEGIN_DECLS
struct _EHTMLEditor;
@@ -40,6 +50,8 @@ struct _EHTMLEditor;
#define E_TYPE_CONTENT_EDITOR e_content_editor_get_type ()
G_DECLARE_INTERFACE (EContentEditor, e_content_editor, E, CONTENT_EDITOR, GtkWidget)
+typedef GHashTable EContentEditorContentHash;
+
typedef void (*EContentEditorInitializedCallback) (EContentEditor *content_editor,
gpointer user_data);
@@ -56,18 +68,20 @@ struct _EContentEditorInterface {
const gchar *content,
EContentEditorInsertContentFlags flags);
- gchar * (*get_content) (EContentEditor *editor,
- EContentEditorGetContentFlags flags,
+ void (*get_content) (EContentEditor *editor,
+ guint32 flags, /* bit-or of
EContentEditorGetContentFlags */
const gchar *inline_images_from_domain,
- GSList **inline_images_parts /* newly created
CamelMimePart * */);
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ EContentEditorContentHash *
+ (*get_content_finish) (EContentEditor *editor,
+ GAsyncResult *result,
+ GError **error);
void (*insert_image) (EContentEditor *editor,
const gchar *uri);
- void (*insert_image_from_mime_part)
- (EContentEditor *editor,
- CamelMimePart *part);
-
void (*insert_emoticon) (EContentEditor *editor,
EEmoticon *emoticon);
@@ -93,8 +107,6 @@ struct _EContentEditorInterface {
void (*set_spell_checking_languages) (EContentEditor *editor,
const gchar **languages);
- gchar * (*get_selected_text) (EContentEditor *editor);
-
gchar * (*get_caret_word) (EContentEditor *editor);
void (*replace_caret_word) (EContentEditor *editor,
@@ -106,9 +118,6 @@ struct _EContentEditorInterface {
void (*selection_unindent) (EContentEditor *editor);
- void (*selection_create_link) (EContentEditor *editor,
- const gchar *uri);
-
void (*selection_unlink) (EContentEditor *editor);
void (*find) (EContentEditor *editor,
@@ -129,10 +138,6 @@ struct _EContentEditorInterface {
void (*selection_wrap) (EContentEditor *editor);
- guint (*get_caret_position) (EContentEditor *editor);
-
- guint (*get_caret_offset) (EContentEditor *editor);
-
gchar * (*get_current_signature_uid) (EContentEditor *editor);
gboolean (*is_ready) (EContentEditor *editor);
@@ -161,9 +166,11 @@ struct _EContentEditorInterface {
void (*insert_row_below) (EContentEditor *editor);
- gboolean (*on_h_rule_dialog_open) (EContentEditor *editor);
+ void (*on_dialog_open) (EContentEditor *editor,
+ const gchar *name);
- void (*on_h_rule_dialog_close) (EContentEditor *editor);
+ void (*on_dialog_close) (EContentEditor *editor,
+ const gchar *name);
void (*h_rule_set_align) (EContentEditor *editor,
const gchar *value);
@@ -187,10 +194,6 @@ struct _EContentEditorInterface {
gboolean (*h_rule_get_no_shade) (EContentEditor *editor);
- void (*on_image_dialog_open) (EContentEditor *editor);
-
- void (*on_image_dialog_close) (EContentEditor *editor);
-
void (*image_set_src) (EContentEditor *editor,
const gchar *value);
@@ -246,22 +249,14 @@ struct _EContentEditorInterface {
gchar * (*image_get_align) (EContentEditor *editor);
- void (*on_link_dialog_open) (EContentEditor *editor);
-
- void (*on_link_dialog_close) (EContentEditor *editor);
-
- void (*link_get_values) (EContentEditor *editor,
+ void (*link_get_properties) (EContentEditor *editor,
gchar **href,
gchar **text);
- void (*link_set_values) (EContentEditor *editor,
+ void (*link_set_properties) (EContentEditor *editor,
const gchar *href,
const gchar *text);
- void (*on_page_dialog_open) (EContentEditor *editor);
-
- void (*on_page_dialog_close) (EContentEditor *editor);
-
void (*page_set_text_color) (EContentEditor *editor,
const GdkRGBA *value);
@@ -285,6 +280,9 @@ struct _EContentEditorInterface {
void (*page_get_visited_link_color) (EContentEditor *editor,
GdkRGBA *value);
+ void (*page_set_font_name) (EContentEditor *editor,
+ const gchar *value);
+ const gchar * (*page_get_font_name) (EContentEditor *editor);
void (*page_set_background_image_uri)
(EContentEditor *editor,
@@ -293,10 +291,6 @@ struct _EContentEditorInterface {
gchar * (*page_get_background_image_uri)
(EContentEditor *editor);
- void (*on_cell_dialog_open) (EContentEditor *editor);
-
- void (*on_cell_dialog_close) (EContentEditor *editor);
-
void (*cell_set_v_align) (EContentEditor *editor,
const gchar *value,
EContentEditorScope scope);
@@ -405,34 +399,19 @@ struct _EContentEditorInterface {
void (*table_set_background_color) (EContentEditor *editor,
const GdkRGBA *value);
- gboolean (*on_table_dialog_open) (EContentEditor *editor);
-
- void (*on_table_dialog_close) (EContentEditor *editor);
-
- void (*on_spell_check_dialog_open) (EContentEditor *editor);
-
- void (*on_spell_check_dialog_close) (EContentEditor *editor);
-
gchar * (*spell_check_next_word) (EContentEditor *editor,
const gchar *word);
gchar * (*spell_check_prev_word) (EContentEditor *editor,
const gchar *word);
- void (*on_replace_dialog_open) (EContentEditor *editor);
-
- void (*on_replace_dialog_close) (EContentEditor *editor);
-
- void (*on_find_dialog_open) (EContentEditor *editor);
-
- void (*on_find_dialog_close) (EContentEditor *editor);
-
/* Signals */
void (*load_finished) (EContentEditor *editor);
gboolean (*paste_clipboard) (EContentEditor *editor);
gboolean (*paste_primary_clipboard) (EContentEditor *editor);
- gboolean (*context_menu_requested) (EContentEditor *editor,
+ void (*context_menu_requested) (EContentEditor *editor,
EContentEditorNodeFlags flags,
+ const gchar *caret_word,
GdkEvent *event);
void (*find_done) (EContentEditor *editor,
guint match_count);
@@ -440,6 +419,8 @@ struct _EContentEditorInterface {
guint replaced_count);
void (*drop_handled) (EContentEditor *editor);
void (*content_changed) (EContentEditor *editor);
+ CamelMimePart * (*ref_mime_part) (EContentEditor *editor,
+ const gchar *uri);
};
/* Properties */
@@ -452,7 +433,7 @@ gboolean e_content_editor_can_copy (EContentEditor *editor);
gboolean e_content_editor_can_paste (EContentEditor *editor);
gboolean e_content_editor_can_undo (EContentEditor *editor);
gboolean e_content_editor_can_redo (EContentEditor *editor);
-gboolean e_content_editor_is_indented (EContentEditor *editor);
+gint e_content_editor_indent_level (EContentEditor *editor);
gboolean e_content_editor_get_spell_check_enabled
(EContentEditor *editor);
void e_content_editor_set_spell_check_enabled
@@ -497,9 +478,6 @@ gboolean e_content_editor_is_bold (EContentEditor *editor);
void e_content_editor_set_italic (EContentEditor *editor,
gboolean italic);
gboolean e_content_editor_is_italic (EContentEditor *editor);
-void e_content_editor_set_monospaced (EContentEditor *editor,
- gboolean monospaced);
-gboolean e_content_editor_is_monospaced (EContentEditor *editor);
void e_content_editor_set_strikethrough
(EContentEditor *editor,
gboolean strikethrough);
@@ -543,14 +521,48 @@ void e_content_editor_insert_content (EContentEditor *editor,
const gchar *content,
EContentEditorInsertContentFlags flags);
-gchar * e_content_editor_get_content (EContentEditor *editor,
- EContentEditorGetContentFlags flags,
+void e_content_editor_get_content (EContentEditor *editor,
+ guint32 flags, /* bit-or of EContentEditorGetContentFlags */
const gchar *inline_images_from_domain,
- GSList **inline_images_parts /* newly created CamelMimePart
* */);
-
-void e_content_editor_insert_image_from_mime_part
- (EContentEditor *editor,
- CamelMimePart *part);
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+EContentEditorContentHash *
+ e_content_editor_get_content_finish
+ (EContentEditor *editor,
+ GAsyncResult *result,
+ GError **error);
+EContentEditorContentHash *
+ e_content_editor_util_new_content_hash
+ (void);
+void e_content_editor_util_free_content_hash
+ (EContentEditorContentHash *content_hash);
+void e_content_editor_util_put_content_data
+ (EContentEditorContentHash *content_hash,
+ EContentEditorGetContentFlags flag,
+ const gchar *data);
+void e_content_editor_util_take_content_data
+ (EContentEditorContentHash *content_hash,
+ EContentEditorGetContentFlags flag,
+ gpointer data,
+ GDestroyNotify destroy_data);
+void e_content_editor_util_take_content_data_images
+ (EContentEditorContentHash *content_hash,
+ GSList *image_parts); /* CamelMimePart * */
+gpointer e_content_editor_util_get_content_data
+ (EContentEditorContentHash *content_hash,
+ EContentEditorGetContentFlags flag);
+gpointer e_content_editor_util_steal_content_data
+ (EContentEditorContentHash *content_hash,
+ EContentEditorGetContentFlags flag,
+ GDestroyNotify *out_destroy_data);
+CamelMimePart * e_content_editor_util_create_data_mimepart
+ (const gchar *uri,
+ const gchar *cid,
+ gboolean as_inline,
+ const gchar *prefer_filename,
+ const gchar *prefer_mime_type,
+ GCancellable *cancellable);
void e_content_editor_insert_image (EContentEditor *editor,
const gchar *uri);
@@ -586,9 +598,6 @@ void e_content_editor_set_spell_checking_languages
void e_content_editor_select_all (EContentEditor *editor);
-gchar * e_content_editor_get_selected_text
- (EContentEditor *editor);
-
gchar * e_content_editor_get_caret_word (EContentEditor *editor);
void e_content_editor_replace_caret_word
@@ -601,10 +610,6 @@ void e_content_editor_selection_indent
void e_content_editor_selection_unindent
(EContentEditor *editor);
-void e_content_editor_selection_create_link
- (EContentEditor *editor,
- const gchar *uri);
-
void e_content_editor_selection_unlink
(EContentEditor *editor);
@@ -627,12 +632,6 @@ void e_content_editor_selection_restore
void e_content_editor_selection_wrap (EContentEditor *editor);
-guint e_content_editor_get_caret_position
- (EContentEditor *editor);
-
-guint e_content_editor_get_caret_offset
- (EContentEditor *editor);
-
gchar * e_content_editor_get_current_signature_uid
(EContentEditor *editor);
@@ -671,11 +670,10 @@ void e_content_editor_insert_row_above
void e_content_editor_insert_row_below
(EContentEditor *editor);
-gboolean e_content_editor_on_h_rule_dialog_open
- (EContentEditor *editor);
-
-void e_content_editor_on_h_rule_dialog_close
- (EContentEditor *editor);
+void e_content_editor_on_dialog_open (EContentEditor *editor,
+ const gchar *name);
+void e_content_editor_on_dialog_close(EContentEditor *editor,
+ const gchar *name);
void e_content_editor_h_rule_set_align
(EContentEditor *editor,
@@ -707,12 +705,6 @@ void e_content_editor_h_rule_set_no_shade
gboolean e_content_editor_h_rule_get_no_shade
(EContentEditor *editor);
-void e_content_editor_on_image_dialog_open
- (EContentEditor *editor);
-
-void e_content_editor_on_image_dialog_close
- (EContentEditor *editor);
-
void e_content_editor_image_set_src (EContentEditor *editor,
const gchar *value);
@@ -783,18 +775,12 @@ void e_content_editor_image_set_height_follow
(EContentEditor *editor,
gboolean value);
-void e_content_editor_on_link_dialog_open
- (EContentEditor *editor);
-
-void e_content_editor_on_link_dialog_close
- (EContentEditor *editor);
-
-void e_content_editor_link_get_values
+void e_content_editor_link_get_properties
(EContentEditor *editor,
gchar **href,
gchar **text);
-void e_content_editor_link_set_values
+void e_content_editor_link_set_properties
(EContentEditor *editor,
const gchar *href,
const gchar *text);
@@ -803,12 +789,6 @@ void e_content_editor_page_set_text_color
(EContentEditor *editor,
const GdkRGBA *value);
-void e_content_editor_on_page_dialog_open
- (EContentEditor *editor);
-
-void e_content_editor_on_page_dialog_close
- (EContentEditor *editor);
-
void e_content_editor_page_get_text_color
(EContentEditor *editor,
GdkRGBA *value);
@@ -836,6 +816,12 @@ void e_content_editor_page_set_visited_link_color
void e_content_editor_page_get_visited_link_color
(EContentEditor *editor,
GdkRGBA *value);
+void e_content_editor_page_set_font_name
+ (EContentEditor *editor,
+ const gchar *value);
+
+const gchar * e_content_editor_page_get_font_name
+ (EContentEditor *editor);
void e_content_editor_page_set_background_image_uri
(EContentEditor *editor,
@@ -844,12 +830,6 @@ void e_content_editor_page_set_background_image_uri
gchar * e_content_editor_page_get_background_image_uri
(EContentEditor *editor);
-void e_content_editor_on_cell_dialog_open
- (EContentEditor *editor);
-
-void e_content_editor_on_cell_dialog_close
- (EContentEditor *editor);
-
void e_content_editor_cell_set_v_align
(EContentEditor *editor,
const gchar *value,
@@ -983,18 +963,6 @@ void e_content_editor_table_set_background_color
(EContentEditor *editor,
const GdkRGBA *value);
-gboolean e_content_editor_on_table_dialog_open
- (EContentEditor *editor);
-
-void e_content_editor_on_table_dialog_close
- (EContentEditor *editor);
-
-void e_content_editor_on_spell_check_dialog_open
- (EContentEditor *editor);
-
-void e_content_editor_on_spell_check_dialog_close
- (EContentEditor *editor);
-
gchar * e_content_editor_spell_check_next_word
(EContentEditor *editor,
const gchar *word);
@@ -1008,18 +976,6 @@ void e_content_editor_spell_check_replace_all
const gchar *word,
const gchar *replacement);
-void e_content_editor_on_replace_dialog_open
- (EContentEditor *editor);
-
-void e_content_editor_on_replace_dialog_close
- (EContentEditor *editor);
-
-void e_content_editor_on_find_dialog_open
- (EContentEditor *editor);
-
-void e_content_editor_on_find_dialog_close
- (EContentEditor *editor);
-
/* Signal helpers */
void e_content_editor_emit_load_finished
@@ -1028,9 +984,10 @@ gboolean e_content_editor_emit_paste_clipboard
(EContentEditor *editor);
gboolean e_content_editor_emit_paste_primary_clipboard
(EContentEditor *editor);
-gboolean e_content_editor_emit_context_menu_requested
+void e_content_editor_emit_context_menu_requested
(EContentEditor *editor,
EContentEditorNodeFlags flags,
+ const gchar *caret_word,
GdkEvent *event);
void e_content_editor_emit_find_done (EContentEditor *editor,
guint match_count);
@@ -1041,6 +998,9 @@ void e_content_editor_emit_drop_handled
(EContentEditor *editor);
void e_content_editor_emit_content_changed
(EContentEditor *editor);
+CamelMimePart * e_content_editor_emit_ref_mime_part
+ (EContentEditor *editor,
+ const gchar *uri);
G_END_DECLS
diff --git a/src/e-util/e-html-editor-actions.c b/src/e-util/e-html-editor-actions.c
index 932ba9479c..056158a030 100644
--- a/src/e-util/e-html-editor-actions.c
+++ b/src/e-util/e-html-editor-actions.c
@@ -605,18 +605,21 @@ update_mode_combobox (gpointer data)
}
static void
-action_mode_cb (GtkRadioAction *action,
- GtkRadioAction *current,
- EHTMLEditor *editor)
+html_editor_actions_notify_html_mode_cb (EContentEditor *cnt_editor,
+ GParamSpec *param,
+ EHTMLEditor *editor)
{
- EContentEditor *cnt_editor;
GtkActionGroup *action_group;
GtkWidget *style_combo_box;
gboolean is_html;
- cnt_editor = e_html_editor_get_content_editor (editor);
+ g_return_if_fail (E_IS_CONTENT_EDITOR (cnt_editor));
+ g_return_if_fail (E_IS_HTML_EDITOR (editor));
+
is_html = e_content_editor_get_html_mode (cnt_editor);
+ g_object_set (G_OBJECT (editor->priv->html_actions), "sensitive", is_html, NULL);
+
/* This must be done from idle callback, because apparently we can change
* current value in callback of current value change */
g_idle_add (update_mode_combobox, editor);
@@ -627,7 +630,8 @@ action_mode_cb (GtkRadioAction *action,
action_group = editor->priv->html_context_actions;
gtk_action_group_set_visible (action_group, is_html);
- gtk_widget_set_sensitive (editor->priv->color_combo_box, is_html);
+ gtk_widget_set_sensitive (editor->priv->fg_color_combo_box, is_html);
+ gtk_widget_set_sensitive (editor->priv->bg_color_combo_box, is_html);
if (is_html) {
gtk_widget_show (editor->priv->html_toolbar);
@@ -656,6 +660,15 @@ action_mode_cb (GtkRadioAction *action,
e_action_combo_box_update_model (E_ACTION_COMBO_BOX (style_combo_box));
}
+static void
+action_mode_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ EHTMLEditor *editor)
+{
+ /* Nothing to do here, wait for notification of
+ a property change from the EContentEditor */
+}
+
static void
clipboard_text_received_for_paste_as_text (GtkClipboard *clipboard,
const gchar *text,
@@ -956,6 +969,96 @@ action_wrap_lines_cb (GtkAction *action,
e_content_editor_selection_wrap (cnt_editor);
}
+/* This is when the user toggled the action */
+static void
+manage_format_subsuperscript_toggled (EHTMLEditor *editor,
+ GtkToggleAction *changed_action,
+ const gchar *prop_name,
+ GtkToggleAction *second_action)
+{
+ EContentEditor *cnt_editor = e_html_editor_get_content_editor (editor);
+
+ g_signal_handlers_block_matched (cnt_editor, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
+ g_signal_handlers_block_matched (changed_action, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
+ g_signal_handlers_block_matched (second_action, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
+
+ if (gtk_toggle_action_get_active (changed_action) &&
+ gtk_toggle_action_get_active (second_action))
+ gtk_toggle_action_set_active (second_action, FALSE);
+
+ g_object_set (G_OBJECT (cnt_editor), prop_name, gtk_toggle_action_get_active (changed_action), NULL);
+
+ g_signal_handlers_unblock_matched (second_action, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
+ g_signal_handlers_unblock_matched (changed_action, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
+ g_signal_handlers_unblock_matched (cnt_editor, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
+}
+
+/* This is when the content editor claimed change on the property */
+static void
+manage_format_subsuperscript_notify (EHTMLEditor *editor,
+ GtkToggleAction *changed_action,
+ const gchar *prop_name,
+ GtkToggleAction *second_action)
+{
+ EContentEditor *cnt_editor = e_html_editor_get_content_editor (editor);
+ gboolean value = FALSE;
+
+ g_signal_handlers_block_matched (cnt_editor, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
+ g_signal_handlers_block_matched (changed_action, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
+ g_signal_handlers_block_matched (second_action, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
+
+ g_object_get (G_OBJECT (cnt_editor), prop_name, &value, NULL);
+
+ gtk_toggle_action_set_active (changed_action, value);
+
+ if (gtk_toggle_action_get_active (changed_action) &&
+ gtk_toggle_action_get_active (second_action))
+ gtk_toggle_action_set_active (second_action, FALSE);
+
+ g_signal_handlers_unblock_matched (second_action, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
+ g_signal_handlers_unblock_matched (changed_action, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
+ g_signal_handlers_unblock_matched (cnt_editor, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
+}
+
+static void
+html_editor_actions_subscript_toggled_cb (GtkToggleAction *action,
+ EHTMLEditor *editor)
+{
+ g_return_if_fail (E_IS_HTML_EDITOR (editor));
+
+ manage_format_subsuperscript_toggled (editor, GTK_TOGGLE_ACTION (ACTION (SUBSCRIPT)), "subscript",
GTK_TOGGLE_ACTION (ACTION (SUPERSCRIPT)));
+}
+
+static void
+html_editor_actions_notify_subscript_cb (EContentEditor *cnt_editor,
+ GParamSpec *param,
+ EHTMLEditor *editor)
+{
+ g_return_if_fail (E_IS_HTML_EDITOR (editor));
+
+ manage_format_subsuperscript_notify (editor, GTK_TOGGLE_ACTION (ACTION (SUBSCRIPT)), "subscript",
GTK_TOGGLE_ACTION (ACTION (SUPERSCRIPT)));
+}
+
+static void
+html_editor_actions_superscript_toggled_cb (GtkToggleAction *action,
+ EHTMLEditor *editor)
+{
+ g_return_if_fail (E_IS_HTML_EDITOR (editor));
+
+ manage_format_subsuperscript_toggled (editor, GTK_TOGGLE_ACTION (ACTION (SUPERSCRIPT)),
"superscript", GTK_TOGGLE_ACTION (ACTION (SUBSCRIPT)));
+}
+
+static void
+html_editor_actions_notify_superscript_cb (EContentEditor *cnt_editor,
+ GParamSpec *param,
+ EHTMLEditor *editor)
+{
+ g_return_if_fail (E_IS_HTML_EDITOR (editor));
+
+ manage_format_subsuperscript_notify (editor, GTK_TOGGLE_ACTION (ACTION (SUPERSCRIPT)), "superscript",
GTK_TOGGLE_ACTION (ACTION (SUBSCRIPT)));
+}
+
+
/*****************************************************************************
* Core Actions
*
@@ -1161,6 +1264,13 @@ static GtkRadioActionEntry core_justify_entries[] = {
N_("Center Alignment"),
E_CONTENT_EDITOR_ALIGNMENT_CENTER },
+ { "justify-fill",
+ "format-justify-fill",
+ N_("_Justified"),
+ "<Control>j",
+ N_("Align Justified"),
+ E_CONTENT_EDITOR_ALIGNMENT_JUSTIFY },
+
{ "justify-left",
"format-justify-left",
N_("_Left"),
@@ -1412,14 +1522,6 @@ static GtkToggleActionEntry html_toggle_entries[] = {
NULL,
FALSE },
- { "monospaced",
- "stock_text-monospaced",
- N_("_Plain Text"),
- "<Control>t",
- N_("Plain Text"),
- NULL,
- FALSE },
-
{ "strikethrough",
"format-text-strikethrough",
N_("_Strikethrough"),
@@ -1428,6 +1530,22 @@ static GtkToggleActionEntry html_toggle_entries[] = {
NULL,
FALSE },
+ { "subscript",
+ NULL,
+ N_("Subs_cript"),
+ "<Control><Shift>b",
+ N_("Subscript"),
+ NULL,
+ FALSE },
+
+ { "superscript",
+ NULL,
+ N_("Su_perscript"),
+ "<Control><Shift>p",
+ N_("Superscript"),
+ NULL,
+ FALSE },
+
{ "underline",
"format-text-underline",
N_("_Underline"),
@@ -2110,6 +2228,42 @@ editor_actions_init (EHTMLEditor *editor)
gtk_action_set_sensitive (ACTION (FIND_AGAIN), FALSE);
}
+static gboolean
+e_html_editor_content_editor_font_name_to_combo_box (GBinding *binding,
+ const GValue *from_value,
+ GValue *to_value,
+ gpointer user_data)
+{
+ gchar *id = NULL;
+
+ id = e_html_editor_util_dup_font_id (GTK_COMBO_BOX (g_binding_get_target (binding)),
g_value_get_string (from_value));
+ g_value_take_string (to_value, id ? id : g_strdup (""));
+
+ return TRUE;
+}
+
+static gboolean
+e_html_editor_indent_level_to_bool_indent_cb (GBinding *binding,
+ const GValue *from_value,
+ GValue *to_value,
+ gpointer user_data)
+{
+ g_value_set_boolean (to_value, g_value_get_int (from_value) < E_HTML_EDITOR_MAX_INDENT_LEVEL);
+
+ return TRUE;
+}
+
+static gboolean
+e_html_editor_indent_level_to_bool_unindent_cb (GBinding *binding,
+ const GValue *from_value,
+ GValue *to_value,
+ gpointer user_data)
+{
+ g_value_set_boolean (to_value, g_value_get_int (from_value) > 0);
+
+ return TRUE;
+}
+
void
editor_actions_bind (EHTMLEditor *editor)
{
@@ -2174,18 +2328,22 @@ editor_actions_bind (EHTMLEditor *editor)
cnt_editor, "block-format",
ACTION (STYLE_NORMAL), "current-value",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
- e_binding_bind_property (
- cnt_editor, "indented",
+ e_binding_bind_property_full (
+ cnt_editor, "indent-level",
+ ACTION (INDENT), "sensitive",
+ G_BINDING_SYNC_CREATE,
+ e_html_editor_indent_level_to_bool_indent_cb,
+ NULL, NULL, NULL);
+ e_binding_bind_property_full (
+ cnt_editor, "indent-level",
ACTION (UNINDENT), "sensitive",
- G_BINDING_SYNC_CREATE);
+ G_BINDING_SYNC_CREATE,
+ e_html_editor_indent_level_to_bool_unindent_cb,
+ NULL, NULL, NULL);
e_binding_bind_property (
cnt_editor, "italic",
ACTION (ITALIC), "active",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
- e_binding_bind_property (
- cnt_editor, "monospaced",
- ACTION (MONOSPACED), "active",
- G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
e_binding_bind_property (
cnt_editor, "strikethrough",
ACTION (STRIKETHROUGH), "active",
@@ -2194,11 +2352,26 @@ editor_actions_bind (EHTMLEditor *editor)
cnt_editor, "underline",
ACTION (UNDERLINE), "active",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+ e_binding_bind_property_full (
+ cnt_editor, "font-name",
+ editor->priv->font_name_combo_box, "active-id",
+ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
+ e_html_editor_content_editor_font_name_to_combo_box,
+ NULL,
+ NULL, NULL);
- e_binding_bind_property (
- cnt_editor, "html-mode",
- editor->priv->html_actions, "sensitive",
- G_BINDING_SYNC_CREATE);
+ /* Cannot use binding, due to subscript and superscript being mutually exclusive */
+ g_signal_connect_object (ACTION (SUBSCRIPT), "toggled",
+ G_CALLBACK (html_editor_actions_subscript_toggled_cb), editor, 0);
+ g_signal_connect_object (cnt_editor, "notify::subscript",
+ G_CALLBACK (html_editor_actions_notify_subscript_cb), editor, 0);
+ g_signal_connect_object (ACTION (SUPERSCRIPT), "toggled",
+ G_CALLBACK (html_editor_actions_superscript_toggled_cb), editor, 0);
+ g_signal_connect_object (cnt_editor, "notify::superscript",
+ G_CALLBACK (html_editor_actions_notify_superscript_cb), editor, 0);
+
+ g_signal_connect_object (cnt_editor, "notify::html-mode",
+ G_CALLBACK (html_editor_actions_notify_html_mode_cb), editor, 0);
/* Disable all actions and toolbars when editor is not editable */
e_binding_bind_property (
diff --git a/src/e-util/e-html-editor-actions.h b/src/e-util/e-html-editor-actions.h
index 74b2773eee..a7898168bb 100644
--- a/src/e-util/e-html-editor-actions.h
+++ b/src/e-util/e-html-editor-actions.h
@@ -83,6 +83,8 @@
E_HTML_EDITOR_ACTION ((editor), "format-menu")
#define E_HTML_EDITOR_ACTION_FORMAT_TEXT(editor) \
E_HTML_EDITOR_ACTION ((editor), "format-text")
+#define E_HTML_EDITOR_ACTION_INDENT(editor) \
+ E_HTML_EDITOR_ACTION ((editor), "indent")
#define E_HTML_EDITOR_ACTION_INSERT_EMOTICON(editor) \
E_HTML_EDITOR_ACTION ((editor), "insert-emoticon")
#define E_HTML_EDITOR_ACTION_INSERT_EMOJI(editor) \
@@ -101,6 +103,8 @@
E_HTML_EDITOR_ACTION ((editor), "italic")
#define E_HTML_EDITOR_ACTION_JUSTIFY_CENTER(editor) \
E_HTML_EDITOR_ACTION ((editor), "justify-center")
+#define E_HTML_EDITOR_ACTION_JUSTIFY_FILL(editor) \
+ E_HTML_EDITOR_ACTION ((editor), "justify-fill")
#define E_HTML_EDITOR_ACTION_JUSTIFY_LEFT(editor) \
E_HTML_EDITOR_ACTION ((editor), "justify-left")
#define E_HTML_EDITOR_ACTION_JUSTIFY_RIGHT(editor) \
@@ -111,8 +115,6 @@
E_HTML_EDITOR_ACTION ((editor), "mode-html")
#define E_HTML_EDITOR_ACTION_MODE_PLAIN(editor) \
E_HTML_EDITOR_ACTION ((editor), "mode-plain")
-#define E_HTML_EDITOR_ACTION_MONOSPACED(editor) \
- E_HTML_EDITOR_ACTION ((editor), "monospaced")
#define E_HTML_EDITOR_ACTION_PASTE(editor) \
E_HTML_EDITOR_ACTION ((editor), "paste")
#define E_HTML_EDITOR_ACTION_PASTE_QUOTE(editor) \
@@ -151,6 +153,10 @@
E_HTML_EDITOR_ACTION ((editor), "style-h6")
#define E_HTML_EDITOR_ACTION_STYLE_NORMAL(editor) \
E_HTML_EDITOR_ACTION ((editor), "style-normal")
+#define E_HTML_EDITOR_ACTION_SUBSCRIPT(editor) \
+ E_HTML_EDITOR_ACTION ((editor), "subscript")
+#define E_HTML_EDITOR_ACTION_SUPERSCRIPT(editor) \
+ E_HTML_EDITOR_ACTION ((editor), "superscript")
#define E_HTML_EDITOR_ACTION_TEST_URL(editor) \
E_HTML_EDITOR_ACTION ((editor), "test-url")
#define E_HTML_EDITOR_ACTION_UNDERLINE(editor) \
diff --git a/src/e-util/e-html-editor-cell-dialog.c b/src/e-util/e-html-editor-cell-dialog.c
index 9f218e9b1f..87cad6fa62 100644
--- a/src/e-util/e-html-editor-cell-dialog.c
+++ b/src/e-util/e-html-editor-cell-dialog.c
@@ -304,7 +304,7 @@ html_editor_cell_dialog_show (GtkWidget *widget)
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
cnt_editor = e_html_editor_get_content_editor (editor);
- e_content_editor_on_cell_dialog_open (cnt_editor);
+ e_content_editor_on_dialog_open (cnt_editor, E_CONTENT_EDITOR_DIALOG_CELL);
gtk_toggle_button_set_active (
GTK_TOGGLE_BUTTON (dialog->priv->scope_cell_button), TRUE);
@@ -374,7 +374,7 @@ html_editor_cell_dialog_hide (GtkWidget *widget)
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
cnt_editor = e_html_editor_get_content_editor (editor);
- e_content_editor_on_cell_dialog_close (cnt_editor);
+ e_content_editor_on_dialog_close (cnt_editor, E_CONTENT_EDITOR_DIALOG_CELL);
GTK_WIDGET_CLASS (e_html_editor_cell_dialog_parent_class)->hide (widget);
}
diff --git a/src/e-util/e-html-editor-find-dialog.c b/src/e-util/e-html-editor-find-dialog.c
index 49def0b946..fe063ccc70 100644
--- a/src/e-util/e-html-editor-find-dialog.c
+++ b/src/e-util/e-html-editor-find-dialog.c
@@ -61,7 +61,7 @@ html_editor_find_dialog_hide (GtkWidget *widget)
{
EHTMLEditorFindDialog *dialog = E_HTML_EDITOR_FIND_DIALOG (widget);
- e_content_editor_on_find_dialog_close (dialog->priv->cnt_editor);
+ e_content_editor_on_dialog_close (dialog->priv->cnt_editor, E_CONTENT_EDITOR_DIALOG_FIND);
/* Chain up to parent's implementation */
GTK_WIDGET_CLASS (e_html_editor_find_dialog_parent_class)->hide (widget);
@@ -75,7 +75,7 @@ html_editor_find_dialog_show (GtkWidget *widget)
reset_dialog (dialog);
gtk_widget_grab_focus (dialog->priv->entry);
- e_content_editor_on_find_dialog_open (dialog->priv->cnt_editor);
+ e_content_editor_on_dialog_open (dialog->priv->cnt_editor, E_CONTENT_EDITOR_DIALOG_FIND);
/* Chain up to parent's implementation */
GTK_WIDGET_CLASS (e_html_editor_find_dialog_parent_class)->show (widget);
diff --git a/src/e-util/e-html-editor-hrule-dialog.c b/src/e-util/e-html-editor-hrule-dialog.c
index 342cdc1522..990196e686 100644
--- a/src/e-util/e-html-editor-hrule-dialog.c
+++ b/src/e-util/e-html-editor-hrule-dialog.c
@@ -187,7 +187,7 @@ html_editor_hrule_dialog_hide (GtkWidget *widget)
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
cnt_editor = e_html_editor_get_content_editor (editor);
- e_content_editor_on_h_rule_dialog_close (cnt_editor);
+ e_content_editor_on_dialog_close (cnt_editor, E_CONTENT_EDITOR_DIALOG_HRULE);
GTK_WIDGET_CLASS (e_html_editor_hrule_dialog_parent_class)->hide (widget);
}
@@ -198,39 +198,17 @@ html_editor_hrule_dialog_show (GtkWidget *widget)
EHTMLEditorHRuleDialog *dialog;
EHTMLEditor *editor;
EContentEditor *cnt_editor;
- gboolean created_new_h_rule = FALSE;
dialog = E_HTML_EDITOR_HRULE_DIALOG (widget);
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
cnt_editor = e_html_editor_get_content_editor (editor);
- created_new_h_rule = e_content_editor_on_h_rule_dialog_open (cnt_editor);
-
- if (!created_new_h_rule) {
- html_editor_hrule_dialog_get_alignment (dialog);
- html_editor_hrule_dialog_get_size (dialog);
- html_editor_hrule_dialog_get_width (dialog);
- html_editor_hrule_dialog_get_shading (dialog);
- } else {
- /* For new rule reset the values to default */
- gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->width_edit), 100.0);
- gtk_combo_box_set_active_id (
- GTK_COMBO_BOX (dialog->priv->unit_combo), "units-percent");
- gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->size_edit), 2.0);
- gtk_combo_box_set_active_id (
- GTK_COMBO_BOX (dialog->priv->alignment_combo), "left");
- gtk_toggle_button_set_active (
- GTK_TOGGLE_BUTTON (dialog->priv->shaded_check), FALSE);
-
- html_editor_hrule_dialog_set_alignment (dialog);
- html_editor_hrule_dialog_set_size (dialog);
- html_editor_hrule_dialog_set_alignment (dialog);
- html_editor_hrule_dialog_set_shading (dialog);
+ e_content_editor_on_dialog_open (cnt_editor, E_CONTENT_EDITOR_DIALOG_HRULE);
- e_content_editor_set_changed (cnt_editor, TRUE);
- }
+ html_editor_hrule_dialog_get_alignment (dialog);
+ html_editor_hrule_dialog_get_size (dialog);
+ html_editor_hrule_dialog_get_width (dialog);
+ html_editor_hrule_dialog_get_shading (dialog);
/* Chain up to parent implementation */
GTK_WIDGET_CLASS (e_html_editor_hrule_dialog_parent_class)->show (widget);
diff --git a/src/e-util/e-html-editor-image-dialog.c b/src/e-util/e-html-editor-image-dialog.c
index aa72f7b13a..7eafa1d302 100644
--- a/src/e-util/e-html-editor-image-dialog.c
+++ b/src/e-util/e-html-editor-image-dialog.c
@@ -359,7 +359,7 @@ html_editor_image_dialog_show (GtkWidget *widget)
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
cnt_editor = e_html_editor_get_content_editor (editor);
- e_content_editor_on_image_dialog_open (cnt_editor);
+ e_content_editor_on_dialog_open (cnt_editor, E_CONTENT_EDITOR_DIALOG_IMAGE);
value = e_content_editor_image_get_src (cnt_editor);
if (value && *value) {
@@ -432,7 +432,7 @@ html_editor_image_dialog_hide (GtkWidget *widget)
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
cnt_editor = e_html_editor_get_content_editor (editor);
- e_content_editor_on_image_dialog_close (cnt_editor);
+ e_content_editor_on_dialog_close (cnt_editor, E_CONTENT_EDITOR_DIALOG_IMAGE);
GTK_WIDGET_CLASS (e_html_editor_image_dialog_parent_class)->hide (widget);
}
diff --git a/src/e-util/e-html-editor-link-dialog.c b/src/e-util/e-html-editor-link-dialog.c
index 368dad3c11..ce5337545f 100644
--- a/src/e-util/e-html-editor-link-dialog.c
+++ b/src/e-util/e-html-editor-link-dialog.c
@@ -94,7 +94,7 @@ html_editor_link_dialog_ok (EHTMLEditorLinkDialog *dialog)
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
cnt_editor = e_html_editor_get_content_editor (editor);
- e_content_editor_link_set_values (
+ e_content_editor_link_set_properties (
cnt_editor,
gtk_entry_get_text (GTK_ENTRY (dialog->priv->url_edit)),
gtk_entry_get_text (GTK_ENTRY (dialog->priv->label_edit)));
@@ -127,7 +127,7 @@ html_editor_link_dialog_hide (GtkWidget *widget)
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
cnt_editor = e_html_editor_get_content_editor (editor);
- e_content_editor_on_link_dialog_close (cnt_editor);
+ e_content_editor_on_dialog_close (cnt_editor, E_CONTENT_EDITOR_DIALOG_LINK);
/* Chain up to parent implementation */
GTK_WIDGET_CLASS (e_html_editor_link_dialog_parent_class)->hide (widget);
@@ -153,21 +153,18 @@ html_editor_link_dialog_show (GtkWidget *widget)
dialog->priv->label_autofill = TRUE;
- e_content_editor_on_link_dialog_open (cnt_editor);
+ e_content_editor_on_dialog_open (cnt_editor, E_CONTENT_EDITOR_DIALOG_LINK);
- e_content_editor_link_get_values (cnt_editor, &href, &text);
+ e_content_editor_link_get_properties (cnt_editor, &href, &text);
if (href && *href)
- gtk_entry_set_text (
- GTK_ENTRY (dialog->priv->url_edit), href);
+ gtk_entry_set_text (GTK_ENTRY (dialog->priv->url_edit), href);
else
- gtk_widget_set_sensitive (
- dialog->priv->remove_link_button, FALSE);
+ gtk_widget_set_sensitive (dialog->priv->remove_link_button, FALSE);
g_free (href);
if (text && *text) {
- gtk_entry_set_text (
- GTK_ENTRY (dialog->priv->label_edit), text);
+ gtk_entry_set_text (GTK_ENTRY (dialog->priv->label_edit), text);
dialog->priv->label_autofill = FALSE;
}
g_free (text);
diff --git a/src/e-util/e-html-editor-manager.ui b/src/e-util/e-html-editor-manager.ui
index b097027a54..f263c13ef0 100644
--- a/src/e-util/e-html-editor-manager.ui
+++ b/src/e-util/e-html-editor-manager.ui
@@ -53,12 +53,13 @@
<menuitem action='mode-plain'/>
<separator/>
<menu action='font-style-menu'>
- <menuitem action='monospaced'/>
- <separator/>
<menuitem action='bold'/>
<menuitem action='italic'/>
<menuitem action='underline'/>
<menuitem action='strikethrough'/>
+ <separator/>
+ <menuitem action='superscript'/>
+ <menuitem action='subscript'/>
</menu>
<menu action='font-size-menu'>
<menuitem action='size-minus-two'/>
@@ -91,6 +92,7 @@
<menuitem action='justify-left'/>
<menuitem action='justify-center'/>
<menuitem action='justify-right'/>
+ <menuitem action='justify-fill'/>
</menu>
<separator/>
<menuitem action='indent'/>
@@ -117,6 +119,7 @@
<toolitem action='justify-left'/>
<toolitem action='justify-center'/>
<toolitem action='justify-right'/>
+ <toolitem action='justify-fill'/>
<separator/>
<toolitem action='unindent'/>
<toolitem action='indent'/>
@@ -125,7 +128,6 @@
</toolbar>
<toolbar name='html-toolbar'>
<separator/>
- <toolitem action='monospaced'/>
<toolitem action='bold'/>
<toolitem action='italic'/>
<toolitem action='underline'/>
diff --git a/src/e-util/e-html-editor-page-dialog.c b/src/e-util/e-html-editor-page-dialog.c
index e86f2c9ee7..f2d5ccc1b7 100644
--- a/src/e-util/e-html-editor-page-dialog.c
+++ b/src/e-util/e-html-editor-page-dialog.c
@@ -27,6 +27,7 @@
#include "e-color-combo.h"
#include "e-misc-utils.h"
#include "e-dialog-widgets.h"
+#include "e-html-editor-private.h"
#define E_HTML_EDITOR_PAGE_DIALOG_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -38,6 +39,8 @@ struct _EHTMLEditorPageDialogPrivate {
GtkWidget *visited_link_color_picker;
GtkWidget *background_color_picker;
+ GtkWidget *text_font_name_combo;
+
GtkWidget *background_template_combo;
GtkWidget *background_image_filechooser;
@@ -206,6 +209,18 @@ html_editor_page_dialog_set_background_color (EHTMLEditorPageDialog *dialog)
e_content_editor_page_set_background_color (cnt_editor, &rgba);
}
+static void
+html_editor_page_dialog_set_text_font_name (EHTMLEditorPageDialog *dialog)
+{
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ e_content_editor_page_set_font_name (cnt_editor, gtk_combo_box_get_active_id (GTK_COMBO_BOX
(dialog->priv->text_font_name_combo)));
+}
+
static void
html_editor_page_dialog_set_background_from_template (EHTMLEditorPageDialog *dialog)
{
@@ -286,13 +301,13 @@ html_editor_page_dialog_show (GtkWidget *widget)
EContentEditor *cnt_editor;
EHTMLEditorPageDialog *dialog;
GdkRGBA rgba;
- gchar *uri;
+ gchar *uri, *font_name;
dialog = E_HTML_EDITOR_PAGE_DIALOG (widget);
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
cnt_editor = e_html_editor_get_content_editor (editor);
- e_content_editor_on_page_dialog_open (cnt_editor);
+ e_content_editor_on_dialog_open (cnt_editor, E_CONTENT_EDITOR_DIALOG_PAGE);
uri = e_content_editor_page_get_background_image_uri (cnt_editor);
if (uri && *uri) {
@@ -331,6 +346,11 @@ html_editor_page_dialog_show (GtkWidget *widget)
e_color_combo_set_current_color (
E_COLOR_COMBO (dialog->priv->background_color_picker), &rgba);
+ font_name = e_html_editor_util_dup_font_id (GTK_COMBO_BOX (dialog->priv->text_font_name_combo),
+ e_content_editor_page_get_font_name (cnt_editor));
+ gtk_combo_box_set_active_id (GTK_COMBO_BOX (dialog->priv->text_font_name_combo), font_name ?
font_name : "");
+ g_free (font_name);
+
GTK_WIDGET_CLASS (e_html_editor_page_dialog_parent_class)->show (widget);
}
@@ -345,7 +365,7 @@ html_editor_page_dialog_hide (GtkWidget *widget)
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
cnt_editor = e_html_editor_get_content_editor (editor);
- e_content_editor_on_page_dialog_close (cnt_editor);
+ e_content_editor_on_dialog_close (cnt_editor, E_CONTENT_EDITOR_DIALOG_PAGE);
GTK_WIDGET_CLASS (e_html_editor_page_dialog_parent_class)->hide (widget);
}
@@ -368,15 +388,19 @@ e_html_editor_page_dialog_init (EHTMLEditorPageDialog *dialog)
GtkBox *box;
GtkGrid *grid, *main_layout;
GtkWidget *widget;
+ PangoAttrList *bold;
gint ii;
dialog->priv = E_HTML_EDITOR_PAGE_DIALOG_GET_PRIVATE (dialog);
main_layout = e_html_editor_dialog_get_container (E_HTML_EDITOR_DIALOG (dialog));
+ bold = pango_attr_list_new ();
+ pango_attr_list_insert (bold, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
+
/* == Colors == */
- widget = gtk_label_new ("");
- gtk_label_set_markup (GTK_LABEL (widget), _("<b>Colors</b>"));
+ widget = gtk_label_new (_("Colors"));
+ gtk_label_set_attributes (GTK_LABEL (widget), bold);
gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
gtk_grid_attach (main_layout, widget, 0, 0, 1, 1);
@@ -446,16 +470,42 @@ e_html_editor_page_dialog_init (EHTMLEditorPageDialog *dialog)
GTK_LABEL (widget), dialog->priv->background_color_picker);
gtk_grid_attach (grid, widget, 0, 3, 1, 1);
- /* == Background Image == */
- widget = gtk_label_new ("");
- gtk_label_set_markup (GTK_LABEL (widget), _("<b>Background Image</b>"));
+ /* == Text == */
+
+ widget = gtk_label_new (_("Text"));
+ gtk_label_set_attributes (GTK_LABEL (widget), bold);
gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
gtk_grid_attach (main_layout, widget, 0, 2, 1, 1);
grid = GTK_GRID (gtk_grid_new ());
gtk_grid_set_row_spacing (grid, 5);
gtk_grid_set_column_spacing (grid, 5);
- gtk_grid_attach (main_layout, GTK_WIDGET (grid), 0, 4, 1, 1);
+ gtk_grid_attach (main_layout, GTK_WIDGET (grid), 0, 3, 1, 1);
+ gtk_widget_set_margin_left (GTK_WIDGET (grid), 10);
+
+ widget = e_html_editor_util_create_font_name_combo ();
+ g_signal_connect_swapped (
+ widget, "notify::active-id",
+ G_CALLBACK (html_editor_page_dialog_set_text_font_name), dialog);
+ gtk_grid_attach (grid, widget, 1, 0, 1, 1);
+ dialog->priv->text_font_name_combo = widget;
+
+ widget = gtk_label_new_with_mnemonic (_("_Font Name:"));
+ gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_RIGHT);
+ gtk_label_set_mnemonic_widget (
+ GTK_LABEL (widget), dialog->priv->text_font_name_combo);
+ gtk_grid_attach (grid, widget, 0, 0, 1, 1);
+
+ /* == Background Image == */
+ widget = gtk_label_new (_("Background Image"));
+ gtk_label_set_attributes (GTK_LABEL (widget), bold);
+ gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
+ gtk_grid_attach (main_layout, widget, 0, 4, 1, 1);
+
+ grid = GTK_GRID (gtk_grid_new ());
+ gtk_grid_set_row_spacing (grid, 5);
+ gtk_grid_set_column_spacing (grid, 5);
+ gtk_grid_attach (main_layout, GTK_WIDGET (grid), 0, 5, 1, 1);
gtk_widget_set_margin_left (GTK_WIDGET (grid), 10);
/* Template */
@@ -503,6 +553,8 @@ e_html_editor_page_dialog_init (EHTMLEditorPageDialog *dialog)
gtk_box_reorder_child (box, widget, 0);
gtk_widget_show_all (GTK_WIDGET (main_layout));
+
+ pango_attr_list_unref (bold);
}
GtkWidget *
diff --git a/src/e-util/e-html-editor-paragraph-dialog.c b/src/e-util/e-html-editor-paragraph-dialog.c
index 014de3b98b..15ccebc00b 100644
--- a/src/e-util/e-html-editor-paragraph-dialog.c
+++ b/src/e-util/e-html-editor-paragraph-dialog.c
@@ -41,6 +41,7 @@ struct _EHTMLEditorParagraphDialogPrivate {
GtkWidget *left_button;
GtkWidget *center_button;
GtkWidget *right_button;
+ GtkWidget *justified_button;
};
static void
@@ -122,6 +123,15 @@ html_editor_paragraph_dialog_constructed (GObject *object)
e_html_editor_get_action (editor, "justify-right"));
dialog->priv->right_button = widget;
+ /* Justified */
+ widget = gtk_toggle_button_new_with_label (_("_Justified"));
+ gtk_button_set_use_stock (GTK_BUTTON (widget), TRUE);
+ gtk_grid_attach (grid, widget, 2, 0, 1, 1);
+ gtk_activatable_set_related_action (
+ GTK_ACTIVATABLE (widget),
+ e_html_editor_get_action (editor, "justify-fill"));
+ dialog->priv->justified_button = widget;
+
gtk_widget_show_all (GTK_WIDGET (main_layout));
}
diff --git a/src/e-util/e-html-editor-private.h b/src/e-util/e-html-editor-private.h
index 5d66c203b2..695ce0a72b 100644
--- a/src/e-util/e-html-editor-private.h
+++ b/src/e-util/e-html-editor-private.h
@@ -77,14 +77,17 @@ struct _EHTMLEditorPrivate {
GtkWidget *cell_dialog;
GtkWidget *spell_check_dialog;
- GtkWidget *color_combo_box;
+ GtkWidget *fg_color_combo_box;
+ GtkWidget *bg_color_combo_box;
GtkWidget *mode_combo_box;
GtkWidget *size_combo_box;
GtkWidget *style_combo_box;
+ GtkWidget *font_name_combo_box;
GtkWidget *scrolled_window;
GtkWidget *emoji_chooser;
+ GHashTable *cid_parts; /* gchar *cid: URI ~> CamelMimePart * */
GHashTable *content_editors;
EContentEditor *use_content_editor;
@@ -94,8 +97,6 @@ struct _EHTMLEditorPrivate {
guint recent_spell_languages_merge_id;
gint editor_layout_row;
-
- gboolean is_testing;
};
void editor_actions_init (EHTMLEditor *editor);
@@ -105,6 +106,10 @@ void editor_actions_update_spellcheck_languages_menu
const gchar * const *languages);
const gchar * e_html_editor_get_content_editor_name
(EHTMLEditor *editor);
+GtkWidget * e_html_editor_util_create_font_name_combo
+ (void);
+gchar * e_html_editor_util_dup_font_id (GtkComboBox *combo_box,
+ const gchar *font_name);
G_END_DECLS
diff --git a/src/e-util/e-html-editor-replace-dialog.c b/src/e-util/e-html-editor-replace-dialog.c
index d217b758f0..e33e7dfcbc 100644
--- a/src/e-util/e-html-editor-replace-dialog.c
+++ b/src/e-util/e-html-editor-replace-dialog.c
@@ -169,7 +169,7 @@ html_editor_replace_dialog_show (GtkWidget *widget)
{
EHTMLEditorReplaceDialog *dialog = E_HTML_EDITOR_REPLACE_DIALOG (widget);
- e_content_editor_on_replace_dialog_open (dialog->priv->cnt_editor);
+ e_content_editor_on_dialog_open (dialog->priv->cnt_editor, E_CONTENT_EDITOR_DIALOG_REPLACE);
gtk_widget_grab_focus (dialog->priv->search_entry);
gtk_widget_hide (dialog->priv->result_label);
@@ -183,7 +183,7 @@ html_editor_replace_dialog_hide (GtkWidget *widget)
{
EHTMLEditorReplaceDialog *dialog = E_HTML_EDITOR_REPLACE_DIALOG (widget);
- e_content_editor_on_replace_dialog_close (dialog->priv->cnt_editor);
+ e_content_editor_on_dialog_close (dialog->priv->cnt_editor, E_CONTENT_EDITOR_DIALOG_REPLACE);
/* Chain up to parent implementation */
GTK_WIDGET_CLASS (e_html_editor_replace_dialog_parent_class)->hide (widget);
diff --git a/src/e-util/e-html-editor-spell-check-dialog.c b/src/e-util/e-html-editor-spell-check-dialog.c
index 3d815ce774..a5b2a09ae8 100644
--- a/src/e-util/e-html-editor-spell-check-dialog.c
+++ b/src/e-util/e-html-editor-spell-check-dialog.c
@@ -288,24 +288,24 @@ html_editor_spell_check_dialog_set_dictionary (EHTMLEditorSpellCheckDialog *dial
static void
html_editor_spell_check_dialog_show (GtkWidget *widget)
{
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
EHTMLEditorSpellCheckDialog *dialog;
dialog = E_HTML_EDITOR_SPELL_CHECK_DIALOG (widget);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
g_free (dialog->priv->word);
dialog->priv->word = NULL;
+ e_content_editor_on_dialog_open (cnt_editor, E_CONTENT_EDITOR_DIALOG_SPELLCHECK);
+
/* Select the first word or quit */
if (html_editor_spell_check_dialog_next (dialog)) {
- EHTMLEditor *editor;
- EContentEditor *cnt_editor;
-
- editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- cnt_editor = e_html_editor_get_content_editor (editor);
-
- e_content_editor_on_spell_check_dialog_open (cnt_editor);
-
GTK_WIDGET_CLASS (e_html_editor_spell_check_dialog_parent_class)->show (widget);
+ } else {
+ e_content_editor_on_dialog_close (cnt_editor, E_CONTENT_EDITOR_DIALOG_SPELLCHECK);
}
}
@@ -319,7 +319,7 @@ html_editor_spell_check_dialog_hide (GtkWidget *widget)
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
cnt_editor = e_html_editor_get_content_editor (editor);
- e_content_editor_on_spell_check_dialog_close (cnt_editor);
+ e_content_editor_on_dialog_close (cnt_editor, E_CONTENT_EDITOR_DIALOG_SPELLCHECK);
/* Chain up to parent implementation */
GTK_WIDGET_CLASS (e_html_editor_spell_check_dialog_parent_class)->hide (widget);
diff --git a/src/e-util/e-html-editor-table-dialog.c b/src/e-util/e-html-editor-table-dialog.c
index d613104856..e13d914fff 100644
--- a/src/e-util/e-html-editor-table-dialog.c
+++ b/src/e-util/e-html-editor-table-dialog.c
@@ -214,8 +214,8 @@ html_editor_table_dialog_get_alignment (EHTMLEditorTableDialog *dialog)
cnt_editor = e_html_editor_get_content_editor (editor);
value = e_content_editor_table_get_align (cnt_editor);
- gtk_combo_box_set_active_id (
- GTK_COMBO_BOX (dialog->priv->alignment_combo), value);
+ gtk_combo_box_set_active_id (GTK_COMBO_BOX (dialog->priv->alignment_combo),
+ value && *value ? value : "left");
g_free (value);
}
@@ -394,32 +394,21 @@ html_editor_table_dialog_get_values (EHTMLEditorTableDialog *dialog)
static void
html_editor_table_dialog_reset_values (EHTMLEditorTableDialog *dialog)
{
- gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->rows_edit), 3);
- gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->columns_edit), 3);
- gtk_combo_box_set_active_id (
- GTK_COMBO_BOX (dialog->priv->alignment_combo), "left");
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->rows_edit), 3);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->columns_edit), 3);
+ gtk_combo_box_set_active_id (GTK_COMBO_BOX (dialog->priv->alignment_combo), "left");
- gtk_toggle_button_set_active (
- GTK_TOGGLE_BUTTON (dialog->priv->width_check), TRUE);
- gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->width_edit), 100);
- gtk_combo_box_set_active_id (
- GTK_COMBO_BOX (dialog->priv->width_units), "units-percent");
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->width_check), TRUE);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->width_edit), 100);
+ gtk_combo_box_set_active_id (GTK_COMBO_BOX (dialog->priv->width_units), "units-percent");
- gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->spacing_edit), 2);
- gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->padding_edit), 1);
- gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->border_edit), 1);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->spacing_edit), 2);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->padding_edit), 1);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->border_edit), 1);
- e_color_combo_set_current_color (
- E_COLOR_COMBO (dialog->priv->background_color_picker), &transparent);
+ e_color_combo_set_current_color (E_COLOR_COMBO (dialog->priv->background_color_picker), &transparent);
- gtk_file_chooser_unselect_all (
- GTK_FILE_CHOOSER (dialog->priv->background_image_chooser));
+ gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (dialog->priv->background_image_chooser));
html_editor_table_dialog_set_row_count (dialog);
html_editor_table_dialog_set_column_count (dialog);
@@ -443,7 +432,9 @@ html_editor_table_dialog_show (GtkWidget *widget)
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
cnt_editor = e_html_editor_get_content_editor (editor);
- if (e_content_editor_on_table_dialog_open (cnt_editor))
+ e_content_editor_on_dialog_open (cnt_editor, E_CONTENT_EDITOR_DIALOG_TABLE);
+
+ if (!e_content_editor_table_get_row_count (cnt_editor))
html_editor_table_dialog_reset_values (dialog);
else
html_editor_table_dialog_get_values (dialog);
@@ -480,7 +471,7 @@ html_editor_table_dialog_hide (GtkWidget *widget)
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
cnt_editor = e_html_editor_get_content_editor (editor);
- e_content_editor_on_table_dialog_close (cnt_editor);
+ e_content_editor_on_dialog_close (cnt_editor, E_CONTENT_EDITOR_DIALOG_TABLE);
GTK_WIDGET_CLASS (e_html_editor_table_dialog_parent_class)->hide (widget);
}
diff --git a/src/e-util/e-html-editor.c b/src/e-util/e-html-editor.c
index 59ab93e472..bb0c998ec1 100644
--- a/src/e-util/e-html-editor.c
+++ b/src/e-util/e-html-editor.c
@@ -95,6 +95,134 @@ G_DEFINE_TYPE_WITH_CODE (
E_TYPE_ALERT_SINK,
e_html_editor_alert_sink_init))
+/* See: https://www.w3schools.com/cssref/css_websafe_fonts.asp */
+static struct _SupportedFonts {
+ const gchar *display_name;
+ const gchar *css_value;
+} supported_fonts[] = {
+ { "Arial", "Arial, Helvetica, sans-serif" },
+ { "Arial Black", "\"Arial Black\", Gadget, sans-serif" },
+ { "Comic Sans MS", "\"Comic Sans MS\", cursive, sans-serif" },
+ { "Courier New", "\"Courier New\", Courier, monospace" },
+ { "Georgia", "Georgia, serif" },
+ { "Impact", "Impact, Charcoal, sans-serif" },
+ { "Lucida Console", "\"Lucida Console\", Monaco, monospace" },
+ { "Lucida Sans", "\"Lucida Sans Unicode\", \"Lucida Grande\", sans-serif" },
+ { "Monospace", "monospace" },
+ { "Palatino", "\"Palatino Linotype\", \"Book Antiqua\", Palatino, serif" },
+ { "Tahoma", "Tahoma, Geneva, sans-serif" },
+ { "Times New Roman", "\"Times New Roman\", Times, serif" },
+ { "Trebuchet MS", "\"Trebuchet MS\", Helvetica, sans-serif" },
+ { "Verdana", "Verdana, Geneva, sans-serif" }
+};
+
+GtkWidget *
+e_html_editor_util_create_font_name_combo (void)
+{
+ GtkComboBoxText *combo_box;
+ gint ii;
+
+ combo_box = GTK_COMBO_BOX_TEXT (gtk_combo_box_text_new ());
+
+ gtk_combo_box_text_append (combo_box, "", _("Default"));
+
+ for (ii = 0; ii < G_N_ELEMENTS (supported_fonts); ii++) {
+ gtk_combo_box_text_append (combo_box, supported_fonts[ii].css_value,
supported_fonts[ii].display_name);
+ }
+
+ return GTK_WIDGET (combo_box);
+}
+
+gchar *
+e_html_editor_util_dup_font_id (GtkComboBox *combo_box,
+ const gchar *font_name)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GSList *free_str = NULL;
+ gchar *id = NULL, **variants;
+ gint id_column, ii;
+
+ g_return_val_if_fail (GTK_IS_COMBO_BOX_TEXT (combo_box), NULL);
+
+ if (!font_name || !*font_name)
+ return NULL;
+
+ for (ii = 0; ii < G_N_ELEMENTS (supported_fonts); ii++) {
+ if (camel_strcase_equal (supported_fonts[ii].css_value, font_name))
+ return g_strdup (font_name);
+ }
+
+ id_column = gtk_combo_box_get_id_column (combo_box);
+ model = gtk_combo_box_get_model (combo_box);
+
+ if (gtk_tree_model_get_iter_first (model, &iter)) {
+ do {
+ gchar *stored_id = NULL;
+
+ gtk_tree_model_get (model, &iter, id_column, &stored_id, -1);
+
+ if (stored_id && *stored_id) {
+ if (camel_strcase_equal (stored_id, font_name)) {
+ id = stored_id;
+ break;
+ }
+
+ free_str = g_slist_prepend (free_str, stored_id);
+ } else {
+ g_free (stored_id);
+ }
+ } while (gtk_tree_model_iter_next (model, &iter));
+ }
+
+ if (!id) {
+ GHashTable *known_fonts;
+ GSList *free_strv = NULL, *link;
+
+ known_fonts = g_hash_table_new (camel_strcase_hash, camel_strcase_equal);
+
+ for (link = free_str; link; link = g_slist_next (link)) {
+ gchar *stored_id = link->data;
+
+ variants = g_strsplit (stored_id, ",", -1);
+ for (ii = 0; variants[ii]; ii++) {
+ if (variants[ii][0] &&
+ !g_hash_table_contains (known_fonts, variants[ii])) {
+ g_hash_table_insert (known_fonts, variants[ii], stored_id);
+ }
+ }
+
+ free_strv = g_slist_prepend (free_strv, variants);
+ }
+
+ variants = g_strsplit (font_name, ",", -1);
+ for (ii = 0; variants[ii]; ii++) {
+ if (variants[ii][0]) {
+ const gchar *stored_id;
+
+ stored_id = g_hash_table_lookup (known_fonts, variants[ii]);
+ if (stored_id) {
+ id = g_strdup (stored_id);
+ break;
+ }
+ }
+ }
+
+ if (!id) {
+ gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo_box), font_name, variants[0]);
+ id = g_strdup (font_name);
+ }
+
+ g_hash_table_destroy (known_fonts);
+ g_slist_free_full (free_strv, (GDestroyNotify) g_strfreev);
+ g_strfreev (variants);
+ }
+
+ g_slist_free_full (free_str, g_free);
+
+ return id;
+}
+
/* Action callback for context menu spelling suggestions.
* XXX This should really be in e-html-editor-actions.c */
static void
@@ -112,7 +240,8 @@ action_context_spell_suggest_cb (GtkAction *action,
}
static void
-html_editor_inline_spelling_suggestions (EHTMLEditor *editor)
+html_editor_inline_spelling_suggestions (EHTMLEditor *editor,
+ const gchar *caret_word)
{
EContentEditor *cnt_editor;
ESpellChecker *spell_checker;
@@ -120,7 +249,6 @@ html_editor_inline_spelling_suggestions (EHTMLEditor *editor)
GtkUIManager *manager;
gchar **suggestions;
const gchar *path;
- gchar *word;
guint count = 0;
guint length;
guint merge_id;
@@ -128,12 +256,11 @@ html_editor_inline_spelling_suggestions (EHTMLEditor *editor)
gint ii;
cnt_editor = e_html_editor_get_content_editor (editor);
- word = e_content_editor_get_caret_word (cnt_editor);
- if (word == NULL || *word == '\0')
+ if (!caret_word || !*caret_word)
return;
spell_checker = e_content_editor_ref_spell_checker (cnt_editor);
- suggestions = e_spell_checker_get_guesses_for_word (spell_checker, word);
+ suggestions = e_spell_checker_get_guesses_for_word (spell_checker, caret_word);
path = "/context-menu/context-spell-suggest/";
manager = e_html_editor_get_ui_manager (editor);
@@ -167,12 +294,9 @@ html_editor_inline_spelling_suggestions (EHTMLEditor *editor)
/* Action name just needs to be unique. */
action_name = g_strdup_printf ("suggest-%d", count++);
+ action_label = g_markup_printf_escaped ("<b>%s</b>", suggestion);
- action_label = g_markup_printf_escaped (
- "<b>%s</b>", suggestion);
-
- action = gtk_action_new (
- action_name, action_label, NULL, NULL);
+ action = gtk_action_new (action_name, action_label, NULL, NULL);
g_object_set_data_full (
G_OBJECT (action), "word",
@@ -201,7 +325,6 @@ html_editor_inline_spelling_suggestions (EHTMLEditor *editor)
g_free (action_label);
}
- g_free (word);
g_strfreev (suggestions);
g_clear_object (&spell_checker);
}
@@ -209,7 +332,8 @@ html_editor_inline_spelling_suggestions (EHTMLEditor *editor)
/* Helper for html_editor_update_actions() */
static void
html_editor_spell_checkers_foreach (EHTMLEditor *editor,
- const gchar *language_code)
+ const gchar *language_code,
+ const gchar *caret_word)
{
EContentEditor *cnt_editor;
ESpellChecker *spell_checker;
@@ -218,22 +342,18 @@ html_editor_spell_checkers_foreach (EHTMLEditor *editor,
GtkUIManager *manager;
GList *list, *link;
gchar *path;
- gchar *word;
gint ii = 0;
guint merge_id;
cnt_editor = e_html_editor_get_content_editor (editor);
- word = e_content_editor_get_caret_word (cnt_editor);
- if (word == NULL || *word == '\0')
+ if (!caret_word || !*caret_word)
return;
spell_checker = e_content_editor_ref_spell_checker (cnt_editor);
- dictionary = e_spell_checker_ref_dictionary (
- spell_checker, language_code);
+ dictionary = e_spell_checker_ref_dictionary (spell_checker, language_code);
if (dictionary != NULL) {
- list = e_spell_dictionary_get_suggestions (
- dictionary, word, -1);
+ list = e_spell_dictionary_get_suggestions (dictionary, caret_word, -1);
g_object_unref (dictionary);
} else {
list = NULL;
@@ -256,14 +376,10 @@ html_editor_spell_checkers_foreach (EHTMLEditor *editor,
GSList *proxies;
/* Action name just needs to be unique. */
- action_name = g_strdup_printf (
- "suggest-%s-%d", language_code, ii);
-
- action_label = g_markup_printf_escaped (
- "%s", suggestion);
+ action_name = g_strdup_printf ("suggest-%s-%d", language_code, ii);
+ action_label = g_markup_printf_escaped ("%s", suggestion);
- action = gtk_action_new (
- action_name, action_label, NULL, NULL);
+ action = gtk_action_new (action_name, action_label, NULL, NULL);
g_object_set_data_full (
G_OBJECT (action), "word",
@@ -297,7 +413,6 @@ html_editor_spell_checkers_foreach (EHTMLEditor *editor,
g_list_free_full (list, (GDestroyNotify) g_free);
g_clear_object (&spell_checker);
g_free (path);
- g_free (word);
}
void
@@ -332,7 +447,8 @@ action_set_visible_and_sensitive (GtkAction *action,
static void
html_editor_update_actions (EHTMLEditor *editor,
- EContentEditorNodeFlags flags)
+ EContentEditorNodeFlags flags,
+ const gchar *caret_word)
{
EContentEditor *cnt_editor;
ESpellChecker *spell_checker;
@@ -422,13 +538,11 @@ html_editor_update_actions (EHTMLEditor *editor,
/* Decide if we should show spell checking items. */
visible = FALSE;
if (n_languages > 0) {
- gchar *word = e_content_editor_get_caret_word (cnt_editor);
- if (word && *word) {
- visible = !e_spell_checker_check_word (spell_checker, word, -1);
+ if (caret_word && *caret_word) {
+ visible = !e_spell_checker_check_word (spell_checker, caret_word, -1);
} else {
visible = FALSE;
}
- g_free (word);
}
action_group = editor->priv->spell_check_actions;
@@ -447,7 +561,7 @@ html_editor_update_actions (EHTMLEditor *editor,
/* Handle a single active language as a special case. */
if (n_languages == 1) {
- html_editor_inline_spelling_suggestions (editor);
+ html_editor_inline_spelling_suggestions (editor, caret_word);
g_strfreev (languages);
e_html_editor_update_spell_actions (editor);
@@ -456,7 +570,7 @@ html_editor_update_actions (EHTMLEditor *editor,
/* Add actions and context menu content for active languages. */
for (ii = 0; ii < n_languages; ii++)
- html_editor_spell_checkers_foreach (editor, languages[ii]);
+ html_editor_spell_checkers_foreach (editor, languages[ii], caret_word);
g_strfreev (languages);
@@ -493,6 +607,7 @@ html_editor_spell_languages_changed (EHTMLEditor *editor)
typedef struct _ContextMenuData {
GWeakRef *editor_weakref; /* EHTMLEditor * */
EContentEditorNodeFlags flags;
+ gchar *caret_word;
GdkEvent *event;
} ContextMenuData;
@@ -504,6 +619,7 @@ context_menu_data_free (gpointer ptr)
if (cmd) {
g_clear_pointer (&cmd->event, gdk_event_free);
e_weak_ref_free (cmd->editor_weakref);
+ g_free (cmd->caret_word);
g_slice_free (ContextMenuData, cmd);
}
}
@@ -532,7 +648,7 @@ html_editor_show_context_menu_idle_cb (gpointer user_data)
menu = e_html_editor_get_managed_widget (editor, "/context-menu");
- g_signal_emit (editor, signals[UPDATE_ACTIONS], 0, cmd->flags);
+ g_signal_emit (editor, signals[UPDATE_ACTIONS], 0, cmd->flags, cmd->caret_word);
if (!gtk_menu_get_attach_widget (GTK_MENU (menu))) {
gtk_menu_attach_to_widget (GTK_MENU (menu), GTK_WIDGET (editor), NULL);
@@ -550,25 +666,25 @@ html_editor_show_context_menu_idle_cb (gpointer user_data)
return FALSE;
}
-static gboolean
+static void
html_editor_context_menu_requested_cb (EContentEditor *cnt_editor,
- EContentEditorNodeFlags flags,
- GdkEvent *event,
- EHTMLEditor *editor)
+ EContentEditorNodeFlags flags,
+ const gchar *caret_word,
+ GdkEvent *event,
+ EHTMLEditor *editor)
{
ContextMenuData *cmd;
- g_return_val_if_fail (E_IS_HTML_EDITOR (editor), FALSE);
+ g_return_if_fail (E_IS_HTML_EDITOR (editor));
cmd = g_slice_new0 (ContextMenuData);
cmd->editor_weakref = e_weak_ref_new (editor);
cmd->flags = flags;
+ cmd->caret_word = g_strdup (caret_word);
cmd->event = gdk_event_copy (event);
g_idle_add_full (G_PRIORITY_LOW, html_editor_show_context_menu_idle_cb,
cmd, context_menu_data_free);
-
- return TRUE;
}
static gchar *
@@ -657,6 +773,7 @@ html_editor_constructed (GObject *object)
{
EHTMLEditor *editor = E_HTML_EDITOR (object);
EHTMLEditorPrivate *priv = editor->priv;
+ GdkRGBA transparent = { 0, 0, 0, 0 };
GtkWidget *widget;
GtkToolbar *toolbar;
GtkToolItem *tool_item;
@@ -768,7 +885,18 @@ html_editor_constructed (GObject *object)
gtk_container_add (GTK_CONTAINER (tool_item), widget);
gtk_widget_set_tooltip_text (widget, _("Font Color"));
gtk_toolbar_insert (toolbar, tool_item, 0);
- priv->color_combo_box = g_object_ref (widget);
+ priv->fg_color_combo_box = g_object_ref (widget);
+ gtk_widget_show_all (GTK_WIDGET (tool_item));
+
+ tool_item = gtk_tool_item_new ();
+ widget = e_color_combo_new ();
+ e_color_combo_set_default_color (E_COLOR_COMBO (widget), &transparent);
+ e_color_combo_set_current_color (E_COLOR_COMBO (widget), &transparent);
+ e_color_combo_set_default_transparent (E_COLOR_COMBO (widget), TRUE);
+ gtk_container_add (GTK_CONTAINER (tool_item), widget);
+ gtk_widget_set_tooltip_text (widget, _("Background Color"));
+ gtk_toolbar_insert (toolbar, tool_item, 1);
+ priv->bg_color_combo_box = g_object_ref (widget);
gtk_widget_show_all (GTK_WIDGET (tool_item));
tool_item = gtk_tool_item_new ();
@@ -781,6 +909,15 @@ html_editor_constructed (GObject *object)
priv->size_combo_box = g_object_ref (widget);
gtk_widget_show_all (GTK_WIDGET (tool_item));
+ tool_item = gtk_tool_item_new ();
+ widget = e_html_editor_util_create_font_name_combo ();
+ gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (widget), FALSE);
+ gtk_container_add (GTK_CONTAINER (tool_item), widget);
+ gtk_widget_set_tooltip_text (widget, _("Font Name"));
+ gtk_toolbar_insert (toolbar, tool_item, 0);
+ priv->font_name_combo_box = g_object_ref (widget);
+ gtk_widget_show_all (GTK_WIDGET (tool_item));
+
g_signal_connect_after (object, "realize", G_CALLBACK (html_editor_realize), NULL);
}
@@ -809,9 +946,11 @@ html_editor_dispose (GObject *object)
g_clear_object (&priv->alert_bar);
g_clear_object (&priv->edit_area);
- g_clear_object (&priv->color_combo_box);
+ g_clear_object (&priv->fg_color_combo_box);
+ g_clear_object (&priv->bg_color_combo_box);
g_clear_object (&priv->mode_combo_box);
g_clear_object (&priv->size_combo_box);
+ g_clear_object (&priv->font_name_combo_box);
g_clear_object (&priv->style_combo_box);
/* Chain up to parent's dispose() method. */
@@ -823,6 +962,7 @@ html_editor_finalize (GObject *object)
{
EHTMLEditor *editor = E_HTML_EDITOR (object);
+ g_hash_table_destroy (editor->priv->cid_parts);
g_hash_table_destroy (editor->priv->content_editors);
/* Chain up to parent's method. */
@@ -878,9 +1018,10 @@ e_html_editor_class_init (EHTMLEditorClass *class)
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (EHTMLEditorClass, update_actions),
NULL, NULL,
- g_cclosure_marshal_VOID__UINT,
- G_TYPE_NONE, 1,
- G_TYPE_UINT);
+ NULL,
+ G_TYPE_NONE, 2,
+ G_TYPE_UINT,
+ G_TYPE_STRING);
signals[SPELL_LANGUAGES_CHANGED] = g_signal_new (
"spell-languages-changed",
@@ -918,6 +1059,7 @@ e_html_editor_init (EHTMLEditor *editor)
priv->language_actions = gtk_action_group_new ("language");
priv->spell_check_actions = gtk_action_group_new ("spell-check");
priv->suggestion_actions = gtk_action_group_new ("suggestion");
+ priv->cid_parts = g_hash_table_new_full (camel_strcase_hash, camel_strcase_equal, g_free,
g_object_unref);
priv->content_editors = g_hash_table_new_full (camel_strcase_hash, camel_strcase_equal, g_free, NULL);
filename = html_editor_find_ui_file ("e-html-editor-manager.ui");
@@ -942,12 +1084,20 @@ e_html_editor_content_editor_initialized (EContentEditor *content_editor,
g_return_if_fail (content_editor == e_html_editor_get_content_editor (html_editor));
e_binding_bind_property (
- html_editor->priv->color_combo_box, "current-color",
+ html_editor->priv->fg_color_combo_box, "current-color",
content_editor, "font-color",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
e_binding_bind_property (
content_editor, "editable",
- html_editor->priv->color_combo_box, "sensitive",
+ html_editor->priv->fg_color_combo_box, "sensitive",
+ G_BINDING_SYNC_CREATE);
+ e_binding_bind_property (
+ html_editor->priv->bg_color_combo_box, "current-color",
+ content_editor, "background-color",
+ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+ e_binding_bind_property (
+ content_editor, "editable",
+ html_editor->priv->bg_color_combo_box, "sensitive",
G_BINDING_SYNC_CREATE);
editor_actions_bind (html_editor);
@@ -1057,8 +1207,12 @@ e_html_editor_get_content_editor (EHTMLEditor *editor)
}
}
- if (editor->priv->use_content_editor)
+ if (editor->priv->use_content_editor) {
e_content_editor_setup_editor (editor->priv->use_content_editor, editor);
+
+ g_signal_connect_swapped (editor->priv->use_content_editor, "ref-mime-part",
+ G_CALLBACK (e_html_editor_ref_cid_part), editor);
+ }
}
return editor->priv->use_content_editor;
@@ -1313,66 +1467,261 @@ e_html_editor_pack_above (EHTMLEditor *editor,
editor->priv->editor_layout_row++;
}
+typedef struct _SaveContentData {
+ GOutputStream *stream;
+ GCancellable *cancellable;
+} SaveContentData;
+
+static SaveContentData *
+save_content_data_new (GOutputStream *stream,
+ GCancellable *cancellable)
+{
+ SaveContentData *scd;
+
+ scd = g_slice_new (SaveContentData);
+ scd->stream = stream;
+ scd->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+
+ return scd;
+}
+
+static void
+save_content_data_free (gpointer ptr)
+{
+ SaveContentData *scd = ptr;
+
+ if (scd) {
+ g_clear_object (&scd->stream);
+ g_clear_object (&scd->cancellable);
+ g_slice_free (SaveContentData, scd);
+ }
+}
+
+static void
+e_html_editor_save_content_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ ESimpleAsyncResult *simple = user_data;
+ EContentEditorContentHash *content_hash;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (source_object));
+ g_return_if_fail (E_IS_SIMPLE_ASYNC_RESULT (simple));
+
+ content_hash = e_content_editor_get_content_finish (E_CONTENT_EDITOR (source_object), result, &error);
+
+ if (content_hash) {
+ const gchar *content;
+
+ content = e_content_editor_util_get_content_data (content_hash, GPOINTER_TO_UINT
(e_simple_async_result_get_op_pointer (simple)));
+
+ if (!content) {
+ g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Failed to obtain
content of editor"));
+ } else {
+ SaveContentData *scd;
+ gsize written;
+
+ scd = e_simple_async_result_get_user_data (simple);
+
+ g_output_stream_write_all (scd->stream, content, strlen (content), &written,
scd->cancellable, &error);
+ }
+
+ e_content_editor_util_free_content_hash (content_hash);
+
+ if (error)
+ e_simple_async_result_take_error (simple, error);
+ } else {
+ e_simple_async_result_take_error (simple, error);
+ }
+
+ e_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
/**
* e_html_editor_save:
* @editor: an #EHTMLEditor
* @filename: file into which to save the content
* @as_html: whether the content should be saved as HTML or plain text
- * @error:[out] a #GError
+ * @cancellable: an optional #GCancellable, or %NULL
+ * @callback: (scope async): a #GAsyncReadyCallback to call when the save is finished
+ * @user_data: (closure callback): user data passed to @callback
*
- * Saves current content of the #EContentEditor into given file. When @as_html
- * is @FALSE, the content is first converted into plain text.
+ * Starts an asynchronous save of the current content of the #EContentEditor
+ * into given file. When @as_html is @FALSE, the content is first converted
+ * into plain text.
*
- * Returns: @TRUE when content is succesfully saved, @FALSE otherwise.
- */
-gboolean
+ * Finish the call with e_html_editor_save_finish() from the @callback.
+ *
+ * Since: 3.38
+ **/
+void
e_html_editor_save (EHTMLEditor *editor,
- const gchar *filename,
- gboolean as_html,
- GError **error)
+ const gchar *filename,
+ gboolean as_html,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
EContentEditor *cnt_editor;
+ ESimpleAsyncResult *simple;
+ EContentEditorGetContentFlags flag;
+ SaveContentData *scd;
GFile *file;
GFileOutputStream *stream;
- gchar *content;
- gsize written;
+ GError *local_error = NULL;
+
+ simple = e_simple_async_result_new (G_OBJECT (editor), callback, user_data, e_html_editor_save);
file = g_file_new_for_path (filename);
- stream = g_file_replace (
- file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, error);
- if ((error && *error) || !stream)
- return FALSE;
+ stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &local_error);
+ if (local_error || !stream) {
+ e_simple_async_result_take_error (simple, local_error);
+ e_simple_async_result_complete_idle (simple);
- cnt_editor = e_html_editor_get_content_editor (editor);
+ g_object_unref (simple);
+ g_object_unref (file);
- if (as_html)
- content = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_TEXT_HTML |
- E_CONTENT_EDITOR_GET_PROCESSED,
- NULL, NULL);
- else
- content = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_TEXT_PLAIN |
- E_CONTENT_EDITOR_GET_PROCESSED,
- NULL, NULL);
-
- if (!content || !*content) {
- g_free (content);
- g_set_error (
- error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Failed to obtain content of editor");
- return FALSE;
+ return;
}
- g_output_stream_write_all (
- G_OUTPUT_STREAM (stream), content, strlen (content),
- &written, NULL, error);
+ flag = as_html ? E_CONTENT_EDITOR_GET_TO_SEND_HTML : E_CONTENT_EDITOR_GET_TO_SEND_PLAIN;
+
+ scd = save_content_data_new (G_OUTPUT_STREAM (stream), cancellable);
+
+ e_simple_async_result_set_user_data (simple, scd, save_content_data_free);
+ e_simple_async_result_set_op_pointer (simple, GUINT_TO_POINTER (flag), NULL);
+
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ e_content_editor_get_content (cnt_editor, flag, NULL, cancellable,
e_html_editor_save_content_ready_cb, simple);
- g_free (content);
- g_object_unref (stream);
g_object_unref (file);
+}
+
+/**
+ * e_html_editor_save_finish:
+ * @editor: an #EHTMLEditor
+ * @result: a #GAsyncResult of the operation
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finished the previous call of e_html_editor_save().
+ *
+ * Returns: whether the save succeeded.
+ *
+ * Since: 3.38
+ **/
+gboolean
+e_html_editor_save_finish (EHTMLEditor *editor,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (e_simple_async_result_is_valid (result, G_OBJECT (editor), e_html_editor_save),
FALSE);
+
+ return !e_simple_async_result_propagate_error (E_SIMPLE_ASYNC_RESULT (result), error);
+}
+
+/**
+ * e_html_editor_add_cid_part:
+ * @editor: an #EHTMLEditor
+ * @mime_part: a #CamelMimePart
+ *
+ * Add the @mime_part with its Content-ID (if not set, one is assigned),
+ * which can be later obtained with e_html_editor_ref_cid_part();
+ *
+ * Since: 3.38
+ **/
+void
+e_html_editor_add_cid_part (EHTMLEditor *editor,
+ CamelMimePart *mime_part)
+{
+ const gchar *cid;
+ gchar *cid_uri;
+
+ g_return_if_fail (E_IS_HTML_EDITOR (editor));
+ g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+
+ cid = camel_mime_part_get_content_id (mime_part);
+
+ if (!cid) {
+ camel_mime_part_set_content_id (mime_part, NULL);
+ cid = camel_mime_part_get_content_id (mime_part);
+ }
+
+ cid_uri = g_strconcat ("cid:", cid, NULL);
+
+ g_hash_table_insert (editor->priv->cid_parts, cid_uri, g_object_ref (mime_part));
+}
+
+/**
+ * e_html_editor_remove_cid_part:
+ * @editor: an #EHTMLEditor
+ * @cid_uri: a Content ID URI (starts with "cid:") to remove
+ *
+ * Removes CID part with given @cid_uri, previously added with
+ * e_html_editor_add_cid_part(). The function does nothing if no
+ * such part is stored.
+ *
+ * Since: 3.38
+ **/
+void
+e_html_editor_remove_cid_part (EHTMLEditor *editor,
+ const gchar *cid_uri)
+{
+ g_return_if_fail (E_IS_HTML_EDITOR (editor));
+ g_return_if_fail (cid_uri != NULL);
+
+ g_hash_table_remove (editor->priv->cid_parts, cid_uri);
+}
+
+/**
+ * e_html_editor_remove_all_cid_parts:
+ * @editor: an #EHTMLEditor
+ *
+ * Removes all CID parts previously added with
+ * e_html_editor_add_cid_part().
+ *
+ * Since: 3.38
+ **/
+void
+e_html_editor_remove_all_cid_parts (EHTMLEditor *editor)
+{
+ g_return_if_fail (E_IS_HTML_EDITOR (editor));
+
+ g_hash_table_remove_all (editor->priv->cid_parts);
+}
+
+/**
+ * e_html_editor_ref_cid_part:
+ * @editor: an #EHTMLEditor
+ * @cid_uri: a Content ID URI (starts with "cid:") to obtain the part for
+ *
+ * References a #CamelMimePart with given @cid_uri as Content ID, if
+ * previously added with e_html_editor_add_cid_part(). The @cid_uri
+ * should start with "cid:".
+ *
+ * The returned non-%NULL object is references, thus it should be freed
+ * with g_object_unref(), when no longer needed.
+ *
+ * Returns: (transfer full) (nullable): a #CamelMimePart with given Content ID,
+ * or %NULL, if not found.
+ *
+ * Since: 3.38
+ **/
+CamelMimePart *
+e_html_editor_ref_cid_part (EHTMLEditor *editor,
+ const gchar *cid_uri)
+{
+ CamelMimePart *mime_part;
+
+ g_return_val_if_fail (E_IS_HTML_EDITOR (editor), NULL);
+ g_return_val_if_fail (cid_uri != NULL, NULL);
+
+ mime_part = g_hash_table_lookup (editor->priv->cid_parts, cid_uri);
+
+ if (mime_part)
+ g_object_ref (mime_part);
- return TRUE;
+ return mime_part;
}
diff --git a/src/e-util/e-html-editor.h b/src/e-util/e-html-editor.h
index 6c5a63a62d..8be1af19ea 100644
--- a/src/e-util/e-html-editor.h
+++ b/src/e-util/e-html-editor.h
@@ -49,6 +49,8 @@
(G_TYPE_INSTANCE_GET_CLASS \
((obj), E_TYPE_HTML_EDITOR, EHTMLEditorClass))
+#define E_HTML_EDITOR_MAX_INDENT_LEVEL 10
+
G_BEGIN_DECLS
typedef struct _EHTMLEditor EHTMLEditor;
@@ -64,7 +66,8 @@ struct _EHTMLEditorClass {
GtkGridClass parent_class;
void (*update_actions) (EHTMLEditor *editor,
- EContentEditorNodeFlags flags);
+ EContentEditorNodeFlags flags,
+ const gchar *caret_word);
void (*spell_languages_changed)
(EHTMLEditor *editor);
@@ -104,16 +107,23 @@ void e_html_editor_pack_above (EHTMLEditor *editor,
GtkWidget *child);
void e_html_editor_update_spell_actions
(EHTMLEditor *editor);
-
-
-/*****************************************************************************
- * High-Level Editing Interface
- *****************************************************************************/
-
-gboolean e_html_editor_save (EHTMLEditor *editor,
+void e_html_editor_save (EHTMLEditor *editor,
const gchar *filename,
gboolean as_html,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_html_editor_save_finish (EHTMLEditor *editor,
+ GAsyncResult *result,
GError **error);
+void e_html_editor_add_cid_part (EHTMLEditor *editor,
+ CamelMimePart *mime_part);
+void e_html_editor_remove_cid_part (EHTMLEditor *editor,
+ const gchar *cid_uri);
+void e_html_editor_remove_all_cid_parts
+ (EHTMLEditor *editor);
+CamelMimePart * e_html_editor_ref_cid_part (EHTMLEditor *editor,
+ const gchar *cid_uri);
G_END_DECLS
diff --git a/src/e-util/e-mail-signature-editor.c b/src/e-util/e-mail-signature-editor.c
index 2ba2955ded..a2fa5d1149 100644
--- a/src/e-util/e-mail-signature-editor.c
+++ b/src/e-util/e-mail-signature-editor.c
@@ -46,10 +46,13 @@ struct _EMailSignatureEditorPrivate {
};
struct _AsyncContext {
+ ESourceRegistry *registry;
ESource *source;
GCancellable *cancellable;
+ EContentEditorGetContentFlags contents_flag;
gchar *contents;
gsize length;
+ GDestroyNotify destroy_contents;
};
enum {
@@ -86,13 +89,14 @@ G_DEFINE_TYPE (
static void
async_context_free (AsyncContext *async_context)
{
- if (async_context->source != NULL)
- g_object_unref (async_context->source);
-
- if (async_context->cancellable != NULL)
- g_object_unref (async_context->cancellable);
+ g_clear_object (&async_context->registry);
+ g_clear_object (&async_context->source);
+ g_clear_object (&async_context->cancellable);
- g_free (async_context->contents);
+ if (async_context->destroy_contents)
+ async_context->destroy_contents (async_context->contents);
+ else
+ g_free (async_context->contents);
g_slice_free (AsyncContext, async_context);
}
@@ -225,16 +229,56 @@ action_close_cb (GtkAction *action,
gtk_widget_destroy (GTK_WIDGET (window));
}
+static void
+mail_signature_editor_commit_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EMailSignatureEditor *editor;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_MAIL_SIGNATURE_EDITOR (source_object));
+
+ editor = E_MAIL_SIGNATURE_EDITOR (source_object);
+
+ e_mail_signature_editor_commit_finish (editor, result, &error);
+
+ /* Ignore cancellations. */
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_error_free (error);
+
+ } else if (error != NULL) {
+ e_alert_submit (
+ E_ALERT_SINK (e_mail_signature_editor_get_editor (editor)),
+ "widgets:no-save-signature",
+ error->message, NULL);
+ g_error_free (error);
+
+ /* Only destroy the editor if the save was successful. */
+ } else {
+ ESourceRegistry *registry;
+ ESource *source;
+
+ registry = e_mail_signature_editor_get_registry (editor);
+ source = e_mail_signature_editor_get_source (editor);
+
+ /* Only make sure that the 'source-changed' is called,
+ * thus the preview of the signature is updated on save.
+ * It is not called when only signature body is changed
+ * (and ESource properties are left unchanged). */
+ g_signal_emit_by_name (registry, "source-changed", source);
+
+ gtk_widget_destroy (GTK_WIDGET (editor));
+ }
+}
+
static void
action_save_and_close_cb (GtkAction *action,
EMailSignatureEditor *editor)
{
GtkEntry *entry;
- EAsyncClosure *closure;
- GAsyncResult *result;
ESource *source;
gchar *display_name;
- GError *error = NULL;
entry = GTK_ENTRY (editor->priv->entry);
source = e_mail_signature_editor_get_source (editor);
@@ -263,43 +307,9 @@ action_save_and_close_cb (GtkAction *action,
editor->priv->cancellable = g_cancellable_new ();
- closure = e_async_closure_new ();
-
e_mail_signature_editor_commit (
editor, editor->priv->cancellable,
- e_async_closure_callback, closure);
-
- result = e_async_closure_wait (closure);
-
- e_mail_signature_editor_commit_finish (editor, result, &error);
-
- e_async_closure_free (closure);
-
- /* Ignore cancellations. */
- if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
- g_error_free (error);
-
- } else if (error != NULL) {
- e_alert_submit (
- E_ALERT_SINK (e_mail_signature_editor_get_editor (editor)),
- "widgets:no-save-signature",
- error->message, NULL);
- g_error_free (error);
-
- /* Only destroy the editor if the save was successful. */
- } else {
- ESourceRegistry *registry;
-
- registry = e_mail_signature_editor_get_registry (editor);
-
- /* Only make sure that the 'source-changed' is called,
- * thus the preview of the signature is updated on save.
- * It is not called when only signature body is changed
- * (and ESource properties are left unchanged). */
- g_signal_emit_by_name (registry, "source-changed", source);
-
- gtk_widget_destroy (GTK_WIDGET (editor));
- }
+ mail_signature_editor_commit_ready_cb, NULL);
}
static GtkActionEntry entries[] = {
@@ -917,6 +927,55 @@ mail_signature_editor_commit_cb (GObject *object,
simple);
}
+static void
+mail_signature_editor_content_hash_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = user_data;
+ EContentEditorContentHash *content_hash;
+ ESourceMailSignature *extension;
+ AsyncContext *async_context;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (source_object));
+
+ content_hash = e_content_editor_get_content_finish (E_CONTENT_EDITOR (source_object), result, &error);
+
+ if (!content_hash) {
+ g_simple_async_result_take_error (simple, error);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ return;
+ }
+
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ async_context->contents = e_content_editor_util_steal_content_data (content_hash,
+ async_context->contents_flag, &async_context->destroy_contents);
+
+ e_content_editor_util_free_content_hash (content_hash);
+
+ if (!async_context->contents) {
+ g_warning ("%s: Failed to retrieve content", G_STRFUNC);
+
+ async_context->contents = g_strdup ("");
+ async_context->destroy_contents = NULL;
+ }
+
+ async_context->length = strlen (async_context->contents);
+
+ extension = e_source_get_extension (async_context->source, E_SOURCE_EXTENSION_MAIL_SIGNATURE);
+ e_source_mail_signature_set_mime_type (extension,
+ async_context->contents_flag == E_CONTENT_EDITOR_GET_RAW_BODY_HTML ? "text/html" :
"text/plain");
+
+ e_source_registry_commit_source (
+ async_context->registry, async_context->source,
+ async_context->cancellable,
+ mail_signature_editor_commit_cb,
+ simple);
+}
+
void
e_mail_signature_editor_commit (EMailSignatureEditor *window,
GCancellable *cancellable,
@@ -925,12 +984,8 @@ e_mail_signature_editor_commit (EMailSignatureEditor *window,
{
GSimpleAsyncResult *simple;
AsyncContext *async_context;
- ESourceMailSignature *extension;
ESourceRegistry *registry;
ESource *source;
- const gchar *extension_name;
- const gchar *mime_type;
- gchar *contents;
EHTMLEditor *editor;
EContentEditor *cnt_editor;
@@ -942,26 +997,10 @@ e_mail_signature_editor_commit (EMailSignatureEditor *window,
editor = e_mail_signature_editor_get_editor (window);
cnt_editor = e_html_editor_get_content_editor (editor);
- mime_type = "text/html";
- contents = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_TEXT_HTML |
- E_CONTENT_EDITOR_GET_BODY,
- NULL, NULL);
-
- if (!contents) {
- g_warning ("%s: Failed to retrieve content", G_STRFUNC);
- contents = g_strdup ("");
- }
-
- extension_name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
- extension = e_source_get_extension (source, extension_name);
- e_source_mail_signature_set_mime_type (extension, mime_type);
-
async_context = g_slice_new0 (AsyncContext);
+ async_context->registry = g_object_ref (registry);
async_context->source = g_object_ref (source);
- async_context->contents = contents; /* takes ownership */
- async_context->length = strlen (contents);
+ async_context->contents_flag = e_content_editor_get_html_mode (cnt_editor) ?
E_CONTENT_EDITOR_GET_RAW_BODY_HTML : E_CONTENT_EDITOR_GET_TO_SEND_PLAIN;
if (G_IS_CANCELLABLE (cancellable))
async_context->cancellable = g_object_ref (cancellable);
@@ -973,11 +1012,8 @@ e_mail_signature_editor_commit (EMailSignatureEditor *window,
g_simple_async_result_set_op_res_gpointer (
simple, async_context, (GDestroyNotify) async_context_free);
- e_source_registry_commit_source (
- registry, source,
- async_context->cancellable,
- mail_signature_editor_commit_cb,
- simple);
+ e_content_editor_get_content (cnt_editor, async_context->contents_flag, NULL,
+ cancellable, mail_signature_editor_content_hash_ready_cb, simple);
}
gboolean
diff --git a/src/e-util/e-misc-utils.c b/src/e-util/e-misc-utils.c
index fc96e4a3e4..d6c9e2ecd5 100644
--- a/src/e-util/e-misc-utils.c
+++ b/src/e-util/e-misc-utils.c
@@ -3691,276 +3691,6 @@ e_util_check_gtk_bindings_in_key_press_event_cb (GtkWidget *widget,
return FALSE;
}
-/**
- * e_util_claim_dbus_proxy_call_error:
- * @dbus_proxy: a #GDBusProxy instance
- * @method_name: a method name of the @dbus_proxy
- * @in_error: (allow-none): a #GError with the failure, or %NULL
- *
- * Claims the @in_error on the console as a failure to call
- * method @method_name of the @dbus_proxy. It's safe to call this
- * with a %NULL @in_error, then the function does nothing.
- * Some errors can be ignored, like the G_IO_ERROR_CANCELLED is.
- *
- * Since: 3.22
- **/
-void
-e_util_claim_dbus_proxy_call_error (GDBusProxy *dbus_proxy,
- const gchar *method_name,
- const GError *in_error)
-{
- g_return_if_fail (G_IS_DBUS_PROXY (dbus_proxy));
- g_return_if_fail (method_name != NULL);
-
- if (in_error &&
- !g_error_matches (in_error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
- !g_error_matches (in_error, G_IO_ERROR, G_IO_ERROR_CLOSED) &&
- !g_error_matches (in_error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED) &&
- !g_error_matches (in_error, G_DBUS_ERROR, G_DBUS_ERROR_DISCONNECTED))
- g_message ("Failed to call a DBus Proxy method %s::%s: %s",
- g_dbus_proxy_get_name (dbus_proxy), method_name, in_error->message);
-}
-
-static void
-e_util_finish_dbus_proxy_call_cb (GObject *source_object,
- GAsyncResult *result,
- gpointer user_data)
-{
- gchar *method_name = user_data;
- GDBusProxy *dbus_proxy;
- GVariant *ret;
- GError *error = NULL;
-
- g_return_if_fail (G_IS_DBUS_PROXY (source_object));
-
- dbus_proxy = G_DBUS_PROXY (source_object);
-
- ret = g_dbus_proxy_call_finish (dbus_proxy, result, &error);
-
- if (ret)
- g_variant_unref (ret);
-
- if (error)
- g_dbus_error_strip_remote_error (error);
-
- e_util_claim_dbus_proxy_call_error (dbus_proxy, method_name, error);
-
- g_clear_error (&error);
- g_free (method_name);
-}
-
-/**
- * e_util_invoke_g_dbus_proxy_call_with_error_check:
- * @dbus_proxy: a #GDBusProxy instance
- * @method_name: a method name to invoke
- * @parameters: (allow-none): parameters of the method, or %NULL
- * @cancellable: (allow-none): a #GCancellable, or %NULL
- *
- * Calls g_dbus_proxy_call() on the @dbus_proxy for the @method_name with @parameters
- * and adds its own callback for the result. Then, if an error is returned, passes this
- * error into e_util_claim_dbus_proxy_call_error().
- *
- * See: e_util_invoke_g_dbus_proxy_call_with_error_check_full()
- *
- * Since: 3.22
- **/
-void
-e_util_invoke_g_dbus_proxy_call_with_error_check (GDBusProxy *dbus_proxy,
- const gchar *method_name,
- GVariant *parameters,
- GCancellable *cancellable)
-{
- g_return_if_fail (G_IS_DBUS_PROXY (dbus_proxy));
- g_return_if_fail (method_name != NULL);
-
- e_util_invoke_g_dbus_proxy_call_with_error_check_full (
- dbus_proxy, method_name, parameters,
- G_DBUS_CALL_FLAGS_NONE, -1, cancellable);
-}
-
-/**
- * e_util_invoke_g_dbus_proxy_call_with_error_check_full:
- * @dbus_proxy: a #GDBusProxy instance
- * @method_name: a method name to invoke
- * @parameters: (allow-none): parameters of the method, or %NULL
- * @flags: a bit-or of #GDBusCallFlags, with the same meaning as in the g_dbus_proxy_call()
- * @timeout_msec: timeout in milliseconds, with the same meaning as in the g_dbus_proxy_call().
- * @cancellable: (allow-none): a #GCancellable, or %NULL
- *
- * Calls g_dbus_proxy_call() on the @dbus_proxy for the @method_name with @parameters
- * and adds its own callback for the result. Then, if an error is returned, passes this
- * error into e_util_claim_dbus_proxy_call_error().
- *
- * See: e_util_invoke_g_dbus_proxy_call_with_error_check()
- *
- * Since: 3.22
- **/
-void
-e_util_invoke_g_dbus_proxy_call_with_error_check_full (GDBusProxy *dbus_proxy,
- const gchar *method_name,
- GVariant *parameters,
- GDBusCallFlags flags,
- gint timeout_msec,
- GCancellable *cancellable)
-{
- g_return_if_fail (G_IS_DBUS_PROXY (dbus_proxy));
- g_return_if_fail (method_name != NULL);
-
- g_dbus_proxy_call (dbus_proxy, method_name, parameters,
- flags, timeout_msec, cancellable,
- e_util_finish_dbus_proxy_call_cb, g_strdup (method_name));
-}
-
-/**
- * e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check:
- * @dbus_proxy: a #GDBusProxy instance
- * @method_name: a method name to invoke
- * @parameters: (allow-none): parameters of the method, or %NULL
- * @cancellable: (allow-none): a #GCancellable, or %NULL
- *
- * Calls e_util_invoke_g_dbus_proxy_call_sync_wrapper_full() with some default
- * values for flags and timeout_msec, while also providing its own GError and
- * after the call is finished it calls e_util_claim_dbus_proxy_call_error()
- * with the returned error, if any.
- *
- * Returns: (transfer full): The result of the method call, or %NULL on error. Free with g_variant_unref().
- *
- * Since: 3.22
- **/
-GVariant *
-e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (GDBusProxy *dbus_proxy,
- const gchar *method_name,
- GVariant *parameters,
- GCancellable *cancellable)
-{
- GVariant *result;
- GError *error = NULL;
-
- g_return_val_if_fail (G_IS_DBUS_PROXY (dbus_proxy), NULL);
- g_return_val_if_fail (method_name != NULL, NULL);
-
- /* Reference the D-Bus proxy, to not have it disappeared under its hands */
- g_object_ref (dbus_proxy);
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_full (dbus_proxy, method_name, parameters,
- G_DBUS_CALL_FLAGS_NONE, -1, cancellable, &error);
-
- if (error)
- g_dbus_error_strip_remote_error (error);
-
- e_util_claim_dbus_proxy_call_error (dbus_proxy, method_name, error);
- g_clear_error (&error);
-
- g_object_unref (dbus_proxy);
-
- return result;
-}
-
-/**
- * e_util_invoke_g_dbus_proxy_call_sync_wrapper:
- * @dbus_proxy: a #GDBusProxy instance
- * @method_name: a method name to invoke
- * @parameters: (allow-none): parameters of the method, or %NULL
- * @cancellable: (allow-none): a #GCancellable, or %NULL
- * @error: (allow-none): Return location for error, or %NULL
- *
- * Wraps GDBusProxy synchronous call into an asynchronous without blocking
- * the main context. This can be useful when doing calls on a WebExtension,
- * because it can avoid freeze when this is called in the UI process and
- * the WebProcess also does its own IPC call.
- *
- * This function should be called only from the main thread.
- *
- * See e_util_invoke_g_dbus_proxy_call_sync_wrapper_full().
- *
- * Returns: (transfer full): The result of the method call, or %NULL on error. Free with g_variant_unref().
- *
- * Since: 3.34
- **/
-GVariant *
-e_util_invoke_g_dbus_proxy_call_sync_wrapper (GDBusProxy *dbus_proxy,
- const gchar *method_name,
- GVariant *parameters,
- GCancellable *cancellable,
- GError **error)
-{
- return e_util_invoke_g_dbus_proxy_call_sync_wrapper_full (dbus_proxy, method_name, parameters,
- G_DBUS_CALL_FLAGS_NONE, -1, cancellable, error);
-}
-
-static void
-sync_wrapper_result_callback (GObject *source_object,
- GAsyncResult *result,
- gpointer user_data)
-{
- GAsyncResult **out_async_result = user_data;
-
- g_return_if_fail (out_async_result != NULL);
- g_return_if_fail (*out_async_result == NULL);
-
- *out_async_result = g_object_ref (result);
-}
-
-/**
- * e_util_invoke_g_dbus_proxy_call_sync_wrapper_full:
- * @dbus_proxy: a #GDBusProxy instance
- * @method_name: a method name to invoke
- * @parameters: (allow-none): parameters of the method, or %NULL
- * @flags: a bit-or of #GDBusCallFlags, with the same meaning as in the g_dbus_proxy_call()
- * @timeout_msec: timeout in milliseconds, with the same meaning as in the g_dbus_proxy_call().
- * @cancellable: (allow-none): a #GCancellable, or %NULL
- * @error: (allow-none): Return location for error, or %NULL
- *
- * Wraps GDBusProxy synchronous call into an asynchronous without blocking
- * the main context. This can be useful when doing calls on a WebExtension,
- * because it can avoid freeze when this is called in the UI process and
- * the WebProcess also does its own IPC call.
- *
- * This function should be called only from the main thread.
- *
- * Returns: (transfer full): The result of the method call, or %NULL on error. Free with g_variant_unref().
- *
- * Since: 3.22
- **/
-GVariant *
-e_util_invoke_g_dbus_proxy_call_sync_wrapper_full (GDBusProxy *dbus_proxy,
- const gchar *method_name,
- GVariant *parameters,
- GDBusCallFlags flags,
- gint timeout_msec,
- GCancellable *cancellable,
- GError **error)
-{
- GAsyncResult *async_result = NULL;
- GVariant *var_result;
- GMainContext *main_context;
-
- g_return_val_if_fail (G_IS_DBUS_PROXY (dbus_proxy), NULL);
- g_return_val_if_fail (method_name != NULL, NULL);
-
- g_warn_if_fail (e_util_is_main_thread (g_thread_self ()));
-
- /* Reference the D-Bus proxy, to not have it disappeared under its hands */
- g_object_ref (dbus_proxy);
-
- g_dbus_proxy_call (
- dbus_proxy, method_name, parameters, flags, timeout_msec, cancellable,
- sync_wrapper_result_callback, &async_result);
-
- main_context = g_main_context_get_thread_default ();
-
- while (!async_result) {
- g_main_context_iteration (main_context, TRUE);
- }
-
- var_result = g_dbus_proxy_call_finish (dbus_proxy, async_result, error);
-
- g_clear_object (&async_result);
- g_object_unref (dbus_proxy);
-
- return var_result;
-}
-
/**
* e_util_save_file_chooser_folder:
* @file_chooser: a #GtkFileChooser
diff --git a/src/e-util/e-misc-utils.h b/src/e-util/e-misc-utils.h
index 27fb594426..5c8848ff0f 100644
--- a/src/e-util/e-misc-utils.h
+++ b/src/e-util/e-misc-utils.h
@@ -303,41 +303,6 @@ gchar * e_util_save_image_from_clipboard
gboolean e_util_check_gtk_bindings_in_key_press_event_cb
(GtkWidget *widget,
GdkEvent *event);
-void e_util_claim_dbus_proxy_call_error
- (GDBusProxy *dbus_proxy,
- const gchar *method_name,
- const GError *in_error);
-void e_util_invoke_g_dbus_proxy_call_with_error_check
- (GDBusProxy *dbus_proxy,
- const gchar *method_name,
- GVariant *parameters,
- GCancellable *cancellable);
-void e_util_invoke_g_dbus_proxy_call_with_error_check_full
- (GDBusProxy *dbus_proxy,
- const gchar *method_name,
- GVariant *parameters,
- GDBusCallFlags flags,
- gint timeout_msec,
- GCancellable *cancellable);
-GVariant * e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check
- (GDBusProxy *dbus_proxy,
- const gchar *method_name,
- GVariant *parameters,
- GCancellable *cancellable);
-GVariant * e_util_invoke_g_dbus_proxy_call_sync_wrapper
- (GDBusProxy *dbus_proxy,
- const gchar *method_name,
- GVariant *parameters,
- GCancellable *cancellable,
- GError **error);
-GVariant * e_util_invoke_g_dbus_proxy_call_sync_wrapper_full
- (GDBusProxy *dbus_proxy,
- const gchar *method_name,
- GVariant *parameters,
- GDBusCallFlags flags,
- gint timeout_msec,
- GCancellable *cancellable,
- GError **error);
void e_util_save_file_chooser_folder (GtkFileChooser *file_chooser);
void e_util_load_file_chooser_folder (GtkFileChooser *file_chooser);
gboolean e_util_get_webkit_developer_mode_enabled
diff --git a/src/e-util/e-spell-checker.c b/src/e-util/e-spell-checker.c
index 3e121de430..5c72859beb 100644
--- a/src/e-util/e-spell-checker.c
+++ b/src/e-util/e-spell-checker.c
@@ -312,7 +312,9 @@ e_spell_checker_list_available_dicts (ESpellChecker *checker)
if (g_hash_table_size (checker->priv->dictionaries_cache) == 0) {
e_spell_checker_init_global_memory ();
+ G_LOCK (global_memory);
g_hash_table_foreach (global_language_tags, copy_enchant_dicts, checker);
+ G_UNLOCK (global_memory);
}
list = g_hash_table_get_values (checker->priv->dictionaries_cache);
@@ -333,7 +335,9 @@ e_spell_checker_count_available_dicts (ESpellChecker *checker)
if (g_hash_table_size (checker->priv->dictionaries_cache) == 0) {
e_spell_checker_init_global_memory ();
+ G_LOCK (global_memory);
g_hash_table_foreach (global_language_tags, copy_enchant_dicts, checker);
+ G_UNLOCK (global_memory);
}
return g_hash_table_size (checker->priv->dictionaries_cache);
diff --git a/src/e-util/e-util-enums.h b/src/e-util/e-util-enums.h
index a951f6b223..8d3fe55a47 100644
--- a/src/e-util/e-util-enums.h
+++ b/src/e-util/e-util-enums.h
@@ -164,22 +164,29 @@ typedef enum {
/**
* EContentEditorGetContentFlags:
- * @E_CONTENT_EDITOR_GET_BODY:
- * @E_CONTENT_EDITOR_GET_INLINE_IMAGES:
- * @E_CONTENT_EDITOR_GET_PROCESSED: raw or processed
- * @E_CONTENT_EDITOR_GET_TEXT_HTML:
- * @E_CONTENT_EDITOR_GET_TEXT_PLAIN:
- * @E_CONTENT_EDITOR_GET_EXCLUDE_SIGNATURE:
- *
- * Since: 3.22
+ * @E_CONTENT_EDITOR_GET_INLINE_IMAGES: Return also list of inline images
+ * @E_CONTENT_EDITOR_GET_RAW_BODY_HTML: text/html version of the body only, as used by the editor
+ * @E_CONTENT_EDITOR_GET_RAW_BODY_PLAIN: text/plain version of the body only, as used by the editor
+ * @E_CONTENT_EDITOR_GET_RAW_BODY_STRIPPED: text/plain version of the body only, without signature, quoted
text and such
+ * @E_CONTENT_EDITOR_GET_RAW_DRAFT: a version of the content, to use as draft message
+ * @E_CONTENT_EDITOR_GET_TO_SEND_HTML: text/html version of the content, suitable to be sent
+ * @E_CONTENT_EDITOR_GET_TO_SEND_PLAIN: text/plain version of the content, suitable to be sent
+ * @E_CONTENT_EDITOR_GET_ALL: a shortcut for all flags
+ *
+ * Influences what content should be returned. Each flag means one
+ * version, or part, of the content.
+ *
+ * Since: 3.38
**/
typedef enum {
- E_CONTENT_EDITOR_GET_BODY = 1 << 0,
- E_CONTENT_EDITOR_GET_INLINE_IMAGES = 1 << 1,
- E_CONTENT_EDITOR_GET_PROCESSED = 1 << 2, /* raw or processed */
- E_CONTENT_EDITOR_GET_TEXT_HTML = 1 << 3,
- E_CONTENT_EDITOR_GET_TEXT_PLAIN = 1 << 4,
- E_CONTENT_EDITOR_GET_EXCLUDE_SIGNATURE = 1 << 5
+ E_CONTENT_EDITOR_GET_INLINE_IMAGES = 1 << 0,
+ E_CONTENT_EDITOR_GET_RAW_BODY_HTML = 1 << 1,
+ E_CONTENT_EDITOR_GET_RAW_BODY_PLAIN = 1 << 2,
+ E_CONTENT_EDITOR_GET_RAW_BODY_STRIPPED = 1 << 3,
+ E_CONTENT_EDITOR_GET_RAW_DRAFT = 1 << 4,
+ E_CONTENT_EDITOR_GET_TO_SEND_HTML = 1 << 5,
+ E_CONTENT_EDITOR_GET_TO_SEND_PLAIN = 1 << 6,
+ E_CONTENT_EDITOR_GET_ALL = ~0
} EContentEditorGetContentFlags;
/**
@@ -206,30 +213,6 @@ typedef enum {
E_CONTENT_EDITOR_NODE_IS_TEXT_COLLAPSED = 1 << 6
} EContentEditorNodeFlags;
-/**
- * EContentEditorStyleFlags:
- * @E_CONTENT_EDITOR_STYLE_NONE: None from the below.
- * @E_CONTENT_EDITOR_STYLE_IS_BOLD:
- * @E_CONTENT_EDITOR_STYLE_IS_ITALIC:
- * @E_CONTENT_EDITOR_STYLE_IS_UNDERLINE:
- * @E_CONTENT_EDITOR_STYLE_IS_STRIKETHROUGH:
- * @E_CONTENT_EDITOR_STYLE_IS_MONOSPACE:
- * @E_CONTENT_EDITOR_STYLE_IS_SUBSCRIPT:
- * @E_CONTENT_EDITOR_STYLE_IS_SUPERSCRIPT:
- *
- * Since: 3.22
- **/
-typedef enum {
- E_CONTENT_EDITOR_STYLE_NONE = 0,
- E_CONTENT_EDITOR_STYLE_IS_BOLD = 1 << 0,
- E_CONTENT_EDITOR_STYLE_IS_ITALIC = 1 << 1,
- E_CONTENT_EDITOR_STYLE_IS_UNDERLINE = 1 << 2,
- E_CONTENT_EDITOR_STYLE_IS_STRIKETHROUGH = 1 << 3,
- E_CONTENT_EDITOR_STYLE_IS_MONOSPACE = 1 << 4,
- E_CONTENT_EDITOR_STYLE_IS_SUBSCRIPT = 1 << 5,
- E_CONTENT_EDITOR_STYLE_IS_SUPERSCRIPT = 1 << 6
-} EContentEditorStyleFlags;
-
/**
* EContentEditorBlockFormat:
* @E_CONTENT_EDITOR_BLOCK_FORMAT_NONE:
@@ -292,16 +275,20 @@ typedef enum {
/**
* EContentEditorAlignment:
+ * @E_CONTENT_EDITOR_ALIGNMENT_NONE:
* @E_CONTENT_EDITOR_ALIGNMENT_LEFT:
* @E_CONTENT_EDITOR_ALIGNMENT_CENTER:
* @E_CONTENT_EDITOR_ALIGNMENT_RIGHT:
+ * @E_CONTENT_EDITOR_ALIGNMENT_JUSTIFY:
*
* Since: 3.22
**/
typedef enum {
+ E_CONTENT_EDITOR_ALIGNMENT_NONE = -1,
E_CONTENT_EDITOR_ALIGNMENT_LEFT = 0,
E_CONTENT_EDITOR_ALIGNMENT_CENTER,
- E_CONTENT_EDITOR_ALIGNMENT_RIGHT
+ E_CONTENT_EDITOR_ALIGNMENT_RIGHT,
+ E_CONTENT_EDITOR_ALIGNMENT_JUSTIFY
} EContentEditorAlignment;
/**
@@ -535,18 +522,20 @@ typedef enum {
} EContentEditorFindFlags;
/**
- * EClipboardFlags:
- * @E_CLIPBOARD_CAN_COPY: It's possible to copy the currently selected content.
+ * EUndoRedoState:
+ * @E_UNDO_REDO_STATE_NONE: Cannot undo, neither redo.
+ * @E_UNDO_REDO_STATE_CAN_UNDO: Undo is available.
+ * @E_UNDO_REDO_STATE_CAN_REDO: Redo is available.
*
- * Specifies clipboard's current state.
+ * Flags in what state Undo/Redo stack is.
*
- * Since: 3.24
+ * Since: 3.38
**/
typedef enum {
- E_CLIPBOARD_CAN_COPY = 1 << 0
- /* E_CLIPBOARD_CAN_CUT = 1 << 1,
- E_CLIPBOARD_CAN_PASTE = 1 << 2 */
-} EClipboardFlags;
+ E_UNDO_REDO_STATE_NONE = 0,
+ E_UNDO_REDO_STATE_CAN_UNDO = 1 << 0,
+ E_UNDO_REDO_STATE_CAN_REDO = 1 << 1
+} EUndoRedoState;
/**
* EDnDTargetType:
diff --git a/src/e-util/e-util.h b/src/e-util/e-util.h
index 4df98d7f6e..fa1243a79e 100644
--- a/src/e-util/e-util.h
+++ b/src/e-util/e-util.h
@@ -263,7 +263,6 @@
#include <e-util/e-util-enums.h>
#include <e-util/e-util-enumtypes.h>
#include <e-util/e-webdav-browser.h>
-#include <e-util/e-web-extension-container.h>
#ifndef E_UTIL_INCLUDE_WITHOUT_WEBKIT
#include <e-util/e-web-view.h>
#include <e-util/e-web-view-jsc-utils.h>
diff --git a/src/e-util/e-web-view.c b/src/e-util/e-web-view.c
index cef66792de..23b125aaee 100644
--- a/src/e-util/e-web-view.c
+++ b/src/e-util/e-web-view.c
@@ -38,7 +38,6 @@
#include "e-popup-action.h"
#include "e-selectable.h"
#include "e-stock-request.h"
-#include "e-web-extension-container.h"
#include "e-web-view-jsc-utils.h"
#include "e-web-view.h"
diff --git a/src/e-util/test-html-editor-units-bugs.c b/src/e-util/test-html-editor-units-bugs.c
index ae6901e20b..7bebfb9276 100644
--- a/src/e-util/test-html-editor-units-bugs.c
+++ b/src/e-util/test-html-editor-units-bugs.c
@@ -22,51 +22,6 @@
#include "test-html-editor-units-bugs.h"
-static void
-test_bug_726548 (TestFixture *fixture)
-{
- /* This test is known to fail, skip it. */
- printf ("SKIPPED ");
-#if 0
- gboolean success;
- gchar *text;
- const gchar *expected_plain =
- "aaa\n"
- " 1. a\n"
- " 2. b\n"
- " 3. c\n";
-
- if (!test_utils_run_simple_test (fixture,
- "mode:plain\n"
- "type:aaa\\n\n"
- "action:style-list-number\n"
- "type:a\\nb\\nc\\n\\n\n"
- "seq:C\n"
- "type:ac\n"
- "seq:c\n",
- HTML_PREFIX "<div style=\"width: 71ch;\">aaa</div>"
- "<ol style=\"width: 65ch;\">"
- "<li>a</li><li>b</li><li>c</li></ol>"
- "<div style=\"width: 71ch;\"><br></div>" HTML_SUFFIX,
- expected_plain)) {
- g_test_fail ();
- return;
- }
-
- text = test_utils_get_clipboard_text (FALSE);
- success = test_utils_html_equal (fixture, text, expected_plain);
-
- if (!success) {
- g_warning ("%s: clipboard Plain text \n---%s---\n does not match expected Plain\n---%s---",
- G_STRFUNC, text, expected_plain);
- g_free (text);
- g_test_fail ();
- } else {
- g_free (text);
- }
-#endif
-}
-
static void
test_bug_750657 (TestFixture *fixture)
{
@@ -77,7 +32,7 @@ test_bug_750657 (TestFixture *fixture)
}
test_utils_insert_content (fixture,
- "<html><head></head><body>\n"
+ "<html><head></head><body>"
"<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">\n"
"<div>This is the first paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>\n"
"<div><br></div>\n"
@@ -88,12 +43,12 @@ test_bug_750657 (TestFixture *fixture)
"</blockquote>\n"
"<div>This is the fourth paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>\n"
"</blockquote>\n"
- "<div><br></div>\n"
+ "<div><br></div>"
"</body></html>",
- E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+ E_CONTENT_EDITOR_INSERT_TEXT_HTML | E_CONTENT_EDITOR_INSERT_REPLACE_ALL);
if (!test_utils_run_simple_test (fixture,
- "seq:uuuSuusD\n",
+ "seq:CecuuuSuusD\n",
HTML_PREFIX
"<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">\n"
"<div>This is the first paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>\n"
@@ -138,7 +93,7 @@ test_bug_760989 (TestFixture *fixture)
"<div>Single line quoted.</div>\n"
"</blockquote>" HTML_SUFFIX,
"One line before quotation\n"
- "> Single line quoted.")) {
+ "> Single line quoted.\n")) {
g_test_fail ();
return;
}
@@ -150,7 +105,7 @@ test_bug_760989 (TestFixture *fixture)
"<div>Single line quoted</div>\n"
"</blockquote>" HTML_SUFFIX,
"One line before quotation\n"
- "> Single line quoted")) {
+ "> Single line quoted\n")) {
g_test_fail ();
return;
}
@@ -166,11 +121,11 @@ test_bug_767903 (TestFixture *fixture)
"type:First item\\n\n"
"type:Second item\n",
HTML_PREFIX "<div style=\"width: 71ch;\">This is the first line:</div>"
- "<ul style=\"width: 68ch;\">"
- "<li>First item</li><li>Second item<br></li></ul>" HTML_SUFFIX,
+ "<ul>"
+ "<li>First item</li><li>Second item</li></ul>" HTML_SUFFIX,
"This is the first line:\n"
" * First item\n"
- " * Second item")) {
+ " * Second item\n")) {
g_test_fail ();
return;
}
@@ -179,11 +134,11 @@ test_bug_767903 (TestFixture *fixture)
"seq:uhb\n"
"undo:undo\n",
HTML_PREFIX "<div style=\"width: 71ch;\">This is the first line:</div>"
- "<ul style=\"width: 68ch;\">"
- "<li>First item</li><li>Second item<br></li></ul>" HTML_SUFFIX,
+ "<ul>"
+ "<li>First item</li><li>Second item</li></ul>" HTML_SUFFIX,
"This is the first line:\n"
" * First item\n"
- " * Second item")) {
+ " * Second item\n")) {
g_test_fail ();
return;
}
@@ -210,12 +165,13 @@ test_bug_769708 (TestFixture *fixture)
if (!test_utils_run_simple_test (fixture,
"",
- HTML_PREFIX "<div>aaa</div><div><span><pre>-- <br></pre>"
- "<div>user <user@no.where></div>"
+ HTML_PREFIX "<div style=\"width: 71ch;\">aaa</div>"
+ "<div class=\"-x-evo-signature-wrapper\" style=\"width: 71ch;\"><span
class=\"-x-evo-signature\" id=\"autogenerated\"><pre>-- <br></pre>"
+ "<div>user <<a href=\"mailto:user@no.where\">user@no.where</a>></div>"
"</span></div>" HTML_SUFFIX,
"aaa\n"
"-- \n"
- "user <user@no.where>"))
+ "user <user@no.where>\n"))
g_test_fail ();
}
@@ -232,7 +188,7 @@ test_bug_769913 (TestFixture *fixture)
"type:ab\n"
"seq:ltlD\n",
HTML_PREFIX "<div>ab</div>" HTML_SUFFIX,
- "ab")) {
+ "ab\n")) {
g_test_fail ();
return;
}
@@ -240,7 +196,7 @@ test_bug_769913 (TestFixture *fixture)
if (!test_utils_run_simple_test (fixture,
"seq:ttllDD\n",
HTML_PREFIX "<div>ab</div>" HTML_SUFFIX,
- "ab")) {
+ "ab\n")) {
g_test_fail ();
return;
}
@@ -248,7 +204,7 @@ test_bug_769913 (TestFixture *fixture)
if (!test_utils_run_simple_test (fixture,
"seq:ttlDlD\n",
HTML_PREFIX "<div>ab</div>" HTML_SUFFIX,
- "ab")) {
+ "ab\n")) {
g_test_fail ();
return;
}
@@ -256,7 +212,7 @@ test_bug_769913 (TestFixture *fixture)
if (!test_utils_run_simple_test (fixture,
"seq:tttlllDDD\n",
HTML_PREFIX "<div>ab</div>" HTML_SUFFIX,
- "ab")) {
+ "ab\n")) {
g_test_fail ();
return;
}
@@ -264,7 +220,7 @@ test_bug_769913 (TestFixture *fixture)
if (!test_utils_run_simple_test (fixture,
"seq:tttlDlDlD\n",
HTML_PREFIX "<div>ab</div>" HTML_SUFFIX,
- "ab")) {
+ "ab\n")) {
g_test_fail ();
return;
}
@@ -272,7 +228,7 @@ test_bug_769913 (TestFixture *fixture)
if (!test_utils_run_simple_test (fixture,
"seq:tb\n",
HTML_PREFIX "<div>ab</div>" HTML_SUFFIX,
- "ab")) {
+ "ab\n")) {
g_test_fail ();
return;
}
@@ -280,7 +236,7 @@ test_bug_769913 (TestFixture *fixture)
if (!test_utils_run_simple_test (fixture,
"seq:ttbb\n",
HTML_PREFIX "<div>ab</div>" HTML_SUFFIX,
- "ab")) {
+ "ab\n")) {
g_test_fail ();
return;
}
@@ -288,7 +244,7 @@ test_bug_769913 (TestFixture *fixture)
if (!test_utils_run_simple_test (fixture,
"seq:ttlbrb\n",
HTML_PREFIX "<div>ab</div>" HTML_SUFFIX,
- "ab")) {
+ "ab\n")) {
g_test_fail ();
return;
}
@@ -296,7 +252,7 @@ test_bug_769913 (TestFixture *fixture)
if (!test_utils_run_simple_test (fixture,
"seq:tttbbb\n",
HTML_PREFIX "<div>ab</div>" HTML_SUFFIX,
- "ab")) {
+ "ab\n")) {
g_test_fail ();
return;
}
@@ -304,7 +260,7 @@ test_bug_769913 (TestFixture *fixture)
if (!test_utils_run_simple_test (fixture,
"seq:tttllbrbrb\n",
HTML_PREFIX "<div>ab</div>" HTML_SUFFIX,
- "ab")) {
+ "ab\n")) {
g_test_fail ();
return;
}
@@ -326,7 +282,7 @@ test_bug_769955 (TestFixture *fixture)
"<a
href=\"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines\">"
"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines</a></pre>"
HTML_SUFFIX,
-
"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) {
+
"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines\n")) {
g_test_fail ();
return;
}
@@ -342,7 +298,7 @@ test_bug_769955 (TestFixture *fixture)
HTML_PREFIX "<pre>"
"[1] <a
href=\"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines\">"
"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines</a></pre>"
HTML_SUFFIX,
- "[1]
http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) {
+ "[1]
http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines\n")) {
g_test_fail ();
return;
}
@@ -359,7 +315,7 @@ test_bug_769955 (TestFixture *fixture)
HTML_PREFIX "<pre>"
"[2] <a
href=\"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines\">"
"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines</a></pre>"
HTML_SUFFIX,
- "[2]
http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) {
+ "[2]
http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines\n")) {
g_test_fail ();
return;
}
@@ -376,7 +332,7 @@ test_bug_769955 (TestFixture *fixture)
HTML_PREFIX "<pre>"
"[3] <a
href=\"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines\">"
"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines</a></pre>"
HTML_SUFFIX,
- "[3]
http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) {
+ "[3]
http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines\n")) {
g_test_fail ();
return;
}
@@ -393,7 +349,7 @@ test_bug_769955 (TestFixture *fixture)
HTML_PREFIX "<pre>"
"[4] <a
href=\"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines\">"
"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines</a></pre>"
HTML_SUFFIX,
- "[4]
http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) {
+ "[4]
http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines\n")) {
g_test_fail ();
return;
}
@@ -412,7 +368,7 @@ test_bug_769955 (TestFixture *fixture)
"<a
href=\"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines\">"
"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines</a></pre>"
HTML_SUFFIX,
-
"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) {
+
"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines\n")) {
g_test_fail ();
return;
}
@@ -428,7 +384,7 @@ test_bug_769955 (TestFixture *fixture)
HTML_PREFIX "<pre>"
"[5] <a
href=\"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines\">"
"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines</a></pre>"
HTML_SUFFIX,
- "[5]
http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) {
+ "[5]
http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines\n")) {
g_test_fail ();
return;
}
@@ -445,7 +401,7 @@ test_bug_769955 (TestFixture *fixture)
HTML_PREFIX "<pre>"
"[6] <a
href=\"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines\">"
"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines</a></pre>"
HTML_SUFFIX,
- "[6]
http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) {
+ "[6]
http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines\n")) {
g_test_fail ();
return;
}
@@ -462,7 +418,7 @@ test_bug_769955 (TestFixture *fixture)
HTML_PREFIX "<pre>"
"[7] <a
href=\"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines\">"
"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines</a></pre>"
HTML_SUFFIX,
- "[7]
http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) {
+ "[7]
http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines\n")) {
g_test_fail ();
return;
}
@@ -479,7 +435,7 @@ test_bug_769955 (TestFixture *fixture)
HTML_PREFIX "<pre>"
"[8] <a
href=\"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines\">"
"http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines</a></pre>"
HTML_SUFFIX,
- "[8]
http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines")) {
+ "[8]
http://www.example.com/this-is-a-very-long-link-which-should-not-be-wrapped-into-multiple-lines\n")) {
g_test_fail ();
return;
}
@@ -503,15 +459,15 @@ test_bug_770073 (TestFixture *fixture)
E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
if (!test_utils_run_simple_test (fixture,
- "seq:Chcddbb\n",
+ "seq:Chcddb\n",
HTML_PREFIX "<div style=\"width: 71ch;\">On Today, User wrote:</div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div style=\"width: 71ch;\">> the 1st line text</div>"
- "<div style=\"width: 71ch;\">> the 3rd line text</div>"
+ "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "the 1st line text</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "the 3rd line text</div>"
"</blockquote>" HTML_SUFFIX,
"On Today, User wrote:\n"
"> the 1st line text\n"
- "> the 3rd line text")) {
+ "> the 3rd line text\n")) {
g_test_fail ();
return;
}
@@ -531,7 +487,7 @@ test_bug_770073 (TestFixture *fixture)
E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
if (!test_utils_run_simple_test (fixture,
- "seq:Chcddbb\n",
+ "seq:Chcddb\n",
HTML_PREFIX "<div>On Today, User wrote:</div>"
"<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
"<div><span>the first line text</span></div>"
@@ -539,7 +495,7 @@ test_bug_770073 (TestFixture *fixture)
"</blockquote>" HTML_SUFFIX,
"On Today, User wrote:\n"
"> the first line text\n"
- "> the third line text"))
+ "> the third line text\n"))
g_test_fail ();
}
@@ -562,17 +518,17 @@ test_bug_770074 (TestFixture *fixture)
E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
if (!test_utils_run_simple_test (fixture,
- "seq:Chcddbb\n"
+ "seq:Chcddb\n"
"seq:n\n"
"undo:undo\n",
HTML_PREFIX "<div style=\"width: 71ch;\">On Today, User wrote:</div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div style=\"width: 71ch;\">> the 1st line text</div>"
- "<div style=\"width: 71ch;\">> the 3rd line text</div>"
+ "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "the 1st line text</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "the 3rd line text</div>"
"</blockquote>" HTML_SUFFIX,
"On Today, User wrote:\n"
"> the 1st line text\n"
- "> the 3rd line text"))
+ "> the 3rd line text\n"))
g_test_fail ();
}
@@ -586,13 +542,15 @@ test_bug_771044 (TestFixture *fixture)
"<div>789 abc</div>"
"<div><br></div>"
HTML_SUFFIX,
- "789 abc\n"))
+ "789 abc\n\n"))
g_test_fail ();
}
static void
test_bug_771131 (TestFixture *fixture)
{
+ test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail",
"composer-wrap-quoted-text-in-replies", TRUE);
+
if (!test_utils_process_commands (fixture,
"mode:plain\n")) {
g_test_fail ();
@@ -601,7 +559,7 @@ test_bug_771131 (TestFixture *fixture)
test_utils_insert_content (fixture,
"<body><pre>On <date1>, <name1> wrote:\n"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">\n"
+ "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
"Hello\n"
"\n"
"Goodbye</blockquote>"
@@ -612,16 +570,49 @@ test_bug_771131 (TestFixture *fixture)
if (!test_utils_run_simple_test (fixture,
"",
- HTML_PREFIX "<div style=\"width: 71ch;\">On Sat, 2016-09-10 at 20:00 +0000, example example
com wrote:</div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div style=\"width: 71ch;\">> On <date1>, <name1> wrote:</div>"
+ HTML_PREFIX "<div style=\"width: 71ch;\">On Sat, 2016-09-10 at 20:00 +0000, <a
href=\"mailto:example example com\">example example com</a> wrote:</div>"
+ "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "On <date1>, <name1> wrote:</div>"
+ "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR QUOTE_CHR) "Hello</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR QUOTE_CHR) "<br></div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR QUOTE_CHR) "Goodbye</div>"
+ "</blockquote>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "the 3rd line text</div>"
+ "</blockquote>"
+ HTML_SUFFIX,
+ "On Sat, 2016-09-10 at 20:00 +0000, example example com wrote:\n"
+ "> On <date1>, <name1> wrote:\n"
+ "> > Hello\n"
+ "> > \n"
+ "> > Goodbye\n"
+ "> the 3rd line text\n"))
+ g_test_fail ();
+
+ test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail",
"composer-wrap-quoted-text-in-replies", FALSE);
+
+ test_utils_insert_content (fixture,
+ "<body><pre>On <date1>, <name1> wrote:\n"
"<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div style=\"width: 71ch;\">> > Hello</div>"
- "<div style=\"width: 71ch;\">> > <br></div>"
- "<div style=\"width: 71ch;\">> > Goodbye</div>"
+ "Hello\n"
+ "\n"
+ "Goodbye</blockquote>"
+ "<div><span>the 3rd line text</span></div>"
+ "</pre><span class=\"-x-evo-to-body\" data-credits=\"On Sat, 2016-09-10 at 20:00 +0000,
example example com wrote:\"></span>"
+ "<span class=\"-x-evo-cite-body\"></span></body>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "",
+ HTML_PREFIX "<div style=\"width: 71ch;\">On Sat, 2016-09-10 at 20:00 +0000, <a
href=\"mailto:example example com\">example example com</a> wrote:</div>"
+ "<blockquote type=\"cite\">"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "On <date1>, <name1> wrote:</pre>"
+ "<blockquote type=\"cite\">"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR QUOTE_CHR) "Hello</pre>"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR QUOTE_CHR) "<br></pre>"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR QUOTE_CHR) "Goodbye</pre>"
"</blockquote>"
- "<div style=\"width: 71ch;\">> <br></div>"
- "<div style=\"width: 71ch;\">> the 3rd line text</div>"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "the 3rd line text</pre>"
"</blockquote>"
HTML_SUFFIX,
"On Sat, 2016-09-10 at 20:00 +0000, example example com wrote:\n"
@@ -629,8 +620,7 @@ test_bug_771131 (TestFixture *fixture)
"> > Hello\n"
"> > \n"
"> > Goodbye\n"
- "> \n"
- "> the 3rd line text"))
+ "> the 3rd line text\n"))
g_test_fail ();
}
@@ -646,7 +636,7 @@ test_bug_771493 (TestFixture *fixture)
test_utils_insert_content (fixture,
"<body><pre><br>"
"----- Original Message -----\n"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">\n"
+ "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
"This week summary:"
"</blockquote>"
"</pre><span class=\"-x-evo-to-body\" data-credits=\"On Thu, 2016-09-15 at 08:08 -0400, user
wrote:\"></span>"
@@ -656,18 +646,18 @@ test_bug_771493 (TestFixture *fixture)
if (!test_utils_run_simple_test (fixture,
"",
HTML_PREFIX "<div style=\"width: 71ch;\">On Thu, 2016-09-15 at 08:08 -0400, user wrote:</div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div style=\"width: 71ch;\">> <br></div>"
- "<div style=\"width: 71ch;\">> ----- Original Message -----</div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div style=\"width: 71ch;\">> > This week summary:</div>"
+ "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<br></div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "----- Original Message -----</div>"
+ "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR QUOTE_CHR) "This week summary:</div>"
"</blockquote>"
"</blockquote>"
HTML_SUFFIX,
"On Thu, 2016-09-15 at 08:08 -0400, user wrote:\n"
"> \n"
"> ----- Original Message -----\n"
- "> > This week summary:"))
+ "> > This week summary:\n"))
g_test_fail ();
}
@@ -689,16 +679,16 @@ test_bug_772171 (TestFixture *fixture)
E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
if (!test_utils_run_simple_test (fixture,
- "seq:ddeb",
+ "seq:deb",
HTML_PREFIX "<div style=\"width: 71ch;\">On Thu, 2016-09-15 at 08:08 -0400, user wrote:</div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div style=\"width: 71ch;\">> <br></div>"
- "<div style=\"width: 71ch;\">> b</div>"
+ "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<br></div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "b</div>"
"</blockquote>"
HTML_SUFFIX,
"On Thu, 2016-09-15 at 08:08 -0400, user wrote:\n"
"> \n"
- "> b"))
+ "> b\n"))
g_test_fail ();
}
@@ -729,7 +719,8 @@ test_bug_772513 (TestFixture *fixture)
if (!test_utils_run_simple_test (fixture,
"",
- HTML_PREFIX "<div style=\"width: 71ch;\"><br></div>" HTML_SUFFIX,
+ HTML_PREFIX "<div style=\"width: 71ch;\"><br></div>"
+ "<div class=\"-x-evo-signature-wrapper\" style=\"width: 71ch;\"><span
class=\"-x-evo-signature\" id=\"none\"></span></div>" HTML_SUFFIX,
"\n"))
g_test_fail ();
}
@@ -745,7 +736,7 @@ test_bug_772918 (TestFixture *fixture)
"undo:undo:6\n"
"undo:redo:6\n",
HTML_PREFIX "<div>a b 1 2 3 c d</div>" HTML_SUFFIX,
- "a b 1 2 3 c d"))
+ "a b 1 2 3 c d\n"))
g_test_fail ();
}
@@ -761,31 +752,35 @@ test_bug_773164 (TestFixture *fixture)
"undo:undo\n"
"undo:test\n"
"undo:redo\n"
- "seq:huuuue\n" /* Go to the end of the first line */
- "seq:Sdds\n"
+ "seq:huuue\n" /* Go to the end of the second line */
+ "seq:Sddes\n"
"action:cut\n"
"seq:dde\n" /* Go to the end of the last line */
"action:paste\n"
- "undo:undo:5\n"
+ "undo:undo:3\n"
"undo:test\n"
- "undo:redo:5\n",
+ "undo:redo:3\n",
HTML_PREFIX "<div style=\"width: 71ch;\">This is paragraph 1</div>"
"<div style=\"width: 71ch;\"><br></div>"
"<div style=\"width: 71ch;\">This is a longer paragraph 3</div>"
"<div style=\"width: 71ch;\"><br></div>"
"<div style=\"width: 71ch;\">This is paragraph 2</div>"
+ "<div style=\"width: 71ch;\"><br></div>"
HTML_SUFFIX,
"This is paragraph 1\n"
"\n"
"This is a longer paragraph 3\n"
"\n"
- "This is paragraph 2"))
+ "This is paragraph 2\n"
+ "\n"))
g_test_fail ();
}
static void
test_bug_775042 (TestFixture *fixture)
{
+ test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail",
"composer-wrap-quoted-text-in-replies", FALSE);
+
test_utils_insert_content (fixture,
"<body><pre>a\n"
"b\n"
@@ -798,17 +793,69 @@ test_bug_775042 (TestFixture *fixture)
"seq:rl\n"
"mode:plain\n",
HTML_PREFIX "<div style=\"width: 71ch;\">On Fri, 2016-11-25 at 08:18 +0000, user wrote:</div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<pre>> a</pre>"
- "<pre>> b</pre>"
- "<pre>> c</pre>"
+ "<blockquote type=\"cite\">"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "a</pre>"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "b</pre>"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "c</pre>"
+ "</blockquote>"
+ HTML_SUFFIX,
+ "On Fri, 2016-11-25 at 08:18 +0000, user wrote:\n"
+ "> a\n"
+ "> b\n"
+ "> c\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<body><pre>a\n"
+ "b\n"
+ "c"
+ "<span class=\"-x-evo-to-body\" data-credits=\"On Fri, 2016-11-25 at 08:18 +0000, user
wrote:\"></span>"
+ "<span class=\"-x-evo-cite-body\"></span></body>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "seq:rl\n",
+ HTML_PREFIX "<div style=\"width: 71ch;\">On Fri, 2016-11-25 at 08:18 +0000, user wrote:</div>"
+ "<blockquote type=\"cite\">"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "a</pre>"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "b</pre>"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "c</pre>"
+ "</blockquote>"
+ HTML_SUFFIX,
+ "On Fri, 2016-11-25 at 08:18 +0000, user wrote:\n"
+ "> a\n"
+ "> b\n"
+ "> c\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<body><div>a</div>"
+ "<p>b</p>"
+ "<div>c</div>"
+ "<span class=\"-x-evo-to-body\" data-credits=\"On Fri, 2016-11-25 at 08:18 +0000, user
wrote:\"></span>"
+ "<span class=\"-x-evo-cite-body\"></span></body>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "seq:rl\n",
+ HTML_PREFIX "<div style=\"width: 71ch;\">On Fri, 2016-11-25 at 08:18 +0000, user wrote:</div>"
+ "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "a</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "b</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "c</div>"
"</blockquote>"
HTML_SUFFIX,
"On Fri, 2016-11-25 at 08:18 +0000, user wrote:\n"
"> a\n"
"> b\n"
- "> c"))
+ "> c\n")) {
g_test_fail ();
+ return;
+ }
}
static void
@@ -825,7 +872,7 @@ test_bug_775691 (TestFixture *fixture)
"<div style=\"width: 71ch;\">def</div>"
HTML_SUFFIX,
"abc def ghi\n"
- "def"))
+ "def\n"))
g_test_fail ();
}
@@ -850,20 +897,53 @@ test_bug_779707 (TestFixture *fixture)
E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
if (!test_utils_run_simple_test (fixture,
- "seq:uuuSesDbnnu\n"
+ "seq:ChcddhSesDbnn\n"
"type:a very long text, which splits into multiple lines when this paragraph is not marked as
preformatted, but as normal, as it should be\n"
- "",
+ "seq:n\n",
HTML_PREFIX "<div style=\"width: 71ch;\">Credits:</div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<pre>> line 1</pre>"
+ "<blockquote type=\"cite\">"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "line 1</pre>"
"</blockquote>"
"<div style=\"width: 71ch;\"><br></div>"
"<div style=\"width: 71ch;\">a very long text, which splits into multiple lines when this
paragraph is not marked as preformatted, but as normal, as it should be</div>"
"<div style=\"width: 71ch;\"><br></div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<pre>> line 3</pre>"
+ "<blockquote type=\"cite\">"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "line 3</pre>"
+ "</blockquote>"
+ HTML_SUFFIX,
+ "Credits:\n"
+ "> line 1\n"
+ "\n"
+ "a very long text, which splits into multiple lines when this paragraph\n"
+ "is not marked as preformatted, but as normal, as it should be\n"
+ "\n"
+ "> line 3\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<div>line 1</div>"
+ "<div>line 2</div>"
+ "<div>line 3</div>"
+ "<span class=\"-x-evo-to-body\" data-credits=\"Credits:\"></span>"
+ "<span class=\"-x-evo-cite-body\"></span>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "seq:ChcddhSesDbnn\n"
+ "type:a very long text, which splits into multiple lines when this paragraph is not marked as
preformatted, but as normal, as it should be\n"
+ "seq:n\n",
+ HTML_PREFIX "<div style=\"width: 71ch;\">Credits:</div>"
+ "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "line 1</div>"
"</blockquote>"
"<div style=\"width: 71ch;\"><br></div>"
+ "<div style=\"width: 71ch;\">a very long text, which splits into multiple lines when this
paragraph is not marked as preformatted, but as normal, as it should be</div>"
+ "<div style=\"width: 71ch;\"><br></div>"
+ "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "line 3</div>"
+ "</blockquote>"
HTML_SUFFIX,
"Credits:\n"
"> line 1\n"
@@ -898,8 +978,7 @@ test_bug_780275_html (TestFixture *fixture)
"seq:hSuusD\n"
"undo:undo\n"
"undo:test:1\n"
- "undo:redo\n"
- "",
+ "undo:redo\n",
HTML_PREFIX "<div>line 0</div>"
"<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
"<div>Xline 1</div>"
@@ -910,7 +989,7 @@ test_bug_780275_html (TestFixture *fixture)
"line 0\n"
"> Xline 1\n"
"> line 2\n"
- "line 4"))
+ "line 4\n"))
g_test_fail ();
}
@@ -939,16 +1018,16 @@ test_bug_780275_plain (TestFixture *fixture)
"undo:test:1\n"
"undo:redo\n",
HTML_PREFIX "<div style=\"width: 71ch;\">line 0</div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div style=\"width: 71ch;\">> Xline 1</div>"
- "<div style=\"width: 71ch;\">> line 2</div>"
+ "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "Xline 1</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "line 2</div>"
"</blockquote>"
"<div style=\"width: 71ch;\">line 4</div>"
HTML_SUFFIX,
"line 0\n"
"> Xline 1\n"
"> line 2\n"
- "line 4"))
+ "line 4\n"))
g_test_fail ();
}
@@ -971,12 +1050,12 @@ test_bug_781722 (TestFixture *fixture)
"seq:dd\n"
"action:style-preformat\n",
HTML_PREFIX "<div style=\"width: 71ch;\">Credits:</div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<pre>> Signed-off-by: User <<a
href=\"mailto:user@no.where\">user@no.where</a>></pre>"
+ "<blockquote type=\"cite\">"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "Signed-off-by: User <<a
href=\"mailto:user@no.where\">user@no.where</a>></pre>"
"</blockquote>"
HTML_SUFFIX,
"Credits:\n"
- "> Signed-off-by: User <user@no.where>"))
+ "> Signed-off-by: User <user@no.where>\n"))
g_test_fail ();
}
@@ -993,7 +1072,7 @@ test_bug_781116 (TestFixture *fixture)
test_utils_insert_content (fixture,
"<pre>a very long text, which splits into multiple lines when this paragraph is not marked as
preformatted, but as normal, as it should be</pre>\n"
- "</pre><span class=\"-x-evo-to-body\" data-credits=\"Credits:\"></span>"
+ "<span class=\"-x-evo-to-body\" data-credits=\"Credits:\"></span>"
"<span class=\"-x-evo-cite-body\"></span>",
E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
@@ -1001,16 +1080,67 @@ test_bug_781116 (TestFixture *fixture)
"seq:dd\n"
"action:wrap-lines\n",
HTML_PREFIX "<div style=\"width: 71ch;\">Credits:</div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<pre>> a very long text, which splits into multiple lines when this<br>"
- "> paragraph is not marked as preformatted, but as normal, as it should<br>"
- "> be</pre>"
+ "<blockquote type=\"cite\">"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "a very long text, which splits into multiple lines when
this<br>"
+ QUOTE_SPAN (QUOTE_CHR) "paragraph is not marked as preformatted, but as normal, as it
should<br>"
+ QUOTE_SPAN (QUOTE_CHR) "be</pre>"
+ "</blockquote>"
+ HTML_SUFFIX,
+ "Credits:\n"
+ "> a very long text, which splits into multiple lines when this\n"
+ "> paragraph is not marked as preformatted, but as normal, as it should\n"
+ "> be\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<blockquote type=\"cite\"><div>a very long text, which splits into multiple lines when this
paragraph is not marked as preformatted, but as normal, as it should be</div></blockquote>"
+ "<span class=\"-x-evo-to-body\" data-credits=\"Credits:\"></span>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "seq:dd\n"
+ "action:wrap-lines\n",
+ HTML_PREFIX "<div style=\"width: 71ch;\">Credits:</div>"
+ "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "a very long text, which splits into multiple lines when
this<br>"
+ QUOTE_SPAN (QUOTE_CHR) "paragraph is not marked as preformatted, but as normal, as it
should<br>"
+ QUOTE_SPAN (QUOTE_CHR) "be</div>"
"</blockquote>"
HTML_SUFFIX,
"Credits:\n"
"> a very long text, which splits into multiple lines when this\n"
"> paragraph is not marked as preformatted, but as normal, as it should\n"
- "> be</pre>"))
+ "> be\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_process_commands (fixture,
+ "mode:html\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<blockquote type=\"cite\"><div>a very long text, which splits into multiple lines when this
paragraph is not marked as preformatted, but as normal, as it should be</div></blockquote>"
+ "<span class=\"-x-evo-to-body\" data-credits=\"Credits:\"></span>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "seq:dd\n"
+ "action:wrap-lines\n",
+ HTML_PREFIX "<div>Credits:</div>"
+ "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<div>a very long text, which splits into multiple lines when this paragraph<br>"
+ "is not marked as preformatted, but as normal, as it should be</div>"
+ "</blockquote>"
+ HTML_SUFFIX,
+ "Credits:\n"
+ "> a very long text, which splits into multiple lines when this\n"
+ "> paragraph\n"
+ "> is not marked as preformatted, but as normal, as it should be\n"))
g_test_fail ();
}
@@ -1023,7 +1153,9 @@ test_bug_780088 (TestFixture *fixture)
return;
}
- test_utils_set_clipboard_text ("Seeing @blah instead of @foo XX'ed on" UNICODE_NBSP
"https://example.sub" UNICODE_NBSP "domain.org/page I'd recommend to XX YY
<https://example.subdomain.org/p/user/> , click fjwvne on the left, click skjd sjewncj on the right, and set
wqje wjfdn Xs to something like wqjfnm www.example.com/~user wjfdncj or such.", FALSE);
+ test_utils_set_clipboard_text ("Seeing @blah instead of @foo XX'ed on" UNICODE_NBSP
"https://example.sub" UNICODE_NBSP "domain.org/page I'd"
+ " recommend to XX YY <https://example.subdomain.org/p/user/> , click fjwvne on the left,
click skjd sjewncj on the right, and set"
+ " wqje wjfdn Xs to something like wqjfnm www.example.com/~user wjfdncj or such.", FALSE);
if (!test_utils_run_simple_test (fixture,
"action:paste\n"
@@ -1033,14 +1165,14 @@ test_bug_780088 (TestFixture *fixture)
" domain.org/page I'd recommend to XX YY "
"<<a
href=\"https://example.subdomain.org/p/user/\">https://example.subdomain.org/p/user/</a>> , "
"click fjwvne on the left, click skjd sjewncj on the right, and set wqje wjfdn Xs to
something like "
- "wqjfnm <a href=\"www.example.com/~user\">www.example.com/~user</a> wjfdncj or such.</div>"
- "</div><div style=\"width: 71ch;\"><br></div>"
+ "wqjfnm <a href=\"https://www.example.com/~user\">www.example.com/~user</a> wjfdncj or
such.</div>"
+ "<div style=\"width: 71ch;\"><br></div>"
HTML_SUFFIX,
- "Seeing @blah instead of @foo XX'ed on" UNICODE_NBSP "https://example.sub" UNICODE_NBSP
"domain.org/pa\n"
- "ge I'd recommend to XX YY <https://example.subdomain.org/p/user/> ,\n"
- "click fjwvne on the left, click skjd sjewncj on the right, and set wqje\n"
- "wjfdn Xs to something like wqjfnm www.example.com/~user wjfdncj or\n"
- "such.\n"))
+ "Seeing @blah instead of @foo XX'ed\n"
+ "on" UNICODE_NBSP "https://example.sub" UNICODE_NBSP "domain.org/page I'd recommend to XX
YY\n"
+ "<https://example.subdomain.org/p/user/> , click fjwvne on the left,\n"
+ "click skjd sjewncj on the right, and set wqje wjfdn Xs to something\n"
+ "like wqjfnm www.example.com/~user wjfdncj or such.\n\n"))
g_test_fail ();
}
@@ -1085,37 +1217,41 @@ test_bug_788829 (TestFixture *fixture)
if (!test_utils_run_simple_test (fixture,
"",
- HTML_PREFIX "<div style=\"width: 71ch;\">On Today, User wrote:</div><blockquote type=\"cite\"
" BLOCKQUOTE_STYLE ">"
- "<div style=\"width: 71ch;\">> Xxxxx xx xxxxxxxxx xx xxxxxxx xx xxxxx xxxx "
- "xxxx xx xxx xxx xxxx xxx<br>> xxxçx xôxé \"xxxxx xxxx xxxxxxx xxx\" xx xxxx "
- "xxxxé xxx xxx xxxéx xxx<br>> x'x xéxxxxé x'xxxxxxxxx xx xxx \"Xxxx XXX Xxxxx"
- "x Xxx\". Xx xxxx<br>> xxxxxxxx xxx xxxxxxxxxxxxxxxx.xx (xxxxxxx xxxxxxxxxx "
- "xx .xxx). Xxxx<br>> êxxx xxx xxxxxxxxxxx xxxéxxxxxxxx, xxxx xxxxx xx XXX xx "
- "xéxxx à xx<br>> xxx \"xxx xxxxxx xxxx xx xxxxxxx\" xx xxxx xx xxxxx xxxxxxxx "
- "xxxxxxxx<br>> xx $ xx xxxx x'xxxxxx.</div><div style=\"width: 71ch;\">"
- "> <br></div><div style=\"width: 71ch;\">> Xxxx xx xéxxxxxxx, xxxxxxxx xxxxxxx "
- "(!), xxxxxxx à xxx, xxxx ooo$ XXX<br>> xxxxé: <br>> <a href=\"https://xxxxx"
- "xxxxxxxxxxx.xx/xxxxxxx/xxxxx-xxxx-xxxxxxxx-xxxxx-xxxx-xxx-xxxxxxxx-xxx/\">https://"
- "xxxxxxxxxxxxxxxx.xx/xxxxxxx/xxxxx-xxxx-xxxxxxxx-xxxxx-xxxx-xxx-xxxxxxxx-xxx/</a><br>"
- "> xx xx xxxx xéxéxxxxxxx x'xxxxxx xxxx xx xxxxxx xx xxxxxxxxxxxx xx xxx<br>> ("
- "xxxxx Xxxxxx) xxxx xxxx x'xxxxxxx xx xxxxxx: <br>> <a href=\"https://xxxxxxxxxxxxxx"
- "xx.xxx/xx-xxxxxxx/xxxxxxx/Xxxxxxxxxxxx-Xxxxx-Xxxx-XXX-Xxxxxx-Xxx.xxx\">https://xxxxxx"
+ HTML_PREFIX "<div style=\"width: 71ch;\">On Today, User wrote:</div><blockquote
type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "Xxxxx xx xxxxxxxxx xx xxxxxxx xx xxxxx xxxx xxxx xx xxx xxx
xxxx xxx<br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "xxxçx xôxé \"xxxxx xxxx xxxxxxx xxx\" xx xxxx xxxxé xxx xxx xxxéx
xxx<br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "x'x xéxxxxé x'xxxxxxxxx xx xxx \"Xxxx XXX Xxxxxx Xxx\". Xx xxxx<br
class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "xxxxxxxx xxx xxxxxxxxxxxxxxxx.xx (xxxxxxx xxxxxxxxxx xx .xxx).
Xxxx<br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "êxxx xxx xxxxxxxxxxx xxxéxxxxxxxx, xxxx xxxxx xx XXX xx xéxxx à xx<br
class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "xxx \"xxx xxxxxx xxxx xx xxxxxxx\" xx xxxx xx xxxxx xxxxxxxx
xxxxxxxx<br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "xx $ xx xxxx x'xxxxxx.</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<br></div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "Xxxx xx xéxxxxxxx, xxxxxxxx xxxxxxx (!), xxxxxxx à xxx, xxxx
ooo$ XXX<br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "xxxxé:<br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "<a
href=\"https://xxxxxxxxxxxxxxxx.xx/xxxxxxx/xxxxx-xxxx-xxxxxxxx-xxxxx-xxxx-xxx-xxxxxxxx-xxx/\">https://"
+ "xxxxxxxxxxxxxxxx.xx/xxxxxxx/xxxxx-xxxx-xxxxxxxx-xxxxx-xxxx-xxx-xxxxxxxx-xxx/</a><br
class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "xx xx xxxx xéxéxxxxxxx x'xxxxxx xxxx xx xxxxxx xx xxxxxxxxxxxx xx
xxx<br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "(xxxxx Xxxxxx) xxxx xxxx x'xxxxxxx xx xxxxxx:<br
class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "<a
href=\"https://xxxxxxxxxxxxxxxx.xxx/xx-xxxxxxx/xxxxxxx/Xxxxxxxxxxxx-Xxxxx-Xxxx-XXX-Xxxxxx-Xxx.xxx\">https://xxxxxx"
"xxxxxxxxxx.xxx/xx-xxxxxxx/xxxxxxx/Xxxxxxxxxxxx-Xxxxx-Xxxx-XXX-Xxxxxx-Xxx.xxx</a></div>"
- "<div style=\"width: 71ch;\">> <br></div><div style=\"width: 71ch;\">> Xxxx xxx x"
- "xx xxxxxxx xxxxxxxéxx x'xxxêxxxx à xxxxx, xxx xx xxxxé xx<br>> oooxooo xxxxx xxxxx "
- "xxxx... xxxx x'xxx xxxxxxxxxxxx xxxxx xxx<br>> xxxxxxxx xx \"xx xxxxx xxx xxx xxxxx"
- "xx xxxxxxx xxxxxxxxxxxxxx xxxx<br>> xxxxx xxxxxx xx xx xxxx xx x'xxxxxx\". Xx xxxx-"
- "êxxx xxx xx xxxxxxxx xx<br>> xxxx \"x'xxxêxx à xxxxx xx oooxooo xxxx xxx xéxxxxxxxx, "
- "xxxx\"...</div><div style=\"width: 71ch;\">> <br></div><div style=\"width: 71ch;\">"
- "> Xxxxx xxxxxx'xx xxx x xxxx xxxxxxx xxxxx xx xxèx xxxxxxxxx<br>> <br>> xxxxxx"
- "xxxxxxxxxx à xx xxx x'xx xx xêxx (éxxxxxxxxx xxxx-xx-xxxxxxxx): <a href=\"https://xxxxx"
- "xxxxxxxxxxx.xxx/xx-xxxxxxx/xxxxxxx/Xxxxx-xxxx-xxx-xxxxxxxxxx-xxxxx.xxx\">https://xxxxxx"
- "xxxxxxxxxx.xxx/xx-xxxxxxx/xxxxxxx/Xxxxx-xxxx-xxx-<br>> xxxxxxxxxx-xxxxx.xxx</a> ; "
- "</div><div style=\"width: 71ch;\">> <br></div><div style=\"width: 71ch;\">> ...x'"
- "x xxxxx xx xxxxxx x'xxxxxx xéxxxxxxx, xx xxx xxxx xxxxxx<br>> x'xxxxxxxxxxx xxxxxx, "
- "xxxx <br>> <a href=\"https://xxxxxxxxxxxxxxxx.xxx/xxxxxxxx-xxxxxxx-xxxx-xxx-o/\">"
- "https://xxxxxxxxxxxxxxxx.xxx/xxxxxxxx-xxxxxxx-xxxx-xxx-o/</a> xxxxx xxx <br>> <a "
- "href=\"https://xxxxxxxxxxxxxxxx.xxx/xxxxxxxx-xxxxxxx-xxxx-xxx-o/\">https://xxxxxxxxx"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<br></div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "Xxxx xxx xxx xxxxxxx xxxxxxxéxx x'xxxêxxxx à xxxxx, xxx xx
xxxxé xx<br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "oooxooo xxxxx xxxxx xxxx... xxxx x'xxx xxxxxxxxxxxx xxxxx xxx<br
class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "xxxxxxxx xx \"xx xxxxx xxx xxx xxxxxxx xxxxxxx xxxxxxxxxxxxxx xxxx<br
class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "xxxxx xxxxxx xx xx xxxx xx x'xxxxxx\". Xx xxxx-êxxx xxx xx xxxxxxxx
xx<br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "xxxx \"x'xxxêxx à xxxxx xx oooxooo xxxx xxx xéxxxxxxxx,
xxxx\"...</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<br></div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "Xxxxx xxxxxx'xx xxx x xxxx xxxxxxx xxxxx xx xxèx xxxxxxxxx<br
class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "xxxxxxxxxxxxxxxx à xx xxx x'xx xx xêxx (éxxxxxxxxx
xxxx-xx-xxxxxxxx):<br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "<a
href=\"https://xxxxxxxxxxxxxxxx.xxx/xx-xxxxxxx/xxxxxxx/Xxxxx-xxxx-xxx-xxxxxxxxxx-xxxxx.xxx\">https://xxxxxx"
+ "xxxxxxxxxx.xxx/xx-xxxxxxx/xxxxxxx/Xxxxx-xxxx-xxx-xxxxxxxxxx-xxxxx.xxx</a><br
class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "; </div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<br></div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "...x'x xxxxx xx xxxxxx x'xxxxxx xéxxxxxxx, xx xxx xxxx
xxxxxx<br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "x'xxxxxxxxxxx xxxxxx, xxxx<br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "<a
href=\"https://xxxxxxxxxxxxxxxx.xxx/xxxxxxxx-xxxxxxx-xxxx-xxx-o/\">"
+ "https://xxxxxxxxxxxxxxxx.xxx/xxxxxxxx-xxxxxxx-xxxx-xxx-o/</a> xxxxx xxx<br
class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "<a
href=\"https://xxxxxxxxxxxxxxxx.xxx/xxxxxxxx-xxxxxxx-xxxx-xxx-o/\">https://xxxxxxxxx"
"xxxxxxx.xxx/xxxxxxxx-xxxxxxx-xxxx-xxx-o/</a> ...</div></blockquote>" HTML_SUFFIX,
"On Today, User wrote:\n"
"> Xxxxx xx xxxxxxxxx xx xxxxxxx xx xxxxx xxxx xxxx xx xxx xxx xxxx xxx\n"
@@ -1127,10 +1263,10 @@ test_bug_788829 (TestFixture *fixture)
"> xx $ xx xxxx x'xxxxxx.\n"
"> \n"
"> Xxxx xx xéxxxxxxx, xxxxxxxx xxxxxxx (!), xxxxxxx à xxx, xxxx ooo$ XXX\n"
- "> xxxxé: \n"
+ "> xxxxé:\n"
"> https://xxxxxxxxxxxxxxxx.xx/xxxxxxx/xxxxx-xxxx-xxxxxxxx-xxxxx-xxxx-xxx-xxxxxxxx-xxx/\n"
"> xx xx xxxx xéxéxxxxxxx x'xxxxxx xxxx xx xxxxxx xx xxxxxxxxxxxx xx xxx\n"
- "> (xxxxx Xxxxxx) xxxx xxxx x'xxxxxxx xx xxxxxx: \n"
+ "> (xxxxx Xxxxxx) xxxx xxxx x'xxxxxxx xx xxxxxx:\n"
">
https://xxxxxxxxxxxxxxxx.xxx/xx-xxxxxxx/xxxxxxx/Xxxxxxxxxxxx-Xxxxx-Xxxx-XXX-Xxxxxx-Xxx.xxx\n"
"> \n"
"> Xxxx xxx xxx xxxxxxx xxxxxxxéxx x'xxxêxxxx à xxxxx, xxx xx xxxxé xx\n"
@@ -1140,14 +1276,14 @@ test_bug_788829 (TestFixture *fixture)
"> xxxx \"x'xxxêxx à xxxxx xx oooxooo xxxx xxx xéxxxxxxxx, xxxx\"...\n"
"> \n"
"> Xxxxx xxxxxx'xx xxx x xxxx xxxxxxx xxxxx xx xxèx xxxxxxxxx\n"
- "> \n"
- "> xxxxxxxxxxxxxxxx à xx xxx x'xx xx xêxx (éxxxxxxxxx xxxx-xx-xxxxxxxx):
https://xxxxxxxxxxxxxxxx.xxx/xx-xxxxxxx/xxxxxxx/Xxxxx-xxxx-xxx-\n"
- "> xxxxxxxxxx-xxxxx.xxx ; \n"
+ "> xxxxxxxxxxxxxxxx à xx xxx x'xx xx xêxx (éxxxxxxxxx xxxx-xx-xxxxxxxx):\n"
+ "> https://xxxxxxxxxxxxxxxx.xxx/xx-xxxxxxx/xxxxxxx/Xxxxx-xxxx-xxx-xxxxxxxxxx-xxxxx.xxx\n"
+ "> ; \n"
"> \n"
"> ...x'x xxxxx xx xxxxxx x'xxxxxx xéxxxxxxx, xx xxx xxxx xxxxxx\n"
- "> x'xxxxxxxxxxx xxxxxx, xxxx \n"
- "> https://xxxxxxxxxxxxxxxx.xxx/xxxxxxxx-xxxxxxx-xxxx-xxx-o/ xxxxx xxx \n"
- "> https://xxxxxxxxxxxxxxxx.xxx/xxxxxxxx-xxxxxxx-xxxx-xxx-o/ ..."))
+ "> x'xxxxxxxxxxx xxxxxx, xxxx\n"
+ "> https://xxxxxxxxxxxxxxxx.xxx/xxxxxxxx-xxxxxxx-xxxx-xxx-o/ xxxxx xxx\n"
+ "> https://xxxxxxxxxxxxxxxx.xxx/xxxxxxxx-xxxxxxx-xxxx-xxx-o/ ...\n"))
g_test_fail ();
}
@@ -1213,26 +1349,26 @@ test_bug_750636 (TestFixture *fixture)
"B\n\n"
"12345678901234567890123456789012345678901234567890123456789012345678901\n"
"C\n\n"
- "1234567890123456789012345678901234567890123456789012345678901234567890 \n"
+ "1234567890123456789012345678901234567890123456789012345678901234567890\n"
"D\n\n"
"12345678901234567890123456789012345678901234567890123456789012345678901\n"
- " E\n\n"
- "1234567890123456789012345678901234567890123456789012345678901234567890 \n"
- " F\n\n"
+ UNICODE_NBSP UNICODE_NBSP UNICODE_NBSP "E\n\n"
+ "1234567890123456789012345678901234567890123456789012345678901234567890" UNICODE_NBSP "\n"
+ UNICODE_NBSP UNICODE_NBSP "F\n\n"
" 1\n"
" 2\n"
" 3\n"
"\n"
- "prefix text \n"
+ "prefix text\n"
"https://www.gnome.org/1234567890123456789012345678901234567890123456789012345678901234567890\n"
"after text\n"
"prefix text https://www.gnome.org/123456789012345678901234567890123\n"
"after text\n"
- "prefix text https://www.gnome.org/12345678901234567890 \n"
+ "prefix text https://www.gnome.org/12345678901234567890\n"
"https://www.gnome.org/12345678901234567890 after text\n"
- "prefix text \n"
+ "prefix text\n"
"https://www.gnome.org/1234567890123456789012345678901234567890123456789012345678901234567890\n"
- " next line text\n"))
+ " next line text\n\n"))
g_test_fail ();
}
@@ -1343,7 +1479,7 @@ test_issue_86 (TestFixture *fixture)
"> > \n"
"> > level 1\n"
"> \n"
- "> back normal text"))
+ "> back normal text\n"))
g_test_fail ();
g_free (to_insert);
@@ -1375,10 +1511,10 @@ test_issue_103 (TestFixture *fixture)
"before\n"
LONG_URL "\n"
"after\n"
- "prefix text \n"
+ "prefix text\n"
SHORTER_URL " suffix\n"
"prefix " SHORT_URL " suffix\n"
- "end")) {
+ "end\n")) {
g_test_fail ();
return;
}
@@ -1398,14 +1534,15 @@ test_issue_104 (TestFixture *fixture)
"seq:h\n"
"action:show-replace\n"
"type:e\t\n"
- "type:\t\t\t\t\t\t\t\n" /* Jump to 'Replace All' */
- "seq:n\n" /* Press it */
+ "seq:A\n" /* Press 'Alt+A' to press 'Replace All' button */
+ "type:a\n"
+ "seq:a\n"
"seq:^\n" /* Close the dialog */
"undo:undo\n"
"undo:test:1\n"
"undo:redo\n",
HTML_PREFIX "<div style=\"width: 71ch;\">txt to rplac</div>" HTML_SUFFIX,
- "txt to rplac"))
+ "txt to rplac\n"))
g_test_fail ();
}
@@ -1443,39 +1580,39 @@ test_issue_107 (TestFixture *fixture)
"",
HTML_PREFIX
"<div style=\"width: 71ch;\">On Today, User wrote:</div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div style=\"width: 71ch;\">> text</div>"
- "<div style=\"width: 71ch;\">> <a
href=\"https://www.01.org/\">https://www.01.org/</a> ?</div>"
- "<div style=\"width: 71ch;\">> <a
href=\"https://www.02.org/\">https://www.02.org/</a> A</div>"
- "<div style=\"width: 71ch;\">> <a
href=\"https://www.03.org/\">https://www.03.org/</a> ěšč</div>"
- "<div style=\"width: 71ch;\">> <a href=\"https://www.04.org/\">https://www.04.org/</a>
?</div>"
- "<div style=\"width: 71ch;\">> <a
href=\"https://www.05.org/\">https://www.05.org/</a></div>"
- "<div style=\"width: 71ch;\">> <a
href=\"https://www.06.org/\">https://www.06.org/</a> </div>"
- "<div style=\"width: 71ch;\">> <a
href=\"https://www.07.org/\">https://www.07.org/</a> </div>"
- "<div style=\"width: 71ch;\">> <a
href=\"https://www.08.org/\">https://www.08.org/</a> > < </div>"
- "<div style=\"width: 71ch;\">> <<a
href=\"https://www.09.org/\">https://www.09.org/</a>></div>"
- "<div style=\"width: 71ch;\">> <<a
href=\"https://www.10.org/\">https://www.10.org/</a> ?></div>"
- "<div style=\"width: 71ch;\">> <a
href=\"https://www.11.org/\">https://www.11.org/</a> </div>"
- "<div style=\"width: 71ch;\">> < <a
href=\"https://www.12.org/\">https://www.12.org/</a> ></div>"
- "<div style=\"width: 71ch;\">> <<a
href=\"https://www.13.org/\">https://www.13.org/</a>> </div>"
- "<div style=\"width: 71ch;\">> Text <a
href=\"https://www.14.org/\">https://www.14.org/</a>\temail: user@no.where</div>"
+ "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "text</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<a
href=\"https://www.01.org/\">https://www.01.org/</a> ?</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<a
href=\"https://www.02.org/\">https://www.02.org/</a> A</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<a
href=\"https://www.03.org/\">https://www.03.org/</a> ěšč</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<a href=\"https://www.04.org/\">https://www.04.org/</a>
?</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<a href=\"https://www.05.org/\">https://www.05.org/</a></div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<a
href=\"https://www.06.org/\">https://www.06.org/</a> </div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<a
href=\"https://www.07.org/\">https://www.07.org/</a> </div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<a
href=\"https://www.08.org/\">https://www.08.org/</a> > < </div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<<a
href=\"https://www.09.org/\">https://www.09.org/</a>></div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<<a
href=\"https://www.10.org/\">https://www.10.org/</a> ?></div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) " <a
href=\"https://www.11.org/\">https://www.11.org/</a> </div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "< <a
href=\"https://www.12.org/\">https://www.12.org/</a> ></div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) " <<a
href=\"https://www.13.org/\">https://www.13.org/</a>> </div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "Text <a
href=\"https://www.14.org/\">https://www.14.org/</a>\temail: <a
href=\"mailto:user@no.where\">user@no.where</a></div>"
"</blockquote>" HTML_SUFFIX,
"On Today, User wrote:\n"
"> text\n"
- "> https://www.01.org/ ?\n"
- "> https://www.02.org/ A\n"
- "> https://www.03.org/ ěšč\n"
+ "> https://www.01.org/" UNICODE_NBSP "?\n"
+ "> https://www.02.org/" UNICODE_NBSP "A\n"
+ "> https://www.03.org/" UNICODE_NBSP "ěšč\n"
"> https://www.04.org/ ?\n"
"> https://www.05.org/\n"
- "> https://www.06.org/ \n"
- "> https://www.07.org/ \n"
- "> https://www.08.org/ > < \n"
+ "> https://www.06.org/" UNICODE_NBSP "\n"
+ "> https://www.07.org/" UNICODE_NBSP UNICODE_NBSP "\n"
+ "> https://www.08.org/" UNICODE_NBSP ">" UNICODE_NBSP "<" UNICODE_NBSP "\n"
"> <https://www.09.org/>\n"
- "> <https://www.10.org/ ?>\n"
- "> https://www.11.org/ \n"
- "> < https://www.12.org/ >\n"
- "> <https://www.13.org/> \n"
- "> Text https://www.14.org/\temail: user@no.where")) {
+ "> <https://www.10.org/" UNICODE_NBSP "?>\n"
+ "> " UNICODE_NBSP "https://www.11.org/" UNICODE_NBSP "\n"
+ "> <" UNICODE_NBSP "https://www.12.org/" UNICODE_NBSP ">\n"
+ "> " UNICODE_NBSP "<https://www.13.org/>" UNICODE_NBSP "\n"
+ "> Text https://www.14.org/\temail: user@no.where\n")) {
g_test_fail ();
}
}
@@ -1483,7 +1620,6 @@ test_issue_107 (TestFixture *fixture)
void
test_add_html_editor_bug_tests (void)
{
- test_utils_add_test ("/bug/726548", test_bug_726548);
test_utils_add_test ("/bug/750657", test_bug_750657);
test_utils_add_test ("/bug/760989", test_bug_760989);
test_utils_add_test ("/bug/767903", test_bug_767903);
@@ -1502,8 +1638,8 @@ test_add_html_editor_bug_tests (void)
test_utils_add_test ("/bug/775042", test_bug_775042);
test_utils_add_test ("/bug/775691", test_bug_775691);
test_utils_add_test ("/bug/779707", test_bug_779707);
- test_utils_add_test ("/bug/780275/html", test_bug_780275_html);
- test_utils_add_test ("/bug/780275/plain", test_bug_780275_plain);
+ test_utils_add_test ("/bug/780275-html", test_bug_780275_html);
+ test_utils_add_test ("/bug/780275-plain", test_bug_780275_plain);
test_utils_add_test ("/bug/781722", test_bug_781722);
test_utils_add_test ("/bug/781116", test_bug_781116);
test_utils_add_test ("/bug/780088", test_bug_780088);
diff --git a/src/e-util/test-html-editor-units-bugs.h b/src/e-util/test-html-editor-units-bugs.h
index c5e78fef34..2a77efd6a3 100644
--- a/src/e-util/test-html-editor-units-bugs.h
+++ b/src/e-util/test-html-editor-units-bugs.h
@@ -20,6 +20,8 @@
#define HTML_PREFIX "<html><head></head><body>"
#define HTML_SUFFIX "</body></html>"
#define BLOCKQUOTE_STYLE "style=\"margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex\""
+#define QUOTE_SPAN(x) "<span class='-x-evo-quoted'>" x "</span>"
+#define QUOTE_CHR "<span class='-x-evo-quote-character'>> </span>"
G_BEGIN_DECLS
diff --git a/src/e-util/test-html-editor-units-utils.c b/src/e-util/test-html-editor-units-utils.c
index daedae625f..51ecd453d8 100644
--- a/src/e-util/test-html-editor-units-utils.c
+++ b/src/e-util/test-html-editor-units-utils.c
@@ -83,6 +83,50 @@ test_utils_free_global_memory (void)
g_clear_object (&global_web_context);
}
+typedef struct _GetContentData {
+ EContentEditorContentHash *content_hash;
+ gpointer async_data;
+} GetContentData;
+
+static void
+get_editor_content_hash_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GetContentData *gcd = user_data;
+ GError *error = NULL;
+
+ g_assert_nonnull (gcd);
+ g_assert (E_IS_CONTENT_EDITOR (source_object));
+
+ gcd->content_hash = e_content_editor_get_content_finish (E_CONTENT_EDITOR (source_object), result,
&error);
+
+ g_assert_no_error (error);
+
+ g_clear_error (&error);
+
+ test_utils_async_call_finish (gcd->async_data);
+}
+
+static EContentEditorContentHash *
+test_utils_get_editor_content_hash_sync (EContentEditor *cnt_editor,
+ guint32 flags)
+{
+ GetContentData gcd;
+
+ g_assert (E_IS_CONTENT_EDITOR (cnt_editor));
+
+ gcd.content_hash = NULL;
+ gcd.async_data = test_utils_async_call_prepare ();
+
+ e_content_editor_get_content (cnt_editor, flags, "test-domain", NULL,
get_editor_content_hash_ready_cb, &gcd);
+
+ g_assert (test_utils_async_call_wait (gcd.async_data, MAX (event_processing_delay_ms / 25, 1) + 1));
+ g_assert_nonnull (gcd.content_hash);
+
+ return gcd.content_hash;
+}
+
typedef struct _UndoContent {
gchar *html;
gchar *plain;
@@ -92,16 +136,20 @@ static UndoContent *
undo_content_new (TestFixture *fixture)
{
EContentEditor *cnt_editor;
+ EContentEditorContentHash *content_hash;
UndoContent *uc;
g_return_val_if_fail (fixture != NULL, NULL);
g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), NULL);
cnt_editor = e_html_editor_get_content_editor (fixture->editor);
+ content_hash = test_utils_get_editor_content_hash_sync (cnt_editor, E_CONTENT_EDITOR_GET_TO_SEND_HTML
| E_CONTENT_EDITOR_GET_TO_SEND_PLAIN);
uc = g_new0 (UndoContent, 1);
- uc->html = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_HTML, NULL, NULL);
- uc->plain = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_PLAIN, NULL, NULL);
+ uc->html = e_content_editor_util_steal_content_data (content_hash, E_CONTENT_EDITOR_GET_TO_SEND_HTML,
NULL);
+ uc->plain = e_content_editor_util_steal_content_data (content_hash,
E_CONTENT_EDITOR_GET_TO_SEND_PLAIN, NULL);
+
+ e_content_editor_util_free_content_hash (content_hash);
g_warn_if_fail (uc->html != NULL);
g_warn_if_fail (uc->plain != NULL);
@@ -127,15 +175,17 @@ undo_content_test (TestFixture *fixture,
gint cmd_index)
{
EContentEditor *cnt_editor;
- gchar *text;
+ EContentEditorContentHash *content_hash;
+ const gchar *text;
g_return_val_if_fail (fixture != NULL, FALSE);
g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE);
g_return_val_if_fail (uc != NULL, FALSE);
cnt_editor = e_html_editor_get_content_editor (fixture->editor);
+ content_hash = test_utils_get_editor_content_hash_sync (cnt_editor, E_CONTENT_EDITOR_GET_TO_SEND_HTML
| E_CONTENT_EDITOR_GET_TO_SEND_PLAIN);
- text = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_HTML, NULL, NULL);
+ text = e_content_editor_util_get_content_data (content_hash, E_CONTENT_EDITOR_GET_TO_SEND_HTML);
g_return_val_if_fail (text != NULL, FALSE);
if (!test_utils_html_equal (fixture, text, uc->html)) {
@@ -143,13 +193,13 @@ undo_content_test (TestFixture *fixture,
g_printerr ("%s: returned HTML\n---%s---\n and expected HTML\n---%s---\n do not match
at command %d\n", G_STRFUNC, text, uc->html, cmd_index);
else
g_warning ("%s: returned HTML\n---%s---\n and expected HTML\n---%s---\n do not match
at command %d", G_STRFUNC, text, uc->html, cmd_index);
- g_free (text);
+
+ e_content_editor_util_free_content_hash (content_hash);
+
return FALSE;
}
- g_free (text);
-
- text = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_PLAIN, NULL, NULL);
+ text = e_content_editor_util_get_content_data (content_hash, E_CONTENT_EDITOR_GET_TO_SEND_PLAIN);
g_return_val_if_fail (text != NULL, FALSE);
if (!test_utils_html_equal (fixture, text, uc->plain)) {
@@ -157,11 +207,13 @@ undo_content_test (TestFixture *fixture,
g_printerr ("%s: returned Plain\n---%s---\n and expected Plain\n---%s---\n do not
match at command %d\n", G_STRFUNC, text, uc->plain, cmd_index);
else
g_warning ("%s: returned Plain\n---%s---\n and expected Plain\n---%s---\n do not
match at command %d", G_STRFUNC, text, uc->plain, cmd_index);
- g_free (text);
+
+ e_content_editor_util_free_content_hash (content_hash);
+
return FALSE;
}
- g_free (text);
+ e_content_editor_util_free_content_hash (content_hash);
return TRUE;
}
@@ -175,9 +227,32 @@ test_utils_web_process_crashed_cb (WebKitWebView *web_view,
return FALSE;
}
+/* <Control>+<Shift>+I */
+#define WEBKIT_INSPECTOR_MOD (GDK_CONTROL_MASK | GDK_SHIFT_MASK)
+#define WEBKIT_INSPECTOR_KEY (GDK_KEY_I)
+
+static gboolean
+wk_editor_key_press_event_cb (WebKitWebView *web_view,
+ GdkEventKey *event)
+{
+ WebKitWebInspector *inspector;
+ gboolean handled = FALSE;
+
+ inspector = webkit_web_view_get_inspector (web_view);
+
+ if ((event->state & WEBKIT_INSPECTOR_MOD) == WEBKIT_INSPECTOR_MOD &&
+ event->keyval == WEBKIT_INSPECTOR_KEY) {
+ webkit_web_inspector_show (inspector);
+ handled = TRUE;
+ }
+
+ return handled;
+}
+
typedef struct _CreateData {
gpointer async_data;
TestFixture *fixture;
+ gboolean created;
} CreateData;
static void
@@ -193,6 +268,8 @@ test_utils_html_editor_created_cb (GObject *source_object,
g_return_if_fail (create_data != NULL);
+ create_data->created = TRUE;
+
fixture = create_data->fixture;
html_editor = e_html_editor_new_finish (result, &error);
@@ -213,6 +290,26 @@ test_utils_html_editor_created_cb (GObject *source_object,
gtk_widget_show (GTK_WIDGET (fixture->editor));
gtk_container_add (GTK_CONTAINER (fixture->window), GTK_WIDGET (fixture->editor));
+ fixture->focus_tracker = e_focus_tracker_new (GTK_WINDOW (fixture->window));
+
+ e_focus_tracker_set_cut_clipboard_action (fixture->focus_tracker,
+ e_html_editor_get_action (fixture->editor, "cut"));
+
+ e_focus_tracker_set_copy_clipboard_action (fixture->focus_tracker,
+ e_html_editor_get_action (fixture->editor, "copy"));
+
+ e_focus_tracker_set_paste_clipboard_action (fixture->focus_tracker,
+ e_html_editor_get_action (fixture->editor, "paste"));
+
+ e_focus_tracker_set_select_all_action (fixture->focus_tracker,
+ e_html_editor_get_action (fixture->editor, "select-all"));
+
+ e_focus_tracker_set_undo_action (fixture->focus_tracker,
+ e_html_editor_get_action (fixture->editor, "undo"));
+
+ e_focus_tracker_set_redo_action (fixture->focus_tracker,
+ e_html_editor_get_action (fixture->editor, "redo"));
+
/* Make sure this is off */
test_utils_fixture_change_setting_boolean (fixture,
"org.gnome.evolution.mail", "prompt-on-composer-mode-switch", FALSE);
@@ -229,12 +326,23 @@ test_utils_html_editor_created_cb (GObject *source_object,
g_signal_connect (cnt_editor, "web-process-crashed",
G_CALLBACK (test_utils_web_process_crashed_cb), NULL);
- if (!test_utils_get_multiple_web_processes () && !global_web_context &&
- WEBKIT_IS_WEB_VIEW (cnt_editor)) {
- WebKitWebContext *web_context;
+ if (WEBKIT_IS_WEB_VIEW (cnt_editor)) {
+ WebKitSettings *web_settings;
+
+ web_settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (cnt_editor));
+ webkit_settings_set_enable_developer_extras (web_settings, TRUE);
+ webkit_settings_set_enable_write_console_messages_to_stdout (web_settings, TRUE);
+
+ g_signal_connect (
+ cnt_editor, "key-press-event",
+ G_CALLBACK (wk_editor_key_press_event_cb), NULL);
- web_context = webkit_web_view_get_context (WEBKIT_WEB_VIEW (cnt_editor));
- global_web_context = g_object_ref (web_context);
+ if (!test_utils_get_multiple_web_processes () && !global_web_context) {
+ WebKitWebContext *web_context;
+
+ web_context = webkit_web_view_get_context (WEBKIT_WEB_VIEW (cnt_editor));
+ global_web_context = g_object_ref (web_context);
+ }
}
gtk_window_set_focus (GTK_WINDOW (fixture->window), GTK_WIDGET (cnt_editor));
@@ -254,6 +362,8 @@ test_utils_add_test (const gchar *name,
test_utils_fixture_set_up, (ETestFixtureFunc) func, test_utils_fixture_tear_down);
}
+static void test_utils_async_call_free (gpointer async_data);
+
void
test_utils_fixture_set_up (TestFixture *fixture,
gconstpointer user_data)
@@ -271,10 +381,14 @@ test_utils_fixture_set_up (TestFixture *fixture,
create_data.async_data = test_utils_async_call_prepare ();
create_data.fixture = fixture;
+ create_data.created = FALSE;
e_html_editor_new (test_utils_html_editor_created_cb, &create_data);
- test_utils_async_call_wait (create_data.async_data, 60);
+ if (create_data.created)
+ test_utils_async_call_free (create_data.async_data);
+ else
+ test_utils_async_call_wait (create_data.async_data, 60);
g_warn_if_fail (fixture->editor != NULL);
g_warn_if_fail (E_IS_HTML_EDITOR (fixture->editor));
@@ -303,6 +417,8 @@ void
test_utils_fixture_tear_down (TestFixture *fixture,
gconstpointer user_data)
{
+ g_clear_object (&fixture->focus_tracker);
+
gtk_widget_destroy (GTK_WIDGET (fixture->window));
fixture->editor = NULL;
@@ -385,6 +501,16 @@ test_utils_flush_main_context (void)
}
}
+static void
+test_utils_async_call_free (gpointer async_data)
+{
+ GMainLoop *loop = async_data;
+
+ test_utils_flush_main_context ();
+
+ g_main_loop_unref (loop);
+}
+
gpointer
test_utils_async_call_prepare (void)
{
@@ -440,9 +566,7 @@ test_utils_async_call_wait (gpointer async_data,
g_source_unref (source);
}
- test_utils_flush_main_context ();
-
- g_main_loop_unref (loop);
+ test_utils_async_call_free (async_data);
return !async_call_data.timeout_reached;
}
@@ -566,16 +690,57 @@ test_utils_type_text (TestFixture *fixture,
return TRUE;
}
+typedef struct _HTMLEqualData {
+ gpointer async_data;
+ gboolean equal;
+} HTMLEqualData;
+
+static void
+test_html_equal_done_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ HTMLEqualData *hed = user_data;
+ WebKitJavascriptResult *js_result;
+ JSCException *exception;
+ JSCValue *js_value;
+ GError *error = NULL;
+
+ g_return_if_fail (hed != NULL);
+
+ js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (source_object), result, &error);
+
+ g_assert_no_error (error);
+ g_clear_error (&error);
+
+ g_assert_nonnull (js_result);
+
+ js_value = webkit_javascript_result_get_js_value (js_result);
+ g_assert_nonnull (js_value);
+ g_assert (jsc_value_is_boolean (js_value));
+
+ hed->equal = jsc_value_to_boolean (js_value);
+
+ exception = jsc_context_get_exception (jsc_value_get_context (js_value));
+
+ if (exception) {
+ g_warning ("Failed to call EvoEditorTest.isHTMLEqual: %s", jsc_exception_get_message
(exception));
+ jsc_context_clear_exception (jsc_value_get_context (js_value));
+ }
+
+ webkit_javascript_result_unref (js_result);
+
+ test_utils_async_call_finish (hed->async_data);
+}
+
gboolean
test_utils_html_equal (TestFixture *fixture,
const gchar *html1,
const gchar *html2)
{
EContentEditor *cnt_editor;
- GDBusProxy *web_extension = NULL;
- GVariant *result;
- GError *error = NULL;
- gboolean html_equal = FALSE;
+ gchar *script;
+ HTMLEqualData hed;
g_return_val_if_fail (fixture != NULL, FALSE);
g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE);
@@ -584,29 +749,33 @@ test_utils_html_equal (TestFixture *fixture,
cnt_editor = e_html_editor_get_content_editor (fixture->editor);
g_return_val_if_fail (cnt_editor != NULL, FALSE);
+ g_return_val_if_fail (WEBKIT_IS_WEB_VIEW (cnt_editor), FALSE);
- g_object_get (cnt_editor, "web-extension", &web_extension, NULL);
-
- g_return_val_if_fail (G_IS_DBUS_PROXY (web_extension), FALSE);
+ script = e_web_view_jsc_printf_script (
+ "var EvoEditorTest = {};\n"
+ "EvoEditorTest.isHTMLEqual = function(html1, html2) {\n"
+ " var elem1, elem2;\n"
+ " elem1 = document.createElement(\"testHtmlEqual\");\n"
+ " elem2 = document.createElement(\"testHtmlEqual\");\n"
+ " elem1.innerHTML = html1.replace(/ /g, \" \").replace(/ /g, \" \");\n"
+ " elem2.innerHTML = html2.replace(/ /g, \" \").replace(/ /g, \" \");\n"
+ " elem1.normalize();\n"
+ " elem2.normalize();\n"
+ " return elem1.isEqualNode(elem2);\n"
+ "}\n"
+ "EvoEditorTest.isHTMLEqual(%s, %s);", html1, html2);
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_full (
- web_extension,
- "TestHTMLEqual",
- g_variant_new ("(tss)", webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (cnt_editor)), html1,
html2),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- NULL,
- &error);
- g_assert_no_error (error);
+ hed.async_data = test_utils_async_call_prepare();
+ hed.equal = FALSE;
- g_clear_error (&error);
+ webkit_web_view_run_javascript (WEBKIT_WEB_VIEW (cnt_editor), script, NULL,
+ test_html_equal_done_cb, &hed);
- g_return_val_if_fail (result != NULL, FALSE);
+ test_utils_async_call_wait (hed.async_data, 10);
- g_variant_get (result, "(b)", &html_equal);
- g_variant_unref (result);
+ g_free (script);
- return html_equal;
+ return hed.equal;
}
static gboolean
@@ -781,6 +950,21 @@ test_utils_execute_action (TestFixture *fixture,
return TRUE;
}
+static gboolean
+test_utils_set_font_name (TestFixture *fixture,
+ const gchar *font_name)
+{
+ EContentEditor *cnt_editor;
+
+ g_return_val_if_fail (fixture != NULL, FALSE);
+ g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE);
+
+ cnt_editor = e_html_editor_get_content_editor (fixture->editor);
+ e_content_editor_set_font_name (cnt_editor, font_name);
+
+ return TRUE;
+}
+
/* Expects only the part like "undo" [ ":" number ] */
static gint
test_utils_maybe_extract_undo_number (const gchar *command)
@@ -825,6 +1009,7 @@ test_utils_pick_undo_content (const GSList *undo_stack,
command = actioncmd ; Execute an action
/ modecmd ; Change editor mode to HTML or Plain Text
+ / fnmcmd ; Set font name
/ seqcmd ; Sequence of special key strokes
/ typecmd ; Type a text
/ undocmd ; Undo/redo commands
@@ -832,7 +1017,9 @@ test_utils_pick_undo_content (const GSList *undo_stack,
actioncmd = "action:" name
- actioncmd = "mode:" ("html" / "plain")
+ modecmd = "mode:" ("html" / "plain")
+
+ fnmcmd = "font-name:" name
seqcmd = "seq:" sequence
@@ -899,6 +1086,8 @@ test_utils_process_commands (TestFixture *fixture,
success = FALSE;
g_warning ("%s: Unknown mode '%s'", G_STRFUNC, mode_change);
}
+ } else if (g_str_has_prefix (command, "font-name:")) {
+ success = test_utils_set_font_name (fixture, command + 10);
} else if (g_str_has_prefix (command, "seq:")) {
success = test_utils_process_sequence (fixture, command + 4);
} else if (g_str_has_prefix (command, "type:")) {
@@ -983,7 +1172,8 @@ test_utils_run_simple_test (TestFixture *fixture,
const gchar *expected_plain)
{
EContentEditor *cnt_editor;
- gchar *text;
+ EContentEditorContentHash *content_hash;
+ const gchar *text;
g_return_val_if_fail (fixture != NULL, FALSE);
g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE);
@@ -994,8 +1184,10 @@ test_utils_run_simple_test (TestFixture *fixture,
if (!test_utils_process_commands (fixture, commands))
return FALSE;
+ content_hash = test_utils_get_editor_content_hash_sync (cnt_editor, E_CONTENT_EDITOR_GET_TO_SEND_HTML
| E_CONTENT_EDITOR_GET_TO_SEND_PLAIN);
+
if (expected_html) {
- text = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_HTML, NULL, NULL);
+ text = e_content_editor_util_get_content_data (content_hash,
E_CONTENT_EDITOR_GET_TO_SEND_HTML);
g_return_val_if_fail (text != NULL, FALSE);
if (!test_utils_html_equal (fixture, text, expected_html)) {
@@ -1003,15 +1195,15 @@ test_utils_run_simple_test (TestFixture *fixture,
g_printerr ("%s: returned HTML\n---%s---\n and expected HTML\n---%s---\n do
not match\n", G_STRFUNC, text, expected_html);
else
g_warning ("%s: returned HTML\n---%s---\n and expected HTML\n---%s---\n do
not match", G_STRFUNC, text, expected_html);
- g_free (text);
+
+ e_content_editor_util_free_content_hash (content_hash);
+
return FALSE;
}
-
- g_free (text);
}
if (expected_plain) {
- text = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_PLAIN, NULL, NULL);
+ text = e_content_editor_util_get_content_data (content_hash,
E_CONTENT_EDITOR_GET_TO_SEND_PLAIN);
g_return_val_if_fail (text != NULL, FALSE);
if (!test_utils_html_equal (fixture, text, expected_plain)) {
@@ -1019,13 +1211,15 @@ test_utils_run_simple_test (TestFixture *fixture,
g_printerr ("%s: returned Plain\n---%s---\n and expected Plain\n---%s---\n do
not match\n", G_STRFUNC, text, expected_plain);
else
g_warning ("%s: returned Plain\n---%s---\n and expected Plain\n---%s---\n do
not match", G_STRFUNC, text, expected_plain);
- g_free (text);
+
+ e_content_editor_util_free_content_hash (content_hash);
+
return FALSE;
}
-
- g_free (text);
}
+ e_content_editor_util_free_content_hash (content_hash);
+
return TRUE;
}
@@ -1099,35 +1293,35 @@ test_utils_get_content_editor (TestFixture *fixture)
}
gchar *
-test_utils_get_base64_data_for_image (const gchar *path)
+test_utils_dup_image_uri (const gchar *path)
{
- gchar *image_data = NULL;
- gchar *image_data_base64;
- gsize image_data_length = 0;
- gboolean success;
+ gchar *image_uri = NULL;
GError *error = NULL;
if (path && strchr (path, G_DIR_SEPARATOR)) {
- success = g_file_get_contents (path, &image_data, &image_data_length, &error);
+ image_uri = g_filename_to_uri (path, NULL, &error);
} else {
gchar *filename;
filename = e_icon_factory_get_icon_filename (path, GTK_ICON_SIZE_MENU);
if (filename) {
- success = g_file_get_contents (filename, &image_data, &image_data_length, &error);
+ image_uri = g_filename_to_uri (filename, NULL, &error);
g_free (filename);
} else {
g_set_error (&error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "Icon '%s' not found", path);
- success = FALSE;
}
}
- g_assert_no_error (error);
- g_assert (success);
+ if (image_uri) {
+ gchar *tmp;
- image_data_base64 = g_base64_encode ((const guchar *) image_data, image_data_length);
+ tmp = g_strconcat ("evo-", image_uri, NULL);
+ g_free (image_uri);
+ image_uri = tmp;
+ }
- g_free (image_data);
+ g_assert_no_error (error);
+ g_assert_nonnull (image_uri);
- return image_data_base64;
+ return image_uri;
}
diff --git a/src/e-util/test-html-editor-units-utils.h b/src/e-util/test-html-editor-units-utils.h
index ee79ac4e02..a24ba56033 100644
--- a/src/e-util/test-html-editor-units-utils.h
+++ b/src/e-util/test-html-editor-units-utils.h
@@ -31,6 +31,7 @@ typedef struct _TestSettings {
typedef struct _TestFixture {
GtkWidget *window;
EHTMLEditor *editor;
+ EFocusTracker *focus_tracker;
GSList *settings; /* TestSettings * */
guint key_state;
@@ -104,8 +105,7 @@ void test_utils_set_clipboard_text (const gchar *text,
gchar * test_utils_get_clipboard_text (gboolean request_html);
EContentEditor *
test_utils_get_content_editor (TestFixture *fixture);
-gchar * test_utils_get_base64_data_for_image
- (const gchar *path);
+gchar * test_utils_dup_image_uri (const gchar *path);
G_END_DECLS
diff --git a/src/e-util/test-html-editor-units.c b/src/e-util/test-html-editor-units.c
index 9d3035f9bd..ddbf0470e9 100644
--- a/src/e-util/test-html-editor-units.c
+++ b/src/e-util/test-html-editor-units.c
@@ -47,7 +47,7 @@ test_style_bold_selection (TestFixture *fixture)
"seq:hCrcrCSrsc\n"
"action:bold\n",
HTML_PREFIX "<div>some <b>bold</b> text</div>" HTML_SUFFIX,
- "some bold text"))
+ "some bold text\n"))
g_test_fail ();
}
@@ -62,7 +62,7 @@ test_style_bold_typed (TestFixture *fixture)
"action:bold\n"
"type: text\n",
HTML_PREFIX "<div>some <b>bold</b> text</div>" HTML_SUFFIX,
- "some bold text"))
+ "some bold text\n"))
g_test_fail ();
}
@@ -75,7 +75,7 @@ test_style_italic_selection (TestFixture *fixture)
"seq:hCrcrCSrsc\n"
"action:italic\n",
HTML_PREFIX "<div>some <i>italic</i> text</div>" HTML_SUFFIX,
- "some italic text"))
+ "some italic text\n"))
g_test_fail ();
}
@@ -90,7 +90,7 @@ test_style_italic_typed (TestFixture *fixture)
"action:italic\n"
"type: text\n",
HTML_PREFIX "<div>some <i>italic</i> text</div>" HTML_SUFFIX,
- "some italic text"))
+ "some italic text\n"))
g_test_fail ();
}
@@ -103,7 +103,7 @@ test_style_underline_selection (TestFixture *fixture)
"seq:hCrcrCSrsc\n"
"action:underline\n",
HTML_PREFIX "<div>some <u>underline</u> text</div>" HTML_SUFFIX,
- "some underline text"))
+ "some underline text\n"))
g_test_fail ();
}
@@ -118,7 +118,7 @@ test_style_underline_typed (TestFixture *fixture)
"action:underline\n"
"type: text\n",
HTML_PREFIX "<div>some <u>underline</u> text</div>" HTML_SUFFIX,
- "some underline text"))
+ "some underline text\n"))
g_test_fail ();
}
@@ -131,7 +131,7 @@ test_style_strikethrough_selection (TestFixture *fixture)
"seq:hCrcrCSrsc\n"
"action:strikethrough\n",
HTML_PREFIX "<div>some <strike>strikethrough</strike> text</div>" HTML_SUFFIX,
- "some strikethrough text"))
+ "some strikethrough text\n"))
g_test_fail ();
}
@@ -146,7 +146,7 @@ test_style_strikethrough_typed (TestFixture *fixture)
"action:strikethrough\n"
"type: text\n",
HTML_PREFIX "<div>some <strike>strikethrough</strike> text</div>" HTML_SUFFIX,
- "some strikethrough text"))
+ "some strikethrough text\n"))
g_test_fail ();
}
@@ -157,9 +157,9 @@ test_style_monospace_selection (TestFixture *fixture)
"mode:html\n"
"type:some monospace text\n"
"seq:hCrcrCSrsc\n"
- "action:monospaced\n",
- HTML_PREFIX "<div>some <font face=\"monospace\" size=\"3\">monospace</font> text</div>"
HTML_SUFFIX,
- "some monospace text"))
+ "font-name:monospace\n",
+ HTML_PREFIX "<div>some <font face=\"monospace\">monospace</font> text</div>" HTML_SUFFIX,
+ "some monospace text\n"))
g_test_fail ();
}
@@ -169,12 +169,12 @@ test_style_monospace_typed (TestFixture *fixture)
if (!test_utils_run_simple_test (fixture,
"mode:html\n"
"type:some \n"
- "action:monospaced\n"
+ "font-name:monospace\n"
"type:monospace\n"
- "action:monospaced\n"
+ "font-name:\n"
"type: text\n",
- HTML_PREFIX "<div>some <font face=\"monospace\" size=\"3\">monospace</font> text</div>"
HTML_SUFFIX,
- "some monospace text"))
+ HTML_PREFIX "<div>some <font face=\"monospace\">monospace</font> text</div>" HTML_SUFFIX,
+ "some monospace text\n"))
g_test_fail ();
}
@@ -193,13 +193,14 @@ test_justify_selection (TestFixture *fixture)
"seq:d\n"
"action:justify-left\n",
HTML_PREFIX
- "<div style=\"text-align: center\">center</div>"
- "<div style=\"text-align: right\">right</div>"
+ "<div style=\"text-align: center;\">center</div>"
+ "<div style=\"text-align: right;\">right</div>"
"<div>left</div><div><br></div>"
HTML_SUFFIX,
" center\n"
" right\n"
- "left\n"))
+ "left\n"
+ "\n"))
g_test_fail ();
}
@@ -215,13 +216,14 @@ test_justify_typed (TestFixture *fixture)
"action:justify-left\n"
"type:left\\n\n",
HTML_PREFIX
- "<div style=\"text-align: center\">center</div>"
- "<div style=\"text-align: right\">right</div>"
+ "<div style=\"text-align: center;\">center</div>"
+ "<div style=\"text-align: right;\">right</div>"
"<div>left</div><div><br></div>"
HTML_SUFFIX,
" center\n"
" right\n"
- "left\n"))
+ "left\n"
+ "\n"))
g_test_fail ();
}
@@ -245,16 +247,16 @@ test_indent_selection (TestFixture *fixture)
"action:unindent\n",
HTML_PREFIX
"<div>level 0</div>"
- "<div style=\"margin-left: 3ch;\">"
- "<div>level 1</div>"
- "<div style=\"margin-left: 3ch;\"><div>level 2</div></div>"
- "<div>level 1</div>"
- "</div><div><br></div>"
+ "<div style=\"margin-left: 3ch;\">level 1</div>"
+ "<div style=\"margin-left: 6ch;\">level 2</div>"
+ "<div style=\"margin-left: 3ch;\">level 1</div>"
+ "<div><br></div>"
HTML_SUFFIX,
"level 0\n"
" level 1\n"
" level 2\n"
- " level 1\n"))
+ " level 1\n"
+ "\n"))
g_test_fail ();
}
@@ -273,16 +275,16 @@ test_indent_typed (TestFixture *fixture)
"action:unindent\n",
HTML_PREFIX
"<div>level 0</div>"
- "<div style=\"margin-left: 3ch;\">"
- "<div>level 1</div>"
- "<div style=\"margin-left: 3ch;\"><div>level 2</div></div>"
- "<div>level 1</div>"
- "</div><div><br></div>"
+ "<div style=\"margin-left: 3ch;\">level 1</div>"
+ "<div style=\"margin-left: 6ch;\">level 2</div>"
+ "<div style=\"margin-left: 3ch;\">level 1</div>"
+ "<div><br></div>"
HTML_SUFFIX,
"level 0\n"
" level 1\n"
" level 2\n"
- " level 1\n"))
+ " level 1\n"
+ "\n"))
g_test_fail ();
}
@@ -308,7 +310,7 @@ test_font_size_selection (TestFixture *fixture)
"action:size-plus-four\n",
HTML_PREFIX "<div><font size=\"1\">FontM2</font> <font size=\"2\">FontM1</font> Font0 <font
size=\"4\">FontP1</font> "
"<font size=\"5\">FontP2</font> <font size=\"6\">FontP3</font> <font
size=\"7\">FontP4</font></div>" HTML_SUFFIX,
- "FontM2 FontM1 Font0 FontP1 FontP2 FontP3 FontP4"))
+ "FontM2 FontM1 Font0 FontP1 FontP2 FontP3 FontP4\n"))
g_test_fail ();
}
@@ -343,9 +345,10 @@ test_font_size_typed (TestFixture *fixture)
"action:size-plus-four\n"
"type:FontP4\n"
"action:size-plus-zero\n",
- HTML_PREFIX "<div><font size=\"1\">FontM2</font> <font size=\"2\">FontM1</font> Font0 <font
size=\"4\">FontP1</font> "
- "<font size=\"5\">FontP2</font> <font size=\"6\">FontP3</font> <font
size=\"7\">FontP4</font><br></div>" HTML_SUFFIX,
- "FontM2 FontM1 Font0 FontP1 FontP2 FontP3 FontP4"))
+ HTML_PREFIX "<div><font size=\"1\">FontM2</font><font size=\"3\"> </font><font
size=\"2\">FontM1</font><font size=\"3\"> Font0 </font>"
+ "<font size=\"4\">FontP1</font><font size=\"3\"> </font><font size=\"5\">FontP2</font><font
size=\"3\"> </font>"
+ "<font size=\"6\">FontP3</font><font size=\"3\"> </font><font size=\"7\">FontP4</font></div>"
HTML_SUFFIX,
+ "FontM2 FontM1 Font0 FontP1 FontP2 FontP3 FontP4\n"))
g_test_fail ();
}
@@ -405,7 +408,7 @@ test_font_color_selection (TestFixture *fixture)
if (!test_utils_run_simple_test (fixture, "",
HTML_PREFIX "<div>default <font color=\"#ff0000\">red</font> <font
color=\"#00ff00\">green</font> "
"<font color=\"#0000ff\">blue</font></div>" HTML_SUFFIX,
- "default red green blue"))
+ "default red green blue\n"))
g_test_fail ();
}
@@ -470,7 +473,7 @@ test_font_color_typed (TestFixture *fixture)
if (!test_utils_run_simple_test (fixture, "",
HTML_PREFIX "<div>default <font color=\"#ff0000\">red </font><font color=\"#00ff00\">green
</font>"
"<font color=\"#0000ff\">blue</font></div>" HTML_SUFFIX,
- "default red green blue"))
+ "default red green blue\n"))
g_test_fail ();
}
@@ -489,7 +492,7 @@ test_list_bullet_plain (TestFixture *fixture)
" * item 1\n"
" * item 2\n"
" * item 3\n"
- "text"))
+ "text\n"))
g_test_fail ();
}
@@ -517,9 +520,9 @@ test_list_bullet_html (TestFixture *fixture)
"<div>text</div>"
HTML_SUFFIX,
" * item 1\n"
- " * item 2\n"
+ " - item 2\n"
" * item 3\n"
- "text"))
+ "text\n"))
g_test_fail ();
}
@@ -531,7 +534,7 @@ test_list_bullet_change (TestFixture *fixture)
"action:style-list-bullet\n"
"action:style-list-number\n",
NULL,
- " 1. "))
+ " 1. \n"))
g_test_fail ();
}
@@ -559,7 +562,7 @@ test_list_bullet_html_from_block (TestFixture *fixture)
" * item 1\n"
" * item 2\n"
" * item 3\n"
- " * "))
+ " * \n"))
g_test_fail ();
}
@@ -587,9 +590,9 @@ test_list_alpha_html (TestFixture *fixture)
"<div>text</div>"
HTML_SUFFIX,
" A. item 1\n"
- " A. item 2\n"
+ " A. item 2\n"
" B. item 3\n"
- "text"))
+ "text\n"))
g_test_fail ();
}
@@ -608,9 +611,60 @@ test_list_alpha_plain (TestFixture *fixture)
"type:text\n",
NULL,
" A. item 1\n"
- " A. item 2\n"
+ " A. item 2\n"
" B. item 3\n"
- "text"))
+ "text\n"))
+ g_test_fail ();
+}
+
+static void
+test_list_number_html (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:style-list-number\n"
+ "type:item 1\\n\n"
+ "action:indent\n"
+ "type:item 2\\n\n"
+ "action:unindent\n"
+ "type:item 3\\n\n"
+ "type:\\n\n"
+ "type:text\n",
+ HTML_PREFIX
+ "<ol>"
+ "<li>item 1</li>"
+ "<ol>"
+ "<li>item 2</li>"
+ "</ol>"
+ "<li>item 3</li>"
+ "</ol>"
+ "<div>text</div>"
+ HTML_SUFFIX,
+ " 1. item 1\n"
+ " 1. item 2\n"
+ " 2. item 3\n"
+ "text\n"))
+ g_test_fail ();
+}
+
+static void
+test_list_number_plain (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "action:style-list-number\n"
+ "type:item 1\\n\n"
+ "action:indent\n"
+ "type:item 2\\n\n"
+ "action:unindent\n"
+ "type:item 3\\n\n"
+ "type:\\n\n"
+ "type:text\n",
+ NULL,
+ " 1. item 1\n"
+ " 1. item 2\n"
+ " 2. item 3\n"
+ "text\n"))
g_test_fail ();
}
@@ -643,24 +697,24 @@ test_list_roman_html (TestFixture *fixture)
"<li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li>"
"<li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li>"
"</ol>" HTML_SUFFIX,
- " I. 1\n"
- " II. 2\n"
- " III. 3\n"
- " IV. 4\n"
- " V. 5\n"
- " VI. 6\n"
- " VII. 7\n"
- "VIII. 8\n"
- " IX. 9\n"
- " X. 10\n"
- " XI. 11\n"
- " XII. 12\n"
- "XIII. 13\n"
- " XIV. 14\n"
- " XV. 15\n"
- " XVI. 16\n"
- "XVII. 17\n"
- "XVIII. 18"))
+ " I. 1\n"
+ " II. 2\n"
+ " III. 3\n"
+ " IV. 4\n"
+ " V. 5\n"
+ " VI. 6\n"
+ " VII. 7\n"
+ " VIII. 8\n"
+ " IX. 9\n"
+ " X. 10\n"
+ " XI. 11\n"
+ " XII. 12\n"
+ " XIII. 13\n"
+ " XIV. 14\n"
+ " XV. 15\n"
+ " XVI. 16\n"
+ " XVII. 17\n"
+ "XVIII. 18\n"))
g_test_fail ();
}
@@ -689,24 +743,24 @@ test_list_roman_plain (TestFixture *fixture)
"type:17\\n\n"
"type:18\n",
NULL,
- " I. 1\n"
- " II. 2\n"
- " III. 3\n"
- " IV. 4\n"
- " V. 5\n"
- " VI. 6\n"
- " VII. 7\n"
- "VIII. 8\n"
- " IX. 9\n"
- " X. 10\n"
- " XI. 11\n"
- " XII. 12\n"
- "XIII. 13\n"
- " XIV. 14\n"
- " XV. 15\n"
- " XVI. 16\n"
- "XVII. 17\n"
- "XVIII. 18"))
+ " I. 1\n"
+ " II. 2\n"
+ " III. 3\n"
+ " IV. 4\n"
+ " V. 5\n"
+ " VI. 6\n"
+ " VII. 7\n"
+ " VIII. 8\n"
+ " IX. 9\n"
+ " X. 10\n"
+ " XI. 11\n"
+ " XII. 12\n"
+ " XIII. 13\n"
+ " XIV. 14\n"
+ " XV. 15\n"
+ " XVI. 16\n"
+ " XVII. 17\n"
+ "XVIII. 18\n"))
g_test_fail ();
}
@@ -737,7 +791,7 @@ test_list_multi_html (TestFixture *fixture)
" * item 2\n"
" I. item 3\n"
" II. item 4\n"
- " III. "))
+ " III. \n"))
g_test_fail ();
}
@@ -758,7 +812,7 @@ test_list_multi_plain (TestFixture *fixture)
" * item 2\n"
" I. item 3\n"
" II. item 4\n"
- " III. "))
+ " III. \n"))
g_test_fail ();
}
@@ -789,7 +843,7 @@ test_list_multi_change_html (TestFixture *fixture)
" 2. item 2\n"
" 3. item 3\n"
" 4. item 4\n"
- " 5. "))
+ " 5. \n"))
g_test_fail ();
}
@@ -812,410 +866,3046 @@ test_list_multi_change_plain (TestFixture *fixture)
" 2. item 2\n"
" 3. item 3\n"
" 4. item 4\n"
- " 5. "))
+ " 5. \n"))
g_test_fail ();
}
static void
-test_link_insert_dialog (TestFixture *fixture)
+test_list_indent_same (TestFixture *fixture,
+ gboolean is_html)
{
- if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "type:a link example: \n"
- "action:insert-link\n"
- "type:http://www.gnome.org\n"
- "seq:n\n",
- HTML_PREFIX "<div>a link example: <a
href=\"http://www.gnome.org\">http://www.gnome.org</a></div>" HTML_SUFFIX,
- "a link example: http://www.gnome.org"))
- g_test_fail ();
-}
+ const gchar *unindented_html, *unindented_plain;
+
+ unindented_html =
+ HTML_PREFIX
+ "<ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ HTML_SUFFIX;
+
+ unindented_plain =
+ " * a\n"
+ " * b\n"
+ " * c\n"
+ " * d\n";
-static void
-test_link_insert_dialog_selection (TestFixture *fixture)
-{
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "type:a link example: GNOME\n"
- "seq:CSlsc\n"
- "action:insert-link\n"
- "type:http://www.gnome.org\n"
- "seq:n\n",
- HTML_PREFIX "<div>a link example: <a href=\"http://www.gnome.org\">GNOME</a></div>"
HTML_SUFFIX,
- "a link example: GNOME"))
+ "action:style-list-bullet\n"
+ "type:a\\n\n"
+ "type:b\\n\n"
+ "type:c\\n\n"
+ "type:d\\n\n"
+ "seq:nb\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
g_test_fail ();
-}
+ return;
+ }
+
+ /* Changing all items */
-static void
-test_link_insert_typed (TestFixture *fixture)
-{
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "type:www.gnome.org \n",
- HTML_PREFIX "<div><a href=\"http://www.gnome.org\">www.gnome.org</a> </div>" HTML_SUFFIX,
- "www.gnome.org "))
+ "undo:save\n" /* 1 */
+ "seq:uuuSddds\n"
+ "action:unindent\n"
+ "action:style-preformat\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>a</pre>"
+ "<pre>b</pre>"
+ "<pre>c</pre>"
+ "<pre>d</pre>"
+ HTML_SUFFIX,
+ "a\n"
+ "b\n"
+ "c\n"
+ "d\n")) {
g_test_fail ();
-}
+ return;
+ }
-static void
-test_link_insert_typed_change_description (TestFixture *fixture)
-{
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "type:www.gnome.org \n"
- "seq:ll\n"
- "action:insert-link\n"
- "seq:A\n" /* Alt+D to jump to the Description */
- "type:D\n"
- "seq:a\n"
- "type:GNOME\n"
- "seq:n\n",
- HTML_PREFIX "<div><a href=\"http://www.gnome.org\">GNOME</a> </div>" HTML_SUFFIX,
- "GNOME "))
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:drop:1\n" /* 1 */
+ "action:indent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ "</ul>"
+ HTML_SUFFIX,
+ " - a\n"
+ " - b\n"
+ " - c\n"
+ " - d\n")) {
g_test_fail ();
-}
+ return;
+ }
-static void
-test_link_insert_dialog_remove_link (TestFixture *fixture)
-{
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "type:www.gnome.org \n"
- "seq:ll\n"
- "action:insert-link\n"
- "seq:A\n" /* Alt+R to press the 'Remove Link' */
- "type:R\n"
- "seq:a\n",
- HTML_PREFIX "<div>www.gnome.org </div>" HTML_SUFFIX,
- "www.gnome.org "))
+ "undo:save\n" /* 2 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
g_test_fail ();
-}
+ return;
+ }
-static void
-test_link_insert_typed_append (TestFixture *fixture)
-{
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "type:www.gnome.org \n"
- "seq:l\n"
- "type:/about\n",
- HTML_PREFIX "<div><a href=\"http://www.gnome.org/\">www.gnome.org/about</a> </div>"
HTML_SUFFIX,
- "www.gnome.org/about "))
+ "undo:test:2\n"
+ "undo:undo\n"
+ "undo:test\n"
+ "undo:redo\n"
+ "undo:test:2\n"
+ "undo:drop:2\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
g_test_fail ();
-}
+ return;
+ }
+
+ /* Changing first item, single select */
-static void
-test_link_insert_typed_remove (TestFixture *fixture)
-{
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "type:www.gnome.org \n"
- "seq:bbb\n",
- HTML_PREFIX "<div><a href=\"http://www.gnome.org\">www.gnome.o</a></div>" HTML_SUFFIX,
- "www.gnome.o"))
+ "undo:save\n" /* 1 */
+ "seq:uuu\n"
+ "action:unindent\n"
+ "action:style-preformat\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>a</pre>"
+ "<ul>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ HTML_SUFFIX,
+ "a\n"
+ " * b\n"
+ " * c\n"
+ " * d\n")) {
g_test_fail ();
-}
+ return;
+ }
-static void
-test_h_rule_insert (TestFixture *fixture)
-{
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "type:text\n"
- "action:insert-rule\n"
- "seq:^\n", /* Escape key press to close the dialog */
- HTML_PREFIX "<div>text</div><hr align=\"left\" size=\"2\" noshade=\"\">" HTML_SUFFIX,
- "text"))
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:drop:1\n" /* 1 */
+ "action:indent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<ul><li>a</li></ul>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ HTML_SUFFIX,
+ " - a\n"
+ " * b\n"
+ " * c\n"
+ " * d\n")) {
g_test_fail ();
-}
+ return;
+ }
-static void
-test_h_rule_insert_text_after (TestFixture *fixture)
-{
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "type:above\n"
- "action:insert-rule\n"
- "seq:tttttn\n" /* Move to the Close button and press it */
- "seq:drn\n" /* Press the right key instead of End key as the End key won't move caret after
the HR element */
- "type:below\n",
- HTML_PREFIX "<div>above</div><hr align=\"left\" size=\"2\" noshade=\"\"><div>below</div>"
HTML_SUFFIX,
- "above\nbelow"))
+ "undo:save\n" /* 2 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
g_test_fail ();
-}
-
-static void
-test_image_insert (TestFixture *fixture)
-{
- EContentEditor *cnt_editor;
- gchar *expected_html;
- gchar *filename;
- gchar *image_data_base64;
- gchar *uri;
- GError *error = NULL;
+ return;
+ }
- if (!test_utils_process_commands (fixture,
- "mode:html\n"
- "type:before*\n")) {
+ if (!test_utils_run_simple_test (fixture,
+ "undo:test:2\n"
+ "undo:undo\n"
+ "undo:test\n"
+ "undo:redo\n"
+ "undo:test:2\n"
+ "undo:drop:2\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
g_test_fail ();
return;
}
- filename = g_build_filename (EVOLUTION_TESTTOPSRCDIR, "data", "icons",
"hicolor_actions_24x24_stock_people.png", NULL);
- uri = g_filename_to_uri (filename, NULL, &error);
- g_assert_no_error (error);
-
- /* Mimic what the action:insert-image does, without invoking the image chooser dialog */
- cnt_editor = e_html_editor_get_content_editor (fixture->editor);
- e_content_editor_insert_image (cnt_editor, uri);
- /* Wait some time until the operation is finished */
- test_utils_wait_milliseconds (500);
-
- image_data_base64 = test_utils_get_base64_data_for_image (filename);
-
- g_free (uri);
- g_free (filename);
-
- g_return_if_fail (image_data_base64 != NULL);
-
- expected_html = g_strconcat (HTML_PREFIX "<div>before*<img src=\"data:image/png;base64,",
- image_data_base64, "\">+after</div>" HTML_SUFFIX, NULL);
-
- g_free (image_data_base64);
+ /* Changing mid item, single select */
if (!test_utils_run_simple_test (fixture,
"undo:save\n" /* 1 */
- "undo:undo\n"
- "undo:redo\n"
- "undo:test:1\n"
- "type:+after\n",
- expected_html,
- "before*+after"))
+ "seq:dh\n"
+ "action:unindent\n"
+ "action:style-preformat\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<li>a</li>"
+ "</ul>"
+ "<pre>b</pre>"
+ "<ul>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ HTML_SUFFIX,
+ " * a\n"
+ "b\n"
+ " * c\n"
+ " * d\n")) {
g_test_fail ();
-
- g_free (expected_html);
-}
-
-static void
-test_emoticon_insert_typed (TestFixture *fixture)
-{
- gchar *image_data_base64;
- gchar *expected_html;
-
- test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail",
"composer-magic-smileys", TRUE);
- test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail",
"composer-unicode-smileys", FALSE);
-
- image_data_base64 = test_utils_get_base64_data_for_image ("face-smile");
-
- expected_html = g_strconcat (HTML_PREFIX "<div>before <img src=\"data:image/png;base64,",
- image_data_base64, "\" alt=\":-)\">after</div>" HTML_SUFFIX, NULL);
-
- g_free (image_data_base64);
+ return;
+ }
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "type:before :)after\n",
- expected_html,
- "before :-)after"))
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:drop:1\n" /* 1 */
+ "action:indent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<li>a</li>"
+ "<ul><li>b</li></ul>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ HTML_SUFFIX,
+ " * a\n"
+ " - b\n"
+ " * c\n"
+ " * d\n")) {
g_test_fail ();
+ return;
+ }
- g_free (expected_html);
-}
-
-static void
-test_emoticon_insert_typed_dash (TestFixture *fixture)
-{
- gchar *image_data_base64;
- gchar *expected_html;
-
- test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail",
"composer-magic-smileys", TRUE);
- test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail",
"composer-unicode-smileys", FALSE);
-
- image_data_base64 = test_utils_get_base64_data_for_image ("face-smile");
-
- expected_html = g_strconcat (HTML_PREFIX "<div>before <img src=\"data:image/png;base64,",
- image_data_base64, "\" alt=\":-)\">after</div>" HTML_SUFFIX, NULL);
-
- g_free (image_data_base64);
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "type:before :-)after\n",
- expected_html,
- "before :-)after"))
+ "undo:test:2\n"
+ "undo:undo\n"
+ "undo:test\n"
+ "undo:redo\n"
+ "undo:test:2\n"
+ "undo:drop:2\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
g_test_fail ();
+ return;
+ }
- g_free (expected_html);
-}
+ /* Changing last item, single select */
-static void
-test_paragraph_normal_selection (TestFixture *fixture)
-{
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "action:style-preformat\n"
- "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\\n\n"
- "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n"
- "seq:hu\n"
- "action:style-normal\n",
- HTML_PREFIX "<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero.</div>"
- "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</pre>" HTML_SUFFIX,
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
- "odio. Praesent libero.\n"
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.")) {
+ "undo:save\n" /* 1 */
+ "seq:dd\n"
+ "action:unindent\n"
+ "action:style-preformat\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "</ul>"
+ "<pre>d</pre>"
+ HTML_SUFFIX,
+ " * a\n"
+ " * b\n"
+ " * c\n"
+ "d\n")) {
g_test_fail ();
return;
}
if (!test_utils_run_simple_test (fixture,
- "mode:plain\n",
- HTML_PREFIX "<div style=\"width: 71ch;\">Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Integer nec odio. Praesent libero.</div>"
- "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</pre>" HTML_SUFFIX,
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
- "odio. Praesent libero.\n"
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.")) {
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:drop:1\n" /* 1 */
+ "action:indent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "<ul><li>d</li></ul>"
+ "</ul>"
+ HTML_SUFFIX,
+ " * a\n"
+ " * b\n"
+ " * c\n"
+ " - d\n")) {
g_test_fail ();
return;
}
if (!test_utils_run_simple_test (fixture,
- "mode:html\n",
- HTML_PREFIX "<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero.</div>"
- "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</pre>" HTML_SUFFIX,
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
- "odio. Praesent libero.\n"
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.")) {
+ "undo:save\n" /* 2 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
g_test_fail ();
return;
}
-}
-static void
-test_paragraph_normal_typed (TestFixture *fixture)
-{
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "action:style-normal\n"
- "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\\n\n"
- "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n",
- HTML_PREFIX "<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero.</div>"
- "<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</div>" HTML_SUFFIX,
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
- "odio. Praesent libero.\n"
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
- "odio. Praesent libero.")) {
+ "undo:test:2\n"
+ "undo:undo\n"
+ "undo:test\n"
+ "undo:redo\n"
+ "undo:test:2\n"
+ "undo:drop:2\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
g_test_fail ();
return;
}
+ /* Changing first items, multi-select */
+
if (!test_utils_run_simple_test (fixture,
- "mode:plain\n",
- HTML_PREFIX "<div style=\"width: 71ch;\">Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Integer nec odio. Praesent libero.</div>"
- "<div style=\"width: 71ch;\">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
nec odio. Praesent libero.</div>" HTML_SUFFIX,
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
- "odio. Praesent libero.\n"
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
- "odio. Praesent libero.")) {
+ "undo:save\n" /* 1 */
+ "seq:uuuhSdes\n"
+ "action:unindent\n"
+ "action:style-preformat\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>a</pre>"
+ "<pre>b</pre>"
+ "<ul>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ HTML_SUFFIX,
+ "a\n"
+ "b\n"
+ " * c\n"
+ " * d\n")) {
g_test_fail ();
return;
}
if (!test_utils_run_simple_test (fixture,
- "mode:html\n",
- HTML_PREFIX "<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero.</div>"
- "<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</div>" HTML_SUFFIX,
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
- "odio. Praesent libero.\n"
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
- "odio. Praesent libero.")) {
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:drop:1\n" /* 1 */
+ "action:indent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<ul><li>a</li>"
+ "<li>b</li></ul>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ HTML_SUFFIX,
+ " - a\n"
+ " - b\n"
+ " * c\n"
+ " * d\n")) {
g_test_fail ();
return;
}
-}
-static void
-test_paragraph_preformatted_selection (TestFixture *fixture)
-{
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "action:style-normal\n"
- "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\\n\n"
- "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n"
- "seq:Chc\n"
- "action:style-preformat\n",
- HTML_PREFIX "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero.</pre>"
- "<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</div>" HTML_SUFFIX,
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n"
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
- "odio. Praesent libero.")) {
+ "undo:save\n" /* 2 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
g_test_fail ();
return;
}
if (!test_utils_run_simple_test (fixture,
- "mode:plain\n",
- HTML_PREFIX "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero.</pre>"
- "<div style=\"width: 71ch;\">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
nec odio. Praesent libero.</div>" HTML_SUFFIX,
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n"
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
- "odio. Praesent libero.")) {
+ "undo:test:2\n"
+ "undo:undo\n"
+ "undo:test\n"
+ "undo:redo\n"
+ "undo:test:2\n"
+ "undo:drop:2\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
g_test_fail ();
return;
}
+ /* Changing mid items, multi-select */
+
if (!test_utils_run_simple_test (fixture,
- "mode:html\n",
- HTML_PREFIX "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero.</pre>"
- "<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</div>" HTML_SUFFIX,
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n"
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
- "odio. Praesent libero.")) {
+ "undo:save\n" /* 1 */
+ "seq:duhSdes\n"
+ "action:unindent\n"
+ "action:style-preformat\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<li>a</li>"
+ "</ul>"
+ "<pre>b</pre>"
+ "<pre>c</pre>"
+ "<ul>"
+ "<li>d</li>"
+ "</ul>"
+ HTML_SUFFIX,
+ " * a\n"
+ "b\n"
+ "c\n"
+ " * d\n")) {
g_test_fail ();
return;
}
-}
-static void
-test_paragraph_preformatted_typed (TestFixture *fixture)
-{
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "action:style-preformat\n"
- "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero. \n"
- "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n",
- HTML_PREFIX "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero."
- " Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</pre>" HTML_SUFFIX,
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. "
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.")) {
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:drop:1\n" /* 1 */
+ "action:indent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<li>a</li>"
+ "<ul><li>b</li>"
+ "<li>c</li></ul>"
+ "<li>d</li>"
+ "</ul>"
+ HTML_SUFFIX,
+ " * a\n"
+ " - b\n"
+ " - c\n"
+ " * d\n")) {
g_test_fail ();
return;
}
if (!test_utils_run_simple_test (fixture,
- "mode:plain\n",
- HTML_PREFIX "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero."
- " Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</pre>" HTML_SUFFIX,
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. "
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.")) {
+ "undo:save\n" /* 2 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
g_test_fail ();
return;
}
if (!test_utils_run_simple_test (fixture,
- "mode:html\n",
- HTML_PREFIX "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero."
- " Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</pre>" HTML_SUFFIX,
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. "
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.")) {
+ "undo:test:2\n"
+ "undo:undo\n"
+ "undo:test\n"
+ "undo:redo\n"
+ "undo:test:2\n"
+ "undo:drop:2\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
g_test_fail ();
return;
}
-}
-static void
-test_paragraph_address_selection (TestFixture *fixture)
-{
+ /* Changing last items, multi-select */
+
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
+ "undo:save\n" /* 1 */
+ "seq:dhSues\n"
+ "action:unindent\n"
+ "action:style-preformat\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "</ul>"
+ "<pre>c</pre>"
+ "<pre>d</pre>"
+ HTML_SUFFIX,
+ " * a\n"
+ " * b\n"
+ "c\n"
+ "d\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:drop:1\n" /* 1 */
+ "action:indent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "<ul><li>c</li>"
+ "<li>d</li></ul>"
+ "</ul>"
+ HTML_SUFFIX,
+ " * a\n"
+ " * b\n"
+ " - c\n"
+ " - d\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:test:2\n"
+ "undo:undo\n"
+ "undo:test\n"
+ "undo:redo\n"
+ "undo:test:2\n"
+ "undo:drop:2\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* The same tests as above, only with added text above and below the list */
+
+ unindented_html =
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX;
+
+ unindented_plain =
+ "prefix\n"
+ " * a\n"
+ " * b\n"
+ " * c\n"
+ " * d\n"
+ "suffix\n";
+
+ if (!test_utils_run_simple_test (fixture,
+ "action:select-all\n"
+ "seq:D\n"
+ "action:style-preformat\n"
+ "type:prefix\\n\n"
+ "action:style-list-bullet\n"
+ "type:a\\n\n"
+ "type:b\\n\n"
+ "type:c\\n\n"
+ "type:d\\n\n"
+ "seq:n\n"
+ "action:style-preformat\n"
+ "type:suffix\n"
+ "seq:u\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* Changing all items */
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 1 */
+ "seq:uuuhSdddes\n"
+ "action:unindent\n"
+ "action:style-preformat\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<pre>a</pre>"
+ "<pre>b</pre>"
+ "<pre>c</pre>"
+ "<pre>d</pre>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ "a\n"
+ "b\n"
+ "c\n"
+ "d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:drop:1\n" /* 1 */
+ "action:indent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ul>"
+ "<ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ "</ul>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " - a\n"
+ " - b\n"
+ " - c\n"
+ " - d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:test:2\n"
+ "undo:undo\n"
+ "undo:test\n"
+ "undo:redo\n"
+ "undo:test:2\n"
+ "undo:drop:2\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* Changing first item, single select */
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 1 */
+ "seq:uuu\n"
+ "action:unindent\n"
+ "action:style-preformat\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<pre>a</pre>"
+ "<ul>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ "a\n"
+ " * b\n"
+ " * c\n"
+ " * d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:drop:1\n" /* 1 */
+ "action:indent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ul>"
+ "<ul><li>a</li></ul>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " - a\n"
+ " * b\n"
+ " * c\n"
+ " * d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:test:2\n"
+ "undo:undo\n"
+ "undo:test\n"
+ "undo:redo\n"
+ "undo:test:2\n"
+ "undo:drop:2\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* Changing mid item, single select */
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 1 */
+ "seq:dh\n"
+ "action:unindent\n"
+ "action:style-preformat\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ul>"
+ "<li>a</li>"
+ "</ul>"
+ "<pre>b</pre>"
+ "<ul>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " * a\n"
+ "b\n"
+ " * c\n"
+ " * d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:drop:1\n" /* 1 */
+ "action:indent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ul>"
+ "<li>a</li>"
+ "<ul><li>b</li></ul>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " * a\n"
+ " - b\n"
+ " * c\n"
+ " * d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:test:2\n"
+ "undo:undo\n"
+ "undo:test\n"
+ "undo:redo\n"
+ "undo:test:2\n"
+ "undo:drop:2\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* Changing last item, single select */
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 1 */
+ "seq:ddh\n"
+ "action:unindent\n"
+ "action:style-preformat\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "</ul>"
+ "<pre>d</pre>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " * a\n"
+ " * b\n"
+ " * c\n"
+ "d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:drop:1\n" /* 1 */
+ "action:indent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "<ul><li>d</li></ul>"
+ "</ul>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " * a\n"
+ " * b\n"
+ " * c\n"
+ " - d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:test:2\n"
+ "undo:undo\n"
+ "undo:test\n"
+ "undo:redo\n"
+ "undo:test:2\n"
+ "undo:drop:2\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* Changing first items, multi-select */
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 1 */
+ "seq:uuuhSdes\n"
+ "action:unindent\n"
+ "action:style-preformat\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<pre>a</pre>"
+ "<pre>b</pre>"
+ "<ul>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ "a\n"
+ "b\n"
+ " * c\n"
+ " * d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:drop:1\n" /* 1 */
+ "action:indent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ul>"
+ "<ul><li>a</li>"
+ "<li>b</li></ul>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " - a\n"
+ " - b\n"
+ " * c\n"
+ " * d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:test:2\n"
+ "undo:undo\n"
+ "undo:test\n"
+ "undo:redo\n"
+ "undo:test:2\n"
+ "undo:drop:2\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* Changing mid items, multi-select */
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 1 */
+ "seq:duhSdes\n"
+ "action:unindent\n"
+ "action:style-preformat\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ul>"
+ "<li>a</li>"
+ "</ul>"
+ "<pre>b</pre>"
+ "<pre>c</pre>"
+ "<ul>"
+ "<li>d</li>"
+ "</ul>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " * a\n"
+ "b\n"
+ "c\n"
+ " * d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:drop:1\n" /* 1 */
+ "action:indent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ul>"
+ "<li>a</li>"
+ "<ul><li>b</li>"
+ "<li>c</li></ul>"
+ "<li>d</li>"
+ "</ul>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " * a\n"
+ " - b\n"
+ " - c\n"
+ " * d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:test:2\n"
+ "undo:undo\n"
+ "undo:test\n"
+ "undo:redo\n"
+ "undo:test:2\n"
+ "undo:drop:2\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* Changing last items, multi-select */
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 1 */
+ "seq:deSuhs\n"
+ "action:unindent\n"
+ "action:style-preformat\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "</ul>"
+ "<pre>c</pre>"
+ "<pre>d</pre>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " * a\n"
+ " * b\n"
+ "c\n"
+ "d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:drop:1\n" /* 1 */
+ "action:indent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "<ul><li>c</li>"
+ "<li>d</li></ul>"
+ "</ul>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " * a\n"
+ " * b\n"
+ " - c\n"
+ " - d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:test:2\n"
+ "undo:undo\n"
+ "undo:test\n"
+ "undo:redo\n"
+ "undo:test:2\n",
+ !is_html ? NULL : unindented_html, unindented_plain))
+ g_test_fail ();
+}
+
+static void
+test_list_indent_same_html (TestFixture *fixture)
+{
+ if (!test_utils_process_commands (fixture, "mode:html\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_list_indent_same (fixture, TRUE);
+}
+
+static void
+test_list_indent_same_plain (TestFixture *fixture)
+{
+ if (!test_utils_process_commands (fixture, "mode:plain\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_list_indent_same (fixture, FALSE);
+}
+
+static void
+test_list_indent_different (TestFixture *fixture,
+ gboolean is_html)
+{
+ const gchar *unindented_html, *unindented_plain;
+
+ unindented_html =
+ HTML_PREFIX
+ "<ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ HTML_SUFFIX;
+
+ unindented_plain =
+ " * a\n"
+ " * b\n"
+ " * c\n"
+ " * d\n";
+
+ if (!test_utils_run_simple_test (fixture,
+ "action:style-list-bullet\n"
+ "type:a\\n\n"
+ "type:b\\n\n"
+ "type:c\\n\n"
+ "type:d\\n\n"
+ "seq:nb\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* Changing first item, single select */
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 1 */
+ "seq:uuu\n"
+ "action:indent\n"
+ "action:style-list-number\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<ol><li>a</li></ol>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ HTML_SUFFIX,
+ " 1. a\n"
+ " * b\n"
+ " * c\n"
+ " * d\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ol><li>a</li></ol>"
+ "<ul>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ HTML_SUFFIX,
+ " 1. a\n"
+ " * b\n"
+ " * c\n"
+ " * d\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 3 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "undo:drop:3\n"
+ "undo:undo:3\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* Changing mid item, single select */
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 1 */
+ "seq:d\n"
+ "action:indent\n"
+ "action:style-list-alpha\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<li>a</li>"
+ "<ol type=\"A\"><li>b</li></ol>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ HTML_SUFFIX,
+ " * a\n"
+ " A. b\n"
+ " * c\n"
+ " * d\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<li>a</li>"
+ "</ul>"
+ "<ol type=\"A\"><li>b</li></ol>"
+ "<ul>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ HTML_SUFFIX,
+ " * a\n"
+ " A. b\n"
+ " * c\n"
+ " * d\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 3 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "undo:drop:3\n"
+ "undo:undo:3\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* Changing last item, single select */
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 1 */
+ "seq:dd\n"
+ "action:indent\n"
+ "action:style-list-roman\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "<ol type=\"I\"><li>d</li></ol>"
+ "</ul>"
+ HTML_SUFFIX,
+ " * a\n"
+ " * b\n"
+ " * c\n"
+ " I. d\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "</ul>"
+ "<ol type=\"I\"><li>d</li></ol>"
+ HTML_SUFFIX,
+ " * a\n"
+ " * b\n"
+ " * c\n"
+ " I. d\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 3 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "undo:drop:3\n"
+ "undo:undo:3\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* Changing first items, multi-select */
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 1 */
+ "seq:uuuhSdes\n"
+ "action:indent\n"
+ "action:style-list-number\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<ol>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "</ol>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ HTML_SUFFIX,
+ " 1. a\n"
+ " 2. b\n"
+ " * c\n"
+ " * d\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ol>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "</ol>"
+ "<ul>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ul>"
+ HTML_SUFFIX,
+ " 1. a\n"
+ " 2. b\n"
+ " * c\n"
+ " * d\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 3 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "undo:drop:3\n"
+ "undo:undo:3\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* Changing mid items, multi-select */
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 1 */
+ "seq:duhSdes\n"
+ "action:indent\n"
+ "action:style-list-alpha\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<li>a</li>"
+ "<ol type=\"A\">"
+ "<li>b</li>"
+ "<li>c</li>"
+ "</ol>"
+ "<li>d</li>"
+ "</ul>"
+ HTML_SUFFIX,
+ " * a\n"
+ " A. b\n"
+ " B. c\n"
+ " * d\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<li>a</li>"
+ "</ul>"
+ "<ol type=\"A\">"
+ "<li>b</li>"
+ "<li>c</li>"
+ "</ol>"
+ "<ul>"
+ "<li>d</li>"
+ "</ul>"
+ HTML_SUFFIX,
+ " * a\n"
+ " A. b\n"
+ " B. c\n"
+ " * d\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 3 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "undo:drop:3\n"
+ "undo:undo:3\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* Changing last items, multi-select */
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 1 */
+ "seq:deSuhs\n"
+ "action:indent\n"
+ "action:style-list-roman\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "<ol type=\"I\">"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ol>"
+ "</ul>"
+ HTML_SUFFIX,
+ " * a\n"
+ " * b\n"
+ " I. c\n"
+ " II. d\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "</ul>"
+ "<ol type=\"I\">"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ol>"
+ HTML_SUFFIX,
+ " * a\n"
+ " * b\n"
+ " I. c\n"
+ " II. d\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 3 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "undo:drop:3\n"
+ "undo:undo:3\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* The same tests as above, only with added text above and below the list */
+
+ unindented_html =
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ol>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ol>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX;
+
+ unindented_plain =
+ "prefix\n"
+ " 1. a\n"
+ " 2. b\n"
+ " 3. c\n"
+ " 4. d\n"
+ "suffix\n";
+
+ if (!test_utils_run_simple_test (fixture,
+ "action:select-all\n"
+ "seq:D\n"
+ "action:style-preformat\n"
+ "type:prefix\\n\n"
+ "action:style-list-number\n"
+ "type:a\\n\n"
+ "type:b\\n\n"
+ "type:c\\n\n"
+ "type:d\\n\n"
+ "seq:n\n"
+ "action:style-preformat\n"
+ "type:suffix\n"
+ "seq:ur\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* Changing first item, single select */
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 1 */
+ "seq:uuu\n"
+ "action:indent\n"
+ "action:style-list-bullet\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ol>"
+ "<ul><li>a</li></ul>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ol>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " - a\n"
+ " 1. b\n"
+ " 2. c\n"
+ " 3. d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ul><li>a</li></ul>"
+ "<ol>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ol>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " * a\n"
+ " 1. b\n"
+ " 2. c\n"
+ " 3. d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 3 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "undo:drop:3\n"
+ "undo:undo:3\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* Changing mid item, single select */
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 1 */
+ "seq:d\n"
+ "action:indent\n"
+ "action:style-list-alpha\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ol>"
+ "<li>a</li>"
+ "<ol type=\"A\"><li>b</li></ol>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ol>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " 1. a\n"
+ " A. b\n"
+ " 2. c\n"
+ " 3. d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ol>"
+ "<li>a</li>"
+ "</ol>"
+ "<ol type=\"A\"><li>b</li></ol>"
+ "<ol>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ol>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " 1. a\n"
+ " A. b\n"
+ " 1. c\n"
+ " 2. d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 3 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "undo:drop:3\n"
+ "undo:undo:3\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* Changing last item, single select */
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 1 */
+ "seq:dd\n"
+ "action:indent\n"
+ "action:style-list-roman\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ol>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "<ol type=\"I\"><li>d</li></ol>"
+ "</ol>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " 1. a\n"
+ " 2. b\n"
+ " 3. c\n"
+ " I. d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ol>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "</ol>"
+ "<ol type=\"I\"><li>d</li></ol>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " 1. a\n"
+ " 2. b\n"
+ " 3. c\n"
+ " I. d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 3 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "undo:drop:3\n"
+ "undo:undo:3\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* Changing first items, multi-select */
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 1 */
+ "seq:uuuhSdes\n"
+ "action:indent\n"
+ "action:style-list-bullet\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ol>"
+ "<ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "</ul>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ol>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " - a\n"
+ " - b\n"
+ " 1. c\n"
+ " 2. d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "</ul>"
+ "<ol>"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ol>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " * a\n"
+ " * b\n"
+ " 1. c\n"
+ " 2. d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 3 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "undo:drop:3\n"
+ "undo:undo:3\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* Changing mid items, multi-select */
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 1 */
+ "seq:duhSdes\n"
+ "action:indent\n"
+ "action:style-list-alpha\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ol>"
+ "<li>a</li>"
+ "<ol type=\"A\">"
+ "<li>b</li>"
+ "<li>c</li>"
+ "</ol>"
+ "<li>d</li>"
+ "</ol>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " 1. a\n"
+ " A. b\n"
+ " B. c\n"
+ " 2. d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ol>"
+ "<li>a</li>"
+ "</ol>"
+ "<ol type=\"A\">"
+ "<li>b</li>"
+ "<li>c</li>"
+ "</ol>"
+ "<ol>"
+ "<li>d</li>"
+ "</ol>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " 1. a\n"
+ " A. b\n"
+ " B. c\n"
+ " 1. d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 3 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "undo:drop:3\n"
+ "undo:undo:3\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ /* Changing last items, multi-select */
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 1 */
+ "seq:deSuhs\n"
+ "action:indent\n"
+ "action:style-list-roman\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ol>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "<ol type=\"I\">"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ol>"
+ "</ol>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " 1. a\n"
+ " 2. b\n"
+ " I. c\n"
+ " II. d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>prefix</pre>"
+ "<ol>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "</ol>"
+ "<ol type=\"I\">"
+ "<li>c</li>"
+ "<li>d</li>"
+ "</ol>"
+ "<pre>suffix</pre>"
+ HTML_SUFFIX,
+ "prefix\n"
+ " 1. a\n"
+ " 2. b\n"
+ " I. c\n"
+ " II. d\n"
+ "suffix\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 3 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "undo:drop:3\n"
+ "undo:undo:3\n",
+ !is_html ? NULL : unindented_html, unindented_plain))
+ g_test_fail ();
+}
+
+static void
+test_list_indent_different_html (TestFixture *fixture)
+{
+ if (!test_utils_process_commands (fixture, "mode:html\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_list_indent_different (fixture, TRUE);
+}
+
+static void
+test_list_indent_different_plain (TestFixture *fixture)
+{
+ if (!test_utils_process_commands (fixture, "mode:plain\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_list_indent_different (fixture, FALSE);
+}
+
+static void
+test_list_indent_multi (TestFixture *fixture,
+ gboolean is_html)
+{
+ const gchar *unindented_html, *unindented_plain;
+
+ unindented_html =
+ HTML_PREFIX
+ "<pre>line 1</pre>"
+ "<pre>line 2</pre>"
+ "<ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "</ul>"
+ "<pre>line 3</pre>"
+ "<ol>"
+ "<li>1</li>"
+ "<li>2</li>"
+ "</ol>"
+ "<pre>line 4</pre>"
+ "<ol type=\"A\">"
+ "<li>A</li>"
+ "<li>B</li>"
+ "</ol>"
+ "<pre>line 5</pre>"
+ "<ol type=\"I\">"
+ "<li>i</li>"
+ "<li>ii</li>"
+ "</ol>"
+ "<pre>line 6</pre>"
+ HTML_SUFFIX;
+
+ unindented_plain =
+ "line 1\n"
+ "line 2\n"
+ " * a\n"
+ " * b\n"
+ " * c\n"
+ "line 3\n"
+ " 1. 1\n"
+ " 2. 2\n"
+ "line 4\n"
+ " A. A\n"
+ " B. B\n"
+ "line 5\n"
+ " I. i\n"
+ " II. ii\n"
+ "line 6\n";
+
+ if (!test_utils_run_simple_test (fixture,
+ "action:style-preformat\n"
+ "type:line 1\\n\n"
+ "type:line 2\\n\n"
+ "action:style-list-bullet\n"
+ "type:a\\n\n"
+ "type:b\\n\n"
+ "type:c\\n\\n\n"
+ "action:style-preformat\n"
+ "type:line 3\\n\n"
+ "action:style-list-number\n"
+ "type:1\\n\n"
+ "type:2\\n\\n\n"
+ "action:style-preformat\n"
+ "type:line 4\\n\n"
+ "action:style-list-alpha\n"
+ "type:A\\n\n"
+ "type:B\\n\\n\n"
+ "action:style-preformat\n"
+ "type:line 5\\n\n"
+ "action:style-list-roman\n"
+ "type:i\\n\n"
+ "type:ii\\n\\n\n"
+ "action:style-preformat\n"
+ "type:line 6\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "action:select-all\n"
+ "undo:save\n" /* 1 */
+ "action:indent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre style=\"margin-left: 3ch;\">line 1</pre>"
+ "<pre style=\"margin-left: 3ch;\">line 2</pre>"
+ "<ul><ul>"
+ "<li>a</li>"
+ "<li>b</li>"
+ "<li>c</li>"
+ "</ul></ul>"
+ "<pre style=\"margin-left: 3ch;\">line 3</pre>"
+ "<ol><ol>"
+ "<li>1</li>"
+ "<li>2</li>"
+ "</ol></ol>"
+ "<pre style=\"margin-left: 3ch;\">line 4</pre>"
+ "<ol type=\"A\"><ol type=\"A\">"
+ "<li>A</li>"
+ "<li>B</li>"
+ "</ol></ol>"
+ "<pre style=\"margin-left: 3ch;\">line 5</pre>"
+ "<ol type=\"I\"><ol type=\"I\">"
+ "<li>i</li>"
+ "<li>ii</li>"
+ "</ol></ol>"
+ "<pre style=\"margin-left: 3ch;\">line 6</pre>"
+ HTML_SUFFIX,
+ " line 1\n"
+ " line 2\n"
+ " - a\n"
+ " - b\n"
+ " - c\n"
+ " line 3\n"
+ " 1. 1\n"
+ " 2. 2\n"
+ " line 4\n"
+ " A. A\n"
+ " B. B\n"
+ " line 5\n"
+ " I. i\n"
+ " II. ii\n"
+ " line 6\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "action:unindent\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:undo\n"
+ "undo:test:1\n"
+ "undo:redo\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "seq:Shur\n" /* To be able to unindent the selection should end inside the list */
+ "action:unindent\n"
+ "action:style-preformat\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>line 1</pre>"
+ "<pre>line 2</pre>"
+ "<pre>a</pre>"
+ "<pre>b</pre>"
+ "<pre>c</pre>"
+ "<pre>line 3</pre>"
+ "<pre>1</pre>"
+ "<pre>2</pre>"
+ "<pre>line 4</pre>"
+ "<pre>A</pre>"
+ "<pre>B</pre>"
+ "<pre>line 5</pre>"
+ "<pre>i</pre>"
+ "<pre>ii</pre>"
+ "<pre>line 6</pre>"
+ HTML_SUFFIX,
+ "line 1\n"
+ "line 2\n"
+ "a\n"
+ "b\n"
+ "c\n"
+ "line 3\n"
+ "1\n"
+ "2\n"
+ "line 4\n"
+ "A\n"
+ "B\n"
+ "line 5\n"
+ "i\n"
+ "ii\n"
+ "line 6\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 3 */
+ "undo:undo:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "undo:undo:2\n",
+ !is_html ? NULL : unindented_html, unindented_plain))
+ g_test_fail ();
+}
+
+static void
+test_list_indent_multi_html (TestFixture *fixture)
+{
+ if (!test_utils_process_commands (fixture, "mode:html\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_list_indent_multi (fixture, TRUE);
+}
+
+static void
+test_list_indent_multi_plain (TestFixture *fixture)
+{
+ if (!test_utils_process_commands (fixture, "mode:plain\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_list_indent_multi (fixture, FALSE);
+}
+
+static void
+test_list_indent_nested (TestFixture *fixture,
+ gboolean is_html)
+{
+ const gchar *unindented_html, *unindented_plain;
+
+ unindented_html =
+ HTML_PREFIX
+ "<pre>line 1</pre>"
+ "<ul>"
+ "<li>a</li>"
+ "<ol>"
+ "<li>123456789 123456789 123456789 123456789 123456789 123456789
123456789 123456789</li>"
+ "<li>2</li>"
+ "<ul>"
+ "<li>x</li>"
+ "<li>y</li>"
+ "</ul>"
+ "<li>3</li>"
+ "</ol>"
+ "<li>b</li>"
+ "</ul>"
+ "<pre>line 2</pre>"
+ "<ol>"
+ "<li>1</li>"
+ "<ul>"
+ "<li>a</li>"
+ "<ol type=\"A\">"
+ "<li>A</li>"
+ "<li>B</li>"
+ "</ol>"
+ "<li>b</li>"
+ "</ul>"
+ "<li>2</li>"
+ "</ol>"
+ "<pre>line 3</pre>"
+ HTML_SUFFIX;
+
+ unindented_plain =
+ "line 1\n"
+ " * a\n"
+ " 1. 123456789 123456789 123456789 123456789 123456789 123456789 123456789\n"
+ " 123456789\n"
+ " 2. 2\n"
+ " + x\n"
+ " + y\n"
+ " 3. 3\n"
+ " * b\n"
+ "line 2\n"
+ " 1. 1\n"
+ " - a\n"
+ " A. A\n"
+ " B. B\n"
+ " - b\n"
+ " 2. 2\n"
+ "line 3\n";
+
+ if (!test_utils_run_simple_test (fixture,
+ "action:style-preformat\n"
+ "type:line 1\\n\n"
+ "action:style-list-bullet\n"
+ "type:a\\n\n"
+ "action:indent\n"
+ "action:style-list-number\n"
+ "type:123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789\\n\n"
+ "type:2\\n\n"
+ "action:indent\n"
+ "action:style-list-bullet\n"
+ "type:x\\n\n"
+ "type:y\\n\\n\n"
+ "type:3\\n\\n\n"
+ "type:b\\n\\n\n"
+ "action:style-preformat\n"
+ "type:line 2\\n\n"
+ "action:style-list-number\n"
+ "type:1\\n\n"
+ "action:indent\n"
+ "action:style-list-bullet\n"
+ "type:a\\n\n"
+ "action:indent\n"
+ "action:style-list-alpha\n"
+ "type:A\\n\n"
+ "type:B\\n\\n\n"
+ "type:b\\n\\n\n"
+ "type:2\\n\\n\n"
+ "action:style-preformat\n"
+ "type:line 3\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "seq:hurSChcds\n" /* selects all but the "line 1" and "line 3" */
+ "undo:save\n" /* 1 */
+ "action:indent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>line 1</pre>"
+ "<ul><ul>"
+ "<li>a</li>"
+ "<ol>"
+ "<li>123456789 123456789 123456789 123456789 123456789 123456789
123456789 123456789</li>"
+ "<li>2</li>"
+ "<ul>"
+ "<li>x</li>"
+ "<li>y</li>"
+ "</ul>"
+ "<li>3</li>"
+ "</ol>"
+ "<li>b</li>"
+ "</ul></ul>"
+ "<pre style=\"margin-left: 3ch;\">line 2</pre>"
+ "<ol><ol>"
+ "<li>1</li>"
+ "<ul>"
+ "<li>a</li>"
+ "<ol type=\"A\">"
+ "<li>A</li>"
+ "<li>B</li>"
+ "</ol>"
+ "<li>b</li>"
+ "</ul>"
+ "<li>2</li>"
+ "</ol></ol>"
+ "<pre>line 3</pre>"
+ HTML_SUFFIX,
+ "line 1\n"
+ " - a\n"
+ " 1. 123456789 123456789 123456789 123456789 123456789 123456789 123456789\n"
+ " 123456789\n"
+ " 2. 2\n"
+ " * x\n"
+ " * y\n"
+ " 3. 3\n"
+ " - b\n"
+ " line 2\n"
+ " 1. 1\n"
+ " + a\n"
+ " A. A\n"
+ " B. B\n"
+ " + b\n"
+ " 2. 2\n"
+ "line 3\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "undo:drop:2\n" /* 0 */
+ "undo:save\n" /* 1 */
+ "action:unindent\n",
+ !is_html ? NULL : unindented_html, unindented_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "undo:drop:2\n" /* 0 */
+ "undo:save\n" /* 1 */
+ "action:unindent\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>line 1</pre>"
+ "<div>a</div>"
+ "<ol>"
+ "<li>123456789 123456789 123456789 123456789 123456789 123456789 123456789
123456789</li>"
+ "<li>2</li>"
+ "<ul>"
+ "<li>x</li>"
+ "<li>y</li>"
+ "</ul>"
+ "<li>3</li>"
+ "</ol>"
+ "<div>b</div>"
+ "<pre>line 2</pre>"
+ "<div>1</div>"
+ "<ul>"
+ "<li>a</li>"
+ "<ol type=\"A\">"
+ "<li>A</li>"
+ "<li>B</li>"
+ "</ol>"
+ "<li>b</li>"
+ "</ul>"
+ "<div>2</div>"
+ "<pre>line 3</pre>"
+ HTML_SUFFIX,
+ "line 1\n"
+ "a\n"
+ " 1. 123456789 123456789 123456789 123456789 123456789 123456789 123456789\n"
+ " 123456789\n"
+ " 2. 2\n"
+ " - x\n"
+ " - y\n"
+ " 3. 3\n"
+ "b\n"
+ "line 2\n"
+ "1\n"
+ " * a\n"
+ " A. A\n"
+ " B. B\n"
+ " * b\n"
+ "2\n"
+ "line 3\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "undo:drop:2\n" /* 0 */
+ "undo:save\n" /* 1 */
+ "seq:CecuueSChcdds\n"
+ "action:unindent\n"
+ "seq:CecuuueSChcddds\n"
+ "action:unindent\n"
+ "action:select-all\n"
+ "action:style-normal\n"
+ "action:style-preformat\n",
+ !is_html ? NULL :
+ HTML_PREFIX
+ "<pre>line 1</pre>"
+ "<pre>a</pre>"
+ "<pre>123456789 123456789 123456789 123456789 123456789 123456789 123456789
123456789</pre>"
+ "<pre>2</pre>"
+ "<pre>x</pre>"
+ "<pre>y</pre>"
+ "<pre>3</pre>"
+ "<pre>b</pre>"
+ "<pre>line 2</pre>"
+ "<pre>1</pre>"
+ "<pre>a</pre>"
+ "<pre>A</pre>"
+ "<pre>B</pre>"
+ "<pre>b</pre>"
+ "<pre>2</pre>"
+ "<pre>line 3</pre>"
+ HTML_SUFFIX,
+ "line 1\n"
+ "a\n"
+ "123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789\n"
+ "2\n"
+ "x\n"
+ "y\n"
+ "3\n"
+ "b\n"
+ "line 2\n"
+ "1\n"
+ "a\n"
+ "A\n"
+ "B\n"
+ "b\n"
+ "2\n"
+ "line 3\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_process_commands (fixture,
+ "undo:save\n" /* 2 */
+ "undo:undo:4\n"
+ "undo:test:2\n"
+ "undo:redo:4\n"
+ "undo:test\n"))
+ g_test_fail ();
+}
+
+static void
+test_list_indent_nested_html (TestFixture *fixture)
+{
+ if (!test_utils_process_commands (fixture, "mode:html\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_list_indent_nested (fixture, TRUE);
+}
+
+static void
+test_list_indent_nested_plain (TestFixture *fixture)
+{
+ if (!test_utils_process_commands (fixture, "mode:plain\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_list_indent_nested (fixture, FALSE);
+}
+
+static void
+test_link_insert_dialog (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:a link example: \n"
+ "action:insert-link\n"
+ "type:http://www.gnome.org\n"
+ "seq:n\n",
+ HTML_PREFIX "<div>a link example: <a
href=\"http://www.gnome.org\">http://www.gnome.org</a></div>" HTML_SUFFIX,
+ "a link example: http://www.gnome.org\n"))
+ g_test_fail ();
+}
+
+static void
+test_link_insert_dialog_selection (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:a link example: GNOME\n"
+ "seq:CSlsc\n"
+ "action:insert-link\n"
+ "type:http://www.gnome.org\n"
+ "seq:n\n",
+ HTML_PREFIX "<div>a link example: <a href=\"http://www.gnome.org\">GNOME</a></div>"
HTML_SUFFIX,
+ "a link example: GNOME\n"))
+ g_test_fail ();
+}
+
+static void
+test_link_insert_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:www.gnome.org \n",
+ HTML_PREFIX "<div><a href=\"https://www.gnome.org\">www.gnome.org</a> </div>" HTML_SUFFIX,
+ "www.gnome.org \n"))
+ g_test_fail ();
+}
+
+static void
+test_link_insert_typed_change_description (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:www.gnome.org \n"
+ "seq:ll\n"
+ "action:insert-link\n"
+ "seq:A\n" /* Alt+D to jump to the Description */
+ "type:D\n"
+ "seq:a\n"
+ "type:GNOME\n"
+ "seq:n\n",
+ HTML_PREFIX "<div><a href=\"https://www.gnome.org\">GNOME</a> </div>" HTML_SUFFIX,
+ "GNOME \n"))
+ g_test_fail ();
+}
+
+static void
+test_link_insert_dialog_remove_link (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:www.gnome.org \n"
+ "seq:ll\n"
+ "action:insert-link\n"
+ "seq:A\n" /* Alt+R to press the 'Remove Link' */
+ "type:R\n"
+ "seq:a\n",
+ HTML_PREFIX "<div>www.gnome.org </div>" HTML_SUFFIX,
+ "www.gnome.org \n"))
+ g_test_fail ();
+}
+
+static void
+test_link_insert_typed_append (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:www.gnome.org \n"
+ "seq:l\n"
+ "type:/about\n",
+ HTML_PREFIX "<div><a href=\"https://www.gnome.org\">www.gnome.org/about</a> </div>"
HTML_SUFFIX,
+ "www.gnome.org/about \n"))
+ g_test_fail ();
+}
+
+static void
+test_link_insert_typed_remove (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:www.gnome.org \n"
+ "seq:bbb\n",
+ HTML_PREFIX "<div><a href=\"https://www.gnome.org\">www.gnome.o</a></div>" HTML_SUFFIX,
+ "www.gnome.o\n"))
+ g_test_fail ();
+}
+
+static void
+test_h_rule_insert (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:text\n"
+ "action:insert-rule\n"
+ "seq:^\n", /* Escape key press to close the dialog */
+ HTML_PREFIX "<div>text</div><hr align=\"center\">" HTML_SUFFIX,
+ "text\n\n"))
+ g_test_fail ();
+}
+
+static void
+test_h_rule_insert_text_after (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:above\n"
+ "action:insert-rule\n"
+ "seq:^\n" /* Escape key press to close the dialog */
+ "seq:drn\n" /* Press the right key instead of End key as the End key won't move caret after
the HR element */
+ "type:below\n",
+ HTML_PREFIX "<div>above</div><hr align=\"center\"><div>below</div>" HTML_SUFFIX,
+ "above\n"
+ "\n"
+ "below\n"))
+ g_test_fail ();
+}
+
+static void
+test_image_insert (TestFixture *fixture)
+{
+ EContentEditor *cnt_editor;
+ gchar *expected_html;
+ gchar *filename;
+ gchar *uri;
+ GError *error = NULL;
+
+ if (!test_utils_process_commands (fixture,
+ "mode:html\n"
+ "type:before*\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ filename = g_build_filename (EVOLUTION_TESTTOPSRCDIR, "data", "icons",
"hicolor_actions_24x24_stock_people.png", NULL);
+ uri = g_filename_to_uri (filename, NULL, &error);
+ g_assert_no_error (error);
+
+ /* Mimic what the action:insert-image does, without invoking the image chooser dialog */
+ cnt_editor = e_html_editor_get_content_editor (fixture->editor);
+ e_content_editor_insert_image (cnt_editor, uri);
+ /* Wait some time until the operation is finished */
+ test_utils_wait_milliseconds (500);
+
+ expected_html = g_strconcat (HTML_PREFIX "<div>before*<img src=\"evo-", uri, "\" width=\"24px\"
height=\"24px\">+after</div>" HTML_SUFFIX, NULL);
+
+ g_free (uri);
+ g_free (filename);
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:save\n" /* 1 */
+ "undo:undo\n"
+ "undo:redo\n"
+ "undo:test:1\n"
+ "type:+after\n",
+ expected_html,
+ "before*+after\n"))
+ g_test_fail ();
+
+ g_free (expected_html);
+}
+
+static void
+test_emoticon_insert_typed (TestFixture *fixture)
+{
+ gchar *image_uri;
+ gchar *expected_html;
+
+ test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail",
"composer-magic-smileys", TRUE);
+ test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail",
"composer-unicode-smileys", FALSE);
+
+ image_uri = test_utils_dup_image_uri ("face-smile");
+
+ expected_html = g_strconcat (HTML_PREFIX "<div>before <img src=\"", image_uri, "\" alt=\":-)\"
width=\"16px\" height=\"16px\">after</div>" HTML_SUFFIX, NULL);
+
+ g_free (image_uri);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:before :)after\n",
+ expected_html,
+ "before :-)after\n"))
+ g_test_fail ();
+
+ g_free (expected_html);
+}
+
+static void
+test_emoticon_insert_typed_dash (TestFixture *fixture)
+{
+ gchar *image_uri;
+ gchar *expected_html;
+
+ test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail",
"composer-magic-smileys", TRUE);
+ test_utils_fixture_change_setting_boolean (fixture, "org.gnome.evolution.mail",
"composer-unicode-smileys", FALSE);
+
+ image_uri = test_utils_dup_image_uri ("face-smile");
+
+ expected_html = g_strconcat (HTML_PREFIX "<div>before <img src=\"", image_uri, "\" alt=\":-)\"
width=\"16px\" height=\"16px\">after</div>" HTML_SUFFIX, NULL);
+
+ g_free (image_uri);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:before :-)after\n",
+ expected_html,
+ "before :-)after\n"))
+ g_test_fail ();
+
+ g_free (expected_html);
+}
+
+static void
+test_paragraph_normal_selection (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:style-preformat\n"
+ "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\\n\n"
+ "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n"
+ "seq:hu\n"
+ "action:style-normal\n",
+ HTML_PREFIX "<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero.</div>"
+ "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</pre>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.\n"
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n",
+ HTML_PREFIX "<div style=\"width: 71ch;\">Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Integer nec odio. Praesent libero.</div>"
+ "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</pre>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.\n"
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n",
+ HTML_PREFIX "<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero.</div>"
+ "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</pre>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.\n"
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n")) {
+ g_test_fail ();
+ return;
+ }
+}
+
+static void
+test_paragraph_normal_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:style-normal\n"
+ "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\\n\n"
+ "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n",
+ HTML_PREFIX "<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero.</div>"
+ "<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</div>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.\n"
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n",
+ HTML_PREFIX "<div style=\"width: 71ch;\">Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Integer nec odio. Praesent libero.</div>"
+ "<div style=\"width: 71ch;\">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
nec odio. Praesent libero.</div>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.\n"
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n",
+ HTML_PREFIX "<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero.</div>"
+ "<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</div>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.\n"
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.\n")) {
+ g_test_fail ();
+ return;
+ }
+}
+
+static void
+test_paragraph_preformatted_selection (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:style-normal\n"
+ "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\\n\n"
+ "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n"
+ "seq:Chc\n"
+ "action:style-preformat\n",
+ HTML_PREFIX "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero.</pre>"
+ "<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</div>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n"
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n",
+ HTML_PREFIX "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero.</pre>"
+ "<div style=\"width: 71ch;\">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
nec odio. Praesent libero.</div>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n"
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n",
+ HTML_PREFIX "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero.</pre>"
+ "<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</div>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n"
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.\n")) {
+ g_test_fail ();
+ return;
+ }
+}
+
+static void
+test_paragraph_preformatted_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:style-preformat\n"
+ "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero. \n"
+ "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n",
+ HTML_PREFIX "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero."
+ " Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</pre>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. "
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n",
+ HTML_PREFIX "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero."
+ " Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</pre>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. "
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n",
+ HTML_PREFIX "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero."
+ " Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</pre>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. "
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n")) {
+ g_test_fail ();
+ return;
+ }
+}
+
+static void
+test_paragraph_address_selection (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
"action:style-normal\n"
"type:normal text\\n\n"
"type:address line 1\\n\n"
@@ -1236,7 +3926,7 @@ test_paragraph_address_selection (TestFixture *fixture)
"address line 2\n"
"address line 3\n"
"\n"
- "normal text"))
+ "normal text\n"))
g_test_fail ();
}
@@ -1265,7 +3955,7 @@ test_paragraph_address_typed (TestFixture *fixture)
"address line 2\n"
"address line 3\n"
"\n"
- "normal text"))
+ "normal text\n"))
g_test_fail ();
}
@@ -1295,7 +3985,7 @@ test_paragraph_header_n_selection (TestFixture *fixture,
expected_plain = g_strdup_printf (
"normal text\n"
"header %d\n"
- "normal text",
+ "normal text\n",
header_n);
success = test_utils_run_simple_test (fixture, actions, expected_html, expected_plain);
@@ -1318,7 +4008,7 @@ test_paragraph_header_n_selection (TestFixture *fixture,
"normal text\n"
"\n"
"header %d\n"
- "normal text",
+ "normal text\n",
header_n);
success = test_utils_run_simple_test (fixture,
@@ -1358,7 +4048,7 @@ test_paragraph_header_n_typed (TestFixture *fixture,
expected_plain = g_strdup_printf (
"normal text\n"
"header %d\n"
- "normal text",
+ "normal text\n",
header_n);
success = test_utils_run_simple_test (fixture, actions, expected_html, expected_plain);
@@ -1381,7 +4071,7 @@ test_paragraph_header_n_typed (TestFixture *fixture,
"normal text\n"
"header %d\n"
"\n"
- "normal text",
+ "normal text\n",
header_n);
success = test_utils_run_simple_test (fixture,
@@ -1488,10 +4178,12 @@ test_paragraph_wrap_lines (TestFixture *fixture)
"type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n"
"action:select-all\n"
"action:wrap-lines\n",
- HTML_PREFIX "<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
nec<br>odio. Praesent libero.</div>"
- "<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec<br>odio. Praesent
libero.</div>" HTML_SUFFIX,
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n" "odio. Praesent
libero.\n"
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n" "odio. Praesent
libero."))
+ HTML_PREFIX "<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec<br>"
+ "odio. Praesent libero. Lorem ipsum dolor sit amet, consectetur<br>"
+ "adipiscing elit. Integer nec odio. Praesent libero.</div>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero. Lorem ipsum dolor sit amet, consectetur\n"
+ "adipiscing elit. Integer nec odio. Praesent libero.\n"))
g_test_fail ();
}
@@ -1506,391 +4198,775 @@ test_paste_singleline_html2html (TestFixture *fixture)
"action:paste\n"
"type: text after\n",
HTML_PREFIX "<div>text before some <b>bold</b> text text after</div>" HTML_SUFFIX,
- "text before some bold text text after"))
+ "text before some bold text text after\n"))
+ g_test_fail ();
+}
+
+static void
+test_paste_singleline_html2plain (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("<html><body>some <b>bold</b> text</body></html>", TRUE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type: text after\n",
+ HTML_PREFIX "<div style=\"width: 71ch;\">text before some bold text text after</div>"
HTML_SUFFIX,
+ "text before some bold text text after\n"))
+ g_test_fail ();
+}
+
+static void
+test_paste_singleline_plain2html (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("some plain text", FALSE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type: text after\n",
+ HTML_PREFIX "<div>text before some plain text text after</div>" HTML_SUFFIX,
+ "text before some plain text text after\n"))
+ g_test_fail ();
+}
+
+static void
+test_paste_singleline_plain2plain (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("some plain text", FALSE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type: text after\n",
+ HTML_PREFIX "<div style=\"width: 71ch;\">text before some plain text text after</div>"
HTML_SUFFIX,
+ "text before some plain text text after\n"))
+ g_test_fail ();
+}
+
+static void
+test_paste_multiline_html2html (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("<html><body><b>bold</b> text<br><i>italic</i>
text<br><u>underline</u> text<br>.</body></html>", TRUE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type:text after\n",
+ HTML_PREFIX "<div>text before <b>bold</b> text</div><div><i>italic</i>
text<br><u>underline</u> text<br>.text after</div>" HTML_SUFFIX,
+ "text before bold text\nitalic text\nunderline text\n.text after\n"))
+ g_test_fail ();
+}
+
+static void
+test_paste_multiline_html2plain (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("<html><body><b>bold</b> text<br><i>italic</i>
text<br><u>underline</u> text</body></html>", TRUE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type:\\ntext after\n",
+ HTML_PREFIX "<div style=\"width: 71ch;\">text before bold text</div>"
+ "<div style=\"width: 71ch;\">italic text<br>underline text</div>"
+ "<div style=\"width: 71ch;\">text after</div>" HTML_SUFFIX,
+ "text before bold text\nitalic text\nunderline text\ntext after\n"))
+ g_test_fail ();
+}
+
+static void
+test_paste_multiline_div_html2html (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("<html><body><div><b>bold</b> text</div><div><i>italic</i>
text</div><div><u>underline</u> text</div><div>.</div></body></html>", TRUE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type:text after\n",
+ HTML_PREFIX "<div>text before <b>bold</b> text</div><div><i>italic</i>
text</div><div><u>underline</u> text</div><div>.text after</div>" HTML_SUFFIX,
+ "text before bold text\nitalic text\nunderline text\n.text after\n"))
+ g_test_fail ();
+}
+
+static void
+test_paste_multiline_div_html2plain (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("<html><body><div><b>bold</b> text</div><div><i>italic</i>
text</div><div><u>underline</u> text</div></body></html>", TRUE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type:\\ntext after\n",
+ HTML_PREFIX "<div style=\"width: 71ch;\">text before bold text</div>"
+ "<div style=\"width: 71ch;\">italic text<br>underline text<br></div>"
+ "<div style=\"width: 71ch;\">text after</div>" HTML_SUFFIX,
+ "text before bold text\nitalic text\nunderline text\ntext after\n"))
+ g_test_fail ();
+}
+
+static void
+test_paste_multiline_p_html2html (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("<html><body><p><b>bold</b> text</p><p><i>italic</i>
text</p><p><u>underline</u> text</p><p><br></p></body></html>", TRUE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type:text after\n",
+ HTML_PREFIX "<div>text before <b>bold</b> text</div><div><i>italic</i>
text</div><div><u>underline</u> text</div><div>text after</div>" HTML_SUFFIX,
+ "text before bold text\nitalic text\nunderline text\ntext after\n"))
+ g_test_fail ();
+}
+
+static void
+test_paste_multiline_p_html2plain (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("<html><body><p><b>bold</b> text</p><p><i>italic</i>
text</p><p><u>underline</u> text</p></body></html>", TRUE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type:\\ntext after\n",
+ HTML_PREFIX "<div style=\"width: 71ch;\">text before bold text</div>"
+ "<div style=\"width: 71ch;\">italic text<br>underline text<br></div>"
+ "<div style=\"width: 71ch;\">text after</div>" HTML_SUFFIX,
+ "text before bold text\nitalic text\nunderline text\ntext after\n"))
+ g_test_fail ();
+}
+
+static void
+test_paste_multiline_plain2html (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("line 1\nline 2\nline 3\n", FALSE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type:text after\n",
+ HTML_PREFIX "<div>text before line 1</div><div>line 2</div><div>line 3</div><div>text
after</div>" HTML_SUFFIX,
+ "text before line 1\nline 2\nline 3\ntext after\n"))
+ g_test_fail ();
+}
+
+static void
+test_paste_multiline_plain2plain (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("line 1\nline 2\nline 3", FALSE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type:\\ntext after\n",
+ HTML_PREFIX "<div style=\"width: 71ch;\">text before line 1</div>"
+ "<div style=\"width: 71ch;\">line 2</div>"
+ "<div style=\"width: 71ch;\">line 3</div>"
+ "<div style=\"width: 71ch;\">text after</div>" HTML_SUFFIX,
+ "text before line 1\nline 2\nline 3\ntext after\n"))
+ g_test_fail ();
+}
+
+static void
+test_paste_quoted_singleline_html2html (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("<html><body>some <b>bold</b> text</body></html>", TRUE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:text before \n"
+ "action:paste-quote\n"
+ "type:\\n\n" /* stop quotting */
+ "type:text after\n",
+ HTML_PREFIX "<div>text before </div>"
+ "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE "><div>some <b>bold</b> text</div></blockquote>"
+ "<div>text after</div>" HTML_SUFFIX,
+ "text before \n"
+ "> some bold text\n"
+ "text after\n"))
g_test_fail ();
}
static void
-test_paste_singleline_html2plain (TestFixture *fixture)
+test_paste_quoted_singleline_html2plain (TestFixture *fixture)
{
test_utils_set_clipboard_text ("<html><body>some <b>bold</b> text</body></html>", TRUE);
if (!test_utils_run_simple_test (fixture,
"mode:plain\n"
"type:text before \n"
- "action:paste\n"
- "type: text after\n",
- HTML_PREFIX "<div style=\"width: 71ch;\">text before some bold text text after</div>"
HTML_SUFFIX,
- "text before some bold text text after"))
+ "action:paste-quote\n"
+ "type:\\n\n" /* stop quotting */
+ "type:text after\n",
+ HTML_PREFIX "<div style=\"width: 71ch;\">text before </div>"
+ "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "some bold text</div>"
+ "</blockquote>"
+ "<div style=\"width: 71ch;\">text after</div>" HTML_SUFFIX,
+ "text before \n"
+ "> some bold text\n"
+ "text after\n"))
g_test_fail ();
}
static void
-test_paste_singleline_plain2html (TestFixture *fixture)
+test_paste_quoted_singleline_plain2html (TestFixture *fixture)
{
test_utils_set_clipboard_text ("some plain text", FALSE);
if (!test_utils_run_simple_test (fixture,
"mode:html\n"
"type:text before \n"
- "action:paste\n"
- "type: text after\n",
- HTML_PREFIX "<div>text before some plain text text after</div>" HTML_SUFFIX,
- "text before some plain text text after"))
+ "action:paste-quote\n"
+ "type:\\n\n" /* stop quotting */
+ "type:text after\n",
+ HTML_PREFIX "<div>text before </div>"
+ "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE "><div>some plain text</div></blockquote>"
+ "<div>text after</div>" HTML_SUFFIX,
+ "text before \n"
+ "> some plain text\n"
+ "text after\n"))
g_test_fail ();
}
static void
-test_paste_singleline_plain2plain (TestFixture *fixture)
+test_paste_quoted_singleline_plain2plain (TestFixture *fixture)
{
test_utils_set_clipboard_text ("some plain text", FALSE);
if (!test_utils_run_simple_test (fixture,
"mode:plain\n"
"type:text before \n"
- "action:paste\n"
- "type: text after\n",
- HTML_PREFIX "<div style=\"width: 71ch;\">text before some plain text text after</div>"
HTML_SUFFIX,
- "text before some plain text text after"))
+ "action:paste-quote\n"
+ "type:\\n\n" /* stop quotting */
+ "type:text after\n",
+ HTML_PREFIX "<div style=\"width: 71ch;\">text before </div>"
+ "<blockquote type=\"cite\"><div>" QUOTE_SPAN (QUOTE_CHR) "some plain text</div></blockquote>"
+ "<div style=\"width: 71ch;\">text after</div>" HTML_SUFFIX,
+ "text before \n"
+ "> some plain text\n"
+ "text after\n"))
g_test_fail ();
}
static void
-test_paste_multiline_html2html (TestFixture *fixture)
+test_paste_quoted_multiline_html2html (TestFixture *fixture)
{
- /* This test is known to fail, skip it. */
- printf ("SKIPPED ");
-
-#if 0
test_utils_set_clipboard_text ("<html><body><b>bold</b> text<br><i>italic</i>
text<br><u>underline</u> text<br></body></html>", TRUE);
if (!test_utils_run_simple_test (fixture,
"mode:html\n"
"type:text before \n"
- "action:paste\n"
+ "action:paste-quote\n"
+ "type:\\n\n" /* stop quotting */
"type:text after\n",
- HTML_PREFIX "<div>text before <b>bold</b> text</div><div><i>italic</i>
text</div><div><u>underline</u> text</div><div>text after</div>" HTML_SUFFIX,
- "text before bold text\nitalic text\nunderline text\ntext after"))
+ HTML_PREFIX "<div>text before </div>"
+ "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE "><div><b>bold</b> text<br>"
+ "<i>italic</i> text<br>"
+ "<u>underline</u> text<br></div></blockquote>"
+ "<div>text after</div>" HTML_SUFFIX,
+ "text before \n"
+ "> bold text\n"
+ "> italic text\n"
+ "> underline text\n"
+ "text after\n"))
g_test_fail ();
-#endif
}
static void
-test_paste_multiline_html2plain (TestFixture *fixture)
+test_paste_quoted_multiline_html2plain (TestFixture *fixture)
{
test_utils_set_clipboard_text ("<html><body><b>bold</b> text<br><i>italic</i>
text<br><u>underline</u> text</body></html>", TRUE);
if (!test_utils_run_simple_test (fixture,
"mode:plain\n"
"type:text before \n"
- "action:paste\n"
- "type:\\ntext after\n",
- HTML_PREFIX "<div style=\"width: 71ch;\">text before bold text</div>"
- "<div style=\"width: 71ch;\">italic text</div>"
- "<div style=\"width: 71ch;\">underline text</div>"
+ "action:paste-quote\n"
+ "type:\\n\n" /* stop quotting */
+ "type:text after\n",
+ HTML_PREFIX "<div style=\"width: 71ch;\">text before </div>"
+ "<blockquote type=\"cite\"><div>" QUOTE_SPAN (QUOTE_CHR) "bold text<br>"
+ QUOTE_SPAN (QUOTE_CHR) "italic text<br>"
+ QUOTE_SPAN (QUOTE_CHR) "underline text</div></blockquote>"
"<div style=\"width: 71ch;\">text after</div>" HTML_SUFFIX,
- "text before bold text\nitalic text\nunderline text\ntext after"))
+ "text before \n"
+ "> bold text\n"
+ "> italic text\n"
+ "> underline text\n"
+ "text after\n"))
g_test_fail ();
}
static void
-test_paste_multiline_div_html2html (TestFixture *fixture)
+test_paste_quoted_multiline_plain2html (TestFixture *fixture)
{
- /* This test is known to fail, skip it. */
- printf ("SKIPPED ");
-
-#if 0
- test_utils_set_clipboard_text ("<html><body><div><b>bold</b> text</div><div><i>italic</i>
text</div><div><u>underline</u> text</div><div></div></body></html>", TRUE);
+ test_utils_set_clipboard_text ("line 1\nline 2\nline 3\n", FALSE);
if (!test_utils_run_simple_test (fixture,
"mode:html\n"
"type:text before \n"
- "action:paste\n"
+ "action:paste-quote\n"
+ "type:\\n\n" /* stop quotting */
"type:text after\n",
- HTML_PREFIX "<div>text before <b>bold</b> text</div><div><i>italic</i>
text</div><div><u>underline</u> text</div><div>text after</div>" HTML_SUFFIX,
- "text before bold text\nitalic text\nunderline text\ntext after"))
+ HTML_PREFIX "<div>text before </div>"
+ "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE "><div>line 1</div>"
+ "<div>line 2</div>"
+ "<div>line 3</div>"
+ "<div><br></div></blockquote>"
+ "<div>text after</div>" HTML_SUFFIX,
+ "text before \n"
+ "> line 1\n"
+ "> line 2\n"
+ "> line 3\n"
+ "> \n"
+ "text after\n"))
g_test_fail ();
-#endif
}
static void
-test_paste_multiline_div_html2plain (TestFixture *fixture)
+test_paste_quoted_multiline_plain2plain (TestFixture *fixture)
{
- test_utils_set_clipboard_text ("<html><body><div><b>bold</b> text</div><div><i>italic</i>
text</div><div><u>underline</u> text</div></body></html>", TRUE);
+ test_utils_set_clipboard_text ("line 1\nline 2\nline 3", FALSE);
if (!test_utils_run_simple_test (fixture,
"mode:plain\n"
"type:text before \n"
- "action:paste\n"
- "type:\\ntext after\n",
- HTML_PREFIX "<div style=\"width: 71ch;\">text before bold text</div>"
- "<div style=\"width: 71ch;\">italic text</div>"
- "<div style=\"width: 71ch;\">underline text</div>"
+ "action:paste-quote\n"
+ "type:\\n\n" /* stop quotting */
+ "type:text after\n",
+ HTML_PREFIX "<div style=\"width: 71ch;\">text before </div>"
+ "<blockquote type=\"cite\"><div>" QUOTE_SPAN (QUOTE_CHR) "line 1</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "line 2</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "line 3</div></blockquote>"
"<div style=\"width: 71ch;\">text after</div>" HTML_SUFFIX,
- "text before bold text\nitalic text\nunderline text\ntext after"))
+ "text before \n"
+ "> line 1\n"
+ "> line 2\n"
+ "> line 3\n"
+ "text after\n"))
g_test_fail ();
}
static void
-test_paste_multiline_p_html2html (TestFixture *fixture)
+test_cite_html2plain (TestFixture *fixture)
{
- /* This test is known to fail, skip it. */
- printf ("SKIPPED ");
+ if (!test_utils_process_commands (fixture,
+ "mode:html\n")) {
+ g_test_fail ();
+ return;
+ }
-#if 0
- test_utils_set_clipboard_text ("<html><body><div><b>bold</b> text</div><div><i>italic</i>
text</div><div><u>underline</u> text</div><div></div></body></html>", TRUE);
+ test_utils_insert_content (fixture,
+ "<html><head></head><body>"
+ "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<div>level 1</div>"
+ "<div><br></div>"
+ "<div>level 1</div>"
+ "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<div>level 2</div>"
+ "</blockquote>"
+ "<div>back in level 1</div>"
+ "</blockquote>"
+ "<div><br></div>"
+ "<div>out of the citation</div>"
+ "</body></html>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+ /* Just check the content was read properly */
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "type:text before \n"
- "action:paste\n"
- "type:text after\n",
- HTML_PREFIX "<div>text before <b>bold</b> text</div><div><i>italic</i>
text</div><div><u>underline</u> text</div><div>text after</div>" HTML_SUFFIX,
- "text before bold text\nitalic text\nunderline text\ntext after"))
+ "",
+ HTML_PREFIX "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE "><div>level
1</div><div><br></div><div>level 1</div>"
+ "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE "><div>level 2</div></blockquote><div>back in
level 1</div></blockquote>"
+ "<div><br></div><div>out of the citation</div>" HTML_SUFFIX,
+ "> level 1\n"
+ "> \n"
+ "> level 1\n"
+ "> > level 2\n"
+ "> back in level 1\n"
+ "\n"
+ "out of the citation\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n",
+ NULL,
+ "> level 1\n"
+ "> \n"
+ "> level 1\n"
+ "> > level 2\n"
+ "> back in level 1\n"
+ "\n"
+ "out of the citation\n"))
g_test_fail ();
-#endif
}
static void
-test_paste_multiline_p_html2plain (TestFixture *fixture)
+test_cite_shortline (TestFixture *fixture)
{
- test_utils_set_clipboard_text ("<html><body><div><b>bold</b> text</div><div><i>italic</i>
text</div><div><u>underline</u> text</div></body></html>", TRUE);
+ if (!test_utils_process_commands (fixture,
+ "mode:html\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<html><head></head><body><blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<div>Just one short line.</div>"
+ "</blockquote></body></html>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
if (!test_utils_run_simple_test (fixture,
- "mode:plain\n"
- "type:text before \n"
- "action:paste\n"
- "type:\\ntext after\n",
- HTML_PREFIX "<div style=\"width: 71ch;\">text before bold text</div>"
- "<div style=\"width: 71ch;\">italic text</div>"
- "<div style=\"width: 71ch;\">underline text</div>"
- "<div style=\"width: 71ch;\">text after</div>" HTML_SUFFIX,
- "text before bold text\nitalic text\nunderline text\ntext after"))
+ "",
+ HTML_PREFIX "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<div>Just one short line.</div>"
+ "</blockquote>" HTML_SUFFIX,
+ "> Just one short line.\n")) {
g_test_fail ();
-}
+ return;
+ }
-static void
-test_paste_multiline_plain2html (TestFixture *fixture)
-{
- test_utils_set_clipboard_text ("line 1\nline 2\nline 3\n", FALSE);
+ if (!test_utils_process_commands (fixture,
+ "seq:C\n"
+ "type:a\n"
+ "seq:cD\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<html><head></head><body><blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<div>Just one short line.</div>"
+ "</blockquote></body></html>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "type:text before \n"
- "action:paste\n"
- "type:text after\n",
- HTML_PREFIX "<div>text before line 1</div><div>line 2</div><div>line 3</div><div>text
after</div>" HTML_SUFFIX,
- "text before line 1\nline 2\nline 3\ntext after"))
+ "",
+ HTML_PREFIX "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<div>Just one short line.</div>"
+ "</blockquote>" HTML_SUFFIX,
+ "> Just one short line.\n")) {
g_test_fail ();
-}
+ return;
+ }
-static void
-test_paste_multiline_plain2plain (TestFixture *fixture)
-{
- test_utils_set_clipboard_text ("line 1\nline 2\nline 3", FALSE);
+ test_utils_insert_content (fixture,
+ "<html><head></head><body><blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<div>short line 1</div>"
+ "<div>short line 2</div>"
+ "<div>short line 3</div>"
+ "</blockquote></body></html>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
if (!test_utils_run_simple_test (fixture,
- "mode:plain\n"
- "type:text before \n"
- "action:paste\n"
- "type:\\ntext after\n",
- HTML_PREFIX "<div style=\"width: 71ch;\">text before line 1</div>"
- "<div style=\"width: 71ch;\">line 2</div>"
- "<div style=\"width: 71ch;\">line 3</div>"
- "<div style=\"width: 71ch;\">text after</div>" HTML_SUFFIX,
- "text before line 1\nline 2\nline 3\ntext after"))
+ "",
+ HTML_PREFIX "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<div>short line 1</div>"
+ "<div>short line 2</div>"
+ "<div>short line 3</div>"
+ "</blockquote>" HTML_SUFFIX,
+ "> short line 1\n"
+ "> short line 2\n"
+ "> short line 3\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_process_commands (fixture,
+ "seq:C\n"
+ "type:a\n"
+ "seq:cD\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<html><head></head><body><blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<div>short line 1</div>"
+ "<div>short line 2</div>"
+ "<div>short line 3</div>"
+ "</blockquote></body></html>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "",
+ HTML_PREFIX "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<div>short line 1</div>"
+ "<div>short line 2</div>"
+ "<div>short line 3</div>"
+ "</blockquote>" HTML_SUFFIX,
+ "> short line 1\n"
+ "> short line 2\n"
+ "> short line 3\n")) {
g_test_fail ();
+ return;
+ }
}
static void
-test_paste_quoted_singleline_html2html (TestFixture *fixture)
+test_cite_longline (TestFixture *fixture)
{
- test_utils_set_clipboard_text ("<html><body>some <b>bold</b> text</body></html>", TRUE);
+ if (!test_utils_process_commands (fixture,
+ "mode:html\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<html><head></head><body><blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<div>This is the first paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>"
+ "</blockquote></body></html>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "type:text before \n"
- "action:paste-quote\n"
- "type:\\n\n" /* stop quotting */
- "type:text after\n",
- HTML_PREFIX "<div>text before </div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE "><div>some <b>bold</b> text</div></blockquote>"
- "<div>text after</div>" HTML_SUFFIX,
- "text before \n"
- "> some bold text\n"
- "text after"))
+ "",
+ HTML_PREFIX "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<div>This is the first paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>"
+ "</blockquote>" HTML_SUFFIX,
+ "> This is the first paragraph of a quoted text which has some long text\n"
+ "> to test. It has the second sentence as well.\n")) {
g_test_fail ();
-}
+ return;
+ }
-static void
-test_paste_quoted_singleline_html2plain (TestFixture *fixture)
-{
- test_utils_set_clipboard_text ("<html><body>some <b>bold</b> text</body></html>", TRUE);
+ if (!test_utils_process_commands (fixture,
+ "seq:C\n"
+ "type:a\n"
+ "seq:cDb\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<html><head></head><body><blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<div>This is the first paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>"
+ "</blockquote></body></html>",
+ E_CONTENT_EDITOR_INSERT_TEXT_HTML | E_CONTENT_EDITOR_INSERT_REPLACE_ALL);
if (!test_utils_run_simple_test (fixture,
- "mode:plain\n"
- "type:text before \n"
- "action:paste-quote\n"
- "type:\\n\n" /* stop quotting */
- "type:text after\n",
- HTML_PREFIX "<div style=\"width: 71ch;\">text before </div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE "><div style=\"width: 71ch;\">> some
<b>bold</b> text</div></blockquote>"
- "<div style=\"width: 71ch;\">text after</div>" HTML_SUFFIX,
- "text before \n"
- "> some bold text\n"
- "text after"))
+ "",
+ HTML_PREFIX "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<div>This is the first paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>"
+ "</blockquote>" HTML_SUFFIX,
+ "> This is the first paragraph of a quoted text which has some long text\n"
+ "> to test. It has the second sentence as well.\n")) {
g_test_fail ();
-}
+ return;
+ }
-static void
-test_paste_quoted_singleline_plain2html (TestFixture *fixture)
-{
- test_utils_set_clipboard_text ("some plain text", FALSE);
+ test_utils_insert_content (fixture,
+ "<html><head></head><body><blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<div>This is the first paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>"
+ "<div>This is the second paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>"
+ "<div>This is the third paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>"
+ "</blockquote><br>after quote</body></html>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "type:text before \n"
- "action:paste-quote\n"
- "type:\\n\n" /* stop quotting */
- "type:text after\n",
- HTML_PREFIX "<div>text before </div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE "><div>some plain text</div></blockquote>"
- "<div>text after</div>" HTML_SUFFIX,
- "text before \n"
- "> some plain text\n"
- "text after"))
+ "",
+ HTML_PREFIX "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<div>This is the first paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>"
+ "<div>This is the second paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>"
+ "<div>This is the third paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>"
+ "</blockquote><br>after quote" HTML_SUFFIX,
+ "> This is the first paragraph of a quoted text which has some long text\n"
+ "> to test. It has the second sentence as well.\n"
+ "> This is the second paragraph of a quoted text which has some long\n"
+ "> text to test. It has the second sentence as well.\n"
+ "> This is the third paragraph of a quoted text which has some long text\n"
+ "> to test. It has the second sentence as well.\n"
+ "\nafter quote")) {
g_test_fail ();
+ return;
+ }
}
static void
-test_paste_quoted_singleline_plain2plain (TestFixture *fixture)
+test_cite_reply_html (TestFixture *fixture)
{
- test_utils_set_clipboard_text ("some plain text", FALSE);
+ if (!test_utils_process_commands (fixture,
+ "mode:html\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<pre>line 1\n"
+ "line 2\n"
+ "</pre><span class=\"-x-evo-to-body\" data-credits=\"On Today, User wrote:\"></span>"
+ "<span class=\"-x-evo-cite-body\"></span>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
if (!test_utils_run_simple_test (fixture,
- "mode:plain\n"
- "type:text before \n"
- "action:paste-quote\n"
- "type:\\n\n" /* stop quotting */
- "type:text after\n",
- HTML_PREFIX "<div style=\"width: 71ch;\">text before </div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE "><div style=\"width: 71ch;\">> some plain
text</div></blockquote>"
- "<div style=\"width: 71ch;\">text after</div>" HTML_SUFFIX,
- "text before \n"
- "> some plain text\n"
- "text after"))
+ "",
+ HTML_PREFIX "<div>On Today, User wrote:</div>"
+ "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE "><pre>line 1</pre>"
+ "<pre>line 2</pre></blockquote>" HTML_SUFFIX,
+ "On Today, User wrote:\n"
+ "> line 1\n"
+ "> line 2\n"))
g_test_fail ();
}
static void
-test_paste_quoted_multiline_html2html (TestFixture *fixture)
+test_cite_reply_html_to_plain (TestFixture *fixture)
{
- /* This test is known to fail, skip it. */
- printf ("SKIPPED ");
+ if (!test_utils_process_commands (fixture,
+ "mode:html\n")) {
+ g_test_fail ();
+ return;
+ }
-#if 0
- test_utils_set_clipboard_text ("<html><body><b>bold</b> text<br><i>italic</i>
text<br><u>underline</u> text<br></body></html>", TRUE);
+ test_utils_insert_content (fixture,
+ "<pre>line 1\n"
+ "line 2\n\n"
+ "</pre><span class=\"-x-evo-to-body\" data-credits=\"On Today, User wrote:\"></span>"
+ "<span class=\"-x-evo-cite-body\"></span>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_process_commands (fixture,
+ "mode:plain\n")) {
+ g_test_fail ();
+ return;
+ }
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "type:text before \n"
- "action:paste-quote\n"
- "seq:b\n" /* stop quotting */
- "type:text after\n",
- HTML_PREFIX "<div>text before </div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">> <b>bold</b> text</div>"
- "<div>> <i>italic</i> text</div>"
- "<div>> <u>underline</u> text</div></blockquote>"
- "<div>text after</div>" HTML_SUFFIX,
- "text before \n"
- "> bold text\n"
- "> italic text\n"
- "> underline text\n"
- "text after"))
+ "",
+ HTML_PREFIX "<div style=\"width: 71ch;\">On Today, User wrote:</div>"
+ "<blockquote type=\"cite\">"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "line 1</pre>"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "line 2</pre>"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "<br></pre></blockquote>" HTML_SUFFIX,
+ "On Today, User wrote:\n"
+ "> line 1\n"
+ "> line 2\n"
+ "> \n")) {
g_test_fail ();
-#endif
-}
+ return;
+ }
-static void
-test_paste_quoted_multiline_html2plain (TestFixture *fixture)
-{
- /* This test is known to fail, skip it. */
- printf ("SKIPPED ");
+ if (!test_utils_process_commands (fixture,
+ "mode:html\n")) {
+ g_test_fail ();
+ return;
+ }
-#if 0
- test_utils_set_clipboard_text ("<html><body><b>bold</b> text<br><i>italic</i>
text<br><u>underline</u> text</body></html>", TRUE);
+ test_utils_insert_content (fixture,
+ "<div>line 1</div>"
+ "<div>line 2</div><br>"
+ "<span class=\"-x-evo-to-body\" data-credits=\"On Today, User wrote:\"></span>"
+ "<span class=\"-x-evo-cite-body\"></span>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_process_commands (fixture,
+ "mode:plain\n")) {
+ g_test_fail ();
+ return;
+ }
if (!test_utils_run_simple_test (fixture,
- "mode:plain\n"
- "type:text before \n"
- "action:paste-quote\n"
- "type:\\n\n" /* stop quotting */
- "type:text after\n",
- HTML_PREFIX "<div style=\"width: 71ch;\">text before </div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE "><div>> bold text</div>"
- "<div style=\"width: 71ch;\">> italic text</div>"
- "<div style=\"width: 71ch;\">> underline text</div></blockquote>"
- "<div style=\"width: 71ch;\">> text after</div>" HTML_SUFFIX,
- "text before \n"
- "> bold text\n"
- "> italic text\n"
- "> underline text\n"
- "text after"))
+ "",
+ HTML_PREFIX "<div style=\"width: 71ch;\">On Today, User wrote:</div>"
+ "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "line 1</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "line 2</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<br></div></blockquote>" HTML_SUFFIX,
+ "On Today, User wrote:\n"
+ "> line 1\n"
+ "> line 2\n"
+ "> \n"))
g_test_fail ();
-#endif
}
static void
-test_paste_quoted_multiline_plain2html (TestFixture *fixture)
+test_cite_reply_plain (TestFixture *fixture)
{
- test_utils_set_clipboard_text ("line 1\nline 2\nline 3\n", FALSE);
+ if (!test_utils_process_commands (fixture,
+ "mode:plain\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<pre>line 1\n"
+ "line 2\n"
+ "</pre><span class=\"-x-evo-to-body\" data-credits=\"On Today, User wrote:\"></span>"
+ "<span class=\"-x-evo-cite-body\"></span>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "type:text before \n"
- "action:paste-quote\n"
- "seq:b\n" /* stop quotting */
- "type:text after\n",
- HTML_PREFIX "<div>text before </div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE "><div>line 1</div>"
- "<div>line 2</div>"
- "<div>line 3</div></blockquote>"
- "<div>text after</div>" HTML_SUFFIX,
- "text before \n"
+ "",
+ HTML_PREFIX "<div style=\"width: 71ch;\">On Today, User wrote:</div>"
+ "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "line 1</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "line 2</div></blockquote>" HTML_SUFFIX,
+ "On Today, User wrote:\n"
"> line 1\n"
- "> line 2\n"
- "> line 3\n"
- "text after"))
+ "> line 2\n"))
g_test_fail ();
}
static void
-test_paste_quoted_multiline_plain2plain (TestFixture *fixture)
+test_cite_reply_link (TestFixture *fixture)
{
- test_utils_set_clipboard_text ("line 1\nline 2\nline 3", FALSE);
+ if (!test_utils_process_commands (fixture,
+ "mode:plain\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<html><head></head><body><div><span>123 (here <a href=\"https://www.example.com\">\n"
+ "https://www.example.com/1234567890/1234567890/1234567890/1234567890/1234567890/"
+ ") and </span>here ěščřžýáíé <a href=\"https://www.example.com\">www.example.com</a>"
+ " with closing text after.</div>"
+ "<div>www.example1.com</div>"
+ "<div>before www.example2.com</div>"
+ "<div>www.example3.com after</div>"
+ "<div>😏😉🙂 user@no.where line with Emoji</div></body></html>"
+ "<span class=\"-x-evo-to-body\" data-credits=\"On Today, User wrote:\"></span>"
+ "<span class=\"-x-evo-cite-body\"></span>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
if (!test_utils_run_simple_test (fixture,
- "mode:plain\n"
- "type:text before \n"
- "action:paste-quote\n"
- "type:\\n\n" /* stop quotting */
- "type:text after\n",
- HTML_PREFIX "<div style=\"width: 71ch;\">text before </div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE "><div style=\"width: 71ch;\">> line 1</div>"
- "<div style=\"width: 71ch;\">> line 2</div>"
- "<div style=\"width: 71ch;\">> line 3</div></blockquote>"
- "<div style=\"width: 71ch;\">text after</div>" HTML_SUFFIX,
- "text before \n"
- "> line 1\n"
- "> line 2\n"
- "> line 3\n"
- "text after"))
+ "",
+ HTML_PREFIX "<div style=\"width: 71ch;\">On Today, User wrote:</div>"
+ "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "123 (here </div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<a
href=\"https://www.example.com/1234567890/1234567890/1234567890/1234567890/1234567890/\">"
+
"https://www.example.com/1234567890/1234567890/1234567890/1234567890/1234567890/</a>)<br
class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "and here ěščřžýáíé <a
href=\"https://www.example.com\">www.example.com</a> with closing text after.</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<a
href=\"https://www.example1.com\">www.example1.com</a></div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "before <a
href=\"https://www.example2.com\">www.example2.com</a></div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<a href=\"https://www.example3.com\">www.example3.com</a>
after</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "😏😉🙂 <a href=\"mailto:user@no.where\">user@no.where</a> line
with Emoji</div>"
+ "</blockquote>" HTML_SUFFIX,
+ "On Today, User wrote:\n"
+ "> 123 (here \n"
+ "> https://www.example.com/1234567890/1234567890/1234567890/1234567890/1234567890/\n"
+ "> ) and here ěščřžýáíé www.example.com with closing text after.\n"
+ "> www.example1.com\n"
+ "> before www.example2.com\n"
+ "> www.example3.com after\n"
+ "> 😏😉🙂 user@no.where line with Emoji\n"))
g_test_fail ();
}
static void
-test_cite_html2plain (TestFixture *fixture)
+test_cite_editing_html (TestFixture *fixture)
{
+ const gchar *plain0, *html0, *plain1, *html1, *plain2, *html2, *plain3, *html3, *plain4, *html4;
+
if (!test_utils_process_commands (fixture,
"mode:html\n")) {
g_test_fail ();
@@ -1898,157 +4974,234 @@ test_cite_html2plain (TestFixture *fixture)
}
test_utils_insert_content (fixture,
- "<html><head></head><body>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div data-evo-paragraph=\"\">level 1</div>"
- "<div data-evo-paragraph=\"\"><br></div>"
- "<div data-evo-paragraph=\"\">level 1</div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div data-evo-paragraph=\"\">level 2</div>"
- "</blockquote>"
- "<div data-evo-paragraph=\"\">back in level 1</div>"
+ "<div>before citation</div>"
+ "<blockquote type='cite'>"
+ "<div>cite level 1a</div>"
+ "<blockquote type='cite'>"
+ "<div>cite level 2</div>"
+ "</blockquote>"
+ "<div>cite level 1b</div>"
"</blockquote>"
- "<div data-evo-paragraph=\"\"><br></div>"
- "<div data-evo-paragraph=\"\">out of the citation</div>"
- "</body></html>",
+ "<div>after citation</div>",
E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
- /* Just check the content was read properly */
+ html0 = HTML_PREFIX "<div>before citation</div>"
+ "<blockquote type='cite' " BLOCKQUOTE_STYLE ">"
+ "<div>cite level 1a</div>"
+ "<blockquote type='cite' " BLOCKQUOTE_STYLE ">"
+ "<div>cite level 2</div>"
+ "</blockquote>"
+ "<div>cite level 1b</div>"
+ "</blockquote>"
+ "<div>after citation</div>" HTML_SUFFIX;
+
+ plain0 = "before citation\n"
+ "> cite level 1a\n"
+ "> > cite level 2\n"
+ "> cite level 1b\n"
+ "after citation\n";
+
+ if (!test_utils_run_simple_test (fixture, "", html0, plain0)) {
+ g_test_fail ();
+ return;
+ }
+
+ html1 = HTML_PREFIX "<div>before citation</div>"
+ "<blockquote type='cite' " BLOCKQUOTE_STYLE ">"
+ "<div>cite level 1a</div>"
+ "<blockquote type='cite' " BLOCKQUOTE_STYLE ">"
+ "<div>ciXte level 2</div>"
+ "</blockquote>"
+ "<div>cite level 1b</div>"
+ "</blockquote>"
+ "<div>after citation</div>" HTML_SUFFIX;
+
+ plain1 = "before citation\n"
+ "> cite level 1a\n"
+ "> > ciXte level 2\n"
+ "> cite level 1b\n"
+ "after citation\n";
+
if (!test_utils_run_simple_test (fixture,
- "",
- HTML_PREFIX "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE "><div>level
1</div><div><br></div><div>level 1</div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE "><div>level 2</div></blockquote><div>back in
level 1</div></blockquote>"
- "<div><br></div><div>out of the citation</div>" HTML_SUFFIX,
- "> level 1\n"
- "> \n"
- "> level 1\n"
- "> > level 2\n"
- "> back in level 1\n"
- "\n"
- "out of the citation")) {
+ "seq:Chc\n" /* Ctrl+Home to get to the beginning of the document */
+ "seq:ddrr\n" /* on the third line, after the second character */
+ "type:X\n",
+ html1, plain1)) {
g_test_fail ();
return;
}
+ html2 = HTML_PREFIX "<div>before citation</div>"
+ "<blockquote type='cite' " BLOCKQUOTE_STYLE ">"
+ "<div>cite level 1a</div>"
+ "<blockquote type='cite' " BLOCKQUOTE_STYLE ">"
+ "<div>ciX</div>"
+ "</blockquote>"
+ "</blockquote>"
+ "<div>Y</div>"
+ "<blockquote type='cite' " BLOCKQUOTE_STYLE ">"
+ "<blockquote type='cite' " BLOCKQUOTE_STYLE ">"
+ "<div>te level 2</div>"
+ "</blockquote>"
+ "<div>cite level 1b</div>"
+ "</blockquote>"
+ "<div>after citation</div>" HTML_SUFFIX;
+
+ plain2 = "before citation\n"
+ "> cite level 1a\n"
+ "> > ciX\n"
+ "Y\n"
+ "> > te level 2\n"
+ "> cite level 1b\n"
+ "after citation\n";
+
if (!test_utils_run_simple_test (fixture,
- "mode:plain\n",
- NULL,
- "> level 1\n"
- "> \n"
- "> level 1\n"
- "> > level 2\n"
- "> back in level 1\n"
- "\n"
- "out of the citation")) {
+ "type:\\nY\n",
+ html2, plain2)) {
g_test_fail ();
+ return;
}
-}
-static void
-test_cite_shortline (TestFixture *fixture)
-{
- if (!test_utils_process_commands (fixture,
- "mode:html\n")) {
+ html3 = HTML_PREFIX "<div>before citation</div>"
+ "<blockquote type='cite' " BLOCKQUOTE_STYLE ">"
+ "<div>cite level 1a</div>"
+ "<blockquote type='cite' " BLOCKQUOTE_STYLE ">"
+ "<div>ciX</div>"
+ "</blockquote>"
+ "</blockquote>"
+ "<div>Y</div>"
+ "<blockquote type='cite' " BLOCKQUOTE_STYLE ">"
+ "<blockquote type='cite' " BLOCKQUOTE_STYLE ">"
+ "<div>tZ<br>e level 2</div>"
+ "</blockquote>"
+ "<div>cite level 1b</div>"
+ "</blockquote>"
+ "<div>after citation</div>" HTML_SUFFIX;
+
+ plain3 = "before citation\n"
+ "> cite level 1a\n"
+ "> > ciX\n"
+ "Y\n"
+ "> > tZ\n"
+ "> > e level 2\n"
+ "> cite level 1b\n"
+ "after citation\n";
+
+ if (!test_utils_run_simple_test (fixture,
+ "seq:dr\n"
+ "type:Z\n"
+ "seq:Sns\n", /* soft Enter */
+ html3, plain3)) {
g_test_fail ();
return;
}
- test_utils_insert_content (fixture,
- "<html><head></head><body><blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div>Just one short line.</div>"
- "</blockquote></body></html>",
- E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+ html4 = HTML_PREFIX "<div>before citation</div>"
+ "<blockquote type='cite' " BLOCKQUOTE_STYLE ">"
+ "<div>cite level 1a</div>"
+ "<blockquote type='cite' " BLOCKQUOTE_STYLE ">"
+ "<div>ciX</div>"
+ "</blockquote>"
+ "</blockquote>"
+ "<div>Y</div>"
+ "<blockquote type='cite' " BLOCKQUOTE_STYLE ">"
+ "<blockquote type='cite' " BLOCKQUOTE_STYLE ">"
+ "<div>tZ<br>e level 2</div>"
+ "</blockquote>"
+ "</blockquote>"
+ "<div><br></div>"
+ "<blockquote type='cite' " BLOCKQUOTE_STYLE ">"
+ "<div><br></div>"
+ "</blockquote>"
+ "<div><br></div>"
+ "<blockquote type='cite' " BLOCKQUOTE_STYLE ">"
+ "<div>cite level 1b</div>"
+ "</blockquote>"
+ "<div><br></div>"
+ "<div>after citation</div>" HTML_SUFFIX;
+
+ plain4 = "before citation\n"
+ "> cite level 1a\n"
+ "> > ciX\n"
+ "Y\n"
+ "> > tZ\n"
+ "> > e level 2\n"
+ "\n"
+ "> \n"
+ "\n"
+ "> cite level 1b\n"
+ "\n"
+ "after citation\n";
if (!test_utils_run_simple_test (fixture,
- "",
- HTML_PREFIX "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div>Just one short line.</div>"
- "</blockquote>" HTML_SUFFIX,
- "> Just one short line.")) {
+ "seq:endhnden\n",
+ html4, plain4)) {
g_test_fail ();
return;
}
- if (!test_utils_process_commands (fixture,
- "seq:C\n"
- "type:a\n"
- "seq:cD\n")) {
+ if (!test_utils_run_simple_test (fixture,
+ "undo:undo:3\n",
+ html3, plain3)) {
g_test_fail ();
return;
}
- test_utils_insert_content (fixture,
- "<html><head></head><body><blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div>Just one short line.</div>"
- "</blockquote></body></html>",
- E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+ if (!test_utils_run_simple_test (fixture,
+ "undo:undo:2\n",
+ html2, plain2)) {
+ g_test_fail ();
+ return;
+ }
if (!test_utils_run_simple_test (fixture,
- "",
- HTML_PREFIX "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div>Just one short line.</div>"
- "</blockquote>" HTML_SUFFIX,
- "> Just one short line.")) {
+ "undo:undo:2\n",
+ html1, plain1)) {
g_test_fail ();
return;
}
- test_utils_insert_content (fixture,
- "<html><head></head><body><blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div>short line 1</div>"
- "<div>short line 2</div>"
- "<div>short line 3</div>"
- "</blockquote></body></html>",
- E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+ if (!test_utils_run_simple_test (fixture,
+ "undo:undo:1\n",
+ html0, plain0)) {
+ g_test_fail ();
+ return;
+ }
if (!test_utils_run_simple_test (fixture,
- "",
- HTML_PREFIX "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div>short line 1</div>"
- "<div>short line 2</div>"
- "<div>short line 3</div>"
- "</blockquote>" HTML_SUFFIX,
- "> short line 1\n"
- "> short line 2\n"
- "> short line 3")) {
+ "undo:redo:1\n",
+ html1, plain1)) {
g_test_fail ();
return;
}
- if (!test_utils_process_commands (fixture,
- "seq:C\n"
- "type:a\n"
- "seq:cD\n")) {
+ if (!test_utils_run_simple_test (fixture,
+ "undo:redo:2\n",
+ html2, plain2)) {
g_test_fail ();
return;
}
- test_utils_insert_content (fixture,
- "<html><head></head><body><blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div>short line 1</div>"
- "<div>short line 2</div>"
- "<div>short line 3</div>"
- "</blockquote></body></html>",
- E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+ if (!test_utils_run_simple_test (fixture,
+ "undo:redo:2\n",
+ html3, plain3)) {
+ g_test_fail ();
+ return;
+ }
if (!test_utils_run_simple_test (fixture,
- "",
- HTML_PREFIX "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div>short line 1</div>"
- "<div>short line 2</div>"
- "<div>short line 3</div>"
- "</blockquote>" HTML_SUFFIX,
- "> short line 1\n"
- "> short line 2\n"
- "> short line 3")) {
+ "undo:redo:3\n",
+ html4, plain4)) {
g_test_fail ();
return;
}
}
static void
-test_cite_longline (TestFixture *fixture)
+test_cite_editing_plain (TestFixture *fixture)
{
+ const gchar *plain0, *html0, *plain1, *html1, *plain2, *html2, *plain3, *html3, *plain4, *html4;
+
if (!test_utils_process_commands (fixture,
"mode:html\n")) {
g_test_fail ();
@@ -2056,135 +5209,229 @@ test_cite_longline (TestFixture *fixture)
}
test_utils_insert_content (fixture,
- "<html><head></head><body><blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div>This is the first paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>"
- "</blockquote></body></html>",
+ "<div>before citation</div>"
+ "<blockquote type='cite'>"
+ "<div>cite level 1a</div>"
+ "<blockquote type='cite'>"
+ "<div>cite level 2</div>"
+ "</blockquote>"
+ "<div>cite level 1b</div>"
+ "</blockquote>"
+ "<div>after citation</div>",
E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+ html0 = HTML_PREFIX "<div style='width: 71ch;'>before citation</div>"
+ "<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "cite level 1a</div>"
+ "<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR QUOTE_CHR) "cite level 2</div>"
+ "</blockquote>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "cite level 1b</div>"
+ "</blockquote>"
+ "<div style='width: 71ch;'>after citation</div>" HTML_SUFFIX;
+
+ plain0 = "before citation\n"
+ "> cite level 1a\n"
+ "> > cite level 2\n"
+ "> cite level 1b\n"
+ "after citation\n";
+
+ if (!test_utils_run_simple_test (fixture, "mode:plain\n", html0, plain0)) {
+ g_test_fail ();
+ return;
+ }
+
+ html1 = HTML_PREFIX "<div style='width: 71ch;'>before citation</div>"
+ "<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "cite level 1a</div>"
+ "<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR QUOTE_CHR) "ciXte level 2</div>"
+ "</blockquote>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "cite level 1b</div>"
+ "</blockquote>"
+ "<div style='width: 71ch;'>after citation</div>" HTML_SUFFIX;
+
+ plain1 = "before citation\n"
+ "> cite level 1a\n"
+ "> > ciXte level 2\n"
+ "> cite level 1b\n"
+ "after citation\n";
+
if (!test_utils_run_simple_test (fixture,
- "",
- HTML_PREFIX "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div>This is the first paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>"
- "</blockquote>" HTML_SUFFIX,
- "> This is the first paragraph of a quoted text which has some long text\n"
- "> to test. It has the second sentence as well.")) {
+ "seq:Chc\n" /* Ctrl+Home to get to the beginning of the document */
+ "seq:ddrr\n" /* on the third line, after the second character */
+ "type:X\n",
+ html1, plain1)) {
g_test_fail ();
return;
}
- if (!test_utils_process_commands (fixture,
- "seq:C\n"
- "type:a\n"
- "seq:cDb\n")) {
+ html2 = HTML_PREFIX "<div style='width: 71ch;'>before citation</div>"
+ "<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "cite level 1a</div>"
+ "<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR QUOTE_CHR) "ciX</div>"
+ "</blockquote>"
+ "</blockquote>"
+ "<div style='width: 71ch;'>Y</div>"
+ "<blockquote type='cite'>"
+ "<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR QUOTE_CHR) "te level 2</div>"
+ "</blockquote>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "cite level 1b</div>"
+ "</blockquote>"
+ "<div style='width: 71ch;'>after citation</div>" HTML_SUFFIX;
+
+ plain2 = "before citation\n"
+ "> cite level 1a\n"
+ "> > ciX\n"
+ "Y\n"
+ "> > te level 2\n"
+ "> cite level 1b\n"
+ "after citation\n";
+
+ if (!test_utils_run_simple_test (fixture,
+ "type:\\nY\n",
+ html2, plain2)) {
g_test_fail ();
return;
}
- test_utils_insert_content (fixture,
- "<html><head></head><body><blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div>This is the first paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>"
- "</blockquote></body></html>",
- E_CONTENT_EDITOR_INSERT_TEXT_HTML | E_CONTENT_EDITOR_INSERT_REPLACE_ALL);
+ html3 = HTML_PREFIX "<div style='width: 71ch;'>before citation</div>"
+ "<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "cite level 1a</div>"
+ "<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR QUOTE_CHR) "ciX</div>"
+ "</blockquote>"
+ "</blockquote>"
+ "<div style='width: 71ch;'>Y</div>"
+ "<blockquote type='cite'>"
+ "<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR QUOTE_CHR) "tZ</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR QUOTE_CHR) "e level 2</div>"
+ "</blockquote>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "cite level 1b</div>"
+ "</blockquote>"
+ "<div style='width: 71ch;'>after citation</div>" HTML_SUFFIX;
+
+ plain3 = "before citation\n"
+ "> cite level 1a\n"
+ "> > ciX\n"
+ "Y\n"
+ "> > tZ\n"
+ "> > e level 2\n"
+ "> cite level 1b\n"
+ "after citation\n";
if (!test_utils_run_simple_test (fixture,
- "",
- HTML_PREFIX "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div>This is the first paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>"
- "</blockquote>" HTML_SUFFIX,
- "> This is the first paragraph of a quoted text which has some long text\n"
- "> to test. It has the second sentence as well.")) {
+ "seq:dr\n"
+ "type:Z\n"
+ "seq:Sns\n", /* soft Enter */
+ html3, plain3)) {
g_test_fail ();
return;
}
- test_utils_insert_content (fixture,
- "<html><head></head><body><blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div>This is the first paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>"
- "<div>This is the second paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>"
- "<div>This is the third paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>"
- "</blockquote><br>after quote</body></html>",
- E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+ html4 = HTML_PREFIX "<div style='width: 71ch;'>before citation</div>"
+ "<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "cite level 1a</div>"
+ "<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR QUOTE_CHR) "ciX</div>"
+ "</blockquote>"
+ "</blockquote>"
+ "<div style='width: 71ch;'>Y</div>"
+ "<blockquote type='cite'>"
+ "<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR QUOTE_CHR) "tZ</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR QUOTE_CHR) "e level 2</div>"
+ "</blockquote>"
+ "</blockquote>"
+ "<div style='width: 71ch;'><br></div>"
+ "<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<br></div>"
+ "</blockquote>"
+ "<div style='width: 71ch;'><br></div>"
+ "<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "cite level 1b</div>"
+ "</blockquote>"
+ "<div style='width: 71ch;'><br></div>"
+ "<div style='width: 71ch;'>after citation</div>" HTML_SUFFIX;
+
+ plain4 = "before citation\n"
+ "> cite level 1a\n"
+ "> > ciX\n"
+ "Y\n"
+ "> > tZ\n"
+ "> > e level 2\n"
+ "\n"
+ "> \n"
+ "\n"
+ "> cite level 1b\n"
+ "\n"
+ "after citation\n";
if (!test_utils_run_simple_test (fixture,
- "",
- HTML_PREFIX "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div>This is the first paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>"
- "<div>This is the second paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>"
- "<div>This is the third paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</div>"
- "</blockquote><br>after quote" HTML_SUFFIX,
- "> This is the first paragraph of a quoted text which has some long text\n"
- "> to test. It has the second sentence as well.\n"
- "> This is the second paragraph of a quoted text which has some long\n"
- "> text to test. It has the second sentence as well.\n"
- "> This is the third paragraph of a quoted text which has some long text\n"
- "> to test. It has the second sentence as well.\n"
- "\nafter quote")) {
+ "seq:endhnden\n",
+ html4, plain4)) {
g_test_fail ();
return;
}
-}
-static void
-test_cite_reply_html (TestFixture *fixture)
-{
- /* This test is known to fail, skip it. */
- printf ("SKIPPED ");
+ if (!test_utils_run_simple_test (fixture,
+ "undo:undo:3\n",
+ html3, plain3)) {
+ g_test_fail ();
+ return;
+ }
-#if 0
- if (!test_utils_process_commands (fixture,
- "mode:html\n")) {
+ if (!test_utils_run_simple_test (fixture,
+ "undo:undo:2\n",
+ html2, plain2)) {
g_test_fail ();
return;
}
- test_utils_insert_content (fixture,
- "<pre>line 1\n"
- "line 2\n"
- "</pre><span class=\"-x-evo-to-body\" data-credits=\"On Today, User wrote:\"></span>"
- "<span class=\"-x-evo-cite-body\"></span>",
- E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+ if (!test_utils_run_simple_test (fixture,
+ "undo:undo:2\n",
+ html1, plain1)) {
+ g_test_fail ();
+ return;
+ }
if (!test_utils_run_simple_test (fixture,
- "",
- HTML_PREFIX "<div>On Today, User wrote:</div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE "><pre>line 1\n"
- "line 2\n"
- "</pre></blockquote>" HTML_SUFFIX,
- "On Today, User wrote:\n"
- "> line 1\n"
- "> line 2\n"
- "> "))
+ "undo:undo:1\n",
+ html0, plain0)) {
g_test_fail ();
-#endif
-}
+ return;
+ }
-static void
-test_cite_reply_plain (TestFixture *fixture)
-{
- if (!test_utils_process_commands (fixture,
- "mode:plain\n")) {
+ if (!test_utils_run_simple_test (fixture,
+ "undo:redo:1\n",
+ html1, plain1)) {
g_test_fail ();
return;
}
- test_utils_insert_content (fixture,
- "<pre>line 1\n"
- "line 2\n\n"
- "</pre><span class=\"-x-evo-to-body\" data-credits=\"On Today, User wrote:\"></span>"
- "<span class=\"-x-evo-cite-body\"></span>",
- E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+ if (!test_utils_run_simple_test (fixture,
+ "undo:redo:2\n",
+ html2, plain2)) {
+ g_test_fail ();
+ return;
+ }
if (!test_utils_run_simple_test (fixture,
- "",
- HTML_PREFIX "<div style=\"width: 71ch;\">On Today, User wrote:</div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE "><div style=\"width: 71ch;\">> line 1</div>"
- "<div style=\"width: 71ch;\">> line 2</div>"
- "<div style=\"width: 71ch;\">> <br></div></blockquote>" HTML_SUFFIX,
- "On Today, User wrote:\n"
- "> line 1\n"
- "> line 2\n"
- "> "))
+ "undo:redo:2\n",
+ html3, plain3)) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:redo:3\n",
+ html4, plain4)) {
g_test_fail ();
+ return;
+ }
}
static void
@@ -2206,7 +5453,7 @@ test_undo_text_typed (TestFixture *fixture)
"undo:drop\n"
"type:xt\n",
HTML_PREFIX "<div>some text</div>" HTML_SUFFIX,
- "some text"))
+ "some text\n"))
g_test_fail ();
}
@@ -2221,7 +5468,7 @@ test_undo_text_forward_delete (TestFixture *fixture)
"undo:redo\n"
"undo:undo\n",
HTML_PREFIX "<div>some text to delete</div>" HTML_SUFFIX,
- "some text to delete"))
+ "some text to delete\n"))
g_test_fail ();
}
@@ -2236,7 +5483,7 @@ test_undo_text_backward_delete (TestFixture *fixture)
"undo:redo\n"
"undo:undo\n",
HTML_PREFIX "<div>some text to delete</div>" HTML_SUFFIX,
- "some text to delete"))
+ "some text to delete\n"))
g_test_fail ();
}
@@ -2250,7 +5497,7 @@ test_undo_text_cut (TestFixture *fixture)
"action:cut\n"
"undo:undo\n",
NULL,
- "some text to delete"))
+ "some text to delete\n"))
g_test_fail ();
}
@@ -2265,104 +5512,104 @@ test_undo_style (TestFixture *fixture)
"action:bold\n"
"type:bold\n"
"undo:save\n" /* 2 */
- "undo:undo:5\n"
+ "undo:undo:4\n"
"undo:test:2\n"
- "undo:redo:5\n"
+ "undo:redo:4\n"
"undo:test\n"
"undo:drop\n" /* drop the save 2 */
- "undo:undo:5\n"
+ "undo:undo:4\n"
"type:bold\n"
"seq:CSlsc\n"
"action:bold\n"
"undo:save\n" /* 2 */
- "undo:undo:5\n"
+ "undo:undo:2\n"
"undo:test:2\n"
- "undo:redo:5\n"
+ "undo:redo:2\n"
"undo:test\n"
"undo:drop\n" /* drop the save 2 */
- "undo:undo:5\n"
+ "undo:undo:2\n"
"action:italic\n"
"type:italic\n"
"undo:save\n" /* 2 */
- "undo:undo:7\n"
+ "undo:undo:6\n"
"undo:test:2\n"
- "undo:redo:7\n"
+ "undo:redo:6\n"
"undo:test\n"
"undo:drop\n" /* drop the save 2 */
- "undo:undo:7\n"
+ "undo:undo:6\n"
"type:italic\n"
"seq:CSlsc\n"
"action:italic\n"
"undo:save\n" /* 2 */
- "undo:undo:7\n"
+ "undo:undo:2\n"
"undo:test:2\n"
- "undo:redo:7\n"
+ "undo:redo:2\n"
"undo:test\n"
"undo:drop\n" /* drop the save 2 */
- "undo:undo:7\n"
+ "undo:undo:2\n"
"action:underline\n"
"type:underline\n"
"undo:save\n" /* 2 */
- "undo:undo:10\n"
+ "undo:undo:9\n"
"undo:test:2\n"
- "undo:redo:10\n"
+ "undo:redo:9\n"
"undo:test\n"
"undo:drop\n" /* drop the save 2 */
- "undo:undo:10\n"
+ "undo:undo:9\n"
"type:underline\n"
"seq:CSlsc\n"
"action:underline\n"
"undo:save\n" /* 2 */
- "undo:undo:10\n"
+ "undo:undo:2\n"
"undo:test:2\n"
- "undo:redo:10\n"
+ "undo:redo:2\n"
"undo:test\n"
"undo:drop\n" /* drop the save 2 */
- "undo:undo:10\n"
+ "undo:undo:2\n"
"action:strikethrough\n"
"type:strikethrough\n"
"undo:save\n" /* 2 */
- "undo:undo:14\n"
+ "undo:undo:13\n"
"undo:test:2\n"
- "undo:redo:14\n"
+ "undo:redo:13\n"
"undo:test\n"
"undo:drop\n" /* drop the save 2 */
- "undo:undo:14\n"
+ "undo:undo:13\n"
"type:strikethrough\n"
"seq:CSlsc\n"
"action:strikethrough\n"
"undo:save\n" /* 2 */
- "undo:undo:14\n"
+ "undo:undo:2\n"
"undo:test:2\n"
- "undo:redo:14\n"
+ "undo:redo:2\n"
"undo:test\n"
"undo:drop\n" /* drop the save 2 */
- "undo:undo:14\n"
+ "undo:undo:2\n"
- "action:monospaced\n"
+ "font-name:monospace\n"
"type:monospaced\n"
"undo:save\n" /* 2 */
- "undo:undo:11\n"
+ "undo:undo:10\n"
"undo:test:2\n"
- "undo:redo:11\n"
+ "undo:redo:10\n"
"undo:test\n"
"undo:drop\n" /* drop the save 2 */
- "undo:undo:11\n"
+ "undo:undo:10\n"
"type:monospaced\n"
"seq:CSlsc\n"
- "action:monospaced\n"
+ "font-name:monospace\n"
"undo:save\n" /* 2 */
- "undo:undo:11\n"
+ "undo:undo:2\n"
"undo:test:2\n"
- "undo:redo:11\n"
+ "undo:redo:2\n"
"undo:test\n"
"undo:drop\n" /* drop the save 2 */
- "undo:undo:11\n",
+ "undo:undo:2\n",
HTML_PREFIX "<div>The first paragraph text</div><div><br></div>" HTML_SUFFIX,
- "The first paragraph text\n"))
+ "The first paragraph text\n\n"))
g_test_fail ();
}
@@ -2427,15 +5674,15 @@ test_undo_justify (TestFixture *fixture)
"seq:CSlsc\n"
"action:justify-right\n"
"undo:save\n" /* 2 */
- "undo:undo:6\n"
+ "undo:undo:2\n"
"undo:test:2\n"
- "undo:redo:6\n"
+ "undo:redo:2\n"
"undo:test\n"
"undo:drop\n" /* drop the save 2 */
- "undo:undo:6\n",
+ "undo:undo:2\n",
HTML_PREFIX "<div>The first paragraph text</div><div><br></div>" HTML_SUFFIX,
- "The first paragraph text\n"))
+ "The first paragraph text\n\n"))
g_test_fail ();
}
@@ -2460,12 +5707,12 @@ test_undo_indent (TestFixture *fixture)
"seq:CSlsc\n"
"action:indent\n"
"undo:save\n" /* 2 */
- "undo:undo:5\n"
+ "undo:undo:2\n"
"undo:test:2\n"
- "undo:redo:5\n"
+ "undo:redo:2\n"
"undo:test\n"
"undo:drop\n" /* drop the save 2 */
- "undo:undo:5\n"
+ "undo:undo:2\n"
"type:text\n"
"undo:save\n" /* 2 */
@@ -2484,7 +5731,7 @@ test_undo_indent (TestFixture *fixture)
"undo:undo:3\n"
"undo:test\n"
"undo:drop\n" /* drop the save 2 */
- "undo:undo:4\n"
+ "undo:undo:1\n"
"undo:test\n"
"type:level 1\\n\n"
@@ -2516,15 +5763,15 @@ test_undo_indent (TestFixture *fixture)
"undo:drop:2\n" /* drop the save 3 and 2 */
"undo:save\n" /* 2 */
- "undo:undo:30\n" /* 6x action:indent, 24x type "level X\\n" */
+ "undo:undo:18\n" /* 6x action:indent, 3x type "level X\\n" (= 4 undo steps) */
"undo:test:2\n"
- "undo:redo:30\n"
+ "undo:redo:18\n"
"undo:test\n"
"undo:drop\n" /* drop the save 2 */
- "undo:undo:30\n",
+ "undo:undo:18\n",
HTML_PREFIX "<div>The first paragraph text</div><div><br></div>" HTML_SUFFIX,
- "The first paragraph text\n"))
+ "The first paragraph text\n\n"))
g_test_fail ();
}
@@ -2542,11 +5789,11 @@ test_undo_link_paste_html (TestFixture *fixture)
"undo:save\n" /* 2 */
"undo:undo:2\n"
"undo:test:2\n"
- "undo:undo:5\n"
- "undo:redo:7\n"
+ "undo:undo:2\n"
+ "undo:redo:4\n"
"undo:test\n",
HTML_PREFIX "<div>URL:</div><div><a
href=\"http://www.gnome.org\">http://www.gnome.org</a></div><div><br></div>" HTML_SUFFIX,
- "URL:\nhttp://www.gnome.org\n"))
+ "URL:\nhttp://www.gnome.org\n\n"))
g_test_fail ();
}
@@ -2570,7 +5817,7 @@ test_undo_link_paste_plain (TestFixture *fixture)
HTML_PREFIX "<div style=\"width: 71ch;\">URL:</div>"
"<div style=\"width: 71ch;\"><a href=\"http://www.gnome.org\">http://www.gnome.org</a></div>"
"<div style=\"width: 71ch;\"><br></div>" HTML_SUFFIX,
- "URL:\nhttp://www.gnome.org\n"))
+ "URL:\nhttp://www.gnome.org\n\n"))
g_test_fail ();
}
@@ -2601,14 +5848,14 @@ test_delete_quoted (TestFixture *fixture)
"undo:test\n"
"undo:redo:2",
HTML_PREFIX "<div style=\"width: 71ch;\">On Thu, 2016-09-15 at 08:08 -0400, user wrote:</div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div style=\"width: 71ch;\">> a</div>"
- "<div style=\"width: 71ch;\">> b</div>"
+ "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "a</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "b</div>"
"</blockquote>"
HTML_SUFFIX,
"On Thu, 2016-09-15 at 08:08 -0400, user wrote:\n"
"> a\n"
- "> b"))
+ "> b\n"))
g_test_fail ();
}
@@ -2632,16 +5879,16 @@ test_delete_after_quoted (TestFixture *fixture)
E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
if (!test_utils_run_simple_test (fixture,
- "seq:ddddbb\n",
+ "seq:dddb\n",
HTML_PREFIX "<div style=\"width: 71ch;\">On Thu, 2016-09-15 at 08:08 -0400, user wrote:</div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<pre>> a</pre>"
- "<pre>> b<br></pre>"
+ "<blockquote type=\"cite\">"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "a</pre>"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "b</pre>"
"</blockquote>"
HTML_SUFFIX,
"On Thu, 2016-09-15 at 08:08 -0400, user wrote:\n"
"> a\n"
- "> b"))
+ "> b\n"))
g_test_fail ();
}
@@ -2661,21 +5908,100 @@ test_delete_quoted_selection (TestFixture *fixture)
"undo:test\n"
"undo:redo\n"
"undo:undo\n"
- "seq:d\n"
+ "seq:r\n"
"type:X\n",
HTML_PREFIX "<div style=\"width: 71ch;\">line 0</div>"
- "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
- "<div style=\"width: 71ch;\">> line 1</div>"
- "<div style=\"width: 71ch;\">> <br></div>"
- "<div style=\"width: 71ch;\">> line 2</div>"
- "<div style=\"width: 71ch;\">> X</div>"
+ "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "line 1</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "<br></div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "line 2</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "X</div>"
"</blockquote>"
HTML_SUFFIX,
"line 0\n"
"> line 1\n"
"> \n"
"> line 2\n"
- "> X"))
+ "> X\n"))
+ g_test_fail ();
+}
+
+static void
+test_delete_quoted_multiselect (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("line 1\nline 2\nline 3", FALSE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:paste-quote\n"
+ "type:X\n"
+ "undo:save\n" /* 1 */
+ "seq:ChcrrSdsD\n",
+ HTML_PREFIX "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<div>line 2</div>"
+ "<div>line 3X</div>"
+ "</blockquote>"
+ HTML_SUFFIX,
+ "> line 2\n"
+ "> line 3X\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:undo\n"
+ "undo:test\n"
+ "undo:redo\n"
+ "undo:drop:1\n"
+ "seq:Cec\n" /* Go to the end of the document (Ctrl+End) */
+ "type:\\nY\n",
+ HTML_PREFIX "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<div>line 2</div>"
+ "<div>line 3X</div>"
+ "</blockquote>"
+ "<div>Y</div>"
+ HTML_SUFFIX,
+ "> line 2\n"
+ "> line 3X\n"
+ "Y\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture, "<body></body>", E_CONTENT_EDITOR_INSERT_REPLACE_ALL |
E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "action:paste-quote\n"
+ "type:X\n"
+ "undo:save\n" /* 1 */
+ "seq:ChcrrSdsD\n",
+ HTML_PREFIX "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "line 2</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "line 3X</div>"
+ "</blockquote>"
+ HTML_SUFFIX,
+ "> line 2\n"
+ "> line 3X\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "undo:undo\n"
+ "undo:test\n"
+ "undo:redo\n"
+ "seq:Cec\n" /* Go to the end of the document (Ctrl+End) */
+ "type:\\nY\n",
+ HTML_PREFIX "<blockquote type=\"cite\">"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "line 2</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "line 3X</div>"
+ "</blockquote>"
+ "<div style=\"width: 71ch;\">Y</div>"
+ HTML_SUFFIX,
+ "> line 2\n"
+ "> line 3X\n"
+ "Y\n"))
g_test_fail ();
}
@@ -2689,14 +6015,15 @@ test_replace_dialog (TestFixture *fixture)
"seq:h\n"
"action:show-replace\n"
"type:to\t2\n"
- "type:\t\t\t\t\t\t\n" /* Jump to 'Replace' */
- "seq:n\n" /* Press it */
+ "seq:A\n" /* Press 'Alt+R' to press 'Replace' button */
+ "type:r\n"
+ "seq:a\n"
"seq:^\n" /* Close the dialog */
"undo:undo\n"
"undo:test:1\n"
"undo:redo\n",
HTML_PREFIX "<div style=\"width: 71ch;\">text 2 replace</div>" HTML_SUFFIX,
- "text 2 replace"))
+ "text 2 replace\n"))
g_test_fail ();
}
@@ -2710,14 +6037,375 @@ test_replace_dialog_all (TestFixture *fixture)
"seq:h\n"
"action:show-replace\n"
"type:e\t3\n"
- "type:\t\t\t\t\t\t\t\n" /* Jump to 'Replace All' */
- "seq:n\n" /* Press it */
+ "seq:A\n" /* Press 'Alt+A' to press 'Replace All' button */
+ "type:a\n"
+ "seq:a\n"
"seq:^\n" /* Close the dialog */
"undo:undo\n"
"undo:test:1\n"
"undo:redo\n",
HTML_PREFIX "<div style=\"width: 71ch;\">t3xt to r3plac3</div>" HTML_SUFFIX,
- "t3xt to r3plac3"))
+ "t3xt to r3plac3\n"))
+ g_test_fail ();
+}
+
+static void
+test_wrap_basic (TestFixture *fixture)
+{
+ test_utils_fixture_change_setting_int32 (fixture, "org.gnome.evolution.mail",
"composer-word-wrap-length", 10);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:123 456 789 123 456\\n\n"
+ "type:a b\\n\n"
+ "type:c \\n\n"
+ "type:d\\n\n"
+ "type: e f\\n\n"
+ "type:\\n\n"
+ "type:123 456 7 8 9 12345 1 2 3 456 789\n"
+ "action:select-all\n"
+ "action:wrap-lines\n",
+ HTML_PREFIX "<div>123 456<br>"
+ "789 123<br>"
+ "456 a b c <br>"
+ "d e f</div>"
+ "<div><br></div>"
+ "<div>123 456 7<br>"
+ "8 9 12345<br>"
+ "1 2 3 456<br>"
+ "789</div>" HTML_SUFFIX,
+ "123 456\n"
+ "789 123\n"
+ "456 a b c \n"
+ "d e f\n"
+ "\n"
+ "123 456 7\n"
+ "8 9 12345\n"
+ "1 2 3 456\n"
+ "789\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "action:select-all\n"
+ "seq:D\n"
+ "type:123 456 7 8 901234567890123456 1 2 3 4 5 6 7\\n\n"
+ "type:1234567890123456 12345678901234567890 1 2 3 4 5 6 7 8\\n\n"
+ "type:12345678 123456789 1234567890 123 456 78\n"
+ "action:select-all\n"
+ "action:wrap-lines\n",
+ HTML_PREFIX "<div>123 456 7<br>"
+ "8<br>"
+ "901234567890123456<br>"
+ "1 2 3 4 5<br>"
+ "6 7<br>"
+ "1234567890123456<br>"
+ "12345678901234567890<br>"
+ "1 2 3 4 5<br>"
+ "6 7 8<br>"
+ "12345678<br>"
+ "123456789<br>"
+ "1234567890<br>"
+ "123 456 78</div>" HTML_SUFFIX,
+ "123 456 7\n"
+ "8\n"
+ "9012345678\n"
+ "90123456\n"
+ "1 2 3 4 5\n"
+ "6 7\n"
+ "1234567890\n"
+ "123456\n"
+ "1234567890\n"
+ "1234567890\n"
+ "1 2 3 4 5\n"
+ "6 7 8\n"
+ "12345678\n"
+ "123456789\n"
+ "1234567890\n"
+ "123 456 78\n")) {
+ g_test_fail ();
+ return;
+ }
+}
+
+static void
+test_wrap_nested (TestFixture *fixture)
+{
+ test_utils_fixture_change_setting_int32 (fixture, "org.gnome.evolution.mail",
"composer-word-wrap-length", 10);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:123 4 \n"
+ "action:bold\n"
+ "type:b\n"
+ "action:bold\n"
+ "type: 5 67 89 \n"
+ "action:bold\n"
+ "type:bold text\n"
+ "action:bold\n"
+ "type: 123 456 \n"
+ "action:italic\n"
+ "type:italic text \n"
+ "action:underline\n"
+ "type:and underline text\n"
+ "action:underline\n"
+ "type: xyz\n"
+ "action:italic\n"
+ "type: 7 8 9 1 2 3 4 5\n"
+ "action:select-all\n"
+ "action:wrap-lines\n",
+ HTML_PREFIX "<div>123 4 <b>b</b> 5<br>"
+ "67 89 <b>bold<br>"
+ "text</b> 123<br>"
+ "456 <i>italic<br>"
+ "text <u>and<br>"
+ "underline<br>"
+ "text</u> xyz</i> 7<br>"
+ "8 9 1 2 3<br>"
+ "4 5</div>" HTML_SUFFIX,
+ "123 4 b 5\n"
+ "67 89 bold\n"
+ "text 123\n"
+ "456 italic\n"
+ "text and\n"
+ "underline\n"
+ "text xyz 7\n"
+ "8 9 1 2 3\n"
+ "4 5\n"))
+ g_test_fail ();
+}
+
+static void
+test_pre_split_simple_html (TestFixture *fixture)
+{
+ if (!test_utils_process_commands (fixture,
+ "mode:html\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<pre>line 1\n"
+ "line 2</pre>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "",
+ HTML_PREFIX "<pre>line 1</pre>"
+ "<pre>line 2</pre>"
+ HTML_SUFFIX,
+ "line 1\n"
+ "line 2\n"))
+ g_test_fail ();
+}
+
+static void
+test_pre_split_simple_plain (TestFixture *fixture)
+{
+ if (!test_utils_process_commands (fixture,
+ "mode:plain\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<pre>line 1\n"
+ "line 2</pre>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "",
+ HTML_PREFIX "<pre>line 1</pre>"
+ "<pre>line 2</pre>"
+ HTML_SUFFIX,
+ "line 1\n"
+ "line 2\n"))
+ g_test_fail ();
+}
+
+static void
+test_pre_split_complex_html (TestFixture *fixture)
+{
+ if (!test_utils_process_commands (fixture,
+ "mode:html\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<div>leading text</div>"
+ "<pre><b>bold1</b><blockquote type=\"cite\">text 1\n"
+ "text 2\n"
+ "text 3</blockquote>"
+ "text A<i>italic</i>text B\n"
+ "<b>bold2</b>"
+ "</pre>"
+ "<div>mid text</div>"
+ "<pre><blockquote type=\"cite\">level 1\n"
+ "E-mail: <<a href=\"mailto:user@no.where\">user@no.where</a>> line\n"
+ "Phone: 1234567890\n"
+ "<div>div in\npre</div>"
+ "<blockquote type=\"cite\">level 2\n"
+ "\n"
+ "level 2\n</blockquote>"
+ "</blockquote></pre>"
+ "<pre>text\n"
+ "text 2<i>italic 1</i>\n"
+ "<i>italic 2</i> text 3\n"
+ "pre <i>imid</i> pos\n"
+ "<i>ipre</i> mid <i>ipos</i>\n"
+ "<i>ipre2</i> mid2 <i>i<b>pos</b>2</i> pos2\n</pre>"
+ "<div>closing text</div>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "",
+ HTML_PREFIX "<div>leading text</div>"
+ "<pre><b>bold1</b></pre>"
+ "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<pre>text 1</pre>"
+ "<pre>text 2</pre>"
+ "<pre>text 3</pre>"
+ "</blockquote>"
+ "<pre>text A<i>italic</i>text B</pre>"
+ "<pre><b>bold2</b></pre>"
+ "<div>mid text</div>"
+ "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<pre>level 1</pre>"
+ "<pre>E-mail: <<a href=\"mailto:user@no.where\">user@no.where</a>> line</pre>"
+ "<pre>Phone: 1234567890</pre>"
+ "<pre><div>div in\npre</div></pre>"
+ "<blockquote type=\"cite\" " BLOCKQUOTE_STYLE ">"
+ "<pre>level 2</pre>"
+ "<pre><br></pre>"
+ "<pre>level 2</pre>"
+ "</blockquote>"
+ "</blockquote>"
+ "<pre>text</pre>"
+ "<pre>text 2<i>italic 1</i></pre>"
+ "<pre><i>italic 2</i> text 3</pre>"
+ "<pre>pre <i>imid</i> pos</pre>"
+ "<pre><i>ipre</i> mid <i>ipos</i></pre>"
+ "<pre><i>ipre2</i> mid2 <i>i<b>pos</b>2</i> pos2</pre>"
+ "<div>closing text</div>"
+ HTML_SUFFIX,
+ "leading text\n"
+ "bold1\n"
+ "> text 1\n"
+ "> text 2\n"
+ "> text 3\n"
+ "text Aitalictext B\n"
+ "bold2\n"
+ "mid text\n"
+ "> level 1\n"
+ "> E-mail: <user@no.where> line\n"
+ "> Phone: 1234567890\n"
+ "> > div in\n" /* this and th ebelow line is level 1 in quotation, but due to nested <div> in
<pre> the EvoConvert */
+ "> > pre\n" /* doubles quotation marks. It's not ideal, but it's a broken HTML anyway
(broken for the HTML editor). */
+ "> > level 2\n"
+ "> > \n"
+ "> > level 2\n"
+ "text\n"
+ "text 2italic 1\n"
+ "italic 2 text 3\n"
+ "pre imid pos\n"
+ "ipre mid ipos\n"
+ "ipre2 mid2 ipos2 pos2\n"
+ "closing text\n"))
+ g_test_fail ();
+}
+
+static void
+test_pre_split_complex_plain (TestFixture *fixture)
+{
+ if (!test_utils_process_commands (fixture,
+ "mode:plain\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<div>leading text</div>"
+ "<pre><b>bold1</b><blockquote type=\"cite\">text 1\n"
+ "text 2\n"
+ "text 3</blockquote>"
+ "text A<i>italic</i>text B\n"
+ "<b>bold2</b>"
+ "</pre>"
+ "<div>mid text</div>"
+ "<pre><blockquote type=\"cite\">level 1\n"
+ "E-mail: <<a href=\"mailto:user@no.where\">user@no.where</a>> line\n"
+ "Phone: 1234567890\n"
+ "<div>div in\npre</div>"
+ "<blockquote type=\"cite\">level 2\n"
+ "\n"
+ "level 2\n</blockquote>"
+ "</blockquote></pre>"
+ "<pre>text\n"
+ "text 2<i>italic 1</i>\n"
+ "<i>italic 2</i> text 3\n"
+ "pre <i>imid</i> pos\n"
+ "<i>ipre</i> mid <i>ipos</i>\n"
+ "<i>ipre2</i> mid2 <i>i<b>pos</b>2</i> pos2\n</pre>"
+ "<div>closing text</div>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "",
+ HTML_PREFIX "<div style='width: 71ch;'>leading text</div>"
+ "<pre><b>bold1</b></pre>"
+ "<blockquote type=\"cite\">"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "text 1</pre>"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "text 2</pre>"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "text 3</pre>"
+ "</blockquote>"
+ "<pre>text A<i>italic</i>text B</pre>"
+ "<pre><b>bold2</b></pre>"
+ "<div style='width: 71ch;'>mid text</div>"
+ "<blockquote type=\"cite\">"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "level 1</pre>"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "E-mail: <<a
href=\"mailto:user@no.where\">user@no.where</a>> line</pre>"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "Phone: 1234567890</pre>"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "div in</pre>"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR) "pre</pre>"
+ "<blockquote type=\"cite\">"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR QUOTE_CHR) "level 2</pre>"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR QUOTE_CHR) "<br></pre>"
+ "<pre>" QUOTE_SPAN (QUOTE_CHR QUOTE_CHR) "level 2</pre>"
+ "</blockquote>"
+ "</blockquote>"
+ "<pre>text</pre>"
+ "<pre>text 2<i>italic 1</i></pre>"
+ "<pre><i>italic 2</i> text 3</pre>"
+ "<pre>pre <i>imid</i> pos</pre>"
+ "<pre><i>ipre</i> mid <i>ipos</i></pre>"
+ "<pre><i>ipre2</i> mid2 <i>i<b>pos</b>2</i> pos2</pre>"
+ "<div style='width: 71ch;'>closing text</div>"
+ HTML_SUFFIX,
+ "leading text\n"
+ "bold1\n"
+ "> text 1\n"
+ "> text 2\n"
+ "> text 3\n"
+ "text Aitalictext B\n"
+ "bold2\n"
+ "mid text\n"
+ "> level 1\n"
+ "> E-mail: <user@no.where> line\n"
+ "> Phone: 1234567890\n"
+ "> div in\n"
+ "> pre\n"
+ "> > level 2\n"
+ "> > \n"
+ "> > level 2\n"
+ "text\n"
+ "text 2italic 1\n"
+ "italic 2 text 3\n"
+ "pre imid pos\n"
+ "ipre mid ipos\n"
+ "ipre2 mid2 ipos2 pos2\n"
+ "closing text\n"))
g_test_fail ();
}
@@ -2767,6 +6455,7 @@ main (gint argc,
user settings when playing with them. */
g_setenv ("GIO_EXTRA_MODULES", EVOLUTION_TESTGIOMODULESDIR, TRUE);
g_setenv ("GSETTINGS_BACKEND", TEST_KEYFILE_SETTINGS_BACKEND_NAME, TRUE);
+ g_setenv ("E_HTML_EDITOR_TEST_SOURCES", "1", FALSE);
g_setenv (TEST_KEYFILE_SETTINGS_FILENAME_ENVVAR, test_keyfile_filename, TRUE);
g_test_init (&argc, &argv, NULL);
@@ -2797,110 +6486,133 @@ main (gint argc,
e_util_init_main_thread (NULL);
e_passwords_init ();
+ gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (), EVOLUTION_ICONDIR);
+
modules = e_module_load_all_in_directory (EVOLUTION_MODULEDIR);
g_list_free_full (modules, (GDestroyNotify) g_type_module_unuse);
test_utils_add_test ("/create/editor", test_create_editor);
- test_utils_add_test ("/style/bold/selection", test_style_bold_selection);
- test_utils_add_test ("/style/bold/typed", test_style_bold_typed);
- test_utils_add_test ("/style/italic/selection", test_style_italic_selection);
- test_utils_add_test ("/style/italic/typed", test_style_italic_typed);
- test_utils_add_test ("/style/underline/selection", test_style_underline_selection);
- test_utils_add_test ("/style/underline/typed", test_style_underline_typed);
- test_utils_add_test ("/style/strikethrough/selection", test_style_strikethrough_selection);
- test_utils_add_test ("/style/strikethrough/typed", test_style_strikethrough_typed);
- test_utils_add_test ("/style/monospace/selection", test_style_monospace_selection);
- test_utils_add_test ("/style/monospace/typed", test_style_monospace_typed);
+ test_utils_add_test ("/style/bold-selection", test_style_bold_selection);
+ test_utils_add_test ("/style/bold-typed", test_style_bold_typed);
+ test_utils_add_test ("/style/italic-selection", test_style_italic_selection);
+ test_utils_add_test ("/style/italic-typed", test_style_italic_typed);
+ test_utils_add_test ("/style/underline-selection", test_style_underline_selection);
+ test_utils_add_test ("/style/underline-typed", test_style_underline_typed);
+ test_utils_add_test ("/style/strikethrough-selection", test_style_strikethrough_selection);
+ test_utils_add_test ("/style/strikethrough-typed", test_style_strikethrough_typed);
+ test_utils_add_test ("/style/monospace-selection", test_style_monospace_selection);
+ test_utils_add_test ("/style/monospace-typed", test_style_monospace_typed);
test_utils_add_test ("/justify/selection", test_justify_selection);
test_utils_add_test ("/justify/typed", test_justify_typed);
test_utils_add_test ("/indent/selection", test_indent_selection);
test_utils_add_test ("/indent/typed", test_indent_typed);
- test_utils_add_test ("/font/size/selection", test_font_size_selection);
- test_utils_add_test ("/font/size/typed", test_font_size_typed);
- test_utils_add_test ("/font/color/selection", test_font_color_selection);
- test_utils_add_test ("/font/color/typed", test_font_color_typed);
- test_utils_add_test ("/list/bullet/plain", test_list_bullet_plain);
- test_utils_add_test ("/list/bullet/html", test_list_bullet_html);
- test_utils_add_test ("/list/bullet/change", test_list_bullet_change);
- test_utils_add_test ("/list/bullet/html/from-block", test_list_bullet_html_from_block);
- test_utils_add_test ("/list/alpha/html", test_list_alpha_html);
- test_utils_add_test ("/list/alpha/plain", test_list_alpha_plain);
- test_utils_add_test ("/list/roman/html", test_list_roman_html);
- test_utils_add_test ("/list/roman/plain", test_list_roman_plain);
- test_utils_add_test ("/list/multi/html", test_list_multi_html);
- test_utils_add_test ("/list/multi/plain", test_list_multi_plain);
- test_utils_add_test ("/list/multi/change/html", test_list_multi_change_html);
- test_utils_add_test ("/list/multi/change/plain", test_list_multi_change_plain);
- test_utils_add_test ("/link/insert/dialog", test_link_insert_dialog);
- test_utils_add_test ("/link/insert/dialog/selection", test_link_insert_dialog_selection);
- test_utils_add_test ("/link/insert/dialog/remove-link", test_link_insert_dialog_remove_link);
- test_utils_add_test ("/link/insert/typed", test_link_insert_typed);
- test_utils_add_test ("/link/insert/typed/change-description",
test_link_insert_typed_change_description);
- test_utils_add_test ("/link/insert/typed/append", test_link_insert_typed_append);
- test_utils_add_test ("/link/insert/typed/remove", test_link_insert_typed_remove);
+ test_utils_add_test ("/font/size-selection", test_font_size_selection);
+ test_utils_add_test ("/font/size-typed", test_font_size_typed);
+ test_utils_add_test ("/font/color-selection", test_font_color_selection);
+ test_utils_add_test ("/font/color-typed", test_font_color_typed);
+ test_utils_add_test ("/list/bullet-plain", test_list_bullet_plain);
+ test_utils_add_test ("/list/bullet-html", test_list_bullet_html);
+ test_utils_add_test ("/list/bullet-change", test_list_bullet_change);
+ test_utils_add_test ("/list/bullet-html-from-block", test_list_bullet_html_from_block);
+ test_utils_add_test ("/list/alpha-html", test_list_alpha_html);
+ test_utils_add_test ("/list/alpha-plain", test_list_alpha_plain);
+ test_utils_add_test ("/list/number-html", test_list_number_html);
+ test_utils_add_test ("/list/number-plain", test_list_number_plain);
+ test_utils_add_test ("/list/roman-html", test_list_roman_html);
+ test_utils_add_test ("/list/roman-plain", test_list_roman_plain);
+ test_utils_add_test ("/list/multi-html", test_list_multi_html);
+ test_utils_add_test ("/list/multi-plain", test_list_multi_plain);
+ test_utils_add_test ("/list/multi-change-html", test_list_multi_change_html);
+ test_utils_add_test ("/list/multi-change-plain", test_list_multi_change_plain);
+ test_utils_add_test ("/list/indent-same-html", test_list_indent_same_html);
+ test_utils_add_test ("/list/indent-same-plain", test_list_indent_same_plain);
+ test_utils_add_test ("/list/indent-different-html", test_list_indent_different_html);
+ test_utils_add_test ("/list/indent-different-plain", test_list_indent_different_plain);
+ test_utils_add_test ("/list/indent-multi-html", test_list_indent_multi_html);
+ test_utils_add_test ("/list/indent-multi-plain", test_list_indent_multi_plain);
+ test_utils_add_test ("/list/indent-nested-html", test_list_indent_nested_html);
+ test_utils_add_test ("/list/indent-nested-plain", test_list_indent_nested_plain);
+ test_utils_add_test ("/link/insert-dialog", test_link_insert_dialog);
+ test_utils_add_test ("/link/insert-dialog-selection", test_link_insert_dialog_selection);
+ test_utils_add_test ("/link/insert-dialog-remove-link", test_link_insert_dialog_remove_link);
+ test_utils_add_test ("/link/insert-typed", test_link_insert_typed);
+ test_utils_add_test ("/link/insert-typed-change-description",
test_link_insert_typed_change_description);
+ test_utils_add_test ("/link/insert-typed-append", test_link_insert_typed_append);
+ test_utils_add_test ("/link/insert-typed-remove", test_link_insert_typed_remove);
test_utils_add_test ("/h-rule/insert", test_h_rule_insert);
test_utils_add_test ("/h-rule/insert-text-after", test_h_rule_insert_text_after);
test_utils_add_test ("/image/insert", test_image_insert);
- test_utils_add_test ("/emoticon/insert/typed", test_emoticon_insert_typed);
- test_utils_add_test ("/emoticon/insert/typed-dash", test_emoticon_insert_typed_dash);
- test_utils_add_test ("/paragraph/normal/selection", test_paragraph_normal_selection);
- test_utils_add_test ("/paragraph/normal/typed", test_paragraph_normal_typed);
- test_utils_add_test ("/paragraph/preformatted/selection", test_paragraph_preformatted_selection);
- test_utils_add_test ("/paragraph/preformatted/typed", test_paragraph_preformatted_typed);
- test_utils_add_test ("/paragraph/address/selection", test_paragraph_address_selection);
- test_utils_add_test ("/paragraph/address/typed", test_paragraph_address_typed);
- test_utils_add_test ("/paragraph/header1/selection", test_paragraph_header1_selection);
- test_utils_add_test ("/paragraph/header1/typed", test_paragraph_header1_typed);
- test_utils_add_test ("/paragraph/header2/selection", test_paragraph_header2_selection);
- test_utils_add_test ("/paragraph/header2/typed", test_paragraph_header2_typed);
- test_utils_add_test ("/paragraph/header3/selection", test_paragraph_header3_selection);
- test_utils_add_test ("/paragraph/header3/typed", test_paragraph_header3_typed);
- test_utils_add_test ("/paragraph/header4/selection", test_paragraph_header4_selection);
- test_utils_add_test ("/paragraph/header4/typed", test_paragraph_header4_typed);
- test_utils_add_test ("/paragraph/header5/selection", test_paragraph_header5_selection);
- test_utils_add_test ("/paragraph/header5/typed", test_paragraph_header5_typed);
- test_utils_add_test ("/paragraph/header6/selection", test_paragraph_header6_selection);
- test_utils_add_test ("/paragraph/header6/typed", test_paragraph_header6_typed);
+ test_utils_add_test ("/emoticon/insert-typed", test_emoticon_insert_typed);
+ test_utils_add_test ("/emoticon/insert-typed-dash", test_emoticon_insert_typed_dash);
+ test_utils_add_test ("/paragraph/normal-selection", test_paragraph_normal_selection);
+ test_utils_add_test ("/paragraph/normal-typed", test_paragraph_normal_typed);
+ test_utils_add_test ("/paragraph/preformatted-selection", test_paragraph_preformatted_selection);
+ test_utils_add_test ("/paragraph/preformatted-typed", test_paragraph_preformatted_typed);
+ test_utils_add_test ("/paragraph/address-selection", test_paragraph_address_selection);
+ test_utils_add_test ("/paragraph/address-typed", test_paragraph_address_typed);
+ test_utils_add_test ("/paragraph/header1-selection", test_paragraph_header1_selection);
+ test_utils_add_test ("/paragraph/header1-typed", test_paragraph_header1_typed);
+ test_utils_add_test ("/paragraph/header2-selection", test_paragraph_header2_selection);
+ test_utils_add_test ("/paragraph/header2-typed", test_paragraph_header2_typed);
+ test_utils_add_test ("/paragraph/header3-selection", test_paragraph_header3_selection);
+ test_utils_add_test ("/paragraph/header3-typed", test_paragraph_header3_typed);
+ test_utils_add_test ("/paragraph/header4-selection", test_paragraph_header4_selection);
+ test_utils_add_test ("/paragraph/header4-typed", test_paragraph_header4_typed);
+ test_utils_add_test ("/paragraph/header5-selection", test_paragraph_header5_selection);
+ test_utils_add_test ("/paragraph/header5-typed", test_paragraph_header5_typed);
+ test_utils_add_test ("/paragraph/header6-selection", test_paragraph_header6_selection);
+ test_utils_add_test ("/paragraph/header6-typed", test_paragraph_header6_typed);
test_utils_add_test ("/paragraph/wrap-lines", test_paragraph_wrap_lines);
- test_utils_add_test ("/paste/singleline/html2html", test_paste_singleline_html2html);
- test_utils_add_test ("/paste/singleline/html2plain", test_paste_singleline_html2plain);
- test_utils_add_test ("/paste/singleline/plain2html", test_paste_singleline_plain2html);
- test_utils_add_test ("/paste/singleline/plain2plain", test_paste_singleline_plain2plain);
- test_utils_add_test ("/paste/multiline/html2html", test_paste_multiline_html2html);
- test_utils_add_test ("/paste/multiline/html2plain", test_paste_multiline_html2plain);
- test_utils_add_test ("/paste/multiline/div/html2html", test_paste_multiline_div_html2html);
- test_utils_add_test ("/paste/multiline/div/html2plain", test_paste_multiline_div_html2plain);
- test_utils_add_test ("/paste/multiline/p/html2html", test_paste_multiline_p_html2html);
- test_utils_add_test ("/paste/multiline/p/html2plain", test_paste_multiline_p_html2plain);
- test_utils_add_test ("/paste/multiline/plain2html", test_paste_multiline_plain2html);
- test_utils_add_test ("/paste/multiline/plain2plain", test_paste_multiline_plain2plain);
- test_utils_add_test ("/paste/quoted/singleline/html2html", test_paste_quoted_singleline_html2html);
- test_utils_add_test ("/paste/quoted/singleline/html2plain", test_paste_quoted_singleline_html2plain);
- test_utils_add_test ("/paste/quoted/singleline/plain2html", test_paste_quoted_singleline_plain2html);
- test_utils_add_test ("/paste/quoted/singleline/plain2plain",
test_paste_quoted_singleline_plain2plain);
- test_utils_add_test ("/paste/quoted/multiline/html2html", test_paste_quoted_multiline_html2html);
- test_utils_add_test ("/paste/quoted/multiline/html2plain", test_paste_quoted_multiline_html2plain);
- test_utils_add_test ("/paste/quoted/multiline/plain2html", test_paste_quoted_multiline_plain2html);
- test_utils_add_test ("/paste/quoted/multiline/plain2plain", test_paste_quoted_multiline_plain2plain);
+ test_utils_add_test ("/paste/singleline-html2html", test_paste_singleline_html2html);
+ test_utils_add_test ("/paste/singleline-html2plain", test_paste_singleline_html2plain);
+ test_utils_add_test ("/paste/singleline-plain2html", test_paste_singleline_plain2html);
+ test_utils_add_test ("/paste/singleline-plain2plain", test_paste_singleline_plain2plain);
+ test_utils_add_test ("/paste/multiline-html2html", test_paste_multiline_html2html);
+ test_utils_add_test ("/paste/multiline-html2plain", test_paste_multiline_html2plain);
+ test_utils_add_test ("/paste/multiline-div-html2html", test_paste_multiline_div_html2html);
+ test_utils_add_test ("/paste/multiline-div-html2plain", test_paste_multiline_div_html2plain);
+ test_utils_add_test ("/paste/multiline-p-html2html", test_paste_multiline_p_html2html);
+ test_utils_add_test ("/paste/multiline-p-html2plain", test_paste_multiline_p_html2plain);
+ test_utils_add_test ("/paste/multiline-plain2html", test_paste_multiline_plain2html);
+ test_utils_add_test ("/paste/multiline-plain2plain", test_paste_multiline_plain2plain);
+ test_utils_add_test ("/paste/quoted-singleline-html2html", test_paste_quoted_singleline_html2html);
+ test_utils_add_test ("/paste/quoted-singleline-html2plain", test_paste_quoted_singleline_html2plain);
+ test_utils_add_test ("/paste/quoted-singleline-plain2html", test_paste_quoted_singleline_plain2html);
+ test_utils_add_test ("/paste/quoted-singleline-plain2plain",
test_paste_quoted_singleline_plain2plain);
+ test_utils_add_test ("/paste/quoted-multiline-html2html", test_paste_quoted_multiline_html2html);
+ test_utils_add_test ("/paste/quoted-multiline-html2plain", test_paste_quoted_multiline_html2plain);
+ test_utils_add_test ("/paste/quoted-multiline-plain2html", test_paste_quoted_multiline_plain2html);
+ test_utils_add_test ("/paste/quoted-multiline-plain2plain", test_paste_quoted_multiline_plain2plain);
test_utils_add_test ("/cite/html2plain", test_cite_html2plain);
test_utils_add_test ("/cite/shortline", test_cite_shortline);
test_utils_add_test ("/cite/longline", test_cite_longline);
- test_utils_add_test ("/cite/reply/html", test_cite_reply_html);
- test_utils_add_test ("/cite/reply/plain", test_cite_reply_plain);
- test_utils_add_test ("/undo/text/typed", test_undo_text_typed);
- test_utils_add_test ("/undo/text/forward-delete", test_undo_text_forward_delete);
- test_utils_add_test ("/undo/text/backward-delete", test_undo_text_backward_delete);
- test_utils_add_test ("/undo/text/cut", test_undo_text_cut);
+ test_utils_add_test ("/cite/reply-html", test_cite_reply_html);
+ test_utils_add_test ("/cite/reply-html-to-plain", test_cite_reply_html_to_plain);
+ test_utils_add_test ("/cite/reply-plain", test_cite_reply_plain);
+ test_utils_add_test ("/cite/reply-link", test_cite_reply_link);
+ test_utils_add_test ("/cite/editing-html", test_cite_editing_html);
+ test_utils_add_test ("/cite/editing-plain", test_cite_editing_plain);
+ test_utils_add_test ("/undo/text-typed", test_undo_text_typed);
+ test_utils_add_test ("/undo/text-forward-delete", test_undo_text_forward_delete);
+ test_utils_add_test ("/undo/text-backward-delete", test_undo_text_backward_delete);
+ test_utils_add_test ("/undo/text-cut", test_undo_text_cut);
test_utils_add_test ("/undo/style", test_undo_style);
test_utils_add_test ("/undo/justify", test_undo_justify);
test_utils_add_test ("/undo/indent", test_undo_indent);
- test_utils_add_test ("/undo/link-paste/html", test_undo_link_paste_html);
- test_utils_add_test ("/undo/link-paste/plain", test_undo_link_paste_plain);
+ test_utils_add_test ("/undo/link-paste-html", test_undo_link_paste_html);
+ test_utils_add_test ("/undo/link-paste-plain", test_undo_link_paste_plain);
test_utils_add_test ("/delete/quoted", test_delete_quoted);
test_utils_add_test ("/delete/after-quoted", test_delete_after_quoted);
- test_utils_add_test ("/delete/quoted/selection", test_delete_quoted_selection);
+ test_utils_add_test ("/delete/quoted-selection", test_delete_quoted_selection);
+ test_utils_add_test ("/delete/quoted-multiselect", test_delete_quoted_multiselect);
test_utils_add_test ("/replace/dialog", test_replace_dialog);
- test_utils_add_test ("/replace-all/dialog", test_replace_dialog_all);
+ test_utils_add_test ("/replace/dialog-all", test_replace_dialog_all);
+ test_utils_add_test ("/wrap/basic", test_wrap_basic);
+ test_utils_add_test ("/wrap/nested", test_wrap_nested);
+ test_utils_add_test ("/pre-split/simple-html", test_pre_split_simple_html);
+ test_utils_add_test ("/pre-split/simple-plain", test_pre_split_simple_plain);
+ test_utils_add_test ("/pre-split/complex-html", test_pre_split_complex_html);
+ test_utils_add_test ("/pre-split/complex-plain", test_pre_split_complex_plain);
test_add_html_editor_bug_tests ();
diff --git a/src/e-util/test-html-editor.c b/src/e-util/test-html-editor.c
index b21632f0d1..9d684e2a41 100644
--- a/src/e-util/test-html-editor.c
+++ b/src/e-util/test-html-editor.c
@@ -59,12 +59,19 @@ static const gchar *view_ui =
" <menuitem action='view-html-output'/>\n"
" <menuitem action='view-html-source'/>\n"
" <menuitem action='view-plain-source'/>\n"
+" <menuitem action='view-draft-source'/>\n"
" <separator/>\n"
" <menuitem action='view-webkit-inspector'/>\n"
" </menu>\n"
" </menubar>\n"
"</ui>";
+enum {
+ GET_CONTENT_PLAIN,
+ GET_CONTENT_HTML,
+ GET_CONTENT_DRAFT
+};
+
static void create_new_editor (void);
static void
@@ -139,19 +146,16 @@ save_dialog (EHTMLEditor *editor)
}
static void
-view_source_dialog (EHTMLEditor *editor,
- const gchar *title,
- gboolean plain_text,
- gboolean show_source)
+view_source_dialog_show (EHTMLEditor *editor,
+ const gchar *title,
+ gboolean plain_text,
+ gboolean show_source,
+ const gchar *content_text)
{
GtkWidget *dialog;
GtkWidget *content;
GtkWidget *content_area;
GtkWidget *scrolled_window;
- EContentEditor *cnt_editor;
- gchar * html;
-
- cnt_editor = e_html_editor_get_content_editor (editor);
dialog = gtk_dialog_new_with_buttons (
title,
@@ -176,32 +180,20 @@ view_source_dialog (EHTMLEditor *editor,
gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 6);
gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 300);
- if (plain_text) {
- html = e_content_editor_get_content (cnt_editor,
- E_CONTENT_EDITOR_GET_PROCESSED | E_CONTENT_EDITOR_GET_TEXT_PLAIN,
- NULL, NULL);
- } else {
- GSList *inline_images = NULL;
-
- html = e_content_editor_get_content (cnt_editor,
- E_CONTENT_EDITOR_GET_PROCESSED | E_CONTENT_EDITOR_GET_TEXT_HTML |
E_CONTENT_EDITOR_GET_INLINE_IMAGES,
- "test-domain", &inline_images);
-
- g_slist_free_full (inline_images, g_object_unref);
- }
-
if (show_source || plain_text) {
GtkTextBuffer *buffer;
content = gtk_text_view_new ();
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (content));
- gtk_text_buffer_set_text (buffer, html ? html : "", -1);
+ gtk_text_buffer_set_text (buffer, content_text ? content_text : "", -1);
gtk_text_view_set_editable (GTK_TEXT_VIEW (content), FALSE);
+ gtk_text_view_set_monospace (GTK_TEXT_VIEW (content), TRUE);
+ if (!plain_text)
+ gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (content), GTK_WRAP_WORD_CHAR);
} else {
content = webkit_web_view_new ();
- webkit_web_view_load_html (WEBKIT_WEB_VIEW (content), html ? html : "", "evo-file://");
+ webkit_web_view_load_html (WEBKIT_WEB_VIEW (content), content_text ? content_text : "",
"evo-file://");
}
- g_free (html);
gtk_container_add (GTK_CONTAINER (scrolled_window), content);
gtk_widget_show_all (scrolled_window);
@@ -210,6 +202,94 @@ view_source_dialog (EHTMLEditor *editor,
gtk_widget_destroy (dialog);
}
+typedef struct _ViewSourceData {
+ EHTMLEditor *editor;
+ gchar *title;
+ guint mode;
+ gboolean show_source;
+} ViewSourceData;
+
+static ViewSourceData *
+view_source_data_new (EHTMLEditor *editor,
+ const gchar *title,
+ guint mode,
+ gboolean show_source)
+{
+ ViewSourceData *vsd;
+
+ vsd = g_slice_new (ViewSourceData);
+ vsd->editor = g_object_ref (editor);
+ vsd->title = g_strdup (title);
+ vsd->mode = mode;
+ vsd->show_source = show_source;
+
+ return vsd;
+}
+
+static void
+view_source_data_free (gpointer ptr)
+{
+ ViewSourceData *vsd = ptr;
+
+ if (vsd) {
+ g_clear_object (&vsd->editor);
+ g_free (vsd->title);
+ g_slice_free (ViewSourceData, vsd);
+ }
+}
+
+static void
+view_source_dialog_content_hash_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ ViewSourceData *vcd = user_data;
+ EContentEditorContentHash *content_hash;
+ GError *error = NULL;
+
+ g_return_if_fail (vcd != NULL);
+ g_return_if_fail (E_IS_CONTENT_EDITOR (source_object));
+
+ content_hash = e_content_editor_get_content_finish (E_CONTENT_EDITOR (source_object), result, &error);
+
+ if (!content_hash) {
+ g_warning ("%s: Failed to get content: %s", G_STRFUNC, error ? error->message : "Unknown
error");
+ } else {
+ view_source_dialog_show (vcd->editor, vcd->title, vcd->mode == GET_CONTENT_PLAIN,
vcd->show_source,
+ e_content_editor_util_get_content_data (content_hash,
+ vcd->mode == GET_CONTENT_PLAIN ? E_CONTENT_EDITOR_GET_TO_SEND_PLAIN :
+ vcd->mode == GET_CONTENT_HTML ? E_CONTENT_EDITOR_GET_TO_SEND_HTML :
+ E_CONTENT_EDITOR_GET_RAW_DRAFT));
+
+ e_content_editor_util_free_content_hash (content_hash);
+ }
+
+ view_source_data_free (vcd);
+ g_clear_error (&error);
+}
+
+static void
+view_source_dialog (EHTMLEditor *editor,
+ const gchar *title,
+ guint mode,
+ gboolean show_source)
+{
+ EContentEditor *cnt_editor;
+ ViewSourceData *vcd;
+ guint32 flags;
+
+ vcd = view_source_data_new (editor, title, mode, show_source);
+
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ flags = mode == GET_CONTENT_PLAIN ? E_CONTENT_EDITOR_GET_TO_SEND_PLAIN :
+ mode == GET_CONTENT_HTML ? E_CONTENT_EDITOR_GET_TO_SEND_HTML |
E_CONTENT_EDITOR_GET_INLINE_IMAGES :
+ E_CONTENT_EDITOR_GET_ALL;
+
+ e_content_editor_get_content (cnt_editor, flags, "test-domain", NULL,
+ view_source_dialog_content_hash_ready_cb, vcd);
+}
+
static void
action_new_editor_cb (GtkAction *action,
EHTMLEditor *editor)
@@ -240,13 +320,24 @@ action_quit_cb (GtkAction *action,
gtk_main_quit ();
}
+static void
+html_editor_save_done_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GError *error = NULL;
+
+ e_html_editor_save_finish (E_HTML_EDITOR (source_object), result, &error);
+
+ handle_error (&error);
+}
+
static void
action_save_cb (GtkAction *action,
EHTMLEditor *editor)
{
const gchar *filename;
gboolean as_html;
- GError *error = NULL;
if (e_html_editor_get_filename (editor) == NULL)
if (save_dialog (editor) == GTK_RESPONSE_CANCEL)
@@ -255,8 +346,7 @@ action_save_cb (GtkAction *action,
filename = e_html_editor_get_filename (editor);
as_html = (e_content_editor_get_html_mode (e_html_editor_get_content_editor (editor)));
- e_html_editor_save (editor, filename, as_html, &error);
- handle_error (&error);
+ e_html_editor_save (editor, filename, as_html, NULL, html_editor_save_done_cb, NULL);
}
static void
@@ -265,7 +355,6 @@ action_save_as_cb (GtkAction *action,
{
const gchar *filename;
gboolean as_html;
- GError *error = NULL;
if (save_dialog (editor) == GTK_RESPONSE_CANCEL)
return;
@@ -273,8 +362,7 @@ action_save_as_cb (GtkAction *action,
filename = e_html_editor_get_filename (editor);
as_html = (e_content_editor_get_html_mode (e_html_editor_get_content_editor (editor)));
- e_html_editor_save (editor, filename, as_html, &error);
- handle_error (&error);
+ e_html_editor_save (editor, filename, as_html, NULL, html_editor_save_done_cb, NULL);
}
static void
@@ -291,21 +379,28 @@ static void
action_view_html_output (GtkAction *action,
EHTMLEditor *editor)
{
- view_source_dialog (editor, _("HTML Output"), FALSE, FALSE);
+ view_source_dialog (editor, _("HTML Output"), GET_CONTENT_HTML, FALSE);
}
static void
action_view_html_source (GtkAction *action,
EHTMLEditor *editor)
{
- view_source_dialog (editor, _("HTML Source"), FALSE, TRUE);
+ view_source_dialog (editor, _("HTML Source"), GET_CONTENT_HTML, TRUE);
}
static void
action_view_plain_source (GtkAction *action,
EHTMLEditor *editor)
{
- view_source_dialog (editor, _("Plain Source"), TRUE, FALSE);
+ view_source_dialog (editor, _("Plain Source"), GET_CONTENT_PLAIN, FALSE);
+}
+
+static void
+action_view_draft_source (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ view_source_dialog (editor, _("Draft"), GET_CONTENT_DRAFT, TRUE);
}
static void
@@ -407,6 +502,13 @@ static GtkActionEntry view_entries[] = {
NULL,
G_CALLBACK (action_view_plain_source) },
+ { "view-draft-source",
+ NULL,
+ N_("_Draft Source"),
+ NULL,
+ NULL,
+ G_CALLBACK (action_view_draft_source) },
+
{ "view-webkit-inspector",
NULL,
N_("Inspector"),
@@ -423,6 +525,7 @@ static GtkActionEntry view_entries[] = {
};
static guint glob_editors = 0;
+static const gchar *glob_prefill_body = NULL;
static void
editor_destroyed_cb (GtkWidget *editor)
@@ -446,6 +549,7 @@ create_new_editor_cb (GObject *source_object,
GtkWidget *widget;
EHTMLEditor *editor;
EContentEditor *cnt_editor;
+ EFocusTracker *focus_tracker;
GError *error = NULL;
widget = e_html_editor_new_finish (result, &error);
@@ -485,6 +589,27 @@ create_new_editor_cb (GObject *source_object,
gtk_widget_set_size_request (widget, 600, 400);
gtk_widget_show (widget);
+ focus_tracker = e_focus_tracker_new (GTK_WINDOW (widget));
+ g_object_set_data_full (G_OBJECT (widget), "e-focus-tracker", focus_tracker, g_object_unref);
+
+ e_focus_tracker_set_cut_clipboard_action (focus_tracker,
+ e_html_editor_get_action (editor, "cut"));
+
+ e_focus_tracker_set_copy_clipboard_action (focus_tracker,
+ e_html_editor_get_action (editor, "copy"));
+
+ e_focus_tracker_set_paste_clipboard_action (focus_tracker,
+ e_html_editor_get_action (editor, "paste"));
+
+ e_focus_tracker_set_select_all_action (focus_tracker,
+ e_html_editor_get_action (editor, "select-all"));
+
+ e_focus_tracker_set_undo_action (focus_tracker,
+ e_html_editor_get_action (editor, "undo"));
+
+ e_focus_tracker_set_redo_action (focus_tracker,
+ e_html_editor_get_action (editor, "redo"));
+
g_signal_connect_swapped (
widget, "destroy",
G_CALLBACK (editor_destroyed_cb), NULL);
@@ -546,6 +671,13 @@ create_new_editor_cb (GObject *source_object,
}
gtk_ui_manager_ensure_update (manager);
+
+ if (glob_prefill_body) {
+ e_content_editor_insert_content (cnt_editor, glob_prefill_body,
E_CONTENT_EDITOR_INSERT_REPLACE_ALL |
+ (*glob_prefill_body == '<' ? E_CONTENT_EDITOR_INSERT_TEXT_HTML :
E_CONTENT_EDITOR_INSERT_TEXT_PLAIN));
+
+ glob_prefill_body = NULL;
+ }
}
static void
@@ -571,9 +703,16 @@ main (gint argc,
e_util_init_main_thread (NULL);
e_passwords_init ();
+ g_setenv ("E_HTML_EDITOR_TEST_SOURCES", "1", FALSE);
+
+ gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (), EVOLUTION_ICONDIR);
+
modules = e_module_load_all_in_directory (EVOLUTION_MODULEDIR);
g_list_free_full (modules, (GDestroyNotify) g_type_module_unuse);
+ if (argc == 2)
+ glob_prefill_body = argv[1];
+
create_new_editor ();
gtk_main ();
diff --git a/src/e-util/test-web-view-jsc.c b/src/e-util/test-web-view-jsc.c
index 33780da89a..dab6108109 100644
--- a/src/e-util/test-web-view-jsc.c
+++ b/src/e-util/test-web-view-jsc.c
@@ -148,6 +148,7 @@ test_utils_fixture_set_up (TestFixture *fixture,
settings = webkit_web_view_get_settings (fixture->web_view);
webkit_settings_set_enable_developer_extras (settings, TRUE);
+ webkit_settings_set_enable_write_console_messages_to_stdout (settings, TRUE);
g_signal_connect (
fixture->window, "key-press-event",
@@ -1419,6 +1420,7 @@ test_selection (TestFixture *fixture)
"<font color=\"red\">R</font>"
"<font color=\"green\">G</font>"
"<font color=\"blue\">B</font>"
+ "<span id=\"rgb-end\"></span>"
"</div>"
"<div id=\"styled\">"
"<span style=\"color:blue;\">bb</span>"
@@ -1448,16 +1450,23 @@ test_selection (TestFixture *fixture)
test_selection_select_in_iframe (fixture, "frm1", "plain", "rgb");
g_assert_cmpint (e_web_view_has_selection (E_WEB_VIEW (fixture->web_view)) ? 1 : 0, ==, 1);
- test_selection_verify (fixture, "unformatted text\n", NULL);
+ test_selection_verify (fixture, "unformatted text\n\n", NULL);
test_selection_verify (fixture, NULL, "<div id=\"plain\">unformatted text</div><br><div
id=\"rgb\"></div>");
- test_selection_verify (fixture, "unformatted text\n", "<div id=\"plain\">unformatted
text</div><br><div id=\"rgb\"></div>");
+ test_selection_verify (fixture, "unformatted text\n\n", "<div id=\"plain\">unformatted
text</div><br><div id=\"rgb\"></div>");
test_selection_select_in_iframe (fixture, "frm1", "rgb", "styled");
+ g_assert_cmpint (e_web_view_has_selection (E_WEB_VIEW (fixture->web_view)) ? 1 : 0, ==, 1);
+ test_selection_verify (fixture, "RGB\n", NULL);
+ test_selection_verify (fixture, NULL, "<div id=\"rgb\"><font color=\"red\">R</font><font
color=\"green\">G</font><font color=\"blue\">B</font><span id=\"rgb-end\"></span></div><div
id=\"styled\"></div>");
+ test_selection_verify (fixture, "RGB\n", "<div id=\"rgb\"><font color=\"red\">R</font><font
color=\"green\">G</font><font color=\"blue\">B</font><span id=\"rgb-end\"></span></div><div
id=\"styled\"></div>");
+
+ test_selection_select_in_iframe (fixture, "frm1", "rgb", "rgb-end");
+
g_assert_cmpint (e_web_view_has_selection (E_WEB_VIEW (fixture->web_view)) ? 1 : 0, ==, 1);
test_selection_verify (fixture, "RGB", NULL);
- test_selection_verify (fixture, NULL, "<div id=\"rgb\"><font color=\"red\">R</font><font
color=\"green\">G</font><font color=\"blue\">B</font></div><div id=\"styled\"></div>");
- test_selection_verify (fixture, "RGB", "<div id=\"rgb\"><font color=\"red\">R</font><font
color=\"green\">G</font><font color=\"blue\">B</font></div><div id=\"styled\"></div>");
+ test_selection_verify (fixture, NULL, "<font color=\"red\">R</font><font
color=\"green\">G</font><font color=\"blue\">B</font>");
+ test_selection_verify (fixture, "RGB", "<font color=\"red\">R</font><font
color=\"green\">G</font><font color=\"blue\">B</font>");
test_selection_select_in_iframe (fixture, "frm1", "styled", "end");
@@ -1610,7 +1619,7 @@ test_get_content (TestFixture *fixture)
test_get_document_content_verify (fixture, "", NULL, expect_html);
test_get_document_content_verify (fixture, "", expect_plain, expect_html);
- expect_plain = "frm1 div";
+ expect_plain = "frm1 div\n";
expect_html = html_frm1;
test_get_document_content_verify (fixture, "frm1", expect_plain, NULL);
test_get_document_content_verify (fixture, "frm1", NULL, expect_html);
@@ -1654,7 +1663,7 @@ test_get_content (TestFixture *fixture)
test_get_element_content_verify (fixture, "", "*body", TRUE, NULL, expect_html);
test_get_element_content_verify (fixture, "", "*body", TRUE, expect_plain, expect_html);
- expect_plain = "frm1 div";
+ expect_plain = "frm1 div\n";
expect_html ="<span id=\"frm1p\"><div id=\"frst\">frm1 div</div></span>";
test_get_element_content_verify (fixture, "frm1", "*body", FALSE, expect_plain, NULL);
test_get_element_content_verify (fixture, "frm1", "*body", FALSE, NULL, expect_html);
@@ -1687,6 +1696,7 @@ test_get_content (TestFixture *fixture)
test_get_element_content_verify (fixture, "frm1", "frst", TRUE, NULL, expect_html);
test_get_element_content_verify (fixture, "frm1", "frst", TRUE, expect_plain, expect_html);
+ expect_plain = "frm1 div\n";
test_get_element_content_verify (fixture, "frm1", "frm1p", FALSE, expect_plain, NULL);
test_get_element_content_verify (fixture, "frm1", "frm1p", FALSE, NULL, expect_html);
test_get_element_content_verify (fixture, "frm1", "frm1p", FALSE, expect_plain, expect_html);
@@ -1922,6 +1932,1005 @@ test_get_element_from_point (TestFixture *fixture)
g_assert_cmpint (tested, >, 0);
}
+static void
+test_convert_to_plain (TestFixture *fixture)
+{
+ #define HTML(_body) ("<html><head><style><!-- span.Apple-tab-span { white-space:pre; }
--></style></head><body style='font-family:monospace;'>" _body "</body></html>")
+ #define TAB "<span class='Apple-tab-span' style='white-space:pre;'>\t</span>"
+ #define BREAK_STYLE " word-break:break-word; word-wrap:break-word; line-break:after-white-space;"
+ #define WRAP_STYLE(_type) " white-space:" _type "; " BREAK_STYLE
+ #define ALIGN_STYLE(_type) " text-align:" _type ";"
+ #define INDENT_STYLE(_type, _val) " margin-" _type ":" _val "ch;"
+ #define DIR_STYLE(_type) " direction:" _type ";"
+
+ struct _tests {
+ const gchar *html;
+ const gchar *plain;
+ gint normal_div_width;
+ } tests[] = {
+ /* 0 */ { HTML ("<div style='width:10ch; " BREAK_STYLE "'>123 5678 0123 5678 0123 678
1234567890abcdefghijklmnopq 012345 356 9 " TAB TAB "0</div>"),
+ "123 5678\n0123 5678\n0123 678\n1234567890\nabcdefghij\nklmnopq\n012345 356\n9\n0\n",
+ -1 },
+ /* 1 */ { HTML ("<div style='width:10ch; " WRAP_STYLE ("normal") "'>123 5678 0123 5678 0123 678
1234567890abcdefghijklmnopq 012345 356 9 " TAB TAB "0</div>"),
+ "123 5678\n0123 5678\n0123 678\n1234567890\nabcdefghij\nklmnopq\n012345 356\n9\n0\n",
+ -1 },
+ /* 2 */ { HTML ("<div style='width:10ch; " WRAP_STYLE ("nowrap") "'>123 5678 0123 5678 0123 678
1234567890abcdefghijklmnopq 012345 356 9 " TAB TAB "0</div>"),
+ "123 5678 0123 5678 0123 678 1234567890abcdefghijklmnopq 012345 356 9 0\n",
+ -1 },
+ /* 3 */ { HTML ("<div style='width:10ch; " WRAP_STYLE ("pre") "'>123 5678 0123 5678 0123 678
1234567890abcdefghijklmnopq 012345 356 9 " TAB TAB "0</div>"),
+ "123 5678 0\n123 5678 0\n123 678 1\n234567890a\nbcdefghijk\nlmnopq 012\n345 \n 356
9 \n \t\t\n0\n",
+ -1 },
+ /* 4 */ { HTML ("<div style='width:10ch; " WRAP_STYLE ("pre") "'>123 5678 0123 5678 0123 678
1234567890abcdefghijklmnopq 012345 356 9 " TAB TAB "0</div>"),
+ "123 5678 0\n123 5678 0\n123 678 1\n234567890a\nbcdefghijk\nlmnopq 012\n345 \n 356
9 \n \t\n\t0\n",
+ -1 },
+ /* 5 */ { HTML ("<div style='width:10ch; " WRAP_STYLE ("pre-line") "'>123 5678 0123 5678 0123 678
1234567890abcdefghijklmnopq 012345 356 9 " TAB TAB "0</div>"),
+ "123 5678\n0123 5678\n0123 678\n1234567890\nabcdefghij\nklmnopq\n012345 356\n9\n0\n",
+ -1 },
+ /* 6 */ { HTML ("<div style='width:10ch; " WRAP_STYLE ("pre-wrap") "'>123 5678 0123 5678 0123 678
1234567890abcdefghijklmnopq 012345 356 9 " TAB TAB "0</div>"),
+ "123 5678\n0123 5678\n0123 678\n1234567890\nabcdefghij\nklmnopq\n012345 \n356 9
\n\t\n\t0\n",
+ -1 },
+ /* 7 */ { HTML ("<pre>123456789012345\n1\t90123\n123 78901\n 34567 <br>123 5</pre>"),
+ "123456789012345\n1\t90123\n123 78901\n 34567 \n123 5\n",
+ -1 },
+ /* 8 */ { HTML ("<pre>123456789012345\n1\t90123\n123 78901\n 34567 <br>123 5</pre>"),
+ "123456789012345\n1\t90123\n123 78901\n 34567 \n123 5\n",
+ 10 },
+ /* 9 */ { HTML ("<h1>Header1</h1>"
+ "<div style='width:10ch; " WRAP_STYLE ("normal") "'>123456 789 123 4567890 123456 789
122</div>"
+ "<div style='width:10ch; " WRAP_STYLE ("normal") "'>987654321 987 654 321
12345678901234567890</div>"),
+ "Header1\n"
+ "123456 789\n123\n4567890\n123456 789\n122\n"
+ "987654321\n987 654\n321\n1234567890\n1234567890\n",
+ -1 },
+ /* 10 */{ HTML ("<h1>Header1</h1>"
+ "<div style='width:10ch; " WRAP_STYLE ("pre-wrap") "'>123456 789 123 4567890 123456
789 122</div>"
+ "<div style='width:10ch; " WRAP_STYLE ("pre-wrap") "'>987654321 987 654 321
12345678901234567890</div>"),
+ "Header1\n"
+ "123456 789\n123\n4567890\n123456 789\n122\n"
+ "987654321\n987 654\n321\n1234567890\n1234567890\n",
+ -1 },
+ /* 11 */{ HTML ("<h1>H1</h1><h2>H2</h2><h3>H3</h3><h4>H4</h4><h5>H5</h5><h6>H6</h6>"),
+ "H1\nH2\nH3\nH4\nH5\nH6\n",
+ -1 },
+ /* 12 */{ HTML ("<address>Line 1<br>Line 2<br>Line 3 ...</address>"),
+ "Line 1\nLine 2\nLine 3 ...\n",
+ -1 },
+ /* 13 */{ HTML ("<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("left") "'>1</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("left") "'>1 2</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("left") "'>1 2 3</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("left") "'>1 2 3 4</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("left") "'>1 2 3 4 5</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("left") "'>1 2 3 4 5 6</div>"),
+ "1\n1 2\n1 2 3\n1 2 3 4\n1 2 3 4 5\n1 2 3 4 5\n6\n",
+ -1 },
+ /* 14 */{ HTML ("<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("center") "'>1</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("center") "'>1 2</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("center") "'>1 2 3</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("center") "'>1 2 3 4</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("center") "'>1 2 3 4 5</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("center") "'>1 2 3 4 5 6</div>"),
+ " 1\n 1 2\n 1 2 3\n 1 2 3 4\n1 2 3 4 5\n1 2 3 4 5\n 6\n",
+ -1 },
+ /* 15 */{ HTML ("<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("right") "'>1</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("right") "'>1 2</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("right") "'>1 2 3</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("right") "'>1 2 3 4</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("right") "'>1 2 3 4 5</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("right") "'>1 2 3 4 5 6</div>"),
+ " 1\n"
+ " 1 2\n"
+ " 1 2 3\n"
+ " 1 2 3 4\n"
+ " 1 2 3 4 5\n"
+ " 1 2 3 4 5\n"
+ " 6\n",
+ -1 },
+ /* 16 */{ HTML ("<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("justify") "'>1 aaaaaaaaa</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("justify") "'>1 2 aaaaaaa</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("justify") "'>1 2 3 aaaaa</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("justify") "'>1 2 3 4 aaa</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("justify") "'>1 2 3 4 5 a</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("justify") "'>1 2 3 4 5 6
7</div>"),
+ "1\n"
+ "aaaaaaaaa\n"
+ "1 2\n"
+ "aaaaaaa\n"
+ "1 2 3\n"
+ "aaaaa\n"
+ "1 2 3 4\n"
+ "aaa\n"
+ "1 2 3 4 5\n"
+ "a\n"
+ "1 2 3 4 5\n"
+ "6 7\n",
+ -1 },
+ /* 17 */{ HTML ("<div style='width:10ch; " BREAK_STYLE "'>123456 789 123 4567890 123456 789
122</div>"),
+ "123456 789\n123\n4567890\n123456 789\n122\n",
+ -1 },
+ /* 18 */{ HTML ("<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("left") "'>123456 789 123 4567890
123456 789 122</div>"),
+ "123456 789\n123\n4567890\n123456 789\n122\n",
+ -1 },
+ /* 19 */{ HTML ("<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("center") "'>123456 789 123
4567890 123456 789 122</div>"),
+ "123456 789\n"
+ " 123\n"
+ " 4567890\n"
+ "123456 789\n"
+ " 122\n",
+ -1 },
+ /* 20 */{ HTML ("<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("right") "'>123456 789 123
4567890 123456 789 122</div>"),
+ "123456 789\n"
+ " 123\n"
+ " 4567890\n"
+ "123456 789\n"
+ " 122\n",
+ -1 },
+ /* 21 */{ HTML ("<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("justify") "'>123456 789 1 3 456
890 1234 789 1 2 3 4 5 122</div>"),
+ "123456 789\n"
+ "1 3 456\n"
+ "890 1234\n"
+ "789 1 2 3\n"
+ "4 5 122\n",
+ -1 },
+ /* 22 */{ HTML ("<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("left") DIR_STYLE ("rtl")
"'>1</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("left") DIR_STYLE ("rtl") "'>1
2</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("left") DIR_STYLE ("rtl") "'>1 2
3</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("left") DIR_STYLE ("rtl") "'>1 2
3 4</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("left") DIR_STYLE ("rtl") "'>1 2
3 4 5</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("left") DIR_STYLE ("rtl") "'>1 2
3 4 5 6</div>"),
+ "1 \n"
+ "1 2 \n"
+ "1 2 3 \n"
+ "1 2 3 4 \n"
+ "1 2 3 4 5 \n"
+ "1 2 3 4 5 \n"
+ "6 \n",
+ -1 },
+ /* 23 */{ HTML ("<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("center") DIR_STYLE ("rtl")
"'>1</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("center") DIR_STYLE ("rtl") "'>1
2</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("center") DIR_STYLE ("rtl") "'>1
2 3</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("center") DIR_STYLE ("rtl") "'>1
2 3 4</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("center") DIR_STYLE ("rtl") "'>1
2 3 4 5</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("center") DIR_STYLE ("rtl") "'>1
2 3 4 5 6</div>"),
+ "1 \n1 2 \n1 2 3 \n1 2 3 4 \n1 2 3 4 5\n1 2 3 4 5\n6 \n",
+ -1 },
+ /* 24 */{ HTML ("<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("right") DIR_STYLE ("rtl")
"'>1</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("right") DIR_STYLE ("rtl") "'>1
2</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("right") DIR_STYLE ("rtl") "'>1 2
3</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("right") DIR_STYLE ("rtl") "'>1 2
3 4</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("right") DIR_STYLE ("rtl") "'>1 2
3 4 5</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("right") DIR_STYLE ("rtl") "'>1 2
3 4 5 6</div>"),
+ "1\n1 2\n1 2 3\n1 2 3 4\n1 2 3 4 5\n1 2 3 4 5\n6\n",
+ -1 },
+ /* 25 */{ HTML ("<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("justify") DIR_STYLE ("rtl") "'>1
aaaaaaaaa</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("justify") DIR_STYLE ("rtl") "'>1
2 aaaaaaa</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("justify") DIR_STYLE ("rtl") "'>1
2 3 aaaaa</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("justify") DIR_STYLE ("rtl") "'>1
2 3 4 aaa</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("justify") DIR_STYLE ("rtl") "'>1
2 3 4 5 a</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("justify") DIR_STYLE ("rtl") "'>1
2 3 4 5 6 7</div>"),
+ "1\n"
+ "aaaaaaaaa\n"
+ "1 2\n"
+ "aaaaaaa\n"
+ "1 2 3\n"
+ "aaaaa\n"
+ "1 2 3 4\n"
+ "aaa\n"
+ "1 2 3 4 5\n"
+ "a\n"
+ "1 2 3 4 5\n"
+ "6 7\n",
+ -1 },
+ /* 26 */{ HTML ("<div style='width:10ch; " BREAK_STYLE DIR_STYLE ("rtl") "'>123456 789 123 4567890
123456 789 122</div>"),
+ "123456 789\n"
+ "123\n"
+ "4567890\n"
+ "123456 789\n"
+ "122\n",
+ -1 },
+ /* 27 */{ HTML ("<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("left") DIR_STYLE ("rtl")
"'>123456 789 123 4567890 123456 789 122</div>"),
+ "123456 789\n"
+ "123 \n"
+ "4567890 \n"
+ "123456 789\n"
+ "122 \n",
+ -1 },
+ /* 28 */{ HTML ("<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("center") DIR_STYLE ("rtl")
"'>123456 789 123 4567890 123456 789 122</div>"),
+ "123456 789\n"
+ "123 \n"
+ "4567890 \n"
+ "123456 789\n"
+ "122 \n",
+ -1 },
+ /* 29 */{ HTML ("<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("right") DIR_STYLE ("rtl")
"'>123456 789 123 4567890 123456 789 122</div>"),
+ "123456 789\n123\n4567890\n123456 789\n122\n",
+ -1 },
+ /* 30 */{ HTML ("<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("justify") DIR_STYLE ("rtl")
"'>123456 789 1 3 456 890 1234 789 1 2 3 4 5 122</div>"),
+ "123456 789\n"
+ "1 3 456\n"
+ "890 1234\n"
+ "789 1 2 3\n"
+ "4 5 122\n",
+ -1 },
+ /* 31 */{ HTML ("<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("left") INDENT_STYLE ("left",
"3") "'>123 567 901 345 789 123 5</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("left") INDENT_STYLE ("left",
"6") "'>987 543 109 765 321 098 6</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("left") INDENT_STYLE ("left",
"3") "'>111 222 333 444 555 666 7</div>"),
+ " 123 567\n"
+ " 901 345\n"
+ " 789 123 5\n"
+ " 987 543\n"
+ " 109 765\n"
+ " 321 098 6\n"
+ " 111 222\n"
+ " 333 444\n"
+ " 555 666 7\n",
+ -1 },
+ /* 32 */{ HTML ("<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("center") INDENT_STYLE ("left",
"3") "'>123 567 901 345 789 123 5</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("center") INDENT_STYLE ("left",
"6") "'>987 543 109 765 321 098 6</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("center") INDENT_STYLE ("left",
"3") "'>111 222 333 444 555 666 7</div>"),
+ " 123 567\n"
+ " 901 345\n"
+ " 789 123 5\n"
+ " 987 543\n"
+ " 109 765\n"
+ " 321 098 6\n"
+ " 111 222\n"
+ " 333 444\n"
+ " 555 666 7\n",
+ -1 },
+ /* 33 */{ HTML ("<div style='width:10ch; " BREAK_STYLE DIR_STYLE ("rtl") INDENT_STYLE ("right", "3")
"'>123 567 901 345 789 123 5</div>"
+ "<div style='width:10ch; " BREAK_STYLE DIR_STYLE ("rtl") INDENT_STYLE ("right", "6")
"'>987 543 109 765 321 098 6</div>"
+ "<div style='width:10ch; " BREAK_STYLE DIR_STYLE ("rtl") INDENT_STYLE ("right", "3")
"'>111 222 333 444 555 666 7</div>"),
+ "123 567 \n"
+ "901 345 \n"
+ "789 123 5 \n"
+ "987 543 \n"
+ "109 765 \n"
+ "321 098 6 \n"
+ "111 222 \n"
+ "333 444 \n"
+ "555 666 7 \n",
+ -1 },
+ /* 34 */{ HTML ("<div style='width:10ch; " BREAK_STYLE DIR_STYLE ("ltr") ALIGN_STYLE ("right")
INDENT_STYLE ("left", "3") "'>123 567 901 345 789 123 5</div>"
+ "<div style='width:10ch; " BREAK_STYLE DIR_STYLE ("ltr") ALIGN_STYLE ("right")
INDENT_STYLE ("left", "6") "'>987 543 109 765 321 098 6</div>"
+ "<div style='width:10ch; " BREAK_STYLE DIR_STYLE ("ltr") ALIGN_STYLE ("right")
INDENT_STYLE ("left", "3") "'>111 222 333 444 555 666 7</div>"),
+ " 123 567\n"
+ " 901 345\n"
+ " 789 123 5\n"
+ " 987 543\n"
+ " 109 765\n"
+ " 321 098 6\n"
+ " 111 222\n"
+ " 333 444\n"
+ " 555 666 7\n",
+ -1 },
+ /* 35 */{ HTML ("<div style='width:10ch; " BREAK_STYLE DIR_STYLE ("rtl") ALIGN_STYLE ("left")
INDENT_STYLE ("right", "3") "'>123 567 901 345 789 123 5</div>"
+ "<div style='width:10ch; " BREAK_STYLE DIR_STYLE ("rtl") ALIGN_STYLE ("left")
INDENT_STYLE ("right", "6") "'>987 543 109 765 321 098 6</div>"
+ "<div style='width:10ch; " BREAK_STYLE DIR_STYLE ("rtl") ALIGN_STYLE ("left")
INDENT_STYLE ("right", "3") "'>111 222 333 444 555 666 7</div>"),
+ "123 567 \n"
+ "901 345 \n"
+ "789 123 5 \n"
+ "987 543 \n"
+ "109 765 \n"
+ "321 098 6 \n"
+ "111 222 \n"
+ "333 444 \n"
+ "555 666 7 \n",
+ -1 },
+ /* 36 */{ HTML ("<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("justify") INDENT_STYLE ("left",
"3") "'>123 567 901 345 789 123 5</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("justify") INDENT_STYLE ("left",
"6") "'>987 543 109 765 321 098 6</div>"
+ "<div style='width:10ch; " BREAK_STYLE ALIGN_STYLE ("justify") INDENT_STYLE ("left",
"3") "'>111 222 333 444 555 666 7</div>"),
+ " 123 567\n"
+ " 901 345\n"
+ " 789 123 5\n"
+ " 987 543\n"
+ " 109 765\n"
+ " 321 098 6\n"
+ " 111 222\n"
+ " 333 444\n"
+ " 555 666 7\n",
+ -1 },
+ /* 37 */{ HTML ("<ul style='width: 9ch;'>"
+ "<li>1 11 111 1111 111 11 1</li>"
+ "<li>2 22 222 2222 222 22 2</li>"
+ "<li>3 33 333 3333 33333 333 33 3</li>"
+ "</ul>"),
+ " * 1 11 111\n"
+ " 1111 111\n"
+ " 11 1\n"
+ " * 2 22 222\n"
+ " 2222 222\n"
+ " 22 2\n"
+ " * 3 33 333\n"
+ " 3333\n"
+ " 33333 333\n"
+ " 33 3\n",
+ -1 },
+ /* 38 */{ HTML ("<ol style='width: 9ch;'>"
+ "<li>1 11 111 1111 111 11 1</li>"
+ "<li>2 22 222 2222 222 22 2</li>"
+ "<li>3 33 333 3333 33333 333 33 3</li>"
+ "</ol>"),
+ " 1. 1 11 111\n"
+ " 1111 111\n"
+ " 11 1\n"
+ " 2. 2 22 222\n"
+ " 2222 222\n"
+ " 22 2\n"
+ " 3. 3 33 333\n"
+ " 3333\n"
+ " 33333 333\n"
+ " 33 3\n",
+ -1 },
+ /* 39 */{ HTML ("<ol type='A' style='width: 9ch;'>"
+ "<li>1 11 111 1111 111 11 1</li>"
+ "<li>2 22 222 2222 222 22 2</li>"
+ "<li>3 33 333 3333 33333 333 33 3</li>"
+ "</ol>"),
+ " A. 1 11 111\n"
+ " 1111 111\n"
+ " 11 1\n"
+ " B. 2 22 222\n"
+ " 2222 222\n"
+ " 22 2\n"
+ " C. 3 33 333\n"
+ " 3333\n"
+ " 33333 333\n"
+ " 33 3\n",
+ -1 },
+ /* 40 */{ HTML ("<ol type='a' style='width: 9ch;'>"
+ "<li>1 11 111 1111 111 11 1</li>"
+ "<li>2 22 222 2222 222 22 2</li>"
+ "<li>3 33 333 3333 33333 333 33 3</li>"
+ "</ol>"),
+ " a. 1 11 111\n"
+ " 1111 111\n"
+ " 11 1\n"
+ " b. 2 22 222\n"
+ " 2222 222\n"
+ " 22 2\n"
+ " c. 3 33 333\n"
+ " 3333\n"
+ " 33333 333\n"
+ " 33 3\n",
+ -1 },
+ /* 41 */{ HTML ("<ol type='I' style='width: 9ch;'>"
+ "<li>1 11 111 1111 111 11 1</li>"
+ "<li>2 22 222 2222 222 22 2</li>"
+ "<li>3 33 333 3333 33333 333 33 3</li>"
+ "</ol>"),
+ " I. 1 11 111\n"
+ " 1111 111\n"
+ " 11 1\n"
+ " II. 2 22 222\n"
+ " 2222 222\n"
+ " 22 2\n"
+ " III. 3 33 333\n"
+ " 3333\n"
+ " 33333 333\n"
+ " 33 3\n",
+ -1 },
+ /* 42 */{ HTML ("<ol type='i' style='width: 9ch;'>"
+ "<li>1 11 111 1111 111 11 1</li>"
+ "<li>2 22 222 2222 222 22 2</li>"
+ "<li>3 33 333 3333 33333 333 33 3</li>"
+ "</ol>"),
+ " i. 1 11 111\n"
+ " 1111 111\n"
+ " 11 1\n"
+ " ii. 2 22 222\n"
+ " 2222 222\n"
+ " 22 2\n"
+ " iii. 3 33 333\n"
+ " 3333\n"
+ " 33333 333\n"
+ " 33 3\n",
+ -1 },
+ /* 43 */{ HTML ("<ol type='i' style='width: 9ch;'>"
+ "<li>1</li>"
+ "<li>2</li>"
+ "<li>3</li>"
+ "<li>4</li>"
+ "<li>5</li>"
+ "<li>6</li>"
+ "<li>7</li>"
+ "<li>8</li>"
+ "<li>9</li>"
+ "<li>10</li>"
+ "<li>11</li>"
+ "<li>12</li>"
+ "<li>13</li>"
+ "<li>14</li>"
+ "<li>15</li>"
+ "<li>16</li>"
+ "<li>17</li>"
+ "<li>18</li>"
+ "<li>19</li>"
+ "<li>20</li>"
+ "</ol>"),
+ " i. 1\n"
+ " ii. 2\n"
+ " iii. 3\n"
+ " iv. 4\n"
+ " v. 5\n"
+ " vi. 6\n"
+ " vii. 7\n"
+ " viii. 8\n"
+ " ix. 9\n"
+ " x. 10\n"
+ " xi. 11\n"
+ " xii. 12\n"
+ " xiii. 13\n"
+ " xiv. 14\n"
+ " xv. 15\n"
+ " xvi. 16\n"
+ " xvii. 17\n"
+ "xviii. 18\n"
+ " xix. 19\n"
+ " xx. 20\n",
+ -1 },
+ /* 44 */{ HTML ("<ol style='width: 9ch; " DIR_STYLE ("rtl") "'>"
+ "<li>1 11 111 1111 111 11 1</li>"
+ "<li>2 22 222 2222 222 22 2</li>"
+ "<li>3 33 333 3333 33333 333 33 3</li>"
+ "<li>4</li>"
+ "</ol>"),
+ "1 11 111 .1 \n"
+ "1111 111 \n"
+ "11 1 \n"
+ "2 22 222 .2 \n"
+ "2222 222 \n"
+ "22 2 \n"
+ "3 33 333 .3 \n"
+ "3333 \n"
+ "33333 333 \n"
+ "33 3 \n"
+ "4 .4 \n",
+ -1 },
+ /* 45 */{ HTML ("<ol type='I' style='width: 9ch; " DIR_STYLE ("rtl") "'>"
+ "<li>1</li>"
+ "<li>2</li>"
+ "<li>3</li>"
+ "<li>4</li>"
+ "<li>5</li>"
+ "<li>6</li>"
+ "<li>7</li>"
+ "<li>8</li>"
+ "<li>9</li>"
+ "<li>10</li>"
+ "<li>11</li>"
+ "<li>12</li>"
+ "<li>13</li>"
+ "<li>14</li>"
+ "<li>15</li>"
+ "<li>16</li>"
+ "<li>17</li>"
+ "<li>18</li>"
+ "<li>19</li>"
+ "<li>20</li>"
+ "</ol>"),
+ "1 .I \n"
+ "2 .II \n"
+ "3 .III \n"
+ "4 .IV \n"
+ "5 .V \n"
+ "6 .VI \n"
+ "7 .VII \n"
+ "8 .VIII \n"
+ "9 .IX \n"
+ "10 .X \n"
+ "11 .XI \n"
+ "12 .XII \n"
+ "13 .XIII \n"
+ "14 .XIV \n"
+ "15 .XV \n"
+ "16 .XVI \n"
+ "17 .XVII \n"
+ "18 .XVIII\n"
+ "19 .XIX \n"
+ "20 .XX \n",
+ -1 },
+ /* 46 */{ HTML ("<ul style='width: 15ch; padding-inline-start: 3ch;'>"
+ "<li>AA 1 2 3 4 5 6 7 8 9 11 22 33</li>"
+ "<ul style='width: 12ch; padding-inline-start: 3ch;'>"
+ "<li>BA 1 2 3 4 5 6 7 8 9</li>"
+ "<li>BB 1 2 3 4 5 6 7 8 9</li>"
+ "<ul style='width: 9ch; padding-inline-start: 3ch;'>"
+ "<li>CA 1 2 3 4 5 6</li>"
+ "<li>CB 1 2 3 4 5 6</li>"
+ "</ul>"
+ "<li>BC 1 2 3 4 5 6</li>"
+ "</ul>"
+ "<li>AB 1 2 3 4 5 6 7</li>"
+ "</ul>"),
+ " * AA 1 2 3 4 5 6\n"
+ " 7 8 9 11 22 33\n"
+ " - BA 1 2 3 4 5\n"
+ " 6 7 8 9\n"
+ " - BB 1 2 3 4 5\n"
+ " 6 7 8 9\n"
+ " + CA 1 2 3\n"
+ " 4 5 6\n"
+ " + CB 1 2 3\n"
+ " 4 5 6\n"
+ " - BC 1 2 3 4 5\n"
+ " 6\n"
+ " * AB 1 2 3 4 5 6\n"
+ " 7\n",
+ -1 },
+ /* 47 */{ HTML ("<ol>"
+ "<li>1</li>"
+ "<ul>"
+ "<li>1.-</li>"
+ "<ol type='i'>"
+ "<li>1.-.i</li>"
+ "<ol type='a'>"
+ "<li>1.-.i.a</li>"
+ "<li>1.-.i.b</li>"
+ "</ol>"
+ "<li>1.-.ii</li>"
+ "<ol type='A'>"
+ "<li>1.-.ii.A</li>"
+ "<ul>"
+ "<li>1.-.ii.A.-</li>"
+ "<ul>"
+ "<li>1.-.ii.A.-.+</li>"
+ "<ol type='I'>"
+ "<li>1.-.ii.A.-.+.I</li>"
+ "<li>1.-.ii.A.-.+.II</li>"
+ "<li>1.-.ii.A.-.+.III</li>"
+ "</ol>"
+ "<li>1.-.ii.A.-.+</li>"
+ "</ul>"
+ "<li>1.-.ii.A.-</li>"
+ "</ul>"
+ "<li>1.-.ii.B</li>"
+ "</ol>"
+ "<li>1.-.iii</li>"
+ "</ol>"
+ "<li>1.-</li>"
+ "</ul>"
+ "<li>2</li>"
+ "</ol>"),
+ " 1. 1\n"
+ " - 1.-\n"
+ " i. 1.-.i\n"
+ " a. 1.-.i.a\n"
+ " b. 1.-.i.b\n"
+ " ii. 1.-.ii\n"
+ " A. 1.-.ii.A\n"
+ " - 1.-.ii.A.-\n"
+ " + 1.-.ii.A.-.+\n"
+ " I. 1.-.ii.A.-.+.I\n"
+ " II. 1.-.ii.A.-.+.II\n"
+ " III. 1.-.ii.A.-.+.III\n"
+ " + 1.-.ii.A.-.+\n"
+ " - 1.-.ii.A.-\n"
+ " B. 1.-.ii.B\n"
+ " iii. 1.-.iii\n"
+ " - 1.-\n"
+ " 2. 2\n",
+ -1 },
+ /* 48 */{ HTML ("<div style='width:10ch'>123456789 1234567890123456789 12345678901234567890
123456789012345678901</div>"),
+ "123456789\n"
+ "1234567890\n"
+ "123456789\n"
+ "1234567890\n"
+ "1234567890\n"
+ "1234567890\n"
+ "1234567890\n"
+ "1\n",
+ 10 },
+ /* 49 */{ HTML ("<div style='width:70ch'>before <img src='https://no.where/img.img'> after</div>"),
+ "before after\n",
+ 70 },
+ /* 50 */{ HTML ("<div style='width:70ch'>before <img src='https://no.where/img.img' alt='alt'>
after</div>"),
+ "before alt after\n",
+ 70 },
+ /* 51 */{ HTML ("<div style='width:70ch'>before <a href='https://no.where/'>https://no.where/</a>
after</div>"),
+ "before https://no.where/ after\n",
+ 70 },
+ /* 52 */{ HTML ("<div style='width:70ch'>before <a href='https://no.where/'>here</a> after</div>"),
+ "before here after\n",
+ 70 },
+ /* 53 */{ HTML ("<div style='width:31ch'>before <a href='https://no.where/'>https://no.where/</a>
after</div>"),
+ "before https://no.where/ after\n",
+ 31 },
+ /* 54 */{ HTML ("<div style='width:26ch'>before <a href='https://no.where/'>https://no.where/</a>
after</div>"),
+ "before https://no.where/\n"
+ "after\n",
+ 26 },
+ /* 55 */{ HTML ("<div style='width:20ch'>before <a href='https://no.where/'>https://no.where/</a>
after</div>"),
+ "before\n"
+ "https://no.where/\n"
+ "after\n",
+ 20 },
+ /* 56 */{ HTML ("<div style='width:20ch'>before <a
href='https://no.where/'>https://no.where/1234567890/123457890/1234567890</a> after</div>"),
+ "before\n"
+ "https://no.where/1234567890/123457890/1234567890\n"
+ "after\n",
+ 20 },
+ /* 57 */{ HTML ("<p><div style='width:20ch'>before <a href='https://no.where/'>https://no.where/</a>
after</div></p>"),
+ "before\n"
+ "https://no.where/\n"
+ "after\n",
+ 20 },
+ /* 58 */{ HTML ("<p><div style='width:20ch'>before <a
href='https://no.where/'>https://no.where/1234567890/123457890/1234567890</a> after</div></p>"),
+ "before\n"
+ "https://no.where/1234567890/123457890/1234567890\n"
+ "after\n",
+ 20 },
+ /* 59 */{ HTML ("<div style='width:16ch'>before <a href='https://no.where/'>anchor text</a>
after</div>"),
+ "before anchor\n"
+ "text after\n",
+ 16 },
+ /* 60 */{ HTML ("<div>text before<br class=\"-x-evo-wrap-br\"><a
href='https://no.where/'>https://no.where/1234567890/123457890/1234567890</a><br
class=\"-x-evo-wrap-br\">text after</div>"),
+ "text\n"
+ "before\n"
+ "https://no.where/1234567890/123457890/1234567890\n"
+ "text\n"
+ "after\n",
+ 6 },
+ /* 61 */{ HTML ("<div>text before<br class=\"-x-evo-wrap-br\"><a
href='https://no.where/'>https://no.where/1234567890/123457890/1234567890</a><br
class=\"-x-evo-wrap-br\">text after</div>"),
+ "text\n"
+ "before\n"
+ "https://no.where/1234567890/123457890/1234567890\n"
+ "text\n"
+ "after\n",
+ 9 },
+ /* 62 */{ HTML ("<div>text before<br class=\"-x-evo-wrap-br\"><a
href='https://no.where/'>https://no.where/1234567890/123457890/1234567890</a><br
class=\"-x-evo-wrap-br\">text after</div>"),
+ "text\n"
+ "before\n"
+ "https://no.where/1234567890/123457890/1234567890\n"
+ "text after\n",
+ 10 },
+ /* 63 */{ HTML ("<div>text before<br class=\"-x-evo-wrap-br\"><a
href='https://no.where/'>https://no.where/1234567890/123457890/1234567890</a><br
class=\"-x-evo-wrap-br\">text after</div>"),
+ "text before\n"
+ "https://no.where/1234567890/123457890/1234567890\n"
+ "text after\n",
+ 11 },
+ /* 64 */{ HTML ("<div>text before<br class=\"-x-evo-wrap-br\"><a
href='https://no.where/'>https://no.where/1234567890/123457890/1234567890</a><br
class=\"-x-evo-wrap-br\">text after</div>"),
+ "text before\n"
+ "https://no.where/1234567890/123457890/1234567890\n"
+ "text after\n",
+ 12 },
+ /* 65 */{ HTML ("<div>text before<br><a
href='https://no.where/'>https://no.where/1234567890/123457890/1234567890</a><br>text after</div>"),
+ "text before\n"
+ "https://no.where/1234567890/123457890/1234567890\n"
+ "text after\n",
+ 12 },
+ /* 66 */{ HTML ("<div>line1<br>\n"
+ "line2<br>\n"
+ "line3<br>\n"
+ "<br>\n"
+ "<br>\n"
+ "line6<br>\n"
+ "</div>"),
+ "line1\n"
+ "line2\n"
+ "line3\n"
+ "\n"
+ "\n"
+ "line6\n",
+ 71 }
+ };
+
+ #undef HTML
+ #undef TAB
+ #undef BREAK_STYLE
+ #undef WRAP_STYLE
+ #undef ALIGN_STYLE
+ #undef INDENT_STYLE
+ #undef DIR_STYLE
+
+ gchar *script;
+ gint ii;
+
+ for (ii = 0; ii < G_N_ELEMENTS (tests); ii++) {
+ test_utils_load_string (fixture, tests[ii].html);
+
+ script = e_web_view_jsc_printf_script ("EvoConvert.ToPlainText(document.body, %d);",
tests[ii].normal_div_width);
+
+ test_utils_jsc_call_string_and_verify (fixture, script, tests[ii].plain);
+
+ g_free (script);
+ }
+}
+
+static void
+test_convert_to_plain_quoted (TestFixture *fixture)
+{
+ #define HTML(_body) ("<html><head><style><!-- span.Apple-tab-span { white-space:pre; }
--></style></head><body style='font-family:monospace;'>" _body "</body></html>")
+ #define QUOTE_SPAN(x) "<span class='-x-evo-quoted'>" x "</span>"
+ #define QUOTE_CHR "<span class='-x-evo-quote-character'>> </span>"
+
+ struct _tests {
+ const gchar *html;
+ const gchar *plain;
+ gint normal_div_width;
+ } tests[] = {
+ /* 0 */ { HTML ("<div style='width:10ch;'>123 456 789 123</div>"
+ "<blockquote type='cite'>"
+ "<div style='width:8ch;'>123 456 789 1 2 3 4</div>"
+ "<div style='width:8ch;'>abc def ghi j k l m</div>"
+ "</blockquote>"
+ "<div>end</div>"),
+ "123 456\n"
+ "789 123\n"
+ "> 123 456\n"
+ "> 789 1 2\n"
+ "> 3 4\n"
+ "> abc def\n"
+ "> ghi j k\n"
+ "> l m\n"
+ "end\n",
+ 10 },
+ /* 1 */ { HTML ("<div style='width:12ch;'>123 456</div>"
+ "<blockquote type='cite'>"
+ "<div style='width:10ch;'>123 456</div>"
+ "<blockquote>"
+ "<div style='width:8ch;'>789 1 2 3 4</div>"
+ "</blockquote>"
+ "<div style='width:10ch;'>mid</div>"
+ "<blockquote>"
+ "<blockquote>"
+ "<div style='width:6ch;'>abc</div>"
+ "<div style='width:6ch;'>def ghi j k l m</div>"
+ "</blockquote>"
+ "<div style='width:8ch;'>abc d e f g h i j</div>"
+ "</blockquote>"
+ "<div style='width:10ch;'>l1 a b c d e f g</div>"
+ "</blockquote>"
+ "<div>end</div>"),
+ "123 456\n"
+ "> 123 456\n"
+ "> > 789 1 2\n"
+ "> > 3 4\n"
+ "> mid\n"
+ "> > > abc\n"
+ "> > > def\n"
+ "> > > ghi j\n"
+ "> > > k l m\n"
+ "> > abc d e\n"
+ "> > f g h i\n"
+ "> > j\n"
+ "> l1 a b c d\n"
+ "> e f g\n"
+ "end\n",
+ 10 },
+ /* 2 */ { HTML ("<div style='width:10ch;'>123 456<br>789 123</div>"
+ "<blockquote type='cite'>"
+ "<div style='width:8ch;'>123 456<br>789 1 2 3 4</div>"
+ "<blockquote type='cite'>"
+ "<div style='width:6ch;'>abc<br>def g h i j k</div>"
+ "</blockquote>"
+ "</blockquote>"
+ "<div>end</div>"),
+ "123 456\n"
+ "789 123\n"
+ "> 123 456\n"
+ "> 789 1 2\n"
+ "> 3 4\n"
+ "> > abc\n"
+ "> > def g\n"
+ "> > h i j\n"
+ "> > k\n"
+ "end\n",
+ 10 },
+ /* 3 */ { HTML ("<p style='width:10ch;'>123 456<br>789 123</p>"
+ "<blockquote type='cite'>"
+ "<p style='width:8ch;'>123 456<br>789 1 2 3 4</p>"
+ "<blockquote type='cite'>"
+ "<p style='width:6ch;'>abc<br>def g h i j k</p>"
+ "</blockquote>"
+ "</blockquote>"
+ "<p>end</p>"),
+ "123 456\n"
+ "789 123\n"
+ "> 123 456\n"
+ "> 789 1 2\n"
+ "> 3 4\n"
+ "> > abc\n"
+ "> > def g\n"
+ "> > h i j\n"
+ "> > k\n"
+ "end\n",
+ 10 },
+ /* 4 */ { HTML ("<pre>123 456 789 123</pre>"
+ "<blockquote type='cite'>"
+ "<pre>123 456 789 1 2 3 4</pre>"
+ "<blockquote type='cite'>"
+ "<pre>abc def g h i j k</pre>"
+ "</blockquote>"
+ "</blockquote>"
+ "<pre>end</pre>"),
+ "123 456 789 123\n"
+ "> 123 456 789 1 2 3 4\n"
+ "> > abc def g h i j k\n"
+ "end\n",
+ 10 },
+ /* 5 */ { HTML ("<pre>123 456\n789 123</pre>"
+ "<blockquote type='cite'>"
+ "<pre>123 456\n789 1 2 3 4</pre>"
+ "<blockquote type='cite'>"
+ "<pre>abc def\ng h\ni j k</pre>"
+ "</blockquote>"
+ "<pre>a b\nc\nd e f</pre>"
+ "</blockquote>"
+ "<pre>end</pre>"),
+ "123 456\n"
+ "789 123\n"
+ "> 123 456\n"
+ "> 789 1 2 3 4\n"
+ "> > abc def\n"
+ "> > g h\n"
+ "> > i j k\n"
+ "> a b\n"
+ "> c\n"
+ "> d e f\n"
+ "end\n",
+ 10 },
+ /* 6 */ { HTML ("<blockquote type='cite'>"
+ "<div style='width:70ch'>before <a href='https://no.where/'>https://no.where/</a>
after</div>"
+ "</blockquote>"),
+ "> before https://no.where/ after\n",
+ 70 },
+ /* 7 */ { HTML ("<blockquote type='cite'>"
+ "<div style='width:70ch'>before <a href='https://no.where/'>here</a> after</div>"
+ "</blockquote>"),
+ "> before here after\n",
+ 70 },
+ /* 8 */ { HTML ("<blockquote type='cite'>"
+ "<div style='width:31ch'>before <a href='https://no.where/'>https://no.where/</a>
after</div>"
+ "</blockquote>"),
+ "> before https://no.where/ after\n",
+ 33 },
+ /* 9 */ { HTML ("<blockquote type='cite'>"
+ "<div style='width:26ch'>before <a href='https://no.where/'>https://no.where/</a>
after</div>"
+ "</blockquote>"),
+ "> before https://no.where/\n"
+ "> after\n",
+ 26 },
+ /* 10 */{ HTML ("<blockquote type='cite'>"
+ "<div style='width:20ch'>before <a href='https://no.where/'>https://no.where/</a>
after</div>"
+ "</blockquote>"),
+ "> before\n"
+ "> https://no.where/\n"
+ "> after\n",
+ 20 },
+ /* 11 */{ HTML ("<blockquote type='cite'>"
+ "<div style='width:20ch'>before <a
href='https://no.where/'>https://no.where/1234567890/123457890/1234567890</a> after</div>"
+ "</blockquote>"),
+ "> before\n"
+ "> https://no.where/1234567890/123457890/1234567890\n"
+ "> after\n",
+ 20 },
+ /* 12 */{ HTML ("<blockquote type='cite'>"
+ "<blockquote type='cite'>"
+ "<div style='width:20ch'>before <a
href='https://no.where/'>https://no.where/</a> after</div>"
+ "</blockquote>"
+ "</blockquote>"),
+ "> > before\n"
+ "> > https://no.where/\n"
+ "> > after\n",
+ 20 },
+ /* 13 */{ HTML ("<blockquote type='cite'>"
+ "<blockquote type='cite'>"
+ "<div style='width:20ch'>before <a
href='https://no.where/'>https://no.where/1234567890/123457890/1234567890</a> after</div>"
+ "</blockquote>"
+ "</blockquote>"),
+ "> > before\n"
+ "> > https://no.where/1234567890/123457890/1234567890\n"
+ "> > after\n",
+ 20 },
+ /* 14 */{ HTML ("<blockquote type='cite'>"
+ "<blockquote type='cite'>"
+ "<div style='width:16ch'>before <a href='https://no.where/'>anchor text</a>
after</div>"
+ "</blockquote>"
+ "</blockquote>"),
+ "> > before anchor\n"
+ "> > text after\n",
+ 16 },
+ /* 15 */{ HTML ("<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "text before<br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "<a
href='https://no.where/'>https://no.where/1234567890/123457890/1234567890</a><br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "text after</div>"
+ "</blockquote>"),
+ "> text\n"
+ "> before\n"
+ "> https://no.where/1234567890/123457890/1234567890\n"
+ "> text\n"
+ "> after\n",
+ 8 },
+ /* 16 */{ HTML ("<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "text before<br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "<a
href='https://no.where/'>https://no.where/1234567890/123457890/1234567890</a><br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "text after</div>"
+ "</blockquote>"),
+ "> text\n"
+ "> before\n"
+ "> https://no.where/1234567890/123457890/1234567890\n"
+ "> text\n"
+ "> after\n",
+ 11 },
+ /* 17 */{ HTML ("<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "text before<br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "<a
href='https://no.where/'>https://no.where/1234567890/123457890/1234567890</a><br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "text after</div>"
+ "</blockquote>"),
+ "> text\n"
+ "> before\n"
+ "> https://no.where/1234567890/123457890/1234567890\n"
+ "> text after\n",
+ 12 },
+ /* 18 */{ HTML ("<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "text before<br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "<a
href='https://no.where/'>https://no.where/1234567890/123457890/1234567890</a><br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "text after</div>"
+ "</blockquote>"),
+ "> text before\n"
+ "> https://no.where/1234567890/123457890/1234567890\n"
+ "> text after\n",
+ 13 },
+ /* 19 */{ HTML ("<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "text before<br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "<a
href='https://no.where/'>https://no.where/1234567890/123457890/1234567890</a><br class=\"-x-evo-wrap-br\">"
+ QUOTE_SPAN (QUOTE_CHR) "text after</div>"
+ "</blockquote>"),
+ "> text before\n"
+ "> https://no.where/1234567890/123457890/1234567890\n"
+ "> text after\n",
+ 14 },
+ /* 20 */{ HTML ("<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "text before<br>"
+ QUOTE_SPAN (QUOTE_CHR) "<a
href='https://no.where/'>https://no.where/1234567890/123457890/1234567890</a><br>"
+ QUOTE_SPAN (QUOTE_CHR) "text after</div>"
+ "</blockquote>"),
+ "> text before\n"
+ "> https://no.where/1234567890/123457890/1234567890\n"
+ "> text after\n",
+ 14 },
+ /* 21 */{ HTML ("<blockquote type='cite'>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "line1<br>\n"
+ QUOTE_SPAN (QUOTE_CHR) "line2<br>\n"
+ QUOTE_SPAN (QUOTE_CHR) "line3<br>\n"
+ QUOTE_SPAN (QUOTE_CHR) "<br>\n"
+ QUOTE_SPAN (QUOTE_CHR) "<br>\n"
+ QUOTE_SPAN (QUOTE_CHR) "line6<br>\n"
+ "</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "paragraph 2<br>\n</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "paragraph 3\n</div>"
+ "<div>" QUOTE_SPAN (QUOTE_CHR) "paragraph 4</div>"
+ "</blockquote>"),
+ "> line1\n"
+ "> line2\n"
+ "> line3\n"
+ "> \n"
+ "> \n"
+ "> line6\n"
+ "> paragraph 2\n"
+ "> paragraph 3\n"
+ "> paragraph 4\n",
+ 71 }
+ };
+
+ #undef QUOTE_SPAN
+ #undef QUOTE_CHR
+ #undef HTML
+
+ gchar *script;
+ gint ii;
+
+ for (ii = 0; ii < G_N_ELEMENTS (tests); ii++) {
+ test_utils_load_string (fixture, tests[ii].html);
+
+ script = e_web_view_jsc_printf_script ("EvoConvert.ToPlainText(document.body, %d);",
tests[ii].normal_div_width);
+
+ test_utils_jsc_call_string_and_verify (fixture, script, tests[ii].plain);
+
+ g_free (script);
+ }
+}
+
gint
main (gint argc,
gchar *argv[])
@@ -1933,6 +2942,8 @@ main (gint argc,
g_test_init (&argc, &argv, NULL);
g_test_bug_base ("https://gitlab.gnome.org/GNOME/evolution/issues/");
+ g_setenv ("E_WEB_VIEW_TEST_SOURCES", "1", FALSE);
+
gtk_init (&argc, &argv);
e_util_init_main_thread (NULL);
@@ -1950,6 +2961,8 @@ main (gint argc,
test_utils_add_test ("/EWebView/Selection", test_selection);
test_utils_add_test ("/EWebView/GetContent", test_get_content);
test_utils_add_test ("/EWebView/GetElementFromPoint", test_get_element_from_point);
+ test_utils_add_test ("/EWebView/ConvertToPlain", test_convert_to_plain);
+ test_utils_add_test ("/EWebView/ConvertToPlainQuoted", test_convert_to_plain_quoted);
res = g_test_run ();
diff --git a/src/mail/e-cid-request.c b/src/mail/e-cid-request.c
index 16d58ec73f..ef12b682a1 100644
--- a/src/mail/e-cid-request.c
+++ b/src/mail/e-cid-request.c
@@ -19,9 +19,49 @@
#include <stdio.h>
#include <string.h>
-#include "e-mail-display.h"
#include "e-cid-request.h"
+G_DEFINE_INTERFACE (ECidResolver, e_cid_resolver, G_TYPE_OBJECT)
+
+static void
+e_cid_resolver_default_init (ECidResolverInterface *iface)
+{
+}
+
+CamelMimePart *
+e_cid_resolver_ref_part (ECidResolver *resolver,
+ const gchar *uri)
+{
+ ECidResolverInterface *iface;
+
+ g_return_val_if_fail (E_IS_CID_RESOLVER (resolver), NULL);
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ iface = E_CID_RESOLVER_GET_INTERFACE (resolver);
+ g_return_val_if_fail (iface != NULL, NULL);
+ g_return_val_if_fail (iface->ref_part != NULL, NULL);
+
+ return iface->ref_part (resolver, uri);
+}
+
+gchar *
+e_cid_resolver_dup_mime_type (ECidResolver *resolver,
+ const gchar *uri)
+{
+ ECidResolverInterface *iface;
+
+ g_return_val_if_fail (E_IS_CID_RESOLVER (resolver), NULL);
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ iface = E_CID_RESOLVER_GET_INTERFACE (resolver);
+ g_return_val_if_fail (iface != NULL, NULL);
+
+ if (iface->dup_mime_type)
+ return iface->dup_mime_type (resolver, uri);
+
+ return NULL;
+}
+
struct _ECidRequestPrivate {
gint dummy;
};
@@ -51,9 +91,6 @@ e_cid_request_process_sync (EContentRequest *request,
GCancellable *cancellable,
GError **error)
{
- EMailDisplay *display;
- EMailPartList *part_list;
- EMailPart *part;
GByteArray *byte_array;
CamelStream *output_stream;
CamelDataWrapper *dw;
@@ -66,20 +103,13 @@ e_cid_request_process_sync (EContentRequest *request,
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return FALSE;
- if (!E_IS_MAIL_DISPLAY (requester))
+ if (!E_IS_CID_RESOLVER (requester))
return FALSE;
- display = E_MAIL_DISPLAY (requester);
-
- part_list = e_mail_display_get_part_list (display);
- if (!part_list)
+ mime_part = e_cid_resolver_ref_part (E_CID_RESOLVER (requester), uri);
+ if (!mime_part)
return FALSE;
- part = e_mail_part_list_ref_part (part_list, uri);
- if (!part)
- return FALSE;
-
- mime_part = e_mail_part_ref_mime_part (part);
dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
g_return_val_if_fail (dw != NULL, FALSE);
@@ -102,11 +132,14 @@ e_cid_request_process_sync (EContentRequest *request,
*out_stream_length = g_bytes_get_size (bytes);
mime_type = camel_data_wrapper_get_mime_type (dw);
- if (mime_type && *mime_type)
+ if (mime_type && *mime_type) {
*out_mime_type = mime_type;
- else {
+ } else {
g_free (mime_type);
- *out_mime_type = g_strdup (e_mail_part_get_mime_type (part));
+ *out_mime_type = e_cid_resolver_dup_mime_type (E_CID_RESOLVER (requester), uri);
+
+ if (!*out_mime_type)
+ *out_mime_type = g_strdup ("application/octet-stream");
}
g_bytes_unref (bytes);
@@ -116,7 +149,6 @@ e_cid_request_process_sync (EContentRequest *request,
g_object_unref (output_stream);
g_object_unref (mime_part);
- g_object_unref (part);
return success;
}
diff --git a/src/mail/e-cid-request.h b/src/mail/e-cid-request.h
index 0ed6e4b242..15b12c7066 100644
--- a/src/mail/e-cid-request.h
+++ b/src/mail/e-cid-request.h
@@ -20,6 +20,24 @@
#include <e-util/e-util.h>
/* Standard GObject macros */
+#define E_TYPE_CID_RESOLVER \
+ (e_cid_resolver_get_type ())
+#define E_CID_RESOLVER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CID_RESOLVER, ECidResolver))
+#define E_CID_RESOLVER_INTERFACE(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CID_RESOLVER, ECidResolverInterface))
+#define E_IS_CID_RESOLVER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CID_RESOLVER))
+#define E_IS_CID_RESOLVER_INTERFACE(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CID_RESOLVER))
+#define E_CID_RESOLVER_GET_INTERFACE(obj) \
+ (G_TYPE_INSTANCE_GET_INTERFACE \
+ ((obj), E_TYPE_CID_RESOLVER, ECidResolverInterface))
+
#define E_TYPE_CID_REQUEST \
(e_cid_request_get_type ())
#define E_CID_REQUEST(obj) \
@@ -40,6 +58,25 @@
G_BEGIN_DECLS
+typedef struct _ECidResolver ECidResolver;
+typedef struct _ECidResolverInterface ECidResolverInterface;
+
+struct _ECidResolverInterface {
+ GTypeInterface parent_interface;
+
+ CamelMimePart * (* ref_part) (ECidResolver *resolver,
+ const gchar *uri);
+
+ gchar * (* dup_mime_type) (ECidResolver *resolver,
+ const gchar *uri);
+};
+
+GType e_cid_resolver_get_type (void);
+CamelMimePart * e_cid_resolver_ref_part (ECidResolver *resolver,
+ const gchar *uri);
+gchar * e_cid_resolver_dup_mime_type (ECidResolver *resolver,
+ const gchar *uri);
+
typedef struct _ECidRequest ECidRequest;
typedef struct _ECidRequestClass ECidRequestClass;
typedef struct _ECidRequestPrivate ECidRequestPrivate;
diff --git a/src/mail/e-mail-display.c b/src/mail/e-mail-display.c
index 4ae60f7929..859f5dacb5 100644
--- a/src/mail/e-mail-display.c
+++ b/src/mail/e-mail-display.c
@@ -113,7 +113,10 @@ enum {
static guint signals[LAST_SIGNAL];
static CamelDataCache *emd_global_http_cache = NULL;
-G_DEFINE_TYPE (EMailDisplay, e_mail_display, E_TYPE_WEB_VIEW)
+static void e_mail_display_cid_resolver_init (ECidResolverInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EMailDisplay, e_mail_display, E_TYPE_WEB_VIEW,
+ G_IMPLEMENT_INTERFACE (E_TYPE_CID_RESOLVER, e_mail_display_cid_resolver_init))
static const gchar *ui =
"<ui>"
@@ -2135,6 +2138,71 @@ mail_display_web_process_crashed_cb (EMailDisplay *display)
e_alert_submit (alert_sink, "mail:webkit-web-process-crashed", NULL);
}
+static EMailPart *
+e_mail_display_ref_mail_part (EMailDisplay *mail_display,
+ const gchar *uri)
+{
+ EMailPartList *part_list;
+
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (mail_display), NULL);
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ part_list = e_mail_display_get_part_list (mail_display);
+ if (!part_list)
+ return NULL;
+
+ return e_mail_part_list_ref_part (part_list, uri);
+}
+
+static CamelMimePart *
+e_mail_display_cid_resolver_ref_part (ECidResolver *resolver,
+ const gchar *uri)
+{
+ EMailPart *mail_part;
+ CamelMimePart *mime_part;
+
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (resolver), NULL);
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ mail_part = e_mail_display_ref_mail_part (E_MAIL_DISPLAY (resolver), uri);
+ if (!mail_part)
+ return NULL;
+
+ mime_part = e_mail_part_ref_mime_part (mail_part);
+
+ g_object_unref (mail_part);
+
+ return mime_part;
+}
+
+static gchar *
+e_mail_display_cid_resolver_dup_mime_type (ECidResolver *resolver,
+ const gchar *uri)
+{
+ EMailPart *mail_part;
+ gchar *mime_type;
+
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (resolver), NULL);
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ mail_part = e_mail_display_ref_mail_part (E_MAIL_DISPLAY (resolver), uri);
+ if (!mail_part)
+ return NULL;
+
+ mime_type = g_strdup (e_mail_part_get_mime_type (mail_part));
+
+ g_object_unref (mail_part);
+
+ return mime_type;
+}
+
+static void
+e_mail_display_cid_resolver_init (ECidResolverInterface *iface)
+{
+ iface->ref_part = e_mail_display_cid_resolver_ref_part;
+ iface->dup_mime_type = e_mail_display_cid_resolver_dup_mime_type;
+}
+
static void
e_mail_display_class_init (EMailDisplayClass *class)
{
diff --git a/src/mail/e-mail-notes.c b/src/mail/e-mail-notes.c
index a730afd101..d99e4b960e 100644
--- a/src/mail/e-mail-notes.c
+++ b/src/mail/e-mail-notes.c
@@ -150,13 +150,11 @@ static void
e_mail_notes_editor_extract_text_from_multipart_related (EMailNotesEditor *notes_editor,
CamelMultipart *multipart)
{
- EContentEditor *cnt_editor;
guint ii, nparts;
g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
g_return_if_fail (CAMEL_IS_MULTIPART (multipart));
- cnt_editor = e_html_editor_get_content_editor (notes_editor->editor);
nparts = camel_multipart_get_number (multipart);
for (ii = 0; ii < nparts; ii++) {
@@ -173,11 +171,14 @@ e_mail_notes_editor_extract_text_from_multipart_related (EMailNotesEditor *notes
continue;
if (camel_content_type_is (ct, "image", "*")) {
- e_content_editor_insert_image_from_mime_part (cnt_editor, part);
+ e_html_editor_add_cid_part (notes_editor->editor, part);
} else if (camel_content_type_is (ct, "multipart", "alternative")) {
content = camel_medium_get_content (CAMEL_MEDIUM (part));
- if (CAMEL_IS_MULTIPART (content))
- e_mail_notes_extract_text_from_multipart_alternative (cnt_editor,
CAMEL_MULTIPART (content));
+
+ if (CAMEL_IS_MULTIPART (content)) {
+ e_mail_notes_extract_text_from_multipart_alternative (
+ e_html_editor_get_content_editor (notes_editor->editor),
CAMEL_MULTIPART (content));
+ }
}
}
}
@@ -289,7 +290,8 @@ e_mail_notes_editor_extract_text_from_message (EMailNotesEditor *notes_editor,
}
static CamelMimeMessage *
-e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
+e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor,
+ EContentEditorContentHash *content_hash)
{
EContentEditor *cnt_editor;
EAttachmentStore *attachment_store;
@@ -301,6 +303,7 @@ e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
g_return_val_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor), NULL);
g_return_val_if_fail (notes_editor->editor, NULL);
+ g_return_val_if_fail (content_hash != NULL, NULL);
cnt_editor = e_html_editor_get_content_editor (notes_editor->editor);
g_return_val_if_fail (E_IS_CONTENT_EDITOR (cnt_editor), NULL);
@@ -330,24 +333,20 @@ e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
CamelMultipart *multipart_body;
CamelMimePart *part;
GSList *inline_images_parts = NULL;
- gchar *text;
+ const gchar *text;
multipart_alternative = camel_multipart_new ();
camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart_alternative),
"multipart/alternative");
camel_multipart_set_boundary (multipart_alternative, NULL);
- text = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_TEXT_PLAIN |
- E_CONTENT_EDITOR_GET_PROCESSED,
- NULL, NULL);
+ text = e_content_editor_util_get_content_data (content_hash,
E_CONTENT_EDITOR_GET_TO_SEND_PLAIN);
if (text && *text) {
- if (!g_str_has_suffix (text, "\r\n")) {
- gchar *tmp = text;
+ gchar *tmp = NULL;
- text = g_strconcat (tmp, "\r\n", NULL);
- g_free (tmp);
+ if (!g_str_has_suffix (text, "\r\n") && !g_str_has_suffix (text, "\n")) {
+ tmp = g_strconcat (text, "\r\n", NULL);
+ text = tmp;
}
part = camel_mime_part_new ();
@@ -355,33 +354,26 @@ e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
camel_multipart_add_part (multipart_alternative, part);
g_object_unref (part);
+ g_free (tmp);
has_text = TRUE;
}
- g_free (text);
-
- text = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_PROCESSED |
- E_CONTENT_EDITOR_GET_TEXT_HTML |
- E_CONTENT_EDITOR_GET_INLINE_IMAGES,
- g_get_host_name (),
- &inline_images_parts);
+ text = e_content_editor_util_get_content_data (content_hash,
E_CONTENT_EDITOR_GET_TO_SEND_HTML);
+ inline_images_parts = e_content_editor_util_get_content_data (content_hash,
E_CONTENT_EDITOR_GET_INLINE_IMAGES);
if (has_attachments && !has_text && (!text || !*text)) {
/* Text is required, thus if there are attachments,
but no text, then store at least a space. */
- g_free (text);
- text = g_strdup ("\r\n");
+ text = "\r\n";
}
if (text && *text) {
- if (!g_str_has_suffix (text, "\r\n")) {
- gchar *tmp = text;
+ gchar *tmp = NULL;
- text = g_strconcat (tmp, "\r\n", NULL);
- g_free (tmp);
+ if (!g_str_has_suffix (text, "\r\n") && !g_str_has_suffix (text, "\n")) {
+ tmp = g_strconcat (text, "\r\n", NULL);
+ text = tmp;
}
part = camel_mime_part_new ();
@@ -389,15 +381,13 @@ e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
camel_multipart_add_part (multipart_alternative, part);
g_object_unref (part);
+ g_free (tmp);
has_text = TRUE;
} else {
- g_slist_free_full (inline_images_parts, g_object_unref);
inline_images_parts = NULL;
}
- g_free (text);
-
if (inline_images_parts) {
GSList *link;
@@ -443,31 +433,25 @@ e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
camel_medium_set_content (CAMEL_MEDIUM (message), CAMEL_DATA_WRAPPER (multipart_body));
- g_slist_free_full (inline_images_parts, g_object_unref);
g_clear_object (&multipart_alternative);
g_clear_object (&multipart_body);
} else {
- gchar *text;
+ const gchar *text;
- text = e_content_editor_get_content (
- cnt_editor,
- E_CONTENT_EDITOR_GET_TEXT_PLAIN |
- E_CONTENT_EDITOR_GET_PROCESSED,
- NULL, NULL);
+ text = e_content_editor_util_get_content_data (content_hash,
E_CONTENT_EDITOR_GET_TO_SEND_PLAIN);
if (has_attachments && !has_text && (!text || !*text)) {
/* Text is required, thus if there are attachments,
but no text, then store at least a space. */
- g_free (text);
- text = g_strdup ("\r\n");
+ text = "\r\n";
}
if (text && *text) {
- if (!g_str_has_suffix (text, "\r\n")) {
- gchar *tmp = text;
+ gchar *tmp = NULL;
- text = g_strconcat (tmp, "\r\n", NULL);
- g_free (tmp);
+ if (!g_str_has_suffix (text, "\r\n") && !g_str_has_suffix (text, "\n")) {
+ tmp = g_strconcat (text, "\r\n", NULL);
+ text = tmp;
}
if (has_attachments) {
@@ -491,10 +475,11 @@ e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
} else {
camel_mime_part_set_content (CAMEL_MIME_PART (message), text, strlen (text),
"text/plain");
}
+
has_text = TRUE;
- }
- g_free (text);
+ g_free (tmp);
+ }
}
if (has_text) {
@@ -790,9 +775,22 @@ action_close_cb (GtkAction *action,
typedef struct {
EMailNotesEditor *notes_editor;
CamelMimeMessage *inner_message;
+ EActivity *activity;
+ GError *error;
gboolean success;
} SaveAndCloseData;
+static SaveAndCloseData *
+save_and_close_data_new (EMailNotesEditor *notes_editor)
+{
+ SaveAndCloseData *scd;
+
+ scd = g_slice_new0 (SaveAndCloseData);
+ scd->notes_editor = g_object_ref (notes_editor);
+
+ return scd;
+}
+
static void
save_and_close_data_free (gpointer ptr)
{
@@ -804,6 +802,8 @@ save_and_close_data_free (gpointer ptr)
else
g_clear_object (&scd->notes_editor);
g_clear_object (&scd->inner_message);
+ g_clear_object (&scd->activity);
+ g_clear_error (&scd->error);
g_slice_free (SaveAndCloseData, scd);
}
}
@@ -819,6 +819,12 @@ e_mail_notes_store_changes_thread (EAlertSinkThreadJobData *job_data,
g_return_if_fail (scd != NULL);
+ if (scd->error) {
+ g_propagate_error (error, scd->error);
+ scd->error = NULL;
+ return;
+ }
+
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return;
@@ -841,35 +847,76 @@ e_mail_notes_store_changes_thread (EAlertSinkThreadJobData *job_data,
}
static void
-action_save_and_close_cb (GtkAction *action,
- EMailNotesEditor *notes_editor)
+mail_notes_get_content_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- SaveAndCloseData *scd;
- gchar *full_display_name;
+ SaveAndCloseData *scd = user_data;
+ EContentEditorContentHash *content_hash;
EActivityBar *activity_bar;
EActivity *activity;
+ gchar *full_display_name;
+ GError *error = NULL;
- g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
+ g_return_if_fail (scd != NULL);
+ g_return_if_fail (E_IS_CONTENT_EDITOR (source_object));
- scd = g_slice_new0 (SaveAndCloseData);
- scd->notes_editor = g_object_ref (notes_editor);
- scd->inner_message = e_mail_notes_editor_encode_text_to_message (notes_editor);
- scd->success = FALSE;
+ content_hash = e_content_editor_get_content_finish (E_CONTENT_EDITOR (source_object), result, &error);
- full_display_name = e_mail_folder_to_full_display_name (notes_editor->folder, NULL);
+ if (content_hash) {
+ scd->inner_message = e_mail_notes_editor_encode_text_to_message (scd->notes_editor,
content_hash);
- activity_bar = e_html_editor_get_activity_bar (notes_editor->editor);
- activity = e_alert_sink_submit_thread_job (E_ALERT_SINK (notes_editor->editor),
+ if (!scd->inner_message)
+ scd->error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED, _("Failed to convert
text to message"));
+ } else {
+ scd->error = error;
+
+ if (!scd->error)
+ scd->error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED, _("Unknown error"));
+ }
+
+ g_clear_object (&scd->activity);
+
+ full_display_name = e_mail_folder_to_full_display_name (scd->notes_editor->folder, NULL);
+
+ activity_bar = e_html_editor_get_activity_bar (scd->notes_editor->editor);
+ activity = e_alert_sink_submit_thread_job (E_ALERT_SINK (scd->notes_editor->editor),
_("Storing changes…"), "mail:failed-store-note",
- full_display_name ? full_display_name : camel_folder_get_display_name (notes_editor->folder),
+ full_display_name ? full_display_name : camel_folder_get_display_name
(scd->notes_editor->folder),
e_mail_notes_store_changes_thread,
scd, save_and_close_data_free);
e_activity_bar_set_activity (activity_bar, activity);
g_clear_object (&activity);
+ e_content_editor_util_free_content_hash (content_hash);
g_free (full_display_name);
}
+static void
+action_save_and_close_cb (GtkAction *action,
+ EMailNotesEditor *notes_editor)
+{
+ SaveAndCloseData *scd;
+ EActivity *activity;
+ EContentEditor *cnt_editor;
+
+ g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
+
+ cnt_editor = e_html_editor_get_content_editor (notes_editor->editor);
+ g_return_if_fail (E_IS_CONTENT_EDITOR (cnt_editor));
+
+ activity = e_html_editor_new_activity (notes_editor->editor);
+ e_activity_set_text (activity, _("Storing changes…"));
+
+ scd = save_and_close_data_new (notes_editor);
+ scd->activity = activity; /* takes ownership */
+
+ e_content_editor_get_content (cnt_editor,
+ E_CONTENT_EDITOR_GET_INLINE_IMAGES | E_CONTENT_EDITOR_GET_TO_SEND_HTML |
E_CONTENT_EDITOR_GET_TO_SEND_PLAIN,
+ g_get_host_name (), e_activity_get_cancellable (activity),
+ mail_notes_get_content_ready_cb, scd);
+}
+
static void
e_mail_notes_editor_dispose (GObject *object)
{
diff --git a/src/modules/composer-to-meeting/e-composer-to-meeting.c
b/src/modules/composer-to-meeting/e-composer-to-meeting.c
index 8bc2b52bfc..04a328ce61 100644
--- a/src/modules/composer-to-meeting/e-composer-to-meeting.c
+++ b/src/modules/composer-to-meeting/e-composer-to-meeting.c
@@ -64,11 +64,10 @@ GType e_composer_to_meeting_get_type (void) G_GNUC_CONST;
G_DEFINE_DYNAMIC_TYPE (EComposerToMeeting, e_composer_to_meeting, E_TYPE_EXTENSION)
static ECalComponent *
-composer_to_meeting_component (EMsgComposer *composer)
+composer_to_meeting_component (EMsgComposer *composer,
+ EContentEditorContentHash *content_hash)
{
ECalComponent *comp;
- EHTMLEditor *html_editor;
- EContentEditor *cnt_editor;
EComposerHeaderTable *header_table;
EDestination **destinations_array[3];
ESource *source;
@@ -210,20 +209,12 @@ composer_to_meeting_component (EMsgComposer *composer)
g_slist_free_full (attendees, e_cal_component_attendee_free);
/* Description */
- html_editor = e_msg_composer_get_editor (composer);
- cnt_editor = e_html_editor_get_content_editor (html_editor);
- text = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_PLAIN, NULL, NULL);
+ text = content_hash ? e_content_editor_util_get_content_data (content_hash,
E_CONTENT_EDITOR_GET_TO_SEND_PLAIN) : NULL;
+
if (text && *text) {
ECalComponentText *description;
GSList *descr_list = NULL;
- if (!g_str_has_suffix (text, "\r\n")) {
- gchar *tmp = text;
-
- text = g_strconcat (tmp, "\r\n", NULL);
- g_free (tmp);
- }
-
description = e_cal_component_text_new (text, NULL);
descr_list = g_slist_append (descr_list, description);
@@ -232,7 +223,6 @@ composer_to_meeting_component (EMsgComposer *composer)
g_slist_free_full (descr_list, e_cal_component_text_free);
}
- g_free (text);
return comp;
}
@@ -270,38 +260,102 @@ composer_to_meeting_copy_attachments (EMsgComposer *composer,
g_list_free_full (attachments, g_object_unref);
}
+typedef struct _AsyncContext {
+ EMsgComposer *composer;
+ EActivity *activity;
+} AsyncContext;
+
+static AsyncContext *
+async_context_new (EMsgComposer *composer, /* adds reference */
+ EActivity *activity) /* assumes ownership */
+{
+ AsyncContext *async_context;
+
+ async_context = g_slice_new (AsyncContext);
+ async_context->composer = g_object_ref (composer);
+ async_context->activity = activity;
+
+ return async_context;
+}
+
+static void
+async_context_free (AsyncContext *async_context)
+{
+ if (async_context) {
+ g_clear_object (&async_context->composer);
+ g_clear_object (&async_context->activity);
+ g_slice_free (AsyncContext, async_context);
+ }
+}
+
+static void
+compose_to_meeting_content_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AsyncContext *async_context = user_data;
+ EContentEditorContentHash *content_hash;
+ ECalComponent *comp;
+ GError *error = NULL;
+
+ g_return_if_fail (async_context != NULL);
+ g_return_if_fail (E_IS_CONTENT_EDITOR (source_object));
+
+ content_hash = e_content_editor_get_content_finish (E_CONTENT_EDITOR (source_object), result, &error);
+
+ comp = composer_to_meeting_component (async_context->composer, content_hash);
+
+ if (comp) {
+ ECompEditor *comp_editor;
+ ECompEditorFlags flags;
+
+ flags = E_COMP_EDITOR_FLAG_IS_NEW |
+ E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER |
+ E_COMP_EDITOR_FLAG_WITH_ATTENDEES;
+
+ comp_editor = e_comp_editor_open_for_component (NULL, e_msg_composer_get_shell
(async_context->composer),
+ NULL, e_cal_component_get_icalcomponent (comp), flags);
+
+ /* Attachments */
+ composer_to_meeting_copy_attachments (async_context->composer, comp_editor);
+
+ gtk_window_present (GTK_WINDOW (comp_editor));
+
+ g_object_unref (comp);
+
+ gtk_widget_destroy (GTK_WIDGET (async_context->composer));
+ }
+
+ e_content_editor_util_free_content_hash (content_hash);
+ async_context_free (async_context);
+ g_clear_error (&error);
+}
+
static void
action_composer_to_meeting_cb (GtkAction *action,
EMsgComposer *composer)
{
- ECalComponent *comp;
- ECompEditor *comp_editor;
- ECompEditorFlags flags;
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ EActivity *activity;
+ AsyncContext *async_context;
g_return_if_fail (E_IS_MSG_COMPOSER (composer));
if (!e_util_prompt_user (GTK_WINDOW (composer), NULL, NULL,
"mail-composer:prompt-composer-to-meeting", NULL))
return;
- comp = composer_to_meeting_component (composer);
- if (!comp)
- return;
-
- flags = E_COMP_EDITOR_FLAG_IS_NEW |
- E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER |
- E_COMP_EDITOR_FLAG_WITH_ATTENDEES;
-
- comp_editor = e_comp_editor_open_for_component (NULL, e_msg_composer_get_shell (composer),
- NULL, e_cal_component_get_icalcomponent (comp), flags);
-
- /* Attachments */
- composer_to_meeting_copy_attachments (composer, comp_editor);
+ editor = e_msg_composer_get_editor (composer);
+ cnt_editor = e_html_editor_get_content_editor (editor);
- gtk_window_present (GTK_WINDOW (comp_editor));
+ activity = e_html_editor_new_activity (editor);
+ e_activity_set_text (activity, _("Reading text content…"));
- g_object_unref (comp);
+ async_context = async_context_new (composer, activity);
- gtk_widget_destroy (GTK_WIDGET (composer));
+ e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_TO_SEND_PLAIN, NULL,
+ e_activity_get_cancellable (activity),
+ compose_to_meeting_content_ready_cb, async_context);
}
static void
diff --git a/src/modules/webkit-editor/e-webkit-editor.c b/src/modules/webkit-editor/e-webkit-editor.c
index 002724e9a6..885b0f42c1 100644
--- a/src/modules/webkit-editor/e-webkit-editor.c
+++ b/src/modules/webkit-editor/e-webkit-editor.c
@@ -18,10 +18,9 @@
#include "e-webkit-editor.h"
-#include "web-extension/e-editor-web-extension-names.h"
-
#include "e-util/e-util.h"
#include "composer/e-msg-composer.h"
+#include "mail/e-cid-request.h"
#include "mail/e-http-request.h"
#include <string.h>
@@ -37,7 +36,6 @@
enum {
PROP_0,
- PROP_WEB_EXTENSION, /* for test purposes */
PROP_IS_MALFUNCTION,
PROP_CAN_COPY,
PROP_CAN_CUT,
@@ -61,13 +59,18 @@ enum {
PROP_FONT_COLOR,
PROP_FONT_NAME,
PROP_FONT_SIZE,
- PROP_INDENTED,
+ PROP_INDENT_LEVEL,
PROP_ITALIC,
- PROP_MONOSPACED,
PROP_STRIKETHROUGH,
PROP_SUBSCRIPT,
PROP_SUPERSCRIPT,
- PROP_UNDERLINE
+ PROP_UNDERLINE,
+
+ PROP_NORMAL_PARAGRAPH_WIDTH,
+ PROP_MAGIC_LINKS,
+ PROP_MAGIC_SMILEYS,
+ PROP_UNICODE_SMILEYS,
+ PROP_WRAP_QUOTED_TEXT_IN_REPLIES
};
struct _EWebKitEditorPrivate {
@@ -75,13 +78,6 @@ struct _EWebKitEditorPrivate {
gpointer initialized_user_data;
GCancellable *cancellable;
- EWebExtensionContainer *container;
- GDBusProxy *web_extension_proxy;
- gint stamp; /* Changed only in the main thread, doesn't need locking */
- guint web_extension_selection_changed_cb_id;
- guint web_extension_content_changed_cb_id;
- guint web_extension_undo_redo_state_changed_cb_id;
- guint web_extension_user_changed_default_colors_cb_id;
gboolean html_mode;
gboolean changed;
@@ -91,28 +87,39 @@ struct _EWebKitEditorPrivate {
gboolean can_undo;
gboolean can_redo;
- gboolean emit_load_finished_when_extension_is_ready;
- gboolean reload_in_progress;
- gboolean copy_paste_clipboard_in_view;
- gboolean copy_paste_primary_in_view;
- gboolean copy_cut_actions_triggered;
- gboolean pasting_primary_clipboard;
- gboolean pasting_from_itself_extension_value;
- gboolean suppress_color_changes;
-
guint32 style_flags;
- gboolean is_indented;
+ guint32 temporary_style_flags; /* that's for collapsed selection, format changes only after something
is typed */
+ gint indent_level;
GdkRGBA *background_color;
GdkRGBA *font_color;
+ GdkRGBA *body_fg_color;
+ GdkRGBA *body_bg_color;
+ GdkRGBA *body_link_color;
+ GdkRGBA *body_vlink_color;
+
+ GdkRGBA theme_bgcolor;
+ GdkRGBA theme_fgcolor;
+ GdkRGBA theme_link_color;
+ GdkRGBA theme_vlink_color;
gchar *font_name;
+ gchar *body_font_name;
guint font_size;
+ gint normal_paragraph_width;
+ gboolean magic_links;
+ gboolean magic_smileys;
+ gboolean unicode_smileys;
+ gboolean wrap_quoted_text_in_replies;
EContentEditorBlockFormat block_format;
EContentEditorAlignment alignment;
+ /* For context menu */
+ gchar *context_menu_caret_word;
+ guint32 context_menu_node_flags; /* bit-or of EContentEditorNodeFlags */
+
gchar *current_user_stylesheet;
WebKitLoadEvent webkit_load_event;
@@ -154,9 +161,18 @@ struct _EWebKitEditorPrivate {
};
static const GdkRGBA black = { 0, 0, 0, 1 };
-static const GdkRGBA white = { 1, 1, 1, 1 };
static const GdkRGBA transparent = { 0, 0, 0, 0 };
+typedef enum {
+ E_WEBKIT_EDITOR_STYLE_NONE = 0,
+ E_WEBKIT_EDITOR_STYLE_IS_BOLD = 1 << 0,
+ E_WEBKIT_EDITOR_STYLE_IS_ITALIC = 1 << 1,
+ E_WEBKIT_EDITOR_STYLE_IS_UNDERLINE = 1 << 2,
+ E_WEBKIT_EDITOR_STYLE_IS_STRIKETHROUGH = 1 << 3,
+ E_WEBKIT_EDITOR_STYLE_IS_SUBSCRIPT = 1 << 4,
+ E_WEBKIT_EDITOR_STYLE_IS_SUPERSCRIPT = 1 << 5
+} EWebKitEditorStyleFlags;
+
typedef void (*PostReloadOperationFunc) (EWebKitEditor *wk_editor, gpointer data,
EContentEditorInsertContentFlags flags);
typedef struct {
@@ -166,27 +182,436 @@ typedef struct {
GDestroyNotify data_free_func;
} PostReloadOperation;
-static void e_webkit_editor_set_web_extension_proxy (EWebKitEditor *wk_editor, GDBusProxy *proxy);
static void e_webkit_editor_content_editor_init (EContentEditorInterface *iface);
+static void e_webkit_editor_cid_resolver_init (ECidResolverInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EWebKitEditor, e_webkit_editor, WEBKIT_TYPE_WEB_VIEW,
+ G_IMPLEMENT_INTERFACE (E_TYPE_CONTENT_EDITOR, e_webkit_editor_content_editor_init)
+ G_IMPLEMENT_INTERFACE (E_TYPE_CID_RESOLVER, e_webkit_editor_cid_resolver_init));
+
+typedef struct _EWebKitEditorFlagClass {
+ GObjectClass parent_class;
+} EWebKitEditorFlagClass;
+
+typedef struct _EWebKitEditorFlag {
+ GObject parent;
+ gboolean is_set;
+} EWebKitEditorFlag;
+
+GType e_webkit_editor_flag_get_type (void);
+
+G_DEFINE_TYPE (EWebKitEditorFlag, e_webkit_editor_flag, G_TYPE_OBJECT)
+
+enum {
+ E_WEBKIT_EDITOR_FLAG_FLAGGED,
+ E_WEBKIT_EDITOR_FLAG_LAST_SIGNAL
+};
+
+static guint e_webkit_editor_flag_signals[E_WEBKIT_EDITOR_FLAG_LAST_SIGNAL];
+
+static void
+e_webkit_editor_flag_class_init (EWebKitEditorFlagClass *klass)
+{
+ e_webkit_editor_flag_signals[E_WEBKIT_EDITOR_FLAG_FLAGGED] = g_signal_new (
+ "flagged",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 0,
+ G_TYPE_NONE);
+}
+
+static void
+e_webkit_editor_flag_init (EWebKitEditorFlag *flag)
+{
+ flag->is_set = FALSE;
+}
+
+static void
+e_webkit_editor_flag_set (EWebKitEditorFlag *flag)
+{
+ flag->is_set = TRUE;
+
+ g_signal_emit (flag, e_webkit_editor_flag_signals[E_WEBKIT_EDITOR_FLAG_FLAGGED], 0, NULL);
+}
+
+static JSCValue * /* transfer full */
+webkit_editor_call_jsc_sync (EWebKitEditor *wk_editor,
+ const gchar *script_format,
+ ...) G_GNUC_PRINTF (2, 3);
+
+typedef struct _JSCCallData {
+ EWebKitEditorFlag *flag;
+ gchar *script;
+ JSCValue *result;
+} JSCCallData;
+
+static void
+webkit_editor_jsc_call_done_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ WebKitJavascriptResult *js_result;
+ JSCCallData *jcd = user_data;
+ GError *error = NULL;
+
+ js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (source), result, &error);
+
+ if (error) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
+ (!g_error_matches (error, WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED)
||
+ /* WebKit can return empty error message, thus ignore those. */
+ (error->message && *(error->message))))
+ g_warning ("Failed to call '%s' function: %s:%d: %s", jcd->script, g_quark_to_string
(error->domain), error->code, error->message);
+ g_clear_error (&error);
+ }
+
+ if (js_result) {
+ JSCException *exception;
+ JSCValue *value;
+
+ value = webkit_javascript_result_get_js_value (js_result);
+ exception = jsc_context_get_exception (jsc_value_get_context (value));
+
+ if (exception) {
+ g_warning ("Failed to call '%s': %s", jcd->script, jsc_exception_get_message
(exception));
+ jsc_context_clear_exception (jsc_value_get_context (value));
+ } else if (!jsc_value_is_null (value) && !jsc_value_is_undefined (value)) {
+ jcd->result = g_object_ref (value);
+ }
+
+ webkit_javascript_result_unref (js_result);
+ }
+
+ e_webkit_editor_flag_set (jcd->flag);
+}
+
+static JSCValue * /* transfer full */
+webkit_editor_call_jsc_sync (EWebKitEditor *wk_editor,
+ const gchar *script_format,
+ ...)
+{
+ JSCCallData jcd;
+ va_list va;
+
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), NULL);
+ g_return_val_if_fail (script_format != NULL, NULL);
+
+ va_start (va, script_format);
+ jcd.script = e_web_view_jsc_vprintf_script (script_format, va);
+ va_end (va);
+
+ jcd.flag = g_object_new (e_webkit_editor_flag_get_type (), NULL);
+ jcd.result = NULL;
+
+ webkit_web_view_run_javascript (WEBKIT_WEB_VIEW (wk_editor), jcd.script, wk_editor->priv->cancellable,
+ webkit_editor_jsc_call_done_cb, &jcd);
+
+ if (!jcd.flag->is_set) {
+ GMainLoop *loop;
+ gulong handler_id;
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ handler_id = g_signal_connect_swapped (jcd.flag, "flagged", G_CALLBACK (g_main_loop_quit),
loop);
+
+ g_main_loop_run (loop);
+ g_main_loop_unref (loop);
+
+ g_signal_handler_disconnect (jcd.flag, handler_id);
+ }
+
+ g_clear_object (&jcd.flag);
+ g_free (jcd.script);
+
+ return jcd.result;
+}
+
+static gboolean
+webkit_editor_extract_and_free_jsc_boolean (JSCValue *jsc_value,
+ gboolean default_value)
+{
+ gboolean value;
+
+ if (jsc_value && jsc_value_is_boolean (jsc_value))
+ value = jsc_value_to_boolean (jsc_value);
+ else
+ value = default_value;
+
+ g_clear_object (&jsc_value);
+
+ return value;
+}
+
+static gint32
+webkit_editor_extract_and_free_jsc_int32 (JSCValue *jsc_value,
+ gint32 default_value)
+{
+ gint32 value;
+
+ if (jsc_value && jsc_value_is_number (jsc_value))
+ value = jsc_value_to_int32 (jsc_value);
+ else
+ value = default_value;
+
+ g_clear_object (&jsc_value);
+
+ return value;
+}
+
+static gchar *
+webkit_editor_extract_and_free_jsc_string (JSCValue *jsc_value,
+ const gchar *default_value)
+{
+ gchar *value;
+
+ if (jsc_value && jsc_value_is_string (jsc_value))
+ value = jsc_value_to_string (jsc_value);
+ else
+ value = g_strdup (default_value);
+
+ g_clear_object (&jsc_value);
+
+ return value;
+}
+
+static const gchar *
+webkit_editor_utils_int_to_string (gchar *inout_buff,
+ gulong buff_len,
+ gint value)
+{
+ g_snprintf (inout_buff, buff_len, "%d", value);
+
+ return inout_buff;
+}
+
+static const gchar *
+webkit_editor_utils_int_with_unit_to_string (gchar *inout_buff,
+ gulong buff_len,
+ gint value,
+ EContentEditorUnit unit)
+{
+ if (unit == E_CONTENT_EDITOR_UNIT_AUTO)
+ g_snprintf (inout_buff, buff_len, "auto");
+ else
+ g_snprintf (inout_buff, buff_len, "%d%s",
+ value,
+ (unit == E_CONTENT_EDITOR_UNIT_PIXEL) ? "px" : "%");
+
+ return inout_buff;
+}
+
+static const gchar *
+webkit_editor_utils_color_to_string (gchar *inout_buff,
+ gulong buff_len,
+ const GdkRGBA *color)
+{
+ if (color && color->alpha > 1e-9)
+ g_snprintf (inout_buff, buff_len, "#%06x", e_rgba_to_value (color));
+ else if (buff_len)
+ inout_buff[0] = '\0';
+
+ return inout_buff;
+}
+
+static void
+webkit_editor_dialog_utils_set_attribute (EWebKitEditor *wk_editor,
+ const gchar *selector,
+ const gchar *name,
+ const gchar *value)
+{
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+ g_return_if_fail (name != NULL);
+
+ if (value) {
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.DialogUtilsSetAttribute(%s, %s, %s);",
+ selector, name, value);
+ } else {
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.DialogUtilsSetAttribute(%s, %s, null);",
+ selector, name);
+ }
+}
+
+static void
+webkit_editor_dialog_utils_set_attribute_int (EWebKitEditor *wk_editor,
+ const gchar *selector,
+ const gchar *name,
+ gint value)
+{
+ gchar str_value[64];
+
+ webkit_editor_dialog_utils_set_attribute (wk_editor, selector, name,
+ webkit_editor_utils_int_to_string (str_value, sizeof (str_value), value));
+}
+
+static void
+webkit_editor_dialog_utils_set_attribute_with_unit (EWebKitEditor *wk_editor,
+ const gchar *selector,
+ const gchar *name,
+ gint value,
+ EContentEditorUnit unit)
+{
+ gchar str_value[64];
+
+ webkit_editor_dialog_utils_set_attribute (wk_editor, selector, name,
+ webkit_editor_utils_int_with_unit_to_string (str_value, sizeof (str_value), value, unit));
+}
+
+static void
+webkit_editor_dialog_utils_set_attribute_color (EWebKitEditor *wk_editor,
+ const gchar *selector,
+ const gchar *name,
+ const GdkRGBA *color)
+{
+ gchar str_value[64];
+
+ webkit_editor_dialog_utils_set_attribute (wk_editor, selector, name,
+ webkit_editor_utils_color_to_string (str_value, sizeof (str_value), color));
+}
+
+static void
+webkit_editor_dialog_utils_set_table_attribute (EWebKitEditor *wk_editor,
+ EContentEditorScope scope,
+ const gchar *name,
+ const gchar *value)
+{
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+ g_return_if_fail (name != NULL);
+
+ if (value) {
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.DialogUtilsTableSetAttribute(%d, %s, %s);",
+ scope, name, value);
+ } else {
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.DialogUtilsTableSetAttribute(%d, %s, null);",
+ scope, name);
+ }
+}
+
+static gchar *
+webkit_editor_dialog_utils_get_attribute (EWebKitEditor *wk_editor,
+ const gchar *selector,
+ const gchar *name)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ return webkit_editor_extract_and_free_jsc_string (
+ webkit_editor_call_jsc_sync (wk_editor,
+ "EvoEditor.DialogUtilsGetAttribute(%s, %s);",
+ selector, name),
+ NULL);
+}
+
+static gint
+webkit_editor_dialog_utils_get_attribute_int (EWebKitEditor *wk_editor,
+ const gchar *selector,
+ const gchar *name,
+ gint default_value)
+{
+ gchar *attr;
+ gint value;
+
+ attr = webkit_editor_dialog_utils_get_attribute (wk_editor, selector, name);
+
+ if (attr && *attr)
+ value = atoi (attr);
+ else
+ value = default_value;
+
+ g_free (attr);
+
+ return value;
+}
+
+static gint
+webkit_editor_dialog_utils_get_attribute_with_unit (EWebKitEditor *wk_editor,
+ const gchar *selector,
+ const gchar *name,
+ gint default_value,
+ EContentEditorUnit *out_unit)
+{
+ gint result;
+ gchar *value;
-G_DEFINE_TYPE_WITH_CODE (
- EWebKitEditor,
- e_webkit_editor,
- WEBKIT_TYPE_WEB_VIEW,
- G_IMPLEMENT_INTERFACE (
- E_TYPE_CONTENT_EDITOR,
- e_webkit_editor_content_editor_init));
+ *out_unit = E_CONTENT_EDITOR_UNIT_AUTO;
-static gint16
-e_webkit_editor_three_state_to_int16 (EThreeState value)
+ if (!wk_editor->priv->html_mode)
+ return default_value;
+
+ value = webkit_editor_dialog_utils_get_attribute (wk_editor, selector, name);
+
+ if (value && *value) {
+ result = atoi (value);
+
+ if (strstr (value, "%"))
+ *out_unit = E_CONTENT_EDITOR_UNIT_PERCENTAGE;
+ else if (g_ascii_strncasecmp (value, "auto", 4) != 0)
+ *out_unit = E_CONTENT_EDITOR_UNIT_PIXEL;
+ } else {
+ result = default_value;
+ }
+
+ g_free (value);
+
+ return result;
+}
+
+static void
+webkit_editor_dialog_utils_get_attribute_color (EWebKitEditor *wk_editor,
+ const gchar *selector,
+ const gchar *name,
+ GdkRGBA *out_color)
+{
+ gchar *value;
+
+ value = webkit_editor_dialog_utils_get_attribute (wk_editor, selector, name);
+
+ if (!value || !*value || !gdk_rgba_parse (out_color, value))
+ *out_color = transparent;
+
+ g_free (value);
+}
+
+static gboolean
+webkit_editor_dialog_utils_has_attribute (EWebKitEditor *wk_editor,
+ const gchar *name)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ return webkit_editor_extract_and_free_jsc_boolean (
+ webkit_editor_call_jsc_sync (wk_editor,
+ "EvoEditor.DialogUtilsHasAttribute(%s);",
+ name),
+ FALSE);
+}
+
+static gboolean
+e_webkit_editor_three_state_to_bool (EThreeState value,
+ const gchar *mail_key)
{
+ gboolean res = FALSE;
+
if (value == E_THREE_STATE_ON)
- return 1;
+ return TRUE;
if (value == E_THREE_STATE_OFF)
- return 0;
+ return FALSE;
- return -1;
+ if (mail_key && *mail_key) {
+ GSettings *settings;
+
+ settings = e_util_ref_settings ("org.gnome.evolution.mail");
+ res = g_settings_get_boolean (settings, mail_key);
+ g_clear_object (&settings);
+ }
+
+ return res;
}
EWebKitEditor *
@@ -215,21 +640,6 @@ webkit_editor_get_last_error (EWebKitEditor *wk_editor)
return wk_editor->priv->last_error;
}
-static void
-webkit_editor_can_paste_cb (WebKitWebView *view,
- GAsyncResult *result,
- EWebKitEditor *wk_editor)
-{
- gboolean value;
-
- value = webkit_web_view_can_execute_editing_command_finish (view, result, NULL);
-
- if (wk_editor->priv->can_paste != value) {
- wk_editor->priv->can_paste = value;
- g_object_notify (G_OBJECT (wk_editor), "can-paste");
- }
-}
-
static gboolean
webkit_editor_can_paste (EWebKitEditor *wk_editor)
{
@@ -238,21 +648,6 @@ webkit_editor_can_paste (EWebKitEditor *wk_editor)
return wk_editor->priv->can_paste;
}
-static void
-webkit_editor_can_cut_cb (WebKitWebView *view,
- GAsyncResult *result,
- EWebKitEditor *wk_editor)
-{
- gboolean value;
-
- value = webkit_web_view_can_execute_editing_command_finish (view, result, NULL);
-
- if (wk_editor->priv->can_cut != value) {
- wk_editor->priv->can_cut = value;
- g_object_notify (G_OBJECT (wk_editor), "can-cut");
- }
-}
-
static gboolean
webkit_editor_can_cut (EWebKitEditor *wk_editor)
{
@@ -261,26 +656,6 @@ webkit_editor_can_cut (EWebKitEditor *wk_editor)
return wk_editor->priv->can_cut;
}
-static void
-webkit_editor_can_copy_cb (WebKitWebView *view,
- GAsyncResult *result,
- EWebKitEditor *wk_editor)
-{
- gboolean value;
-
- value = webkit_web_view_can_execute_editing_command_finish (view, result, NULL);
-
- if (wk_editor->priv->can_copy != value) {
- wk_editor->priv->can_copy = value;
- /* This means that we have an active selection thus the primary
- * clipboard content is from composer. */
- if (value)
- wk_editor->priv->copy_paste_primary_in_view = TRUE;
- /* FIXME notify web extension about pasting content from itself */
- g_object_notify (G_OBJECT (wk_editor), "can-copy");
- }
-}
-
static gboolean
webkit_editor_is_malfunction (EWebKitEditor *wk_editor)
{
@@ -351,470 +726,373 @@ webkit_editor_set_can_redo (EWebKitEditor *wk_editor,
}
static void
-web_extension_content_changed_cb (GDBusConnection *connection,
- const gchar *sender_name,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *signal_name,
- GVariant *parameters,
- EWebKitEditor *wk_editor)
+content_changed_cb (WebKitUserContentManager *manager,
+ WebKitJavascriptResult *js_result,
+ gpointer user_data)
{
- if (g_strcmp0 (signal_name, "ContentChanged") != 0)
- return;
-
- if (parameters) {
- guint64 page_id = 0;
+ EWebKitEditor *wk_editor = user_data;
- g_variant_get (parameters, "(t)", &page_id);
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
- if (page_id == webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (wk_editor)))
- webkit_editor_set_changed (wk_editor, TRUE);
- }
+ webkit_editor_set_changed (wk_editor, TRUE);
}
static void
-web_extension_selection_changed_cb (GDBusConnection *connection,
- const gchar *sender_name,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *signal_name,
- GVariant *parameters,
- EWebKitEditor *wk_editor)
+context_menu_requested_cb (WebKitUserContentManager *manager,
+ WebKitJavascriptResult *js_result,
+ gpointer user_data)
{
- guint64 page_id = 0;
- gchar *font_color = NULL;
- guint32 alignment, block_format, style_flags, font_size;
- gboolean is_indented;
+ EWebKitEditor *wk_editor = user_data;
+ JSCValue *jsc_params;
- if (g_strcmp0 (signal_name, "SelectionChanged") != 0)
- return;
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+ g_return_if_fail (js_result != NULL);
- if (!parameters)
- return;
+ jsc_params = webkit_javascript_result_get_js_value (js_result);
+ g_return_if_fail (jsc_value_is_object (jsc_params));
- g_variant_get (
- parameters,
- "(tiibiis)",
- &page_id,
- &alignment,
- &block_format,
- &is_indented,
- &style_flags,
- &font_size,
- &font_color);
-
- if (page_id != webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (wk_editor))) {
- g_free (font_color);
- return;
- }
+ g_clear_pointer (&wk_editor->priv->context_menu_caret_word, g_free);
- webkit_web_view_can_execute_editing_command (
- WEBKIT_WEB_VIEW (wk_editor),
- WEBKIT_EDITING_COMMAND_COPY,
- NULL, /* cancellable */
- (GAsyncReadyCallback) webkit_editor_can_copy_cb,
- wk_editor);
-
- webkit_web_view_can_execute_editing_command (
- WEBKIT_WEB_VIEW (wk_editor),
- WEBKIT_EDITING_COMMAND_CUT,
- NULL, /* cancellable */
- (GAsyncReadyCallback) webkit_editor_can_cut_cb,
- wk_editor);
-
- webkit_web_view_can_execute_editing_command (
- WEBKIT_WEB_VIEW (wk_editor),
- WEBKIT_EDITING_COMMAND_PASTE,
- NULL, /* cancellable */
- (GAsyncReadyCallback) webkit_editor_can_paste_cb,
- wk_editor);
-
- g_object_freeze_notify (G_OBJECT (wk_editor));
-
- wk_editor->priv->alignment = alignment;
- wk_editor->priv->block_format = block_format;
- wk_editor->priv->is_indented = is_indented;
- wk_editor->priv->style_flags = style_flags;
- wk_editor->priv->font_size = font_size;
+ wk_editor->priv->context_menu_node_flags = e_web_view_jsc_get_object_property_int32 (jsc_params,
"nodeFlags", 0);
+ wk_editor->priv->context_menu_caret_word = e_web_view_jsc_get_object_property_string (jsc_params,
"caretWord", NULL);
+}
- if (wk_editor->priv->html_mode) {
- GdkRGBA color;
+static gboolean
+webkit_editor_update_color_value (JSCValue *jsc_params,
+ const gchar *param_name,
+ GdkRGBA **out_rgba)
+{
+ JSCValue *jsc_value;
+ GdkRGBA color;
+ gboolean res = FALSE;
- if (font_color && *font_color && gdk_rgba_parse (&color, font_color)) {
- if (wk_editor->priv->font_color)
- gdk_rgba_free (wk_editor->priv->font_color);
- wk_editor->priv->font_color = gdk_rgba_copy (&color);
- }
- }
- g_free (font_color);
+ g_return_val_if_fail (jsc_params != NULL, FALSE);
+ g_return_val_if_fail (out_rgba != NULL, FALSE);
- g_object_notify (G_OBJECT (wk_editor), "can-undo");
- g_object_notify (G_OBJECT (wk_editor), "can-redo");
+ jsc_value = jsc_value_object_get_property (jsc_params, param_name);
+ if (jsc_value && jsc_value_is_string (jsc_value)) {
+ gchar *value;
- g_object_notify (G_OBJECT (wk_editor), "alignment");
- g_object_notify (G_OBJECT (wk_editor), "block-format");
- g_object_notify (G_OBJECT (wk_editor), "indented");
+ value = jsc_value_to_string (jsc_value);
- if (wk_editor->priv->html_mode) {
- /* g_object_notify (G_OBJECT (wk_editor), "background-color"); */
- g_object_notify (G_OBJECT (wk_editor), "bold");
- /* g_object_notify (G_OBJECT (wk_editor), "font-name"); */
- g_object_notify (G_OBJECT (wk_editor), "font-size");
- g_object_notify (G_OBJECT (wk_editor), "font-color");
- g_object_notify (G_OBJECT (wk_editor), "italic");
- g_object_notify (G_OBJECT (wk_editor), "monospaced");
- g_object_notify (G_OBJECT (wk_editor), "strikethrough");
- g_object_notify (G_OBJECT (wk_editor), "subscript");
- g_object_notify (G_OBJECT (wk_editor), "superscript");
- g_object_notify (G_OBJECT (wk_editor), "underline");
- }
+ if (value && *value && gdk_rgba_parse (&color, value)) {
+ if (!(*out_rgba) || !gdk_rgba_equal (&color, *out_rgba)) {
+ if (*out_rgba)
+ gdk_rgba_free (*out_rgba);
+ *out_rgba = gdk_rgba_copy (&color);
- g_object_thaw_notify (G_OBJECT (wk_editor));
-}
+ res = TRUE;
+ }
+ } else {
+ if (*out_rgba) {
+ gdk_rgba_free (*out_rgba);
+ res = TRUE;
+ }
-static void
-web_extension_undo_redo_state_changed_cb (GDBusConnection *connection,
- const gchar *sender_name,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *signal_name,
- GVariant *parameters,
- EWebKitEditor *wk_editor)
-{
- guint64 page_id = 0;
- gboolean can_undo = FALSE, can_redo = FALSE;
+ *out_rgba = NULL;
+ }
- if (g_strcmp0 (signal_name, "UndoRedoStateChanged") != 0)
- return;
+ g_free (value);
+ }
- g_variant_get (parameters, "(tbb)", &page_id, &can_undo, &can_redo);
+ g_clear_object (&jsc_value);
- if (page_id == webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (wk_editor))) {
- webkit_editor_set_can_undo (wk_editor, can_undo);
- webkit_editor_set_can_redo (wk_editor, can_redo);
- }
+ return res;
}
+static void webkit_editor_update_styles (EContentEditor *editor);
+static void webkit_editor_style_updated (EWebKitEditor *wk_editor, gboolean force);
+
static void
-web_extension_user_changed_default_colors_cb (GDBusConnection *connection,
- const gchar *sender_name,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *signal_name,
- GVariant *parameters,
- EWebKitEditor *wk_editor)
+formatting_changed_cb (WebKitUserContentManager *manager,
+ WebKitJavascriptResult *js_result,
+ gpointer user_data)
{
- if (g_strcmp0 (signal_name, "UserChangedDefaultColors") != 0)
- return;
+ EWebKitEditor *wk_editor = user_data;
+ JSCValue *jsc_params, *jsc_value;
+ GObject *object;
+ gboolean changed, forced = FALSE;
- if (parameters)
- g_variant_get (parameters, "(b)", &wk_editor->priv->suppress_color_changes);
-}
-
-static void
-dispatch_pending_operations (EWebKitEditor *wk_editor)
-{
- if (wk_editor->priv->webkit_load_event != WEBKIT_LOAD_FINISHED ||
- !wk_editor->priv->web_extension_proxy)
- return;
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
- /* Dispatch queued operations - as we are using this just for load
- * operations load just the latest request and throw away the rest. */
- if (wk_editor->priv->post_reload_operations &&
- !g_queue_is_empty (wk_editor->priv->post_reload_operations)) {
+ jsc_params = webkit_javascript_result_get_js_value (js_result);
+ g_return_if_fail (jsc_value_is_object (jsc_params));
- PostReloadOperation *op;
+ object = G_OBJECT (wk_editor);
- op = g_queue_pop_head (wk_editor->priv->post_reload_operations);
+ g_object_freeze_notify (object);
- op->func (wk_editor, op->data, op->flags);
+ jsc_value = jsc_value_object_get_property (jsc_params, "forced");
+ if (jsc_value && jsc_value_is_boolean (jsc_value)) {
+ forced = jsc_value_to_boolean (jsc_value);
+ }
+ g_clear_object (&jsc_value);
- if (op->data_free_func)
- op->data_free_func (op->data);
- g_free (op);
+ changed = FALSE;
+ jsc_value = jsc_value_object_get_property (jsc_params, "mode");
+ if (jsc_value && jsc_value_is_number (jsc_value)) {
+ gint value = jsc_value_to_int32 (jsc_value);
- while ((op = g_queue_pop_head (wk_editor->priv->post_reload_operations))) {
- if (op->data_free_func)
- op->data_free_func (op->data);
- g_free (op);
+ if ((value ? 1 : 0) != (wk_editor->priv->html_mode ? 1 : 0)) {
+ wk_editor->priv->html_mode = value;
+ changed = TRUE;
}
-
- g_queue_clear (wk_editor->priv->post_reload_operations);
}
-}
+ g_clear_object (&jsc_value);
-static void
-e_webkit_editor_page_proxy_changed_cb (EWebExtensionContainer *container,
- guint64 page_id,
- gint stamp,
- GDBusProxy *proxy,
- gpointer user_data)
-{
- EWebKitEditor *wk_editor = user_data;
-
- g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+ if (changed) {
+ /* Update fonts - in plain text we only want monospaced */
+ webkit_editor_update_styles (E_CONTENT_EDITOR (wk_editor));
+ webkit_editor_style_updated (wk_editor, FALSE);
- if (stamp == wk_editor->priv->stamp &&
- page_id == webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (wk_editor))) {
- e_webkit_editor_set_web_extension_proxy (wk_editor, proxy);
+ g_object_notify (object, "html-mode");
+ }
- if (proxy) {
- dispatch_pending_operations (wk_editor);
+ changed = FALSE;
+ jsc_value = jsc_value_object_get_property (jsc_params, "alignment");
+ if (jsc_value && jsc_value_is_number (jsc_value)) {
+ gint value = jsc_value_to_int32 (jsc_value);
- if (wk_editor->priv->emit_load_finished_when_extension_is_ready) {
- e_content_editor_emit_load_finished (E_CONTENT_EDITOR (wk_editor));
+ if (value != wk_editor->priv->alignment) {
+ wk_editor->priv->alignment = value;
+ changed = TRUE;
+ }
+ }
+ g_clear_object (&jsc_value);
- wk_editor->priv->emit_load_finished_when_extension_is_ready = FALSE;
- }
+ if (changed || forced)
+ g_object_notify (object, "alignment");
- g_object_notify (G_OBJECT (wk_editor), "web-extension");
+ changed = FALSE;
+ jsc_value = jsc_value_object_get_property (jsc_params, "blockFormat");
+ if (jsc_value && jsc_value_is_number (jsc_value)) {
+ gint value = jsc_value_to_int32 (jsc_value);
- if (wk_editor->priv->initialized_callback) {
- EContentEditorInitializedCallback initialized_callback;
- gpointer initialized_user_data;
+ if (value != wk_editor->priv->block_format) {
+ wk_editor->priv->block_format = value;
+ changed = TRUE;
+ }
+ }
+ g_clear_object (&jsc_value);
- initialized_callback = wk_editor->priv->initialized_callback;
- initialized_user_data = wk_editor->priv->initialized_user_data;
+ if (changed || forced)
+ g_object_notify (object, "block-format");
- wk_editor->priv->initialized_callback = NULL;
- wk_editor->priv->initialized_user_data = NULL;
+ changed = FALSE;
+ jsc_value = jsc_value_object_get_property (jsc_params, "indentLevel");
+ if (jsc_value && jsc_value_is_number (jsc_value)) {
+ gint value = jsc_value_to_int32 (jsc_value);
- initialized_callback (E_CONTENT_EDITOR (wk_editor), initialized_user_data);
- }
+ if (value != wk_editor->priv->indent_level) {
+ wk_editor->priv->indent_level = value;
+ changed = TRUE;
}
}
-}
+ g_clear_object (&jsc_value);
-static void
-e_webkit_editor_set_web_extension_proxy (EWebKitEditor *wk_editor,
- GDBusProxy *proxy)
-{
- g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+ if (changed || forced)
+ g_object_notify (object, "indent-level");
- if (wk_editor->priv->web_extension_proxy) {
- GDBusConnection *connection;
+ #define update_style_flag(_flag, _set) \
+ changed = (wk_editor->priv->style_flags & (_flag)) != ((_set) ? (_flag) : 0); \
+ wk_editor->priv->style_flags = (wk_editor->priv->style_flags & ~(_flag)) | ((_set) ? (_flag)
: 0);
- connection = g_dbus_proxy_get_connection (wk_editor->priv->web_extension_proxy);
+ changed = FALSE;
+ jsc_value = jsc_value_object_get_property (jsc_params, "bold");
+ if (jsc_value && jsc_value_is_boolean (jsc_value)) {
+ gboolean value = jsc_value_to_boolean (jsc_value);
- if (connection && g_dbus_connection_is_closed (connection))
- connection = NULL;
+ update_style_flag (E_WEBKIT_EDITOR_STYLE_IS_BOLD, value);
+ }
+ g_clear_object (&jsc_value);
- if (wk_editor->priv->web_extension_content_changed_cb_id) {
- if (connection)
- g_dbus_connection_signal_unsubscribe (connection,
wk_editor->priv->web_extension_content_changed_cb_id);
- wk_editor->priv->web_extension_content_changed_cb_id = 0;
- }
+ if (changed || forced)
+ g_object_notify (G_OBJECT (wk_editor), "bold");
- if (wk_editor->priv->web_extension_selection_changed_cb_id) {
- if (connection)
- g_dbus_connection_signal_unsubscribe (connection,
wk_editor->priv->web_extension_selection_changed_cb_id);
- wk_editor->priv->web_extension_selection_changed_cb_id = 0;
- }
+ changed = FALSE;
+ jsc_value = jsc_value_object_get_property (jsc_params, "italic");
+ if (jsc_value && jsc_value_is_boolean (jsc_value)) {
+ gboolean value = jsc_value_to_boolean (jsc_value);
- if (wk_editor->priv->web_extension_undo_redo_state_changed_cb_id) {
- if (connection)
- g_dbus_connection_signal_unsubscribe (connection,
wk_editor->priv->web_extension_undo_redo_state_changed_cb_id);
- wk_editor->priv->web_extension_undo_redo_state_changed_cb_id = 0;
- }
+ update_style_flag (E_WEBKIT_EDITOR_STYLE_IS_ITALIC, value);
+ }
+ g_clear_object (&jsc_value);
- if (wk_editor->priv->web_extension_user_changed_default_colors_cb_id) {
- if (connection)
- g_dbus_connection_signal_unsubscribe (connection,
wk_editor->priv->web_extension_user_changed_default_colors_cb_id);
- wk_editor->priv->web_extension_user_changed_default_colors_cb_id = 0;
- }
+ if (changed || forced)
+ g_object_notify (G_OBJECT (wk_editor), "italic");
+
+ changed = FALSE;
+ jsc_value = jsc_value_object_get_property (jsc_params, "underline");
+ if (jsc_value && jsc_value_is_boolean (jsc_value)) {
+ gboolean value = jsc_value_to_boolean (jsc_value);
- g_clear_object (&wk_editor->priv->web_extension_proxy);
+ update_style_flag (E_WEBKIT_EDITOR_STYLE_IS_UNDERLINE, value);
}
+ g_clear_object (&jsc_value);
+
+ if (changed || forced)
+ g_object_notify (G_OBJECT (wk_editor), "underline");
- if (proxy) {
- wk_editor->priv->web_extension_proxy = g_object_ref (proxy);
-
- wk_editor->priv->web_extension_selection_changed_cb_id =
- g_dbus_connection_signal_subscribe (
- g_dbus_proxy_get_connection (wk_editor->priv->web_extension_proxy),
- g_dbus_proxy_get_name (wk_editor->priv->web_extension_proxy),
- E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE,
- "SelectionChanged",
- E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
- NULL,
- G_DBUS_SIGNAL_FLAGS_NONE,
- (GDBusSignalCallback) web_extension_selection_changed_cb,
- wk_editor,
- NULL);
-
- wk_editor->priv->web_extension_content_changed_cb_id =
- g_dbus_connection_signal_subscribe (
- g_dbus_proxy_get_connection (wk_editor->priv->web_extension_proxy),
- g_dbus_proxy_get_name (wk_editor->priv->web_extension_proxy),
- E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE,
- "ContentChanged",
- E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
- NULL,
- G_DBUS_SIGNAL_FLAGS_NONE,
- (GDBusSignalCallback) web_extension_content_changed_cb,
- wk_editor,
- NULL);
-
- wk_editor->priv->web_extension_undo_redo_state_changed_cb_id =
- g_dbus_connection_signal_subscribe (
- g_dbus_proxy_get_connection (wk_editor->priv->web_extension_proxy),
- g_dbus_proxy_get_name (wk_editor->priv->web_extension_proxy),
- E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE,
- "UndoRedoStateChanged",
- E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
- NULL,
- G_DBUS_SIGNAL_FLAGS_NONE,
- (GDBusSignalCallback) web_extension_undo_redo_state_changed_cb,
- wk_editor,
- NULL);
-
- wk_editor->priv->web_extension_user_changed_default_colors_cb_id =
- g_dbus_connection_signal_subscribe (
- g_dbus_proxy_get_connection (wk_editor->priv->web_extension_proxy),
- g_dbus_proxy_get_name (wk_editor->priv->web_extension_proxy),
- E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE,
- "UserChangedDefaultColors",
- E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
- NULL,
- G_DBUS_SIGNAL_FLAGS_NONE,
- (GDBusSignalCallback) web_extension_user_changed_default_colors_cb,
- wk_editor,
- NULL);
+ changed = FALSE;
+ jsc_value = jsc_value_object_get_property (jsc_params, "strikethrough");
+ if (jsc_value && jsc_value_is_boolean (jsc_value)) {
+ gboolean value = jsc_value_to_boolean (jsc_value);
+
+ update_style_flag (E_WEBKIT_EDITOR_STYLE_IS_STRIKETHROUGH, value);
}
-}
+ g_clear_object (&jsc_value);
-static guint64
-current_page_id (EWebKitEditor *wk_editor)
-{
- return webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (wk_editor));
-}
+ if (changed || forced)
+ g_object_notify (G_OBJECT (wk_editor), "strikethrough");
-static void
-webkit_editor_call_simple_extension_function_sync (EWebKitEditor *wk_editor,
- const gchar *method_name)
-{
- GVariant *result;
+ jsc_value = jsc_value_object_get_property (jsc_params, "script");
+ if (jsc_value && jsc_value_is_number (jsc_value)) {
+ gint value = jsc_value_to_int32 (jsc_value);
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
+ changed = FALSE;
+ update_style_flag (E_WEBKIT_EDITOR_STYLE_IS_SUBSCRIPT, value < 0);
+
+ if (changed || forced)
+ g_object_notify (object, "subscript");
+
+ changed = FALSE;
+ update_style_flag (E_WEBKIT_EDITOR_STYLE_IS_SUPERSCRIPT, value > 0);
+
+ if (changed || forced)
+ g_object_notify (object, "superscript");
+ } else if (forced) {
+ g_object_notify (object, "subscript");
+ g_object_notify (object, "superscript");
}
+ g_clear_object (&jsc_value);
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- method_name,
- g_variant_new ("(t)", current_page_id (wk_editor)),
- NULL);
+ wk_editor->priv->temporary_style_flags = wk_editor->priv->style_flags;
- if (result)
- g_variant_unref (result);
-}
+ #undef update_style_flag
-static void
-webkit_editor_call_simple_extension_function (EWebKitEditor *wk_editor,
- const gchar *method_name)
-{
- guint64 page_id;
+ changed = FALSE;
+ jsc_value = jsc_value_object_get_property (jsc_params, "fontSize");
+ if (jsc_value && jsc_value_is_number (jsc_value)) {
+ gint value = jsc_value_to_int32 (jsc_value);
- page_id = current_page_id (wk_editor);
+ if (value != wk_editor->priv->font_size) {
+ wk_editor->priv->font_size = value;
+ changed = TRUE;
+ }
+ }
+ g_clear_object (&jsc_value);
- e_web_extension_container_call_simple (wk_editor->priv->container, page_id, wk_editor->priv->stamp,
- method_name, g_variant_new ("(t)", page_id));
-}
+ if (changed || forced)
+ g_object_notify (object, "font-size");
-static GVariant *
-webkit_editor_get_element_attribute (EWebKitEditor *wk_editor,
- const gchar *selector,
- const gchar *attribute)
-{
- GVariant *result;
+ changed = FALSE;
+ jsc_value = jsc_value_object_get_property (jsc_params, "fontFamily");
+ if (jsc_value && jsc_value_is_string (jsc_value)) {
+ gchar *value = jsc_value_to_string (jsc_value);
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return NULL;
+ if (g_strcmp0 (value, wk_editor->priv->font_name) != 0) {
+ g_free (wk_editor->priv->font_name);
+ wk_editor->priv->font_name = value;
+ changed = TRUE;
+ } else {
+ g_free (value);
+ }
}
+ g_clear_object (&jsc_value);
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "ElementGetAttributeBySelector",
- g_variant_new ("(tss)", current_page_id (wk_editor), selector, attribute),
- NULL);
+ if (changed || forced)
+ g_object_notify (object, "font-name");
- return result;
-}
+ jsc_value = jsc_value_object_get_property (jsc_params, "bodyFontFamily");
+ if (jsc_value && jsc_value_is_string (jsc_value)) {
+ gchar *value = jsc_value_to_string (jsc_value);
-static void
-webkit_editor_set_element_attribute (EWebKitEditor *wk_editor,
- const gchar *selector,
- const gchar *attribute,
- const gchar *value)
-{
- guint64 page_id;
+ if (g_strcmp0 (value, wk_editor->priv->body_font_name) != 0) {
+ g_free (wk_editor->priv->body_font_name);
+ wk_editor->priv->body_font_name = value;
+ } else {
+ g_free (value);
+ }
+ }
+ g_clear_object (&jsc_value);
+
+ if (webkit_editor_update_color_value (jsc_params, "fgColor", &wk_editor->priv->font_color) || forced)
+ g_object_notify (object, "font-color");
+
+ if (webkit_editor_update_color_value (jsc_params, "bgColor", &wk_editor->priv->background_color) ||
forced)
+ g_object_notify (object, "background-color");
- page_id = current_page_id (wk_editor);
+ webkit_editor_update_color_value (jsc_params, "bodyFgColor", &wk_editor->priv->body_fg_color);
+ webkit_editor_update_color_value (jsc_params, "bodyBgColor", &wk_editor->priv->body_bg_color);
+ webkit_editor_update_color_value (jsc_params, "bodyLinkColor", &wk_editor->priv->body_link_color);
+ webkit_editor_update_color_value (jsc_params, "bodyVlinkColor", &wk_editor->priv->body_vlink_color);
- e_web_extension_container_call_simple (wk_editor->priv->container, page_id, wk_editor->priv->stamp,
- "ElementSetAttributeBySelector", g_variant_new ("(tsss)", page_id, selector, attribute,
value));
+ g_object_thaw_notify (object);
}
static void
-webkit_editor_remove_element_attribute (EWebKitEditor *wk_editor,
- const gchar *selector,
- const gchar *attribute)
+selection_changed_cb (WebKitUserContentManager *manager,
+ WebKitJavascriptResult *js_result,
+ gpointer user_data)
{
- guint64 page_id;
+ EWebKitEditor *wk_editor = user_data;
+ WebKitEditorState *editor_state;
+ JSCValue *jsc_value;
+ gboolean is_collapsed;
- page_id = current_page_id (wk_editor);
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
- e_web_extension_container_call_simple (wk_editor->priv->container, page_id, wk_editor->priv->stamp,
- "ElementRemoveAttributeBySelector", g_variant_new ("(tss)", page_id, selector, attribute));
-}
+ jsc_value = webkit_javascript_result_get_js_value (js_result);
+ is_collapsed = jsc_value_is_boolean (jsc_value) && jsc_value_to_boolean (jsc_value);
-static void
-webkit_editor_set_format_boolean (EWebKitEditor *wk_editor,
- const gchar *format_dom_function,
- gboolean format_value)
-{
- guint64 page_id;
+ editor_state = webkit_web_view_get_editor_state (WEBKIT_WEB_VIEW (wk_editor));
- page_id = current_page_id (wk_editor);
+ if (editor_state) {
+ GObject *object = G_OBJECT (wk_editor);
+ gboolean value;
- e_web_extension_container_call_simple (wk_editor->priv->container, page_id, wk_editor->priv->stamp,
- format_dom_function, g_variant_new ("(tb)", page_id, format_value));
-}
+ #define check_and_set_prop(_prop_var, _prop_name, _val) \
+ value = _val; \
+ if (_prop_var != value) { \
+ _prop_var = value; \
+ g_object_notify (object, _prop_name); \
+ }
-static void
-webkit_editor_set_format_int (EWebKitEditor *wk_editor,
- const gchar *format_dom_function,
- gint32 format_value)
-{
- guint64 page_id;
+ g_object_freeze_notify (object);
+
+ check_and_set_prop (wk_editor->priv->can_copy, "can-copy", !is_collapsed);
+ check_and_set_prop (wk_editor->priv->can_cut, "can-cut", !is_collapsed);
+ check_and_set_prop (wk_editor->priv->can_paste, "can-paste",
webkit_editor_state_is_paste_available (editor_state));
- page_id = current_page_id (wk_editor);
+ g_object_thaw_notify (object);
- e_web_extension_container_call_simple (wk_editor->priv->container, page_id, wk_editor->priv->stamp,
- format_dom_function, g_variant_new ("(ti)", page_id, format_value));
+ #undef set_prop
+ }
}
static void
-webkit_editor_set_format_string (EWebKitEditor *wk_editor,
- const gchar *format_name,
- const gchar *format_dom_function,
- const gchar *format_value)
+undu_redo_state_changed_cb (WebKitUserContentManager *manager,
+ WebKitJavascriptResult *js_result,
+ gpointer user_data)
{
- guint64 page_id;
-
- if (!wk_editor->priv->html_mode)
- return;
+ EWebKitEditor *wk_editor = user_data;
+ JSCValue *jsc_value;
+ JSCValue *jsc_params;
+ gint32 state;
- webkit_editor_set_changed (wk_editor, TRUE);
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+ g_return_if_fail (js_result != NULL);
- page_id = current_page_id (wk_editor);
+ jsc_params = webkit_javascript_result_get_js_value (js_result);
+ g_return_if_fail (jsc_value_is_object (jsc_params));
- e_web_extension_container_call_simple (wk_editor->priv->container, page_id, wk_editor->priv->stamp,
- format_dom_function, g_variant_new ("(ts)", page_id, format_value));
+ jsc_value = jsc_value_object_get_property (jsc_params, "state");
+ g_return_if_fail (jsc_value_is_number (jsc_value));
+ state = jsc_value_to_int32 (jsc_value);
+ g_clear_object (&jsc_value);
- g_object_notify (G_OBJECT (wk_editor), format_name);
+ webkit_editor_set_can_undo (wk_editor, (state & E_UNDO_REDO_STATE_CAN_UNDO) != 0);
+ webkit_editor_set_can_redo (wk_editor, (state & E_UNDO_REDO_STATE_CAN_REDO) != 0);
}
static void
@@ -864,7 +1142,7 @@ webkit_editor_initialize (EContentEditor *content_editor,
wk_editor = E_WEBKIT_EDITOR (content_editor);
- if (wk_editor->priv->web_extension_proxy) {
+ if (wk_editor->priv->webkit_load_event == WEBKIT_LOAD_FINISHED) {
callback (content_editor, user_data);
} else {
g_return_if_fail (wk_editor->priv->initialized_callback == NULL);
@@ -1022,36 +1300,6 @@ webkit_editor_update_styles (EContentEditor *editor)
" outline: 1px dotted red;\n"
"}\n");
- g_string_append (
- stylesheet,
- "body[data-evo-plain-text] "
- "{\n"
- " font-family: Monospace; \n"
- "}\n");
-
- g_string_append (
- stylesheet,
- "body[data-evo-plain-text] img.-x-evo-smiley-img, "
- "body:not([data-evo-plain-text]) span.-x-evo-smiley-text "
- "{\n"
- " display: none \n"
- "}\n");
-
- g_string_append (
- stylesheet,
- "[data-evo-paragraph] "
- "{\n"
- " white-space: pre-wrap; \n"
- "}\n");
-
- g_string_append (
- stylesheet,
- "body[data-evo-plain-text] [data-evo-paragraph] "
- "{\n"
- " word-wrap: break-word; \n"
- " word-break: break-word; \n"
- "}\n");
-
g_string_append_printf (
stylesheet,
".-x-evo-plaintext-table "
@@ -1059,7 +1307,7 @@ webkit_editor_update_styles (EContentEditor *editor)
" border-collapse: collapse;\n"
" width: %dch;\n"
"}\n",
- g_settings_get_int (wk_editor->priv->mail_settings, "composer-word-wrap-length"));
+ wk_editor->priv->normal_paragraph_width);
g_string_append (
stylesheet,
@@ -1068,49 +1316,213 @@ webkit_editor_update_styles (EContentEditor *editor)
" vertical-align: top;\n"
"}\n");
- g_string_append_printf (
- stylesheet,
- "body[data-evo-plain-text] ul "
- "{\n"
- " list-style: outside none;\n"
- " -webkit-padding-start: %dch; \n"
- "}\n", SPACES_PER_LIST_LEVEL);
+ if (wk_editor->priv->html_mode) {
+ g_string_append (
+ stylesheet,
+ "body ul > li.-x-evo-align-center,ol > li.-x-evo-align-center "
+ "{\n"
+ " list-style-position: inside;\n"
+ "}\n");
- g_string_append_printf (
- stylesheet,
- "body[data-evo-plain-text] ul > li "
- "{\n"
- " list-style-position: outside;\n"
- " text-indent: -%dch;\n"
- "}\n", SPACES_PER_LIST_LEVEL - 1);
+ g_string_append (
+ stylesheet,
+ "body ul > li.-x-evo-align-right, ol > li.-x-evo-align-right "
+ "{\n"
+ " list-style-position: inside;\n"
+ "}\n");
- g_string_append (
- stylesheet,
- "body[data-evo-plain-text] ul > li::before "
- "{\n"
- " content: \"*"UNICODE_NBSP"\";\n"
- "}\n");
+ g_string_append (
+ stylesheet,
+ "body "
+ "blockquote[type=cite] "
+ "{\n"
+ " padding: 0ch 1ch 0ch 1ch;\n"
+ " margin: 0ch;\n"
+ " border-width: 0px 2px 0px 2px;\n"
+ " border-style: none solid none solid;\n"
+ " border-radius: 2px;\n"
+ "}\n");
- g_string_append_printf (
- stylesheet,
- "body[data-evo-plain-text] ul.-x-evo-indented "
- "{\n"
- " -webkit-padding-start: %dch; \n"
- "}\n", SPACES_PER_LIST_LEVEL);
+ g_string_append_printf (
+ stylesheet,
+ "body "
+ "blockquote[type=cite] "
+ "{\n"
+ " border-color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (1));
- g_string_append (
- stylesheet,
- "body:not([data-evo-plain-text]) ul > li.-x-evo-align-center,ol > li.-x-evo-align-center "
- "{\n"
- " list-style-position: inside;\n"
- "}\n");
+ g_string_append_printf (
+ stylesheet,
+ "body "
+ "blockquote[type=cite] "
+ "blockquote[type=cite] "
+ "{\n"
+ " border-color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (2));
- g_string_append (
- stylesheet,
- "body:not([data-evo-plain-text]) ul > li.-x-evo-align-right, ol > li.-x-evo-align-right "
- "{\n"
- " list-style-position: inside;\n"
- "}\n");
+ g_string_append_printf (
+ stylesheet,
+ "body "
+ "blockquote[type=cite] "
+ "blockquote[type=cite] "
+ "blockquote[type=cite] "
+ "{\n"
+ " border-color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (3));
+
+ g_string_append_printf (
+ stylesheet,
+ "body "
+ "blockquote[type=cite] "
+ "blockquote[type=cite] "
+ "blockquote[type=cite] "
+ "blockquote[type=cite] "
+ "{\n"
+ " border-color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (4));
+
+ g_string_append_printf (
+ stylesheet,
+ "body "
+ "blockquote[type=cite] "
+ "blockquote[type=cite] "
+ "blockquote[type=cite] "
+ "blockquote[type=cite] "
+ "blockquote[type=cite] "
+ "{\n"
+ " border-color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (5));
+ } else {
+ g_string_append (
+ stylesheet,
+ "body "
+ "{\n"
+ " font-family: Monospace; \n"
+ "}\n");
+
+ g_string_append_printf (
+ stylesheet,
+ "body ul "
+ "{\n"
+ " list-style: outside none;\n"
+ " -webkit-padding-start: %dch; \n"
+ "}\n", SPACES_PER_LIST_LEVEL);
+
+ g_string_append_printf (
+ stylesheet,
+ "body ul > li "
+ "{\n"
+ " list-style-position: outside;\n"
+ " text-indent: -%dch;\n"
+ "}\n", SPACES_PER_LIST_LEVEL - 1);
+
+ g_string_append (
+ stylesheet,
+ "body ul > li::before "
+ "{\n"
+ " content: \"*" UNICODE_NBSP "\";\n"
+ "}\n");
+
+ g_string_append (
+ stylesheet,
+ "body ul ul > li::before, "
+ "body ol ul > li::before "
+ "{\n"
+ " content: \"-" UNICODE_NBSP "\";\n"
+ "}\n");
+
+ g_string_append (
+ stylesheet,
+ "body ul ul ul > li::before, "
+ "body ol ul ul > li::before, "
+ "body ul ol ul > li::before, "
+ "body ol ol ul > li::before "
+ "{\n"
+ " content: \"+" UNICODE_NBSP "\";\n"
+ "}\n");
+
+ g_string_append (
+ stylesheet,
+ "body ul ul ul ul > li::before, "
+ "body ol ul ul ul > li::before, "
+ "body ul ol ul ul > li::before, "
+ "body ul ul ol ul > li::before, "
+ "body ol ol ul ul > li::before, "
+ "body ol ul ol ul > li::before, "
+ "body ul ol ol ul > li::before, "
+ "body ol ol ol ul > li::before "
+ "{\n"
+ " content: \"*" UNICODE_NBSP "\";\n"
+ "}\n");
+
+ g_string_append (
+ stylesheet,
+ "body div "
+ "{\n"
+ " word-wrap: break-word; \n"
+ " word-break: break-word; \n"
+ " white-space: pre-wrap; \n"
+ "}\n");
+
+ g_string_append (
+ stylesheet,
+ ".-x-evo-quoted { -webkit-user-select: none; }\n");
+
+ g_string_append_printf (
+ stylesheet,
+ ".-x-evo-quote-character "
+ "{\n"
+ " color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (1));
+
+ g_string_append_printf (
+ stylesheet,
+ ".-x-evo-quote-character+"
+ ".-x-evo-quote-character"
+ "{\n"
+ " color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (2));
+
+ g_string_append_printf (
+ stylesheet,
+ ".-x-evo-quote-character+"
+ ".-x-evo-quote-character+"
+ ".-x-evo-quote-character"
+ "{\n"
+ " color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (3));
+
+ g_string_append_printf (
+ stylesheet,
+ ".-x-evo-quote-character+"
+ ".-x-evo-quote-character+"
+ ".-x-evo-quote-character+"
+ ".-x-evo-quote-character"
+ "{\n"
+ " color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (4));
+
+ g_string_append_printf (
+ stylesheet,
+ ".-x-evo-quote-character+"
+ ".-x-evo-quote-character+"
+ ".-x-evo-quote-character+"
+ ".-x-evo-quote-character+"
+ ".-x-evo-quote-character"
+ "{\n"
+ " color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (5));
+ }
g_string_append_printf (
stylesheet,
@@ -1119,48 +1531,20 @@ webkit_editor_update_styles (EContentEditor *editor)
" -webkit-padding-start: %dch; \n"
"}\n", SPACES_ORDERED_LIST_FIRST_LEVEL);
- g_string_append_printf (
- stylesheet,
- "ol.-x-evo-indented "
- "{\n"
- " -webkit-padding-start: %dch; \n"
- "}\n", SPACES_PER_LIST_LEVEL);
-
- g_string_append (
- stylesheet,
- ".-x-evo-align-left "
- "{\n"
- " text-align: left; \n"
- "}\n");
-
g_string_append (
stylesheet,
- ".-x-evo-align-center "
+ "ol,ul "
"{\n"
- " text-align: center; \n"
+ " -webkit-margin-before: 0em; \n"
+ " -webkit-margin-after: 0em; \n"
"}\n");
g_string_append (
stylesheet,
- ".-x-evo-align-right "
+ "blockquote "
"{\n"
- " text-align: right; \n"
- "}\n");
-
- g_string_append (
- stylesheet,
- "ol,ul "
- "{\n"
- " -webkit-margin-before: 0em; \n"
- " -webkit-margin-after: 0em; \n"
- "}\n");
-
- g_string_append (
- stylesheet,
- "blockquote "
- "{\n"
- " -webkit-margin-before: 0em; \n"
- " -webkit-margin-after: 0em; \n"
+ " -webkit-margin-before: 0em; \n"
+ " -webkit-margin-after: 0em; \n"
"}\n");
if (wk_editor->priv->html_mode) {
@@ -1208,123 +1592,6 @@ webkit_editor_update_styles (EContentEditor *editor)
g_string_append (stylesheet, "}\n");
- g_string_append_printf (
- stylesheet,
- ".-x-evo-quote-character "
- "{\n"
- " color: %s;\n"
- "}\n",
- e_web_view_get_citation_color_for_level (1));
-
- g_string_append_printf (
- stylesheet,
- ".-x-evo-quote-character+"
- ".-x-evo-quote-character"
- "{\n"
- " color: %s;\n"
- "}\n",
- e_web_view_get_citation_color_for_level (2));
-
- g_string_append_printf (
- stylesheet,
- ".-x-evo-quote-character+"
- ".-x-evo-quote-character+"
- ".-x-evo-quote-character"
- "{\n"
- " color: %s;\n"
- "}\n",
- e_web_view_get_citation_color_for_level (3));
-
- g_string_append_printf (
- stylesheet,
- ".-x-evo-quote-character+"
- ".-x-evo-quote-character+"
- ".-x-evo-quote-character+"
- ".-x-evo-quote-character"
- "{\n"
- " color: %s;\n"
- "}\n",
- e_web_view_get_citation_color_for_level (4));
-
- g_string_append_printf (
- stylesheet,
- ".-x-evo-quote-character+"
- ".-x-evo-quote-character+"
- ".-x-evo-quote-character+"
- ".-x-evo-quote-character+"
- ".-x-evo-quote-character"
- "{\n"
- " color: %s;\n"
- "}\n",
- e_web_view_get_citation_color_for_level (5));
-
- g_string_append (
- stylesheet,
- "body:not([data-evo-plain-text]) "
- "blockquote[type=cite] "
- "{\n"
- " padding: 0ch 1ch 0ch 1ch;\n"
- " margin: 0ch;\n"
- " border-width: 0px 2px 0px 2px;\n"
- " border-style: none solid none solid;\n"
- " border-radius: 2px;\n"
- "}\n");
-
- g_string_append_printf (
- stylesheet,
- "body:not([data-evo-plain-text]) "
- "blockquote[type=cite] "
- "{\n"
- " border-color: %s;\n"
- "}\n",
- e_web_view_get_citation_color_for_level (1));
-
- g_string_append_printf (
- stylesheet,
- "body:not([data-evo-plain-text]) "
- "blockquote[type=cite] "
- "blockquote[type=cite] "
- "{\n"
- " border-color: %s;\n"
- "}\n",
- e_web_view_get_citation_color_for_level (2));
-
- g_string_append_printf (
- stylesheet,
- "body:not([data-evo-plain-text]) "
- "blockquote[type=cite] "
- "blockquote[type=cite] "
- "blockquote[type=cite] "
- "{\n"
- " border-color: %s;\n"
- "}\n",
- e_web_view_get_citation_color_for_level (3));
-
- g_string_append_printf (
- stylesheet,
- "body:not([data-evo-plain-text]) "
- "blockquote[type=cite] "
- "blockquote[type=cite] "
- "blockquote[type=cite] "
- "blockquote[type=cite] "
- "{\n"
- " border-color: %s;\n"
- "}\n",
- e_web_view_get_citation_color_for_level (4));
-
- g_string_append_printf (
- stylesheet,
- "body:not([data-evo-plain-text]) "
- "blockquote[type=cite] "
- "blockquote[type=cite] "
- "blockquote[type=cite] "
- "blockquote[type=cite] "
- "blockquote[type=cite] "
- "{\n"
- " border-color: %s;\n"
- "}\n",
- e_web_view_get_citation_color_for_level (5));
-
if (wk_editor->priv->visually_wrap_long_lines) {
g_string_append (
stylesheet,
@@ -1378,200 +1645,166 @@ webkit_editor_update_styles (EContentEditor *editor)
}
static void
-webkit_editor_page_set_text_color (EContentEditor *editor,
- const GdkRGBA *value)
+webkit_editor_add_color_style (GString *css,
+ const gchar *selector,
+ const gchar *property,
+ const GdkRGBA *value)
{
- EWebKitEditor *wk_editor;
- gchar *color;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- color = g_strdup_printf ("#%06x", e_rgba_to_value (value));
+ g_return_if_fail (css != NULL);
+ g_return_if_fail (selector != NULL);
+ g_return_if_fail (property != NULL);
- webkit_editor_set_element_attribute (wk_editor, "body", "text", color);
+ if (!value || value->alpha <= 1e-9)
+ return;
- g_free (color);
+ g_string_append_printf (css, "%s { %s : #%06x; }\n", selector, property, e_rgba_to_value (value));
}
static void
-webkit_editor_page_get_text_color (EContentEditor *editor,
- GdkRGBA *color)
+webkit_editor_set_page_color_attribute (EContentEditor *editor,
+ GString *script, /* serves two purposes, also says whether write to
body or not */
+ const gchar *attr_name,
+ const GdkRGBA *value)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- if (!wk_editor->priv->html_mode)
- goto theme;
+ if (value && value->alpha > 1e-9) {
+ gchar color[64];
- result = webkit_editor_get_element_attribute (wk_editor, "body", "text");
- if (result) {
- const gchar *value;
+ webkit_editor_utils_color_to_string (color, sizeof (color), value);
- g_variant_get (result, "(&s)", &value);
- if (!value || !*value || !gdk_rgba_parse (color, value)) {
- g_variant_unref (result);
- goto theme;
+ if (script) {
+ e_web_view_jsc_printf_script_gstring (script,
+ "document.documentElement.setAttribute(%s, %s);\n",
+ attr_name,
+ color);
+ } else {
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.SetBodyAttribute(%s, %s);",
+ attr_name,
+ color);
}
- g_variant_unref (result);
- return;
+ } else if (script) {
+ e_web_view_jsc_printf_script_gstring (script,
+ "document.documentElement.removeAttribute(%s);\n",
+ attr_name);
+ } else {
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.SetBodyAttribute(%s, null);",
+ attr_name);
}
-
- theme:
- e_utils_get_theme_color (
- GTK_WIDGET (wk_editor),
- "theme_text_color",
- E_UTILS_DEFAULT_THEME_TEXT_COLOR,
- color);
}
static void
-webkit_editor_page_set_background_color (EContentEditor *editor,
- const GdkRGBA *value)
+webkit_editor_page_set_text_color (EContentEditor *editor,
+ const GdkRGBA *value)
{
- EWebKitEditor *wk_editor;
- gchar *color;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
+ webkit_editor_set_page_color_attribute (editor, NULL, "text", value);
+}
- if (value->alpha != 0.0)
- color = g_strdup_printf ("#%06x", e_rgba_to_value (value));
- else
- color = g_strdup ("");
+static void
+webkit_editor_page_get_text_color (EContentEditor *editor,
+ GdkRGBA *color)
+{
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- webkit_editor_set_element_attribute (wk_editor, "body", "bgcolor", color);
+ if (wk_editor->priv->html_mode &&
+ wk_editor->priv->body_fg_color) {
+ *color = *wk_editor->priv->body_fg_color;
+ } else {
+ e_utils_get_theme_color (GTK_WIDGET (wk_editor), "theme_text_color",
E_UTILS_DEFAULT_THEME_TEXT_COLOR, color);
+ }
+}
- g_free (color);
+static void
+webkit_editor_page_set_background_color (EContentEditor *editor,
+ const GdkRGBA *value)
+{
+ webkit_editor_set_page_color_attribute (editor, NULL, "bgcolor", value);
}
static void
webkit_editor_page_get_background_color (EContentEditor *editor,
GdkRGBA *color)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- goto theme;
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- result = webkit_editor_get_element_attribute (wk_editor, "body", "bgcolor");
- if (result) {
- const gchar *value;
-
- g_variant_get (result, "(&s)", &value);
- if (!value || !*value || !gdk_rgba_parse (color, value)) {
- g_variant_unref (result);
- goto theme;
- }
- g_variant_unref (result);
- return;
+ if (wk_editor->priv->html_mode &&
+ wk_editor->priv->body_bg_color) {
+ *color = *wk_editor->priv->body_bg_color;
+ } else {
+ e_utils_get_theme_color (GTK_WIDGET (wk_editor), "theme_base_color",
E_UTILS_DEFAULT_THEME_BASE_COLOR, color);
}
-
- theme:
- e_utils_get_theme_color (
- GTK_WIDGET (wk_editor),
- "theme_base_color",
- E_UTILS_DEFAULT_THEME_BASE_COLOR,
- color);
}
static void
webkit_editor_page_set_link_color (EContentEditor *editor,
const GdkRGBA *value)
{
- EWebKitEditor *wk_editor;
- gchar *color;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- color = g_strdup_printf ("#%06x", e_rgba_to_value (value));
-
- webkit_editor_set_element_attribute (wk_editor, "body", "link", color);
-
- g_free (color);
+ webkit_editor_set_page_color_attribute (editor, NULL, "link", value);
}
static void
webkit_editor_page_get_link_color (EContentEditor *editor,
GdkRGBA *color)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- if (!wk_editor->priv->html_mode)
- goto theme;
-
- result = webkit_editor_get_element_attribute (wk_editor, "body", "link");
- if (result) {
- const gchar *value;
-
- g_variant_get (result, "(&s)", &value);
- if (!value || !*value || !gdk_rgba_parse (color, value)) {
- g_variant_unref (result);
- goto theme;
- }
- g_variant_unref (result);
- return;
+ if (wk_editor->priv->html_mode &&
+ wk_editor->priv->body_link_color) {
+ *color = *wk_editor->priv->body_link_color;
+ } else {
+ color->alpha = 1;
+ color->red = 0;
+ color->green = 0;
+ color->blue = 1;
}
-
- theme:
- color->alpha = 1;
- color->red = 0;
- color->green = 0;
- color->blue = 1;
}
static void
webkit_editor_page_set_visited_link_color (EContentEditor *editor,
const GdkRGBA *value)
{
- EWebKitEditor *wk_editor;
- gchar *color;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- color = g_strdup_printf ("#%06x", e_rgba_to_value (value));
-
- webkit_editor_set_element_attribute (wk_editor, "body", "vlink", color);
-
- g_free (color);
+ webkit_editor_set_page_color_attribute (editor, NULL, "vlink", value);
}
static void
webkit_editor_page_get_visited_link_color (EContentEditor *editor,
GdkRGBA *color)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- wk_editor = E_WEBKIT_EDITOR (editor);
+ if (wk_editor->priv->html_mode &&
+ wk_editor->priv->body_vlink_color) {
+ *color = *wk_editor->priv->body_vlink_color;
+ } else {
+ color->alpha = 1;
+ color->red = 1;
+ color->green = 0;
+ color->blue = 0;
+ }
+}
- if (!wk_editor->priv->html_mode)
- goto theme;
+static void
+webkit_editor_page_set_font_name (EContentEditor *editor,
+ const gchar *value)
+{
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- result = webkit_editor_get_element_attribute (wk_editor, "body", "vlink");
- if (result) {
- const gchar *value;
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.SetBodyFontName(%s);",
+ value ? value : "");
+}
- g_variant_get (result, "(&s)", &value);
- if (!value || !*value || !gdk_rgba_parse (color, value)) {
- g_variant_unref (result);
- goto theme;
- }
- g_variant_unref (result);
- return;
- }
+static const gchar *
+webkit_editor_page_get_font_name (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return NULL;
- theme:
- color->alpha = 1;
- color->red = 1;
- color->green = 0;
- color->blue = 0;
+ return wk_editor->priv->body_font_name;
}
static void
@@ -1611,56 +1844,95 @@ get_color_from_context (GtkStyleContext *context,
}
static void
-webkit_editor_style_updated_cb (EWebKitEditor *wk_editor)
+webkit_editor_style_updated (EWebKitEditor *wk_editor,
+ gboolean force)
{
- GdkRGBA rgba;
+ EContentEditor *cnt_editor;
+ GdkRGBA bgcolor, fgcolor, link_color, vlink_color;
GtkStateFlags state_flags;
GtkStyleContext *style_context;
+ GString *css, *script;
gboolean backdrop;
+ gboolean inherit_theme_colors;
- /* If the user set the colors in Page dialog, this callback is useless. */
- if (wk_editor->priv->suppress_color_changes)
- return;
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ cnt_editor = E_CONTENT_EDITOR (wk_editor);
+ inherit_theme_colors = g_settings_get_boolean (wk_editor->priv->mail_settings,
"composer-inherit-theme-colors");
state_flags = gtk_widget_get_state_flags (GTK_WIDGET (wk_editor));
style_context = gtk_widget_get_style_context (GTK_WIDGET (wk_editor));
backdrop = (state_flags & GTK_STATE_FLAG_BACKDROP) != 0;
- if (wk_editor->priv->html_mode && !g_settings_get_boolean (wk_editor->priv->mail_settings,
"composer-inherit-theme-colors")) {
+ if (wk_editor->priv->html_mode && !inherit_theme_colors) {
/* Default to white background when not inheriting theme colors */
- rgba.red = 1.0;
- rgba.green = 1.0;
- rgba.blue = 1.0;
- rgba.alpha = 1.0;
+ bgcolor.red = 1.0;
+ bgcolor.green = 1.0;
+ bgcolor.blue = 1.0;
+ bgcolor.alpha = 1.0;
} else if (!gtk_style_context_lookup_color (
style_context,
backdrop ? "theme_unfocused_base_color" : "theme_base_color",
- &rgba)) {
- gdk_rgba_parse (&rgba, E_UTILS_DEFAULT_THEME_BASE_COLOR);
+ &bgcolor)) {
+ gdk_rgba_parse (&bgcolor, E_UTILS_DEFAULT_THEME_BASE_COLOR);
}
- webkit_editor_page_set_background_color (E_CONTENT_EDITOR (wk_editor), &rgba);
-
- if (wk_editor->priv->html_mode && !g_settings_get_boolean (wk_editor->priv->mail_settings,
"composer-inherit-theme-colors")) {
+ if (wk_editor->priv->html_mode && !inherit_theme_colors) {
/* Default to black text color when not inheriting theme colors */
- rgba.red = 0.0;
- rgba.green = 0.0;
- rgba.blue = 0.0;
- rgba.alpha = 1.0;
+ fgcolor.red = 0.0;
+ fgcolor.green = 0.0;
+ fgcolor.blue = 0.0;
+ fgcolor.alpha = 1.0;
} else if (!gtk_style_context_lookup_color (
style_context,
backdrop ? "theme_unfocused_fg_color" : "theme_fg_color",
- &rgba)) {
- gdk_rgba_parse (&rgba, E_UTILS_DEFAULT_THEME_FG_COLOR);
+ &fgcolor)) {
+ gdk_rgba_parse (&fgcolor, E_UTILS_DEFAULT_THEME_FG_COLOR);
}
- webkit_editor_page_set_text_color (E_CONTENT_EDITOR (wk_editor), &rgba);
+ get_color_from_context (style_context, "link-color", &link_color);
+ get_color_from_context (style_context, "visited-link-color", &vlink_color);
+
+ if (!force &&
+ gdk_rgba_equal (&bgcolor, &wk_editor->priv->theme_bgcolor) &&
+ gdk_rgba_equal (&fgcolor, &wk_editor->priv->theme_fgcolor) &&
+ gdk_rgba_equal (&link_color, &wk_editor->priv->theme_link_color) &&
+ gdk_rgba_equal (&vlink_color, &wk_editor->priv->theme_vlink_color))
+ return;
+
+ wk_editor->priv->theme_bgcolor = bgcolor;
+ wk_editor->priv->theme_fgcolor = fgcolor;
+ wk_editor->priv->theme_link_color = link_color;
+ wk_editor->priv->theme_vlink_color = vlink_color;
+
+ css = g_string_sized_new (160);
+ script = g_string_sized_new (256);
+
+ webkit_editor_set_page_color_attribute (cnt_editor, script, "x-evo-bgcolor", &bgcolor);
+ webkit_editor_set_page_color_attribute (cnt_editor, script, "x-evo-text", &fgcolor);
+ webkit_editor_set_page_color_attribute (cnt_editor, script, "x-evo-link", &link_color);
+ webkit_editor_set_page_color_attribute (cnt_editor, script, "x-evo-vlink", &vlink_color);
+
+ webkit_editor_add_color_style (css, "html", "background-color", &bgcolor);
+ webkit_editor_add_color_style (css, "html", "color", &fgcolor);
+ webkit_editor_add_color_style (css, "a", "color", &link_color);
+ webkit_editor_add_color_style (css, "a:visited", "color", &vlink_color);
+
+ e_web_view_jsc_printf_script_gstring (script,
+ "EvoEditor.UpdateThemeStyleSheet(%s);",
+ css->str);
+
+ e_web_view_jsc_run_script_take (WEBKIT_WEB_VIEW (wk_editor),
+ g_string_free (script, FALSE),
+ wk_editor->priv->cancellable);
- get_color_from_context (style_context, "link-color", &rgba);
- webkit_editor_page_set_link_color (E_CONTENT_EDITOR (wk_editor), &rgba);
+ g_string_free (css, TRUE);
+}
- get_color_from_context (style_context, "visited-link-color", &rgba);
- webkit_editor_page_set_visited_link_color (E_CONTENT_EDITOR (wk_editor), &rgba);
+static void
+webkit_editor_style_updated_cb (EWebKitEditor *wk_editor)
+{
+ webkit_editor_style_updated (wk_editor, FALSE);
}
static gboolean
@@ -1698,90 +1970,23 @@ static void
webkit_editor_set_html_mode (EWebKitEditor *wk_editor,
gboolean html_mode)
{
- gboolean convert = FALSE;
- GVariant *result;
-
g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
if (html_mode == wk_editor->priv->html_mode)
return;
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMCheckIfConversionNeeded",
- g_variant_new ("(t)", current_page_id (wk_editor)),
- NULL);
-
- if (result) {
- g_variant_get (result, "(b)", &convert);
- g_variant_unref (result);
- }
-
- /* If toggling from HTML to the plain text mode, ask the user first if
- * he wants to convert the content. */
- if (convert) {
- if (!show_lose_formatting_dialog (wk_editor))
- return;
-
- webkit_editor_set_changed (wk_editor, TRUE);
- }
-
wk_editor->priv->html_mode = html_mode;
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "SetEditorHTMLMode",
- g_variant_new ("(tbb)", current_page_id (wk_editor), html_mode, convert),
- wk_editor->priv->cancellable);
+ if (html_mode) {
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.SetMode(EvoEditor.MODE_HTML);");
+ } else {
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.SetMode(EvoEditor.MODE_PLAIN_TEXT);");
+ }
- /* Update fonts - in plain text we only want monospaced */
webkit_editor_update_styles (E_CONTENT_EDITOR (wk_editor));
- webkit_editor_style_updated_cb (wk_editor);
-
- g_object_notify (G_OBJECT (wk_editor), "html-mode");
-}
-
-static void
-set_convert_in_situ (EWebKitEditor *wk_editor,
- gboolean value)
-{
- GVariant *result;
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "SetConvertInSitu",
- g_variant_new ("(tbnn)", current_page_id (wk_editor), value,
- e_webkit_editor_three_state_to_int16 (e_content_editor_get_start_bottom
(E_CONTENT_EDITOR (wk_editor))),
- e_webkit_editor_three_state_to_int16 (e_content_editor_get_top_signature
(E_CONTENT_EDITOR (wk_editor)))),
- NULL);
-
- if (result)
- g_variant_unref (result);
-}
-
-static void
-e_webkit_editor_load_data (EWebKitEditor *wk_editor,
- const gchar *html)
-{
- gchar *uri_with_stamp;
-
- g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
-
- if (!html)
- html = "";
-
- /* Make WebKit think we are displaying a local file, so that it
- * does not block loading resources from file:// protocol */
- uri_with_stamp = g_strdup_printf ("file:///?evo-stamp=%d", wk_editor->priv->stamp);
-
- webkit_web_view_load_html (WEBKIT_WEB_VIEW (wk_editor), html, uri_with_stamp);
-
- g_free (uri_with_stamp);
+ webkit_editor_style_updated (wk_editor, FALSE);
}
static void
@@ -1797,8 +2002,7 @@ webkit_editor_insert_content (EContentEditor *editor,
* another load operation) so we have to queue the current operation and
* redo it again when the view is ready. This was happening when loading
* the stuff in EMailSignatureEditor. */
- if (wk_editor->priv->webkit_load_event != WEBKIT_LOAD_FINISHED ||
- wk_editor->priv->reload_in_progress) {
+ if (wk_editor->priv->webkit_load_event != WEBKIT_LOAD_FINISHED) {
webkit_editor_queue_post_reload_operation (
wk_editor,
(PostReloadOperationFunc) webkit_editor_insert_content,
@@ -1808,51 +2012,17 @@ webkit_editor_insert_content (EContentEditor *editor,
return;
}
- if (!wk_editor->priv->web_extension_proxy) {
- /* If the operation needs a web extension and it is not ready yet
- * we need to schedule the current operation again a dispatch it
- * when the extension is ready */
- if (!((flags & E_CONTENT_EDITOR_INSERT_REPLACE_ALL) &&
- (flags & E_CONTENT_EDITOR_INSERT_TEXT_HTML) &&
- (strstr (content, "data-evo-draft") ||
- strstr (content, "data-evo-signature-plain-text-mode")))) {
- webkit_editor_queue_post_reload_operation (
- wk_editor,
- (PostReloadOperationFunc) webkit_editor_insert_content,
- g_strdup (content),
- g_free,
- flags);
- return;
- }
- }
-
if ((flags & E_CONTENT_EDITOR_INSERT_CONVERT) &&
!(flags & E_CONTENT_EDITOR_INSERT_REPLACE_ALL)) {
- /* e_html_editor_view_convert_and_insert_plain_text
- e_html_editor_view_convert_and_insert_html_to_plain_text
- e_html_editor_view_insert_text */
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMConvertAndInsertHTMLIntoSelection",
- g_variant_new (
- "(tsb)",
- current_page_id (wk_editor),
- content,
- (flags & E_CONTENT_EDITOR_INSERT_TEXT_HTML)),
- wk_editor->priv->cancellable);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.InsertContent(%s, %x, %x);",
+ content, (flags & E_CONTENT_EDITOR_INSERT_TEXT_HTML) != 0, FALSE);
} else if ((flags & E_CONTENT_EDITOR_INSERT_REPLACE_ALL) &&
(flags & E_CONTENT_EDITOR_INSERT_TEXT_HTML)) {
if ((strstr (content, "data-evo-draft") ||
strstr (content, "data-evo-signature-plain-text-mode"))) {
- wk_editor->priv->reload_in_progress = TRUE;
- e_webkit_editor_load_data (wk_editor, content);
- return;
- }
-
- if (strstr (content, "data-evo-draft") && !(wk_editor->priv->html_mode)) {
- set_convert_in_situ (wk_editor, TRUE);
- wk_editor->priv->reload_in_progress = TRUE;
- e_webkit_editor_load_data (wk_editor, content);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.LoadHTML(%s);", content);
return;
}
@@ -1861,200 +2031,222 @@ webkit_editor_insert_content (EContentEditor *editor,
if (strstr (content, "<!-- text/html -->") &&
!strstr (content, "<!-- disable-format-prompt -->")) {
if (!show_lose_formatting_dialog (wk_editor)) {
- set_convert_in_situ (wk_editor, FALSE);
- wk_editor->priv->reload_in_progress = TRUE;
webkit_editor_set_html_mode (wk_editor, TRUE);
- e_webkit_editor_load_data (wk_editor, content);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor),
wk_editor->priv->cancellable,
+ "EvoEditor.LoadHTML(%s);", content);
return;
}
}
- set_convert_in_situ (wk_editor, TRUE);
}
- wk_editor->priv->reload_in_progress = TRUE;
- e_webkit_editor_load_data (wk_editor, content);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.LoadHTML(%s);", content);
} else if ((flags & E_CONTENT_EDITOR_INSERT_REPLACE_ALL) &&
(flags & E_CONTENT_EDITOR_INSERT_TEXT_PLAIN)) {
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMConvertContent",
- g_variant_new ("(tsnn)", current_page_id (wk_editor), content,
- e_webkit_editor_three_state_to_int16 (e_content_editor_get_start_bottom
(editor)),
- e_webkit_editor_three_state_to_int16 (e_content_editor_get_top_signature
(editor))),
- wk_editor->priv->cancellable);
- } else if ((flags & E_CONTENT_EDITOR_INSERT_CONVERT) &&
- !(flags & E_CONTENT_EDITOR_INSERT_REPLACE_ALL) &&
- !(flags & E_CONTENT_EDITOR_INSERT_QUOTE_CONTENT)) {
- /* e_html_editor_view_paste_as_text */
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMConvertAndInsertHTMLIntoSelection",
- g_variant_new (
- "(tsb)", current_page_id (wk_editor), content, TRUE),
- wk_editor->priv->cancellable);
- } else if ((flags & E_CONTENT_EDITOR_INSERT_QUOTE_CONTENT) &&
- !(flags & E_CONTENT_EDITOR_INSERT_REPLACE_ALL)) {
- /* e_html_editor_view_paste_clipboard_quoted */
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMQuoteAndInsertTextIntoSelection",
- g_variant_new (
- "(tsb)", current_page_id (wk_editor), content, (flags &
E_CONTENT_EDITOR_INSERT_TEXT_HTML) != 0),
- wk_editor->priv->cancellable);
- } else if (!(flags & E_CONTENT_EDITOR_INSERT_CONVERT) &&
- !(flags & E_CONTENT_EDITOR_INSERT_REPLACE_ALL)) {
- /* e_html_editor_view_insert_html */
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMInsertHTML",
- g_variant_new (
- "(ts)", current_page_id (wk_editor), content),
- wk_editor->priv->cancellable);
- } else
- g_warning ("Unsupported flags combination (%d) in (%s)", flags, G_STRFUNC);
-}
+ gchar *html, **lines;
+ gint ii;
-static CamelMimePart *
-create_part_for_inline_image_from_element_data (const gchar *element_src,
- const gchar *name,
- const gchar *id)
-{
- CamelStream *stream;
- CamelDataWrapper *wrapper;
- CamelMimePart *part = NULL;
- gsize decoded_size;
- gssize size;
- gchar *mime_type = NULL;
- const gchar *base64_encoded_data;
- guchar *base64_decoded_data = NULL;
+ lines = g_strsplit (content ? content : "", "\n", -1);
- base64_encoded_data = strstr (element_src, ";base64,");
- if (!base64_encoded_data)
- goto out;
+ for (ii = 0; lines && lines[ii]; ii++) {
+ gchar *line = lines[ii];
+ gint len = strlen (line);
- mime_type = g_strndup (
- element_src + 5,
- base64_encoded_data - (strstr (element_src, "data:") + 5));
+ if (len > 0 && line[len - 1] == '\r') {
+ line[len - 1] = 0;
+ len--;
+ }
- /* Move to actual data */
- base64_encoded_data += 8;
+ if (len)
+ lines[ii] = g_markup_printf_escaped ("<div>%s</div>", line);
+ else
+ lines[ii] = g_strdup ("<div><br></div>");
- base64_decoded_data = g_base64_decode (base64_encoded_data, &decoded_size);
+ g_free (line);
+ }
- stream = camel_stream_mem_new ();
- size = camel_stream_write (
- stream, (gchar *) base64_decoded_data, decoded_size, NULL, NULL);
+ html = g_strjoinv ("", lines);
- if (size == -1)
- goto out;
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.LoadHTML(%s);", html);
- wrapper = camel_data_wrapper_new ();
- camel_data_wrapper_construct_from_stream_sync (
- wrapper, stream, NULL, NULL);
- g_object_unref (stream);
+ g_strfreev (lines);
+ g_free (html);
+ } else if ((flags & E_CONTENT_EDITOR_INSERT_CONVERT) &&
+ !(flags & E_CONTENT_EDITOR_INSERT_REPLACE_ALL) &&
+ !(flags & E_CONTENT_EDITOR_INSERT_QUOTE_CONTENT)) {
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.InsertContent(%s, %x, %x);",
+ content, TRUE, FALSE);
+ } else if ((flags & E_CONTENT_EDITOR_INSERT_QUOTE_CONTENT) &&
+ !(flags & E_CONTENT_EDITOR_INSERT_REPLACE_ALL)) {
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.InsertContent(%s, %x, %x);",
+ content, (flags & E_CONTENT_EDITOR_INSERT_TEXT_HTML) != 0, TRUE);
+ } else if (!(flags & E_CONTENT_EDITOR_INSERT_CONVERT) &&
+ !(flags & E_CONTENT_EDITOR_INSERT_REPLACE_ALL)) {
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.InsertContent(%s, %x, %x);",
+ content, (flags & E_CONTENT_EDITOR_INSERT_TEXT_HTML) != 0, FALSE);
+ } else {
+ g_warning ("%s: Unsupported flags combination (0x%x)", G_STRFUNC, flags);
+ }
- camel_data_wrapper_set_mime_type (wrapper, mime_type);
+ if (flags & E_CONTENT_EDITOR_INSERT_REPLACE_ALL)
+ webkit_editor_style_updated (wk_editor, TRUE);
+}
- part = camel_mime_part_new ();
- camel_medium_set_content (CAMEL_MEDIUM (part), wrapper);
- g_object_unref (wrapper);
+static void
+webkit_editor_get_content (EContentEditor *editor,
+ guint32 flags, /* bit-or of EContentEditorGetContentFlags */
+ const gchar *inline_images_from_domain,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ gchar *script, *cid_uid_prefix;
+
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (editor));
+
+ cid_uid_prefix = camel_header_msgid_generate (inline_images_from_domain ? inline_images_from_domain :
"");
+ script = e_web_view_jsc_printf_script ("EvoEditor.GetContent(%d, %s)", flags, cid_uid_prefix);
- camel_mime_part_set_content_id (part, id);
- camel_mime_part_set_filename (part, name);
- camel_mime_part_set_disposition (part, "inline");
- camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64);
-out:
- g_free (mime_type);
- g_free (base64_decoded_data);
+ webkit_web_view_run_javascript (WEBKIT_WEB_VIEW (editor), script, cancellable, callback, user_data);
- return part;
+ g_free (cid_uid_prefix);
+ g_free (script);
}
-static GSList *
-webkit_editor_get_parts_for_inline_images (GVariant *images)
+static EContentEditorContentHash *
+webkit_editor_get_content_finish (EContentEditor *editor,
+ GAsyncResult *result,
+ GError **error)
{
- const gchar *element_src, *name, *id;
- GVariantIter *iter;
- GSList *parts = NULL;
+ WebKitJavascriptResult *js_result;
+ EContentEditorContentHash *content_hash = NULL;
+ GError *local_error = NULL;
- if (g_variant_check_format_string (images, "a(sss)", FALSE)) {
- g_variant_get (images, "a(sss)", &iter);
- while (g_variant_iter_loop (iter, "(&s&s&s)", &element_src, &name, &id)) {
- CamelMimePart *part;
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (editor), NULL);
+ g_return_val_if_fail (result != NULL, NULL);
- part = create_part_for_inline_image_from_element_data (
- element_src, name, id);
- parts = g_slist_prepend (parts, part);
- }
- g_variant_iter_free (iter);
- }
+ js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (editor), result, &local_error);
- return parts ? g_slist_reverse (parts) : NULL;
-}
+ if (local_error) {
+ g_propagate_error (error, local_error);
-static gchar *
-webkit_editor_get_content (EContentEditor *editor,
- EContentEditorGetContentFlags flags,
- const gchar *inline_images_from_domain,
- GSList **inline_images_parts)
-{
- EWebKitEditor *wk_editor;
- GVariant *result;
- GError *local_error = NULL;
+ if (js_result)
+ webkit_javascript_result_unref (js_result);
- wk_editor = E_WEBKIT_EDITOR (editor);
- if (!wk_editor->priv->web_extension_proxy)
return NULL;
+ }
- if ((flags & E_CONTENT_EDITOR_GET_TEXT_HTML) &&
- !(flags & E_CONTENT_EDITOR_GET_PROCESSED) &&
- !(flags & E_CONTENT_EDITOR_GET_BODY))
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMEmbedStyleSheet",
- g_variant_new (
- "(ts)",
- current_page_id (wk_editor),
- wk_editor->priv->current_user_stylesheet),
- wk_editor->priv->cancellable);
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper (
- wk_editor->priv->web_extension_proxy,
- "DOMGetContent",
- g_variant_new (
- "(tsi)",
- current_page_id (wk_editor),
- inline_images_from_domain ? inline_images_from_domain : "",
- (gint32) flags),
- wk_editor->priv->cancellable,
- &local_error);
-
- webkit_editor_set_last_error (wk_editor, local_error);
- g_clear_error (&local_error);
-
- if ((flags & E_CONTENT_EDITOR_GET_TEXT_HTML) &&
- !(flags & E_CONTENT_EDITOR_GET_PROCESSED) &&
- !(flags & E_CONTENT_EDITOR_GET_BODY))
- webkit_editor_call_simple_extension_function (
- wk_editor, "DOMRemoveEmbeddedStyleSheet");
+ if (js_result) {
+ JSCException *exception;
+ JSCValue *value;
- if (result) {
- GVariant *images = NULL;
- gchar *value = NULL;
+ value = webkit_javascript_result_get_js_value (js_result);
+ exception = jsc_context_get_exception (jsc_value_get_context (value));
+
+ if (exception) {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "EvoEditor.GetContent() call
failed: %s", jsc_exception_get_message (exception));
+ jsc_context_clear_exception (jsc_value_get_context (value));
+ webkit_javascript_result_unref (js_result);
+ return NULL;
+ }
+
+ if (jsc_value_is_object (value)) {
+ struct _formats {
+ const gchar *name;
+ guint32 flags;
+ } formats[] = {
+ { "raw-body-html", E_CONTENT_EDITOR_GET_RAW_BODY_HTML },
+ { "raw-body-plain", E_CONTENT_EDITOR_GET_RAW_BODY_PLAIN },
+ { "raw-body-stripped", E_CONTENT_EDITOR_GET_RAW_BODY_STRIPPED },
+ { "raw-draft", E_CONTENT_EDITOR_GET_RAW_DRAFT },
+ { "to-send-html", E_CONTENT_EDITOR_GET_TO_SEND_HTML },
+ { "to-send-plain", E_CONTENT_EDITOR_GET_TO_SEND_PLAIN }
+ };
+ JSCValue *images_value;
+ gint ii;
+
+ content_hash = e_content_editor_util_new_content_hash ();
+
+ for (ii = 0; ii < G_N_ELEMENTS (formats); ii++) {
+ gchar *cnt;
+
+ cnt = e_web_view_jsc_get_object_property_string (value, formats[ii].name,
NULL);
+ if (cnt)
+ e_content_editor_util_take_content_data (content_hash,
formats[ii].flags, cnt, g_free);
+ }
+
+ images_value = jsc_value_object_get_property (value, "images");
+
+ if (images_value) {
+ if (jsc_value_is_array (images_value)) {
+ GSList *image_parts = NULL;
+ gint length;
+
+ length = e_web_view_jsc_get_object_property_int32 (images_value,
"length", 0);
+
+ for (ii = 0; ii < length; ii++) {
+ JSCValue *item_value;
+
+ item_value = jsc_value_object_get_property_at_index
(images_value, ii);
+
+ if (!item_value ||
+ jsc_value_is_null (item_value) ||
+ jsc_value_is_undefined (item_value)) {
+ g_warn_if_reached ();
+ g_clear_object (&item_value);
+ break;
+ }
+
+ if (jsc_value_is_object (item_value)) {
+ gchar *src, *cid, *name;
+
+ src = e_web_view_jsc_get_object_property_string
(item_value, "src", NULL);
+ cid = e_web_view_jsc_get_object_property_string
(item_value, "cid", NULL);
+ name = e_web_view_jsc_get_object_property_string
(item_value, "name", NULL);
+
+ if (src && *src && cid && *cid) {
+ CamelMimePart *part = NULL;
+
+ if (g_ascii_strncasecmp (src, "cid:", 4) == 0)
+ part =
e_content_editor_emit_ref_mime_part (editor, src);
- g_variant_get (result, "(sv)", &value, &images);
- if (inline_images_parts)
- *inline_images_parts = webkit_editor_get_parts_for_inline_images (images);
+ if (!part) {
+ part =
e_content_editor_util_create_data_mimepart (src, cid, TRUE, name, NULL,
+ E_WEBKIT_EDITOR
(editor)->priv->cancellable);
+ }
- if (images)
- g_variant_unref (images);
+ if (part)
+ image_parts = g_slist_prepend
(image_parts, part);
+ }
- g_variant_unref (result);
+ g_free (name);
+ g_free (src);
+ g_free (cid);
+ }
- return value;
+ g_clear_object (&item_value);
+ }
+
+ if (image_parts)
+ e_content_editor_util_take_content_data_images (content_hash,
g_slist_reverse (image_parts));
+ } else if (!jsc_value_is_undefined (images_value) && !jsc_value_is_null
(images_value)) {
+ g_warn_if_reached ();
+ }
+
+ g_clear_object (&images_value);
+ }
+ } else {
+ g_warn_if_reached ();
+ }
+
+ webkit_javascript_result_unref (js_result);
}
- return NULL;
+ return content_hash;
}
static gboolean
@@ -2070,9 +2262,12 @@ webkit_editor_undo (EContentEditor *editor)
{
EWebKitEditor *wk_editor;
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (editor));
+
wk_editor = E_WEBKIT_EDITOR (editor);
- webkit_editor_call_simple_extension_function (wk_editor, "DOMUndo");
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoUndoRedo.Undo();");
}
static gboolean
@@ -2092,33 +2287,25 @@ webkit_editor_redo (EContentEditor *editor)
wk_editor = E_WEBKIT_EDITOR (editor);
- webkit_editor_call_simple_extension_function (wk_editor, "DOMRedo");
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoUndoRedo.Redo();");
}
static void
webkit_editor_move_caret_on_coordinates (EContentEditor *editor,
- gint x,
- gint y,
- gboolean cancel_if_not_collapsed)
+ gint xx,
+ gint yy,
+ gboolean cancel_if_not_collapsed)
{
EWebKitEditor *wk_editor;
- GVariant *result;
- wk_editor = E_WEBKIT_EDITOR (editor);
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (editor));
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMMoveSelectionOnPoint",
- g_variant_new (
- "(tiib)", current_page_id (wk_editor), x, y, cancel_if_not_collapsed),
- NULL);
+ wk_editor = E_WEBKIT_EDITOR (editor);
- if (result)
- g_variant_unref (result);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.MoveSelectionToPoint(%d, %d, %x);",
+ xx, yy, cancel_if_not_collapsed);
}
static void
@@ -2126,77 +2313,36 @@ webkit_editor_insert_emoticon (EContentEditor *editor,
EEmoticon *emoticon)
{
EWebKitEditor *wk_editor;
+ GSettings *settings;
+ const gchar *text;
+ gchar *image_uri = NULL;
+ gint width = 0, height = 0;
- wk_editor = E_WEBKIT_EDITOR (editor);
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMInsertSmiley",
- g_variant_new (
- "(ts)", current_page_id (wk_editor), e_emoticon_get_name (emoticon)),
- wk_editor->priv->cancellable);
-}
-
-static void
-webkit_editor_insert_image_from_mime_part (EContentEditor *editor,
- CamelMimePart *part)
-{
- CamelDataWrapper *dw;
- CamelStream *stream;
- EWebKitEditor *wk_editor;
- GByteArray *byte_array;
- gchar *src, *base64_encoded, *mime_type, *cid_uri;
- const gchar *cid, *name;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- dw = camel_medium_get_content (CAMEL_MEDIUM (part));
- g_return_if_fail (dw);
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (editor));
+ g_return_if_fail (emoticon != NULL);
- stream = camel_stream_mem_new ();
- camel_data_wrapper_decode_to_stream_sync (dw, stream, NULL, NULL);
- camel_stream_close (stream, NULL, NULL);
+ settings = e_util_ref_settings ("org.gnome.evolution.mail");
- byte_array = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (stream));
+ if (g_settings_get_boolean (settings, "composer-unicode-smileys")) {
+ text = emoticon->unicode_character;
+ } else {
+ text = emoticon->text_face;
+ image_uri = e_emoticon_get_uri (emoticon);
- if (!byte_array->data) {
- g_object_unref (stream);
- return;
+ if (image_uri) {
+ width = 16;
+ height = 16;
+ }
}
- base64_encoded = g_base64_encode ((const guchar *) byte_array->data, byte_array->len);
-
- mime_type = camel_data_wrapper_get_mime_type (dw);
- name = camel_mime_part_get_filename (part);
- /* Insert file name before new src */
- src = g_strconcat (name ? name : "", name ? ";data:" : "", mime_type, ";base64,", base64_encoded,
NULL);
-
- cid = camel_mime_part_get_content_id (part);
- if (!cid) {
- camel_mime_part_set_content_id (part, NULL);
- cid = camel_mime_part_get_content_id (part);
- }
- cid_uri = g_strdup_printf ("cid:%s", cid);
+ wk_editor = E_WEBKIT_EDITOR (editor);
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMAddNewInlineImageIntoList",
- g_variant_new ("(tsss)", current_page_id (wk_editor), name ? name : "", cid_uri, src),
- wk_editor->priv->cancellable);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.InsertEmoticon(%s, %s, %d, %d);",
+ text, image_uri, width, height);
- g_free (base64_encoded);
- g_free (mime_type);
- g_free (cid_uri);
- g_free (src);
- g_object_unref (stream);
+ g_clear_object (&settings);
+ g_free (image_uri);
}
static void
@@ -2204,6 +2350,8 @@ webkit_editor_select_all (EContentEditor *editor)
{
EWebKitEditor *wk_editor;
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (editor));
+
wk_editor = E_WEBKIT_EDITOR (editor);
webkit_web_view_execute_editing_command (
@@ -2215,17 +2363,20 @@ webkit_editor_selection_wrap (EContentEditor *editor)
{
EWebKitEditor *wk_editor;
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (editor));
+
wk_editor = E_WEBKIT_EDITOR (editor);
- webkit_editor_call_simple_extension_function (wk_editor, "DOMSelectionWrap");
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.WrapSelection();");
}
static gboolean
-webkit_editor_selection_is_indented (EWebKitEditor *wk_editor)
+webkit_editor_get_indent_level (EWebKitEditor *wk_editor)
{
g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
- return wk_editor->priv->is_indented;
+ return wk_editor->priv->indent_level;
}
static void
@@ -2235,8 +2386,8 @@ webkit_editor_selection_indent (EContentEditor *editor)
wk_editor = E_WEBKIT_EDITOR (editor);
- webkit_editor_call_simple_extension_function (
- wk_editor, "DOMSelectionIndent");
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.Indent(true);");
}
static void
@@ -2246,37 +2397,20 @@ webkit_editor_selection_unindent (EContentEditor *editor)
wk_editor = E_WEBKIT_EDITOR (editor);
- webkit_editor_call_simple_extension_function (
- wk_editor, "DOMSelectionUnindent");
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.Indent(false);");
}
static void
webkit_editor_cut (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- wk_editor->priv->copy_cut_actions_triggered = TRUE;
-
- webkit_editor_call_simple_extension_function_sync (
- wk_editor, "EEditorActionsSaveHistoryForCut");
-
- webkit_web_view_execute_editing_command (
- WEBKIT_WEB_VIEW (wk_editor), WEBKIT_EDITING_COMMAND_CUT);
+ webkit_web_view_execute_editing_command (WEBKIT_WEB_VIEW (editor), WEBKIT_EDITING_COMMAND_CUT);
}
static void
webkit_editor_copy (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- wk_editor->priv->copy_cut_actions_triggered = TRUE;
-
- webkit_web_view_execute_editing_command (
- WEBKIT_WEB_VIEW (wk_editor), WEBKIT_EDITING_COMMAND_COPY);
+ webkit_web_view_execute_editing_command (WEBKIT_WEB_VIEW (editor), WEBKIT_EDITING_COMMAND_COPY);
}
static ESpellChecker *
@@ -2290,28 +2424,9 @@ webkit_editor_get_spell_checker (EWebKitEditor *wk_editor)
static gchar *
webkit_editor_get_caret_word (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- gchar *ret_val = NULL;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return NULL;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMGetCaretWord",
- g_variant_new ("(t)", current_page_id (wk_editor)),
+ return webkit_editor_extract_and_free_jsc_string (
+ webkit_editor_call_jsc_sync (E_WEBKIT_EDITOR (editor), "EvoEditor.GetCaretWord();"),
NULL);
-
- if (result) {
- g_variant_get (result, "(s)", &ret_val);
- g_variant_unref (result);
- }
-
- return ret_val;
}
static void
@@ -2337,6 +2452,10 @@ webkit_editor_set_start_bottom (EWebKitEditor *wk_editor,
wk_editor->priv->start_bottom = value;
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.START_BOTTOM = %x;",
+ e_webkit_editor_three_state_to_bool (value, "composer-reply-start-bottom"));
+
g_object_notify (G_OBJECT (wk_editor), "start-bottom");
}
@@ -2359,6 +2478,10 @@ webkit_editor_set_top_signature (EWebKitEditor *wk_editor,
wk_editor->priv->top_signature = value;
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.TOP_SIGNATURE = %x;",
+ e_webkit_editor_three_state_to_bool (value, "composer-top-signature"));
+
g_object_notify (G_OBJECT (wk_editor), "top-signature");
}
@@ -2383,9 +2506,6 @@ webkit_editor_set_spell_check_enabled (EWebKitEditor *wk_editor,
wk_editor->priv->spell_check_enabled = enable;
- webkit_editor_call_simple_extension_function (
- wk_editor, enable ? "DOMForceSpellCheck" : "DOMTurnSpellCheckOff");
-
web_context = webkit_web_view_get_context (WEBKIT_WEB_VIEW (wk_editor));
webkit_web_context_set_spell_checking_enabled (web_context, enable);
@@ -2441,51 +2561,29 @@ webkit_editor_set_editable (EWebKitEditor *wk_editor,
return webkit_web_view_set_editable (WEBKIT_WEB_VIEW (wk_editor), editable);
}
-static gchar *
-webkit_editor_get_current_signature_uid (EContentEditor *editor)
+static gboolean
+webkit_editor_is_ready (EContentEditor *editor)
{
EWebKitEditor *wk_editor;
- gchar *ret_val= NULL;
- GVariant *result;
wk_editor = E_WEBKIT_EDITOR (editor);
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return NULL;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMGetActiveSignatureUid",
- g_variant_new ("(t)", current_page_id (wk_editor)),
- NULL);
-
- if (result) {
- g_variant_get (result, "(s)", &ret_val);
- g_variant_unref (result);
- }
-
- return ret_val;
+ /* Editor is ready just in case that the web view is not loading. */
+ return wk_editor->priv->webkit_load_event == WEBKIT_LOAD_FINISHED &&
+ !webkit_web_view_is_loading (WEBKIT_WEB_VIEW (wk_editor));
}
-static gboolean
-webkit_editor_is_ready (EContentEditor *editor)
+static gchar *
+webkit_editor_get_current_signature_uid (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (editor), NULL);
- /* Editor is ready just in case that the web view is not loading, there
- * is no reload in progress and there is no pending post reload operation
- * and the web extension for the editor is created. */
- return !webkit_web_view_is_loading (WEBKIT_WEB_VIEW (wk_editor)) &&
- !wk_editor->priv->reload_in_progress &&
- wk_editor->priv->web_extension_proxy &&
- (!wk_editor->priv->post_reload_operations || g_queue_is_empty
(wk_editor->priv->post_reload_operations));
+ return webkit_editor_extract_and_free_jsc_string (
+ webkit_editor_call_jsc_sync (E_WEBKIT_EDITOR (editor), "EvoEditor.GetCurrentSignatureUid();"),
+ NULL);
}
-static char *
+static gchar *
webkit_editor_insert_signature (EContentEditor *editor,
const gchar *content,
gboolean is_html,
@@ -2494,101 +2592,42 @@ webkit_editor_insert_signature (EContentEditor *editor,
gboolean *check_if_signature_is_changed,
gboolean *ignore_next_signature_change)
{
- EWebKitEditor *wk_editor;
- gchar *ret_val = NULL;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return NULL;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMInsertSignature",
- g_variant_new (
- "(tsbsbbbnn)",
- current_page_id (wk_editor),
- content ? content : "",
- is_html,
- signature_id,
- *set_signature_from_message,
- *check_if_signature_is_changed,
- *ignore_next_signature_change,
- e_webkit_editor_three_state_to_int16 (e_content_editor_get_start_bottom (editor)),
- e_webkit_editor_three_state_to_int16 (e_content_editor_get_top_signature (editor))),
- NULL);
-
- if (result) {
- g_variant_get (
- result,
- "(sbbb)",
- &ret_val,
- set_signature_from_message,
- check_if_signature_is_changed,
- ignore_next_signature_change);
- g_variant_unref (result);
- }
-
- return ret_val;
-}
-
-static guint
-webkit_editor_get_caret_position (EContentEditor *editor)
-{
- EWebKitEditor *wk_editor;
- GVariant *result;
- guint ret_val = 0;
+ JSCValue *jsc_value;
+ gchar *res = NULL, *tmp = NULL;
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return 0;
- }
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (editor), NULL);
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMGetCaretPosition",
- g_variant_new ("(t)", current_page_id (wk_editor)),
- NULL);
+ if (!is_html && content && *content) {
+ tmp = camel_text_to_html (content, CAMEL_MIME_FILTER_TOHTML_PRE, 0);
- if (result) {
- g_variant_get (result, "(u)", &ret_val);
- g_variant_unref (result);
+ if (tmp)
+ content = tmp;
}
- return ret_val;
-}
-
-static guint
-webkit_editor_get_caret_offset (EContentEditor *editor)
-{
- EWebKitEditor *wk_editor;
- GVariant *result;
- guint ret_val = 0;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
+ jsc_value = webkit_editor_call_jsc_sync (E_WEBKIT_EDITOR (editor),
+ "EvoEditor.InsertSignature(%s, %x, %s, %x, %x, %x, %x, %x, %x);",
+ content ? content : "",
+ is_html,
+ signature_id,
+ *set_signature_from_message,
+ *check_if_signature_is_changed,
+ *ignore_next_signature_change,
+ e_webkit_editor_three_state_to_bool (e_content_editor_get_start_bottom (editor),
"composer-reply-start-bottom"),
+ e_webkit_editor_three_state_to_bool (e_content_editor_get_top_signature (editor),
"composer-top-signature"),
+ !e_webkit_editor_three_state_to_bool (E_THREE_STATE_INCONSISTENT,
"composer-no-signature-delim"));
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return 0;
- }
+ g_free (tmp);
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMGetCaretOffset",
- g_variant_new ("(t)", current_page_id (wk_editor)),
- NULL);
+ if (jsc_value) {
+ *set_signature_from_message = e_web_view_jsc_get_object_property_boolean (jsc_value,
"fromMessage", FALSE);
+ *check_if_signature_is_changed = e_web_view_jsc_get_object_property_boolean (jsc_value,
"checkChanged", FALSE);
+ *ignore_next_signature_change = e_web_view_jsc_get_object_property_boolean (jsc_value,
"ignoreNextChange", FALSE);
+ res = e_web_view_jsc_get_object_property_string (jsc_value, "newUid", NULL);
- if (result) {
- g_variant_get (result, "(u)", &ret_val);
- g_variant_unref (result);
+ g_clear_object (&jsc_value);
}
- return ret_val;
+ return res;
}
static void
@@ -2596,18 +2635,12 @@ webkit_editor_clear_undo_redo_history (EContentEditor *editor)
{
EWebKitEditor *wk_editor;
- wk_editor = E_WEBKIT_EDITOR (editor);
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (editor));
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
+ wk_editor = E_WEBKIT_EDITOR (editor);
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMClearUndoRedoHistory",
- g_variant_new ("(t)", current_page_id (wk_editor)),
- wk_editor->priv->cancellable);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoUndoRedo.Clear();");
}
static void
@@ -2615,22 +2648,13 @@ webkit_editor_replace_caret_word (EContentEditor *editor,
const gchar *replacement)
{
EWebKitEditor *wk_editor;
- GVariant *result;
- wk_editor = E_WEBKIT_EDITOR (editor);
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (editor));
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMReplaceCaretWord",
- g_variant_new ("(ts)", current_page_id (wk_editor), replacement),
- wk_editor->priv->cancellable);
+ wk_editor = E_WEBKIT_EDITOR (editor);
- if (result)
- g_variant_unref (result);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.ReplaceCaretWord(%s);", replacement);
}
static void
@@ -2683,22 +2707,13 @@ webkit_editor_replace (EContentEditor *editor,
const gchar *replacement)
{
EWebKitEditor *wk_editor;
- GVariant *result;
- wk_editor = E_WEBKIT_EDITOR (editor);
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (editor));
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMSelectionReplace",
- g_variant_new ("(ts)", current_page_id (wk_editor), replacement),
- wk_editor->priv->cancellable);
+ wk_editor = E_WEBKIT_EDITOR (editor);
- if (result)
- g_variant_unref (result);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.ReplaceSelection(%s);", replacement);
}
static gboolean
@@ -2723,11 +2738,8 @@ webkit_find_controller_found_text_cb (WebKitFindController *find_controller,
/* Repeatedly search for 'word', then replace selection by
* 'replacement'. Repeat until there's at least one occurrence of
* 'word' in the document */
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMSelectionReplace",
- g_variant_new ("(ts)", current_page_id (wk_editor), wk_editor->priv->replace_with),
- wk_editor->priv->cancellable);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.ReplaceSelection(%s);", wk_editor->priv->replace_with);
g_idle_add ((GSourceFunc) search_next_on_idle, wk_editor);
} else {
@@ -2744,25 +2756,8 @@ webkit_find_controller_failed_to_find_text_cb (WebKitFindController *find_contro
if (wk_editor->priv->performing_replace_all) {
guint replaced_count = wk_editor->priv->replaced_count;
- if (replaced_count > 0) {
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- } else {
- GVariant *result;
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMInsertReplaceAllHistoryEvent",
- g_variant_new ("(tss)",
- current_page_id (wk_editor),
- webkit_find_controller_get_search_text (find_controller),
- wk_editor->priv->replace_with),
- NULL);
-
- if (result)
- g_variant_unref (result);
- }
- }
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_GROUP, %s);", "ReplaceAll");
webkit_editor_finish_search (wk_editor);
e_content_editor_emit_replace_all_done (E_CONTENT_EDITOR (wk_editor), replaced_count);
@@ -2857,6 +2852,9 @@ webkit_editor_replace_all (EContentEditor *editor,
wk_editor->priv->performing_replace_all = TRUE;
wk_editor->priv->replaced_count = 0;
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_GROUP, %s);", "ReplaceAll");
+
webkit_web_view_execute_editing_command (WEBKIT_WEB_VIEW (wk_editor),
"MoveToBeginningOfDocumentAndModifySelection");
webkit_find_controller_search (wk_editor->priv->find_controller, find_text, wk_options, G_MAXUINT);
@@ -2867,10 +2865,12 @@ webkit_editor_selection_save (EContentEditor *editor)
{
EWebKitEditor *wk_editor;
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (editor));
+
wk_editor = E_WEBKIT_EDITOR (editor);
- webkit_editor_call_simple_extension_function (
- wk_editor, "DOMSaveSelection");
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.StoreSelection();");
}
static void
@@ -2878,210 +2878,186 @@ webkit_editor_selection_restore (EContentEditor *editor)
{
EWebKitEditor *wk_editor;
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (editor));
+
wk_editor = E_WEBKIT_EDITOR (editor);
- webkit_editor_call_simple_extension_function (
- wk_editor, "DOMRestoreSelection");
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.RestoreSelection();");
}
static void
-webkit_editor_delete_cell_contents (EContentEditor *editor)
+webkit_editor_on_dialog_open (EContentEditor *editor,
+ const gchar *name)
{
- EWebKitEditor *wk_editor;
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- wk_editor = E_WEBKIT_EDITOR (editor);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.OnDialogOpen(%s);", name);
+
+ if (g_strcmp0 (name, E_CONTENT_EDITOR_DIALOG_SPELLCHECK) == 0) {
+ gchar **strv;
+
+ strv = e_spell_checker_list_active_languages (wk_editor->priv->spell_checker, NULL);
+
+ if (strv) {
+ gint ii, len = 0;
+ gchar *langs, *ptr;
+
+ for (ii = 0; strv[ii]; ii++) {
+ len += strlen (strv[ii]) + 1;
+ }
+
+ len++;
+
+ langs = g_slice_alloc0 (len);
+ ptr = langs;
+
+ for (ii = 0; strv[ii]; ii++) {
+ strcpy (ptr, strv[ii]);
+ ptr += strlen (strv[ii]);
+ if (strv[ii + 1]) {
+ *ptr = '|';
+ ptr++;
+ }
+ }
+
+ *ptr = '\0';
+
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.SetSpellCheckLanguages(%s);", langs);
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorDialogDeleteCellContents");
+ g_slice_free1 (len, langs);
+ g_strfreev (strv);
+ }
+ }
}
static void
-webkit_editor_delete_column (EContentEditor *editor)
+webkit_editor_on_dialog_close (EContentEditor *editor,
+ const gchar *name)
{
- EWebKitEditor *wk_editor;
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- wk_editor = E_WEBKIT_EDITOR (editor);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.OnDialogClose(%s);", name);
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorDialogDeleteColumn");
+ if (g_strcmp0 (name, E_CONTENT_EDITOR_DIALOG_SPELLCHECK) == 0 ||
+ g_strcmp0 (name, E_CONTENT_EDITOR_DIALOG_FIND) == 0 ||
+ g_strcmp0 (name, E_CONTENT_EDITOR_DIALOG_REPLACE) == 0)
+ webkit_editor_finish_search (E_WEBKIT_EDITOR (editor));
}
static void
-webkit_editor_delete_row (EContentEditor *editor)
+webkit_editor_delete_cell_contents (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- wk_editor = E_WEBKIT_EDITOR (editor);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.DialogUtilsTableDeleteCellContent();");
+}
+
+static void
+webkit_editor_delete_column (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorDialogDeleteRow");
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.DialogUtilsTableDeleteColumn();");
}
static void
-webkit_editor_delete_table (EContentEditor *editor)
+webkit_editor_delete_row (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- wk_editor = E_WEBKIT_EDITOR (editor);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.DialogUtilsTableDeleteRow();");
+}
+
+static void
+webkit_editor_delete_table (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorDialogDeleteTable");
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.DialogUtilsTableDelete();");
}
static void
webkit_editor_insert_column_after (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorDialogInsertColumnAfter");
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.DialogUtilsTableInsert(%s, %d);", "column", +1);
}
static void
webkit_editor_insert_column_before (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorDialogInsertColumnBefore");
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.DialogUtilsTableInsert(%s, %d);", "column", -1);
}
-
static void
webkit_editor_insert_row_above (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorDialogInsertRowAbove");
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.DialogUtilsTableInsert(%s, %d);", "row", -1);
}
static void
webkit_editor_insert_row_below (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorDialogInsertRowBelow");
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.DialogUtilsTableInsert(%s, %d);", "row", +1);
}
-static gboolean
-webkit_editor_on_h_rule_dialog_open (EContentEditor *editor)
+static void
+webkit_editor_h_rule_set_align (EContentEditor *editor,
+ const gchar *value)
{
- EWebKitEditor *wk_editor;
- gboolean value = FALSE;
- GVariant *result;
+ webkit_editor_dialog_utils_set_attribute (E_WEBKIT_EDITOR (editor), NULL, "align", value);
+}
- wk_editor = E_WEBKIT_EDITOR (editor);
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return FALSE;
- }
+static gchar *
+webkit_editor_h_rule_get_align (EContentEditor *editor)
+{
+ gchar *value;
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorHRuleDialogFindHRule",
- g_variant_new ("(t)", current_page_id (wk_editor)),
- NULL);
+ value = webkit_editor_dialog_utils_get_attribute (E_WEBKIT_EDITOR (editor), NULL, "align");
- if (result) {
- g_variant_get (result, "(b)", &value);
- g_variant_unref (result);
+ if (!value || !*value) {
+ g_free (value);
+ value = g_strdup ("center");
}
return value;
}
static void
-webkit_editor_on_h_rule_dialog_close (EContentEditor *editor)
+webkit_editor_h_rule_set_size (EContentEditor *editor,
+ gint value)
{
- EWebKitEditor *wk_editor;
+ webkit_editor_dialog_utils_set_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "size", value);
+}
- wk_editor = E_WEBKIT_EDITOR (editor);
+static gint
+webkit_editor_h_rule_get_size (EContentEditor *editor)
+{
+ gint size;
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorHRuleDialogOnClose");
-}
+ size = webkit_editor_dialog_utils_get_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "size", 2);
-static void
-webkit_editor_h_rule_set_align (EContentEditor *editor,
- const gchar *value)
-{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- webkit_editor_set_element_attribute (
- wk_editor, "#-x-evo-current-hr", "align", value);
-}
-
-static gchar *
-webkit_editor_h_rule_get_align (EContentEditor *editor)
-{
- EWebKitEditor *wk_editor;
- gchar *value = NULL;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- result = webkit_editor_get_element_attribute (
- wk_editor, "#-x-evo-current-hr", "align");
- if (result) {
- g_variant_get (result, "(s)", &value);
- g_variant_unref (result);
- }
-
- return value;
-}
-
-static void
-webkit_editor_h_rule_set_size (EContentEditor *editor,
- gint value)
-{
- EWebKitEditor *wk_editor;
- gchar *size;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- size = g_strdup_printf ("%d", value);
-
- webkit_editor_set_element_attribute (
- wk_editor, "#-x-evo-current-hr", "size", size);
-
- g_free (size);
-}
-
-static gint
-webkit_editor_h_rule_get_size (EContentEditor *editor)
-{
- EWebKitEditor *wk_editor;
- gint size = 0;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- result = webkit_editor_get_element_attribute (
- wk_editor, "#-x-evo-current-hr", "size");
- if (result) {
- const gchar *value;
-
- g_variant_get (result, "(&s)", &value);
- if (value && *value)
- size = atoi (value);
-
- if (size == 0)
- size = 2;
-
- g_variant_unref (result);
- }
+ if (!size)
+ size = 2;
return size;
}
@@ -3091,45 +3067,20 @@ webkit_editor_h_rule_set_width (EContentEditor *editor,
gint value,
EContentEditorUnit unit)
{
- EWebKitEditor *wk_editor;
- gchar *width;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- width = g_strdup_printf (
- "%d%s",
- value,
- (unit == E_CONTENT_EDITOR_UNIT_PIXEL) ? "px" : "%");
-
- webkit_editor_set_element_attribute (
- wk_editor, "#-x-evo-current-hr", "width", width);
-
- g_free (width);
+ webkit_editor_dialog_utils_set_attribute_with_unit (E_WEBKIT_EDITOR (editor), NULL, "width", value,
unit);
}
static gint
webkit_editor_h_rule_get_width (EContentEditor *editor,
EContentEditorUnit *unit)
{
- EWebKitEditor *wk_editor;
- gint value = 0;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
+ gint value;
- *unit = E_CONTENT_EDITOR_UNIT_PIXEL;
+ value = webkit_editor_dialog_utils_get_attribute_with_unit (E_WEBKIT_EDITOR (editor), NULL, "width",
0, unit);
- result = webkit_editor_get_element_attribute (
- wk_editor, "#-x-evo-current-hr", "width");
- if (result) {
- const gchar *width;
- g_variant_get (result, "(&s)", &width);
- if (width && *width) {
- value = atoi (width);
- if (strstr (width, "%"))
- *unit = E_CONTENT_EDITOR_UNIT_PERCENTAGE;
- }
- g_variant_unref (result);
+ if (!value && *unit == E_CONTENT_EDITOR_UNIT_AUTO) {
+ *unit = E_CONTENT_EDITOR_UNIT_PERCENTAGE;
+ value = 100;
}
return value;
@@ -3139,89 +3090,42 @@ static void
webkit_editor_h_rule_set_no_shade (EContentEditor *editor,
gboolean value)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- if (value)
- webkit_editor_set_element_attribute (
- wk_editor, "#-x-evo-current-hr", "noshade", "");
- else
- webkit_editor_remove_element_attribute (
- wk_editor, "#-x-evo-current-hr", "noshade");
+ webkit_editor_dialog_utils_set_attribute (E_WEBKIT_EDITOR (editor), NULL, "noshade", value ? "" :
NULL);
}
static gboolean
webkit_editor_h_rule_get_no_shade (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
- gboolean no_shade = FALSE;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return FALSE;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "ElementHasAttribute",
- g_variant_new ("(tss)", current_page_id (wk_editor), "-x-evo-current-hr", "noshade"),
- NULL);
-
- if (result) {
- g_variant_get (result, "(b)", &no_shade);
- g_variant_unref (result);
- }
-
- return no_shade;
-}
-
-static void
-webkit_editor_on_image_dialog_open (EContentEditor *editor)
-{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorImageDialogMarkImage");
+ return webkit_editor_dialog_utils_has_attribute (E_WEBKIT_EDITOR (editor), "noshade");
}
static void
-webkit_editor_on_image_dialog_close (EContentEditor *editor)
+webkit_editor_insert_image (EContentEditor *editor,
+ const gchar *image_uri)
{
- EWebKitEditor *wk_editor;
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
+ gint width = -1, height = -1;
- wk_editor = E_WEBKIT_EDITOR (editor);
+ g_return_if_fail (image_uri != NULL);
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorImageDialogSaveHistoryOnExit");
-}
+ if (g_ascii_strncasecmp (image_uri, "file://", 7) == 0) {
+ gchar *filename;
-static void
-webkit_editor_insert_image (EContentEditor *editor,
- const gchar *image_uri)
-{
- EWebKitEditor *wk_editor;
+ filename = g_filename_from_uri (image_uri, NULL, NULL);
- wk_editor = E_WEBKIT_EDITOR (editor);
+ if (filename) {
+ if (!gdk_pixbuf_get_file_info (filename, &width, &height)) {
+ width = -1;
+ height = -1;
+ }
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
+ g_free (filename);
+ }
}
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMSelectionInsertImage",
- g_variant_new ("(ts)", current_page_id (wk_editor), image_uri),
- wk_editor->priv->cancellable);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.InsertImage(%s, %d, %d);",
+ image_uri, width, height);
}
static void
@@ -3229,565 +3133,205 @@ webkit_editor_replace_image_src (EWebKitEditor *wk_editor,
const gchar *selector,
const gchar *image_uri)
{
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "DOMReplaceImageSrc",
- g_variant_new ("(tss)", current_page_id (wk_editor), selector, image_uri),
- wk_editor->priv->cancellable);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.ReplaceImageSrc(%s, %s);",
+ selector,
+ image_uri);
}
static void
webkit_editor_image_set_src (EContentEditor *editor,
const gchar *value)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- webkit_editor_replace_image_src (
- wk_editor, "img#-x-evo-current-img", value);
+ webkit_editor_dialog_utils_set_attribute (E_WEBKIT_EDITOR (editor), NULL, "src", value);
}
static gchar *
webkit_editor_image_get_src (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- gchar *value = NULL;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- result = webkit_editor_get_element_attribute (
- wk_editor, "#-x-evo-current-img", "data-uri");
-
- if (result) {
- g_variant_get (result, "(s)", &value);
- g_variant_unref (result);
- }
-
- return value;
+ return webkit_editor_dialog_utils_get_attribute (E_WEBKIT_EDITOR (editor), NULL, "src");
}
static void
webkit_editor_image_set_alt (EContentEditor *editor,
const gchar *value)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- webkit_editor_set_element_attribute (
- wk_editor, "#-x-evo-current-img", "alt", value);
+ webkit_editor_dialog_utils_set_attribute (E_WEBKIT_EDITOR (editor), NULL, "alt", value);
}
static gchar *
webkit_editor_image_get_alt (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- gchar *value = NULL;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- result = webkit_editor_get_element_attribute (
- wk_editor, "#-x-evo-current-img", "alt");
-
- if (result) {
- g_variant_get (result, "(s)", &value);
- g_variant_unref (result);
- }
-
- return value;
+ return webkit_editor_dialog_utils_get_attribute (E_WEBKIT_EDITOR (editor), NULL, "alt");
}
static void
webkit_editor_image_set_url (EContentEditor *editor,
const gchar *value)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorImageDialogSetElementUrl",
- g_variant_new ("(ts)", current_page_id (wk_editor), value),
- wk_editor->priv->cancellable);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.DialogUtilsSetImageUrl(%s);",
+ value);
}
static gchar *
webkit_editor_image_get_url (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
- gchar *value = NULL;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return NULL;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorImageDialogGetElementUrl",
- g_variant_new ("(t)", current_page_id (wk_editor)),
+ return webkit_editor_extract_and_free_jsc_string (
+ webkit_editor_call_jsc_sync (E_WEBKIT_EDITOR (editor), "EvoEditor.DialogUtilsGetImageUrl();"),
NULL);
-
- if (result) {
- g_variant_get (result, "(s)", &value);
- g_variant_unref (result);
- }
-
- return value;
}
static void
webkit_editor_image_set_vspace (EContentEditor *editor,
gint value)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "ImageElementSetVSpace",
- g_variant_new (
- "(tsi)", current_page_id (wk_editor), "-x-evo-current-img", value),
- wk_editor->priv->cancellable);
+ webkit_editor_dialog_utils_set_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "vspace", value);
}
static gint
webkit_editor_image_get_vspace (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
- gint value = 0;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return 0;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "ImageElementGetVSpace",
- g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-img"),
- NULL);
-
- if (result) {
- g_variant_get (result, "(i)", &value);
- g_variant_unref (result);
- }
-
- return value;
+ return webkit_editor_dialog_utils_get_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "vspace", 0);
}
static void
webkit_editor_image_set_hspace (EContentEditor *editor,
gint value)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "ImageElementSetHSpace",
- g_variant_new (
- "(tsi)", current_page_id (wk_editor), "-x-evo-current-img", value),
- wk_editor->priv->cancellable);
+ webkit_editor_dialog_utils_set_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "hspace", value);
}
static gint
webkit_editor_image_get_hspace (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
- gint value = 0;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return 0;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "ImageElementGetHSpace",
- g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-img"),
- NULL);
-
- if (result) {
- g_variant_get (result, "(i)", &value);
- g_variant_unref (result);
- }
-
- return value;
+ return webkit_editor_dialog_utils_get_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "hspace", 0);
}
static void
webkit_editor_image_set_border (EContentEditor *editor,
gint value)
{
- EWebKitEditor *wk_editor;
- gchar *border;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- border = g_strdup_printf ("%d", value);
-
- webkit_editor_set_element_attribute (
- wk_editor, "#-x-evo-current-img", "border", border);
-
- g_free (border);
+ webkit_editor_dialog_utils_set_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "border", value);
}
static gint
webkit_editor_image_get_border (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- gint value = 0;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- result = webkit_editor_get_element_attribute (
- wk_editor, "#-x-evo-current-img", "border");
-
- if (result) {
- const gchar *border;
- g_variant_get (result, "(&s)", &border);
- if (border && *border)
- value = atoi (border);
- g_variant_unref (result);
- }
-
- return value;
+ return webkit_editor_dialog_utils_get_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "border", 0);
}
static void
webkit_editor_image_set_align (EContentEditor *editor,
const gchar *value)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- webkit_editor_set_element_attribute (
- wk_editor, "#-x-evo-current-img", "align", value);
+ webkit_editor_dialog_utils_set_attribute (E_WEBKIT_EDITOR (editor), NULL, "align", value);
}
static gchar *
webkit_editor_image_get_align (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- gchar *value = NULL;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- result = webkit_editor_get_element_attribute (
- wk_editor, "#-x-evo-current-img", "align");
-
- if (result) {
- g_variant_get (result, "(s)", &value);
- g_variant_unref (result);
- }
-
- return value;
+ return webkit_editor_dialog_utils_get_attribute (E_WEBKIT_EDITOR (editor), NULL, "align");
}
static gint32
webkit_editor_image_get_natural_width (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
- gint32 value = 0;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return 0;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "ImageElementGetNaturalWidth",
- g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-img"),
- NULL);
-
- if (result) {
- g_variant_get (result, "(i)", &value);
- g_variant_unref (result);
- }
-
- return value;
+ return webkit_editor_extract_and_free_jsc_int32 (
+ webkit_editor_call_jsc_sync (E_WEBKIT_EDITOR (editor),
"EvoEditor.DialogUtilsGetImageWidth(true);"),
+ 0);
}
static gint32
webkit_editor_image_get_natural_height (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
- gint32 value = 0;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return 0;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "ImageElementGetNaturalHeight",
- g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-img"),
- NULL);
-
- if (result) {
- g_variant_get (result, "(i)", &value);
- g_variant_unref (result);
- }
-
- return value;
+ return webkit_editor_extract_and_free_jsc_int32 (
+ webkit_editor_call_jsc_sync (E_WEBKIT_EDITOR (editor),
"EvoEditor.DialogUtilsGetImageHeight(true);"),
+ 0);
}
static void
webkit_editor_image_set_height (EContentEditor *editor,
gint value)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "ImageElementSetHeight",
- g_variant_new (
- "(tsi)", current_page_id (wk_editor), "-x-evo-current-img", value),
- wk_editor->priv->cancellable);
+ webkit_editor_dialog_utils_set_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "height", value);
}
static void
webkit_editor_image_set_width (EContentEditor *editor,
gint value)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "ImageElementSetWidth",
- g_variant_new (
- "(tsi)", current_page_id (wk_editor), "-x-evo-current-img", value),
- wk_editor->priv->cancellable);
-}
+ webkit_editor_dialog_utils_set_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "width", value);
+}
static void
webkit_editor_image_set_height_follow (EContentEditor *editor,
gboolean value)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (value)
- webkit_editor_set_element_attribute (
- wk_editor, "#-x-evo-current-img", "style", "height: auto;");
- else
- webkit_editor_remove_element_attribute (
- wk_editor, "#-x-evo-current-img", "style");
+ webkit_editor_dialog_utils_set_attribute (E_WEBKIT_EDITOR (editor), NULL, "style", value ? "height:
auto;" : NULL);
}
static void
webkit_editor_image_set_width_follow (EContentEditor *editor,
gboolean value)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (value)
- webkit_editor_set_element_attribute (
- wk_editor, "#-x-evo-current-img", "style", "width: auto;");
- else
- webkit_editor_remove_element_attribute (
- wk_editor, "#-x-evo-current-img", "style");
+ webkit_editor_dialog_utils_set_attribute (E_WEBKIT_EDITOR (editor), NULL, "style", value ? "width:
auto;" : NULL);
}
static gint32
webkit_editor_image_get_width (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
- gint32 value = 0;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return 0;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "ImageElementGetWidth",
- g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-img"),
- NULL);
-
- if (result) {
- g_variant_get (result, "(i)", &value);
- g_variant_unref (result);
- }
-
- return value;
+ return webkit_editor_extract_and_free_jsc_int32 (
+ webkit_editor_call_jsc_sync (E_WEBKIT_EDITOR (editor),
"EvoEditor.DialogUtilsGetImageWidth(false);"),
+ 0);
}
static gint32
webkit_editor_image_get_height (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
- gint32 value = 0;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return 0;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "ImageElementGetHeight",
- g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-img"),
- NULL);
-
- if (result) {
- g_variant_get (result, "(i)", &value);
- g_variant_unref (result);
- }
-
- return value;
+ return webkit_editor_extract_and_free_jsc_int32 (
+ webkit_editor_call_jsc_sync (E_WEBKIT_EDITOR (editor),
"EvoEditor.DialogUtilsGetImageHeight(false);"),
+ 0);
}
static void
webkit_editor_selection_unlink (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorLinkDialogUnlink");
-}
-
-static void
-webkit_editor_on_link_dialog_open (EContentEditor *editor)
-{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorLinkDialogOnOpen");
-}
-
-static void
-webkit_editor_on_link_dialog_close (EContentEditor *editor)
-{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorLinkDialogOnClose");
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.Unlink();");
}
static void
-webkit_editor_link_set_values (EContentEditor *editor,
- const gchar *href,
- const gchar *text)
+webkit_editor_link_set_properties (EContentEditor *editor,
+ const gchar *href,
+ const gchar *text)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorLinkDialogOk",
- g_variant_new ("(tss)", current_page_id (wk_editor), href, text),
- wk_editor->priv->cancellable);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.LinkSetProperties(%s, %s);",
+ href, text);
}
static void
-webkit_editor_link_get_values (EContentEditor *editor,
- gchar **href,
- gchar **text)
+webkit_editor_link_get_properties (EContentEditor *editor,
+ gchar **href,
+ gchar **text)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
+ JSCValue *result;
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorLinkDialogShow",
- g_variant_new ("(t)", current_page_id (wk_editor)),
- NULL);
+ result = webkit_editor_call_jsc_sync (wk_editor, "EvoEditor.LinkGetProperties();");
if (result) {
- g_variant_get (result, "(ss)", href, text);
- g_variant_unref (result);
+ *href = e_web_view_jsc_get_object_property_string (result, "href", NULL);
+ *text = e_web_view_jsc_get_object_property_string (result, "text", NULL);
+
+ g_clear_object (&result);
} else {
*href = NULL;
*text = NULL;
@@ -3800,8 +3344,9 @@ webkit_editor_set_alignment (EWebKitEditor *wk_editor,
{
g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
- webkit_editor_set_format_int (
- wk_editor, "DOMSelectionSetAlignment", (gint32) value);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.SetAlignment(%d);",
+ value);
}
static EContentEditorAlignment
@@ -3818,8 +3363,9 @@ webkit_editor_set_block_format (EWebKitEditor *wk_editor,
{
g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
- webkit_editor_set_format_int (
- wk_editor, "DOMSelectionSetBlockFormat", (gint32) value);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.SetBlockFormat(%d);",
+ value);
}
static EContentEditorBlockFormat
@@ -3834,27 +3380,25 @@ static void
webkit_editor_set_background_color (EWebKitEditor *wk_editor,
const GdkRGBA *value)
{
- gchar *color;
+ gchar color[64];
g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
- if (gdk_rgba_equal (value, wk_editor->priv->background_color))
+ if ((!value && !wk_editor->priv->background_color) ||
+ (value && wk_editor->priv->background_color && gdk_rgba_equal (value,
wk_editor->priv->background_color)))
return;
- color = g_strdup_printf ("#%06x", e_rgba_to_value (value));
-
- if (wk_editor->priv->background_color)
- gdk_rgba_free (wk_editor->priv->background_color);
-
- wk_editor->priv->background_color = gdk_rgba_copy (value);
-
- webkit_editor_set_format_string (
- wk_editor,
- "background-color",
- "DOMSelectionSetBackgroundColor",
- color);
+ if (value && value->alpha > 1e-9) {
+ webkit_editor_utils_color_to_string (color, sizeof (color), value);
+ g_clear_pointer (&wk_editor->priv->background_color, gdk_rgba_free);
+ wk_editor->priv->background_color = gdk_rgba_copy (value);
+ } else {
+ g_snprintf (color, sizeof (color), "inherit");
+ g_clear_pointer (&wk_editor->priv->background_color, gdk_rgba_free);
+ wk_editor->priv->background_color = NULL;
+ }
- g_free (color);
+ webkit_web_view_execute_editing_command_with_argument (WEBKIT_WEB_VIEW (wk_editor), "BackColor",
color);
}
static const GdkRGBA *
@@ -3862,13 +3406,8 @@ webkit_editor_get_background_color (EWebKitEditor *wk_editor)
{
g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), NULL);
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return NULL;
- }
-
- if (!wk_editor->priv->html_mode || !wk_editor->priv->background_color)
- return &white;
+ if (!wk_editor->priv->background_color)
+ return &transparent;
return wk_editor->priv->background_color;
}
@@ -3879,10 +3418,9 @@ webkit_editor_set_font_name (EWebKitEditor *wk_editor,
{
g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
- wk_editor->priv->font_name = g_strdup (value);
-
- webkit_editor_set_format_string (
- wk_editor, "font-name", "DOMSelectionSetFontName", value);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.SetFontName(%s);",
+ value ? value : "");
}
static const gchar *
@@ -3890,6 +3428,9 @@ webkit_editor_get_font_name (EWebKitEditor *wk_editor)
{
g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), NULL);
+ if (!wk_editor->priv->html_mode)
+ return NULL;
+
return wk_editor->priv->font_name;
}
@@ -3897,27 +3438,18 @@ static void
webkit_editor_set_font_color (EWebKitEditor *wk_editor,
const GdkRGBA *value)
{
- gchar *color;
+ gchar color[64];
g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
- if (gdk_rgba_equal (value, wk_editor->priv->font_color))
+ if ((!value && !wk_editor->priv->font_color) ||
+ (value && wk_editor->priv->font_color && gdk_rgba_equal (value, wk_editor->priv->font_color)))
return;
- color = g_strdup_printf ("#%06x", e_rgba_to_value (value));
-
- if (wk_editor->priv->font_color)
- gdk_rgba_free (wk_editor->priv->font_color);
+ webkit_editor_utils_color_to_string (color, sizeof (color), value);
- wk_editor->priv->font_color = gdk_rgba_copy (value);
-
- webkit_editor_set_format_string (
- wk_editor,
- "font-color",
- "DOMSelectionSetFontColor",
- color);
-
- g_free (color);
+ webkit_web_view_execute_editing_command_with_argument (WEBKIT_WEB_VIEW (wk_editor), "ForeColor",
+ webkit_editor_utils_color_to_string (color, sizeof (color), value));
}
static const GdkRGBA *
@@ -3925,11 +3457,6 @@ webkit_editor_get_font_color (EWebKitEditor *wk_editor)
{
g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), NULL);
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return NULL;
- }
-
if (!wk_editor->priv->html_mode || !wk_editor->priv->font_color)
return &black;
@@ -3940,15 +3467,21 @@ static void
webkit_editor_set_font_size (EWebKitEditor *wk_editor,
gint value)
{
+ gchar sz[2] = { 0, 0 };
+
g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
if (wk_editor->priv->font_size == value)
return;
- wk_editor->priv->font_size = value;
+ if (value >= 1 && value <= 7) {
+ sz[0] = '0' + value;
+ } else {
+ g_warn_if_reached ();
+ return;
+ }
- webkit_editor_set_format_int (
- wk_editor, "DOMSelectionSetFontSize", value);
+ webkit_web_view_execute_editing_command_with_argument (WEBKIT_WEB_VIEW (wk_editor), "FontSize", sz);
}
static gint
@@ -3961,123 +3494,60 @@ webkit_editor_get_font_size (EWebKitEditor *wk_editor)
static void
webkit_editor_set_style_flag (EWebKitEditor *wk_editor,
- EContentEditorStyleFlags flag,
- gboolean do_set,
- const gchar *dom_function_name)
+ EWebKitEditorStyleFlags flag,
+ gboolean do_set)
{
g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
- if (((wk_editor->priv->style_flags & flag) != 0 ? 1 : 0) == (do_set ? 1 : 0))
+ if (((wk_editor->priv->temporary_style_flags & flag) != 0 ? 1 : 0) == (do_set ? 1 : 0))
return;
- wk_editor->priv->style_flags = (wk_editor->priv->style_flags & ~flag) | (do_set ? flag : 0);
-
- webkit_editor_set_format_boolean (wk_editor, dom_function_name, do_set);
+ switch (flag) {
+ case E_WEBKIT_EDITOR_STYLE_NONE:
+ break;
+ case E_WEBKIT_EDITOR_STYLE_IS_BOLD:
+ webkit_web_view_execute_editing_command (WEBKIT_WEB_VIEW (wk_editor), "Bold");
+ break;
+ case E_WEBKIT_EDITOR_STYLE_IS_ITALIC:
+ webkit_web_view_execute_editing_command (WEBKIT_WEB_VIEW (wk_editor), "Italic");
+ break;
+ case E_WEBKIT_EDITOR_STYLE_IS_UNDERLINE:
+ webkit_web_view_execute_editing_command (WEBKIT_WEB_VIEW (wk_editor), "Underline");
+ break;
+ case E_WEBKIT_EDITOR_STYLE_IS_STRIKETHROUGH:
+ webkit_web_view_execute_editing_command (WEBKIT_WEB_VIEW (wk_editor), "Strikethrough");
+ break;
+ case E_WEBKIT_EDITOR_STYLE_IS_SUBSCRIPT:
+ webkit_web_view_execute_editing_command (WEBKIT_WEB_VIEW (wk_editor), "Subscript");
+ break;
+ case E_WEBKIT_EDITOR_STYLE_IS_SUPERSCRIPT:
+ webkit_web_view_execute_editing_command (WEBKIT_WEB_VIEW (wk_editor), "Superscript");
+ break;
+ }
+
+ wk_editor->priv->temporary_style_flags = (wk_editor->priv->temporary_style_flags & (~flag)) | (do_set
? flag : 0);
}
static gboolean
webkit_editor_get_style_flag (EWebKitEditor *wk_editor,
- EContentEditorStyleFlags flag)
+ EWebKitEditorStyleFlags flag)
{
g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
return (wk_editor->priv->style_flags & flag) != 0;
}
-static void
-webkit_editor_on_page_dialog_open (EContentEditor *editor)
-{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorPageDialogSaveHistory");
-}
-
-static void
-webkit_editor_on_page_dialog_close (EContentEditor *editor)
-{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorPageDialogSaveHistoryOnExit");
-}
-
static gchar *
webkit_editor_page_get_background_image_uri (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return NULL;
-
- result = webkit_editor_get_element_attribute (wk_editor, "body", "data-uri");
- if (result) {
- gchar *value;
-
- g_variant_get (result, "(s)", &value);
- g_variant_unref (result);
- }
-
- return NULL;
+ return webkit_editor_dialog_utils_get_attribute (E_WEBKIT_EDITOR (editor), "body", "background");
}
static void
webkit_editor_page_set_background_image_uri (EContentEditor *editor,
const gchar *uri)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return;
-
- if (uri && *uri)
- webkit_editor_replace_image_src (wk_editor, "body", uri);
- else {
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "RemoveImageAttributesFromElementBySelector",
- g_variant_new ("(ts)", current_page_id (wk_editor), "body"),
- wk_editor->priv->cancellable);
- }
-}
-
-static void
-webkit_editor_on_cell_dialog_open (EContentEditor *editor)
-{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorCellDialogMarkCurrentCellElement",
- g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-cell"),
- wk_editor->priv->cancellable);
-}
-
-static void
-webkit_editor_on_cell_dialog_close (EContentEditor *editor)
-{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorCellDialogSaveHistoryOnExit");
+ webkit_editor_replace_image_src (E_WEBKIT_EDITOR (editor), "body", uri);
}
static void
@@ -4085,45 +3555,13 @@ webkit_editor_cell_set_v_align (EContentEditor *editor,
const gchar *value,
EContentEditorScope scope)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return;
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorCellDialogSetElementVAlign",
- g_variant_new ("(tsi)", current_page_id (wk_editor), value, (gint32) scope),
- wk_editor->priv->cancellable);
+ webkit_editor_dialog_utils_set_table_attribute (E_WEBKIT_EDITOR (editor), scope, "valign", value &&
*value ? value : NULL);
}
static gchar *
webkit_editor_cell_get_v_align (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- gchar *value = NULL;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return NULL;
-
- result = webkit_editor_get_element_attribute (
- wk_editor, "#-x-evo-current-cell", "valign");
- if (result) {
- g_variant_get (result, "(s)", &value);
- g_variant_unref (result);
- }
-
- return value;
+ return webkit_editor_dialog_utils_get_attribute (E_WEBKIT_EDITOR (editor), NULL, "valign");
}
static void
@@ -4131,45 +3569,13 @@ webkit_editor_cell_set_align (EContentEditor *editor,
const gchar *value,
EContentEditorScope scope)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return;
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorCellDialogSetElementAlign",
- g_variant_new ("(tsi)", current_page_id (wk_editor), value, (gint32) scope),
- wk_editor->priv->cancellable);
+ webkit_editor_dialog_utils_set_table_attribute (E_WEBKIT_EDITOR (editor), scope, "align", value &&
*value ? value : NULL);
}
static gchar *
webkit_editor_cell_get_align (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- gchar *value = NULL;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return NULL;
-
- result = webkit_editor_get_element_attribute (
- wk_editor, "#-x-evo-current-cell", "align");
- if (result) {
- g_variant_get (result, "(s)", &value);
- g_variant_unref (result);
- }
-
- return value;
+ return webkit_editor_dialog_utils_get_attribute (E_WEBKIT_EDITOR (editor), NULL, "align");
}
static void
@@ -4177,53 +3583,19 @@ webkit_editor_cell_set_wrap (EContentEditor *editor,
gboolean value,
EContentEditorScope scope)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return;
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorCellDialogSetElementNoWrap",
- g_variant_new ("(tbi)", current_page_id (wk_editor), !value, (gint32) scope),
- wk_editor->priv->cancellable);
+ webkit_editor_dialog_utils_set_table_attribute (E_WEBKIT_EDITOR (editor), scope, "nowrap", !value ?
"" : NULL);
}
static gboolean
webkit_editor_cell_get_wrap (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
gboolean value = FALSE;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return FALSE;
+ gchar *nowrap;
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return FALSE;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "TableCellElementGetNoWrap",
- g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-cell"),
- NULL);
+ nowrap = webkit_editor_dialog_utils_get_attribute (E_WEBKIT_EDITOR (editor), NULL, "nowrap");
+ value = !nowrap;
- if (result) {
- g_variant_get (result, "(b)", &value);
- value = !value;
- g_variant_unref (result);
- }
+ g_free (nowrap);
return value;
}
@@ -4235,205 +3607,54 @@ webkit_editor_cell_set_header_style (EContentEditor *editor,
{
EWebKitEditor *wk_editor;
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (editor));
- if (!wk_editor->priv->html_mode)
- return;
+ wk_editor = E_WEBKIT_EDITOR (editor);
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorCellDialogSetElementHeaderStyle",
- g_variant_new ("(tbi)", current_page_id (wk_editor), value, (gint32) scope),
- wk_editor->priv->cancellable);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.DialogUtilsTableSetHeader(%d, %x);",
+ scope, value);
}
static gboolean
webkit_editor_cell_is_header (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- gboolean value = FALSE;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return FALSE;
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return FALSE;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "ElementGetTagName",
- g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-cell"),
- NULL);
-
- if (result) {
- const gchar *tag_name;
-
- g_variant_get (result, "(&s)", &tag_name);
- value = g_ascii_strncasecmp (tag_name, "TH", 2) == 0;
- g_variant_unref (result);
- }
-
- return value;
+ return webkit_editor_extract_and_free_jsc_boolean (
+ webkit_editor_call_jsc_sync (E_WEBKIT_EDITOR (editor),
+ "EvoEditor.DialogUtilsTableGetCellIsHeader();"),
+ FALSE);
}
static gint
webkit_editor_cell_get_width (EContentEditor *editor,
EContentEditorUnit *unit)
{
- EWebKitEditor *wk_editor;
- gint value = 0;
- GVariant *result;
+ return webkit_editor_dialog_utils_get_attribute_with_unit (E_WEBKIT_EDITOR (editor), NULL, "width",
0, unit);
+}
- wk_editor = E_WEBKIT_EDITOR (editor);
+static gint
+webkit_editor_cell_get_row_span (EContentEditor *editor)
+{
+ return webkit_editor_dialog_utils_get_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "rowspan", 0);
+}
- *unit = E_CONTENT_EDITOR_UNIT_AUTO;
-
- if (!wk_editor->priv->html_mode)
- return 0;
-
- result = webkit_editor_get_element_attribute (
- wk_editor, "#-x-evo-current-cell", "width");
-
- if (result) {
- const gchar *width;
-
- g_variant_get (result, "(&s)", &width);
- if (width && *width) {
- value = atoi (width);
- if (strstr (width, "%"))
- *unit = E_CONTENT_EDITOR_UNIT_PERCENTAGE;
- else if (g_ascii_strncasecmp (width, "auto", 4) != 0)
- *unit = E_CONTENT_EDITOR_UNIT_PIXEL;
- }
- g_variant_unref (result);
- }
-
- return value;
-}
-
-static gint
-webkit_editor_cell_get_row_span (EContentEditor *editor)
-{
- EWebKitEditor *wk_editor;
- gint value = 0;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return 0;
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return 0;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "TableCellElementGetRowSpan",
- g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-cell"),
- NULL);
-
- if (result) {
- g_variant_get (result, "(i)", &value);
- g_variant_unref (result);
- }
-
- return value;
-}
-
-static gint
-webkit_editor_cell_get_col_span (EContentEditor *editor)
-{
- EWebKitEditor *wk_editor;
- gint value = 0;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return 0;
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return 0;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "TableCellElementGetColSpan",
- g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-cell"),
- NULL);
-
- if (result) {
- g_variant_get (result, "(i)", &value);
- g_variant_unref (result);
- }
-
- return value;
-}
+static gint
+webkit_editor_cell_get_col_span (EContentEditor *editor)
+{
+ return webkit_editor_dialog_utils_get_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "colspan", 0);
+}
static gchar *
webkit_editor_cell_get_background_image_uri (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return NULL;
-
- result = webkit_editor_get_element_attribute (
- wk_editor, "#-x-evo-current-cell", "data-uri");
- if (result) {
- gchar *value;
-
- g_variant_get (result, "(s)", &value);
- g_variant_unref (result);
- }
-
- return NULL;
+ return webkit_editor_dialog_utils_get_attribute (E_WEBKIT_EDITOR (editor), NULL, "background");
}
static void
webkit_editor_cell_get_background_color (EContentEditor *editor,
GdkRGBA *color)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- goto exit;
-
- result = webkit_editor_get_element_attribute (
- wk_editor, "#-x-evo-current-cell", "bgcolor");
- if (result) {
- const gchar *value;
-
- g_variant_get (result, "(&s)", &value);
- if (!value || !*value || !gdk_rgba_parse (color, value)) {
- g_variant_unref (result);
- goto exit;
- }
- g_variant_unref (result);
- return;
- }
-
- exit:
- *color = transparent;
+ webkit_editor_dialog_utils_get_attribute_color (E_WEBKIT_EDITOR (editor), NULL, "bgcolor", color);
}
static void
@@ -4441,23 +3662,10 @@ webkit_editor_cell_set_row_span (EContentEditor *editor,
gint value,
EContentEditorScope scope)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
+ gchar str_value[64];
- if (!wk_editor->priv->html_mode)
- return;
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorCellDialogSetElementRowSpan",
- g_variant_new ("(tii)", current_page_id (wk_editor), value, (gint32) scope),
- wk_editor->priv->cancellable);
+ webkit_editor_dialog_utils_set_table_attribute (E_WEBKIT_EDITOR (editor), scope, "rowspan",
+ webkit_editor_utils_int_to_string (str_value, sizeof (str_value), value));
}
static void
@@ -4465,23 +3673,10 @@ webkit_editor_cell_set_col_span (EContentEditor *editor,
gint value,
EContentEditorScope scope)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return;
+ gchar str_value[64];
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorCellDialogSetElementColSpan",
- g_variant_new ("(tii)", current_page_id (wk_editor), value, (gint32) scope),
- wk_editor->priv->cancellable);
+ webkit_editor_dialog_utils_set_table_attribute (E_WEBKIT_EDITOR (editor), scope, "colspan",
+ webkit_editor_utils_int_to_string (str_value, sizeof (str_value), value));
}
static void
@@ -4490,34 +3685,10 @@ webkit_editor_cell_set_width (EContentEditor *editor,
EContentEditorUnit unit,
EContentEditorScope scope)
{
- EWebKitEditor *wk_editor;
- gchar *width;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return;
+ gchar str_value[64];
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- if (unit == E_CONTENT_EDITOR_UNIT_AUTO)
- width = g_strdup ("auto");
- else
- width = g_strdup_printf (
- "%d%s",
- value,
- (unit == E_CONTENT_EDITOR_UNIT_PIXEL) ? "px" : "%");
-
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorCellDialogSetElementWidth",
- g_variant_new ("(tsi)", current_page_id (wk_editor), width, (gint32) scope),
- wk_editor->priv->cancellable);
-
- g_free (width);
+ webkit_editor_dialog_utils_set_table_attribute (E_WEBKIT_EDITOR (editor), scope, "width",
+ webkit_editor_utils_int_with_unit_to_string (str_value, sizeof (str_value), value, unit));
}
static void
@@ -4525,163 +3696,55 @@ webkit_editor_cell_set_background_color (EContentEditor *editor,
const GdkRGBA *value,
EContentEditorScope scope)
{
- EWebKitEditor *wk_editor;
- gchar *color;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
+ gchar str_value[64];
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- if (value->alpha != 0.0)
- color = g_strdup_printf ("#%06x", e_rgba_to_value (value));
- else
- color = g_strdup ("");
-
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorCellDialogSetElementBgColor",
- g_variant_new ("(tsi)", current_page_id (wk_editor), color, (gint32) scope),
- wk_editor->priv->cancellable);
-
- g_free (color);
+ webkit_editor_dialog_utils_set_table_attribute (E_WEBKIT_EDITOR (editor), scope, "bgcolor",
+ webkit_editor_utils_color_to_string (str_value, sizeof (str_value), value));
}
static void
webkit_editor_cell_set_background_image_uri (EContentEditor *editor,
const gchar *uri)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- if (!wk_editor->priv->html_mode)
- return;
-
- if (uri && *uri)
- webkit_editor_replace_image_src (wk_editor, "#-x-evo-current-cell", uri);
- else {
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "RemoveImageAttributesFromElementBySelector",
- g_variant_new ("(ts)", current_page_id (wk_editor), "#-x-evo-current-cell"),
- wk_editor->priv->cancellable);
- }
+ webkit_editor_replace_image_src (E_WEBKIT_EDITOR (editor), NULL, uri);
}
static void
webkit_editor_table_set_row_count (EContentEditor *editor,
guint value)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return;
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorTableDialogSetRowCount",
- g_variant_new ("(tu)", current_page_id (wk_editor), value),
- wk_editor->priv->cancellable);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.DialogUtilsTableSetRowCount(%d);",
+ value);
}
static guint
webkit_editor_table_get_row_count (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
- guint value = 0;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return 0;
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return 0;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorTableDialogGetRowCount",
- g_variant_new ("(t)", current_page_id (wk_editor)),
- NULL);
-
- if (result) {
- g_variant_get (result, "(u)", &value);
- g_variant_unref (result);
- }
-
- return value;
+ return webkit_editor_extract_and_free_jsc_int32 (
+ webkit_editor_call_jsc_sync (E_WEBKIT_EDITOR (editor),
"EvoEditor.DialogUtilsTableGetRowCount();"),
+ 0);
}
static void
webkit_editor_table_set_column_count (EContentEditor *editor,
guint value)
{
- EWebKitEditor *wk_editor;
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return;
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorTableDialogSetColumnCount",
- g_variant_new ("(tu)", current_page_id (wk_editor), value),
- wk_editor->priv->cancellable);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.DialogUtilsTableSetColumnCount(%d);",
+ value);
}
static guint
webkit_editor_table_get_column_count (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
- guint value = 0;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return 0;
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return 0;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorTableDialogGetColumnCount",
- g_variant_new ("(t)", current_page_id (wk_editor)),
- NULL);
-
- if (result) {
- g_variant_get (result, "(u)", &value);
- g_variant_unref (result);
- }
-
- return value;
+ return webkit_editor_extract_and_free_jsc_int32 (
+ webkit_editor_call_jsc_sync (E_WEBKIT_EDITOR (editor),
"EvoEditor.DialogUtilsTableGetColumnCount();"),
+ 0);
}
static void
@@ -4689,465 +3752,111 @@ webkit_editor_table_set_width (EContentEditor *editor,
gint value,
EContentEditorUnit unit)
{
- EWebKitEditor *wk_editor;
- gchar *width;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return;
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- if (unit == E_CONTENT_EDITOR_UNIT_AUTO)
- width = g_strdup ("auto");
- else
- width = g_strdup_printf (
- "%d%s",
- value,
- (unit == E_CONTENT_EDITOR_UNIT_PIXEL) ? "px" : "%");
-
- webkit_editor_set_element_attribute (
- wk_editor, "#-x-evo-current-table", "width", width);
-
- g_free (width);
+ webkit_editor_dialog_utils_set_attribute_with_unit (E_WEBKIT_EDITOR (editor), NULL, "width", value,
unit);
}
static guint
webkit_editor_table_get_width (EContentEditor *editor,
EContentEditorUnit *unit)
{
- EWebKitEditor *wk_editor;
- guint value = 0;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- *unit = E_CONTENT_EDITOR_UNIT_PIXEL;
-
- if (!wk_editor->priv->html_mode)
- return 0;
-
- result = webkit_editor_get_element_attribute (
- wk_editor, "#-x-evo-current-table", "width");
-
- if (result) {
- const gchar *width;
-
- g_variant_get (result, "(&s)", &width);
- if (width && *width) {
- value = atoi (width);
- if (strstr (width, "%"))
- *unit = E_CONTENT_EDITOR_UNIT_PERCENTAGE;
- else if (g_ascii_strncasecmp (width, "auto", 4) != 0)
- *unit = E_CONTENT_EDITOR_UNIT_PIXEL;
- }
- g_variant_unref (result);
- }
-
- return value;
+ return webkit_editor_dialog_utils_get_attribute_with_unit (E_WEBKIT_EDITOR (editor), NULL, "width",
0, unit);
}
static void
webkit_editor_table_set_align (EContentEditor *editor,
const gchar *value)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return;
-
- webkit_editor_set_element_attribute (
- wk_editor, "#-x-evo-current-table", "align", value);
+ webkit_editor_dialog_utils_set_attribute (E_WEBKIT_EDITOR (editor), NULL, "align", value);
}
static gchar *
webkit_editor_table_get_align (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- gchar *value = NULL;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return NULL;
-
- result = webkit_editor_get_element_attribute (
- wk_editor, "#-x-evo-current-table", "align");
- if (result) {
- g_variant_get (result, "(s)", &value);
- g_variant_unref (result);
- }
-
- return value;
+ return webkit_editor_dialog_utils_get_attribute (E_WEBKIT_EDITOR (editor), NULL, "align");
}
static void
webkit_editor_table_set_padding (EContentEditor *editor,
gint value)
{
- EWebKitEditor *wk_editor;
- gchar *padding;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- padding = g_strdup_printf ("%d", value);
-
- webkit_editor_set_element_attribute (
- wk_editor, "#-x-evo-current-table", "cellpadding", padding);
-
- g_free (padding);
+ webkit_editor_dialog_utils_set_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "cellpadding", value);
}
static gint
webkit_editor_table_get_padding (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
- gint value = 0;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- result = webkit_editor_get_element_attribute (
- wk_editor, "#-x-evo-current-table", "cellpadding");
-
- if (result) {
- const gchar *padding;
-
- g_variant_get (result, "(&s)", &padding);
- if (padding && *padding)
- value = atoi (padding);
- g_variant_unref (result);
- }
-
- return value;
+ return webkit_editor_dialog_utils_get_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "cellpadding",
0);
}
static void
webkit_editor_table_set_spacing (EContentEditor *editor,
gint value)
{
- EWebKitEditor *wk_editor;
- gchar *spacing;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- spacing = g_strdup_printf ("%d", value);
-
- webkit_editor_set_element_attribute (
- wk_editor, "#-x-evo-current-table", "cellspacing", spacing);
-
- g_free (spacing);
+ webkit_editor_dialog_utils_set_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "cellspacing", value);
}
static gint
webkit_editor_table_get_spacing (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
- gint value = 0;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- result = webkit_editor_get_element_attribute (
- wk_editor, "#-x-evo-current-table", "cellspacing");
-
- if (result) {
- const gchar *spacing;
-
- g_variant_get (result, "(&s)", &spacing);
- if (spacing && *spacing)
- value = atoi (spacing);
- g_variant_unref (result);
- }
-
- return value;
+ return webkit_editor_dialog_utils_get_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "cellspacing",
0);
}
static void
webkit_editor_table_set_border (EContentEditor *editor,
gint value)
{
- EWebKitEditor *wk_editor;
- gchar *border;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- border = g_strdup_printf ("%d", value);
-
- webkit_editor_set_element_attribute (
- wk_editor, "#-x-evo-current-table", "border", border);
-
- g_free (border);
+ webkit_editor_dialog_utils_set_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "border", value);
}
static gint
webkit_editor_table_get_border (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
- gint value = 0;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- result = webkit_editor_get_element_attribute (
- wk_editor, "#-x-evo-current-table", "border");
-
- if (result) {
- const gchar *border;
-
- g_variant_get (result, "(&s)", &border);
- if (border && *border)
- value = atoi (border);
- g_variant_unref (result);
- }
-
- return value;
+ return webkit_editor_dialog_utils_get_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "border", 0);
}
static void
webkit_editor_table_get_background_color (EContentEditor *editor,
GdkRGBA *color)
{
- EWebKitEditor *wk_editor;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- goto exit;
-
- result = webkit_editor_get_element_attribute (
- wk_editor, "#-x-evo-current-table", "bgcolor");
- if (result) {
- const gchar *value;
-
- g_variant_get (result, "(&s)", &value);
- if (!value || !*value || !gdk_rgba_parse (color, value)) {
- g_variant_unref (result);
- goto exit;
- }
- g_variant_unref (result);
- return;
- }
-
- exit:
- *color = transparent;
+ webkit_editor_dialog_utils_get_attribute_color (E_WEBKIT_EDITOR (editor), NULL, "bgcolor", color);
}
static void
webkit_editor_table_set_background_color (EContentEditor *editor,
const GdkRGBA *value)
{
- EWebKitEditor *wk_editor;
- gchar *color;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- if (value->alpha != 0.0)
- color = g_strdup_printf ("#%06x", e_rgba_to_value (value));
- else
- color = g_strdup ("");
-
- webkit_editor_set_element_attribute (
- wk_editor, "#-x-evo-current-table", "bgcolor", color);
-
- g_free (color);
-}
-
-static gchar *
-webkit_editor_table_get_background_image_uri (EContentEditor *editor)
-{
- EWebKitEditor *wk_editor;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->html_mode)
- return NULL;
-
- result = webkit_editor_get_element_attribute (wk_editor, "#-x-evo-current-table", "data-uri");
- if (result) {
- gchar *value;
-
- g_variant_get (result, "(s)", &value);
- g_variant_unref (result);
- }
-
- return NULL;
-}
-
-static void
-webkit_editor_table_set_background_image_uri (EContentEditor *editor,
- const gchar *uri)
-{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return;
- }
-
- if (!wk_editor->priv->html_mode)
- return;
-
- if (uri && *uri)
- webkit_editor_replace_image_src (wk_editor, "#-x-evo-current-table", uri);
- else {
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "RemoveImageAttributesFromElementBySelector",
- g_variant_new ("(ts)", current_page_id (wk_editor), "#-x-evo-current-table"),
- wk_editor->priv->cancellable);
- }
-}
-
-static gboolean
-webkit_editor_on_table_dialog_open (EContentEditor *editor)
-{
- EWebKitEditor *wk_editor;
- GVariant *result;
- gboolean value = FALSE;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return FALSE;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorTableDialogShow",
- g_variant_new ("(t)", current_page_id (wk_editor)),
- NULL);
-
- if (result) {
- g_variant_get (result, "(b)", &value);
- g_variant_unref (result);
- }
-
- return value;
-}
-
-static void
-webkit_editor_on_table_dialog_close (EContentEditor *editor)
-{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorTableDialogSaveHistoryOnExit");
-
- webkit_editor_finish_search (E_WEBKIT_EDITOR (editor));
-}
-
-static void
-webkit_editor_on_spell_check_dialog_open (EContentEditor *editor)
-{
-}
-
-static void
-webkit_editor_on_spell_check_dialog_close (EContentEditor *editor)
-{
- webkit_editor_finish_search (E_WEBKIT_EDITOR (editor));
-}
-
-static gchar *
-move_to_another_word (EContentEditor *editor,
- const gchar *word,
- const gchar *dom_function)
-{
- EWebKitEditor *wk_editor;
- gchar **active_languages;
- gchar *another_word = NULL;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
- return NULL;
- }
-
- active_languages = e_spell_checker_list_active_languages (
- wk_editor->priv->spell_checker, NULL);
- if (!active_languages)
- return NULL;
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- dom_function,
- g_variant_new (
- "(ts^as)", current_page_id (wk_editor), word ? word : "", active_languages),
- NULL);
-
- g_strfreev (active_languages);
-
- if (result) {
- g_variant_get (result, "(s)", &another_word);
- g_variant_unref (result);
- }
-
- return another_word;
-}
-
-static gchar *
-webkit_editor_spell_check_next_word (EContentEditor *editor,
- const gchar *word)
-{
- return move_to_another_word (editor, word, "EEditorSpellCheckDialogNext");
-}
-
-static gchar *
-webkit_editor_spell_check_prev_word (EContentEditor *editor,
- const gchar *word)
-{
- return move_to_another_word (editor, word, "EEditorSpellCheckDialogPrev");
-}
-
-static void
-webkit_editor_on_replace_dialog_open (EContentEditor *editor)
-{
+ webkit_editor_dialog_utils_set_attribute_color (E_WEBKIT_EDITOR (editor), NULL, "bgcolor", value);
}
-static void
-webkit_editor_on_replace_dialog_close (EContentEditor *editor)
+static gchar *
+webkit_editor_table_get_background_image_uri (EContentEditor *editor)
{
- webkit_editor_finish_search (E_WEBKIT_EDITOR (editor));
+ return webkit_editor_dialog_utils_get_attribute (E_WEBKIT_EDITOR (editor), NULL, "background");
}
static void
-webkit_editor_on_find_dialog_open (EContentEditor *editor)
+webkit_editor_table_set_background_image_uri (EContentEditor *editor,
+ const gchar *uri)
{
+ webkit_editor_replace_image_src (E_WEBKIT_EDITOR (editor), NULL, uri);
}
-static void
-webkit_editor_on_find_dialog_close (EContentEditor *editor)
+static gchar *
+webkit_editor_spell_check_next_word (EContentEditor *editor,
+ const gchar *word)
{
- webkit_editor_finish_search (E_WEBKIT_EDITOR (editor));
+ return webkit_editor_extract_and_free_jsc_string (
+ webkit_editor_call_jsc_sync (E_WEBKIT_EDITOR (editor),
"EvoEditor.SpellCheckContinue(%x,%x);", word && *word, TRUE),
+ NULL);
}
-static GDBusProxy *
-webkit_editor_get_web_extension (EWebKitEditor *wk_editor)
+static gchar *
+webkit_editor_spell_check_prev_word (EContentEditor *editor,
+ const gchar *word)
{
- g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), NULL);
-
- return wk_editor->priv->web_extension_proxy;
+ return webkit_editor_extract_and_free_jsc_string (
+ webkit_editor_call_jsc_sync (E_WEBKIT_EDITOR (editor),
"EvoEditor.SpellCheckContinue(%x,%x);", word && *word, FALSE),
+ NULL);
}
static void
@@ -5211,6 +3920,131 @@ webkit_editor_process_uri_request_cb (WebKitURISchemeRequest *request,
webkit_editor_uri_request_done_cb, g_object_ref (request));
}
+static void
+webkit_editor_set_normal_paragraph_width (EWebKitEditor *wk_editor,
+ gint value)
+{
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ if (wk_editor->priv->normal_paragraph_width != value) {
+ wk_editor->priv->normal_paragraph_width = value;
+
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.SetNormalParagraphWidth(%d);",
+ value);
+
+ g_object_notify (G_OBJECT (wk_editor), "normal-paragraph-width");
+ }
+}
+
+static gint
+webkit_editor_get_normal_paragraph_width (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), -1);
+
+ return wk_editor->priv->normal_paragraph_width;
+}
+
+static void
+webkit_editor_set_magic_links (EWebKitEditor *wk_editor,
+ gboolean value)
+{
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ if ((wk_editor->priv->magic_links ? 1 : 0) != (value ? 1 : 0)) {
+ wk_editor->priv->magic_links = value;
+
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.MAGIC_LINKS = %x;",
+ value);
+
+ g_object_notify (G_OBJECT (wk_editor), "magic-links");
+ }
+}
+
+static gboolean
+webkit_editor_get_magic_links (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
+
+ return wk_editor->priv->magic_links;
+}
+
+static void
+webkit_editor_set_magic_smileys (EWebKitEditor *wk_editor,
+ gboolean value)
+{
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ if ((wk_editor->priv->magic_smileys ? 1 : 0) != (value ? 1 : 0)) {
+ wk_editor->priv->magic_smileys = value;
+
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.MAGIC_SMILEYS = %x;",
+ value);
+
+ g_object_notify (G_OBJECT (wk_editor), "magic-smileys");
+ }
+}
+
+static gboolean
+webkit_editor_get_magic_smileys (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
+
+ return wk_editor->priv->magic_smileys;
+}
+
+static void
+webkit_editor_set_unicode_smileys (EWebKitEditor *wk_editor,
+ gboolean value)
+{
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ if ((wk_editor->priv->unicode_smileys ? 1 : 0) != (value ? 1 : 0)) {
+ wk_editor->priv->unicode_smileys = value;
+
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.UNICODE_SMILEYS = %x;",
+ value);
+
+ g_object_notify (G_OBJECT (wk_editor), "unicode-smileys");
+ }
+}
+
+static gboolean
+webkit_editor_get_unicode_smileys (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
+
+ return wk_editor->priv->unicode_smileys;
+}
+
+static void
+webkit_editor_set_wrap_quoted_text_in_replies (EWebKitEditor *wk_editor,
+ gboolean value)
+{
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ if ((wk_editor->priv->wrap_quoted_text_in_replies ? 1 : 0) != (value ? 1 : 0)) {
+ wk_editor->priv->wrap_quoted_text_in_replies = value;
+
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.WRAP_QUOTED_TEXT_IN_REPLIES = %x;",
+ value);
+
+ g_object_notify (G_OBJECT (wk_editor), "wrap-quoted-text-in-replies");
+ }
+}
+
+static gboolean
+webkit_editor_get_wrap_quoted_text_in_replies (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
+
+ return wk_editor->priv->wrap_quoted_text_in_replies;
+}
+
static void
e_webkit_editor_initialize_web_extensions_cb (WebKitWebContext *web_context,
gpointer user_data)
@@ -5218,13 +4052,8 @@ e_webkit_editor_initialize_web_extensions_cb (WebKitWebContext *web_context,
EWebKitEditor *wk_editor = user_data;
g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
- g_return_if_fail (wk_editor->priv->container);
webkit_web_context_set_web_extensions_directory (web_context,
EVOLUTION_WEB_EXTENSIONS_WEBKIT_EDITOR_DIR);
- webkit_web_context_set_web_extensions_initialization_user_data (web_context,
- g_variant_new ("(ss)",
- e_web_extension_container_get_server_guid (wk_editor->priv->container),
- e_web_extension_container_get_server_address (wk_editor->priv->container)));
}
static void
@@ -5236,6 +4065,8 @@ webkit_editor_constructed (GObject *object)
WebKitWebContext *web_context;
WebKitSettings *web_settings;
WebKitWebView *web_view;
+ WebKitUserContentManager *manager;
+ GSettings *settings;
wk_editor = E_WEBKIT_EDITOR (object);
web_view = WEBKIT_WEB_VIEW (wk_editor);
@@ -5249,6 +4080,25 @@ webkit_editor_constructed (GObject *object)
G_OBJECT_CLASS (e_webkit_editor_parent_class)->constructed (object);
+ manager = webkit_web_view_get_user_content_manager (WEBKIT_WEB_VIEW (wk_editor));
+
+ g_signal_connect_object (manager, "script-message-received::contentChanged",
+ G_CALLBACK (content_changed_cb), wk_editor, 0);
+ g_signal_connect_object (manager, "script-message-received::contextMenuRequested",
+ G_CALLBACK (context_menu_requested_cb), wk_editor, 0);
+ g_signal_connect_object (manager, "script-message-received::formattingChanged",
+ G_CALLBACK (formatting_changed_cb), wk_editor, 0);
+ g_signal_connect_object (manager, "script-message-received::selectionChanged",
+ G_CALLBACK (selection_changed_cb), wk_editor, 0);
+ g_signal_connect_object (manager, "script-message-received::undoRedoStateChanged",
+ G_CALLBACK (undu_redo_state_changed_cb), wk_editor, 0);
+
+ webkit_user_content_manager_register_script_message_handler (manager, "contentChanged");
+ webkit_user_content_manager_register_script_message_handler (manager, "contextMenuRequested");
+ webkit_user_content_manager_register_script_message_handler (manager, "formattingChanged");
+ webkit_user_content_manager_register_script_message_handler (manager, "selectionChanged");
+ webkit_user_content_manager_register_script_message_handler (manager, "undoRedoStateChanged");
+
/* Give spell check languages to WebKit */
languages = e_spell_checker_list_active_languages (wk_editor->priv->spell_checker, NULL);
@@ -5256,6 +4106,16 @@ webkit_editor_constructed (GObject *object)
webkit_web_context_set_spell_checking_languages (web_context, (const gchar * const *) languages);
g_strfreev (languages);
+ content_request = e_cid_request_new ();
+ webkit_web_context_register_uri_scheme (web_context, "cid", webkit_editor_process_uri_request_cb,
+ g_object_ref (content_request), g_object_unref);
+ g_object_unref (content_request);
+
+ content_request = e_file_request_new ();
+ webkit_web_context_register_uri_scheme (web_context, "evo-file", webkit_editor_process_uri_request_cb,
+ g_object_ref (content_request), g_object_unref);
+ g_object_unref (content_request);
+
content_request = e_http_request_new ();
webkit_web_context_register_uri_scheme (web_context, "evo-http", webkit_editor_process_uri_request_cb,
g_object_ref (content_request), g_object_unref);
@@ -5267,9 +4127,39 @@ webkit_editor_constructed (GObject *object)
web_settings = webkit_web_view_get_settings (web_view);
webkit_settings_set_allow_file_access_from_file_urls (web_settings, TRUE);
+ webkit_settings_set_enable_write_console_messages_to_stdout (web_settings,
e_util_get_webkit_developer_mode_enabled ());
webkit_settings_set_enable_developer_extras (web_settings, e_util_get_webkit_developer_mode_enabled
());
- e_webkit_editor_load_data (wk_editor, "");
+ settings = e_util_ref_settings ("org.gnome.evolution.mail");
+
+ g_settings_bind (
+ settings, "composer-word-wrap-length",
+ wk_editor, "normal-paragraph-width",
+ G_SETTINGS_BIND_GET);
+
+ g_settings_bind (
+ settings, "composer-magic-links",
+ wk_editor, "magic-links",
+ G_SETTINGS_BIND_GET);
+
+ g_settings_bind (
+ settings, "composer-magic-smileys",
+ wk_editor, "magic-smileys",
+ G_SETTINGS_BIND_GET);
+
+ g_settings_bind (
+ settings, "composer-unicode-smileys",
+ wk_editor, "unicode-smileys",
+ G_SETTINGS_BIND_GET);
+
+ g_settings_bind (
+ settings, "composer-wrap-quoted-text-in-replies",
+ wk_editor, "wrap-quoted-text-in-replies",
+ G_SETTINGS_BIND_GET);
+
+ g_object_unref (settings);
+
+ webkit_web_view_load_html (WEBKIT_WEB_VIEW (wk_editor), "", "evo-file:///");
}
static GObjectConstructParam*
@@ -5364,11 +4254,6 @@ webkit_editor_dispose (GObject *object)
priv->mail_settings = NULL;
}
- e_webkit_editor_set_web_extension_proxy (E_WEBKIT_EDITOR (object), NULL);
-
- if (priv->container && priv->stamp)
- e_web_extension_container_forget_stamp (priv->container, priv->stamp);
-
if (priv->owner_change_clipboard_cb_id > 0) {
g_signal_handler_disconnect (
gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
@@ -5385,8 +4270,6 @@ webkit_editor_dispose (GObject *object)
webkit_editor_finish_search (E_WEBKIT_EDITOR (object));
- g_clear_object (&priv->container);
-
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_webkit_editor_parent_class)->dispose (object);
}
@@ -5410,15 +4293,12 @@ webkit_editor_finalize (GObject *object)
priv->post_reload_operations = NULL;
}
- if (priv->background_color != NULL) {
- gdk_rgba_free (priv->background_color);
- priv->background_color = NULL;
- }
-
- if (priv->font_color != NULL) {
- gdk_rgba_free (priv->font_color);
- priv->font_color = NULL;
- }
+ g_clear_pointer (&priv->background_color, gdk_rgba_free);
+ g_clear_pointer (&priv->font_color, gdk_rgba_free);
+ g_clear_pointer (&priv->body_fg_color, gdk_rgba_free);
+ g_clear_pointer (&priv->body_bg_color, gdk_rgba_free);
+ g_clear_pointer (&priv->body_link_color, gdk_rgba_free);
+ g_clear_pointer (&priv->body_vlink_color, gdk_rgba_free);
g_free (priv->last_hover_uri);
priv->last_hover_uri = NULL;
@@ -5427,7 +4307,9 @@ webkit_editor_finalize (GObject *object)
g_clear_object (&priv->cancellable);
g_clear_error (&priv->last_error);
+ g_free (priv->body_font_name);
g_free (priv->font_name);
+ g_free (priv->context_menu_caret_word);
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_webkit_editor_parent_class)->finalize (object);
@@ -5458,6 +4340,36 @@ webkit_editor_set_property (GObject *object,
g_value_get_boolean (value));
return;
+ case PROP_NORMAL_PARAGRAPH_WIDTH:
+ webkit_editor_set_normal_paragraph_width (
+ E_WEBKIT_EDITOR (object),
+ g_value_get_int (value));
+ return;
+
+ case PROP_MAGIC_LINKS:
+ webkit_editor_set_magic_links (
+ E_WEBKIT_EDITOR (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_MAGIC_SMILEYS:
+ webkit_editor_set_magic_smileys (
+ E_WEBKIT_EDITOR (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_UNICODE_SMILEYS:
+ webkit_editor_set_unicode_smileys (
+ E_WEBKIT_EDITOR (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_WRAP_QUOTED_TEXT_IN_REPLIES:
+ webkit_editor_set_wrap_quoted_text_in_replies (
+ E_WEBKIT_EDITOR (object),
+ g_value_get_boolean (value));
+ return;
+
case PROP_ALIGNMENT:
webkit_editor_set_alignment (
E_WEBKIT_EDITOR (object),
@@ -5473,9 +4385,8 @@ webkit_editor_set_property (GObject *object,
case PROP_BOLD:
webkit_editor_set_style_flag (
E_WEBKIT_EDITOR (object),
- E_CONTENT_EDITOR_STYLE_IS_BOLD,
- g_value_get_boolean (value),
- "DOMSelectionSetBold");
+ E_WEBKIT_EDITOR_STYLE_IS_BOLD,
+ g_value_get_boolean (value));
return;
case PROP_FONT_COLOR:
@@ -5505,49 +4416,36 @@ webkit_editor_set_property (GObject *object,
case PROP_ITALIC:
webkit_editor_set_style_flag (
E_WEBKIT_EDITOR (object),
- E_CONTENT_EDITOR_STYLE_IS_ITALIC,
- g_value_get_boolean (value),
- "DOMSelectionSetItalic");
- return;
-
- case PROP_MONOSPACED:
- webkit_editor_set_style_flag (
- E_WEBKIT_EDITOR (object),
- E_CONTENT_EDITOR_STYLE_IS_MONOSPACE,
- g_value_get_boolean (value),
- "DOMSelectionSetMonospaced");
+ E_WEBKIT_EDITOR_STYLE_IS_ITALIC,
+ g_value_get_boolean (value));
return;
case PROP_STRIKETHROUGH:
webkit_editor_set_style_flag (
E_WEBKIT_EDITOR (object),
- E_CONTENT_EDITOR_STYLE_IS_STRIKETHROUGH,
- g_value_get_boolean (value),
- "DOMSelectionSetStrikethrough");
+ E_WEBKIT_EDITOR_STYLE_IS_STRIKETHROUGH,
+ g_value_get_boolean (value));
return;
case PROP_SUBSCRIPT:
webkit_editor_set_style_flag (
E_WEBKIT_EDITOR (object),
- E_CONTENT_EDITOR_STYLE_IS_SUBSCRIPT,
- g_value_get_boolean (value),
- "DOMSelectionSetSubscript");
+ E_WEBKIT_EDITOR_STYLE_IS_SUBSCRIPT,
+ g_value_get_boolean (value));
return;
case PROP_SUPERSCRIPT:
webkit_editor_set_style_flag (
E_WEBKIT_EDITOR (object),
- E_CONTENT_EDITOR_STYLE_IS_SUPERSCRIPT,
- g_value_get_boolean (value),
- "DOMSelectionSetSuperscript");
+ E_WEBKIT_EDITOR_STYLE_IS_SUPERSCRIPT,
+ g_value_get_boolean (value));
return;
case PROP_UNDERLINE:
webkit_editor_set_style_flag (
E_WEBKIT_EDITOR (object),
- E_CONTENT_EDITOR_STYLE_IS_UNDERLINE,
- g_value_get_boolean (value),
- "DOMSelectionSetUnderline");
+ E_WEBKIT_EDITOR_STYLE_IS_UNDERLINE,
+ g_value_get_boolean (value));
return;
case PROP_START_BOTTOM:
@@ -5591,12 +4489,6 @@ webkit_editor_get_property (GObject *object,
GParamSpec *pspec)
{
switch (property_id) {
- case PROP_WEB_EXTENSION:
- g_value_set_object (
- value, webkit_editor_get_web_extension (
- E_WEBKIT_EDITOR (object)));
- return;
-
case PROP_IS_MALFUNCTION:
g_value_set_boolean (
value, webkit_editor_is_malfunction (
@@ -5651,6 +4543,31 @@ webkit_editor_get_property (GObject *object,
E_WEBKIT_EDITOR (object)));
return;
+ case PROP_NORMAL_PARAGRAPH_WIDTH:
+ g_value_set_int (value,
+ webkit_editor_get_normal_paragraph_width (E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_MAGIC_LINKS:
+ g_value_set_boolean (value,
+ webkit_editor_get_magic_links (E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_MAGIC_SMILEYS:
+ g_value_set_boolean (value,
+ webkit_editor_get_magic_smileys (E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_UNICODE_SMILEYS:
+ g_value_set_boolean (value,
+ webkit_editor_get_unicode_smileys (E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_WRAP_QUOTED_TEXT_IN_REPLIES:
+ g_value_set_boolean (value,
+ webkit_editor_get_wrap_quoted_text_in_replies (E_WEBKIT_EDITOR (object)));
+ return;
+
case PROP_ALIGNMENT:
g_value_set_enum (
value,
@@ -5677,7 +4594,7 @@ webkit_editor_get_property (GObject *object,
value,
webkit_editor_get_style_flag (
E_WEBKIT_EDITOR (object),
- E_CONTENT_EDITOR_STYLE_IS_BOLD));
+ E_WEBKIT_EDITOR_STYLE_IS_BOLD));
return;
case PROP_FONT_COLOR:
@@ -5701,10 +4618,10 @@ webkit_editor_get_property (GObject *object,
E_WEBKIT_EDITOR (object)));
return;
- case PROP_INDENTED:
- g_value_set_boolean (
+ case PROP_INDENT_LEVEL:
+ g_value_set_int (
value,
- webkit_editor_selection_is_indented (
+ webkit_editor_get_indent_level (
E_WEBKIT_EDITOR (object)));
return;
@@ -5713,15 +4630,7 @@ webkit_editor_get_property (GObject *object,
value,
webkit_editor_get_style_flag (
E_WEBKIT_EDITOR (object),
- E_CONTENT_EDITOR_STYLE_IS_ITALIC));
- return;
-
- case PROP_MONOSPACED:
- g_value_set_boolean (
- value,
- webkit_editor_get_style_flag (
- E_WEBKIT_EDITOR (object),
- E_CONTENT_EDITOR_STYLE_IS_MONOSPACE));
+ E_WEBKIT_EDITOR_STYLE_IS_ITALIC));
return;
case PROP_STRIKETHROUGH:
@@ -5729,7 +4638,7 @@ webkit_editor_get_property (GObject *object,
value,
webkit_editor_get_style_flag (
E_WEBKIT_EDITOR (object),
- E_CONTENT_EDITOR_STYLE_IS_STRIKETHROUGH));
+ E_WEBKIT_EDITOR_STYLE_IS_STRIKETHROUGH));
return;
case PROP_SUBSCRIPT:
@@ -5737,7 +4646,7 @@ webkit_editor_get_property (GObject *object,
value,
webkit_editor_get_style_flag (
E_WEBKIT_EDITOR (object),
- E_CONTENT_EDITOR_STYLE_IS_SUBSCRIPT));
+ E_WEBKIT_EDITOR_STYLE_IS_SUBSCRIPT));
return;
case PROP_SUPERSCRIPT:
@@ -5745,7 +4654,7 @@ webkit_editor_get_property (GObject *object,
value,
webkit_editor_get_style_flag (
E_WEBKIT_EDITOR (object),
- E_CONTENT_EDITOR_STYLE_IS_SUPERSCRIPT));
+ E_WEBKIT_EDITOR_STYLE_IS_SUPERSCRIPT));
return;
case PROP_UNDERLINE:
@@ -5753,7 +4662,7 @@ webkit_editor_get_property (GObject *object,
value,
webkit_editor_get_style_flag (
E_WEBKIT_EDITOR (object),
- E_CONTENT_EDITOR_STYLE_IS_UNDERLINE));
+ E_WEBKIT_EDITOR_STYLE_IS_UNDERLINE));
return;
case PROP_START_BOTTOM:
@@ -5855,99 +4764,91 @@ webkit_editor_style_settings_changed_cb (GSettings *settings,
else
g_hash_table_remove (wk_editor->priv->old_settings, key);
- webkit_editor_style_updated_cb (wk_editor);
+ webkit_editor_style_updated (wk_editor, FALSE);
} else if (new_value) {
g_variant_unref (new_value);
}
}
static void
-webkit_editor_load_changed_cb (EWebKitEditor *wk_editor,
- WebKitLoadEvent load_event)
+webkit_editor_can_paste_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- wk_editor->priv->webkit_load_event = load_event;
+ EWebKitEditor *wk_editor;
+ gboolean can;
- if (load_event != WEBKIT_LOAD_FINISHED)
- return;
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (source_object));
- wk_editor->priv->reload_in_progress = FALSE;
+ wk_editor = E_WEBKIT_EDITOR (source_object);
- if (webkit_editor_is_ready (E_CONTENT_EDITOR (wk_editor))) {
- e_content_editor_emit_load_finished (E_CONTENT_EDITOR (wk_editor));
- webkit_editor_style_updated_cb (wk_editor);
- } else
- wk_editor->priv->emit_load_finished_when_extension_is_ready = TRUE;
+ can = webkit_web_view_can_execute_editing_command_finish (WEBKIT_WEB_VIEW (wk_editor), result, NULL);
- dispatch_pending_operations (wk_editor);
+ if (wk_editor->priv->can_paste != can) {
+ wk_editor->priv->can_paste = can;
+ g_object_notify (G_OBJECT (wk_editor), "can-paste");
+ }
}
static void
-webkit_editor_clipboard_owner_change_cb (GtkClipboard *clipboard,
- GdkEventOwnerChange *event,
- EWebKitEditor *wk_editor)
+webkit_editor_load_changed_cb (EWebKitEditor *wk_editor,
+ WebKitLoadEvent load_event)
{
- if (!E_IS_WEBKIT_EDITOR (wk_editor))
- return;
+ wk_editor->priv->webkit_load_event = load_event;
- if (!wk_editor->priv->web_extension_proxy)
+ if (load_event != WEBKIT_LOAD_FINISHED ||
+ !webkit_editor_is_ready (E_CONTENT_EDITOR (wk_editor)))
return;
- if (wk_editor->priv->copy_cut_actions_triggered && event->owner)
- wk_editor->priv->copy_paste_clipboard_in_view = TRUE;
- else
- wk_editor->priv->copy_paste_clipboard_in_view = FALSE;
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.START_BOTTOM = %x;\n"
+ "EvoEditor.TOP_SIGNATURE = %x;",
+ e_webkit_editor_three_state_to_bool (wk_editor->priv->start_bottom,
"composer-reply-start-bottom"),
+ e_webkit_editor_three_state_to_bool (wk_editor->priv->top_signature,
"composer-top-signature"));
- if (wk_editor->priv->copy_paste_clipboard_in_view ==
wk_editor->priv->pasting_from_itself_extension_value)
- return;
+ /* Dispatch queued operations - as we are using this just for load
+ * operations load just the latest request and throw away the rest. */
+ if (wk_editor->priv->post_reload_operations &&
+ !g_queue_is_empty (wk_editor->priv->post_reload_operations)) {
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "SetPastingContentFromItself",
- g_variant_new (
- "(tb)",
- current_page_id (wk_editor),
- wk_editor->priv->copy_paste_clipboard_in_view),
- wk_editor->priv->cancellable);
+ PostReloadOperation *op;
- wk_editor->priv->copy_cut_actions_triggered = FALSE;
+ op = g_queue_pop_head (wk_editor->priv->post_reload_operations);
- wk_editor->priv->pasting_from_itself_extension_value = wk_editor->priv->copy_paste_clipboard_in_view;
-}
+ op->func (wk_editor, op->data, op->flags);
-static void
-webkit_editor_primary_clipboard_owner_change_cb (GtkClipboard *clipboard,
- GdkEventOwnerChange *event,
- EWebKitEditor *wk_editor)
-{
- if (!E_IS_WEBKIT_EDITOR (wk_editor) ||
- !wk_editor->priv->web_extension_proxy)
- return;
+ if (op->data_free_func)
+ op->data_free_func (op->data);
+ g_free (op);
- if (!event->owner || !wk_editor->priv->can_copy)
- wk_editor->priv->copy_paste_clipboard_in_view = FALSE;
+ while ((op = g_queue_pop_head (wk_editor->priv->post_reload_operations))) {
+ if (op->data_free_func)
+ op->data_free_func (op->data);
+ g_free (op);
+ }
- if (wk_editor->priv->copy_paste_clipboard_in_view ==
wk_editor->priv->pasting_from_itself_extension_value)
- return;
+ g_queue_clear (wk_editor->priv->post_reload_operations);
+ }
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "SetPastingContentFromItself",
- g_variant_new (
- "(tb)",
- current_page_id (wk_editor),
- wk_editor->priv->copy_paste_clipboard_in_view),
- wk_editor->priv->cancellable);
+ webkit_editor_style_updated (wk_editor, FALSE);
- wk_editor->priv->pasting_from_itself_extension_value = wk_editor->priv->copy_paste_clipboard_in_view;
-}
+ if (wk_editor->priv->initialized_callback) {
+ EContentEditorInitializedCallback initialized_callback;
+ gpointer initialized_user_data;
-static gboolean
-webkit_editor_paste_prefer_text_html (EWebKitEditor *wk_editor)
-{
- if (wk_editor->priv->pasting_primary_clipboard)
- return wk_editor->priv->copy_paste_primary_in_view;
- else
- return wk_editor->priv->copy_paste_clipboard_in_view;
+ initialized_callback = wk_editor->priv->initialized_callback;
+ initialized_user_data = wk_editor->priv->initialized_user_data;
+
+ wk_editor->priv->initialized_callback = NULL;
+ wk_editor->priv->initialized_user_data = NULL;
+
+ initialized_callback (E_CONTENT_EDITOR (wk_editor), initialized_user_data);
+ }
+
+ webkit_web_view_can_execute_editing_command (WEBKIT_WEB_VIEW (wk_editor),
+ WEBKIT_EDITING_COMMAND_PASTE, NULL, webkit_editor_can_paste_cb, NULL);
+
+ e_content_editor_emit_load_finished (E_CONTENT_EDITOR (wk_editor));
}
static void
@@ -5975,8 +4876,7 @@ webkit_editor_paste_clipboard_targets_cb (GtkClipboard *clipboard,
* with SRCSET attribute in clipboard correctly). And if this fails the
* source application can cancel the content and we could not fallback
* to at least some content. */
- if (wk_editor->priv->html_mode ||
- webkit_editor_paste_prefer_text_html (wk_editor)) {
+ if (wk_editor->priv->html_mode) {
if (e_targets_include_html (targets, n_targets)) {
content = e_clipboard_wait_for_html (clipboard);
is_html = TRUE;
@@ -6045,10 +4945,6 @@ webkit_editor_paste_primary (EContentEditor *editor)
wk_editor = E_WEBKIT_EDITOR (editor);
- /* Remember, that we are pasting primary clipboard to return
- * correct value in e_html_editor_view_is_pasting_content_from_itself. */
- wk_editor->priv->pasting_primary_clipboard = TRUE;
-
webkit_editor_move_caret_on_current_coordinates (GTK_WIDGET (wk_editor));
clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
@@ -6069,8 +4965,6 @@ webkit_editor_paste (EContentEditor *editor)
wk_editor = E_WEBKIT_EDITOR (editor);
- wk_editor->priv->pasting_primary_clipboard = FALSE;
-
clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
if (gtk_clipboard_wait_for_targets (clipboard, &targets, &n_targets)) {
@@ -6100,18 +4994,17 @@ webkit_editor_context_menu_cb (EWebKitEditor *wk_editor,
GdkEvent *event,
WebKitHitTestResult *hit_test_result)
{
- GVariant *result;
- EContentEditorNodeFlags flags = 0;
- gboolean handled;
-
- webkit_context_menu_remove_all (context_menu);
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
- if ((result = webkit_context_menu_get_user_data (context_menu)))
- flags = g_variant_get_int32 (result);
+ e_content_editor_emit_context_menu_requested (E_CONTENT_EDITOR (wk_editor),
+ wk_editor->priv->context_menu_node_flags,
+ wk_editor->priv->context_menu_caret_word,
+ event);
- handled = e_content_editor_emit_context_menu_requested (E_CONTENT_EDITOR (wk_editor), flags, event);
+ wk_editor->priv->context_menu_node_flags = E_CONTENT_EDITOR_NODE_UNKNOWN;
+ g_clear_pointer (&wk_editor->priv->context_menu_caret_word, g_free);
- return handled;
+ return TRUE;
}
static void
@@ -6165,8 +5058,6 @@ webkit_editor_drag_data_received_cb (GtkWidget *widget,
} else {
GTK_WIDGET_CLASS (e_webkit_editor_parent_class)->drag_leave(widget, context, time);
g_signal_stop_emission_by_name (widget, "drag-data-received");
- if (!is_move)
- webkit_editor_call_simple_extension_function (wk_editor,
"DOMLastDropOperationDidCopy");
e_content_editor_emit_drop_handled (E_CONTENT_EDITOR (widget));
}
return;
@@ -6337,6 +5228,15 @@ paste_primary_clipboard_quoted (EContentEditor *editor)
}
}
+static CamelMimePart *
+e_webkit_editor_cid_resolver_ref_part (ECidResolver *resolver,
+ const gchar *cid_uri)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (resolver), NULL);
+
+ return e_content_editor_emit_ref_mime_part (E_CONTENT_EDITOR (resolver), cid_uri);
+}
+
static gboolean
webkit_editor_button_press_event (GtkWidget *widget,
GdkEventButton *event)
@@ -6465,17 +5365,6 @@ e_webkit_editor_class_init (EWebKitEditorClass *class)
widget_class->button_press_event = webkit_editor_button_press_event;
widget_class->key_press_event = webkit_editor_key_press_event;
- g_object_class_install_property (
- object_class,
- PROP_WEB_EXTENSION,
- g_param_spec_object (
- "web-extension",
- "Web Extension",
- "The Web Extension to use to talk to the WebProcess",
- G_TYPE_DBUS_PROXY,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
g_object_class_override_property (
object_class, PROP_IS_MALFUNCTION, "is-malfunction");
g_object_class_override_property (
@@ -6509,11 +5398,9 @@ e_webkit_editor_class_init (EWebKitEditorClass *class)
g_object_class_override_property (
object_class, PROP_FONT_SIZE, "font-size");
g_object_class_override_property (
- object_class, PROP_INDENTED, "indented");
+ object_class, PROP_INDENT_LEVEL, "indent-level");
g_object_class_override_property (
object_class, PROP_ITALIC, "italic");
- g_object_class_override_property (
- object_class, PROP_MONOSPACED, "monospaced");
g_object_class_override_property (
object_class, PROP_STRIKETHROUGH, "strikethrough");
g_object_class_override_property (
@@ -6534,6 +5421,69 @@ e_webkit_editor_class_init (EWebKitEditorClass *class)
object_class, PROP_LAST_ERROR, "last-error");
g_object_class_override_property (
object_class, PROP_SPELL_CHECKER, "spell-checker");
+
+ g_object_class_install_property (
+ object_class,
+ PROP_NORMAL_PARAGRAPH_WIDTH,
+ g_param_spec_int (
+ "normal-paragraph-width",
+ NULL,
+ NULL,
+ G_MININT32,
+ G_MAXINT32,
+ 71, /* Should be the same as e-editor.js:EvoEditor.NORMAL_PARAGRAPH_WIDTH and in the
init()*/
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MAGIC_LINKS,
+ g_param_spec_boolean (
+ "magic-links",
+ NULL,
+ NULL,
+ TRUE, /* Should be the same as e-editor.js:EvoEditor.MAGIC_LINKS and in the init() */
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MAGIC_SMILEYS,
+ g_param_spec_boolean (
+ "magic-smileys",
+ NULL,
+ NULL,
+ FALSE, /* Should be the same as e-editor.js:EvoEditor.MAGIC_SMILEYS and in the init()
*/
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_UNICODE_SMILEYS,
+ g_param_spec_boolean (
+ "unicode-smileys",
+ NULL,
+ NULL,
+ FALSE, /* Should be the same as e-editor.js:EvoEditor.UNICODE_SMILEYS and in the
init() */
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+
+ g_object_class_install_property (
+ object_class,
+ PROP_WRAP_QUOTED_TEXT_IN_REPLIES,
+ g_param_spec_boolean (
+ "wrap-quoted-text-in-replies",
+ NULL,
+ NULL,
+ TRUE, /* Should be the same as e-editor.js:EvoEditor.WRAP_QUOTED_TEXT_IN_REPLIES and
in the init() */
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
}
static void
@@ -6551,14 +5501,12 @@ e_webkit_editor_init (EWebKitEditor *wk_editor)
wk_editor->priv->spell_checker = e_spell_checker_new ();
wk_editor->priv->old_settings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
(GDestroyNotify) g_variant_unref);
wk_editor->priv->visually_wrap_long_lines = FALSE;
- wk_editor->priv->container = e_web_extension_container_new
(E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH, E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE);
- /* Do not change assigned stamp on every content load. It can have issues like when
- loading new content into already initialized editor. */
- wk_editor->priv->stamp = e_web_extension_container_reserve_stamp (wk_editor->priv->container);
-
- g_signal_connect_object (wk_editor->priv->container, "page-proxy-changed",
- G_CALLBACK (e_webkit_editor_page_proxy_changed_cb), wk_editor, 0);
+ wk_editor->priv->normal_paragraph_width = 71;
+ wk_editor->priv->magic_links = TRUE;
+ wk_editor->priv->magic_smileys = FALSE;
+ wk_editor->priv->unicode_smileys = FALSE;
+ wk_editor->priv->wrap_quoted_text_in_replies = TRUE;
g_signal_connect (
wk_editor, "load-changed",
@@ -6604,14 +5552,6 @@ e_webkit_editor_init (EWebKitEditor *wk_editor)
wk_editor, "state-flags-changed",
G_CALLBACK (webkit_editor_style_updated_cb), NULL);
- wk_editor->priv->owner_change_primary_clipboard_cb_id = g_signal_connect (
- gtk_clipboard_get (GDK_SELECTION_PRIMARY), "owner-change",
- G_CALLBACK (webkit_editor_primary_clipboard_owner_change_cb), wk_editor);
-
- wk_editor->priv->owner_change_clipboard_cb_id = g_signal_connect (
- gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), "owner-change",
- G_CALLBACK (webkit_editor_clipboard_owner_change_cb), wk_editor);
-
g_settings = e_util_ref_settings ("org.gnome.desktop.interface");
g_signal_connect (
g_settings, "changed::font-name",
@@ -6647,17 +5587,11 @@ e_webkit_editor_init (EWebKitEditor *wk_editor)
wk_editor->priv->can_paste = FALSE;
wk_editor->priv->can_undo = FALSE;
wk_editor->priv->can_redo = FALSE;
- wk_editor->priv->copy_paste_clipboard_in_view = FALSE;
- wk_editor->priv->copy_paste_primary_in_view = FALSE;
- wk_editor->priv->copy_cut_actions_triggered = FALSE;
- wk_editor->priv->pasting_primary_clipboard = FALSE;
- wk_editor->priv->pasting_from_itself_extension_value = FALSE;
wk_editor->priv->current_user_stylesheet = NULL;
- wk_editor->priv->emit_load_finished_when_extension_is_ready = FALSE;
- wk_editor->priv->suppress_color_changes = FALSE;
- wk_editor->priv->font_color = gdk_rgba_copy (&black);
- wk_editor->priv->background_color = gdk_rgba_copy (&white);
+ wk_editor->priv->font_color = NULL;
+ wk_editor->priv->background_color = NULL;
+ wk_editor->priv->body_font_name = NULL;
wk_editor->priv->font_name = NULL;
wk_editor->priv->font_size = E_CONTENT_EDITOR_FONT_SIZE_NORMAL;
wk_editor->priv->block_format = E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH;
@@ -6665,11 +5599,6 @@ e_webkit_editor_init (EWebKitEditor *wk_editor)
wk_editor->priv->start_bottom = E_THREE_STATE_INCONSISTENT;
wk_editor->priv->top_signature = E_THREE_STATE_INCONSISTENT;
-
- wk_editor->priv->web_extension_selection_changed_cb_id = 0;
- wk_editor->priv->web_extension_content_changed_cb_id = 0;
- wk_editor->priv->web_extension_undo_redo_state_changed_cb_id = 0;
- wk_editor->priv->web_extension_user_changed_default_colors_cb_id = 0;
}
static void
@@ -6679,8 +5608,8 @@ e_webkit_editor_content_editor_init (EContentEditorInterface *iface)
iface->update_styles = webkit_editor_update_styles;
iface->insert_content = webkit_editor_insert_content;
iface->get_content = webkit_editor_get_content;
+ iface->get_content_finish = webkit_editor_get_content_finish;
iface->insert_image = webkit_editor_insert_image;
- iface->insert_image_from_mime_part = webkit_editor_insert_image_from_mime_part;
iface->insert_emoticon = webkit_editor_insert_emoticon;
iface->move_caret_on_coordinates = webkit_editor_move_caret_on_coordinates;
iface->cut = webkit_editor_cut;
@@ -6691,13 +5620,11 @@ e_webkit_editor_content_editor_init (EContentEditorInterface *iface)
iface->redo = webkit_editor_redo;
iface->clear_undo_redo_history = webkit_editor_clear_undo_redo_history;
iface->set_spell_checking_languages = webkit_editor_set_spell_checking_languages;
- /* FIXME WK2 iface->get_selected_text = webkit_editor_get_selected_text; */
iface->get_caret_word = webkit_editor_get_caret_word;
iface->replace_caret_word = webkit_editor_replace_caret_word;
iface->select_all = webkit_editor_select_all;
iface->selection_indent = webkit_editor_selection_indent;
iface->selection_unindent = webkit_editor_selection_unindent;
- /* FIXME WK2 iface->create_link = webkit_editor_create_link; */
iface->selection_unlink = webkit_editor_selection_unlink;
iface->find = webkit_editor_find;
iface->replace = webkit_editor_replace;
@@ -6705,11 +5632,11 @@ e_webkit_editor_content_editor_init (EContentEditorInterface *iface)
iface->selection_save = webkit_editor_selection_save;
iface->selection_restore = webkit_editor_selection_restore;
iface->selection_wrap = webkit_editor_selection_wrap;
- iface->get_caret_position = webkit_editor_get_caret_position;
- iface->get_caret_offset = webkit_editor_get_caret_offset;
iface->get_current_signature_uid = webkit_editor_get_current_signature_uid;
iface->is_ready = webkit_editor_is_ready;
iface->insert_signature = webkit_editor_insert_signature;
+ iface->on_dialog_open = webkit_editor_on_dialog_open;
+ iface->on_dialog_close = webkit_editor_on_dialog_close;
iface->delete_cell_contents = webkit_editor_delete_cell_contents;
iface->delete_column = webkit_editor_delete_column;
iface->delete_row = webkit_editor_delete_row;
@@ -6718,8 +5645,6 @@ e_webkit_editor_content_editor_init (EContentEditorInterface *iface)
iface->insert_column_before = webkit_editor_insert_column_before;
iface->insert_row_above = webkit_editor_insert_row_above;
iface->insert_row_below = webkit_editor_insert_row_below;
- iface->on_h_rule_dialog_open = webkit_editor_on_h_rule_dialog_open;
- iface->on_h_rule_dialog_close = webkit_editor_on_h_rule_dialog_close;
iface->h_rule_set_align = webkit_editor_h_rule_set_align;
iface->h_rule_get_align = webkit_editor_h_rule_get_align;
iface->h_rule_set_size = webkit_editor_h_rule_set_size;
@@ -6728,8 +5653,6 @@ e_webkit_editor_content_editor_init (EContentEditorInterface *iface)
iface->h_rule_get_width = webkit_editor_h_rule_get_width;
iface->h_rule_set_no_shade = webkit_editor_h_rule_set_no_shade;
iface->h_rule_get_no_shade = webkit_editor_h_rule_get_no_shade;
- iface->on_image_dialog_open = webkit_editor_on_image_dialog_open;
- iface->on_image_dialog_close = webkit_editor_on_image_dialog_close;
iface->image_set_src = webkit_editor_image_set_src;
iface->image_get_src = webkit_editor_image_get_src;
iface->image_set_alt = webkit_editor_image_set_alt;
@@ -6752,10 +5675,8 @@ e_webkit_editor_content_editor_init (EContentEditorInterface *iface)
iface->image_set_width_follow = webkit_editor_image_set_width_follow;
iface->image_get_width = webkit_editor_image_get_width;
iface->image_get_height = webkit_editor_image_get_height;
- iface->on_link_dialog_open = webkit_editor_on_link_dialog_open;
- iface->on_link_dialog_close = webkit_editor_on_link_dialog_close;
- iface->link_set_values = webkit_editor_link_set_values;
- iface->link_get_values = webkit_editor_link_get_values;
+ iface->link_set_properties = webkit_editor_link_set_properties;
+ iface->link_get_properties = webkit_editor_link_get_properties;
iface->page_set_text_color = webkit_editor_page_set_text_color;
iface->page_get_text_color = webkit_editor_page_get_text_color;
iface->page_set_background_color = webkit_editor_page_set_background_color;
@@ -6764,12 +5685,10 @@ e_webkit_editor_content_editor_init (EContentEditorInterface *iface)
iface->page_get_link_color = webkit_editor_page_get_link_color;
iface->page_set_visited_link_color = webkit_editor_page_set_visited_link_color;
iface->page_get_visited_link_color = webkit_editor_page_get_visited_link_color;
+ iface->page_set_font_name = webkit_editor_page_set_font_name;
+ iface->page_get_font_name = webkit_editor_page_get_font_name;
iface->page_set_background_image_uri = webkit_editor_page_set_background_image_uri;
iface->page_get_background_image_uri = webkit_editor_page_get_background_image_uri;
- iface->on_page_dialog_open = webkit_editor_on_page_dialog_open;
- iface->on_page_dialog_close = webkit_editor_on_page_dialog_close;
- iface->on_cell_dialog_open = webkit_editor_on_cell_dialog_open;
- iface->on_cell_dialog_close = webkit_editor_on_cell_dialog_close;
iface->cell_set_v_align = webkit_editor_cell_set_v_align;
iface->cell_get_v_align = webkit_editor_cell_get_v_align;
iface->cell_set_align = webkit_editor_cell_set_align;
@@ -6806,14 +5725,13 @@ e_webkit_editor_content_editor_init (EContentEditorInterface *iface)
iface->table_set_background_image_uri = webkit_editor_table_set_background_image_uri;
iface->table_get_background_color = webkit_editor_table_get_background_color;
iface->table_set_background_color = webkit_editor_table_set_background_color;
- iface->on_table_dialog_open = webkit_editor_on_table_dialog_open;
- iface->on_table_dialog_close = webkit_editor_on_table_dialog_close;
- iface->on_spell_check_dialog_open = webkit_editor_on_spell_check_dialog_open;
- iface->on_spell_check_dialog_close = webkit_editor_on_spell_check_dialog_close;
iface->spell_check_next_word = webkit_editor_spell_check_next_word;
iface->spell_check_prev_word = webkit_editor_spell_check_prev_word;
- iface->on_replace_dialog_open = webkit_editor_on_replace_dialog_open;
- iface->on_replace_dialog_close = webkit_editor_on_replace_dialog_close;
- iface->on_find_dialog_open = webkit_editor_on_find_dialog_open;
- iface->on_find_dialog_close = webkit_editor_on_find_dialog_close;
+}
+
+static void
+e_webkit_editor_cid_resolver_init (ECidResolverInterface *iface)
+{
+ iface->ref_part = e_webkit_editor_cid_resolver_ref_part;
+ /* iface->dup_mime_type = e_webkit_editor_cid_resolver_dup_mime_part; - not needed here */
}
diff --git a/src/modules/webkit-editor/web-extension/CMakeLists.txt
b/src/modules/webkit-editor/web-extension/CMakeLists.txt
index ed59c7ebc7..7ec514acc4 100644
--- a/src/modules/webkit-editor/web-extension/CMakeLists.txt
+++ b/src/modules/webkit-editor/web-extension/CMakeLists.txt
@@ -23,30 +23,28 @@ macro(add_webextension_editor_module _name _sourcesvar _depsvar _defsvar _cflags
endmacro(add_webextension_editor_module)
set(extra_deps
+ evolution-util
evolution-mail
)
set(sources
- e-composer-dom-functions.c
- e-composer-dom-functions.h
- e-dialogs-dom-functions.c
- e-dialogs-dom-functions.h
- e-dom-utils.c
- e-dom-utils.h
- e-editor-dom-functions.c
- e-editor-dom-functions.h
- e-editor-page.c
- e-editor-page.h
- e-editor-undo-redo-manager.c
- e-editor-undo-redo-manager.h
e-editor-web-extension.c
e-editor-web-extension.h
e-editor-web-extension-main.c
- e-editor-web-extension-names.h
)
-set(extra_defines)
-set(extra_cflags)
-set(extra_incdirs)
-set(extra_ldflags)
+set(extra_defines
+ -DEVOLUTION_WEBKITDATADIR=\"${webkitdatadir}\"
+ -DEVOLUTION_SOURCE_WEBKITDATADIR=\"${CMAKE_SOURCE_DIR}/data/webkit\"
+)
+
+set(extra_cflags
+ ${EVOLUTION_DATA_SERVER_CFLAGS}
+)
+set(extra_incdirs
+ ${EVOLUTION_DATA_SERVER_INCLUDE_DIRS}
+)
+set(extra_ldflags
+ ${EVOLUTION_DATA_SERVER_LDFLAGS}
+)
add_webextension_editor_module(module-webkit-editor-webextension
sources
diff --git a/src/modules/webkit-editor/web-extension/e-editor-web-extension-main.c
b/src/modules/webkit-editor/web-extension/e-editor-web-extension-main.c
index a10c233f47..4acccdd9f1 100644
--- a/src/modules/webkit-editor/web-extension/e-editor-web-extension-main.c
+++ b/src/modules/webkit-editor/web-extension/e-editor-web-extension-main.c
@@ -18,39 +18,8 @@
#include "evolution-config.h"
-#include <camel/camel.h>
-
-#define E_UTIL_INCLUDE_WITHOUT_WEBKIT
-#include <e-util/e-util.h>
-#undef E_UTIL_INCLUDE_WITHOUT_WEBKIT
-
#include "e-editor-web-extension.h"
-static void
-connected_to_server_cb (GObject *source_object,
- GAsyncResult *result,
- gpointer user_data)
-{
- EEditorWebExtension *extension = user_data;
- GDBusConnection *connection;
- GError *error = NULL;
-
- g_return_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension));
-
- connection = e_web_extension_container_utils_connect_to_server_finish (result, &error);
- if (!connection) {
- g_warning ("%d %s: Failed to connect to the UI D-Bus server: %s", getpid (), G_STRFUNC,
- error ? error->message : "Unknown error");
- g_clear_error (&error);
- return;
- }
-
- e_editor_web_extension_dbus_register (extension, connection);
-
- g_object_unref (connection);
- g_object_unref (extension);
-}
-
/* Forward declaration */
G_MODULE_EXPORT void webkit_web_extension_initialize_with_user_data (WebKitWebExtension *wk_extension,
GVariant *user_data);
@@ -60,21 +29,7 @@ webkit_web_extension_initialize_with_user_data (WebKitWebExtension *wk_extension
GVariant *user_data)
{
EEditorWebExtension *extension;
- const gchar *guid = NULL, *server_address = NULL;
-
- g_return_if_fail (user_data != NULL);
-
- g_variant_get (user_data, "(&s&s)", &guid, &server_address);
-
- if (!server_address) {
- g_warning ("%d %s: The UI process didn't provide server address", getpid (), G_STRFUNC);
- return;
- }
-
- camel_debug_init ();
extension = e_editor_web_extension_get_default ();
e_editor_web_extension_initialize (extension, wk_extension);
-
- e_web_extension_container_utils_connect_to_server (server_address, NULL, connected_to_server_cb,
g_object_ref (extension));
}
diff --git a/src/modules/webkit-editor/web-extension/e-editor-web-extension.c
b/src/modules/webkit-editor/web-extension/e-editor-web-extension.c
index 05a1d4ac8d..07667f87d7 100644
--- a/src/modules/webkit-editor/web-extension/e-editor-web-extension.c
+++ b/src/modules/webkit-editor/web-extension/e-editor-web-extension.c
@@ -18,2435 +18,508 @@
#include "evolution-config.h"
-#include <string.h>
-
-#include <glib/gstdio.h>
-#include <gio/gio.h>
-#include <gtk/gtk.h>
#include <webkit2/webkit-web-extension.h>
-#include <camel/camel.h>
-#include <webkitdom/webkitdom.h>
+#include <libedataserver/libedataserver.h>
-#define E_UTIL_INCLUDE_WITHOUT_WEBKIT
-#include "mail/e-http-request.h"
+#define E_UTIL_INCLUDE_WITHOUT_WEBKIT 1
+#include "e-util/e-util.h"
#undef E_UTIL_INCLUDE_WITHOUT_WEBKIT
-//#include "e-dom-utils.h"
-#include "e-editor-page.h"
-#include "e-composer-dom-functions.h"
-#include "e-dialogs-dom-functions.h"
-#include "e-editor-dom-functions.h"
-#include "e-editor-undo-redo-manager.h"
-
#include "e-editor-web-extension.h"
-#define E_EDITOR_WEB_EXTENSION_GET_PRIVATE(obj) \
- (G_TYPE_INSTANCE_GET_PRIVATE \
- ((obj), E_TYPE_EDITOR_WEB_EXTENSION, EEditorWebExtensionPrivate))
-
struct _EEditorWebExtensionPrivate {
WebKitWebExtension *wk_extension;
-
- GDBusConnection *dbus_connection;
- guint registration_id;
-
- GSList *pages; /* EEditorPage * */
+ ESpellChecker *spell_checker;
};
-static CamelDataCache *emd_global_http_cache = NULL;
-
-static const gchar *introspection_xml =
-"<node>"
-" <interface name='" E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE "'>"
-" <signal name='ExtensionObjectReady'>"
-" </signal>"
-" <method name='GetExtensionHandlesPages'>"
-" <arg type='at' name='array' direction='out'/>"
-" </method>"
-" <signal name='ExtensionHandlesPage'>"
-" <arg type='t' name='page_id' direction='out'/>"
-" <arg type='i' name='stamp' direction='out'/>"
-" </signal>"
-"<!-- ********************************************************* -->"
-"<!-- SIGNALS -->"
-"<!-- ********************************************************* -->"
-" <signal name='SelectionChanged'>"
-" <arg type='t' name='page_id' direction='out'/>"
-" <arg type='i' name='alignment' direction='out'/>"
-" <arg type='i' name='block_format' direction='out'/>"
-" <arg type='b' name='indented' direction='out'/>"
-" <arg type='i' name='style_flags' direction='out'/>"
-" <arg type='i' name='font_size' direction='out'/>"
-" <arg type='s' name='font_color' direction='out'/>"
-" </signal>"
-" <signal name='ContentChanged'>"
-" <arg type='t' name='page_id' direction='out'/>"
-" </signal>"
-" <signal name='UndoRedoStateChanged'>"
-" <arg type='t' name='page_id' direction='out'/>"
-" <arg type='b' name='can_undo' direction='out'/>"
-" <arg type='b' name='can_redo' direction='out'/>"
-" </signal>"
-" <signal name='UserChangedDefaultColors'>"
-" <arg type='b' name='suppress_color_changes' direction='out'/>"
-" </signal>"
-"<!-- ********************************************************* -->"
-"<!-- METHODS -->"
-"<!-- ********************************************************* -->"
-"<!-- ********************************************************* -->"
-"<!-- FOR TESTING ONLY -->"
-"<!-- ********************************************************* -->"
-" <method name='TestHTMLEqual'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='html1' direction='in'/>"
-" <arg type='s' name='html2' direction='in'/>"
-" <arg type='b' name='equal' direction='out'/>"
-" </method>"
-"<!-- ********************************************************* -->"
-"<!-- GENERIC -->"
-"<!-- ********************************************************* -->"
-" <method name='ElementHasAttribute'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='element_id' direction='in'/>"
-" <arg type='s' name='attribute' direction='in'/>"
-" <arg type='b' name='has_attribute' direction='out'/>"
-" </method>"
-" <method name='ElementGetAttribute'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='element_id' direction='in'/>"
-" <arg type='s' name='attribute' direction='in'/>"
-" <arg type='s' name='value' direction='out'/>"
-" </method>"
-" <method name='ElementGetAttributeBySelector'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='selector' direction='in'/>"
-" <arg type='s' name='attribute' direction='in'/>"
-" <arg type='s' name='value' direction='out'/>"
-" </method>"
-" <method name='ElementRemoveAttribute'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='element_id' direction='in'/>"
-" <arg type='s' name='attribute' direction='in'/>"
-" </method>"
-" <method name='ElementRemoveAttributeBySelector'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='selector' direction='in'/>"
-" <arg type='s' name='attribute' direction='in'/>"
-" </method>"
-" <method name='ElementSetAttribute'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='element_id' direction='in'/>"
-" <arg type='s' name='attribute' direction='in'/>"
-" <arg type='s' name='value' direction='in'/>"
-" </method>"
-" <method name='ElementSetAttributeBySelector'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='selector' direction='in'/>"
-" <arg type='s' name='attribute' direction='in'/>"
-" <arg type='s' name='value' direction='in'/>"
-" </method>"
-" <method name='ElementGetTagName'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='element_id' direction='in'/>"
-" <arg type='s' name='tag_name' direction='out'/>"
-" </method>"
-"<!-- ********************************************************* -->"
-"<!-- Functions that are specific to composer -->"
-"<!-- ********************************************************* -->"
-" <method name='RemoveImageAttributesFromElementBySelector'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='selector' direction='in'/>"
-" </method>"
-"<!-- ********************************************************* -->"
-"<!-- Functions that are used in EEditorCellDialog -->"
-"<!-- ********************************************************* -->"
-" <method name='EEditorCellDialogMarkCurrentCellElement'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='element_id' direction='in'/>"
-" </method>"
-" <method name='EEditorCellDialogSaveHistoryOnExit'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='EEditorCellDialogSetElementVAlign'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='value' direction='in'/>"
-" <arg type='i' name='scope' direction='in'/>"
-" </method>"
-" <method name='EEditorCellDialogSetElementAlign'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='value' direction='in'/>"
-" <arg type='i' name='scope' direction='in'/>"
-" </method>"
-" <method name='EEditorCellDialogSetElementNoWrap'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='b' name='value' direction='in'/>"
-" <arg type='i' name='scope' direction='in'/>"
-" </method>"
-" <method name='EEditorCellDialogSetElementHeaderStyle'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='b' name='value' direction='in'/>"
-" <arg type='i' name='scope' direction='in'/>"
-" </method>"
-" <method name='EEditorCellDialogSetElementWidth'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='value' direction='in'/>"
-" <arg type='i' name='scope' direction='in'/>"
-" </method>"
-" <method name='EEditorCellDialogSetElementColSpan'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='i' name='value' direction='in'/>"
-" <arg type='i' name='scope' direction='in'/>"
-" </method>"
-" <method name='EEditorCellDialogSetElementRowSpan'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='i' name='value' direction='in'/>"
-" <arg type='i' name='scope' direction='in'/>"
-" </method>"
-" <method name='EEditorCellDialogSetElementBgColor'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='value' direction='in'/>"
-" <arg type='i' name='scope' direction='in'/>"
-" </method>"
-"<!-- ********************************************************* -->"
-"<!-- Functions that are used in EEditorHRuleDialog -->"
-"<!-- ********************************************************* -->"
-" <method name='EEditorHRuleDialogFindHRule'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='b' name='created_new_hr' direction='out'/>"
-" </method>"
-" <method name='EEditorHRuleDialogOnClose'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-"<!-- ********************************************************* -->"
-"<!-- Functions that are used in EEditorImageDialog -->"
-"<!-- ********************************************************* -->"
-" <method name='EEditorImageDialogMarkImage'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='EEditorImageDialogSaveHistoryOnExit'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='EEditorImageDialogSetElementUrl'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='value' direction='in'/>"
-" </method>"
-" <method name='EEditorImageDialogGetElementUrl'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='value' direction='out'/>"
-" </method>"
-" <method name='ImageElementSetWidth'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='element_id' direction='in'/>"
-" <arg type='i' name='value' direction='in'/>"
-" </method>"
-" <method name='ImageElementGetWidth'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='element_id' direction='in'/>"
-" <arg type='i' name='value' direction='out'/>"
-" </method>"
-" <method name='ImageElementSetHeight'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='element_id' direction='in'/>"
-" <arg type='i' name='value' direction='in'/>"
-" </method>"
-" <method name='ImageElementGetHeight'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='element_id' direction='in'/>"
-" <arg type='i' name='value' direction='out'/>"
-" </method>"
-" <method name='ImageElementGetNaturalWidth'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='element_id' direction='in'/>"
-" <arg type='i' name='value' direction='out'/>"
-" </method>"
-" <method name='ImageElementGetNaturalHeight'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='element_id' direction='in'/>"
-" <arg type='i' name='value' direction='out'/>"
-" </method>"
-" <method name='ImageElementSetHSpace'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='element_id' direction='in'/>"
-" <arg type='i' name='value' direction='in'/>"
-" </method>"
-" <method name='ImageElementGetHSpace'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='element_id' direction='in'/>"
-" <arg type='i' name='value' direction='out'/>"
-" </method>"
-" <method name='ImageElementSetVSpace'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='element_id' direction='in'/>"
-" <arg type='i' name='value' direction='in'/>"
-" </method>"
-" <method name='ImageElementGetVSpace'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='element_id' direction='in'/>"
-" <arg type='i' name='value' direction='out'/>"
-" </method>"
-"<!-- ********************************************************* -->"
-"<!-- Functions that are used in EEditorLinkDialog -->"
-"<!-- ********************************************************* -->"
-" <method name='EEditorLinkDialogOk'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='url' direction='in'/>"
-" <arg type='s' name='inner_text' direction='in'/>"
-" </method>"
-" <method name='EEditorLinkDialogShow'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='url' direction='out'/>"
-" <arg type='s' name='inner_text' direction='out'/>"
-" </method>"
-" <method name='EEditorLinkDialogOnOpen'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='EEditorLinkDialogOnClose'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='EEditorLinkDialogUnlink'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-"<!-- ********************************************************* -->"
-"<!-- Functions that are used in EEditorPageDialog -->"
-"<!-- ********************************************************* -->"
-" <method name='EEditorPageDialogSaveHistory'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='EEditorPageDialogSaveHistoryOnExit'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-"<!-- ********************************************************* -->"
-"<!-- Functions that are used in EEditorSpellCheckDialog -->"
-"<!-- ********************************************************* -->"
-" <method name='EEditorSpellCheckDialogNext'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='word' direction='in'/>"
-" <arg type='as' name='languages' direction='in'/>"
-" <arg type='s' name='next_word' direction='out'/>"
-" </method>"
-" <method name='EEditorSpellCheckDialogPrev'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='word' direction='in'/>"
-" <arg type='as' name='languages' direction='in'/>"
-" <arg type='s' name='prev_word' direction='out'/>"
-" </method>"
-"<!-- ********************************************************* -->"
-"<!-- Functions that are used in EEditorTableDialog -->"
-"<!-- ********************************************************* -->"
-" <method name='EEditorTableDialogSetRowCount'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='u' name='value' direction='in'/>"
-" </method>"
-" <method name='EEditorTableDialogGetRowCount'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='u' name='value' direction='out'/>"
-" </method>"
-" <method name='EEditorTableDialogSetColumnCount'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='u' name='value' direction='in'/>"
-" </method>"
-" <method name='EEditorTableDialogGetColumnCount'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='u' name='value' direction='out'/>"
-" </method>"
-" <method name='EEditorTableDialogShow'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='b' name='created_new_table' direction='out'/>"
-" </method>"
-" <method name='EEditorTableDialogSaveHistoryOnExit'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-"<!-- ********************************************************* -->"
-"<!-- Functions that are used in EEditorActions -->"
-"<!-- ********************************************************* -->"
-" <method name='TableCellElementGetNoWrap'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='element_id' direction='in'/>"
-" <arg type='b' name='no_wrap' direction='out'/>"
-" </method>"
-" <method name='TableCellElementGetRowSpan'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='element_id' direction='in'/>"
-" <arg type='i' name='row_span' direction='out'/>"
-" </method>"
-" <method name='TableCellElementGetColSpan'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='element_id' direction='in'/>"
-" <arg type='i' name='col_span' direction='out'/>"
-" </method>"
-" <method name='EEditorDialogDeleteCellContents'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='EEditorDialogDeleteColumn'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='EEditorDialogDeleteRow'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='EEditorDialogDeleteTable'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='EEditorDialogInsertColumnAfter'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='EEditorDialogInsertColumnBefore'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='EEditorDialogInsertRowAbove'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='EEditorDialogInsertRowBelow'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='EEditorActionsSaveHistoryForCut'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-"<!-- ********************************************************* -->"
-"<!-- Functions that are used in EEditorView -->"
-"<!-- ********************************************************* -->"
-" <method name='SetPastingContentFromItself'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='b' name='value' direction='in'/>"
-" </method>"
-" <method name='SetEditorHTMLMode'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='b' name='html_mode' direction='in'/>"
-" <arg type='b' name='convert' direction='in'/>"
-" </method>"
-" <method name='SetConvertInSitu'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='b' name='value' direction='in'/>"
-" <arg type='n' name='start_at_bottom' direction='in'/>"
-" <arg type='n' name='top_signature' direction='in'/>"
-" </method>"
-" <method name='DOMForceSpellCheck'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='DOMTurnSpellCheckOff'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='DOMScrollToCaret'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='DOMEmbedStyleSheet'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='style_sheet_content' direction='in'/>"
-" </method>"
-" <method name='DOMRemoveEmbeddedStyleSheet'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='DOMSaveSelection'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='DOMRestoreSelection'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='DOMUndo'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='DOMRedo'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='DOMQuoteAndInsertTextIntoSelection'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='text' direction='in'/>"
-" <arg type='b' name='is_html' direction='in'/>"
-" </method>"
-" <method name='DOMConvertAndInsertHTMLIntoSelection'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='text' direction='in'/>"
-" <arg type='b' name='is_html' direction='in'/>"
-" </method>"
-" <method name='DOMCheckIfConversionNeeded'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='b' name='conversion_needed' direction='out'/>"
-" </method>"
-" <method name='DOMGetContent'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='from_domain' direction='in'/>"
-" <arg type='i' name='flags' direction='in'/>"
-" <arg type='s' name='content' direction='out'/>"
-" <arg type='v' name='inline_images' direction='out'/>"
-" </method>"
-" <method name='DOMInsertHTML'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='html' direction='in'/>"
-" </method>"
-" <method name='DOMConvertContent'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='preffered_text' direction='in'/>"
-" <arg type='n' name='start_at_bottom' direction='in'/>"
-" <arg type='n' name='top_signature' direction='in'/>"
-" </method>"
-" <method name='DOMAddNewInlineImageIntoList'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='filename' direction='in'/>"
-" <arg type='s' name='cid_src' direction='in'/>"
-" <arg type='s' name='src' direction='in'/>"
-" </method>"
-" <method name='DOMReplaceImageSrc'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='selector' direction='in'/>"
-" <arg type='s' name='uri' direction='in'/>"
-" </method>"
-" <method name='DOMMoveSelectionOnPoint'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='i' name='x' direction='in'/>"
-" <arg type='i' name='y' direction='in'/>"
-" <arg type='b' name='cancel_if_not_collapsed' direction='in'/>"
-" </method>"
-" <method name='DOMInsertSmiley'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='smiley_name' direction='in'/>"
-" </method>"
-" <method name='DOMLastDropOperationDidCopy'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-"<!-- ********************************************************* -->"
-"<!-- Functions that are used in EEditorSelection -->"
-"<!-- ********************************************************* -->"
-" <method name='DOMSelectionIndent'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='DOMSelectionInsertImage'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='uri' direction='in'/>"
-" </method>"
-" <method name='DOMInsertReplaceAllHistoryEvent'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='search_text' direction='in'/>"
-" <arg type='s' name='replacement' direction='in'/>"
-" </method>"
-" <method name='DOMSelectionReplace'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='replacement' direction='in'/>"
-" </method>"
-" <method name='DOMSelectionSetAlignment'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='i' name='alignment' direction='in'/>"
-" </method>"
-" <method name='DOMSelectionSetBold'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='b' name='bold' direction='in'/>"
-" </method>"
-" <method name='DOMSelectionSetBlockFormat'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='i' name='block_format' direction='in'/>"
-" </method>"
-" <method name='DOMSelectionSetFontColor'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='color' direction='in'/>"
-" </method>"
-" <method name='DOMSelectionSetFontSize'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='i' name='font_size' direction='in'/>"
-" </method>"
-" <method name='DOMSelectionSetItalic'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='b' name='italic' direction='in'/>"
-" </method>"
-" <method name='DOMSelectionSetMonospaced'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='b' name='monospaced' direction='in'/>"
-" </method>"
-" <method name='DOMSelectionSetStrikethrough'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='b' name='strikethrough' direction='in'/>"
-" </method>"
-" <method name='DOMSelectionSetSubscript'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='b' name='subscript' direction='in'/>"
-" </method>"
-" <method name='DOMSelectionSetSuperscript'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='b' name='superscript' direction='in'/>"
-" </method>"
-" <method name='DOMSelectionSetUnderline'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='b' name='underline' direction='in'/>"
-" </method>"
-" <method name='DOMSelectionUnindent'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='DOMSelectionWrap'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" <method name='DOMGetCaretWord'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='word' direction='out'/>"
-" </method>"
-" <method name='DOMReplaceCaretWord'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='replacement' direction='in'/>"
-" </method>"
-"<!-- ********************************************************* -->"
-"<!-- Functions that are used in EComposerPrivate -->"
-"<!-- ********************************************************* -->"
-" <method name='DOMInsertSignature'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='content' direction='in'/>"
-" <arg type='b' name='is_html' direction='in'/>"
-" <arg type='s' name='signature_id' direction='in'/>"
-" <arg type='b' name='set_signature_from_message' direction='in'/>"
-" <arg type='b' name='check_if_signature_is_changed' direction='in'/>"
-" <arg type='b' name='ignore_next_signature_change' direction='in'/>"
-" <arg type='n' name='start_at_bottom' direction='in'/>"
-" <arg type='n' name='top_signature' direction='in'/>"
-" <arg type='s' name='new_signature_id' direction='out'/>"
-" <arg type='b' name='out_set_signature_from_message' direction='out'/>"
-" <arg type='b' name='out_check_if_signature_is_changed' direction='out'/>"
-" <arg type='b' name='out_ignore_next_signature_change' direction='out'/>"
-" </method>"
-" <method name='DOMGetActiveSignatureUid'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='s' name='uid' direction='out'/>"
-" </method>"
-"<!-- ********************************************************* -->"
-"<!-- Functions that are used in External Editor plugin -->"
-"<!-- ********************************************************* -->"
-" <method name='DOMGetCaretPosition'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='u' name='position' direction='out'/>"
-" </method>"
-" <method name='DOMGetCaretOffset'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" <arg type='u' name='offset' direction='out'/>"
-" </method>"
-" <method name='DOMClearUndoRedoHistory'>"
-" <arg type='t' name='page_id' direction='in'/>"
-" </method>"
-" </interface>"
-"</node>";
-
-G_DEFINE_TYPE (EEditorWebExtension, e_editor_web_extension, G_TYPE_OBJECT)
-
-static EEditorPage *
-get_editor_page (EEditorWebExtension *extension,
- guint64 page_id)
+G_DEFINE_TYPE_WITH_PRIVATE (EEditorWebExtension, e_editor_web_extension, G_TYPE_OBJECT)
+
+static void
+e_editor_web_extension_dispose (GObject *object)
{
- GSList *link;
+ EEditorWebExtension *extension = E_EDITOR_WEB_EXTENSION (object);
- g_return_val_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension), NULL);
+ g_clear_object (&extension->priv->wk_extension);
+ g_clear_object (&extension->priv->spell_checker);
- for (link = extension->priv->pages; link; link = g_slist_next (link)) {
- EEditorPage *page = link->data;
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_editor_web_extension_parent_class)->dispose (object);
+}
- if (page && e_editor_page_get_page_id (page) == page_id)
- return page;
- }
+static void
+e_editor_web_extension_class_init (EEditorWebExtensionClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
- return NULL;
+ object_class->dispose = e_editor_web_extension_dispose;
}
-static EEditorPage *
-get_editor_page_or_return_dbus_error (GDBusMethodInvocation *invocation,
- EEditorWebExtension *extension,
- guint64 page_id)
+static void
+e_editor_web_extension_init (EEditorWebExtension *extension)
{
- WebKitWebPage *web_page;
- EEditorPage *editor_page;
+ extension->priv = e_editor_web_extension_get_instance_private (extension);
+ extension->priv->spell_checker = NULL;
+}
- g_return_val_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension), NULL);
+static gpointer
+e_editor_web_extension_create_instance (gpointer data)
+{
+ return g_object_new (E_TYPE_EDITOR_WEB_EXTENSION, NULL);
+}
- web_page = webkit_web_extension_get_page (extension->priv->wk_extension, page_id);
- if (!web_page) {
- g_dbus_method_invocation_return_error (
- invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
- "Invalid page ID: %" G_GUINT64_FORMAT, page_id);
+EEditorWebExtension *
+e_editor_web_extension_get_default (void)
+{
+ static GOnce once_init = G_ONCE_INIT;
+ return E_EDITOR_WEB_EXTENSION (g_once (&once_init, e_editor_web_extension_create_instance, NULL));
+}
- return NULL;
- }
+static gboolean
+use_sources_js_file (void)
+{
+ static gint res = -1;
- editor_page = get_editor_page (extension, page_id);
- if (!editor_page) {
- g_dbus_method_invocation_return_error (
- invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
- "Invalid page ID: %" G_GUINT64_FORMAT, page_id);
- }
+ if (res == -1)
+ res = g_strcmp0 (g_getenv ("E_HTML_EDITOR_TEST_SOURCES"), "1") == 0 ? 1 : 0;
- return editor_page;
+ return res;
}
static void
-handle_method_call (GDBusConnection *connection,
- const char *sender,
- const char *object_path,
- const char *interface_name,
- const char *method_name,
- GVariant *parameters,
- GDBusMethodInvocation *invocation,
- gpointer user_data)
+load_javascript_file (JSCContext *jsc_context,
+ const gchar *js_filename)
{
- guint64 page_id;
- EEditorWebExtension *extension = E_EDITOR_WEB_EXTENSION (user_data);
- WebKitDOMDocument *document;
- EEditorPage *editor_page;
-
- if (g_strcmp0 (interface_name, E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE) != 0)
- return;
-
- if (camel_debug ("webkit:editor"))
- printf ("EEditorWebExtension - %s - %s\n", G_STRFUNC, method_name);
-
- if (g_strcmp0 (method_name, "GetExtensionHandlesPages") == 0) {
- GVariantBuilder *builder;
- GSList *link;
+ JSCValue *result;
+ JSCException *exception;
+ gchar *content, *filename = NULL, *resource_uri;
+ gsize length = 0;
+ GError *error = NULL;
- builder = g_variant_builder_new (G_VARIANT_TYPE ("at"));
+ g_return_if_fail (jsc_context != NULL);
- for (link = extension->priv->pages; link; link = g_slist_next (link)) {
- EEditorPage *page = link->data;
+ if (use_sources_js_file ()) {
+ filename = g_build_filename (EVOLUTION_SOURCE_WEBKITDATADIR, js_filename, NULL);
- if (page) {
- g_variant_builder_add (builder, "t", e_editor_page_get_page_id (page));
- g_variant_builder_add (builder, "t", (guint64) e_editor_page_get_stamp
(page));
- }
- }
-
- g_dbus_method_invocation_return_value (invocation,
- g_variant_new ("(at)", builder));
-
- g_variant_builder_unref (builder);
- } else if (g_strcmp0 (method_name, "TestHTMLEqual") == 0) {
- gboolean equal = FALSE;
- const gchar *html1 = NULL, *html2 = NULL;
-
- g_variant_get (parameters, "(t&s&s)", &page_id, &html1, &html2);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- equal = e_editor_dom_test_html_equal (document, html1, html2);
-
- g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", equal));
- } else if (g_strcmp0 (method_name, "ElementHasAttribute") == 0) {
- gboolean value = FALSE;
- const gchar *element_id, *attribute;
- WebKitDOMElement *element;
-
- g_variant_get (
- parameters, "(t&s&s)", &page_id, &element_id, &attribute);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_get_element_by_id (document, element_id);
- if (element)
- value = webkit_dom_element_has_attribute (element, attribute);
-
- g_dbus_method_invocation_return_value (
- invocation, g_variant_new ("(b)", value));
- } else if (g_strcmp0 (method_name, "ElementGetAttribute") == 0) {
- const gchar *element_id, *attribute;
- gchar *value = NULL;
- WebKitDOMElement *element;
-
- g_variant_get (
- parameters, "(t&s&s)", &page_id, &element_id, &attribute);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_get_element_by_id (document, element_id);
- if (element)
- value = webkit_dom_element_get_attribute (element, attribute);
-
- g_dbus_method_invocation_return_value (
- invocation,
- g_variant_new (
- "(@s)",
- g_variant_new_take_string (
- value ? value : g_strdup (""))));
- } else if (g_strcmp0 (method_name, "ElementGetAttributeBySelector") == 0) {
- const gchar *attribute, *selector;
- gchar *value = NULL;
- WebKitDOMElement *element;
-
- g_variant_get (
- parameters, "(t&s&s)", &page_id, &selector, &attribute);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_query_selector (document, selector, NULL);
- if (element)
- value = webkit_dom_element_get_attribute (element, attribute);
-
- g_dbus_method_invocation_return_value (
- invocation,
- g_variant_new (
- "(@s)",
- g_variant_new_take_string (
- value ? value : g_strdup (""))));
- } else if (g_strcmp0 (method_name, "ElementRemoveAttribute") == 0) {
- const gchar *element_id, *attribute;
- WebKitDOMElement *element;
-
- g_variant_get (
- parameters, "(t&s&s)", &page_id, &element_id, &attribute);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_get_element_by_id (document, element_id);
- if (element)
- webkit_dom_element_remove_attribute (element, attribute);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "ElementRemoveAttributeBySelector") == 0) {
- const gchar *attribute, *selector;
- WebKitDOMElement *element;
-
- g_variant_get (
- parameters, "(t&s&s)", &page_id, &selector, &attribute);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_query_selector (document, selector, NULL);
- if (element)
- webkit_dom_element_remove_attribute (element, attribute);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "ElementSetAttribute") == 0) {
- const gchar *element_id, *attribute, *value;
- WebKitDOMElement *element;
-
- g_variant_get (
- parameters,
- "(t&s&s&s)",
- &page_id, &element_id, &attribute, &value);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_get_element_by_id (document, element_id);
- if (element)
- webkit_dom_element_set_attribute (
- element, attribute, value, NULL);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "ElementSetAttributeBySelector") == 0) {
- const gchar *attribute, *selector, *value;
- WebKitDOMElement *element;
-
- g_variant_get (
- parameters, "(t&s&s&s)", &page_id, &selector, &attribute, &value);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_query_selector (document, selector, NULL);
- if (element) {
- if (g_strcmp0 (selector, "body") == 0 &&
- g_strcmp0 (attribute, "link") == 0)
- e_editor_dom_set_link_color (editor_page, value);
- else if (g_strcmp0 (selector, "body") == 0 &&
- g_strcmp0 (attribute, "vlink") == 0)
- e_editor_dom_set_visited_link_color (editor_page, value);
- else
- webkit_dom_element_set_attribute (
- element, attribute, value, NULL);
- }
+ if (!g_file_test (filename, G_FILE_TEST_EXISTS)) {
+ g_warning ("Cannot find '%s', using installed file '%s/%s' instead", filename,
EVOLUTION_WEBKITDATADIR, js_filename);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "ElementGetTagName") == 0) {
- const gchar *element_id;
- gchar *value = NULL;
- WebKitDOMElement *element;
-
- g_variant_get (parameters, "(t&s)", &page_id, &element_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_get_element_by_id (document, element_id);
- if (element)
- value = webkit_dom_element_get_tag_name (element);
-
- g_dbus_method_invocation_return_value (
- invocation,
- g_variant_new (
- "(@s)",
- g_variant_new_take_string (
- value ? value : g_strdup (""))));
- } else if (g_strcmp0 (method_name, "RemoveImageAttributesFromElementBySelector") == 0) {
- const gchar *selector;
- WebKitDOMElement *element;
-
- g_variant_get (parameters, "(t&s)", &page_id, &selector);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_query_selector (document, selector, NULL);
- if (element) {
- webkit_dom_element_remove_attribute (element, "background");
- webkit_dom_element_remove_attribute (element, "data-uri");
- webkit_dom_element_remove_attribute (element, "data-inline");
- webkit_dom_element_remove_attribute (element, "data-name");
+ g_clear_pointer (&filename, g_free);
}
+ }
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorCellDialogMarkCurrentCellElement") == 0) {
- const gchar *element_id;
-
- g_variant_get (parameters, "(t&s)", &page_id, &element_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_cell_mark_current_cell_element (editor_page, element_id);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorCellDialogSaveHistoryOnExit") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_cell_save_history_on_exit (editor_page);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementVAlign") == 0) {
- const gchar *value;
- EContentEditorScope scope;
-
- g_variant_get (parameters, "(t&si)", &page_id, &value, &scope);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_cell_set_element_v_align (editor_page, value, scope);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementAlign") == 0) {
- const gchar *value;
- EContentEditorScope scope;
-
- g_variant_get (parameters, "(t&si)", &page_id, &value, &scope);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_cell_set_element_align (editor_page, value, scope);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementNoWrap") == 0) {
- gboolean value;
- EContentEditorScope scope;
-
- g_variant_get (parameters, "(tbi)", &page_id, &value, &scope);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_cell_set_element_no_wrap (editor_page, value, scope);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementHeaderStyle") == 0) {
- gboolean value;
- EContentEditorScope scope;
-
- g_variant_get (parameters, "(tbi)", &page_id, &value, &scope);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_cell_set_element_header_style (editor_page, value, scope);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementWidth") == 0) {
- const gchar *value;
- EContentEditorScope scope;
-
- g_variant_get (parameters, "(t&si)", &page_id, &value, &scope);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_cell_set_element_width (editor_page, value, scope);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementColSpan") == 0) {
- glong value;
- EContentEditorScope scope;
-
- g_variant_get (parameters, "(tii)", &page_id, &value, &scope);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_cell_set_element_col_span (editor_page, value, scope);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementRowSpan") == 0) {
- glong value;
- EContentEditorScope scope;
-
- g_variant_get (parameters, "(tii)", &page_id, &value, &scope);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_cell_set_element_row_span (editor_page, value, scope);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementBgColor") == 0) {
- const gchar *value;
- EContentEditorScope scope;
-
- g_variant_get (parameters, "(t&si)", &page_id, &value, &scope);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_cell_set_element_bg_color (editor_page, value, scope);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorHRuleDialogFindHRule") == 0) {
- gboolean created_new_hr = FALSE;
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- created_new_hr = e_dialogs_dom_h_rule_find_hrule (editor_page);
-
- g_dbus_method_invocation_return_value (
- invocation, g_variant_new ("(b)", created_new_hr));
- } else if (g_strcmp0 (method_name, "EEditorHRuleDialogOnClose") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_h_rule_dialog_on_close (editor_page);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorImageDialogMarkImage") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_image_mark_image (editor_page);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorImageDialogSaveHistoryOnExit") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_image_save_history_on_exit (editor_page);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorImageDialogSetElementUrl") == 0) {
- const gchar *value;
-
- g_variant_get (parameters, "(t&s)", &page_id, &value);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_image_set_element_url (editor_page, value);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorImageDialogGetElementUrl") == 0) {
- gchar *value;
-
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- value = e_dialogs_dom_image_get_element_url (editor_page);
-
- g_dbus_method_invocation_return_value (
- invocation,
- g_variant_new (
- "(@s)",
- g_variant_new_take_string (
- value ? value : g_strdup (""))));
- } else if (g_strcmp0 (method_name, "ImageElementSetWidth") == 0) {
- const gchar *element_id;
- gint32 value;
- WebKitDOMElement *element;
-
- g_variant_get (
- parameters, "(t&si)", &page_id, &element_id, &value);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_get_element_by_id (document, element_id);
- if (element)
- webkit_dom_html_image_element_set_width (
- WEBKIT_DOM_HTML_IMAGE_ELEMENT (element), value);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "ImageElementGetWidth") == 0) {
- const gchar *element_id;
- glong value = 0;
- WebKitDOMElement *element;
-
- g_variant_get (
- parameters, "(t&s)", &page_id, &element_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_get_element_by_id (document, element_id);
- if (element)
- value = webkit_dom_html_image_element_get_width (
- WEBKIT_DOM_HTML_IMAGE_ELEMENT (element));
-
- g_dbus_method_invocation_return_value (
- invocation, g_variant_new ("(i)", value));
- } else if (g_strcmp0 (method_name, "ImageElementSetHeight") == 0) {
- const gchar *element_id;
- gint32 value;
- WebKitDOMElement *element;
-
- g_variant_get (
- parameters, "(t&si)", &page_id, &element_id, &value);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_get_element_by_id (document, element_id);
- if (element)
- webkit_dom_html_image_element_set_width (
- WEBKIT_DOM_HTML_IMAGE_ELEMENT (element), value);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "ImageElementGetHeight") == 0) {
- const gchar *element_id;
- glong value = 0;
- WebKitDOMElement *element;
-
- g_variant_get (
- parameters, "(t&s)", &page_id, &element_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_get_element_by_id (document, element_id);
- if (element)
- value = webkit_dom_html_image_element_get_height (
- WEBKIT_DOM_HTML_IMAGE_ELEMENT (element));
-
- g_dbus_method_invocation_return_value (
- invocation, g_variant_new ("(i)", value));
- } else if (g_strcmp0 (method_name, "ImageElementGetNaturalWidth") == 0) {
- const gchar *element_id;
- glong value = 0;
- WebKitDOMElement *element;
-
- g_variant_get (
- parameters, "(t&s)", &page_id, &element_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_get_element_by_id (document, element_id);
- if (element)
- value = webkit_dom_html_image_element_get_natural_width (
- WEBKIT_DOM_HTML_IMAGE_ELEMENT (element));
-
- g_dbus_method_invocation_return_value (
- invocation, g_variant_new ("(i)", value));
- } else if (g_strcmp0 (method_name, "ImageElementGetNaturalHeight") == 0) {
- const gchar *element_id;
- glong value = 0;
- WebKitDOMElement *element;
-
- g_variant_get (
- parameters, "(t&s)", &page_id, &element_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_get_element_by_id (document, element_id);
- if (element)
- value = webkit_dom_html_image_element_get_natural_height (
- WEBKIT_DOM_HTML_IMAGE_ELEMENT (element));
-
- g_dbus_method_invocation_return_value (
- invocation, g_variant_new ("(i)", value));
- } else if (g_strcmp0 (method_name, "ImageElementSetHSpace") == 0) {
- const gchar *element_id;
- gint32 value;
- WebKitDOMElement *element;
-
- g_variant_get (
- parameters, "(t&si)", &page_id, &element_id, &value);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_get_element_by_id (document, element_id);
- if (element)
- webkit_dom_html_image_element_set_hspace (
- WEBKIT_DOM_HTML_IMAGE_ELEMENT (element), value);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "ImageElementGetHSpace") == 0) {
- const gchar *element_id;
- glong value = 0;
- WebKitDOMElement *element;
-
- g_variant_get (
- parameters, "(t&s)", &page_id, &element_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_get_element_by_id (document, element_id);
- if (element)
- value = webkit_dom_html_image_element_get_hspace (
- WEBKIT_DOM_HTML_IMAGE_ELEMENT (element));
-
- g_dbus_method_invocation_return_value (
- invocation, g_variant_new ("(i)", value));
- } else if (g_strcmp0 (method_name, "ImageElementSetVSpace") == 0) {
- const gchar *element_id;
- gint32 value;
- WebKitDOMElement *element;
-
- g_variant_get (
- parameters, "(t&si)", &page_id, &element_id, &value);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_get_element_by_id (document, element_id);
- if (element)
- webkit_dom_html_image_element_set_vspace (
- WEBKIT_DOM_HTML_IMAGE_ELEMENT (element), value);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "ImageElementGetVSpace") == 0) {
- const gchar *element_id;
- glong value = 0;
- WebKitDOMElement *element;
-
- g_variant_get (
- parameters, "(t&s)", &page_id, &element_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_get_element_by_id (document, element_id);
- if (element)
- value = webkit_dom_html_image_element_get_vspace (
- WEBKIT_DOM_HTML_IMAGE_ELEMENT (element));
-
- g_dbus_method_invocation_return_value (
- invocation, g_variant_new ("(i)", value));
- } else if (g_strcmp0 (method_name, "EEditorLinkDialogOk") == 0) {
- const gchar *url, *inner_text;
-
- g_variant_get (parameters, "(t&s&s)", &page_id, &url, &inner_text);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_link_commit (editor_page, url, inner_text);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorLinkDialogShow") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- g_dbus_method_invocation_return_value (
- invocation, e_dialogs_dom_link_show (editor_page));
- } else if (g_strcmp0 (method_name, "EEditorPageDialogSaveHistory") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_page_save_history (editor_page);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorPageDialogSaveHistoryOnExit") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_page_save_history_on_exit (editor_page);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorSpellCheckDialogNext") == 0) {
- const gchar *from_word = NULL;
- const gchar * const *languages = NULL;
- gchar *value = NULL;
-
- g_variant_get (parameters, "(t&s^as)", &page_id, &from_word, &languages);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- value = e_dialogs_dom_spell_check_next (editor_page, from_word, languages);
-
- g_dbus_method_invocation_return_value (
- invocation,
- g_variant_new (
- "(@s)",
- g_variant_new_take_string (
- value ? value : g_strdup (""))));
- } else if (g_strcmp0 (method_name, "EEditorSpellCheckDialogPrev") == 0) {
- const gchar *from_word = NULL;
- const gchar * const *languages = NULL;
- gchar *value = NULL;
-
- g_variant_get (parameters, "(t&s^as)", &page_id, &from_word, &languages);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- value = e_dialogs_dom_spell_check_prev (editor_page, from_word, languages);
-
- g_dbus_method_invocation_return_value (
- invocation,
- g_variant_new (
- "(@s)",
- g_variant_new_take_string (
- value ? value : g_strdup (""))));
- } else if (g_strcmp0 (method_name, "EEditorTableDialogSetRowCount") == 0) {
- guint32 value;
-
- g_variant_get (parameters, "(tu)", &page_id, &value);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_table_set_row_count (editor_page, value);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorTableDialogGetRowCount") == 0) {
- gulong value;
-
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- value = e_dialogs_dom_table_get_row_count (editor_page);
-
- g_dbus_method_invocation_return_value (
- invocation, g_variant_new ("(u)", value));
- } else if (g_strcmp0 (method_name, "EEditorTableDialogSetColumnCount") == 0) {
- guint32 value;
-
- g_variant_get (parameters, "(tu)", &page_id, &value);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_table_set_column_count (editor_page, value);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorTableDialogGetColumnCount") == 0) {
- gulong value;
-
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- value = e_dialogs_dom_table_get_column_count (editor_page);
-
- g_dbus_method_invocation_return_value (
- invocation, g_variant_new ("(u)", value));
- } else if (g_strcmp0 (method_name, "EEditorTableDialogShow") == 0) {
- gboolean created_new_table;
-
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- created_new_table = e_dialogs_dom_table_show (editor_page);
-
- g_dbus_method_invocation_return_value (
- invocation, g_variant_new ("(b)", created_new_table));
- } else if (g_strcmp0 (method_name, "EEditorTableDialogSaveHistoryOnExit") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_table_save_history_on_exit (editor_page);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorDialogDeleteCellContents") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_delete_cell_contents (editor_page);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorDialogDeleteColumn") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_delete_column (editor_page);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorDialogDeleteRow") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_delete_row (editor_page);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorDialogDeleteTable") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_delete_table (editor_page);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorDialogInsertColumnAfter") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_insert_column_after (editor_page);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorDialogInsertColumnBefore") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_insert_column_before (editor_page);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorDialogInsertRowAbove") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_insert_row_above (editor_page);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorDialogInsertRowBelow") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_insert_row_below (editor_page);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorLinkDialogOnOpen") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_link_dialog_on_open (editor_page);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorLinkDialogOnClose") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_dialogs_dom_link_dialog_on_close (editor_page);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorLinkDialogUnlink") == 0) {
- EEditorUndoRedoManager *manager;
-
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- manager = e_editor_page_get_undo_redo_manager (editor_page);
- /* Remove the history event that was saved when the dialog was opened */
- e_editor_undo_redo_manager_remove_current_history_event (manager);
-
- e_editor_dom_selection_unlink (editor_page);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "EEditorActionsSaveHistoryForCut") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_save_history_for_cut (editor_page);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "TableCellElementGetNoWrap") == 0) {
- const gchar *element_id;
- gboolean value = FALSE;
- WebKitDOMElement *element;
-
- g_variant_get (parameters, "(t&s)", &page_id, &element_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_get_element_by_id (document, element_id);
- if (element)
- value = webkit_dom_html_table_cell_element_get_no_wrap (
- WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (element));
-
- g_dbus_method_invocation_return_value (
- invocation, g_variant_new ("(b)", value));
- } else if (g_strcmp0 (method_name, "TableCellElementGetRowSpan") == 0) {
- const gchar *element_id;
- glong value = 0;
- WebKitDOMElement *element;
-
- g_variant_get (parameters, "(t&s)", &page_id, &element_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_get_element_by_id (document, element_id);
- if (element)
- value = webkit_dom_html_table_cell_element_get_row_span (
- WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (element));
-
- g_dbus_method_invocation_return_value (
- invocation, g_variant_new ("(i)", value));
- } else if (g_strcmp0 (method_name, "TableCellElementGetColSpan") == 0) {
- const gchar *element_id;
- glong value = 0;
- WebKitDOMElement *element;
-
- g_variant_get (parameters, "(t&s)", &page_id, &element_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- document = e_editor_page_get_document (editor_page);
- element = webkit_dom_document_get_element_by_id (document, element_id);
- if (element)
- value = webkit_dom_html_table_cell_element_get_col_span (
- WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (element));
-
- g_dbus_method_invocation_return_value (
- invocation, g_variant_new ("(i)", value));
- } else if (g_strcmp0 (method_name, "DOMSaveSelection") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_selection_save (editor_page);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMRestoreSelection") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_selection_restore (editor_page);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMUndo") == 0) {
- EEditorUndoRedoManager *manager;
-
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- manager = e_editor_page_get_undo_redo_manager (editor_page);
-
- e_editor_undo_redo_manager_undo (manager);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMRedo") == 0) {
- EEditorUndoRedoManager *manager;
-
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- manager = e_editor_page_get_undo_redo_manager (editor_page);
-
- e_editor_undo_redo_manager_redo (manager);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMTurnSpellCheckOff") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_turn_spell_check_off (editor_page);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMQuoteAndInsertTextIntoSelection") == 0) {
- gboolean is_html = FALSE;
- const gchar *text;
+ if (!filename)
+ filename = g_build_filename (EVOLUTION_WEBKITDATADIR, js_filename, NULL);
- g_variant_get (parameters, "(t&sb)", &page_id, &text, &is_html);
+ if (!g_file_get_contents (filename, &content, &length, &error)) {
+ g_warning ("Failed to load '%s': %s", filename, error ? error->message : "Unknown error");
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ g_clear_error (&error);
+ g_free (filename);
- e_editor_dom_quote_and_insert_text_into_selection (editor_page, text, is_html);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMConvertAndInsertHTMLIntoSelection") == 0) {
- gboolean is_html;
- const gchar *text;
+ return;
+ }
- g_variant_get (parameters, "(t&sb)", &page_id, &text, &is_html);
+ resource_uri = g_strconcat ("resource:///", js_filename, NULL);
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ result = jsc_context_evaluate_with_source_uri (jsc_context, content, length, resource_uri, 1);
- e_editor_dom_convert_and_insert_html_into_selection (editor_page, text, is_html);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMEmbedStyleSheet") == 0) {
- const gchar *style_sheet_content;
+ g_free (resource_uri);
- g_variant_get (parameters, "(t&s)", &page_id, &style_sheet_content);
+ exception = jsc_context_get_exception (jsc_context);
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ if (exception) {
+ g_warning ("Failed to call script '%s': %d:%d: %s",
+ filename,
+ jsc_exception_get_line_number (exception),
+ jsc_exception_get_column_number (exception),
+ jsc_exception_get_message (exception));
- e_editor_dom_embed_style_sheet (editor_page, style_sheet_content);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMRemoveEmbeddedStyleSheet") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
+ jsc_context_clear_exception (jsc_context);
+ }
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ g_clear_object (&result);
+ g_free (filename);
+ g_free (content);
+}
- e_editor_dom_remove_embedded_style_sheet (editor_page);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "SetPastingContentFromItself") == 0) {
- gboolean value = FALSE;
+static void
+evo_editor_find_pattern (const gchar *text,
+ const gchar *pattern,
+ gint *out_start,
+ gint *out_end)
+{
+ GRegex *regex;
- g_variant_get (parameters, "(tb)", &page_id, &value);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_page_set_pasting_content_from_itself (editor_page, value);
+ g_return_if_fail (out_start != NULL);
+ g_return_if_fail (out_end != NULL);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "SetEditorHTMLMode") == 0) {
- gboolean html_mode = FALSE;
- gboolean convert = FALSE;
+ *out_start = -1;
+ *out_end = -1;
- g_variant_get (parameters, "(tbb)", &page_id, &html_mode, &convert);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ regex = g_regex_new (pattern, 0, 0, NULL);
+ if (regex) {
+ GMatchInfo *match_info = NULL;
+ gint start = -1, end = -1;
- convert = convert && e_editor_page_get_html_mode (editor_page) && !html_mode;
- e_editor_page_set_html_mode (editor_page, html_mode);
-
- if (convert)
- e_editor_dom_convert_when_changing_composer_mode (editor_page);
- else
- e_editor_dom_process_content_after_mode_change (editor_page);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "SetConvertInSitu") == 0) {
- gboolean value = FALSE;
- gint16 start_at_bottom = -1, top_signature = -1;
-
- g_variant_get (parameters, "(tbnn)", &page_id, &value, &start_at_bottom, &top_signature);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_page_set_convert_in_situ (editor_page, value, start_at_bottom, top_signature);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMForceSpellCheck") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_force_spell_check (editor_page);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMCheckIfConversionNeeded") == 0) {
- gboolean conversion_needed;
-
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- conversion_needed = e_editor_dom_check_if_conversion_needed (editor_page);
- g_dbus_method_invocation_return_value (
- invocation, g_variant_new ("(b)", conversion_needed));
- } else if (g_strcmp0 (method_name, "DOMGetContent") == 0) {
- EContentEditorGetContentFlags flags;
- const gchar *from_domain;
- gchar *value = NULL;
- GVariant *inline_images = NULL;
-
- g_variant_get (parameters, "(t&si)", &page_id, &from_domain, &flags);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- if ((flags & E_CONTENT_EDITOR_GET_INLINE_IMAGES) && from_domain && *from_domain)
- inline_images = e_editor_dom_get_inline_images_data (editor_page, from_domain);
-
- if ((flags & E_CONTENT_EDITOR_GET_TEXT_HTML) &&
- !(flags & E_CONTENT_EDITOR_GET_PROCESSED)) {
- value = e_editor_dom_process_content_for_draft (
- editor_page, (flags & E_CONTENT_EDITOR_GET_BODY));
- } else if ((flags & E_CONTENT_EDITOR_GET_TEXT_HTML) &&
- (flags & E_CONTENT_EDITOR_GET_PROCESSED) &&
- !(flags & E_CONTENT_EDITOR_GET_BODY)) {
- value = e_editor_dom_process_content_to_html_for_exporting (editor_page);
- } else if ((flags & E_CONTENT_EDITOR_GET_TEXT_PLAIN) &&
- (flags & E_CONTENT_EDITOR_GET_PROCESSED) &&
- !(flags & E_CONTENT_EDITOR_GET_BODY)) {
- value = e_editor_dom_process_content_to_plain_text_for_exporting (editor_page);
- } else if ((flags & E_CONTENT_EDITOR_GET_TEXT_PLAIN) &&
- (flags & E_CONTENT_EDITOR_GET_BODY) &&
- !(flags & E_CONTENT_EDITOR_GET_PROCESSED)) {
- if (flags & E_CONTENT_EDITOR_GET_EXCLUDE_SIGNATURE)
- value = e_composer_dom_get_raw_body_content_without_signature (editor_page);
- else
- value = e_composer_dom_get_raw_body_content (editor_page);
- } else {
- g_warning ("Unsupported flags combination (%d) in (%s)", flags, G_STRFUNC);
+ if (g_regex_match_all (regex, text, G_REGEX_MATCH_NOTEMPTY, &match_info) &&
+ g_match_info_fetch_pos (match_info, 0, &start, &end) &&
+ start >= 0 && end >= 0) {
+ *out_start = start;
+ *out_end = end;
}
- if ((flags & E_CONTENT_EDITOR_GET_INLINE_IMAGES) && from_domain && *from_domain &&
inline_images)
- e_editor_dom_restore_images (editor_page, inline_images);
-
- /* If no inline images are requested we still have to return
- * something even it won't be used at all. */
- g_dbus_method_invocation_return_value (
- invocation,
- g_variant_new (
- "(sv)",
- value ? value : "",
- inline_images ? inline_images : g_variant_new_int32 (0)));
-
- g_free (value);
- } else if (g_strcmp0 (method_name, "DOMInsertHTML") == 0) {
- const gchar *html;
-
- g_variant_get (parameters, "(t&s)", &page_id, &html);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_insert_html (editor_page, html);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMConvertContent") == 0) {
- const gchar *preferred_text;
- gint64 start_at_bottom = -1, top_signature = -1;
-
- g_variant_get (parameters, "(t&snn)", &page_id, &preferred_text, &start_at_bottom,
&top_signature);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_convert_content (editor_page, preferred_text, start_at_bottom, top_signature);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMAddNewInlineImageIntoList") == 0) {
- const gchar *cid_uri, *src, *filename;
-
- g_variant_get (parameters, "(t&s&s&s)", &page_id, &filename, &cid_uri, &src);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_page_add_new_inline_image_into_list (
- editor_page, cid_uri, src);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMReplaceImageSrc") == 0) {
- const gchar *selector, *uri;
-
- g_variant_get (parameters, "(t&s&s)", &page_id, &selector, &uri);
+ if (match_info)
+ g_match_info_free (match_info);
+ g_regex_unref (regex);
+ }
+}
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+/* Returns 'null', when no match for magicLinks in 'text' were found, otherwise
+ returns an array of 'object { text : string, [ href : string] };' with the text
+ split into parts, where those with also 'href' property defined are meant
+ to be anchors. */
+static JSCValue *
+evo_editor_jsc_split_text_with_links (const gchar *text,
+ JSCContext *jsc_context)
+{
+ // stephenhay from https://mathiasbynens.be/demo/url-regex
+ const gchar *URL_PATTERN = "((?:(?:(?:"
+ "news|telnet|nntp|file|https?|s?ftp|webcal|localhost|ssh"
+ ")\\:\\/\\/)|(?:www\\.|ftp\\.))[^\\s\\/\\$\\.\\?#].[^\\s]*+)";
+ // from camel-url-scanner.c
+ const gchar *URL_INVALID_TRAILING_CHARS = ",.:;?!-|}])\">";
+ // http://www.w3.org/TR/html5/forms.html#valid-e-mail-address
+ const gchar *EMAIL_PATTERN = "[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}"
+ "[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*+";
+ JSCValue *array = NULL;
+ guint array_len = 0;
+ gboolean done = FALSE;
+
+ if (!text || !*text)
+ return jsc_value_new_null (jsc_context);
+
+ #define add_to_array(_obj) G_STMT_START { \
+ if (!array) \
+ array = jsc_value_new_array (jsc_context, G_TYPE_NONE); \
+ jsc_value_object_set_property_at_index (array, array_len, _obj); \
+ array_len++; \
+ } G_STMT_END
+
+ while (!done) {
+ gboolean is_email;
+ gint start = -1, end = -1;
+
+ done = TRUE;
+
+ is_email = strchr (text, '@') && !strstr (text, "://");
+
+ evo_editor_find_pattern (text, is_email ? EMAIL_PATTERN : URL_PATTERN, &start, &end);
+
+ if (start >= 0 && end >= 0) {
+ const gchar *url_end;
+
+ url_end = text + end - 1;
+
+ /* URLs are extremely unlikely to end with any punctuation, so
+ * strip any trailing punctuation off from link and put it after
+ * the link. Do the same for any closing double-quotes as well. */
+ while (end > start && *url_end && strchr (URL_INVALID_TRAILING_CHARS, *url_end)) {
+ gchar open_bracket = 0, close_bracket = *url_end;
+
+ if (close_bracket == ')')
+ open_bracket = '(';
+ else if (close_bracket == '}')
+ open_bracket = '{';
+ else if (close_bracket == ']')
+ open_bracket = '[';
+ else if (close_bracket == '>')
+ open_bracket = '<';
+
+ if (open_bracket != 0) {
+ gint n_opened = 0, n_closed = 0;
+ const gchar *ptr;
+
+ for (ptr = text + start; ptr <= url_end; ptr++) {
+ if (*ptr == open_bracket)
+ n_opened++;
+ else if (*ptr == close_bracket)
+ n_closed++;
+ }
- e_editor_dom_replace_image_src (editor_page, selector, uri);
+ /* The closing bracket can match one inside the URL,
+ thus keep it there. */
+ if (n_opened > 0 && n_opened - n_closed >= 0)
+ break;
+ }
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMInsertSmiley") == 0) {
- const gchar *smiley_name;
+ url_end--;
+ end--;
+ }
- g_variant_get (parameters, "(t&s)", &page_id, &smiley_name);
+ if (end > start) {
+ JSCValue *object, *string;
+ gchar *url, *tmp;
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ if (start > 0) {
+ tmp = g_strndup (text, start);
- e_editor_dom_insert_smiley_by_name (editor_page, smiley_name);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMMoveSelectionOnPoint") == 0) {
- gboolean cancel_if_not_collapsed;
- gint x, y;
+ object = jsc_value_new_object (jsc_context, NULL, NULL);
- g_variant_get (parameters, "(tiib)", &page_id, &x, &y, &cancel_if_not_collapsed);
+ string = jsc_value_new_string (jsc_context, tmp);
+ jsc_value_object_set_property (object, "text", string);
+ g_clear_object (&string);
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ add_to_array (object);
- if (cancel_if_not_collapsed) {
- if (e_editor_dom_selection_is_collapsed (editor_page))
- e_editor_dom_selection_set_on_point (editor_page, x, y);
- } else
- e_editor_dom_selection_set_on_point (editor_page, x, y);
+ g_clear_object (&object);
+ g_free (tmp);
+ }
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMSelectionIndent") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
+ tmp = g_strndup (text + start, end - start);
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ if (is_email)
+ url = g_strconcat ("mailto:", tmp, NULL);
+ else if (g_str_has_prefix (tmp, "www."))
+ url = g_strconcat ("https://", tmp, NULL);
+ else
+ url = NULL;
- e_editor_dom_selection_indent (editor_page);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMSelectionSave") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
+ object = jsc_value_new_object (jsc_context, NULL, NULL);
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ string = jsc_value_new_string (jsc_context, tmp);
+ jsc_value_object_set_property (object, "text", string);
+ g_clear_object (&string);
- e_editor_dom_selection_save (editor_page);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMSelectionRestore") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
+ string = jsc_value_new_string (jsc_context, url ? url : tmp);
+ jsc_value_object_set_property (object, "href", string);
+ g_clear_object (&string);
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ add_to_array (object);
- e_editor_dom_selection_restore (editor_page);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMSelectionInsertImage") == 0) {
- const gchar *uri;
+ g_clear_object (&object);
+ g_free (tmp);
+ g_free (url);
- g_variant_get (parameters, "(t&s)", &page_id, &uri);
+ text = text + end;
+ done = FALSE;
+ }
+ }
+ }
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ if (array && *text) {
+ JSCValue *object, *string;
- e_editor_dom_insert_image (editor_page, uri);
+ object = jsc_value_new_object (jsc_context, NULL, NULL);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMInsertReplaceAllHistoryEvent") == 0) {
- const gchar *replacement, *search_text;
+ string = jsc_value_new_string (jsc_context, text);
+ jsc_value_object_set_property (object, "text", string);
+ g_clear_object (&string);
- g_variant_get (parameters, "(t&s&s)", &page_id, &search_text, &replacement);
+ add_to_array (object);
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ g_clear_object (&object);
+ }
- e_editor_dom_insert_replace_all_history_event (editor_page, search_text, replacement);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMSelectionReplace") == 0) {
- const gchar *replacement;
+ #undef add_to_array
- g_variant_get (parameters, "(t&s)", &page_id, &replacement);
+ return array ? array : jsc_value_new_null (jsc_context);
+}
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+/* Returns 'null' or an object { text : string, imageUri : string, width : nnn, height : nnn }
+ where only the 'text' is required, describing an emoticon. */
+static JSCValue *
+evo_editor_jsc_lookup_emoticon (const gchar *iconName,
+ gboolean use_unicode_smileys,
+ JSCContext *jsc_context)
+{
+ JSCValue *object = NULL;
- e_editor_dom_selection_replace (editor_page, replacement);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMSelectionSetAlignment") == 0) {
- EContentEditorAlignment alignment;
+ if (iconName && *iconName) {
+ const EEmoticon *emoticon;
- g_variant_get (parameters, "(ti)", &page_id, &alignment);
+ emoticon = e_emoticon_chooser_lookup_emoticon (iconName);
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ if (emoticon) {
+ JSCValue *value;
- e_editor_dom_selection_set_alignment (editor_page, alignment);
- e_editor_page_set_alignment (editor_page, alignment);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMSelectionSetBold") == 0) {
- gboolean bold;
+ object = jsc_value_new_object (jsc_context, NULL, NULL);
- g_variant_get (parameters, "(tb)", &page_id, &bold);
+ if (use_unicode_smileys) {
+ value = jsc_value_new_string (jsc_context, emoticon->unicode_character);
+ jsc_value_object_set_property (object, "text", value);
+ g_clear_object (&value);
+ } else {
+ gchar *image_uri;
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ value = jsc_value_new_string (jsc_context, emoticon->text_face);
+ jsc_value_object_set_property (object, "text", value);
+ g_clear_object (&value);
- e_editor_page_set_bold (editor_page, bold);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMSelectionSetBlockFormat") == 0) {
- EContentEditorBlockFormat block_format;
+ image_uri = e_emoticon_get_uri ((EEmoticon *) emoticon);
- g_variant_get (parameters, "(ti)", &page_id, &block_format);
+ if (image_uri) {
+ value = jsc_value_new_string (jsc_context, image_uri);
+ jsc_value_object_set_property (object, "imageUri", value);
+ g_clear_object (&value);
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ value = jsc_value_new_number (jsc_context, 16);
+ jsc_value_object_set_property (object, "width", value);
+ g_clear_object (&value);
- e_editor_dom_selection_set_block_format (editor_page, block_format);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMSelectionSetFontColor") == 0) {
- const gchar *color;
+ value = jsc_value_new_number (jsc_context, 16);
+ jsc_value_object_set_property (object, "height", value);
+ g_clear_object (&value);
- g_variant_get (parameters, "(t&s)", &page_id, &color);
+ g_free (image_uri);
+ }
+ }
+ }
+ }
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ return object ? object : jsc_value_new_null (jsc_context);
+}
- e_editor_dom_selection_set_font_color (editor_page, color);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMSelectionSetFontSize") == 0) {
- EContentEditorFontSize font_size;
+static void
+evo_editor_jsc_set_spell_check_languages (const gchar *langs,
+ GWeakRef *wkrf_extension)
+{
+ EEditorWebExtension *extension;
+ gchar **strv;
- g_variant_get (parameters, "(ti)", &page_id, &font_size);
+ g_return_if_fail (wkrf_extension != NULL);
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ extension = g_weak_ref_get (wkrf_extension);
- e_editor_dom_selection_set_font_size (editor_page, font_size);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMSelectionSetItalic") == 0) {
- gboolean italic;
+ if (!extension)
+ return;
- g_variant_get (parameters, "(tb)", &page_id, &italic);
+ if (langs && *langs)
+ strv = g_strsplit (langs, "|", -1);
+ else
+ strv = NULL;
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ if (!extension->priv->spell_checker)
+ extension->priv->spell_checker = e_spell_checker_new ();
- e_editor_page_set_italic (editor_page, italic);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMSelectionSetMonospaced") == 0) {
- gboolean monospaced;
+ e_spell_checker_set_active_languages (extension->priv->spell_checker, (const gchar * const *) strv);
- g_variant_get (parameters, "(tb)", &page_id, &monospaced);
+ g_object_unref (extension);
+ g_strfreev (strv);
+}
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+/* Returns whether the 'word' is a properly spelled word. It checks
+ with languages previously set by EvoEditor.SetSpellCheckLanguages(). */
+static gboolean
+evo_editor_jsc_spell_check_word (const gchar *word,
+ GWeakRef *wkrf_extension)
+{
+ EEditorWebExtension *extension;
+ gboolean is_correct;
- e_editor_page_set_monospace (editor_page, monospaced);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMSelectionSetStrikethrough") == 0) {
- gboolean strikethrough;
+ g_return_val_if_fail (wkrf_extension != NULL, FALSE);
- g_variant_get (parameters, "(tb)", &page_id, &strikethrough);
+ extension = g_weak_ref_get (wkrf_extension);
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ if (!extension)
+ return TRUE;
- e_editor_page_set_strikethrough (editor_page, strikethrough);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMSelectionSetSubscript") == 0) {
- gboolean subscript;
+ /* It should be created as part of EvoEditor.SetSpellCheckLanguages(). */
+ g_warn_if_fail (extension->priv->spell_checker != NULL);
- g_variant_get (parameters, "(tb)", &page_id, &subscript);
+ if (!extension->priv->spell_checker)
+ extension->priv->spell_checker = e_spell_checker_new ();
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_selection_set_subscript (editor_page, subscript);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMSelectionSetSuperscript") == 0) {
- gboolean superscript;
-
- g_variant_get (parameters, "(tb)", &page_id, &superscript);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_selection_set_superscript (editor_page, superscript);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMSelectionSetUnderline") == 0) {
- gboolean underline;
-
- g_variant_get (parameters, "(tb)", &page_id, &underline);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_page_set_underline (editor_page, underline);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMSelectionUnindent") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_selection_unindent (editor_page);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMSelectionWrap") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_selection_wrap (editor_page);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMGetCaretWord") == 0) {
- gchar *word;
-
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- word = e_editor_dom_get_caret_word (editor_page);
-
- g_dbus_method_invocation_return_value (
- invocation,
- g_variant_new (
- "(@s)",
- g_variant_new_take_string (
- word ? word : g_strdup (""))));
- } else if (g_strcmp0 (method_name, "DOMReplaceCaretWord") == 0) {
- const gchar *replacement = NULL;
-
- g_variant_get (parameters, "(t&s)", &page_id, &replacement);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_replace_caret_word (editor_page, replacement);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMInsertSignature") == 0) {
- gboolean is_html, set_signature_from_message;
- gboolean check_if_signature_is_changed, ignore_next_signature_change;
- gint16 start_at_bottom = -1, top_signature = -1;
- const gchar *content, *signature_id;
- gchar *new_signature_id = NULL;
-
- g_variant_get (
- parameters,
- "(t&sb&sbbbnn)",
- &page_id,
- &content,
- &is_html,
- &signature_id,
- &set_signature_from_message,
- &check_if_signature_is_changed,
- &ignore_next_signature_change,
- &start_at_bottom,
- &top_signature);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- new_signature_id = e_composer_dom_insert_signature (
- editor_page,
- content,
- is_html,
- signature_id,
- &set_signature_from_message,
- &check_if_signature_is_changed,
- &ignore_next_signature_change,
- start_at_bottom,
- top_signature);
-
- g_dbus_method_invocation_return_value (
- invocation,
- g_variant_new (
- "(sbbb)",
- new_signature_id ? new_signature_id : "",
- set_signature_from_message,
- check_if_signature_is_changed,
- ignore_next_signature_change));
-
- g_free (new_signature_id);
- } else if (g_strcmp0 (method_name, "DOMGetActiveSignatureUid") == 0) {
- gchar *value;
-
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- value = e_composer_dom_get_active_signature_uid (editor_page);
-
- g_dbus_method_invocation_return_value (
- invocation,
- g_variant_new (
- "(@s)",
- g_variant_new_take_string (
- value ? value : g_strdup (""))));
- } else if (g_strcmp0 (method_name, "DOMLastDropOperationDidCopy") == 0) {
- EEditorUndoRedoManager *manager;
-
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- manager = e_editor_page_get_undo_redo_manager (editor_page);
- if (manager)
- e_editor_undo_redo_manager_last_drop_operation_did_copy (manager);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMGetCaretPosition") == 0) {
- guint32 value;
-
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- value = e_editor_dom_get_caret_position (editor_page);
-
- g_dbus_method_invocation_return_value (
- invocation,
- g_variant_new ("(u)", value));
- } else if (g_strcmp0 (method_name, "DOMGetCaretOffset") == 0) {
- guint32 value;
-
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- value = e_editor_dom_get_caret_offset (editor_page);
-
- g_dbus_method_invocation_return_value (
- invocation,
- g_variant_new ("(u)", value));
- } else if (g_strcmp0 (method_name, "DOMClearUndoRedoHistory") == 0) {
- EEditorUndoRedoManager *manager;
-
- g_variant_get (parameters, "(t)", &page_id);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- manager = e_editor_page_get_undo_redo_manager (editor_page);
- if (manager)
- e_editor_undo_redo_manager_clean_history (manager);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else {
- g_warning ("UNKNOWN METHOD '%s'", method_name);
- }
+ is_correct = e_spell_checker_check_word (extension->priv->spell_checker, word, -1);
- return;
+ g_object_unref (extension);
- error:
- g_warning ("Cannot obtain WebKitWebPage for %" G_GUINT64_FORMAT, page_id);
+ return is_correct;
}
static void
-web_page_gone_cb (gpointer user_data,
- GObject *gone_web_page)
+window_object_cleared_cb (WebKitScriptWorld *world,
+ WebKitWebPage *page,
+ WebKitFrame *frame,
+ gpointer user_data)
{
EEditorWebExtension *extension = user_data;
- GSList *link;
+ JSCContext *jsc_context;
+ JSCValue *jsc_editor;
g_return_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension));
- for (link = extension->priv->pages; link; link = g_slist_next (link)) {
- EEditorPage *editor_page = link->data;
- WebKitWebPage *web_page = e_editor_page_get_web_page (editor_page);
-
- if ((gpointer) web_page == gone_web_page) {
- extension->priv->pages = g_slist_remove (extension->priv->pages, editor_page);
- g_object_unref (editor_page);
- break;
- }
- }
-}
-
-static const GDBusInterfaceVTable interface_vtable = {
- handle_method_call,
- NULL,
- NULL
-};
-
-static void
-e_editor_web_extension_dispose (GObject *object)
-{
- EEditorWebExtension *extension = E_EDITOR_WEB_EXTENSION (object);
-
- if (extension->priv->dbus_connection) {
- g_dbus_connection_unregister_object (
- extension->priv->dbus_connection,
- extension->priv->registration_id);
- extension->priv->registration_id = 0;
-
- g_clear_object (&extension->priv->dbus_connection);
- }
-
- g_slist_free_full (extension->priv->pages, g_object_unref);
- extension->priv->pages = NULL;
+ /* Load the javascript files only to the main frame, not to the subframes */
+ if (!webkit_frame_is_main_frame (frame))
+ return;
- g_clear_object (&extension->priv->wk_extension);
+ jsc_context = webkit_frame_get_js_context (frame);
- /* Chain up to parent's dispose() method. */
- G_OBJECT_CLASS (e_editor_web_extension_parent_class)->dispose (object);
-}
+ /* Read in order approximately as each other uses the previous */
+ load_javascript_file (jsc_context, "e-convert.js");
+ load_javascript_file (jsc_context, "e-selection.js");
+ load_javascript_file (jsc_context, "e-undo-redo.js");
+ load_javascript_file (jsc_context, "e-editor.js");
-static void
-e_editor_web_extension_class_init (EEditorWebExtensionClass *class)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (class);
+ jsc_editor = jsc_context_get_value (jsc_context, "EvoEditor");
- object_class->dispose = e_editor_web_extension_dispose;
+ if (jsc_editor) {
+ JSCValue *jsc_function;
+ const gchar *func_name;
- g_type_class_add_private (object_class, sizeof(EEditorWebExtensionPrivate));
-}
+ /* EvoEditor.splitTextWithLinks(text) */
+ func_name = "splitTextWithLinks";
+ jsc_function = jsc_value_new_function (jsc_context, func_name,
+ G_CALLBACK (evo_editor_jsc_split_text_with_links), g_object_ref (jsc_context),
g_object_unref,
+ JSC_TYPE_VALUE, 1, G_TYPE_STRING);
-static void
-e_editor_web_extension_init (EEditorWebExtension *extension)
-{
- extension->priv = E_EDITOR_WEB_EXTENSION_GET_PRIVATE (extension);
-}
+ jsc_value_object_set_property (jsc_editor, func_name, jsc_function);
-static gpointer
-e_editor_web_extension_create_instance (gpointer data)
-{
- return g_object_new (E_TYPE_EDITOR_WEB_EXTENSION, NULL);
-}
+ g_clear_object (&jsc_function);
-EEditorWebExtension *
-e_editor_web_extension_get_default (void)
-{
- static GOnce once_init = G_ONCE_INIT;
- return E_EDITOR_WEB_EXTENSION (g_once (&once_init, e_editor_web_extension_create_instance, NULL));
-}
+ /* EvoEditor.lookupEmoticon(iconName, useUnicodeSmileys) */
+ func_name = "lookupEmoticon";
+ jsc_function = jsc_value_new_function (jsc_context, func_name,
+ G_CALLBACK (evo_editor_jsc_lookup_emoticon), g_object_ref (jsc_context),
g_object_unref,
+ JSC_TYPE_VALUE, 2, G_TYPE_STRING, G_TYPE_BOOLEAN);
-static gboolean
-image_exists_in_cache (const gchar *image_uri)
-{
- gchar *filename;
- gchar *hash;
- gboolean exists = FALSE;
+ jsc_value_object_set_property (jsc_editor, func_name, jsc_function);
- if (!emd_global_http_cache)
- return FALSE;
+ g_clear_object (&jsc_function);
- hash = e_http_request_util_compute_uri_checksum (image_uri);
- filename = camel_data_cache_get_filename (
- emd_global_http_cache, "http", hash);
+ /* EvoEditor.SetSpellCheckLanguages(langs) */
+ func_name = "SetSpellCheckLanguages";
+ jsc_function = jsc_value_new_function (jsc_context, func_name,
+ G_CALLBACK (evo_editor_jsc_set_spell_check_languages), e_weak_ref_new (extension),
(GDestroyNotify) e_weak_ref_free,
+ G_TYPE_NONE, 1, G_TYPE_STRING);
- if (filename != NULL) {
- struct stat st;
+ jsc_value_object_set_property (jsc_editor, func_name, jsc_function);
- exists = g_file_test (filename, G_FILE_TEST_EXISTS);
- if (exists && g_stat (filename, &st) == 0) {
- exists = st.st_size != 0;
- } else {
- exists = FALSE;
- }
- g_free (filename);
- }
+ g_clear_object (&jsc_function);
- g_free (hash);
+ /* EvoEditor.SpellCheckWord(word) */
+ func_name = "SpellCheckWord";
+ jsc_function = jsc_value_new_function (jsc_context, func_name,
+ G_CALLBACK (evo_editor_jsc_spell_check_word), e_weak_ref_new (extension),
(GDestroyNotify) e_weak_ref_free,
+ G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
- return exists;
-}
+ jsc_value_object_set_property (jsc_editor, func_name, jsc_function);
-static gboolean
-redirect_http_uri (EEditorWebExtension *extension,
- WebKitWebPage *web_page,
- WebKitURIRequest *request)
-{
- const gchar *uri;
- gchar *new_uri;
- SoupURI *soup_uri;
- gboolean image_exists;
- EEditorPage *editor_page;
- EImageLoadingPolicy image_policy;
-
- editor_page = get_editor_page (extension, webkit_web_page_get_id (web_page));
- g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
-
- uri = webkit_uri_request_get_uri (request);
-
- /* Check Evolution's cache */
- image_exists = image_exists_in_cache (uri);
-
- /* If the URI is not cached and we are not allowed to load it
- * then redirect to invalid URI, so that webkit would display
- * a native placeholder for it. */
- image_policy = e_editor_page_get_image_loading_policy (editor_page);
- if (!image_exists && !e_editor_page_get_force_image_load (editor_page) &&
- (image_policy == E_IMAGE_LOADING_POLICY_NEVER)) {
- return FALSE;
+ g_clear_object (&jsc_function);
+ g_clear_object (&jsc_editor);
}
- new_uri = g_strconcat ("evo-", uri, NULL);
- soup_uri = soup_uri_new (new_uri);
- g_free (new_uri);
-
- new_uri = soup_uri_to_string (soup_uri, FALSE);
- webkit_uri_request_set_uri (request, new_uri);
- soup_uri_free (soup_uri);
-
- g_free (new_uri);
-
- return TRUE;
+ g_clear_object (&jsc_context);
}
static gboolean
web_page_send_request_cb (WebKitWebPage *web_page,
- WebKitURIRequest *request,
- WebKitURIResponse *redirected_response,
- EEditorWebExtension *extension)
+ WebKitURIRequest *request,
+ WebKitURIResponse *redirected_response,
+ EEditorWebExtension *extension)
{
- const char *request_uri;
- const char *page_uri;
- gboolean uri_is_http;
+ const gchar *request_uri;
+ const gchar *page_uri;
request_uri = webkit_uri_request_get_uri (request);
page_uri = webkit_web_page_get_uri (web_page);
@@ -2455,136 +528,38 @@ web_page_send_request_cb (WebKitWebPage *web_page,
if (g_strcmp0 (request_uri, page_uri) == 0)
return FALSE;
- uri_is_http =
- g_str_has_prefix (request_uri, "http:") ||
- g_str_has_prefix (request_uri, "https:") ||
- g_str_has_prefix (request_uri, "evo-http:") ||
- g_str_has_prefix (request_uri, "evo-https:");
+ if (g_str_has_prefix (request_uri, "http:") ||
+ g_str_has_prefix (request_uri, "https:")) {
+ gchar *new_uri;
- if (uri_is_http &&
- !redirect_http_uri (extension, web_page, request))
- return TRUE;
-
- return FALSE;
-}
-
-static void
-web_page_document_loaded_cb (WebKitWebPage *web_page,
- gpointer user_data)
-{
- WebKitDOMDocument *document;
- WebKitDOMRange *range = NULL;
- WebKitDOMDOMWindow *dom_window;
- WebKitDOMDOMSelection *dom_selection;
-
- g_return_if_fail (WEBKIT_IS_WEB_PAGE (web_page));
-
- document = webkit_web_page_get_dom_document (web_page);
- if (!document)
- return;
+ new_uri = g_strconcat ("evo-", request_uri, NULL);
- dom_window = webkit_dom_document_get_default_view (document);
- dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ webkit_uri_request_set_uri (request, new_uri);
- /* Make sure there is a cursor located in the body after the document loads. */
- if (!webkit_dom_dom_selection_get_anchor_node (dom_selection) &&
- !webkit_dom_dom_selection_get_focus_node (dom_selection)) {
- range = webkit_dom_document_caret_range_from_point (document, 0, 0);
- webkit_dom_dom_selection_remove_all_ranges (dom_selection);
- webkit_dom_dom_selection_add_range (dom_selection, range);
+ g_free (new_uri);
}
- g_clear_object (&range);
- g_clear_object (&dom_selection);
- g_clear_object (&dom_window);
+ return FALSE;
}
static void
-web_page_notify_uri_cb (GObject *object,
- GParamSpec *param,
- gpointer user_data)
+web_page_document_loaded_cb (WebKitWebPage *web_page,
+ gpointer user_data)
{
- EEditorWebExtension *extension = user_data;
- WebKitWebPage *web_page;
- GSList *link;
- const gchar *uri;
-
- g_return_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension));
-
- web_page = WEBKIT_WEB_PAGE (object);
- uri = webkit_web_page_get_uri (web_page);
-
- for (link = extension->priv->pages; link; link = g_slist_next (link)) {
- EEditorPage *page = link->data;
-
- if (page && e_editor_page_get_web_page (page) == web_page) {
- gint new_stamp = 0;
-
- if (uri && *uri) {
- SoupURI *suri;
-
- suri = soup_uri_new (uri);
- if (suri) {
- if (soup_uri_get_query (suri)) {
- GHashTable *form;
-
- form = soup_form_decode (soup_uri_get_query (suri));
- if (form) {
- const gchar *evo_stamp;
-
- evo_stamp = g_hash_table_lookup (form, "evo-stamp");
- if (evo_stamp)
- new_stamp = (gint) g_ascii_strtoll
(evo_stamp, NULL, 10);
-
- g_hash_table_destroy (form);
- }
- }
-
- soup_uri_free (suri);
- }
- }
-
- e_editor_page_set_stamp (page, new_stamp);
-
- if (extension->priv->dbus_connection) {
- GError *error = NULL;
-
- g_dbus_connection_emit_signal (
- extension->priv->dbus_connection,
- NULL,
- E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
- E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE,
- "ExtensionHandlesPage",
- g_variant_new ("(ti)", webkit_web_page_get_id (web_page), new_stamp),
- &error);
-
- if (error) {
- g_warning ("Error emitting signal ExtensionHandlesPage: %s",
error->message);
- g_error_free (error);
- }
- }
-
- return;
- }
- }
+ g_return_if_fail (WEBKIT_IS_WEB_PAGE (web_page));
- g_warning ("%s: Cannot find web_page %p\n", G_STRFUNC, web_page);
+ window_object_cleared_cb (NULL, web_page, webkit_web_page_get_main_frame (web_page), user_data);
}
static void
web_page_created_cb (WebKitWebExtension *wk_extension,
- WebKitWebPage *web_page,
- EEditorWebExtension *extension)
+ WebKitWebPage *web_page,
+ EEditorWebExtension *extension)
{
- EEditorPage *editor_page;
-
g_return_if_fail (WEBKIT_IS_WEB_PAGE (web_page));
g_return_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension));
- editor_page = e_editor_page_new (web_page, extension);
- extension->priv->pages = g_slist_prepend (extension->priv->pages, editor_page);
-
- g_object_weak_ref (G_OBJECT (web_page), web_page_gone_cb, extension);
+ window_object_cleared_cb (NULL, web_page, webkit_web_page_get_main_frame (web_page), extension);
g_signal_connect (
web_page, "send-request",
@@ -2592,77 +567,25 @@ web_page_created_cb (WebKitWebExtension *wk_extension,
g_signal_connect (
web_page, "document-loaded",
- G_CALLBACK (web_page_document_loaded_cb), NULL);
-
- g_signal_connect_object (
- web_page, "notify::uri",
- G_CALLBACK (web_page_notify_uri_cb),
- extension, 0);
+ G_CALLBACK (web_page_document_loaded_cb), extension);
}
void
e_editor_web_extension_initialize (EEditorWebExtension *extension,
- WebKitWebExtension *wk_extension)
+ WebKitWebExtension *wk_extension)
{
+ WebKitScriptWorld *script_world;
+
g_return_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension));
extension->priv->wk_extension = g_object_ref (wk_extension);
- if (emd_global_http_cache == NULL) {
- emd_global_http_cache = camel_data_cache_new (
- e_get_user_cache_dir (), NULL);
-
- if (emd_global_http_cache) {
- /* cache expiry - 2 hour access, 1 day max */
- camel_data_cache_set_expire_age (
- emd_global_http_cache, 24 * 60 * 60);
- camel_data_cache_set_expire_access (
- emd_global_http_cache, 2 * 60 * 60);
- }
- }
-
g_signal_connect (
wk_extension, "page-created",
G_CALLBACK (web_page_created_cb), extension);
-}
-
-void
-e_editor_web_extension_dbus_register (EEditorWebExtension *extension,
- GDBusConnection *connection)
-{
- GError *error = NULL;
- static GDBusNodeInfo *introspection_data = NULL;
- g_return_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension));
- g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
-
- if (!introspection_data) {
- introspection_data =
- g_dbus_node_info_new_for_xml (introspection_xml, NULL);
-
- extension->priv->registration_id =
- g_dbus_connection_register_object (
- connection,
- E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
- introspection_data->interfaces[0],
- &interface_vtable,
- extension,
- NULL,
- &error);
-
- if (!extension->priv->registration_id) {
- g_warning ("Failed to register object: %s\n", error->message);
- g_error_free (error);
- } else {
- extension->priv->dbus_connection = g_object_ref (connection);
- }
- }
-}
-
-GDBusConnection *
-e_editor_web_extension_get_connection (EEditorWebExtension *extension)
-{
- g_return_val_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension), NULL);
+ script_world = webkit_script_world_get_default ();
- return extension->priv->dbus_connection;
+ g_signal_connect (script_world, "window-object-cleared",
+ G_CALLBACK (window_object_cleared_cb), extension);
}
diff --git a/src/modules/webkit-editor/web-extension/e-editor-web-extension.h
b/src/modules/webkit-editor/web-extension/e-editor-web-extension.h
index 987b3de1c0..9470b63b15 100644
--- a/src/modules/webkit-editor/web-extension/e-editor-web-extension.h
+++ b/src/modules/webkit-editor/web-extension/e-editor-web-extension.h
@@ -22,12 +22,6 @@
#include <glib-object.h>
#include <webkit2/webkit-web-extension.h>
-#define E_UTIL_INCLUDE_WITHOUT_WEBKIT
-#include <e-util/e-util.h>
-#undef E_UTIL_INCLUDE_WITHOUT_WEBKIT
-
-#include "e-editor-web-extension-names.h"
-
/* Standard GObject macros */
#define E_TYPE_EDITOR_WEB_EXTENSION \
(e_editor_web_extension_get_type ())
@@ -72,11 +66,5 @@ EEditorWebExtension *
void e_editor_web_extension_initialize
(EEditorWebExtension *extension,
WebKitWebExtension *wk_extension);
-void e_editor_web_extension_dbus_register
- (EEditorWebExtension *extension,
- GDBusConnection *connection);
-GDBusConnection *
- e_editor_web_extension_get_connection
- (EEditorWebExtension *extension);
#endif /* E_EDITOR_WEB_EXTENSION_H */
diff --git a/src/plugins/external-editor/external-editor.c b/src/plugins/external-editor/external-editor.c
index fd140b81bd..a4c7ce17f3 100644
--- a/src/plugins/external-editor/external-editor.c
+++ b/src/plugins/external-editor/external-editor.c
@@ -56,9 +56,6 @@ static gboolean key_press_cb (GtkWidget *widget,
GdkEventKey *event,
EMsgComposer *composer);
-/* used to track when the external editor is active */
-static GThread *editor_thread;
-
gint e_plugin_lib_enable (EPlugin *ep, gint enable);
gint
@@ -201,9 +198,23 @@ enable_composer_idle (gpointer user_data)
struct ExternalEditorData {
EMsgComposer *composer;
gchar *content;
- gint cursor_position, cursor_offset;
+ GDestroyNotify content_destroy_notify;
+ guint cursor_position, cursor_offset;
};
+static void
+external_editor_data_free (gpointer ptr)
+{
+ struct ExternalEditorData *eed = ptr;
+
+ if (eed) {
+ g_clear_object (&eed->composer);
+ if (eed->content_destroy_notify)
+ eed->content_destroy_notify (eed->content);
+ g_slice_free (struct ExternalEditorData, eed);
+ }
+}
+
/* needed because the new thread needs to call g_idle_add () */
static gboolean
update_composer_text (gpointer user_data)
@@ -224,9 +235,7 @@ update_composer_text (gpointer user_data)
e_content_editor_set_changed (cnt_editor, TRUE);
- g_clear_object (&eed->composer);
- g_free (eed->content);
- g_slice_free (struct ExternalEditorData, eed);
+ external_editor_data_free (eed);
return FALSE;
}
@@ -387,7 +396,8 @@ external_editor_thread (gpointer user_data)
eed2 = g_slice_new0 (struct ExternalEditorData);
eed2->composer = g_object_ref (eed->composer);
- eed2->content = camel_text_to_html (buf, CAMEL_MIME_FILTER_TOHTML_PRE, 0);
+ eed2->content = camel_text_to_html (buf, CAMEL_MIME_FILTER_TOHTML_PRE, 0);
+ eed2->content_destroy_notify = g_free;
g_idle_add ((GSourceFunc) update_composer_text, eed2);
@@ -406,14 +416,44 @@ finished:
external_editor_running = FALSE;
g_mutex_unlock (&external_editor_running_lock);
- g_clear_object (&eed->composer);
- g_free (eed->content);
- g_slice_free (struct ExternalEditorData, eed);
+ external_editor_data_free (eed);
return NULL;
}
-static void launch_editor (GtkAction *action, EMsgComposer *composer)
+static void
+launch_editor_content_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ struct ExternalEditorData *eed = user_data;
+ EContentEditor *cnt_editor;
+ EContentEditorContentHash *content_hash;
+ GThread *editor_thread;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (source_object));
+ g_return_if_fail (eed != NULL);
+
+ cnt_editor = E_CONTENT_EDITOR (source_object);
+
+ content_hash = e_content_editor_get_content_finish (cnt_editor, result, &error);
+
+ if (!content_hash)
+ g_warning ("%s: Faild to get content: %s", G_STRFUNC, error ? error->message : "Unknown
error");
+
+ eed->content = content_hash ? e_content_editor_util_steal_content_data (content_hash,
E_CONTENT_EDITOR_GET_TO_SEND_PLAIN, &(eed->content_destroy_notify)) : NULL;
+
+ editor_thread = g_thread_new (NULL, external_editor_thread, eed);
+ g_thread_unref (editor_thread);
+
+ e_content_editor_util_free_content_hash (content_hash);
+ g_clear_error (&error);
+}
+
+static void
+launch_editor (GtkAction *action,
+ EMsgComposer *composer)
{
struct ExternalEditorData *eed;
EHTMLEditor *editor;
@@ -438,16 +478,9 @@ static void launch_editor (GtkAction *action, EMsgComposer *composer)
eed = g_slice_new0 (struct ExternalEditorData);
eed->composer = g_object_ref (composer);
- eed->content = e_content_editor_get_content (cnt_editor,
- E_CONTENT_EDITOR_GET_TEXT_PLAIN |
- E_CONTENT_EDITOR_GET_PROCESSED,
- NULL, NULL);
- eed->cursor_position = e_content_editor_get_caret_position (cnt_editor);
- if (eed->cursor_position > 0)
- eed->cursor_offset = e_content_editor_get_caret_offset (cnt_editor);
- editor_thread = g_thread_new (NULL, external_editor_thread, eed);
- g_thread_unref (editor_thread);
+ e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_TO_SEND_PLAIN, NULL, NULL,
+ launch_editor_content_ready_cb, eed);
}
static GtkActionEntry entries[] = {
diff --git a/src/web-extensions/CMakeLists.txt b/src/web-extensions/CMakeLists.txt
index 35151503fe..dd699b76c0 100644
--- a/src/web-extensions/CMakeLists.txt
+++ b/src/web-extensions/CMakeLists.txt
@@ -19,6 +19,7 @@ add_dependencies(ewebextension
target_compile_definitions(ewebextension PRIVATE
-DG_LOG_DOMAIN=\"ewebextension\"
-DEVOLUTION_WEBKITDATADIR=\"${webkitdatadir}\"
+ -DEVOLUTION_SOURCE_WEBKITDATADIR=\"${CMAKE_SOURCE_DIR}/data/webkit\"
)
target_compile_options(ewebextension PUBLIC
diff --git a/src/web-extensions/e-web-extension.c b/src/web-extensions/e-web-extension.c
index 29a7c209d2..979818a67c 100644
--- a/src/web-extensions/e-web-extension.c
+++ b/src/web-extensions/e-web-extension.c
@@ -145,19 +145,41 @@ evo_jsc_get_uri_tooltip (const gchar *uri,
return e_util_get_uri_tooltip (uri);
}
+static gboolean
+use_sources_js_file (void)
+{
+ static gint res = -1;
+
+ if (res == -1)
+ res = g_strcmp0 (g_getenv ("E_WEB_VIEW_TEST_SOURCES"), "1") == 0 ? 1 : 0;
+
+ return res;
+}
+
static void
load_javascript_file (JSCContext *jsc_context,
const gchar *js_filename)
{
JSCValue *result;
JSCException *exception;
- gchar *content, *filename, *resource_uri;
+ gchar *content, *filename = NULL, *resource_uri;
gsize length = 0;
GError *error = NULL;
g_return_if_fail (jsc_context != NULL);
- filename = g_build_filename (EVOLUTION_WEBKITDATADIR, js_filename, NULL);
+ if (use_sources_js_file ()) {
+ filename = g_build_filename (EVOLUTION_SOURCE_WEBKITDATADIR, js_filename, NULL);
+
+ if (!g_file_test (filename, G_FILE_TEST_EXISTS)) {
+ g_warning ("Cannot find '%s', using installed file '%s/%s' instead", filename,
EVOLUTION_WEBKITDATADIR, js_filename);
+
+ g_clear_pointer (&filename, g_free);
+ }
+ }
+
+ if (!filename)
+ filename = g_build_filename (EVOLUTION_WEBKITDATADIR, js_filename, NULL);
if (!g_file_get_contents (filename, &content, &length, &error)) {
g_warning ("Failed to load '%s': %s", filename, error ? error->message : "Unknown error");
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]