[evolution/wip/mcrha/webkit-jsc-api] NeedInput and Selection
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution/wip/mcrha/webkit-jsc-api] NeedInput and Selection
- Date: Thu, 26 Sep 2019 16:34:16 +0000 (UTC)
commit d8c392f99088fbe0406e8b69e9e1d82061d0758c
Author: Milan Crha <mcrha redhat com>
Date: Thu Sep 26 18:34:24 2019 +0200
NeedInput and Selection
src/e-util/e-web-view-jsc-utils.c | 70 ++++++++
src/e-util/e-web-view-jsc-utils.h | 17 ++
src/e-util/e-web-view.c | 298 ++++++++++---------------------
src/e-util/e-web-view.h | 7 +-
src/e-util/test-web-view.c | 305 ++++++++++++++++++++++++++++++--
src/mail/e-mail-display.c | 4 +-
src/mail/e-mail-reader-utils.c | 2 +-
src/mail/e-mail-reader.c | 2 +-
src/plugins/mail-to-task/mail-to-task.c | 2 +-
src/web-extensions/ext-utils.js | 101 ++++++++++-
10 files changed, 576 insertions(+), 232 deletions(-)
---
diff --git a/src/e-util/e-web-view-jsc-utils.c b/src/e-util/e-web-view-jsc-utils.c
index ed680679ef..6cb4e99e9c 100644
--- a/src/e-util/e-web-view-jsc-utils.c
+++ b/src/e-util/e-web-view-jsc-utils.c
@@ -359,3 +359,73 @@ e_web_view_jsc_register_element_clicked (WebKitWebView *web_view,
webkit_web_view_run_javascript (web_view, script, cancellable, ewv_jsc_call_done_cb, script);
}
+
+void
+e_web_view_jsc_get_selection (WebKitWebView *web_view,
+ ETextFormat format,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ gchar *script;
+
+ g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view));
+
+ script = e_web_view_jsc_strdup_call ("Evo.GetSelection(%d)", format);
+
+ webkit_web_view_run_javascript (web_view, script, cancellable, callback, user_data);
+
+ g_free (script);
+}
+
+gboolean
+e_web_view_jsc_get_selection_finish (WebKitWebView *web_view,
+ GAsyncResult *result,
+ GSList **out_texts,
+ GError **error)
+{
+ WebKitJavascriptResult *js_result;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (WEBKIT_IS_WEB_VIEW (web_view), FALSE);
+ g_return_val_if_fail (result != NULL, FALSE);
+ g_return_val_if_fail (out_texts != NULL, FALSE);
+
+ *out_texts = NULL;
+
+ js_result = webkit_web_view_run_javascript_finish (web_view, result, &local_error);
+
+ if (local_error) {
+ g_propagate_error (error, local_error);
+
+ if (js_result)
+ webkit_javascript_result_unref (js_result);
+
+ return FALSE;
+ }
+
+ 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_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Call failed: %s",
jsc_exception_get_message (exception));
+ webkit_javascript_result_unref (js_result);
+ return FALSE;
+ }
+
+ if (jsc_value_is_string (value)) {
+ *out_texts = g_slist_prepend (*out_texts, jsc_value_to_string (value));
+ } else if (jsc_value_is_object (value)) {
+ *out_texts = g_slist_prepend (*out_texts, e_web_view_jsc_get_object_property_string
(value, "html", NULL));
+ *out_texts = g_slist_prepend (*out_texts, e_web_view_jsc_get_object_property_string
(value, "plain", NULL));
+ }
+
+ webkit_javascript_result_unref (js_result);
+ }
+
+ return TRUE;
+}
diff --git a/src/e-util/e-web-view-jsc-utils.h b/src/e-util/e-web-view-jsc-utils.h
index 16a786ab21..aefc453af2 100644
--- a/src/e-util/e-web-view-jsc-utils.h
+++ b/src/e-util/e-web-view-jsc-utils.h
@@ -86,6 +86,23 @@ void e_web_view_jsc_register_element_clicked
const gchar *elem_classes,
GCancellable *cancellable);
+typedef enum _ETextFormat {
+ E_TEXT_FORMAT_PLAIN = 1,
+ E_TEXT_FORMAT_HTML = 2,
+ E_TEXT_FORMAT_BOTH = 3
+} ETextFormat;
+
+void e_web_view_jsc_get_selection (WebKitWebView *web_view,
+ ETextFormat format,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_web_view_jsc_get_selection_finish
+ (WebKitWebView *web_view,
+ GAsyncResult *result,
+ GSList **out_texts,
+ GError **error);
+
G_END_DECLS
#endif /* 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 d7a0e446b7..9dddfded08 100644
--- a/src/e-util/e-web-view.c
+++ b/src/e-util/e-web-view.c
@@ -98,11 +98,8 @@ struct _EWebViewPrivate {
GHashTable *element_clicked_cbs; /* gchar *element_class ~> GPtrArray {ElementClickedData} */
- guint32 clipboard_flags;
- guint web_extension_clipboard_flags_changed_signal_id;
-
+ gboolean has_selection;
gboolean need_input;
- guint web_extension_need_input_changed_signal_id;
GCancellable *load_cancellable;
};
@@ -118,11 +115,11 @@ struct _AsyncContext {
enum {
PROP_0,
PROP_CARET_MODE,
- PROP_CLIPBOARD_FLAGS,
PROP_COPY_TARGET_LIST,
PROP_CURSOR_IMAGE_SRC,
PROP_DISABLE_PRINTING,
PROP_DISABLE_SAVE_TO_DISK,
+ PROP_HAS_SELECTION,
PROP_NEED_INPUT,
PROP_OPEN_PROXY,
PROP_PASTE_TARGET_LIST,
@@ -907,12 +904,6 @@ web_view_set_property (GObject *object,
g_value_get_boolean (value));
return;
- case PROP_CLIPBOARD_FLAGS:
- e_web_view_set_clipboard_flags (
- E_WEB_VIEW (object),
- g_value_get_uint (value));
- return;
-
case PROP_COPY_TARGET_LIST:
/* This is a fake property. */
g_warning ("%s: EWebView::copy-target-list not used", G_STRFUNC);
@@ -936,12 +927,6 @@ web_view_set_property (GObject *object,
g_value_get_boolean (value));
return;
- case PROP_NEED_INPUT:
- e_web_view_set_need_input (
- E_WEB_VIEW (object),
- g_value_get_boolean (value));
- return;
-
case PROP_OPEN_PROXY:
e_web_view_set_open_proxy (
E_WEB_VIEW (object),
@@ -987,12 +972,6 @@ web_view_get_property (GObject *object,
E_WEB_VIEW (object)));
return;
- case PROP_CLIPBOARD_FLAGS:
- g_value_set_uint (
- value, e_web_view_get_clipboard_flags (
- E_WEB_VIEW (object)));
- return;
-
case PROP_COPY_TARGET_LIST:
/* This is a fake property. */
g_value_set_boxed (value, NULL);
@@ -1016,6 +995,10 @@ web_view_get_property (GObject *object,
E_WEB_VIEW (object)));
return;
+ case PROP_HAS_SELECTION:
+ g_value_set_boolean (value, e_web_view_has_selection (E_WEB_VIEW (object)));
+ return;
+
case PROP_NEED_INPUT:
g_value_set_boolean (
value, e_web_view_get_need_input (
@@ -1424,6 +1407,69 @@ e_web_view_content_loaded_cb (WebKitUserContentManager *manager,
g_free (iframe_id);
}
+static void
+e_web_view_set_has_selection (EWebView *web_view,
+ gboolean has_selection)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ if ((!web_view->priv->has_selection) == (!has_selection))
+ return;
+
+ web_view->priv->has_selection = has_selection;
+
+ g_object_notify (G_OBJECT (web_view), "has-selection");
+}
+
+
+static void
+e_web_view_has_selection_cb (WebKitUserContentManager *manager,
+ WebKitJavascriptResult *js_result,
+ gpointer user_data)
+{
+ EWebView *web_view = user_data;
+ JSCValue *jsc_value;
+
+ g_return_if_fail (web_view != NULL);
+ g_return_if_fail (js_result != NULL);
+
+ jsc_value = webkit_javascript_result_get_js_value (js_result);
+ g_return_if_fail (jsc_value_is_boolean (jsc_value));
+
+ e_web_view_set_has_selection (web_view, jsc_value_to_boolean (jsc_value));
+}
+
+static void
+e_web_view_set_need_input (EWebView *web_view,
+ gboolean need_input)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ if ((!web_view->priv->need_input) == (!need_input))
+ return;
+
+ web_view->priv->need_input = need_input;
+
+ g_object_notify (G_OBJECT (web_view), "need-input");
+}
+
+static void
+e_web_view_need_input_changed_cb (WebKitUserContentManager *manager,
+ WebKitJavascriptResult *js_result,
+ gpointer user_data)
+{
+ EWebView *web_view = user_data;
+ JSCValue *jsc_value;
+
+ g_return_if_fail (web_view != NULL);
+ g_return_if_fail (js_result != NULL);
+
+ jsc_value = webkit_javascript_result_get_js_value (js_result);
+ g_return_if_fail (jsc_value_is_boolean (jsc_value));
+
+ e_web_view_set_need_input (web_view, jsc_value_to_boolean (jsc_value));
+}
+
static void
web_view_constructed (GObject *object)
{
@@ -1481,8 +1527,16 @@ web_view_constructed (GObject *object)
g_signal_connect (manager, "script-message-received::contentLoaded",
G_CALLBACK (e_web_view_content_loaded_cb), web_view);
+ g_signal_connect (manager, "script-message-received::hasSelection",
+ G_CALLBACK (e_web_view_has_selection_cb), web_view);
+
+ g_signal_connect (manager, "script-message-received::needInputChanged",
+ G_CALLBACK (e_web_view_need_input_changed_cb), web_view);
+
webkit_user_content_manager_register_script_message_handler (manager, "contentLoaded");
webkit_user_content_manager_register_script_message_handler (manager, "elementClicked");
+ webkit_user_content_manager_register_script_message_handler (manager, "hasSelection");
+ webkit_user_content_manager_register_script_message_handler (manager, "needInputChanged");
}
static void
@@ -1741,60 +1795,6 @@ web_view_stop_loading (EWebView *web_view)
webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (web_view));
}
-static void
-web_view_need_input_changed_signal_cb (GDBusConnection *connection,
- const gchar *sender_name,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *signal_name,
- GVariant *parameters,
- gpointer user_data)
-{
- EWebView *web_view = user_data;
- guint64 page_id = 0;
- gboolean need_input = FALSE;
-
- if (g_strcmp0 (signal_name, "NeedInputChanged") != 0)
- return;
-
- g_return_if_fail (E_IS_WEB_VIEW (web_view));
-
- if (!parameters)
- return;
-
- g_variant_get (parameters, "(tb)", &page_id, &need_input);
-
- if (page_id == webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)))
- e_web_view_set_need_input (web_view, need_input);
-}
-
-static void
-web_view_clipboard_flags_changed_signal_cb (GDBusConnection *connection,
- const gchar *sender_name,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *signal_name,
- GVariant *parameters,
- gpointer user_data)
-{
- EWebView *web_view = user_data;
- guint64 page_id = 0;
- guint32 clipboard_flags = 0;
-
- if (g_strcmp0 (signal_name, "ClipboardFlagsChanged") != 0)
- return;
-
- g_return_if_fail (E_IS_WEB_VIEW (web_view));
-
- if (!parameters)
- return;
-
- g_variant_get (parameters, "(tu)", &page_id, &clipboard_flags);
-
- if (page_id == webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)))
- e_web_view_set_clipboard_flags (web_view, clipboard_flags);
-}
-
static void
e_web_view_set_web_extension_proxy (EWebView *web_view,
GDBusProxy *proxy)
@@ -1804,59 +1804,11 @@ e_web_view_set_web_extension_proxy (EWebView *web_view,
if (web_view->priv->web_extension_proxy == proxy)
return;
- if (web_view->priv->web_extension_proxy) {
- GDBusConnection *connection;
-
- connection = g_dbus_proxy_get_connection (web_view->priv->web_extension_proxy);
-
- if (connection && g_dbus_connection_is_closed (connection))
- connection = NULL;
+ g_clear_object (&web_view->priv->web_extension_proxy);
- if (web_view->priv->web_extension_clipboard_flags_changed_signal_id) {
- if (connection)
- g_dbus_connection_signal_unsubscribe (connection,
web_view->priv->web_extension_clipboard_flags_changed_signal_id);
- web_view->priv->web_extension_clipboard_flags_changed_signal_id = 0;
- }
-
- if (web_view->priv->web_extension_need_input_changed_signal_id) {
- if (connection)
- g_dbus_connection_signal_unsubscribe (connection,
web_view->priv->web_extension_need_input_changed_signal_id);
- web_view->priv->web_extension_need_input_changed_signal_id = 0;
- }
-
- g_clear_object (&web_view->priv->web_extension_proxy);
- }
-
- if (proxy) {
+ if (proxy)
web_view->priv->web_extension_proxy = g_object_ref (proxy);
- web_view->priv->web_extension_clipboard_flags_changed_signal_id =
- g_dbus_connection_signal_subscribe (
- g_dbus_proxy_get_connection (proxy),
- g_dbus_proxy_get_name (proxy),
- E_WEB_EXTENSION_INTERFACE,
- "ClipboardFlagsChanged",
- E_WEB_EXTENSION_OBJECT_PATH,
- NULL,
- G_DBUS_SIGNAL_FLAGS_NONE,
- web_view_clipboard_flags_changed_signal_cb,
- web_view,
- NULL);
-
- web_view->priv->web_extension_need_input_changed_signal_id =
- g_dbus_connection_signal_subscribe (
- g_dbus_proxy_get_connection (proxy),
- g_dbus_proxy_get_name (proxy),
- E_WEB_EXTENSION_INTERFACE,
- "NeedInputChanged",
- E_WEB_EXTENSION_OBJECT_PATH,
- NULL,
- G_DBUS_SIGNAL_FLAGS_NONE,
- web_view_need_input_changed_signal_cb,
- web_view,
- NULL);
- }
-
g_object_notify (G_OBJECT (web_view), "web-extension-proxy");
}
@@ -1906,7 +1858,7 @@ web_view_update_actions (EWebView *web_view)
g_return_if_fail (E_IS_WEB_VIEW (web_view));
uri = e_web_view_get_selected_uri (web_view);
- can_copy = (e_web_view_get_clipboard_flags (web_view) & E_CLIPBOARD_CAN_COPY) != 0;
+ can_copy = e_web_view_has_selection (web_view);
cursor_image_src = e_web_view_get_cursor_image_src (web_view);
/* Parse the URI early so we know if the actions will work. */
@@ -2119,7 +2071,7 @@ web_view_selectable_update_actions (ESelectable *selectable,
web_view = E_WEB_VIEW (selectable);
- can_copy = (e_web_view_get_clipboard_flags (web_view) & E_CLIPBOARD_CAN_COPY) != 0;
+ can_copy = e_web_view_has_selection (web_view);
action = e_focus_tracker_get_copy_clipboard_action (focus_tracker);
gtk_action_set_sensitive (action, can_copy);
@@ -2288,17 +2240,6 @@ e_web_view_class_init (EWebViewClass *class)
FALSE,
G_PARAM_READWRITE));
- g_object_class_install_property (
- object_class,
- PROP_CLIPBOARD_FLAGS,
- g_param_spec_uint (
- "clipboard-flags",
- "Clipboard Flags",
- NULL,
- 0, G_MAXUINT, 0,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT));
-
/* Inherited from ESelectableInterface; just a fake property here */
g_object_class_override_property (
object_class,
@@ -2343,6 +2284,16 @@ e_web_view_class_init (EWebViewClass *class)
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
+ g_object_class_install_property (
+ object_class,
+ PROP_HAS_SELECTION,
+ g_param_spec_boolean (
+ "has-selection",
+ "Has Selection",
+ NULL,
+ FALSE,
+ G_PARAM_READABLE));
+
g_object_class_install_property (
object_class,
PROP_NEED_INPUT,
@@ -2351,8 +2302,7 @@ e_web_view_class_init (EWebViewClass *class)
"Need Input",
NULL,
FALSE,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT));
+ G_PARAM_READABLE));
g_object_class_install_property (
object_class,
@@ -3002,28 +2952,6 @@ e_web_view_set_editable (EWebView *web_view,
webkit_web_view_set_editable (WEBKIT_WEB_VIEW (web_view), editable);
}
-guint32
-e_web_view_get_clipboard_flags (EWebView *web_view)
-{
- g_return_val_if_fail (E_IS_WEB_VIEW (web_view), 0);
-
- return web_view->priv->clipboard_flags;
-}
-
-void
-e_web_view_set_clipboard_flags (EWebView *web_view,
- guint32 clipboard_flags)
-{
- g_return_if_fail (E_IS_WEB_VIEW (web_view));
-
- if (web_view->priv->clipboard_flags == clipboard_flags)
- return;
-
- web_view->priv->clipboard_flags = clipboard_flags;
-
- g_object_notify (G_OBJECT (web_view), "clipboard-flags");
-}
-
gboolean
e_web_view_get_need_input (EWebView *web_view)
{
@@ -3032,20 +2960,6 @@ e_web_view_get_need_input (EWebView *web_view)
return web_view->priv->need_input;
}
-void
-e_web_view_set_need_input (EWebView *web_view,
- gboolean need_input)
-{
- g_return_if_fail (E_IS_WEB_VIEW (web_view));
-
- if ((!web_view->priv->need_input) == (!need_input))
- return;
-
- web_view->priv->need_input = need_input;
-
- g_object_notify (G_OBJECT (web_view), "need-input");
-}
-
const gchar *
e_web_view_get_selected_uri (EWebView *web_view)
{
@@ -3277,35 +3191,11 @@ e_web_view_cut_clipboard (EWebView *web_view)
}
gboolean
-e_web_view_is_selection_active (EWebView *web_view)
+e_web_view_has_selection (EWebView *web_view)
{
- GDBusProxy *web_extension;
-
g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
- web_extension = e_web_view_get_web_extension_proxy (web_view);
- if (web_extension) {
- GVariant *result;
-
- result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
- web_extension,
- "DocumentHasSelection",
- g_variant_new (
- "(t)",
- webkit_web_view_get_page_id (
- WEBKIT_WEB_VIEW (web_view))),
- NULL);
-
- if (result) {
- gboolean value = FALSE;
-
- g_variant_get (result, "(b)", &value);
- g_variant_unref (result);
- return value;
- }
- }
-
- return FALSE;
+ return web_view->priv->has_selection;
}
void
diff --git a/src/e-util/e-web-view.h b/src/e-util/e-web-view.h
index 5c479ed41f..5d2d66eede 100644
--- a/src/e-util/e-web-view.h
+++ b/src/e-util/e-web-view.h
@@ -172,12 +172,7 @@ void e_web_view_set_disable_save_to_disk
gboolean e_web_view_get_editable (EWebView *web_view);
void e_web_view_set_editable (EWebView *web_view,
gboolean editable);
-guint32 e_web_view_get_clipboard_flags (EWebView *web_view);
-void e_web_view_set_clipboard_flags (EWebView *web_view,
- guint32 clipboard_flags);
gboolean e_web_view_get_need_input (EWebView *web_view);
-void e_web_view_set_need_input (EWebView *web_view,
- gboolean need_input);
gboolean e_web_view_get_inline_spelling (EWebView *web_view);
void e_web_view_set_inline_spelling (EWebView *web_view,
gboolean inline_spelling);
@@ -214,7 +209,7 @@ GtkActionGroup *e_web_view_get_action_group (EWebView *web_view,
const gchar *group_name);
void e_web_view_copy_clipboard (EWebView *web_view);
void e_web_view_cut_clipboard (EWebView *web_view);
-gboolean e_web_view_is_selection_active (EWebView *web_view);
+gboolean e_web_view_has_selection (EWebView *web_view);
void e_web_view_paste_clipboard (EWebView *web_view);
gboolean e_web_view_scroll_forward (EWebView *web_view);
gboolean e_web_view_scroll_backward (EWebView *web_view);
diff --git a/src/e-util/test-web-view.c b/src/e-util/test-web-view.c
index caf27a2ef4..c1af5516a4 100644
--- a/src/e-util/test-web-view.c
+++ b/src/e-util/test-web-view.c
@@ -23,6 +23,14 @@
#include <locale.h>
#include <e-util/e-util.h>
+enum {
+ LOAD_ALL = -1,
+ LOAD_MAIN = 0,
+ LOAD_FRM1 = 1,
+ LOAD_FRM1_1 = 2,
+ LOAD_FRM2 = 3
+};
+
typedef struct _TestFlagClass {
GObjectClass parent_class;
} TestFlagClass;
@@ -463,7 +471,7 @@ static void
test_utils_load_body (TestFixture *fixture,
gint index)
{
- if (index == 0 || index == -1) {
+ if (index == LOAD_MAIN || index == LOAD_ALL) {
test_utils_load_string (fixture,
"<html><body>"
"Top<br>"
@@ -475,7 +483,7 @@ test_utils_load_body (TestFixture *fixture,
"</body></html>");
}
- if (index == 1 || index == -1) {
+ if (index == LOAD_FRM1 || index == LOAD_ALL) {
test_utils_load_iframe_content (fixture, "frm1",
"<html><body>"
"frm1<br>"
@@ -484,7 +492,7 @@ test_utils_load_body (TestFixture *fixture,
"</body></html>");
}
- if (index == 2 || index == -1) {
+ if (index == LOAD_FRM1_1 || index == LOAD_ALL) {
test_utils_load_iframe_content (fixture, "frm1_1",
"<html><body>"
"frm1_1<br>"
@@ -494,7 +502,7 @@ test_utils_load_body (TestFixture *fixture,
"</body></html>");
}
- if (index == 3 || index == -1) {
+ if (index == LOAD_FRM2 || index == LOAD_ALL) {
test_utils_load_iframe_content (fixture, "frm2",
"<html><body>"
"frm2<br>"
@@ -567,7 +575,7 @@ test_jsc_object_properties (TestFixture *fixture)
static void
test_set_element_hidden (TestFixture *fixture)
{
- test_utils_load_body (fixture, -1);
+ test_utils_load_body (fixture, LOAD_ALL);
g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn1\").hidden"));
g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn3\").hidden"));
@@ -640,7 +648,7 @@ test_set_element_hidden (TestFixture *fixture)
static void
test_set_element_style_property (TestFixture *fixture)
{
- test_utils_load_body (fixture, -1);
+ test_utils_load_body (fixture, LOAD_ALL);
test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"\",
\"btn1\").style.getPropertyValue(\"color\")", "");
test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"\",
\"btn3\").style.getPropertyValue(\"color\")", "");
@@ -683,7 +691,7 @@ test_set_element_style_property (TestFixture *fixture)
static void
test_set_element_attribute (TestFixture *fixture)
{
- test_utils_load_body (fixture, -1);
+ test_utils_load_body (fixture, LOAD_ALL);
test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"\", \"btn1\").getAttributeNS(\"\",
\"myattr\")", NULL);
test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"\", \"btn3\").getAttributeNS(\"\",
\"myattr\")", NULL);
@@ -726,7 +734,7 @@ test_set_element_attribute (TestFixture *fixture)
static void
test_style_sheets (TestFixture *fixture)
{
- test_utils_load_body (fixture, -1);
+ test_utils_load_body (fixture, LOAD_ALL);
test_utils_jsc_call_sync (fixture,
"var Test = {};\n"
@@ -872,7 +880,7 @@ test_element_clicked (TestFixture *fixture)
{
ElementClickedData expects;
- test_utils_load_body (fixture, 0);
+ test_utils_load_body (fixture, LOAD_MAIN);
expects.fixture = fixture;
@@ -881,12 +889,12 @@ test_element_clicked (TestFixture *fixture)
test_verify_element_clicked (fixture, &expects, "", "dots1", "cdots", NULL, FALSE);
test_verify_element_clicked (fixture, &expects, "", "btn1", "cbtn1", "Button1", TRUE);
- test_utils_load_body (fixture, 1);
+ test_utils_load_body (fixture, LOAD_FRM1);
test_verify_element_clicked (fixture, &expects, "", "btn1", "cbtn1", "Button1", TRUE);
test_verify_element_clicked (fixture, &expects, "frm1", "btn1", "cbtn1", "Button1", TRUE);
- test_utils_load_body (fixture, 2);
+ test_utils_load_body (fixture, LOAD_FRM1_1);
test_verify_element_clicked (fixture, &expects, "frm1_1", "btn2", "cbtn2", "Button2", FALSE);
@@ -895,7 +903,7 @@ test_element_clicked (TestFixture *fixture)
test_verify_element_clicked (fixture, &expects, "frm1_1", "btn1", "cbtn1", "Button1", TRUE);
test_verify_element_clicked (fixture, &expects, "frm1_1", "btn2", "cbtn2", "Button2", TRUE);
- test_utils_load_body (fixture, 3);
+ test_utils_load_body (fixture, LOAD_FRM2);
test_verify_element_clicked (fixture, &expects, "frm1_1", "btn2", "cbtn2", "Button2", TRUE);
test_verify_element_clicked (fixture, &expects, "frm2", "btn2", "cbtn2", "Button2", TRUE);
@@ -940,6 +948,277 @@ test_element_clicked (TestFixture *fixture)
test_utils_wait_noop (fixture);
}
+typedef struct _NeedInputData {
+ TestFixture *fixture;
+ gboolean expects;
+} NeedInputData;
+
+static void
+test_verify_need_input_cb (GObject *object,
+ GParamSpec *param,
+ gpointer user_data)
+{
+ NeedInputData *nid = user_data;
+
+ g_assert_nonnull (nid);
+ g_assert_cmpint ((e_web_view_get_need_input (E_WEB_VIEW (nid->fixture->web_view)) ? 1 : 0), ==,
(nid->expects ? 1 : 0));
+
+ test_flag_set (nid->fixture->flag);
+}
+
+static void
+test_verify_need_input (TestFixture *fixture,
+ NeedInputData *nid,
+ const gchar *iframe_id,
+ const gchar *element_id,
+ gboolean expects)
+{
+ nid->expects = expects;
+
+ if (iframe_id) {
+ gchar *script;
+
+ script = e_web_view_jsc_strdup_call ("Evo.findIFrameDocument(%s).getElementById(%s).focus();",
+ iframe_id, element_id);
+
+ test_utils_jsc_call (fixture, script);
+
+ g_free (script);
+ } else {
+ test_utils_jsc_call (fixture, "document.activeElement.blur();");
+ }
+
+ test_utils_wait (fixture);
+}
+
+static void
+test_need_input_changed (TestFixture *fixture)
+{
+ gulong handler_id;
+ NeedInputData nid;
+
+ test_utils_load_string (fixture,
+ "<html><body>"
+ "Top<br>"
+ "<input id=\"btn1\" class=\"cbtn1\" type=\"button\" value=\"Button1\"><br>"
+ "<iframe id=\"frm1_1\" src=\"empty:///\"></iframe><br>"
+ "<input id=\"btn3\" class=\"cbtn3\" type=\"button\" value=\"Button3\">"
+ "<a name=\"dots\" id=\"dots1\" class=\"cdots\">...</a>"
+ "<label for=\"inptrdo\" id=\"lblradio\">Radio</label>"
+ "<input type=\"radio\" name=\"rdo\" id=\"inptrdo\" value=\"rdoval\"><br>"
+ "<textarea id=\"txt\" rows=\"3\" cols=\"20\">Text area text</textarea><br>"
+ "<select id=\"slct\">"
+ " <option value=\"opt1\">opt1</option>"
+ " <option value=\"opt2\">opt2</option>"
+ " <option value=\"opt3\">opt3</option>"
+ "</select><br>"
+ "<button id=\"bbtn\" type=\"button\">Button</button>"
+ "</body></html>");
+
+ test_utils_load_body (fixture, LOAD_FRM1_1);
+
+ g_assert (!e_web_view_get_need_input (E_WEB_VIEW (fixture->web_view)));
+
+ nid.fixture = fixture;
+ nid.expects = FALSE;
+
+ handler_id = g_signal_connect (fixture->web_view, "notify::need-input",
+ G_CALLBACK (test_verify_need_input_cb), &nid);
+
+ test_verify_need_input (fixture, &nid, "", "btn1", TRUE);
+ test_verify_need_input (fixture, &nid, NULL, NULL, FALSE);
+ test_verify_need_input (fixture, &nid, "frm1_1", "btn2", TRUE);
+ test_verify_need_input (fixture, &nid, NULL, NULL, FALSE);
+ test_verify_need_input (fixture, &nid, "", "btn3", TRUE);
+ test_verify_need_input (fixture, &nid, NULL, NULL, FALSE);
+ test_verify_need_input (fixture, &nid, "", "lblradio", TRUE);
+ test_verify_need_input (fixture, &nid, NULL, NULL, FALSE);
+ test_verify_need_input (fixture, &nid, "", "inptrdo", TRUE);
+ test_verify_need_input (fixture, &nid, NULL, NULL, FALSE);
+ test_verify_need_input (fixture, &nid, "", "inptrdo", TRUE);
+ test_verify_need_input (fixture, &nid, NULL, NULL, FALSE);
+ test_verify_need_input (fixture, &nid, "", "txt", TRUE);
+ test_verify_need_input (fixture, &nid, NULL, NULL, FALSE);
+ test_verify_need_input (fixture, &nid, "", "slct", TRUE);
+ test_verify_need_input (fixture, &nid, NULL, NULL, FALSE);
+ test_verify_need_input (fixture, &nid, "", "bbtn", TRUE);
+ test_verify_need_input (fixture, &nid, NULL, NULL, FALSE);
+
+ g_signal_handler_disconnect (fixture->web_view, handler_id);
+
+ g_assert (!e_web_view_get_need_input (E_WEB_VIEW (fixture->web_view)));
+}
+
+static void
+test_selection_select_in_iframe (TestFixture *fixture,
+ const gchar *iframe_id,
+ const gchar *start_elem_id,
+ const gchar *end_elem_id)
+{
+ gchar *script;
+
+ script = e_web_view_jsc_strdup_call (
+ /* Clean selection in both places first, otherwise the previous selection
+ can stay when changing it only in one of them. */
+ "Evo.findIFrameDocument(\"\").defaultView.getSelection().empty();\n"
+ "Evo.findIFrameDocument(\"frm1\").defaultView.getSelection().empty();\n"
+ "\n"
+ "var doc, range;\n"
+ "doc = Evo.findIFrameDocument(%s);\n"
+ "range = doc.createRange();\n"
+ "range.selectNodeContents(doc.getElementById(%s));"
+ "doc.defaultView.getSelection().addRange(range);\n"
+ "doc.defaultView.getSelection().extend(doc.getElementById(%s));\n",
+ iframe_id, start_elem_id, end_elem_id);
+
+ test_utils_jsc_call_sync (fixture, script, NULL);
+
+ g_free (script);
+
+ /* Wait for the notification from JS about changed selection
+ to be propagated into EWebView's has-selection. */
+ test_utils_wait_noop (fixture);
+}
+
+typedef struct _GetSelectionData {
+ TestFixture *fixture;
+ const gchar *expect_plain;
+ const gchar *expect_html;
+} GetSelectionData;
+
+static void
+test_selection_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GetSelectionData *gsd = user_data;
+ GSList *texts = NULL;
+ gboolean success;
+ GError *error = NULL;
+
+ g_assert (WEBKIT_IS_WEB_VIEW (source_object));
+ g_assert_nonnull (gsd);
+
+ success = e_web_view_jsc_get_selection_finish (WEBKIT_WEB_VIEW (source_object), result, &texts,
&error);
+
+ g_assert_no_error (error);
+ g_assert (success);
+
+ if (gsd->expect_plain && gsd->expect_html) {
+ g_assert_cmpint (g_slist_length (texts), ==, 2);
+ g_assert_cmpstr (texts->data, ==, gsd->expect_plain);
+ g_assert_cmpstr (texts->next->data, ==, gsd->expect_html);
+ } else if (gsd->expect_plain) {
+ g_assert_cmpint (g_slist_length (texts), ==, 1);
+ g_assert_cmpstr (texts->data, ==, gsd->expect_plain);
+ } else if (gsd->expect_html) {
+ g_assert_cmpint (g_slist_length (texts), ==, 1);
+ g_assert_cmpstr (texts->data, ==, gsd->expect_html);
+ } else {
+ g_assert_cmpint (g_slist_length (texts), ==, 0);
+ }
+
+ g_slist_free_full (texts, g_free);
+
+ test_flag_set (gsd->fixture->flag);
+}
+
+static void
+test_selection_verify (TestFixture *fixture,
+ const gchar *expect_plain,
+ const gchar *expect_html)
+{
+ ETextFormat format;
+ GetSelectionData *gsd;
+
+ if (expect_plain && expect_html)
+ format = E_TEXT_FORMAT_BOTH;
+ else if (expect_html)
+ format = E_TEXT_FORMAT_HTML;
+ else
+ format = E_TEXT_FORMAT_PLAIN;
+
+ gsd = g_new0 (GetSelectionData, 1);
+ gsd->fixture = fixture;
+ gsd->expect_plain = expect_plain;
+ gsd->expect_html = expect_html;
+
+ e_web_view_jsc_get_selection (fixture->web_view, format, NULL, test_selection_ready_cb, gsd);
+
+ test_utils_wait (fixture);
+}
+
+static void
+test_selection (TestFixture *fixture)
+{
+ test_utils_load_string (fixture,
+ "<html><body>"
+ "<pre id=\"pr\">Out<span id=\"pr1\"></span>er text\nin PR<span id=\"pr2\"></span>E</pre><br
id=\"br1\">"
+ "o<font color=\"orange\">rang</font>e; <b>bold</b><i>italic</i><br id=\"br2\">"
+ "<iframe id=\"frm1\" src=\"empty:///\"></iframe><br>"
+ "</body></html>");
+
+ test_utils_load_iframe_content (fixture, "frm1",
+ "<html><body>"
+ "frm1<br>"
+ "<div id=\"plain\">unformatted text</div><br>"
+ "<div id=\"rgb\">"
+ "<font color=\"red\">R</font>"
+ "<font color=\"green\">G</font>"
+ "<font color=\"blue\">B</font>"
+ "</div>"
+ "<div id=\"styled\">"
+ "<span style=\"color:blue;\">bb</span>"
+ "<span style=\"color:green;\">gg</span>"
+ "<span style=\"color:red;\">rr</span>"
+ "</div>"
+ "<div id=\"end\"></div>"
+ "</body></html>");
+
+ g_assert_cmpint (e_web_view_has_selection (E_WEB_VIEW (fixture->web_view)) ? 1 : 0, ==, 0);
+ test_selection_verify (fixture, NULL, NULL);
+
+ test_selection_select_in_iframe (fixture, "", "pr1", "pr2");
+
+ g_assert_cmpint (e_web_view_has_selection (E_WEB_VIEW (fixture->web_view)) ? 1 : 0, ==, 1);
+ test_selection_verify (fixture, "er text\nin PR", NULL);
+ test_selection_verify (fixture, NULL, "<pre>er text\nin PR</pre>");
+ test_selection_verify (fixture, "er text\nin PR", "<pre>er text\nin PR</pre>");
+
+ test_selection_select_in_iframe (fixture, "", "br1", "br2");
+
+ g_assert_cmpint (e_web_view_has_selection (E_WEB_VIEW (fixture->web_view)) ? 1 : 0, ==, 1);
+ test_selection_verify (fixture, "\norange; bolditalic", NULL);
+ test_selection_verify (fixture, NULL, "<br id=\"br1\">o<font color=\"orange\">rang</font>e;
<b>bold</b><i>italic</i>");
+ test_selection_verify (fixture, "\norange; bolditalic", "<br id=\"br1\">o<font
color=\"orange\">rang</font>e; <b>bold</b><i>italic</i>");
+
+ 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, 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_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", 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_select_in_iframe (fixture, "frm1", "styled", "end");
+
+ g_assert_cmpint (e_web_view_has_selection (E_WEB_VIEW (fixture->web_view)) ? 1 : 0, ==, 1);
+ test_selection_verify (fixture, "bbggrr", NULL);
+ test_selection_verify (fixture, NULL, "<span style=\"color:blue;\">bb</span><span
style=\"color:green;\">gg</span><span style=\"color:red;\">rr</span>");
+ test_selection_verify (fixture, "bbggrr", "<span style=\"color:blue;\">bb</span><span
style=\"color:green;\">gg</span><span style=\"color:red;\">rr</span>");
+
+ test_selection_select_in_iframe (fixture, "frm1", "end", "end");
+
+ g_assert_cmpint (e_web_view_has_selection (E_WEB_VIEW (fixture->web_view)) ? 1 : 0, ==, 0);
+ test_selection_verify (fixture, NULL, NULL);
+}
+
gint
main (gint argc,
gchar *argv[])
@@ -962,6 +1241,8 @@ main (gint argc,
test_utils_add_test ("/EWebView/SetElementAttribute", test_set_element_attribute);
test_utils_add_test ("/EWebView/StyleSheets", test_style_sheets);
test_utils_add_test ("/EWebView/ElementClicked", test_element_clicked);
+ test_utils_add_test ("/EWebView/NeedInputChanged", test_need_input_changed);
+ test_utils_add_test ("/EWebView/Selection", test_selection);
res = g_test_run ();
diff --git a/src/mail/e-mail-display.c b/src/mail/e-mail-display.c
index 3b72657a55..0a18d284da 100644
--- a/src/mail/e-mail-display.c
+++ b/src/mail/e-mail-display.c
@@ -2776,7 +2776,7 @@ e_mail_display_get_selection_content_multipart_sync (EMailDisplay *display,
g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
- if (!e_web_view_is_selection_active (E_WEB_VIEW (display)))
+ if (!e_web_view_has_selection (E_WEB_VIEW (display)))
return NULL;
web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (display));
@@ -2819,7 +2819,7 @@ e_mail_display_get_selection_plain_text_sync (EMailDisplay *display,
g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
- if (!e_web_view_is_selection_active (E_WEB_VIEW (display)))
+ if (!e_web_view_has_selection (E_WEB_VIEW (display)))
return NULL;
web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (display));
diff --git a/src/mail/e-mail-reader-utils.c b/src/mail/e-mail-reader-utils.c
index 2db5f04bc4..5fe3b12ce7 100644
--- a/src/mail/e-mail-reader-utils.c
+++ b/src/mail/e-mail-reader-utils.c
@@ -2734,7 +2734,7 @@ e_mail_reader_reply_to_message (EMailReader *reader,
g_clear_object (&part_list);
- if (!e_web_view_is_selection_active (web_view))
+ if (!e_web_view_has_selection (web_view))
goto whole_message;
content_type = camel_mime_part_get_content_type (CAMEL_MIME_PART (src_message));
diff --git a/src/mail/e-mail-reader.c b/src/mail/e-mail-reader.c
index 9898602880..e9edcd857e 100644
--- a/src/mail/e-mail-reader.c
+++ b/src/mail/e-mail-reader.c
@@ -4831,7 +4831,7 @@ mail_reader_update_actions (EMailReader *reader,
action = e_mail_reader_get_action (reader, "mail-search-web");
gtk_action_set_sensitive (action, single_message_selected &&
- mail_display && e_web_view_is_selection_active (E_WEB_VIEW (mail_display)));
+ mail_display && e_web_view_has_selection (E_WEB_VIEW (mail_display)));
mail_reader_update_labels_menu (reader);
}
diff --git a/src/plugins/mail-to-task/mail-to-task.c b/src/plugins/mail-to-task/mail-to-task.c
index e28dba3e8d..6d9f6eac8f 100644
--- a/src/plugins/mail-to-task/mail-to-task.c
+++ b/src/plugins/mail-to-task/mail-to-task.c
@@ -1099,7 +1099,7 @@ get_selected_text (EMailReader *reader)
display = e_mail_reader_get_mail_display (reader);
- if (!e_web_view_is_selection_active (E_WEB_VIEW (display)))
+ if (!e_web_view_has_selection (E_WEB_VIEW (display)))
return NULL;
text = e_mail_display_get_selection_plain_text_sync (display, NULL, NULL);
diff --git a/src/web-extensions/ext-utils.js b/src/web-extensions/ext-utils.js
index 1c17a2b013..ab083b2547 100644
--- a/src/web-extensions/ext-utils.js
+++ b/src/web-extensions/ext-utils.js
@@ -1,6 +1,8 @@
'use strict';
-var Evo = {};
+var Evo = {
+ hasSelection : false
+};
Evo.findIFrameInDocument = function(doc, iframe_id)
{
@@ -199,8 +201,8 @@ Evo.ElemClicked = function(elem)
var with_parents_left, with_parents_top, scroll_x = 0, scroll_y = 0, offset_parent, dom_window;
var parent_iframe_id = "";
- if (elem.ownerDocument.defaultView.window.frameElement)
- parent_iframe_id = elem.ownerDocument.defaultView.window.frameElement.id;
+ if (elem.ownerDocument.defaultView.frameElement)
+ parent_iframe_id = elem.ownerDocument.defaultView.frameElement.id;
with_parents_left = elem.offsetLeft;
with_parents_top = elem.offsetTop;
@@ -292,6 +294,86 @@ Evo.RegisterElementClicked = function(iframe_id, elem_classes_str)
}
}
+Evo.checkAnyParentIsPre = function(node)
+{
+ if (!node)
+ return false;
+
+ while (node = node.parentElement, node) {
+ if (node instanceof HTMLPreElement)
+ return true;
+ if (node instanceof HTMLIFrameElement)
+ break;
+ }
+
+ return false;
+}
+
+Evo.convertHTMLToPlain = function(node)
+{
+ /* TODO */
+ return node.innerText;
+}
+
+Evo.checkHasSelectionRecursive = function(doc, content)
+{
+ var has = false, iframes, ii;
+
+ if (!doc.defaultView.getSelection().isCollapsed) {
+ if (content) {
+ var fragment, node, inpre;
+
+ fragment = doc.defaultView.getSelection().getRangeAt(0).cloneContents();
+ inpre =
Evo.checkAnyParentIsPre(doc.defaultView.getSelection().getRangeAt(0).startContainer);
+ node = doc.createElement(inpre ? "PRE" : "DIV");
+ node.appendChild(fragment);
+
+ if (content.format == 1) {
+ content.data = Evo.convertHTMLToPlain(node);
+ } else if (content.format == 2) {
+ content.data = inpre ? node.outerHTML : node.innerHTML;
+ } else if (content.format == 3) {
+ content.data["plain"] = Evo.convertHTMLToPlain(node);
+ content.data["html"] = inpre ? node.outerHTML : node.innerHTML;
+ }
+ }
+
+ return true;
+ }
+
+ iframes = doc.getElementsByTagName("iframe");
+
+ for (ii = 0; !has && ii < iframes.length; ii++) {
+ has = Evo.checkHasSelectionRecursive(iframes[ii].contentDocument, content);
+ }
+
+ return has;
+}
+
+Evo.selectionChanged = function()
+{
+ var has;
+
+ has = Evo.checkHasSelectionRecursive(document, null);
+
+ if (has != Evo.hasSelection) {
+ Evo.hasSelection = has;
+ window.webkit.messageHandlers.hasSelection.postMessage(has);
+ }
+}
+
+Evo.GetSelection = function(format)
+{
+ var content = { format: 0, data: {} };
+
+ content.format = format;
+
+ if (!Evo.checkHasSelectionRecursive(document, content))
+ return null;
+
+ return content.data;
+}
+
Evo.Initialize = function(elem)
{
var doc, elems, ii;
@@ -315,14 +397,23 @@ Evo.Initialize = function(elem)
doc.documentElement.style.setProperty("color", "inherit");
doc.documentElement.style.setProperty("background-color", "inherit");
}
+
+ elems = doc.querySelectorAll("input, textarea, select, button, label");
+
+ for (ii = 0; ii < elems.length; ii++) {
+ elems[ii].onfocus = function() {
window.webkit.messageHandlers.needInputChanged.postMessage(true); };
+ elems[ii].onblur = function() {
window.webkit.messageHandlers.needInputChanged.postMessage(false); };
+ }
+
+ doc.onselectionchange = Evo.selectionChanged;
}
Evo.InitializeAndPostContentLoaded = function(elem)
{
var iframe_id = "";
- if (elem && elem.ownerDocument && elem.ownerDocument.defaultView.window.frameElement)
- iframe_id = elem.ownerDocument.defaultView.window.frameElement.id;
+ if (elem && elem.ownerDocument && elem.ownerDocument.defaultView.frameElement)
+ iframe_id = elem.ownerDocument.defaultView.frameElement.id;
else if (window.frameElement)
iframe_id = window.frameElement.id;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]