[evolution/wip/mcrha/webkit-jsc-api] Implement link dialog/editing
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution/wip/mcrha/webkit-jsc-api] Implement link dialog/editing
- Date: Fri, 6 Dec 2019 14:32:09 +0000 (UTC)
commit 92a0a9c247ffa8a02a605fafd63908225950a0f4
Author: Milan Crha <mcrha redhat com>
Date: Fri Dec 6 15:33:08 2019 +0100
Implement link dialog/editing
data/webkit/e-editor.js | 292 +++++++++++++++++++++++++---
data/webkit/e-undo-redo.js | 14 +-
src/e-util/e-content-editor.c | 20 +-
src/e-util/e-content-editor.h | 6 +-
src/e-util/e-html-editor.c | 79 ++++----
src/e-util/e-html-editor.h | 3 +-
src/e-util/test-html-editor-units.c | 16 +-
src/modules/webkit-editor/e-webkit-editor.c | 265 ++++++++++++++++++-------
8 files changed, 528 insertions(+), 167 deletions(-)
---
diff --git a/data/webkit/e-editor.js b/data/webkit/e-editor.js
index 3e9c567864..693adb0927 100644
--- a/data/webkit/e-editor.js
+++ b/data/webkit/e-editor.js
@@ -29,34 +29,43 @@ var EvoEditor = {
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])?)*+",
- 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_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_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,
/* Flags for ClaimAffectedContent() */
CLAIM_CONTENT_FLAG_NONE : 0,
@@ -78,6 +87,7 @@ var EvoEditor = {
mode : 1, // one of the MODE constants
storedSelection : null,
+ propertiesSelection : null, // dedicated to Properties dialogs
inheritThemeColors : false,
checkInheritFontsOnChange : false,
forceFormatStateUpdate : false,
@@ -169,7 +179,7 @@ EvoEditor.maybeUpdateFormattingState = function(force)
tmp = computedStyle ? computedStyle.webkitTextDecorationsInEffect : "";
- value = tmp.search("underline") >= 0;
+ value = tmp.search("underline") >= 0 && (!baseElem || baseElem.tagName != "A");
if (force || value != EvoEditor.formattingState.underline) {
EvoEditor.formattingState.underline = value;
changes["underline"] = value;
@@ -264,7 +274,7 @@ EvoEditor.maybeUpdateFormattingState = function(force)
};
for (parent = baseElem; parent && !(parent == document.body) && (
- obj.script == 0 || obj.blockFormat == null || obj.fontSize == null || obj.indented == null
||obj.bgColor == null);
+ obj.script == 0 || obj.blockFormat == null || obj.fontSize == null || obj.indented == null ||
obj.bgColor == null);
parent = parent.parentElement) {
if (obj.script == 0) {
if (parent.tagName == "SUB")
@@ -1548,9 +1558,56 @@ EvoEditor.SetBodyFontName = function(name)
}
}
+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.baseNode ||
+ selection.baseNode.nodeType != selection.baseNode.TEXT_NODE ||
+ selection.baseOffset != selection.baseNode.nodeValue.length ||
+ !selection.baseNode.parentElement ||
+ selection.baseNode.parentElement.tagName != "A")
+ return;
+
+ var node = selection.baseNode;
+
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_EVENT, "insertText", selection.baseNode,
selection.baseNode,
+ 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.initializeContent = function()
{
if (document.body) {
+ // attach on body, thus it runs before EvoUndoRedo.beforeInputCb()
+ document.body.onbeforeinput = EvoEditor.beforeInputCb;
+
if (!document.body.firstChild) {
EvoUndoRedo.Disable();
try {
@@ -2229,6 +2286,191 @@ EvoEditor.AfterInputEvent = function(inputEvent, isWordDelim)
}
}
+EvoEditor.getCaretElement = function(tagName)
+{
+ var node;
+
+ node = document.getSelection().extentNode;
+
+ if (!node)
+ node = document.getSelection().baseNode;
+
+ while (node && node.nodeType != node.ELEMENT_NODE) {
+ 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) {
+ }
+ }
+}
+
+EvoEditor.OnPropertiesOpen = function()
+{
+ EvoEditor.storePropertiesSelection();
+}
+
+EvoEditor.OnPropertiesClose = function()
+{
+ EvoEditor.restorePropertiesSelection();
+}
+
+EvoEditor.GetLinkValues = function()
+{
+ var res = null, anchor = EvoEditor.getCaretElement("A");
+
+ 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.SetLinkValues = function(href, text)
+{
+ // The properties dialog can discard selection, thus restore it before doing changes
+ EvoEditor.restorePropertiesSelection();
+
+ var anchor = EvoEditor.getCaretElement("A");
+
+ 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");
+ }
+ } 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.getCaretElement("A");
+
+ if (anchor) {
+ EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "Unlink", anchor.parentElement,
anchor.parentElement, EvoEditor.CLAIM_CONTENT_FLAG_SAVE_HTML);
+ try {
+ var selectionUpdater = EvoSelection.CreateUpdaterObject(), firstChild;
+
+ firstChild = anchor.firstChild;
+
+ while (anchor.firstChild) {
+ anchor.parentElement.insertBefore(anchor.firstChild, anchor);
+ }
+
+ selectionUpdater.beforeRemove(anchor);
+ anchor.parentElement.removeChild(anchor);
+ selectionUpdater.afterRemove(firstChild);
+
+ selectionUpdater.restore();
+ } finally {
+ EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "Unlink");
+ }
+ }
+}
+
+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.onContextMenu = function(event)
+{
+ var node = event.target;
+
+ if (!node)
+ node = document.getSelection().extentNode;
+ if (!node)
+ node = document.getSelection().baseNode;
+
+ var nodeFlags = EvoEditor.E_CONTENT_EDITOR_NODE_UNKNOWN, hasNode = node, res;
+
+ while (node) {
+ 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_CELL;
+
+ node = node.parentElement;
+ }
+
+ if (!nodeFlags && hasNode)
+ 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() {
diff --git a/data/webkit/e-undo-redo.js b/data/webkit/e-undo-redo.js
index 5155578519..e277e69cb0 100644
--- a/data/webkit/e-undo-redo.js
+++ b/data/webkit/e-undo-redo.js
@@ -327,7 +327,7 @@ var EvoUndoRedo = {
delete all nodes between index >= firstChildIndex && index < children.length - restChildrenCount.
*/
- dropTarget : null, // passed from drop_cb() into before_input_cb()/input_cb() for "insertFromDrop"
event
+ dropTarget : null, // passed from dropCb() into beforeInputCb()/inputCb() for "insertFromDrop" event
disabled : 0,
ongoingRecordings : [] // the recordings can be nested
};
@@ -335,9 +335,9 @@ var EvoUndoRedo = {
EvoUndoRedo.Attach = function()
{
if (document.documentElement) {
- document.documentElement.onbeforeinput = EvoUndoRedo.before_input_cb;
- document.documentElement.oninput = EvoUndoRedo.input_cb;
- document.documentElement.ondrop = EvoUndoRedo.drop_cb;
+ document.documentElement.onbeforeinput = EvoUndoRedo.beforeInputCb;
+ document.documentElement.oninput = EvoUndoRedo.inputCb;
+ document.documentElement.ondrop = EvoUndoRedo.dropCb;
}
}
@@ -376,7 +376,7 @@ EvoUndoRedo.isWordDelimEvent = function(inputEvent)
(inputEvent.data == " " || inputEvent.data == "\t");
}
-EvoUndoRedo.before_input_cb = function(inputEvent)
+EvoUndoRedo.beforeInputCb = function(inputEvent)
{
if (EvoUndoRedo.disabled) {
return;
@@ -450,7 +450,7 @@ EvoUndoRedo.before_input_cb = function(inputEvent)
}
}
-EvoUndoRedo.input_cb = function(inputEvent)
+EvoUndoRedo.inputCb = function(inputEvent)
{
var isWordDelim = EvoUndoRedo.isWordDelimEvent(inputEvent);
@@ -484,7 +484,7 @@ EvoUndoRedo.input_cb = function(inputEvent)
EvoEditor.AfterInputEvent(inputEvent, isWordDelim);
}
-EvoUndoRedo.drop_cb = function(event)
+EvoUndoRedo.dropCb = function(event)
{
EvoUndoRedo.dropTarget = event.toElement;
}
diff --git a/src/e-util/e-content-editor.c b/src/e-util/e-content-editor.c
index db4f5bc617..08706662a9 100644
--- a/src/e-util/e-content-editor.c
+++ b/src/e-util/e-content-editor.c
@@ -548,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);
/**
@@ -4111,18 +4112,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
diff --git a/src/e-util/e-content-editor.h b/src/e-util/e-content-editor.h
index 84892846de..548315ed73 100644
--- a/src/e-util/e-content-editor.h
+++ b/src/e-util/e-content-editor.h
@@ -451,8 +451,9 @@ struct _EContentEditorInterface {
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);
@@ -1099,9 +1100,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);
diff --git a/src/e-util/e-html-editor.c b/src/e-util/e-html-editor.c
index 55e59e7876..e6dff74a41 100644
--- a/src/e-util/e-html-editor.c
+++ b/src/e-util/e-html-editor.c
@@ -240,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;
@@ -248,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;
@@ -256,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);
@@ -295,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",
@@ -329,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);
}
@@ -337,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;
@@ -346,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;
@@ -384,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",
@@ -425,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
@@ -460,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;
@@ -550,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;
@@ -575,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);
@@ -584,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);
@@ -621,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;
@@ -632,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_free (cmd);
}
}
@@ -660,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);
@@ -678,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_new0 (ContextMenuData, 1);
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 *
@@ -1029,9 +1017,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",
diff --git a/src/e-util/e-html-editor.h b/src/e-util/e-html-editor.h
index 121eae7758..db0d9270af 100644
--- a/src/e-util/e-html-editor.h
+++ b/src/e-util/e-html-editor.h
@@ -64,7 +64,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);
diff --git a/src/e-util/test-html-editor-units.c b/src/e-util/test-html-editor-units.c
index f4a55c93d5..905e613ab7 100644
--- a/src/e-util/test-html-editor-units.c
+++ b/src/e-util/test-html-editor-units.c
@@ -3316,7 +3316,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 ();
}
@@ -3331,7 +3331,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 ();
}
@@ -3342,7 +3342,7 @@ test_link_insert_typed (TestFixture *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 "))
+ "www.gnome.org \n"))
g_test_fail ();
}
@@ -3360,7 +3360,7 @@ test_link_insert_typed_change_description (TestFixture *fixture)
"type:GNOME\n"
"seq:n\n",
HTML_PREFIX "<div><a href=\"http://www.gnome.org\">GNOME</a> </div>" HTML_SUFFIX,
- "GNOME "))
+ "GNOME \n"))
g_test_fail ();
}
@@ -3376,7 +3376,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 ();
}
@@ -3388,8 +3388,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=\"http://www.gnome.org\">www.gnome.org/about</a> </div>"
HTML_SUFFIX,
+ "www.gnome.org/about \n"))
g_test_fail ();
}
@@ -3401,7 +3401,7 @@ test_link_insert_typed_remove (TestFixture *fixture)
"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"))
+ "www.gnome.o\n"))
g_test_fail ();
}
diff --git a/src/modules/webkit-editor/e-webkit-editor.c b/src/modules/webkit-editor/e-webkit-editor.c
index 145d582e71..b60a003bdc 100644
--- a/src/modules/webkit-editor/e-webkit-editor.c
+++ b/src/modules/webkit-editor/e-webkit-editor.c
@@ -122,6 +122,10 @@ struct _EWebKitEditorPrivate {
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;
@@ -194,6 +198,145 @@ G_DEFINE_TYPE_WITH_CODE (
E_TYPE_CONTENT_EDITOR,
e_webkit_editor_content_editor_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 gint16
e_webkit_editor_three_state_to_int16 (EThreeState value)
{
@@ -379,6 +522,26 @@ content_changed_cb (WebKitUserContentManager *manager,
webkit_editor_set_changed (wk_editor, TRUE);
}
+static void
+context_menu_requested_cb (WebKitUserContentManager *manager,
+ WebKitJavascriptResult *js_result,
+ gpointer user_data)
+{
+ EWebKitEditor *wk_editor = user_data;
+ JSCValue *jsc_params;
+
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+ g_return_if_fail (js_result != NULL);
+
+ jsc_params = webkit_javascript_result_get_js_value (js_result);
+ g_return_if_fail (jsc_value_is_object (jsc_params));
+
+ g_clear_pointer (&wk_editor->priv->context_menu_caret_word, g_free);
+
+ 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);
+}
+
static gboolean
webkit_editor_update_color_value (JSCValue *jsc_params,
const gchar *param_name,
@@ -2234,27 +2397,12 @@ 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) {
- printf ("EHTMLEditorWebExtension not ready at %s!\n", 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)),
- NULL);
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (editor), NULL);
- if (result) {
- g_variant_get (result, "(s)", &ret_val);
- g_variant_unref (result);
- }
+ wk_editor = E_WEBKIT_EDITOR (editor);
- return ret_val;
+ return NULL;
}
static void
@@ -3621,34 +3769,28 @@ webkit_editor_image_get_height (EContentEditor *editor)
static void
webkit_editor_selection_unlink (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, "EEditorLinkDialogUnlink");
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.Unlink();");
}
static void
webkit_editor_on_link_dialog_open (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, "EEditorLinkDialogOnOpen");
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.OnPropertiesOpen();");
}
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.OnPropertiesClose();");
}
static void
@@ -3656,20 +3798,11 @@ webkit_editor_link_set_values (EContentEditor *editor,
const gchar *href,
const gchar *text)
{
- EWebKitEditor *wk_editor;
-
- wk_editor = E_WEBKIT_EDITOR (editor);
-
- if (!wk_editor->priv->web_extension_proxy) {
- printf ("EHTMLEditorWebExtension not ready at %s!\n", G_STRFUNC);
- return;
- }
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
- e_util_invoke_g_dbus_proxy_call_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorLinkDialogOk",
- g_variant_new ("(tss)", current_page_id (wk_editor), href, text),
- wk_editor->priv->cancellable);
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.SetLinkValues(%s, %s);",
+ href, text);
}
static void
@@ -3678,24 +3811,17 @@ webkit_editor_link_get_values (EContentEditor *editor,
gchar **text)
{
EWebKitEditor *wk_editor;
- GVariant *result;
+ JSCValue *result;
wk_editor = E_WEBKIT_EDITOR (editor);
- if (!wk_editor->priv->web_extension_proxy) {
- printf ("EHTMLEditorWebExtension not ready at %s!\n", G_STRFUNC);
- return;
- }
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- "EEditorLinkDialogShow",
- g_variant_new ("(t)", current_page_id (wk_editor)),
- NULL);
+ result = webkit_editor_call_jsc_sync (wk_editor, "EvoEditor.GetLinkValues();");
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;
@@ -5265,12 +5391,15 @@ webkit_editor_constructed (GObject *object)
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::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, "undoRedoStateChanged");
@@ -5468,6 +5597,7 @@ webkit_editor_finalize (GObject *object)
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);
@@ -6168,18 +6298,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
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]