[evolution/wip/mcrha/webkit-jsc-api] Added named params object/array functions and test, with elementClicked callback
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution/wip/mcrha/webkit-jsc-api] Added named params object/array functions and test, with elementClicked callback
- Date: Wed, 25 Sep 2019 14:12:23 +0000 (UTC)
commit 5266b8cd6a1fbaf4d5ecd40682da19fa2144a215
Author: Milan Crha <mcrha redhat com>
Date: Wed Sep 25 16:11:59 2019 +0200
Added named params object/array functions and test, with elementClicked callback
src/e-util/e-web-view-jsc-utils.c | 94 +++++++++++++++++++++++++++++++++++
src/e-util/e-web-view-jsc-utils.h | 17 +++++++
src/e-util/e-web-view.c | 78 +++++++++++++++++++++++++++++
src/e-util/e-web-view.h | 5 ++
src/e-util/test-web-view.c | 92 ++++++++++++++++++++++++----------
src/web-extensions/ext-utils.js | 102 +++++++++++++++++++++++++++++++++++++-
6 files changed, 361 insertions(+), 27 deletions(-)
---
diff --git a/src/e-util/e-web-view-jsc-utils.c b/src/e-util/e-web-view-jsc-utils.c
index 59028b67c1..6c68da614f 100644
--- a/src/e-util/e-web-view-jsc-utils.c
+++ b/src/e-util/e-web-view-jsc-utils.c
@@ -102,6 +102,100 @@ e_web_view_jsc_strdup_call (const gchar *call_format,
return g_string_free (script, FALSE);
}
+gboolean
+e_web_view_jsc_get_object_property_boolean (JSCValue *jsc_object,
+ const gchar *property_name,
+ gboolean default_value)
+{
+ JSCValue *value;
+ gboolean res = default_value;
+
+ g_return_val_if_fail (JSC_IS_VALUE (jsc_object), default_value);
+ g_return_val_if_fail (property_name != NULL, default_value);
+
+ value = jsc_value_object_get_property (jsc_object, property_name);
+ if (!value)
+ return default_value;
+
+ if (jsc_value_is_boolean (value))
+ res = jsc_value_to_boolean (value);
+
+ g_clear_object (&value);
+
+ return res;
+}
+
+gint32
+e_web_view_jsc_get_object_property_int32 (JSCValue *jsc_object,
+ const gchar *property_name,
+ gint32 default_value)
+{
+ JSCValue *value;
+ gint32 res = default_value;
+
+ g_return_val_if_fail (JSC_IS_VALUE (jsc_object), default_value);
+ g_return_val_if_fail (property_name != NULL, default_value);
+
+ value = jsc_value_object_get_property (jsc_object, property_name);
+ if (!value)
+ return default_value;
+
+ if (jsc_value_is_number (value))
+ res = jsc_value_to_int32 (value);
+
+ g_clear_object (&value);
+
+ return res;
+}
+
+gdouble
+e_web_view_jsc_get_object_property_double (JSCValue *jsc_object,
+ const gchar *property_name,
+ gdouble default_value)
+{
+ JSCValue *value;
+ gdouble res = default_value;
+
+ g_return_val_if_fail (JSC_IS_VALUE (jsc_object), default_value);
+ g_return_val_if_fail (property_name != NULL, default_value);
+
+ value = jsc_value_object_get_property (jsc_object, property_name);
+ if (!value)
+ return default_value;
+
+ if (jsc_value_is_number (value))
+ res = jsc_value_to_double (value);
+
+ g_clear_object (&value);
+
+ return res;
+}
+
+gchar *
+e_web_view_jsc_get_object_property_string (JSCValue *jsc_object,
+ const gchar *property_name,
+ const gchar *default_value)
+{
+ JSCValue *value;
+ gchar *res;
+
+ g_return_val_if_fail (JSC_IS_VALUE (jsc_object), NULL);
+ g_return_val_if_fail (property_name != NULL, NULL);
+
+ value = jsc_value_object_get_property (jsc_object, property_name);
+ if (!value)
+ return g_strdup (default_value);
+
+ if (jsc_value_is_string (value))
+ res = jsc_value_to_string (value);
+ else
+ res = g_strdup (default_value);
+
+ g_clear_object (&value);
+
+ return res;
+}
+
static void
ewv_jsc_call_done_cb (GObject *source,
GAsyncResult *result,
diff --git a/src/e-util/e-web-view-jsc-utils.h b/src/e-util/e-web-view-jsc-utils.h
index 5f382a455a..c5c4136b1d 100644
--- a/src/e-util/e-web-view-jsc-utils.h
+++ b/src/e-util/e-web-view-jsc-utils.h
@@ -29,6 +29,23 @@ G_BEGIN_DECLS
gchar * e_web_view_jsc_strdup_call (const gchar *call_format,
...) G_GNUC_PRINTF (1, 2);
+gboolean e_web_view_jsc_get_object_property_boolean
+ (JSCValue *jsc_object,
+ const gchar *property_name,
+ gboolean default_value);
+gint32 e_web_view_jsc_get_object_property_int32
+ (JSCValue *jsc_object,
+ const gchar *property_name,
+ gint32 default_value);
+gdouble e_web_view_jsc_get_object_property_double
+ (JSCValue *jsc_object,
+ const gchar *property_name,
+ gdouble default_value);
+gchar * e_web_view_jsc_get_object_property_string
+ (JSCValue *jsc_object,
+ const gchar *property_name,
+ const gchar *default_value);
+
void e_web_view_jsc_set_element_hidden
(WebKitWebView *web_view,
const gchar *iframe_id,
diff --git a/src/e-util/e-web-view.c b/src/e-util/e-web-view.c
index 9ff2d79549..ccd9bd4b6d 100644
--- a/src/e-util/e-web-view.c
+++ b/src/e-util/e-web-view.c
@@ -39,6 +39,7 @@
#include "e-selectable.h"
#include "e-stock-request.h"
#include "e-web-extension-container.h"
+#include "e-web-view-jsc-utils.h"
#include "web-extensions/e-web-extension-names.h"
@@ -140,6 +141,7 @@ enum {
UPDATE_ACTIONS,
PROCESS_MAILTO,
URI_REQUESTED,
+ CONTENT_LOADED,
LAST_SIGNAL
};
@@ -1317,10 +1319,67 @@ e_web_view_initialize_web_extensions_cb (WebKitWebContext *web_context,
e_web_extension_container_get_server_address (web_view->priv->container)));
}
+static void
+e_web_view_element_clicked_cb (WebKitUserContentManager *manager,
+ WebKitJavascriptResult *js_result,
+ gpointer user_data)
+{
+ EWebView *web_view = user_data;
+ JSCValue *jsc_object;
+ gchar *frame_id, *elem_id, *elem_class_name, *elem_value;
+ guint elem_left, elem_top, elem_width, elem_height;
+
+ g_return_if_fail (web_view != NULL);
+ g_return_if_fail (js_result != NULL);
+
+ jsc_object = webkit_javascript_result_get_js_value (js_result);
+ g_return_if_fail (jsc_value_is_object (jsc_object));
+
+ frame_id = e_web_view_jsc_get_object_property_string (jsc_object, "frame-id", NULL);
+ elem_id = e_web_view_jsc_get_object_property_string (jsc_object, "elem-id", NULL);
+ elem_class_name = e_web_view_jsc_get_object_property_string (jsc_object, "elem-class-name", NULL);
+ elem_value = e_web_view_jsc_get_object_property_string (jsc_object, "elem-value", NULL);
+ elem_left = e_web_view_jsc_get_object_property_int32 (jsc_object, "left", 0);
+ elem_top = e_web_view_jsc_get_object_property_int32 (jsc_object, "top", 0);
+ elem_width = e_web_view_jsc_get_object_property_int32 (jsc_object, "width", 0);
+ elem_height = e_web_view_jsc_get_object_property_int32 (jsc_object, "height", 0);
+
+ printf ("%s: received elementclicked: frm:%s elem:'%s' cls:'%s' val:'%s' at:[%d,%d,%d,%d]\n",
__FUNCTION__,
+ frame_id, elem_id, elem_class_name, elem_value, elem_left, elem_top, elem_width, elem_height);
+
+ g_free (frame_id);
+ g_free (elem_id);
+ g_free (elem_class_name);
+ g_free (elem_value);
+}
+
+static void
+e_web_view_content_loaded_cb (WebKitUserContentManager *manager,
+ WebKitJavascriptResult *js_result,
+ gpointer user_data)
+{
+ EWebView *web_view = user_data;
+ JSCValue *jsc_value;
+ gchar *iframe_id;
+
+ 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_string (jsc_value));
+
+ iframe_id = jsc_value_to_string (jsc_value);
+
+ g_signal_emit (web_view, signals[CONTENT_LOADED], 0, iframe_id);
+
+ g_free (iframe_id);
+}
+
static void
web_view_constructed (GObject *object)
{
WebKitSettings *web_settings;
+ WebKitUserContentManager *manager;
EWebView *web_view = E_WEB_VIEW (object);
#ifndef G_OS_WIN32
GSettings *settings;
@@ -1364,6 +1423,17 @@ web_view_constructed (GObject *object)
web_view_initialize (WEBKIT_WEB_VIEW (object));
web_view_set_find_controller (web_view);
+
+ manager = webkit_web_view_get_user_content_manager (WEBKIT_WEB_VIEW (object));
+
+ g_signal_connect (manager, "script-message-received::elementClicked",
+ G_CALLBACK (e_web_view_element_clicked_cb), web_view);
+
+ g_signal_connect (manager, "script-message-received::contentLoaded",
+ G_CALLBACK (e_web_view_content_loaded_cb), web_view);
+
+ webkit_user_content_manager_register_script_message_handler (manager, "contentLoaded");
+ webkit_user_content_manager_register_script_message_handler (manager, "elementClicked");
}
static void
@@ -2440,6 +2510,14 @@ e_web_view_class_init (EWebViewClass *class)
G_STRUCT_OFFSET (EWebViewClass, uri_requested),
NULL, NULL, NULL,
G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER);
+
+ signals[CONTENT_LOADED] = g_signal_new (
+ "content-loaded",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EWebViewClass, content_loaded),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1, G_TYPE_STRING);
}
static void
diff --git a/src/e-util/e-web-view.h b/src/e-util/e-web-view.h
index 474140dfb6..387ca0d72c 100644
--- a/src/e-util/e-web-view.h
+++ b/src/e-util/e-web-view.h
@@ -111,6 +111,11 @@ struct _EWebViewClass {
void (*uri_requested) (EWebView *web_view,
const gchar *uri,
gchar **redirect_to_uri);
+ void (*content_loaded) (EWebView *web_view,
+ const gchar *frame_id);
+
+ /* Padding for future expansion */
+ gpointer reserved[16];
};
GType e_web_view_get_type (void) G_GNUC_CONST;
diff --git a/src/e-util/test-web-view.c b/src/e-util/test-web-view.c
index a1e2fdd5cc..df21bebfaa 100644
--- a/src/e-util/test-web-view.c
+++ b/src/e-util/test-web-view.c
@@ -378,18 +378,13 @@ test_utils_wait_noop (TestFixture *fixture)
}
static void
-test_utils_iframe_loaded_cb (WebKitUserContentManager *manager,
- WebKitJavascriptResult *js_result,
+test_utils_iframe_loaded_cb (EWebView *web_view,
+ const gchar *iframe_id,
gpointer user_data)
{
TestFixture *fixture = user_data;
- JSCValue *jsc_value;
g_return_if_fail (fixture != 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_string (jsc_value));
test_flag_set (fixture->flag);
}
@@ -399,25 +394,12 @@ test_utils_load_iframe_content (TestFixture *fixture,
const gchar *iframe_id,
const gchar *content)
{
- WebKitUserContentManager *manager;
gchar *script;
gulong handler_id;
- manager = webkit_web_view_get_user_content_manager (fixture->web_view);
-
- handler_id = g_signal_connect (manager, "script-message-received::iframeLoaded",
+ handler_id = g_signal_connect (fixture->web_view, "content-loaded",
G_CALLBACK (test_utils_iframe_loaded_cb), fixture);
- webkit_user_content_manager_register_script_message_handler (manager, "iframeLoaded");
-
- script = e_web_view_jsc_strdup_call (
- "Evo.findIFrame(%s).onload = window.webkit.messageHandlers.iframeLoaded.postMessage(%s);\n",
- iframe_id, iframe_id);
-
- test_utils_jsc_call (fixture, script);
-
- g_free (script);
-
script = e_web_view_jsc_strdup_call ("Evo.SetIFrameContent(%s,%s)", iframe_id, content);
test_utils_jsc_call (fixture, script);
@@ -426,8 +408,7 @@ test_utils_load_iframe_content (TestFixture *fixture,
test_utils_wait (fixture);
- g_signal_handler_disconnect (manager, handler_id);
- webkit_user_content_manager_unregister_script_message_handler (manager, "iframeLoaded");
+ g_signal_handler_disconnect (fixture->web_view, handler_id);
}
static void
@@ -492,6 +473,66 @@ test_utils_load_body (TestFixture *fixture)
"</body></html>");
}
+static void
+test_jsc_object_properties (TestFixture *fixture)
+{
+ JSCValue *jsc_object = NULL;
+ gchar *str;
+
+ str = e_web_view_jsc_strdup_call (
+ "test_obj_props = function()\n"
+ "{\n"
+ " var arrobj = [];\n"
+ " arrobj[\"btrue\"] = true;\n"
+ " arrobj[\"bfalse\"] = false;\n"
+ " arrobj[\"i2\"] = 2;\n"
+ " arrobj[\"i67890\"] = 67890;\n"
+ " arrobj[\"i-12345\"] = -12345;\n"
+ " arrobj[\"d-54.32\"] = -54.32;\n"
+ " arrobj[\"d67.89\"] = 67.89;\n"
+ " arrobj[\"s-it\"] = \"it\";\n"
+ " arrobj[\"s-Is\"] = \"Is\";\n"
+ " return arrobj;\n"
+ "}\n"
+ "test_obj_props();\n");
+
+ test_utils_jsc_call_sync (fixture, str, &jsc_object);
+
+ g_free (str);
+
+ g_assert_nonnull (jsc_object);
+ g_assert (jsc_value_is_object (jsc_object));
+
+ g_assert (e_web_view_jsc_get_object_property_boolean (jsc_object, "btrue", FALSE));
+ g_assert (!e_web_view_jsc_get_object_property_boolean (jsc_object, "bfalse", TRUE));
+ g_assert (!e_web_view_jsc_get_object_property_boolean (jsc_object, "budenfined", FALSE));
+ g_assert (e_web_view_jsc_get_object_property_boolean (jsc_object, "budenfined", TRUE));
+ g_assert_cmpint (e_web_view_jsc_get_object_property_int32 (jsc_object, "i2", 0), ==, 2);
+ g_assert_cmpint (e_web_view_jsc_get_object_property_int32 (jsc_object, "i67890", 0), ==, 67890);
+ g_assert_cmpint (e_web_view_jsc_get_object_property_int32 (jsc_object, "i-12345", 0), ==, -12345);
+ g_assert_cmpint (e_web_view_jsc_get_object_property_int32 (jsc_object, "iundefined", 333), ==, 333);
+ g_assert_cmpfloat (e_web_view_jsc_get_object_property_double (jsc_object, "d-54.32", 0.0), ==,
-54.32);
+ g_assert_cmpfloat (e_web_view_jsc_get_object_property_double (jsc_object, "d67.89", 0.0), ==, 67.89);
+ g_assert_cmpfloat (e_web_view_jsc_get_object_property_double (jsc_object, "dundefined", 123.456), ==,
123.456);
+
+ str = e_web_view_jsc_get_object_property_string (jsc_object, "s-it", NULL);
+ g_assert_cmpstr (str, ==, "it");
+ g_free (str);
+
+ str = e_web_view_jsc_get_object_property_string (jsc_object, "s-Is", NULL);
+ g_assert_cmpstr (str, ==, "Is");
+ g_free (str);
+
+ str = e_web_view_jsc_get_object_property_string (jsc_object, "sundefined", "xxx");
+ g_assert_cmpstr (str, ==, "xxx");
+ g_free (str);
+
+ str = e_web_view_jsc_get_object_property_string (jsc_object, "sundefined", NULL);
+ g_assert_null (str);
+
+ g_clear_object (&jsc_object);
+}
+
static void
test_set_element_hidden (TestFixture *fixture)
{
@@ -544,7 +585,7 @@ test_set_element_hidden (TestFixture *fixture)
g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn1\").hidden"));
g_assert (test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"frm2\", \"btn2\").hidden"));
- e_web_view_jsc_set_element_hidden (fixture->web_view, "frm1", "btn1", FALSE, NULL);
+ e_web_view_jsc_set_element_hidden (fixture->web_view, "frm2", "btn1", FALSE, NULL);
test_utils_wait_noop (fixture);
g_assert (!test_utils_jsc_call_bool_sync (fixture, "Evo.findElement(\"\", \"btn1\").hidden"));
@@ -649,8 +690,6 @@ test_set_element_attribute (TestFixture *fixture)
test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm1_1\",
\"btn1\").getAttributeNS(\"\", \"myattr\")", NULL);
test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm2\",
\"btn1\").getAttributeNS(\"\", \"myattr\")", NULL);
test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm2\",
\"btn2\").getAttributeNS(\"\", \"myattr\")", NULL);
-
- test_utils_wait (fixture);
}
gint
@@ -669,6 +708,7 @@ main (gint argc,
e_util_init_main_thread (NULL);
e_passwords_init ();
+ test_utils_add_test ("/EWebView/JSCObjectProperties", test_jsc_object_properties);
test_utils_add_test ("/EWebView/SetElementHidden", test_set_element_hidden);
test_utils_add_test ("/EWebView/SetElementStyleProperty", test_set_element_style_property);
test_utils_add_test ("/EWebView/SetElementAttribute", test_set_element_attribute);
diff --git a/src/web-extensions/ext-utils.js b/src/web-extensions/ext-utils.js
index 7151f31297..6062e60cc6 100644
--- a/src/web-extensions/ext-utils.js
+++ b/src/web-extensions/ext-utils.js
@@ -79,6 +79,14 @@ Evo.SetElementAttribute = function(iframe_id, element_id, namespace_uri, qualifi
}
}
+Evo.SetDocumentContent = function(content)
+{
+ document.documentElement.innerHTML = content;
+
+ window.webkit.messageHandlers.contentLoaded.postMessage("");
+ Evo.Initialize("");
+}
+
Evo.SetIFrameSrc = function(iframe_id, src_uri)
{
var iframe = Evo.findIFrame(iframe_id);
@@ -91,6 +99,98 @@ Evo.SetIFrameContent = function(iframe_id, content)
{
var iframe = Evo.findIFrame(iframe_id);
- if (iframe)
+ if (iframe) {
iframe.contentDocument.documentElement.innerHTML = content;
+
+ window.webkit.messageHandlers.contentLoaded.postMessage(iframe_id);
+ Evo.Initialize(iframe);
+ }
+}
+
+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;
+
+ with_parents_left = elem.offsetLeft;
+ with_parents_top = elem.offsetTop;
+
+ offset_parent = elem;
+ while (offset_parent = offset_parent.offsetParent, offset_parent) {
+ with_parents_left += offset_parent.offsetLeft;
+ with_parents_top += offset_parent.offsetTop;
+ }
+
+ dom_window = elem.ownerDocument.defaultView;
+ while (dom_window instanceof Window) {
+ var parent_dom_window, iframe_elem;
+
+ parent_dom_window = dom_window.parent;
+ iframe_elem = dom_window.frameElement;
+
+ while (iframe_elem) {
+ with_parents_left += iframe_elem.offsetLeft;
+ with_parents_top += iframe_elem.offsetTop;
+
+ iframe_elem = iframe_elem.offsetParent;
+ }
+
+ scroll_x += dom_window.scrollX;
+ scroll_y += dom_window.scrollY;
+
+ if (parent_dom_window == dom_window)
+ break;
+
+ dom_window = parent_dom_window;
+ }
+
+ var res = [];
+
+ res["frame-id"] = parent_iframe_id;
+ res["elem-id"] = elem.id;
+ res["elem-class-name"] = elem.className;
+ res["elem-value"] = elem.getAttribute("value");
+ res["left"] = with_parents_left - scroll_x;
+ res["top"] = with_parents_top - scroll_y;
+ res["width"] = elem.offsetWidth;
+ res["height"] = elem.offsetHeight;
+
+ window.webkit.messageHandlers.elementClicked.postMessage(res);
+}
+
+Evo.Initialize = function(elem)
+{
+ var elems, ii;
+
+ if (elem && elem instanceof HTMLIFrameElement && elem.contentDocument)
+ elems = elem.contentDocument.getElementsByTagName("iframe");
+ else
+ elems = document.getElementsByTagName("iframe");
+
+ for (ii = 0; ii < elems.length; ii++) {
+ elems[ii].onload = function() { Evo.PostContentLoadedAndInitialize(this) };
+ }
+}
+
+Evo.PostContentLoadedAndInitialize = function(elem)
+{
+ var iframe_id = "";
+
+ if (elem && elem.ownerDocument && elem.ownerDocument.defaultView.window.frameElement)
+ iframe_id = elem.ownerDocument.defaultView.window.frameElement.id;
+ else if (window.frameElement)
+ iframe_id = window.frameElement.id;
+
+ window.webkit.messageHandlers.contentLoaded.postMessage(iframe_id);
+ Evo.Initialize(elem);
+}
+
+if (this instanceof Window && this.document) {
+ this.document.onload = function() { Evo.PostContentLoadedAndInitialize(this); };
+
+ if (this.document.body.firstChild)
+ Evo.PostContentLoadedAndInitialize(this.document);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]