[evolution/wip/mcrha/webkit-jsc-api] Cover spell checking dialog
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution/wip/mcrha/webkit-jsc-api] Cover spell checking dialog
- Date: Wed, 15 Jan 2020 18:02:01 +0000 (UTC)
commit b93ec2cc89743de7708968b505feb45d6fa93d43
Author: Milan Crha <mcrha redhat com>
Date: Wed Jan 15 19:03:53 2020 +0100
Cover spell checking dialog
data/webkit/e-editor.js | 80 ++++++++++++++++++
src/e-util/e-spell-checker.c | 4 +
src/modules/webkit-editor/e-webkit-editor.c | 84 +++++++++----------
.../webkit-editor/web-extension/CMakeLists.txt | 13 ++-
.../web-extension/e-editor-web-extension.c | 95 ++++++++++++++++++++--
5 files changed, 226 insertions(+), 50 deletions(-)
---
diff --git a/data/webkit/e-editor.js b/data/webkit/e-editor.js
index 78b7353bff..761a0cb557 100644
--- a/data/webkit/e-editor.js
+++ b/data/webkit/e-editor.js
@@ -3336,6 +3336,86 @@ EvoEditor.GetCaretWord = function()
return range.toString();
}
+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.onContextMenu = function(event)
{
var node = event.target;
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/modules/webkit-editor/e-webkit-editor.c b/src/modules/webkit-editor/e-webkit-editor.c
index 46b3439778..9efdb6b8ce 100644
--- a/src/modules/webkit-editor/e-webkit-editor.c
+++ b/src/modules/webkit-editor/e-webkit-editor.c
@@ -3072,6 +3072,43 @@ webkit_editor_on_dialog_open (EContentEditor *editor,
e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
"EvoEditor.OnDialogOpen(%s);", name);
+
+ if (g_strcmp0 (name, E_CONTENT_EDITOR_DIALOG_SPELLCHECK) == 0) {
+ gchar **strv;
+
+ strv = e_spell_checker_list_active_languages (wk_editor->priv->spell_checker, NULL);
+
+ if (strv) {
+ gint ii, len = 0;
+ gchar *langs, *ptr;
+
+ for (ii = 0; strv[ii]; ii++) {
+ len += strlen (strv[ii]) + 1;
+ }
+
+ len++;
+
+ langs = g_slice_alloc0 (len);
+ ptr = langs;
+
+ for (ii = 0; strv[ii]; ii++) {
+ strcpy (ptr, strv[ii]);
+ ptr += strlen (strv[ii]);
+ if (strv[ii + 1]) {
+ *ptr = '|';
+ ptr++;
+ }
+ }
+
+ *ptr = '\0';
+
+ e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+ "EvoEditor.SetSpellCheckLanguages(%s);", langs);
+
+ g_slice_free1 (len, langs);
+ g_strfreev (strv);
+ }
+ }
}
static void
@@ -3960,57 +3997,22 @@ webkit_editor_table_set_background_image_uri (EContentEditor *editor,
webkit_editor_replace_image_src (E_WEBKIT_EDITOR (editor), NULL, uri);
}
-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) {
- printf ("EHTMLEditorWebExtension not ready at %s!\n", G_STRFUNC);
- return NULL;
- }
-
- active_languages = e_spell_checker_list_active_languages (
- wk_editor->priv->spell_checker, NULL);
- if (!active_languages)
- return NULL;
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- wk_editor->priv->web_extension_proxy,
- dom_function,
- g_variant_new (
- "(ts^as)", current_page_id (wk_editor), word ? word : "", active_languages),
- NULL);
-
- g_strfreev (active_languages);
-
- if (result) {
- g_variant_get (result, "(s)", &another_word);
- g_variant_unref (result);
- }
-
- return another_word;
-}
-
static gchar *
webkit_editor_spell_check_next_word (EContentEditor *editor,
const gchar *word)
{
- return move_to_another_word (editor, word, "EEditorSpellCheckDialogNext");
+ return webkit_editor_extract_and_free_jsc_string (
+ webkit_editor_call_jsc_sync (E_WEBKIT_EDITOR (editor),
"EvoEditor.SpellCheckContinue(%x,%x);", word && *word, TRUE),
+ NULL);
}
static gchar *
webkit_editor_spell_check_prev_word (EContentEditor *editor,
const gchar *word)
{
- return move_to_another_word (editor, word, "EEditorSpellCheckDialogPrev");
+ 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
diff --git a/src/modules/webkit-editor/web-extension/CMakeLists.txt
b/src/modules/webkit-editor/web-extension/CMakeLists.txt
index 7852e44834..7ec514acc4 100644
--- a/src/modules/webkit-editor/web-extension/CMakeLists.txt
+++ b/src/modules/webkit-editor/web-extension/CMakeLists.txt
@@ -23,6 +23,7 @@ macro(add_webextension_editor_module _name _sourcesvar _depsvar _defsvar _cflags
endmacro(add_webextension_editor_module)
set(extra_deps
+ evolution-util
evolution-mail
)
set(sources
@@ -35,9 +36,15 @@ set(extra_defines
-DEVOLUTION_SOURCE_WEBKITDATADIR=\"${CMAKE_SOURCE_DIR}/data/webkit\"
)
-set(extra_cflags)
-set(extra_incdirs)
-set(extra_ldflags)
+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.c
b/src/modules/webkit-editor/web-extension/e-editor-web-extension.c
index 497e53ee01..765f8ffb63 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
@@ -20,10 +20,17 @@
#include <webkit2/webkit-web-extension.h>
+#include <libedataserver/libedataserver.h>
+
+#define E_UTIL_INCLUDE_WITHOUT_WEBKIT 1
+#include "e-util/e-util.h"
+#undef E_UTIL_INCLUDE_WITHOUT_WEBKIT
+
#include "e-editor-web-extension.h"
struct _EEditorWebExtensionPrivate {
WebKitWebExtension *wk_extension;
+ ESpellChecker *spell_checker;
};
G_DEFINE_TYPE_WITH_PRIVATE (EEditorWebExtension, e_editor_web_extension, G_TYPE_OBJECT)
@@ -34,6 +41,7 @@ e_editor_web_extension_dispose (GObject *object)
EEditorWebExtension *extension = E_EDITOR_WEB_EXTENSION (object);
g_clear_object (&extension->priv->wk_extension);
+ g_clear_object (&extension->priv->spell_checker);
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_editor_web_extension_parent_class)->dispose (object);
@@ -51,6 +59,7 @@ static void
e_editor_web_extension_init (EEditorWebExtension *extension)
{
extension->priv = e_editor_web_extension_get_instance_private (extension);
+ extension->priv->spell_checker = e_spell_checker_new ();
}
static gpointer
@@ -206,15 +215,66 @@ evo_editor_jsc_find_pattern (const gchar *text,
return object ? object : jsc_value_new_null (jsc_context);
}
+static void
+evo_editor_jsc_set_spell_check_languages (const gchar *langs,
+ GWeakRef *wkrf_extension)
+{
+ EEditorWebExtension *extension;
+ gchar **strv;
+
+ g_return_if_fail (wkrf_extension != NULL);
+
+ extension = g_weak_ref_get (wkrf_extension);
+
+ if (!extension)
+ return;
+
+ if (langs && *langs)
+ strv = g_strsplit (langs, "|", -1);
+ else
+ strv = NULL;
+
+ e_spell_checker_set_active_languages (extension->priv->spell_checker, (const gchar * const *) strv);
+
+ 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
+evo_editor_jsc_spell_check_word (const gchar *word,
+ GWeakRef *wkrf_extension)
+{
+ EEditorWebExtension *extension;
+ gboolean is_correct;
+
+ g_return_val_if_fail (wkrf_extension != NULL, FALSE);
+
+ extension = g_weak_ref_get (wkrf_extension);
+
+ if (!extension)
+ return TRUE;
+
+ is_correct = e_spell_checker_check_word (extension->priv->spell_checker, word, -1);
+
+ g_object_unref (extension);
+
+ return is_correct;
+}
+
static void
window_object_cleared_cb (WebKitScriptWorld *world,
WebKitWebPage *page,
WebKitFrame *frame,
gpointer user_data)
{
+ EEditorWebExtension *extension = user_data;
JSCContext *jsc_context;
JSCValue *jsc_editor;
+ g_return_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension));
+
/* Load the javascript files only to the main frame, not to the subframes */
if (!webkit_frame_is_main_frame (frame))
return;
@@ -231,12 +291,35 @@ window_object_cleared_cb (WebKitScriptWorld *world,
if (jsc_editor) {
JSCValue *jsc_function;
+ const gchar *func_name;
- jsc_function = jsc_value_new_function (jsc_context, "findPattern",
+ /* 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);
- jsc_value_object_set_property (jsc_editor, "findPattern", jsc_function);
+ jsc_value_object_set_property (jsc_editor, func_name, jsc_function);
+
+ g_clear_object (&jsc_function);
+
+ /* 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);
+
+ jsc_value_object_set_property (jsc_editor, func_name, jsc_function);
+
+ g_clear_object (&jsc_function);
+
+ /* 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);
+
+ jsc_value_object_set_property (jsc_editor, func_name, jsc_function);
g_clear_object (&jsc_function);
g_clear_object (&jsc_editor);
@@ -251,7 +334,7 @@ web_page_document_loaded_cb (WebKitWebPage *web_page,
{
g_return_if_fail (WEBKIT_IS_WEB_PAGE (web_page));
- window_object_cleared_cb (NULL, web_page, webkit_web_page_get_main_frame (web_page), NULL);
+ window_object_cleared_cb (NULL, web_page, webkit_web_page_get_main_frame (web_page), user_data);
}
static void
@@ -262,7 +345,7 @@ web_page_created_cb (WebKitWebExtension *wk_extension,
g_return_if_fail (WEBKIT_IS_WEB_PAGE (web_page));
g_return_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension));
- window_object_cleared_cb (NULL, web_page, webkit_web_page_get_main_frame (web_page), NULL);
+ window_object_cleared_cb (NULL, web_page, webkit_web_page_get_main_frame (web_page), extension);
g_signal_connect (
web_page, "send-request",
@@ -270,7 +353,7 @@ web_page_created_cb (WebKitWebExtension *wk_extension,
g_signal_connect (
web_page, "document-loaded",
- G_CALLBACK (web_page_document_loaded_cb), NULL);
+ G_CALLBACK (web_page_document_loaded_cb), extension);
}
void
@@ -290,5 +373,5 @@ e_editor_web_extension_initialize (EEditorWebExtension *extension,
script_world = webkit_script_world_get_default ();
g_signal_connect (script_world, "window-object-cleared",
- G_CALLBACK (window_object_cleared_cb), NULL);
+ G_CALLBACK (window_object_cleared_cb), extension);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]