[evolution/wip/mcrha/webkit-jsc-api] Added named params object/array functions and test, with elementClicked callback



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]