[evolution/wip/mcrha/webkit-jsc-api] EWebKitEditor: Use WebKit JavaScriptCore API
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution/wip/mcrha/webkit-jsc-api] EWebKitEditor: Use WebKit JavaScriptCore API
- Date: Wed, 11 Mar 2020 16:12:12 +0000 (UTC)
commit 42301d22ae1252923b8da0bb58d0caabfb28fe37
Author: Milan Crha <mcrha redhat com>
Date: Fri Oct 18 12:57:09 2019 +0200
EWebKitEditor: Use WebKit JavaScriptCore API
data/webkit/CMakeLists.txt | 3 +
data/webkit/e-convert.js | 789 +-
data/webkit/e-editor.js | 4583 +++++
data/webkit/e-selection.js | 435 +
data/webkit/e-undo-redo.js | 906 +
data/webkit/e-web-view.js | 21 +-
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 | 653 +-
src/composer/e-msg-composer.h | 2 +
src/e-util/CMakeLists.txt | 3 +-
src/e-util/e-content-editor.c | 835 +-
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 | 96 +-
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-utils.c | 313 +-
src/e-util/test-html-editor-units-utils.h | 4 +-
src/e-util/test-html-editor-units.c | 3505 +++-
src/e-util/test-html-editor.c | 169 +-
src/e-util/test-web-view-jsc.c | 786 +-
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 | 5297 +++---
.../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 | 2766 +--
.../web-extension/e-editor-web-extension.h | 12 -
src/plugins/external-editor/external-editor.c | 50 +-
src/web-extensions/CMakeLists.txt | 1 +
src/web-extensions/e-web-extension.c | 26 +-
70 files changed, 15726 insertions(+), 35322 deletions(-)
---
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..e952921730 100644
--- a/data/webkit/e-convert.js
+++ b/data/webkit/e-convert.js
@@ -1,12 +1,797 @@
+/* -*- 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
+};
+
+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",
+ canWrap : whiteSpace != "nowrap",
+ charWrap : whiteSpace == "pre",
+ useWrapWidth : wrapWidth,
+ spacesFrom : -1, // in 'str'
+ lastSpace : -1, // in this->line
+ lastWasWholeLine : false, // to distinguish between new line in the text and new line
from wrapping with while line text
+ lineLetters : 0,
+ line : "",
+
+ shouldWrap : function() {
+ return worker.canWrap && (worker.lineLetters > worker.useWrapWidth || (
+ worker.lineLetters == worker.useWrapWidth && (
+ worker.lastSpace == -1/* || worker.lastSpace ==
worker.line.length*/)));
+ },
+
+ commitSpaces : function(ii) {
+ if (worker.spacesFrom != -1 && (!worker.canWrap || worker.line.length <=
worker.useWrapWidth)) {
+ var spaces;
+
+ spaces = ii - worker.spacesFrom;
+
+ if (worker.canWrap && worker.line.length + spaces >
worker.useWrapWidth)
+ spaces = worker.useWrapWidth - worker.line.length;
+
+ if (!worker.canWrap || (worker.line.length + spaces <=
worker.useWrapWidth) && spaces >= 0) {
+ if (worker.collapseWhiteSpace && (!extraIndent ||
lines.length))
+ worker.line += " ";
+ else
+ worker.line += " ".repeat(spaces);
+ }
+
+ worker.spacesFrom = -1;
+ worker.lastSpace = worker.line.length;
+ } else if (worker.spacesFrom != -1) {
+ worker.lastSpace = worker.line.length;
+ }
+ },
+
+ commit : function(ii) {
+ worker.commitSpaces(ii);
+
+ if (worker.canWrap && worker.lastSpace != -1 && worker.lineLetters >
worker.useWrapWidth) {
+ lines[lines.length] = worker.line.substr(0, worker.lastSpace);
+ worker.line = worker.line.substr(worker.lastSpace);
+ } else if (worker.charWrap && worker.useWrapWidth != -1 && worker.lineLetters
worker.useWrapWidth) {
+ var jj, subLineLetters = 0;
+
+ for(jj = 0; jj < worker.line.length; jj++) {
+ if (worker.line.charAt(jj) == "\t") {
+ subLineLetters = subLineLetters - (subLineLetters %
EvoConvert.TAB_SIZE) + EvoConvert.TAB_SIZE;
+ } else {
+ subLineLetters++;
+ }
+
+ if (subLineLetters >= worker.useWrapWidth)
+ break;
+ }
+
+ lines[lines.length] = worker.line.substr(0, jj);
+ worker.line = worker.line.substr(jj);
+ } else if (worker.lastWasWholeLine && worker.line == "") {
+ worker.lastWasWholeLine = false;
+ } else {
+ lines[lines.length] = worker.line;
+ worker.line = "";
+ worker.lastWasWholeLine = true;
+ }
+
+ if (worker.canWrap && worker.collapseWhiteSpace && 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);
+ }
+
+ worker.lineLetters = worker.canWrap ? EvoConvert.calcLineLetters(worker.line)
: worker.line.length;
+ worker.spacesFrom = -1;
+ worker.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 == "\r")
+ continue;
+
+ if (chr == "\n") {
+ worker.commit(ii);
+ } else if (!worker.charWrap && !worker.collapseWhiteSpace && chr == "\t") {
+ if (worker.shouldWrap())
+ worker.commit(ii);
+ else
+ worker.commitSpaces(ii);
+
+ var add = " ".repeat(EvoConvert.TAB_WIDTH - (worker.lineLetters %
EvoConvert.TAB_WIDTH));
+
+ worker.lineLetters = worker.lineLetters - (worker.lineLetters %
EvoConvert.TAB_WIDTH) + EvoConvert.TAB_WIDTH;
+
+ if (worker.shouldWrap())
+ worker.commit(ii);
+
+ 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 %
EvoConvert.TAB_WIDTH) + EvoConvert.TAB_WIDTH;
+ setSpacesFrom = true;
+ } else if ((worker.spacesFrom == -1 && worker.line != "") ||
!worker.collapseWhiteSpace) {
+ 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 %
EvoConvert.TAB_WIDTH) + EvoConvert.TAB_WIDTH;
+ else
+ worker.lineLetters++;
+
+ if (worker.shouldWrap())
+ worker.commit(ii);
+ }
+ }
+
+ while (worker.line.length || worker.spacesFrom != -1 || !lines.length) {
+ worker.commit(ii);
+ }
+ } 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.processNode = function(node, normalDivWidth, quoteLevel)
+{
+ var str = "";
+
+ if (node.nodeType == node.TEXT_NODE) {
+ str = node.nodeValue;
+ } else if (node.nodeType == node.ELEMENT_NODE) {
+ if (node.hidden)
+ 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;
+
+ 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)
+ width = normalDivWidth;
+ } else {
+ width = normalDivWidth;
+ }
+
+ 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") {
+ str = "\n";
+ } else if (node.tagName == "IMG") {
+ str = EvoConvert.ImgToText(node);
+ } 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 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);
+ }
+
+ return str;
}
diff --git a/data/webkit/e-editor.js b/data/webkit/e-editor.js
new file mode 100644
index 0000000000..5f11d96523
--- /dev/null
+++ b/data/webkit/e-editor.js
@@ -0,0 +1,4583 @@
+/* -*- 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 = {
+ // stephenhay from https://mathiasbynens.be/demo/url-regex
+ URL_PATTERN : "((?:(?:(?:" + "news|telnet|nntp|file|https?|s?ftp|webcal|localhost|ssh" +
")\\:\\/\\/)|(?:www\\.|ftp\\.))[^\\s\\/\\$\\.\\?#].[^\\s]*+)",
+ // from camel-url-scanner.c
+ URL_INVALID_TRAILING_CHARS : ",.:;?!-|}])\">",
+ // http://www.w3.org/TR/html5/forms.html#valid-e-mail-address
+ 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])?)*+",
+
+ CURRENT_ELEMENT_ATTR : "x-evo-dialog-current-element",
+
+ 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,
+
+ 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, computedStyle;
+
+ value = EvoEditor.mode;
+ if (value != EvoEditor.formattingState.mode) {
+ EvoEditor.formattingState.mode = value;
+ changes["mode"] = value;
+ nchanges++;
+ }
+
+ computedStyle = anchorElem ? window.getComputedStyle(anchorElem) : null;
+
+ value = (computedStyle ? computedStyle.fontWeight : "") == "bold";
+ if (value != EvoEditor.formattingState.bold) {
+ EvoEditor.formattingState.bold = value;
+ changes["bold"] = value;
+ nchanges++;
+ }
+
+ tmp = computedStyle ? computedStyle.fontStyle : "";
+
+ value = tmp == "italic" || tmp == "oblique";
+ if (force || value != EvoEditor.formattingState.italic) {
+ EvoEditor.formattingState.italic = value;
+ changes["italic"] = value;
+ nchanges++;
+ }
+
+ tmp = computedStyle ? computedStyle.webkitTextDecorationsInEffect : "";
+
+ value = tmp.search("underline") >= 0 && (!anchorElem || anchorElem.tagName != "A");
+ if (force || value != EvoEditor.formattingState.underline) {
+ EvoEditor.formattingState.underline = value;
+ changes["underline"] = value;
+ nchanges++;
+ }
+
+ value = tmp.search("line-through") >= 0;
+ if (force || value != EvoEditor.formattingState.strikethrough) {
+ EvoEditor.formattingState.strikethrough = value;
+ changes["strikethrough"] = value;
+ nchanges++;
+ }
+
+ value = computedStyle ? computedStyle.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"] = (window.getComputedStyle(document.body).fontFamily == value) ? "" :
value;
+ nchanges++;
+ }
+
+ value = document.body ? document.body.style.fontFamily : "";
+ if (force || value != EvoEditor.formattingState.bodyFontFamily) {
+ EvoEditor.formattingState.bodyFontFamily = value;
+ changes["bodyFontFamily"] = value;
+ nchanges++;
+ }
+
+ value = computedStyle ? computedStyle.color : "";
+ if (force || value != EvoEditor.formattingState.fgColor) {
+ EvoEditor.formattingState.fgColor = value;
+ changes["fgColor"] = value;
+ nchanges++;
+ }
+
+ tmp = (computedStyle ? computedStyle.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 ((computedStyle ? computedStyle.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++;
+ }
+
+ value = 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,
+ fontSize : null,
+ indentLevel : 0,
+ bgColor : 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 && parent.tagName == "FONT" && parent.hasAttribute("size")) {
+ value = parent.getAttribute("size");
+ value = value ? parseInt(value, 10) : 0;
+ if (Number.isInteger(value) && value >= 1 && value <= 7) {
+ obj.fontSize = value;
+ }
+ }
+
+ 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;
+ }
+ }
+
+ 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;
+ 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.bgColor ? obj.bgColor : computedStyle.backgroundColor;
+ if (force || value != EvoEditor.formattingState.bgColor) {
+ EvoEditor.formattingState.bgColor = value;
+ changes["bgColor"] = 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.parentElement.removeChild(element);
+
+ return newElement;
+}
+
+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.parentElement.removeChild(element);
+
+ 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 (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.parentElement.removeChild(child);
+
+ 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.parentElement.removeChild(element);
+
+ 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.parentElement.removeChild(element);
+
+ 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.InsertHTML = function(opType, html)
+{
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_GROUP, opType, null, null,
EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE | EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ try {
+ document.execCommand("insertHTML", false, html);
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_GROUP, opType);
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+}
+
+EvoEditor.applySetBodyAttribute = function(record, isUndo)
+{
+ if (isUndo) {
+ if (record.beforeValue)
+ document.body.setAttribute(record.attrName, record.beforeValue);
+ else
+ document.body.removeAttribute(record.attrName);
+ } else {
+ if (record.attrValue)
+ document.body.setAttribute(record.attrName, record.attrValue);
+ else
+ document.body.removeAttribute(record.attrName);
+ }
+}
+
+EvoEditor.SetBodyAttribute = function(name, value)
+{
+ var record;
+
+ record = EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "setBodyAttribute::" + name,
document.body, document.body, EvoEditor.CLAIM_CONTENT_FLAG_NONE);
+
+ try {
+ if (record) {
+ record.attrName = name;
+ record.attrValue = value;
+ record.beforeValue = document.body.getAttribute(name);
+ record.apply = EvoEditor.applySetBodyAttribute;
+ }
+
+ if (value)
+ document.body.setAttribute(name, value);
+ else
+ document.body.removeAttribute(name);
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "setBodyAttribute::" + name);
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+}
+
+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.beforeInputCb = function(inputEvent)
+{
+ 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");
+ }
+
+ // it will add the text, if anything breaks before it gets here
+ inputEvent.stopImmediatePropagation();
+ inputEvent.stopPropagation();
+ inputEvent.preventDefault();
+}
+
+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().setPosition(document.body.firstChild ?
document.body.firstChild : document.body, 0);
+ }
+ }
+}
+
+EvoEditor.convertParagraphs = function(parent, wrapWidth)
+{
+ 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) {
+ child.style.width = "";
+ EvoEditor.removeEmptyStyleAttribute(child);
+ } else {
+ child.style.width = wrapWidth + "ch";
+ }
+ } else if (child.tagName == "BLOCKQUOTE") {
+ var innerWrapWidth = wrapWidth;
+
+ innerWrapWidth -= 2; // length of "> "
+
+ if (innerWrapWidth < EvoConvert.MIN_PARAGRAPH_WIDTH)
+ innerWrapWidth = EvoConvert.MIN_PARAGRAPH_WIDTH;
+
+ EvoEditor.convertParagraphs(child, innerWrapWidth);
+ } 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, EvoEditor.NORMAL_PARAGRAPH_WIDTH);
+ }
+}
+
+EvoEditor.convertImages = function()
+{
+ var ii;
+
+ for (ii = document.images.length - 1; ii >= 0; ii--) {
+ var img = document.images[ii];
+
+ img.outerText = EvoConvert.ImgToText(img);
+ }
+}
+
+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;
+
+ if (mode == EvoEditor.MODE_PLAIN_TEXT) {
+ EvoEditor.convertImages();
+ EvoEditor.convertParagraphs(document.body, EvoEditor.NORMAL_PARAGRAPH_WIDTH);
+ } else {
+ EvoEditor.convertParagraphs(document.body, -1);
+ }
+ } 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)
+{
+ var nodes, ii;
+
+ 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);
+ }
+
+ parent.removeChild(node);
+ } else {
+ node.removeAttribute("face");
+ }
+
+ if (change)
+ change.htmlAfter = parent.innerHTML;
+ }
+
+ if (undoRedoRecord && undoRedoRecord.changes)
+ undoRedoRecord.apply = EvoEditor.applyFontReset;
+}
+
+EvoEditor.maybeReplaceInheritFonts = function()
+{
+ if (document.querySelectorAll("font[face=inherit]").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);
+
+ 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", null, null,
+ EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE | EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ 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;
+
+ 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");
+
+ 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;
+ }
+ }
+
+ html = document.documentElement.outerHTML;
+
+ 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");
+ }
+
+ if (themeCss)
+ EvoEditor.UpdateThemeStyleSheet(themeCss);
+
+ return html;
+}
+
+EvoEditor.GetContent = function(flags, cid_uid_prefix)
+{
+ var content_data = {}, img_elems = [], bkg_elems = [], elems, ii, jj, currentElemsArray = null;
+
+ if (!document.body)
+ return content_data;
+
+ EvoUndoRedo.Disable();
+
+ try {
+ currentElemsArray = EvoEditor.RemoveCurrentElementAttr();
+
+ 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;
+ }
+ } else if (elem && src.startsWith("cid:")) {
+ images[images.length] = {
+ cid : elem.src,
+ src : elem.src
+ };
+ }
+ }
+
+ 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);
+ }
+ } else if (elem && src.startsWith("cid:")) {
+ images[images.length] = {
+ cid : elem.getAttribute("background"),
+ src : elem.getAttribute("background")
+ };
+ }
+ }
+
+ 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 < 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();
+ }
+ }
+
+ 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.innerText = 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.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 == "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.textIndent = "";
+ EvoEditor.removeEmptyStyleAttribute(selection.anchorNode);
+ EvoEditor.maybeUpdateParagraphWidth(selection.anchorNode);
+ }
+
+ // 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();
+ }
+ }
+ }
+
+ 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);
+
+ if (canLinks) {
+ var tmpNode;
+
+ for (tmpNode = anchorNode; tmpNode && tmpNode.tagName != "BODY"; tmpNode =
tmpNode.parentElement) {
+ if (tmpNode.tagName == "A") {
+ canLinks = false;
+ break;
+ }
+ }
+ }
+
+ var text = anchorNode.nodeValue, covered = false;
+
+ var replaceMatchWithNode = function(opType, match, newNode, canEmit) {
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, opType, anchorNode.parentElement,
anchorNode.parentElement,
+ EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+
+ try {
+ var offset = selection.anchorOffset, updateSelection = selection.anchorNode ===
anchorNode, newAnchorNode;
+
+ anchorNode.splitText(match.end);
+ newAnchorNode = anchorNode.nextSibling;
+ anchorNode.splitText(match.start);
+
+ anchorNode = anchorNode.nextSibling;
+
+ anchorNode.parentElement.insertBefore(newNode, anchorNode);
+ if (newNode.tagName == "A")
+ newNode.appendChild(anchorNode);
+ else
+ anchorNode.parentElement.removeChild(anchorNode);
+
+ if (updateSelection && newAnchorNode && offset - match.end >= 0)
+ selection.setPosition(newAnchorNode, offset - match.end);
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, opType);
+
+ if (canEmit) {
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+ }
+ }
+
+ if (canLinks) {
+ var isEmail = text.search("@") >= 0, match;
+
+ // the replace call below replaces (0xA0) with regular space
+ match = EvoEditor.findPattern(text.replace(/Â /g, " "), isEmail ? EvoEditor.EMAIL_PATTERN :
EvoEditor.URL_PATTERN);
+ if (match) {
+ var url = text.substring(match.start, match.end), node;
+
+ // because 'search' uses Regex and throws exception on brackets and other
Regex-sensitive characters
+ var isInvalidTrailingChar = function(chr) {
+ var jj;
+
+ for (jj = 0; jj < EvoEditor.URL_INVALID_TRAILING_CHARS.length; jj++) {
+ if (chr == EvoEditor.URL_INVALID_TRAILING_CHARS.charAt(jj))
+ return true;
+ }
+
+ return false;
+ };
+
+ /* 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 (url.length > 0 && isInvalidTrailingChar(url.charAt(url.length - 1))) {
+ var open_bracket = 0, close_bracket = url.charAt(url.length - 1);
+
+ 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) {
+ var n_opened = 0, n_closed = 0, ii, chr;
+
+ for (ii = 0; ii < url.length; ii++) {
+ chr = url.charAt(ii);
+
+ if (chr == open_bracket)
+ n_opened++;
+ else if (chr == close_bracket)
+ n_closed++;
+ }
+
+ /* The closing bracket can match one inside the URL,
+ thus keep it there. */
+ if (n_opened > 0 && n_opened - n_closed >= 0)
+ break;
+ }
+
+ url = url.substr(0, url.length - 1);
+ match.end--;
+ }
+
+ if (url.length > 0) {
+ covered = true;
+
+ if (isEmail)
+ url = "mailto:" + url;
+ else if (url.startsWith("www."))
+ url = "https://" + url;
+
+ node = document.createElement("A");
+ node.href = url;
+
+ replaceMatchWithNode("magicLink", match, node, 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 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;
+ }
+
+ replaceMatchWithNode("magicSmiley", match, node, sz == 1);
+ }
+ } finally {
+ if (sz > 1) {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_GROUP, "magicSmiley");
+ 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);
+ 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.parentElement.removeChild(element);
+ 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.parentElement.removeChild(cell);
+
+ 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.parentElement.removeChild(cell);
+ } 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.parentElement.removeChild(element);
+ } 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().modify("move", "forward", "word");
+ }
+ } 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.InsertSignature = function(content, isHTML, uid, fromMessage, checkChanged, ignoreNextChange,
startBottom, topSignature, addDelimiter)
+{
+ var sigSpan, node;
+
+ 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;
+
+ 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.parentElement)
+ node.parentElement.removeChild(node);
+
+ node = sigSpan.querySelector("#-x-evo-selection-end-marker");
+ if (node && node.parentElement)
+ node.parentElement.removeChild(node);
+ }
+
+ 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"))) {
+ if (node.parentElement)
+ node.parentElement.removeChild(node);
+ }
+ }
+
+ /* Leave just one signature wrapper there as it will be reused. */
+ if (ii) {
+ if (wrapper.parentElement)
+ wrapper.parentElement.removeChild(wrapper);
+ } 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);
+ }
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM,
"InsertSignature::new-changes");
+ }
+ } else {
+ useWrapper = document.createElement("DIV");
+ useWrapper.className = "-x-evo-signature-wrapper";
+ useWrapper.appendChild(sigSpan);
+
+ if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT)
+ useWrapper.style.width = EvoEditor.NORMAL_PARAGRAPH_WIDTH + "ch";
+
+ 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");
+ }
+
+ var res = [];
+
+ res["fromMessage"] = fromMessage;
+ res["checkChanged"] = checkChanged;
+ res["ignoreNextChange"] = ignoreNextChange;
+ res["newUid"] = uid;
+
+ return res;
+}
+
+// the body contains data, which should be converted into editable content;
+// preferredPlainText can be empty, if not, then it replaces body content
+EvoEditor.ConvertContent = function(preferredPlainText, startBottom, topSignature)
+{
+}
+
+// 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 content = document.createElement(quote ? "BLOCKQUOTE" : "DIV");
+
+ if (quote) {
+ content.setAttribute("type", "cite");
+ }
+
+ if (isHTML) {
+ if (EvoEditor.mode == EvoEditor.MODE_HTML) {
+ 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);
+ }
+ } else {
+ content.innerText = text;
+ }
+ } else {
+ content.innerText = text;
+ }
+
+ if (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)
+
document.getSelection().setPosition(content.lastChild, 0);
+ else
+ document.getSelection().setPosition(content, 0);
+
+ if (anchorNode.nodeType == anchorNode.ELEMENT_NODE &&
anchorNode.parentElement &&
+ (anchorNode.tagName == "DIV" || anchorNode.tagName == "P"
|| anchorNode.tagName == "PRE") &&
+ (!anchorNode.children.length ||
(anchorNode.children.length == 1 && anchorNode.children[0].tagName == "BR"))) {
+ anchorNode.parentElement.removeChild(anchorNode);
+ }
+ } 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);
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM,
"InsertContent::text");
+ }
+ }
+ } else {
+ EvoEditor.InsertHTML("InsertContent::text", content.outerHTML);
+ }
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_GROUP, "InsertContent");
+ EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
+ EvoEditor.EmitContentChanged();
+ }
+}
+
+EvoEditor.processLoadedContent = function()
+{
+ var node, cite;
+
+ node = document.querySelector("span.-x-evo-cite-body");
+
+ cite = node;
+
+ if (node && node.parentElement) {
+ node.parentElement.removeChild(node);
+ }
+
+ if (cite) {
+ cite = document.createElement("BLOCKQUOTE");
+ cite.setAttribute("type", "cite");
+ while (document.body.firstChild) {
+ cite.appendChild(document.body.firstChild);
+ }
+
+ document.body.appendChild(cite);
+ }
+
+ var ii, list;
+
+ 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);
+ }
+
+ node.parentElement.removeChild(node);
+ }
+
+ list = document.querySelectorAll(".-x-evo-paragraph");
+
+ for (ii = list.length - 1; ii >= 0; ii--) {
+ node = list[ii];
+ node.removeAttribute("class");
+ }
+
+ // require blocks under BLOCKQUOTE
+ list = document.querySelectorAll("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)) {
+ if (!addingTo) {
+ addingTo = document.createElement("DIV");
+ blockquoteNode.insertBefore(addingTo, node);
+ EvoEditor.maybeUpdateParagraphWidth(addingTo);
+ }
+
+ addingTo.appendChild(node);
+ } else {
+ addingTo = null;
+ }
+ }
+ }
+}
+
+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.parentElement.removeChild(child);
+
+ 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.parentElement.removeChild(nextSibling);
+ }
+
+ child = nextChild;
+ continue;
+ }
+ } else {
+ nextChild = child.nextSibling;
+
+ child.parentElement.removeChild(child);
+
+ 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) {
+ 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 {
+ usedLetters = EvoEditor.wrapParagraph(nodeFrom, maxLetters,
currentPar, usedLetters, false);
+
+ 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.parentElement.removeChild(node);
+ } 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(null);
+};
+
+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..86aefcbe29
--- /dev/null
+++ b/data/webkit/e-undo-redo.js
@@ -0,0 +1,906 @@
+/* -*- 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 : 1024, /* 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");
+ }
+ },
+
+ 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;
+
+ 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) {
+ throw "EvoUndoRedo:StopRecord: Mismatch in record kind, expected " + record.kind + ", but
received " + kind;
+ }
+
+ if (record.opType != opType) {
+ throw "EvoUndoRedo:StopRecord: Mismatch in record opType, expected '" + record.opType + "',
but received '" + opType + "'";
+ }
+
+ 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.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);
+ }
+}
+
+/* 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 e84fd7eb95..b2c5201fcf 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/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..07cfb1edbc 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,15 +1446,12 @@ 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);
}
@@ -1449,7 +1459,6 @@ composer_build_message (EMsgComposer *composer,
g_byte_array_append (data, (guint8 *) text, strlen (text));
if (!g_str_has_suffix (text, "\r\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"))
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");
- 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");
- 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);
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..fce296fd1e 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,348 @@ 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);
+
+ 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);
+ g_clear_object (&file);
+
+ if (file_stream) {
+ if (!prefer_filename) {
+ file_info = g_file_input_stream_query_info (file_stream,
G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, 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;
+ }
+ }
+
+ 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");
- iface->insert_image_from_mime_part (editor, part);
+ if (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 +2071,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 +2149,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 +2342,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 +2532,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 +2557,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 +2681,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 +3003,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 +3013,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 +3029,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 +3162,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 +3172,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 +3186,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 +3202,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 +3762,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 +3792,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 +3824,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 +3868,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 5abc9a4c91..2b2584260d 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
*
@@ -1154,6 +1257,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"),
@@ -1405,14 +1515,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"),
@@ -1421,6 +1523,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"),
@@ -2103,6 +2221,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)
{
@@ -2167,18 +2321,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",
@@ -2187,11 +2345,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 e6af175d34..8c50ff8ec1 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..ad56b0c01a 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);
}
@@ -917,6 +921,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 +978,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 +991,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 +1006,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 9639784dbf..ab8906ed7f 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 9b1efc389b..28fbd86fe1 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 1c8ea78dc2..873324d635 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-utils.c b/src/e-util/test-html-editor-units-utils.c
index daedae625f..25dca04aef 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,22 @@ 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);
+
+ 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 +361,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 +380,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 +416,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 +500,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 +565,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 +689,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 +748,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);
+ 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);
- g_return_val_if_fail (G_IS_DBUS_PROXY (web_extension), FALSE);
+ hed.async_data = test_utils_async_call_prepare();
+ hed.equal = FALSE;
- 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);
+ webkit_web_view_run_javascript (WEBKIT_WEB_VIEW (cnt_editor), script, NULL,
+ test_html_equal_done_cb, &hed);
- g_clear_error (&error);
+ test_utils_async_call_wait (hed.async_data, 10);
- g_return_val_if_fail (result != NULL, FALSE);
+ g_free (script);
- g_variant_get (result, "(b)", &html_equal);
- g_variant_unref (result);
-
- return html_equal;
+ return hed.equal;
}
static gboolean
@@ -781,6 +949,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 +1008,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 +1016,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 +1085,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 +1171,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 +1183,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 +1194,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 +1210,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 +1292,27 @@ 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);
-
- image_data_base64 = g_base64_encode ((const guchar *) image_data, image_data_length);
-
- g_free (image_data);
+ 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..83a316526b 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 ();
}
@@ -306,9 +308,9 @@ test_font_size_selection (TestFixture *fixture)
"action:size-plus-three\n"
"seq:rrCSrcs\n"
"action:size-plus-four\n",
- HTML_PREFIX "<div><font size=\"1\">FontM2</font> <font size=\"2\">FontM1</font> Font0 <font
size=\"4\">FontP1</font> "
+ HTML_PREFIX "<div><font size=\"1\">FontM2</font> <font size=\"2\">FontM1</font> <font
size=\"3\">Font0</font> <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,177 +697,2821 @@ 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 ();
+}
+
+static void
+test_list_roman_plain (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "action:style-list-roman\n"
+ "type:1\\n\n"
+ "type:2\\n\n"
+ "type:3\\n\n"
+ "type:4\\n\n"
+ "type:5\\n\n"
+ "type:6\\n\n"
+ "type:7\\n\n"
+ "type:8\\n\n"
+ "type:9\\n\n"
+ "type:10\\n\n"
+ "type:11\\n\n"
+ "type:12\\n\n"
+ "type:13\\n\n"
+ "type:14\\n\n"
+ "type:15\\n\n"
+ "type:16\\n\n"
+ "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\n"))
+ g_test_fail ();
+}
+
+static void
+test_list_multi_html (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:style-list-bullet\n"
+ "type:item 1\\n\n"
+ "type:item 2\\n\n"
+ "type:\\n\n"
+ "action:style-list-roman\n"
+ "type:item 3\\n\n"
+ "type:item 4\\n\n",
+ HTML_PREFIX
+ "<ul>"
+ "<li>item 1</li>"
+ "<li>item 2</li>"
+ "</ul>"
+ "<ol type=\"I\">"
+ "<li>item 3</li>"
+ "<li>item 4</li>"
+ "<li><br></li>"
+ "</ol>"
+ HTML_SUFFIX,
+ " * item 1\n"
+ " * item 2\n"
+ " I. item 3\n"
+ " II. item 4\n"
+ " III. \n"))
+ g_test_fail ();
+}
+
+static void
+test_list_multi_plain (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "action:style-list-bullet\n"
+ "type:item 1\\n\n"
+ "type:item 2\\n\n"
+ "type:\\n\n"
+ "action:style-list-roman\n"
+ "type:item 3\\n\n"
+ "type:item 4\\n\n",
+ NULL,
+ " * item 1\n"
+ " * item 2\n"
+ " I. item 3\n"
+ " II. item 4\n"
+ " III. \n"))
+ g_test_fail ();
+}
+
+static void
+test_list_multi_change_html (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:style-list-bullet\n"
+ "type:item 1\\n\n"
+ "type:item 2\\n\n"
+ "type:\\n\n"
+ "action:style-list-roman\n"
+ "type:item 3\\n\n"
+ "type:item 4\\n\n"
+ "action:select-all\n"
+ "action:style-list-number\n",
+ HTML_PREFIX
+ "<ol>"
+ "<li>item 1</li>"
+ "<li>item 2</li>"
+ "<li>item 3</li>"
+ "<li>item 4</li>"
+ "<li><br></li>"
+ "</ol>"
+ HTML_SUFFIX,
+ " 1. item 1\n"
+ " 2. item 2\n"
+ " 3. item 3\n"
+ " 4. item 4\n"
+ " 5. \n"))
+ g_test_fail ();
+}
+
+static void
+test_list_multi_change_plain (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "action:style-list-bullet\n"
+ "type:item 1\\n\n"
+ "type:item 2\\n\n"
+ "type:\\n\n"
+ "action:style-list-roman\n"
+ "type:item 3\\n\n"
+ "type:item 4\\n\n"
+ "action:select-all\n"
+ "action:style-list-number\n",
+ NULL,
+ " 1. item 1\n"
+ " 2. item 2\n"
+ " 3. item 3\n"
+ " 4. item 4\n"
+ " 5. \n"))
+ g_test_fail ();
+}
+
+static void
+test_list_indent_same (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 all items */
+
+ if (!test_utils_run_simple_test (fixture,
+ "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;
+ }
+
+ 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>"
+ "<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;
+ }
+
+ 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>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;
+ }
+
+ 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>"
+ "<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;
+ }
+
+ 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:d\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 ();
+ 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>"
+ "<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;
+ }
+
+ 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: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,
+ "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,
+ "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:uuuSds\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,
+ "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;
+ }
+
+ 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:duSds\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;
+ }
+
+ 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>"
+ "<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,
+ "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:dSus\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:uuuSddds\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:d\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:dd\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:uuuSds\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:duSds\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:dSus\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:uuuSds\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:duSds\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:dSus\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:uuuSds\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:duSds\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:dSus\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_roman_plain (TestFixture *fixture)
+test_list_indent_multi_html (TestFixture *fixture)
{
- if (!test_utils_run_simple_test (fixture,
- "mode:plain\n"
- "action:style-list-roman\n"
- "type:1\\n\n"
- "type:2\\n\n"
- "type:3\\n\n"
- "type:4\\n\n"
- "type:5\\n\n"
- "type:6\\n\n"
- "type:7\\n\n"
- "type:8\\n\n"
- "type:9\\n\n"
- "type:10\\n\n"
- "type:11\\n\n"
- "type:12\\n\n"
- "type:13\\n\n"
- "type:14\\n\n"
- "type:15\\n\n"
- "type:16\\n\n"
- "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"))
+ if (!test_utils_process_commands (fixture, "mode:html\n")) {
g_test_fail ();
+ return;
+ }
+
+ test_list_indent_multi (fixture, TRUE);
}
static void
-test_list_multi_html (TestFixture *fixture)
+test_list_indent_multi_plain (TestFixture *fixture)
{
- if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "action:style-list-bullet\n"
- "type:item 1\\n\n"
- "type:item 2\\n\n"
- "type:\\n\n"
- "action:style-list-roman\n"
- "type:item 3\\n\n"
- "type:item 4\\n\n",
+ 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>item 1</li>"
- "<li>item 2</li>"
+ "<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>"
- "<ol type=\"I\">"
- "<li>item 3</li>"
- "<li>item 4</li>"
- "<li><br></li>"
+ "<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,
- " * item 1\n"
- " * item 2\n"
- " I. item 3\n"
- " II. item 4\n"
- " III. "))
+ "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;
+ }
-static void
-test_list_multi_plain (TestFixture *fixture)
-{
if (!test_utils_run_simple_test (fixture,
- "mode:plain\n"
- "action:style-list-bullet\n"
- "type:item 1\\n\n"
- "type:item 2\\n\n"
- "type:\\n\n"
- "action:style-list-roman\n"
- "type:item 3\\n\n"
- "type:item 4\\n\n",
- NULL,
- " * item 1\n"
- " * item 2\n"
- " I. item 3\n"
- " II. item 4\n"
- " III. "))
+ "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;
+ }
-static void
-test_list_multi_change_html (TestFixture *fixture)
-{
if (!test_utils_run_simple_test (fixture,
- "mode:html\n"
- "action:style-list-bullet\n"
- "type:item 1\\n\n"
- "type:item 2\\n\n"
- "type:\\n\n"
- "action:style-list-roman\n"
- "type:item 3\\n\n"
- "type:item 4\\n\n"
- "action:select-all\n"
- "action:style-list-number\n",
+ "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>item 1</li>"
- "<li>item 2</li>"
- "<li>item 3</li>"
- "<li>item 4</li>"
- "<li><br></li>"
+ "<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,
- " 1. item 1\n"
- " 2. item 2\n"
- " 3. item 3\n"
- " 4. item 4\n"
- " 5. "))
+ "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_multi_change_plain (TestFixture *fixture)
+test_list_indent_nested_html (TestFixture *fixture)
{
- if (!test_utils_run_simple_test (fixture,
- "mode:plain\n"
- "action:style-list-bullet\n"
- "type:item 1\\n\n"
- "type:item 2\\n\n"
- "type:\\n\n"
- "action:style-list-roman\n"
- "type:item 3\\n\n"
- "type:item 4\\n\n"
- "action:select-all\n"
- "action:style-list-number\n",
- NULL,
- " 1. item 1\n"
- " 2. item 2\n"
- " 3. item 3\n"
- " 4. item 4\n"
- " 5. "))
+ 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
@@ -826,7 +3524,7 @@ test_link_insert_dialog (TestFixture *fixture)
"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"))
+ "a link example: http://www.gnome.org\n"))
g_test_fail ();
}
@@ -841,7 +3539,7 @@ test_link_insert_dialog_selection (TestFixture *fixture)
"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"))
+ "a link example: GNOME\n"))
g_test_fail ();
}
@@ -851,8 +3549,8 @@ 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 "))
+ HTML_PREFIX "<div><a href=\"https://www.gnome.org\">www.gnome.org</a> </div>" HTML_SUFFIX,
+ "www.gnome.org \n"))
g_test_fail ();
}
@@ -869,8 +3567,8 @@ test_link_insert_typed_change_description (TestFixture *fixture)
"seq:a\n"
"type:GNOME\n"
"seq:n\n",
- HTML_PREFIX "<div><a href=\"http://www.gnome.org\">GNOME</a> </div>" HTML_SUFFIX,
- "GNOME "))
+ HTML_PREFIX "<div><a href=\"https://www.gnome.org\">GNOME</a> </div>" HTML_SUFFIX,
+ "GNOME \n"))
g_test_fail ();
}
@@ -886,7 +3584,7 @@ test_link_insert_dialog_remove_link (TestFixture *fixture)
"type:R\n"
"seq:a\n",
HTML_PREFIX "<div>www.gnome.org </div>" HTML_SUFFIX,
- "www.gnome.org "))
+ "www.gnome.org \n"))
g_test_fail ();
}
@@ -898,8 +3596,8 @@ test_link_insert_typed_append (TestFixture *fixture)
"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 "))
+ 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 ();
}
@@ -910,8 +3608,8 @@ test_link_insert_typed_remove (TestFixture *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"))
+ HTML_PREFIX "<div><a href=\"https://www.gnome.org\">www.gnome.o</a></div>" HTML_SUFFIX,
+ "www.gnome.o\n"))
g_test_fail ();
}
@@ -923,8 +3621,8 @@ test_h_rule_insert (TestFixture *fixture)
"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"))
+ HTML_PREFIX "<div>text</div><hr align=\"center\">" HTML_SUFFIX,
+ "text\n\n"))
g_test_fail ();
}
@@ -938,8 +3636,10 @@ test_h_rule_insert_text_after (TestFixture *fixture)
"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"))
+ HTML_PREFIX "<div>above</div><hr align=\"center\"><div>below</div>" HTML_SUFFIX,
+ "above\n"
+ "\n"
+ "below\n"))
g_test_fail ();
}
@@ -949,7 +3649,6 @@ test_image_insert (TestFixture *fixture)
EContentEditor *cnt_editor;
gchar *expected_html;
gchar *filename;
- gchar *image_data_base64;
gchar *uri;
GError *error = NULL;
@@ -970,18 +3669,11 @@ test_image_insert (TestFixture *fixture)
/* Wait some time until the operation is finished */
test_utils_wait_milliseconds (500);
- image_data_base64 = test_utils_get_base64_data_for_image (filename);
+ expected_html = g_strconcat (HTML_PREFIX "<div>before*<img src=\"", uri, "\" width=\"24px\"
height=\"24px\">+after</div>" HTML_SUFFIX, NULL);
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);
-
if (!test_utils_run_simple_test (fixture,
"undo:save\n" /* 1 */
"undo:undo\n"
@@ -989,7 +3681,7 @@ test_image_insert (TestFixture *fixture)
"undo:test:1\n"
"type:+after\n",
expected_html,
- "before*+after"))
+ "before*+after\n"))
g_test_fail ();
g_free (expected_html);
@@ -998,24 +3690,23 @@ test_image_insert (TestFixture *fixture)
static void
test_emoticon_insert_typed (TestFixture *fixture)
{
- gchar *image_data_base64;
+ 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_data_base64 = test_utils_get_base64_data_for_image ("face-smile");
+ image_uri = test_utils_dup_image_uri ("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);
+ 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_data_base64);
+ g_free (image_uri);
if (!test_utils_run_simple_test (fixture,
"mode:html\n"
"type:before :)after\n",
expected_html,
- "before :-)after"))
+ "before :-)after\n"))
g_test_fail ();
g_free (expected_html);
@@ -1024,24 +3715,23 @@ test_emoticon_insert_typed (TestFixture *fixture)
static void
test_emoticon_insert_typed_dash (TestFixture *fixture)
{
- gchar *image_data_base64;
+ 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_data_base64 = test_utils_get_base64_data_for_image ("face-smile");
+ image_uri = test_utils_dup_image_uri ("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);
+ 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_data_base64);
+ g_free (image_uri);
if (!test_utils_run_simple_test (fixture,
"mode:html\n"
"type:before :-)after\n",
expected_html,
- "before :-)after"))
+ "before :-)after\n"))
g_test_fail ();
g_free (expected_html);
@@ -1061,7 +3751,7 @@ test_paragraph_normal_selection (TestFixture *fixture)
"<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.")) {
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n")) {
g_test_fail ();
return;
}
@@ -1072,7 +3762,7 @@ test_paragraph_normal_selection (TestFixture *fixture)
"<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.")) {
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n")) {
g_test_fail ();
return;
}
@@ -1083,7 +3773,7 @@ test_paragraph_normal_selection (TestFixture *fixture)
"<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.")) {
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n")) {
g_test_fail ();
return;
}
@@ -1102,7 +3792,7 @@ test_paragraph_normal_typed (TestFixture *fixture)
"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.")) {
+ "odio. Praesent libero.\n")) {
g_test_fail ();
return;
}
@@ -1114,7 +3804,7 @@ test_paragraph_normal_typed (TestFixture *fixture)
"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.")) {
+ "odio. Praesent libero.\n")) {
g_test_fail ();
return;
}
@@ -1126,7 +3816,7 @@ test_paragraph_normal_typed (TestFixture *fixture)
"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.")) {
+ "odio. Praesent libero.\n")) {
g_test_fail ();
return;
}
@@ -1146,7 +3836,7 @@ test_paragraph_preformatted_selection (TestFixture *fixture)
"<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.")) {
+ "odio. Praesent libero.\n")) {
g_test_fail ();
return;
}
@@ -1157,7 +3847,7 @@ test_paragraph_preformatted_selection (TestFixture *fixture)
"<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.")) {
+ "odio. Praesent libero.\n")) {
g_test_fail ();
return;
}
@@ -1168,7 +3858,7 @@ test_paragraph_preformatted_selection (TestFixture *fixture)
"<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.")) {
+ "odio. Praesent libero.\n")) {
g_test_fail ();
return;
}
@@ -1185,7 +3875,7 @@ test_paragraph_preformatted_typed (TestFixture *fixture)
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.")) {
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n")) {
g_test_fail ();
return;
}
@@ -1195,7 +3885,7 @@ test_paragraph_preformatted_typed (TestFixture *fixture)
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.")) {
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n")) {
g_test_fail ();
return;
}
@@ -1205,7 +3895,7 @@ test_paragraph_preformatted_typed (TestFixture *fixture)
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.")) {
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n")) {
g_test_fail ();
return;
}
@@ -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 ();
}
@@ -1939,9 +4631,8 @@ test_cite_html2plain (TestFixture *fixture)
"> > level 2\n"
"> back in level 1\n"
"\n"
- "out of the citation")) {
+ "out of the citation"))
g_test_fail ();
- }
}
static void
@@ -2342,7 +5033,7 @@ test_undo_style (TestFixture *fixture)
"undo:drop\n" /* drop the save 2 */
"undo:undo:14\n"
- "action:monospaced\n"
+ "font-name:monospace\n"
"type:monospaced\n"
"undo:save\n" /* 2 */
"undo:undo:11\n"
@@ -2353,7 +5044,7 @@ test_undo_style (TestFixture *fixture)
"undo:undo:11\n"
"type:monospaced\n"
"seq:CSlsc\n"
- "action:monospaced\n"
+ "font-name:monospace\n"
"undo:save\n" /* 2 */
"undo:undo:11\n"
"undo:test:2\n"
@@ -2696,7 +5387,7 @@ test_replace_dialog (TestFixture *fixture)
"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 ();
}
@@ -2717,7 +5408,134 @@ test_replace_dialog_all (TestFixture *fixture)
"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 ();
}
@@ -2767,6 +5585,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 +5616,124 @@ 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-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 ("/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 ("/replace/dialog", test_replace_dialog);
test_utils_add_test ("/replace-all/dialog", test_replace_dialog_all);
+ test_utils_add_test ("/wrap/basic", test_wrap_basic);
+ test_utils_add_test ("/wrap/nested", test_wrap_nested);
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..7403523ecc 100644
--- a/src/e-util/test-html-editor.c
+++ b/src/e-util/test-html-editor.c
@@ -139,19 +139,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 +173,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 +195,94 @@ view_source_dialog (EHTMLEditor *editor,
gtk_widget_destroy (dialog);
}
+typedef struct _ViewSourceData {
+ EHTMLEditor *editor;
+ gchar *title;
+ gboolean plain_text;
+ gboolean show_source;
+} ViewSourceData;
+
+static ViewSourceData *
+view_source_data_new (EHTMLEditor *editor,
+ const gchar *title,
+ gboolean plain_text,
+ gboolean show_source)
+{
+ ViewSourceData *vsd;
+
+ vsd = g_slice_new (ViewSourceData);
+ vsd->editor = g_object_ref (editor);
+ vsd->title = g_strdup (title);
+ vsd->plain_text = plain_text;
+ 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->plain_text, vcd->show_source,
+ e_content_editor_util_get_content_data (content_hash,
+ vcd->plain_text ? E_CONTENT_EDITOR_GET_TO_SEND_PLAIN :
E_CONTENT_EDITOR_GET_TO_SEND_HTML));
+
+ 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,
+ gboolean plain_text,
+ gboolean show_source)
+{
+ EContentEditor *cnt_editor;
+ ViewSourceData *vcd;
+ guint32 flags;
+
+ vcd = view_source_data_new (editor, title, plain_text, show_source);
+
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ if (plain_text) {
+ flags = E_CONTENT_EDITOR_GET_TO_SEND_PLAIN;
+ } else {
+ flags = E_CONTENT_EDITOR_GET_INLINE_IMAGES | E_CONTENT_EDITOR_GET_TO_SEND_HTML;
+ }
+
+ 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 +313,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 +339,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 +348,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 +355,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
@@ -446,6 +527,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 +567,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);
@@ -571,6 +674,10 @@ 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);
diff --git a/src/e-util/test-web-view-jsc.c b/src/e-util/test-web-view-jsc.c
index 33780da89a..dd9f25c230 100644
--- a/src/e-util/test-web-view-jsc.c
+++ b/src/e-util/test-web-view-jsc.c
@@ -1419,6 +1419,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 +1449,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 +1618,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 +1662,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 +1695,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 +1931,767 @@ 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 \n 0\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 }
+ };
+
+ #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>")
+
+ 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 }
+ };
+
+ #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 +2703,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 +2722,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..1caaadca18 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")) {
+ 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")) {
+ 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")) {
+ 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..d78bc933b3 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,17 @@ 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
};
struct _EWebKitEditorPrivate {
@@ -75,13 +77,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 +86,38 @@ 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;
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 +159,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 +180,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 +638,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 +646,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 +654,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 +724,368 @@ 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_cb (EWebKitEditor *wk_editor);
+
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_cb (wk_editor);
- 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");
- g_clear_object (&wk_editor->priv->web_extension_proxy);
+ 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);
+
+ 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");
+
+ 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);
- 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);
+ 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");
- page_id = current_page_id (wk_editor);
+ if (webkit_editor_update_color_value (jsc_params, "bgColor", &wk_editor->priv->background_color) ||
forced)
+ g_object_notify (object, "background-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));
+ 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);
+
+ 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;
- 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));
-}
+ editor_state = webkit_web_view_get_editor_state (WEBKIT_WEB_VIEW (wk_editor));
-static void
-webkit_editor_set_format_boolean (EWebKitEditor *wk_editor,
- const gchar *format_dom_function,
- gboolean format_value)
-{
- guint64 page_id;
+ if (editor_state) {
+ GObject *object = G_OBJECT (wk_editor);
+ gboolean value;
- page_id = current_page_id (wk_editor);
+ #define check_and_set_prop(_prop_var, _prop_name, _val_func) \
+ value = _val_func (editor_state); \
+ if (_prop_var != value) { \
+ _prop_var = value; \
+ g_object_notify (object, _prop_name); \
+ }
- 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));
-}
+ g_object_freeze_notify (object);
-static void
-webkit_editor_set_format_int (EWebKitEditor *wk_editor,
- const gchar *format_dom_function,
- gint32 format_value)
-{
- guint64 page_id;
+ check_and_set_prop (wk_editor->priv->can_copy, "can-copy",
webkit_editor_state_is_copy_available);
+ check_and_set_prop (wk_editor->priv->can_cut, "can-cut",
webkit_editor_state_is_cut_available);
+ check_and_set_prop (wk_editor->priv->can_paste, "can-paste",
webkit_editor_state_is_paste_available);
- 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 +1135,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 +1293,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 +1300,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,84 +1309,166 @@ 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,
- "ol "
- "{\n"
- " -webkit-padding-start: %dch; \n"
- "}\n", SPACES_ORDERED_LIST_FIRST_LEVEL);
+ 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,
- "ol.-x-evo-indented "
- "{\n"
- " -webkit-padding-start: %dch; \n"
- "}\n", SPACES_PER_LIST_LEVEL);
+ 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 (
- stylesheet,
- ".-x-evo-align-left "
- "{\n"
- " text-align: left; \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 (
- stylesheet,
- ".-x-evo-align-center "
- "{\n"
- " text-align: center; \n"
- "}\n");
+ 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 (
+ 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_printf (
stylesheet,
- ".-x-evo-align-right "
+ "ol "
"{\n"
- " text-align: right; \n"
- "}\n");
+ " -webkit-padding-start: %dch; \n"
+ "}\n", SPACES_ORDERED_LIST_FIRST_LEVEL);
g_string_append (
stylesheet,
@@ -1258,85 +1581,18 @@ webkit_editor_update_styles (EContentEditor *editor)
"}\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");
+ if (wk_editor->priv->visually_wrap_long_lines) {
+ g_string_append (
+ stylesheet,
+ "pre {\n"
+ " white-space: pre-wrap;\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,
- "pre {\n"
- " white-space: pre-wrap;\n"
- "}\n");
- }
-
- if (pango_font_description_get_size (ms) < pango_font_description_get_size (vw) ||
!wk_editor->priv->html_mode)
- min_size = ms;
- else
- min_size = vw;
+ if (pango_font_description_get_size (ms) < pango_font_description_get_size (vw) ||
!wk_editor->priv->html_mode)
+ min_size = ms;
+ else
+ min_size = vw;
settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (wk_editor));
g_object_set (
@@ -1378,200 +1634,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);
+ g_return_if_fail (css != NULL);
+ g_return_if_fail (selector != NULL);
+ g_return_if_fail (property != NULL);
- color = g_strdup_printf ("#%06x", e_rgba_to_value (value));
-
- 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;
-
- result = webkit_editor_get_element_attribute (wk_editor, "body", "bgcolor");
- if (result) {
- const gchar *value;
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- 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);
-
- if (!wk_editor->priv->html_mode)
- goto theme;
-
- result = webkit_editor_get_element_attribute (wk_editor, "body", "link");
- if (result) {
- const gchar *value;
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- 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
@@ -1613,54 +1835,85 @@ get_color_from_context (GtkStyleContext *context,
static void
webkit_editor_style_updated_cb (EWebKitEditor *wk_editor)
{
- 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 (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;
- get_color_from_context (style_context, "link-color", &rgba);
- webkit_editor_page_set_link_color (E_CONTENT_EDITOR (wk_editor), &rgba);
+ css = g_string_sized_new (160);
+ script = g_string_sized_new (256);
- get_color_from_context (style_context, "visited-link-color", &rgba);
- webkit_editor_page_set_visited_link_color (E_CONTENT_EDITOR (wk_editor), &rgba);
+ 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);
+
+ g_string_free (css, TRUE);
}
static gboolean
@@ -1698,90 +1951,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);
}
static void
@@ -1797,8 +1983,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 +1993,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 +2012,193 @@ 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);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.ConvertContent(%s, %x, %x);",
+ content,
+ 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"));
} 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);
+ !(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_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);
+ 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_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);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.InsertHTML(%s, %s);",
+ "InsertHTML", content);
+ } else {
+ g_warning ("%s: Unsupported flags combination (0x%x)", G_STRFUNC, flags);
+ }
}
-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;
-
- base64_encoded_data = strstr (element_src, ";base64,");
- if (!base64_encoded_data)
- goto out;
+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;
- mime_type = g_strndup (
- element_src + 5,
- base64_encoded_data - (strstr (element_src, "data:") + 5));
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (editor));
- /* Move to actual data */
- base64_encoded_data += 8;
+ 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);
- base64_decoded_data = g_base64_decode (base64_encoded_data, &decoded_size);
+ webkit_web_view_run_javascript (WEBKIT_WEB_VIEW (editor), script, cancellable, callback, user_data);
- stream = camel_stream_mem_new ();
- size = camel_stream_write (
- stream, (gchar *) base64_decoded_data, decoded_size, NULL, NULL);
+ g_free (cid_uid_prefix);
+ g_free (script);
+}
- if (size == -1)
- goto out;
+static EContentEditorContentHash *
+webkit_editor_get_content_finish (EContentEditor *editor,
+ GAsyncResult *result,
+ GError **error)
+{
+ WebKitJavascriptResult *js_result;
+ EContentEditorContentHash *content_hash = NULL;
+ GError *local_error = NULL;
- wrapper = camel_data_wrapper_new ();
- camel_data_wrapper_construct_from_stream_sync (
- wrapper, stream, NULL, NULL);
- g_object_unref (stream);
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (editor), NULL);
+ g_return_val_if_fail (result != NULL, NULL);
- camel_data_wrapper_set_mime_type (wrapper, mime_type);
+ js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (editor), result, &local_error);
- part = camel_mime_part_new ();
- camel_medium_set_content (CAMEL_MEDIUM (part), wrapper);
- g_object_unref (wrapper);
+ if (local_error) {
+ g_propagate_error (error, local_error);
- 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);
+ if (js_result)
+ webkit_javascript_result_unref (js_result);
- return part;
-}
+ return NULL;
+ }
-static GSList *
-webkit_editor_get_parts_for_inline_images (GVariant *images)
-{
- const gchar *element_src, *name, *id;
- GVariantIter *iter;
- GSList *parts = NULL;
+ if (js_result) {
+ JSCException *exception;
+ JSCValue *value;
- 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;
+ value = webkit_javascript_result_get_js_value (js_result);
+ exception = jsc_context_get_exception (jsc_value_get_context (value));
- part = create_part_for_inline_image_from_element_data (
- element_src, name, id);
- parts = g_slist_prepend (parts, part);
+ 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;
}
- g_variant_iter_free (iter);
- }
- return parts ? g_slist_reverse (parts) : 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);
+ }
-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;
+ images_value = jsc_value_object_get_property (value, "images");
- wk_editor = E_WEBKIT_EDITOR (editor);
- if (!wk_editor->priv->web_extension_proxy)
- return NULL;
+ if (images_value) {
+ if (jsc_value_is_array (images_value)) {
+ GSList *image_parts = NULL;
+ gint length;
- 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");
+ length = e_web_view_jsc_get_object_property_int32 (images_value,
"length", 0);
- if (result) {
- GVariant *images = NULL;
- gchar *value = NULL;
+ 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;
+
+ 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);
+
+ if (src && *src && cid && *cid) {
+ CamelMimePart *part = NULL;
- g_variant_get (result, "(sv)", &value, &images);
- if (inline_images_parts)
- *inline_images_parts = webkit_editor_get_parts_for_inline_images (images);
+ if (g_ascii_strncasecmp (src, "cid:", 4) == 0)
+ part =
e_content_editor_emit_ref_mime_part (editor, src);
- if (images)
- g_variant_unref (images);
+ if (!part) {
+ part =
e_content_editor_util_create_data_mimepart (src, cid, TRUE, NULL, NULL,
+ E_WEBKIT_EDITOR
(editor)->priv->cancellable);
+ }
- g_variant_unref (result);
+ if (part)
+ image_parts = g_slist_prepend
(image_parts, part);
+ }
+
+ g_free (src);
+ g_free (cid);
+ }
+
+ g_clear_object (&item_value);
+ }
+
+ if (image_parts)
+ e_content_editor_util_take_content_data_images (content_hash,
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 ();
+ }
- return value;
+ webkit_javascript_result_unref (js_result);
}
- return NULL;
+ return content_hash;
}
static gboolean
@@ -2070,9 +2214,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 +2239,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 +2265,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;
- }
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (editor));
+ g_return_if_fail (emoticon != NULL);
- 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);
-}
+ settings = e_util_ref_settings ("org.gnome.evolution.mail");
-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);
-
- stream = camel_stream_mem_new ();
- camel_data_wrapper_decode_to_stream_sync (dw, stream, NULL, NULL);
- camel_stream_close (stream, NULL, NULL);
-
- 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 +2302,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 +2315,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 +2338,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 +2349,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 +2376,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
@@ -2383,9 +2450,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 +2505,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 +2536,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;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
+ JSCValue *jsc_value;
+ gchar *res = NULL, *tmp = NULL;
- 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 +2579,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 +2592,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 +2651,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 +2682,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 +2700,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);
@@ -2859,6 +2798,11 @@ webkit_editor_replace_all (EContentEditor *editor,
webkit_web_view_execute_editing_command (WEBKIT_WEB_VIEW (wk_editor),
"MoveToBeginningOfDocumentAndModifySelection");
+ 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 +2811,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,165 +2824,165 @@ 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);
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorDialogDeleteCellContents");
-}
+ if (g_strcmp0 (name, E_CONTENT_EDITOR_DIALOG_SPELLCHECK) == 0) {
+ gchar **strv;
-static void
-webkit_editor_delete_column (EContentEditor *editor)
-{
- EWebKitEditor *wk_editor;
+ strv = e_spell_checker_list_active_languages (wk_editor->priv->spell_checker, NULL);
- wk_editor = E_WEBKIT_EDITOR (editor);
+ 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, "EEditorDialogDeleteColumn");
+ g_slice_free1 (len, langs);
+ g_strfreev (strv);
+ }
+ }
}
static void
-webkit_editor_delete_row (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, "EEditorDialogDeleteRow");
+ 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_table (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);
-
- 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.DialogUtilsTableDeleteCellContent();");
}
static void
-webkit_editor_insert_column_after (EContentEditor *editor)
+webkit_editor_delete_column (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, "EEditorDialogInsertColumnAfter");
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.DialogUtilsTableDeleteColumn();");
}
static void
-webkit_editor_insert_column_before (EContentEditor *editor)
+webkit_editor_delete_row (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.DialogUtilsTableDeleteRow();");
}
-
static void
-webkit_editor_insert_row_above (EContentEditor *editor)
+webkit_editor_delete_table (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, "EEditorDialogInsertRowAbove");
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.DialogUtilsTableDelete();");
}
static void
-webkit_editor_insert_row_below (EContentEditor *editor)
+webkit_editor_insert_column_after (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);", "column", +1);
}
-static gboolean
-webkit_editor_on_h_rule_dialog_open (EContentEditor *editor)
+static void
+webkit_editor_insert_column_before (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- gboolean value = FALSE;
- 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 FALSE;
- }
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- 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);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.DialogUtilsTableInsert(%s, %d);", "column", -1);
+}
- if (result) {
- g_variant_get (result, "(b)", &value);
- g_variant_unref (result);
- }
+static void
+webkit_editor_insert_row_above (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- return value;
+ 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_on_h_rule_dialog_close (EContentEditor *editor)
+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, "EEditorHRuleDialogOnClose");
+ 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_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);
+ webkit_editor_dialog_utils_set_attribute (E_WEBKIT_EDITOR (editor), NULL, "align", value);
}
static gchar *
webkit_editor_h_rule_get_align (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- gchar *value = NULL;
- GVariant *result;
+ gchar *value;
- wk_editor = E_WEBKIT_EDITOR (editor);
+ value = webkit_editor_dialog_utils_get_attribute (E_WEBKIT_EDITOR (editor), NULL, "align");
- 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);
+ if (!value || !*value) {
+ g_free (value);
+ value = g_strdup ("center");
}
return value;
@@ -3046,42 +2992,18 @@ 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);
+ webkit_editor_dialog_utils_set_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "size", value);
}
static gint
webkit_editor_h_rule_get_size (EContentEditor *editor)
{
- EWebKitEditor *wk_editor;
- gint size = 0;
- GVariant *result;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
+ gint size;
- 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);
+ size = webkit_editor_dialog_utils_get_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "size", 2);
- if (size == 0)
- size = 2;
-
- g_variant_unref (result);
- }
+ if (!size)
+ size = 2;
return size;
}
@@ -3091,45 +3013,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 +3036,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;
+ return webkit_editor_dialog_utils_has_attribute (E_WEBKIT_EDITOR (editor), "noshade");
+}
- 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 void
+webkit_editor_insert_image (EContentEditor *editor,
+ const gchar *image_uri)
+{
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
+ gint width = -1, height = -1;
- 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);
+ g_return_if_fail (image_uri != NULL);
- if (result) {
- g_variant_get (result, "(b)", &no_shade);
- g_variant_unref (result);
- }
+ if (g_ascii_strncasecmp (image_uri, "file://", 7) == 0) {
+ gchar *filename;
- return no_shade;
-}
+ filename = g_filename_from_uri (image_uri, NULL, NULL);
-static void
-webkit_editor_on_image_dialog_open (EContentEditor *editor)
-{
- EWebKitEditor *wk_editor;
+ if (filename) {
+ if (!gdk_pixbuf_get_file_info (filename, &width, &height)) {
+ width = -1;
+ height = -1;
+ }
- wk_editor = E_WEBKIT_EDITOR (editor);
+ g_free (filename);
+ }
+ }
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorImageDialogMarkImage");
-}
-
-static void
-webkit_editor_on_image_dialog_close (EContentEditor *editor)
-{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- webkit_editor_call_simple_extension_function (
- wk_editor, "EEditorImageDialogSaveHistoryOnExit");
-}
-
-static void
-webkit_editor_insert_image (EContentEditor *editor,
- const gchar *image_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;
- }
-
- 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 +3079,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;
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (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,
- "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;
-
- 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);
+ JSCValue *result;
- 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 +3290,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 +3309,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 +3326,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 +3352,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 +3364,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,34 +3374,28 @@ webkit_editor_get_font_name (EWebKitEditor *wk_editor)
{
g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), NULL);
- return wk_editor->priv->font_name;
+ if (!wk_editor->priv->html_mode)
+ return NULL;
+
+ return wk_editor->priv->font_name;
}
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));
+ webkit_editor_utils_color_to_string (color, sizeof (color), value);
- if (wk_editor->priv->font_color)
- gdk_rgba_free (wk_editor->priv->font_color);
-
- 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 +3403,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 +3413,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 +3440,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 +3501,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 +3515,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 +3529,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;
+ gchar *nowrap;
- 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,
- "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 +3553,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;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- *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;
+ return webkit_editor_dialog_utils_get_attribute_with_unit (E_WEBKIT_EDITOR (editor), NULL, "width",
0, unit);
}
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;
+ return webkit_editor_dialog_utils_get_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "rowspan", 0);
}
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;
+ 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 +3608,10 @@ webkit_editor_cell_set_row_span (EContentEditor *editor,
gint 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;
- }
+ gchar str_value[64];
- 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 +3619,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,198 +3631,66 @@ webkit_editor_cell_set_width (EContentEditor *editor,
EContentEditorUnit unit,
EContentEditorScope scope)
{
- EWebKitEditor *wk_editor;
- gchar *width;
+ gchar str_value[64];
- 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" : "%");
-
- 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
webkit_editor_cell_set_background_color (EContentEditor *editor,
const GdkRGBA *value,
EContentEditorScope scope)
{
- 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;
- }
+ gchar str_value[64];
- 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;
+ EWebKitEditor *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,
- "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 +3698,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;
-}
-
-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);
-}
-
-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;
-}
-
-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);
-}
-
-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;
-}
-
-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;
-}
-
-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);
+ return webkit_editor_dialog_utils_get_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "cellpadding",
0);
}
-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);
- }
+static void
+webkit_editor_table_set_spacing (EContentEditor *editor,
+ gint value)
+{
+ webkit_editor_dialog_utils_set_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "cellspacing", value);
+}
- return another_word;
+static gint
+webkit_editor_table_get_spacing (EContentEditor *editor)
+{
+ return webkit_editor_dialog_utils_get_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "cellspacing",
0);
}
-static gchar *
-webkit_editor_spell_check_next_word (EContentEditor *editor,
- const gchar *word)
+static void
+webkit_editor_table_set_border (EContentEditor *editor,
+ gint value)
{
- return move_to_another_word (editor, word, "EEditorSpellCheckDialogNext");
+ webkit_editor_dialog_utils_set_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "border", value);
}
-static gchar *
-webkit_editor_spell_check_prev_word (EContentEditor *editor,
- const gchar *word)
+static gint
+webkit_editor_table_get_border (EContentEditor *editor)
{
- return move_to_another_word (editor, word, "EEditorSpellCheckDialogPrev");
+ return webkit_editor_dialog_utils_get_attribute_int (E_WEBKIT_EDITOR (editor), NULL, "border", 0);
}
static void
-webkit_editor_on_replace_dialog_open (EContentEditor *editor)
+webkit_editor_table_get_background_color (EContentEditor *editor,
+ GdkRGBA *color)
{
+ webkit_editor_dialog_utils_get_attribute_color (E_WEBKIT_EDITOR (editor), NULL, "bgcolor", color);
}
static void
-webkit_editor_on_replace_dialog_close (EContentEditor *editor)
+webkit_editor_table_set_background_color (EContentEditor *editor,
+ const GdkRGBA *value)
{
- webkit_editor_finish_search (E_WEBKIT_EDITOR (editor));
+ webkit_editor_dialog_utils_set_attribute_color (E_WEBKIT_EDITOR (editor), NULL, "bgcolor", value);
}
-static void
-webkit_editor_on_find_dialog_open (EContentEditor *editor)
+static gchar *
+webkit_editor_table_get_background_image_uri (EContentEditor *editor)
{
+ return webkit_editor_dialog_utils_get_attribute (E_WEBKIT_EDITOR (editor), NULL, "background");
}
static void
-webkit_editor_on_find_dialog_close (EContentEditor *editor)
+webkit_editor_table_set_background_image_uri (EContentEditor *editor,
+ const gchar *uri)
{
- webkit_editor_finish_search (E_WEBKIT_EDITOR (editor));
+ webkit_editor_replace_image_src (E_WEBKIT_EDITOR (editor), NULL, uri);
}
-static GDBusProxy *
-webkit_editor_get_web_extension (EWebKitEditor *wk_editor)
+static gchar *
+webkit_editor_spell_check_next_word (EContentEditor *editor,
+ const gchar *word)
{
- g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), NULL);
+ 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);
+}
- return wk_editor->priv->web_extension_proxy;
+static gchar *
+webkit_editor_spell_check_prev_word (EContentEditor *editor,
+ const gchar *word)
+{
+ 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 +3866,106 @@ 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
e_webkit_editor_initialize_web_extensions_cb (WebKitWebContext *web_context,
gpointer user_data)
@@ -5218,13 +3973,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 +3986,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 +4001,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 +4027,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 +4048,34 @@ 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_object_unref (settings);
+
+ webkit_web_view_load_html (WEBKIT_WEB_VIEW (wk_editor), "", "evo-file:///");
}
static GObjectConstructParam*
@@ -5364,11 +4170,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 +4186,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 +4209,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 +4223,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 +4256,30 @@ 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_ALIGNMENT:
webkit_editor_set_alignment (
E_WEBKIT_EDITOR (object),
@@ -5473,9 +4295,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 +4326,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 +4399,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 +4453,26 @@ 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_ALIGNMENT:
g_value_set_enum (
value,
@@ -5677,7 +4499,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 +4523,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 +4535,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 +4543,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 +4551,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 +4559,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 +4567,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:
@@ -5862,92 +4676,78 @@ webkit_editor_style_settings_changed_cb (GSettings *settings,
}
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;
+ /* 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)) {
- if (wk_editor->priv->copy_paste_clipboard_in_view ==
wk_editor->priv->pasting_from_itself_extension_value)
- return;
+ PostReloadOperation *op;
- 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);
+ op = g_queue_pop_head (wk_editor->priv->post_reload_operations);
- wk_editor->priv->copy_cut_actions_triggered = FALSE;
+ op->func (wk_editor, op->data, op->flags);
- wk_editor->priv->pasting_from_itself_extension_value = wk_editor->priv->copy_paste_clipboard_in_view;
-}
+ if (op->data_free_func)
+ op->data_free_func (op->data);
+ g_free (op);
-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;
+ 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 (!event->owner || !wk_editor->priv->can_copy)
- wk_editor->priv->copy_paste_clipboard_in_view = FALSE;
+ g_queue_clear (wk_editor->priv->post_reload_operations);
+ }
- if (wk_editor->priv->copy_paste_clipboard_in_view ==
wk_editor->priv->pasting_from_itself_extension_value)
- return;
+ webkit_editor_style_updated_cb (wk_editor);
- 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);
+ if (wk_editor->priv->initialized_callback) {
+ EContentEditorInitializedCallback initialized_callback;
+ gpointer initialized_user_data;
- wk_editor->priv->pasting_from_itself_extension_value = wk_editor->priv->copy_paste_clipboard_in_view;
-}
+ initialized_callback = wk_editor->priv->initialized_callback;
+ initialized_user_data = wk_editor->priv->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;
+ 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 +4775,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 +4844,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 +4864,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 +4893,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 +4957,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 +5127,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 +5264,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 +5297,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 +5320,56 @@ 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));
}
static void
@@ -6551,14 +5387,11 @@ 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;
g_signal_connect (
wk_editor, "load-changed",
@@ -6604,14 +5437,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 +5472,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 +5484,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 +5493,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 +5505,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 +5517,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 +5530,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 +5538,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 +5560,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 +5570,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 +5610,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..2def8ee041 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,2573 +18,407 @@
#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)
-{
- GSList *link;
-
- g_return_val_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension), NULL);
+G_DEFINE_TYPE_WITH_PRIVATE (EEditorWebExtension, e_editor_web_extension, G_TYPE_OBJECT)
- for (link = extension->priv->pages; link; link = g_slist_next (link)) {
- EEditorPage *page = link->data;
+static void
+e_editor_web_extension_dispose (GObject *object)
+{
+ EEditorWebExtension *extension = E_EDITOR_WEB_EXTENSION (object);
- if (page && e_editor_page_get_page_id (page) == page_id)
- return page;
- }
+ g_clear_object (&extension->priv->wk_extension);
+ g_clear_object (&extension->priv->spell_checker);
- return NULL;
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_editor_web_extension_parent_class)->dispose (object);
}
-static EEditorPage *
-get_editor_page_or_return_dbus_error (GDBusMethodInvocation *invocation,
- EEditorWebExtension *extension,
- guint64 page_id)
+static void
+e_editor_web_extension_class_init (EEditorWebExtensionClass *class)
{
- WebKitWebPage *web_page;
- EEditorPage *editor_page;
-
- g_return_val_if_fail (E_IS_EDITOR_WEB_EXTENSION (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);
-
- return NULL;
- }
-
- 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);
- }
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
- return editor_page;
+ object_class->dispose = e_editor_web_extension_dispose;
}
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)
+e_editor_web_extension_init (EEditorWebExtension *extension)
{
- 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;
-
- builder = g_variant_builder_new (G_VARIANT_TYPE ("at"));
-
- for (link = extension->priv->pages; link; link = g_slist_next (link)) {
- EEditorPage *page = link->data;
-
- 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);
- }
-
- 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_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);
+ extension->priv = e_editor_web_extension_get_instance_private (extension);
+ extension->priv->spell_checker = NULL;
+}
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMTurnSpellCheckOff") == 0) {
- g_variant_get (parameters, "(t)", &page_id);
+static gpointer
+e_editor_web_extension_create_instance (gpointer data)
+{
+ return g_object_new (E_TYPE_EDITOR_WEB_EXTENSION, NULL);
+}
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+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));
+}
- 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;
+static gboolean
+web_page_send_request_cb (WebKitWebPage *web_page,
+ WebKitURIRequest *request,
+ WebKitURIResponse *redirected_response,
+ EEditorWebExtension *extension)
+{
+ const gchar *request_uri;
+ const gchar *page_uri;
- g_variant_get (parameters, "(t&sb)", &page_id, &text, &is_html);
+ request_uri = webkit_uri_request_get_uri (request);
+ page_uri = webkit_web_page_get_uri (web_page);
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ /* Always load the main resource. */
+ if (g_strcmp0 (request_uri, page_uri) == 0)
+ return FALSE;
- 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;
+ if (g_str_has_prefix (request_uri, "http:") ||
+ g_str_has_prefix (request_uri, "https:")) {
+ gchar *new_uri;
- g_variant_get (parameters, "(t&sb)", &page_id, &text, &is_html);
+ new_uri = g_strconcat ("evo-", request_uri, NULL);
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ webkit_uri_request_set_uri (request, new_uri);
- 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 (new_uri);
+ }
- g_variant_get (parameters, "(t&s)", &page_id, &style_sheet_content);
+ return FALSE;
+}
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+static gboolean
+use_sources_js_file (void)
+{
+ static gint res = -1;
- 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);
+ if (res == -1)
+ res = g_strcmp0 (g_getenv ("E_HTML_EDITOR_TEST_SOURCES"), "1") == 0 ? 1 : 0;
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ return res;
+}
- 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
+load_javascript_file (JSCContext *jsc_context,
+ const gchar *js_filename)
+{
+ JSCValue *result;
+ JSCException *exception;
+ gchar *content, *filename = NULL, *resource_uri;
+ gsize length = 0;
+ GError *error = NULL;
- 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 (jsc_context != NULL);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "SetEditorHTMLMode") == 0) {
- gboolean html_mode = FALSE;
- gboolean convert = FALSE;
+ if (use_sources_js_file ()) {
+ filename = g_build_filename (EVOLUTION_SOURCE_WEBKITDATADIR, js_filename, NULL);
- 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;
+ 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);
- 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);
+ g_clear_pointer (&filename, g_free);
}
+ }
- 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);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_replace_image_src (editor_page, selector, uri);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMInsertSmiley") == 0) {
- const gchar *smiley_name;
-
- g_variant_get (parameters, "(t&s)", &page_id, &smiley_name);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- 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;
-
- g_variant_get (parameters, "(tiib)", &page_id, &x, &y, &cancel_if_not_collapsed);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- 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_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMSelectionIndent") == 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_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);
-
- 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, "DOMSelectionRestore") == 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, "DOMSelectionInsertImage") == 0) {
- const gchar *uri;
-
- g_variant_get (parameters, "(t&s)", &page_id, &uri);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- e_editor_dom_insert_image (editor_page, uri);
-
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMInsertReplaceAllHistoryEvent") == 0) {
- const gchar *replacement, *search_text;
-
- g_variant_get (parameters, "(t&s&s)", &page_id, &search_text, &replacement);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- 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;
-
- 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_selection_replace (editor_page, replacement);
- g_dbus_method_invocation_return_value (invocation, NULL);
- } else if (g_strcmp0 (method_name, "DOMSelectionSetAlignment") == 0) {
- EContentEditorAlignment alignment;
-
- g_variant_get (parameters, "(ti)", &page_id, &alignment);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- 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;
-
- g_variant_get (parameters, "(tb)", &page_id, &bold);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
-
- 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;
-
- g_variant_get (parameters, "(ti)", &page_id, &block_format);
-
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ if (!filename)
+ filename = g_build_filename (EVOLUTION_WEBKITDATADIR, js_filename, NULL);
- 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;
+ if (!g_file_get_contents (filename, &content, &length, &error)) {
+ g_warning ("Failed to load '%s': %s", filename, error ? error->message : "Unknown error");
- g_variant_get (parameters, "(t&s)", &page_id, &color);
+ g_clear_error (&error);
+ g_free (filename);
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ return;
+ }
- 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;
+ resource_uri = g_strconcat ("resource:///", js_filename, NULL);
- g_variant_get (parameters, "(ti)", &page_id, &font_size);
+ result = jsc_context_evaluate_with_source_uri (jsc_context, content, length, resource_uri, 1);
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ g_free (resource_uri);
- 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;
+ exception = jsc_context_get_exception (jsc_context);
- g_variant_get (parameters, "(tb)", &page_id, &italic);
+ 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));
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ jsc_context_clear_exception (jsc_context);
+ }
- 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;
+ g_clear_object (&result);
+ g_free (filename);
+ g_free (content);
+}
- g_variant_get (parameters, "(tb)", &page_id, &monospaced);
+/* Returns 'null', when no match for the 'pattern' in 'text' found, otherwise
+ returns an 'object { start : nnn, end : nnn };' with the first longest pattern match. */
+static JSCValue *
+evo_editor_jsc_find_pattern (const gchar *text,
+ const gchar *pattern,
+ JSCContext *jsc_context)
+{
+ JSCValue *object = NULL;
+ GRegex *regex;
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ if (!text || !*text || !pattern || !*pattern)
+ return jsc_value_new_null (jsc_context);
- 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;
+ regex = g_regex_new (pattern, 0, 0, NULL);
+ if (regex) {
+ GMatchInfo *match_info = NULL;
+ gint start = -1, end = -1;
- g_variant_get (parameters, "(tb)", &page_id, &strikethrough);
+ 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) {
+ JSCValue *number;
- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
- if (!editor_page)
- goto error;
+ object = jsc_value_new_object (jsc_context, NULL, NULL);
- 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;
+ number = jsc_value_new_number (jsc_context, start);
+ jsc_value_object_set_property (object, "start", number);
+ g_clear_object (&number);
- g_variant_get (parameters, "(tb)", &page_id, &subscript);
+ number = jsc_value_new_number (jsc_context, end);
+ jsc_value_object_set_property (object, "end", number);
+ g_clear_object (&number);
+ }
- 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);
+ if (match_info)
+ g_match_info_free (match_info);
+ g_regex_unref (regex);
}
- return;
-
- error:
- g_warning ("Cannot obtain WebKitWebPage for %" G_GUINT64_FORMAT, page_id);
+ return object ? object : jsc_value_new_null (jsc_context);
}
-static void
-web_page_gone_cb (gpointer user_data,
- GObject *gone_web_page)
+/* 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)
{
- EEditorWebExtension *extension = user_data;
- GSList *link;
+ JSCValue *object = NULL;
- g_return_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension));
+ if (iconName && *iconName) {
+ const EEmoticon *emoticon;
- 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);
+ emoticon = e_emoticon_chooser_lookup_emoticon (iconName);
- if ((gpointer) web_page == gone_web_page) {
- extension->priv->pages = g_slist_remove (extension->priv->pages, editor_page);
- g_object_unref (editor_page);
- break;
- }
- }
-}
+ if (emoticon) {
+ JSCValue *value;
-static const GDBusInterfaceVTable interface_vtable = {
- handle_method_call,
- NULL,
- NULL
-};
+ object = jsc_value_new_object (jsc_context, NULL, NULL);
-static void
-e_editor_web_extension_dispose (GObject *object)
-{
- EEditorWebExtension *extension = E_EDITOR_WEB_EXTENSION (object);
+ 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;
- if (extension->priv->dbus_connection) {
- g_dbus_connection_unregister_object (
- extension->priv->dbus_connection,
- extension->priv->registration_id);
- extension->priv->registration_id = 0;
+ value = jsc_value_new_string (jsc_context, emoticon->text_face);
+ jsc_value_object_set_property (object, "text", value);
+ g_clear_object (&value);
- g_clear_object (&extension->priv->dbus_connection);
- }
+ image_uri = e_emoticon_get_uri ((EEmoticon *) emoticon);
- g_slist_free_full (extension->priv->pages, g_object_unref);
- extension->priv->pages = NULL;
+ if (image_uri) {
+ value = jsc_value_new_string (jsc_context, image_uri);
+ jsc_value_object_set_property (object, "imageUri", value);
+ g_clear_object (&value);
- g_clear_object (&extension->priv->wk_extension);
+ value = jsc_value_new_number (jsc_context, 16);
+ jsc_value_object_set_property (object, "width", value);
+ g_clear_object (&value);
- /* Chain up to parent's dispose() method. */
- G_OBJECT_CLASS (e_editor_web_extension_parent_class)->dispose (object);
-}
+ value = jsc_value_new_number (jsc_context, 16);
+ jsc_value_object_set_property (object, "height", value);
+ g_clear_object (&value);
-static void
-e_editor_web_extension_class_init (EEditorWebExtensionClass *class)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (class);
-
- object_class->dispose = e_editor_web_extension_dispose;
+ g_free (image_uri);
+ }
+ }
+ }
+ }
- g_type_class_add_private (object_class, sizeof(EEditorWebExtensionPrivate));
+ return object ? object : jsc_value_new_null (jsc_context);
}
static void
-e_editor_web_extension_init (EEditorWebExtension *extension)
+evo_editor_jsc_set_spell_check_languages (const gchar *langs,
+ GWeakRef *wkrf_extension)
{
- extension->priv = E_EDITOR_WEB_EXTENSION_GET_PRIVATE (extension);
-}
+ EEditorWebExtension *extension;
+ gchar **strv;
-static gpointer
-e_editor_web_extension_create_instance (gpointer data)
-{
- return g_object_new (E_TYPE_EDITOR_WEB_EXTENSION, NULL);
-}
+ g_return_if_fail (wkrf_extension != NULL);
-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));
-}
-
-static gboolean
-image_exists_in_cache (const gchar *image_uri)
-{
- gchar *filename;
- gchar *hash;
- gboolean exists = FALSE;
-
- if (!emd_global_http_cache)
- return FALSE;
+ extension = g_weak_ref_get (wkrf_extension);
- hash = e_http_request_util_compute_uri_checksum (image_uri);
- filename = camel_data_cache_get_filename (
- emd_global_http_cache, "http", hash);
+ if (!extension)
+ return;
- if (filename != NULL) {
- struct stat st;
+ if (langs && *langs)
+ strv = g_strsplit (langs, "|", -1);
+ else
+ strv = NULL;
- 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);
- }
+ if (!extension->priv->spell_checker)
+ extension->priv->spell_checker = e_spell_checker_new ();
- g_free (hash);
+ e_spell_checker_set_active_languages (extension->priv->spell_checker, (const gchar * const *) strv);
- return exists;
+ g_object_unref (extension);
+ g_strfreev (strv);
}
+/* Returns whether the 'word' is a properly spelled word. It checks
+ with languages previously set by EvoEditor.SetSpellCheckLanguages(). */
static gboolean
-redirect_http_uri (EEditorWebExtension *extension,
- WebKitWebPage *web_page,
- WebKitURIRequest *request)
+evo_editor_jsc_spell_check_word (const gchar *word,
+ GWeakRef *wkrf_extension)
{
- 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;
- }
+ EEditorWebExtension *extension;
+ gboolean is_correct;
- new_uri = g_strconcat ("evo-", uri, NULL);
- soup_uri = soup_uri_new (new_uri);
- g_free (new_uri);
+ g_return_val_if_fail (wkrf_extension != NULL, FALSE);
- new_uri = soup_uri_to_string (soup_uri, FALSE);
- webkit_uri_request_set_uri (request, new_uri);
- soup_uri_free (soup_uri);
+ extension = g_weak_ref_get (wkrf_extension);
- g_free (new_uri);
+ if (!extension)
+ return TRUE;
- return TRUE;
-}
+ /* It should be created as part of EvoEditor.SetSpellCheckLanguages(). */
+ g_warn_if_fail (extension->priv->spell_checker != NULL);
-static gboolean
-web_page_send_request_cb (WebKitWebPage *web_page,
- WebKitURIRequest *request,
- WebKitURIResponse *redirected_response,
- EEditorWebExtension *extension)
-{
- const char *request_uri;
- const char *page_uri;
- gboolean uri_is_http;
+ if (!extension->priv->spell_checker)
+ extension->priv->spell_checker = e_spell_checker_new ();
- request_uri = webkit_uri_request_get_uri (request);
- page_uri = webkit_web_page_get_uri (web_page);
+ is_correct = e_spell_checker_check_word (extension->priv->spell_checker, word, -1);
- /* Always load the main resource. */
- 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:");
+ g_object_unref (extension);
- if (uri_is_http &&
- !redirect_http_uri (extension, web_page, request))
- return TRUE;
-
- return FALSE;
+ return is_correct;
}
static void
-web_page_document_loaded_cb (WebKitWebPage *web_page,
- gpointer user_data)
+window_object_cleared_cb (WebKitScriptWorld *world,
+ WebKitWebPage *page,
+ WebKitFrame *frame,
+ gpointer user_data)
{
- WebKitDOMDocument *document;
- WebKitDOMRange *range = NULL;
- WebKitDOMDOMWindow *dom_window;
- WebKitDOMDOMSelection *dom_selection;
+ EEditorWebExtension *extension = user_data;
+ JSCContext *jsc_context;
+ JSCValue *jsc_editor;
- g_return_if_fail (WEBKIT_IS_WEB_PAGE (web_page));
+ g_return_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension));
- document = webkit_web_page_get_dom_document (web_page);
- if (!document)
+ /* Load the javascript files only to the main frame, not to the subframes */
+ if (!webkit_frame_is_main_frame (frame))
return;
- dom_window = webkit_dom_document_get_default_view (document);
- dom_selection = webkit_dom_dom_window_get_selection (dom_window);
-
- /* 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);
- }
+ jsc_context = webkit_frame_get_js_context (frame);
- g_clear_object (&range);
- g_clear_object (&dom_selection);
- g_clear_object (&dom_window);
-}
+ /* 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
-web_page_notify_uri_cb (GObject *object,
- GParamSpec *param,
- gpointer user_data)
-{
- EEditorWebExtension *extension = user_data;
- WebKitWebPage *web_page;
- GSList *link;
- const gchar *uri;
+ jsc_editor = jsc_context_get_value (jsc_context, "EvoEditor");
- g_return_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension));
+ if (jsc_editor) {
+ JSCValue *jsc_function;
+ const gchar *func_name;
- web_page = WEBKIT_WEB_PAGE (object);
- uri = webkit_web_page_get_uri (web_page);
+ /* EvoEditor.findPattern(text, pattern) */
+ func_name = "findPattern";
+ jsc_function = jsc_value_new_function (jsc_context, func_name,
+ G_CALLBACK (evo_editor_jsc_find_pattern), g_object_ref (jsc_context), g_object_unref,
+ JSC_TYPE_VALUE, 2, G_TYPE_STRING, G_TYPE_STRING);
- for (link = extension->priv->pages; link; link = g_slist_next (link)) {
- EEditorPage *page = link->data;
+ jsc_value_object_set_property (jsc_editor, func_name, jsc_function);
- if (page && e_editor_page_get_web_page (page) == web_page) {
- gint new_stamp = 0;
+ g_clear_object (&jsc_function);
- if (uri && *uri) {
- SoupURI *suri;
+ /* 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);
- suri = soup_uri_new (uri);
- if (suri) {
- if (soup_uri_get_query (suri)) {
- GHashTable *form;
+ jsc_value_object_set_property (jsc_editor, func_name, jsc_function);
- form = soup_form_decode (soup_uri_get_query (suri));
- if (form) {
- const gchar *evo_stamp;
+ g_clear_object (&jsc_function);
- evo_stamp = g_hash_table_lookup (form, "evo-stamp");
- if (evo_stamp)
- new_stamp = (gint) g_ascii_strtoll
(evo_stamp, NULL, 10);
+ /* 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);
- g_hash_table_destroy (form);
- }
- }
+ jsc_value_object_set_property (jsc_editor, func_name, jsc_function);
- soup_uri_free (suri);
- }
- }
+ g_clear_object (&jsc_function);
- e_editor_page_set_stamp (page, new_stamp);
+ /* 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);
- if (extension->priv->dbus_connection) {
- GError *error = NULL;
+ jsc_value_object_set_property (jsc_editor, func_name, jsc_function);
- 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);
+ g_clear_object (&jsc_function);
+ g_clear_object (&jsc_editor);
+ }
- if (error) {
- g_warning ("Error emitting signal ExtensionHandlesPage: %s",
error->message);
- g_error_free (error);
- }
- }
+ g_clear_object (&jsc_context);
+}
- return;
- }
- }
+static void
+web_page_document_loaded_cb (WebKitWebPage *web_page,
+ gpointer user_data)
+{
+ 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 +426,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 cc77b75fc1..cdc2671a52 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,7 +198,7 @@ enable_composer_idle (gpointer user_data)
struct ExternalEditorData {
EMsgComposer *composer;
gchar *content;
- gint cursor_position, cursor_offset;
+ guint cursor_position, cursor_offset;
};
/* needed because the new thread needs to call g_idle_add () */
@@ -412,7 +409,39 @@ finished:
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_get_content_data (content_hash,
E_CONTENT_EDITOR_GET_TO_SEND_PLAIN) : 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;
@@ -437,16 +466,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 77db1f54ed..ff3ea426f1 100644
--- a/src/web-extensions/e-web-extension.c
+++ b/src/web-extensions/e-web-extension.c
@@ -136,19 +136,41 @@ web_page_created_cb (WebKitWebExtension *wk_extension,
extension, 0);
}
+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]