[evolution/wip/mcrha/webkit-jsc-api] Style Sheet related functions



commit 94fe76598331ed4f3c8d18240bf01e3db35ad86b
Author: Milan Crha <mcrha redhat com>
Date:   Wed Sep 25 23:44:32 2019 +0200

    Style Sheet related functions

 src/e-util/e-web-view-jsc-utils.c |  42 +++++++++++++++
 src/e-util/e-web-view-jsc-utils.h |  13 +++++
 src/e-util/e-web-view.c           |   5 ++
 src/e-util/test-web-view.c        | 107 +++++++++++++++++++++++++++++++++++++-
 src/web-extensions/ext-utils.js   | 104 ++++++++++++++++++++++++++++++++++--
 5 files changed, 267 insertions(+), 4 deletions(-)
---
diff --git a/src/e-util/e-web-view-jsc-utils.c b/src/e-util/e-web-view-jsc-utils.c
index 6c68da614f..04df46ecdd 100644
--- a/src/e-util/e-web-view-jsc-utils.c
+++ b/src/e-util/e-web-view-jsc-utils.c
@@ -296,3 +296,45 @@ e_web_view_jsc_set_element_attribute (WebKitWebView *web_view,
 
        webkit_web_view_run_javascript (web_view, script, cancellable, ewv_jsc_call_done_cb, script);
 }
+
+void
+e_web_view_jsc_create_css_style_sheet (WebKitWebView *web_view,
+                                      const gchar *iframe_id,
+                                      const gchar *style_sheet_id,
+                                      const gchar *content,
+                                      GCancellable *cancellable)
+{
+       gchar *script;
+
+       g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view));
+       g_return_if_fail (style_sheet_id != NULL);
+
+       script = e_web_view_jsc_strdup_call ("Evo.CreateCSSStyleSheet(%s,%s,%s)",
+               iframe_id,
+               style_sheet_id,
+               content);
+
+       webkit_web_view_run_javascript (web_view, script, cancellable, ewv_jsc_call_done_cb, script);
+}
+
+void
+e_web_view_jsc_add_css_rule_into_style_sheet (WebKitWebView *web_view,
+                                             const gchar *iframe_id,
+                                             const gchar *style_sheet_id,
+                                             const gchar *selector,
+                                             const gchar *style,
+                                             GCancellable *cancellable)
+{
+       gchar *script;
+
+       g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view));
+       g_return_if_fail (style_sheet_id != NULL);
+
+       script = e_web_view_jsc_strdup_call ("Evo.AddCSSRuleIntoStyleSheet(%s,%s,%s,%s)",
+               iframe_id,
+               style_sheet_id,
+               selector,
+               style);
+
+       webkit_web_view_run_javascript (web_view, script, cancellable, ewv_jsc_call_done_cb, script);
+}
diff --git a/src/e-util/e-web-view-jsc-utils.h b/src/e-util/e-web-view-jsc-utils.h
index c5c4136b1d..6cada9a51d 100644
--- a/src/e-util/e-web-view-jsc-utils.h
+++ b/src/e-util/e-web-view-jsc-utils.h
@@ -67,6 +67,19 @@ void         e_web_view_jsc_set_element_attribute
                                                 const gchar *qualified_name,
                                                 const gchar *value,
                                                 GCancellable *cancellable);
+void           e_web_view_jsc_create_css_style_sheet
+                                               (WebKitWebView *web_view,
+                                                const gchar *iframe_id,
+                                                const gchar *style_sheet_id,
+                                                const gchar *content,
+                                                GCancellable *cancellable);
+void           e_web_view_jsc_add_css_rule_into_style_sheet
+                                               (WebKitWebView *web_view,
+                                                const gchar *iframe_id,
+                                                const gchar *style_sheet_id,
+                                                const gchar *selector,
+                                                const gchar *style,
+                                                GCancellable *cancellable);
 
 G_END_DECLS
 
diff --git a/src/e-util/e-web-view.c b/src/e-util/e-web-view.c
index ccd9bd4b6d..2a22193835 100644
--- a/src/e-util/e-web-view.c
+++ b/src/e-util/e-web-view.c
@@ -1370,6 +1370,11 @@ e_web_view_content_loaded_cb (WebKitUserContentManager *manager,
 
        iframe_id = jsc_value_to_string (jsc_value);
 
+       if (!iframe_id || !*iframe_id) {
+               e_web_view_update_fonts (web_view);
+               style_updated_cb (web_view);
+       }
+
        g_signal_emit (web_view, signals[CONTENT_LOADED], 0, iframe_id);
 
        g_free (iframe_id);
diff --git a/src/e-util/test-web-view.c b/src/e-util/test-web-view.c
index df21bebfaa..e6c4f196d2 100644
--- a/src/e-util/test-web-view.c
+++ b/src/e-util/test-web-view.c
@@ -332,6 +332,25 @@ test_utils_jsc_call_bool_sync (TestFixture *fixture,
        return res;
 }
 
+static gint32
+test_utils_jsc_call_int32_sync (TestFixture *fixture,
+                               const gchar *script)
+{
+       JSCValue *result = NULL;
+       gint32 res;
+
+       test_utils_jsc_call_sync (fixture, script, &result);
+
+       g_assert_nonnull (result);
+       g_assert (jsc_value_is_number (result));
+
+       res = jsc_value_to_int32 (result);
+
+       g_clear_object (&result);
+
+       return res;
+}
+
 static gchar *
 test_utils_jsc_call_string_sync (TestFixture *fixture,
                                 const gchar *script)
@@ -374,7 +393,7 @@ test_utils_jsc_call_string_and_verify (TestFixture *fixture,
 static void
 test_utils_wait_noop (TestFixture *fixture)
 {
-       test_utils_jsc_call_sync (fixture, "document.title", NULL);
+       test_utils_jsc_call_sync (fixture, "javascript:void(0);", NULL);
 }
 
 static void
@@ -692,6 +711,91 @@ test_set_element_attribute (TestFixture *fixture)
        test_utils_jsc_call_string_and_verify (fixture, "Evo.findElement(\"frm2\", 
\"btn2\").getAttributeNS(\"\", \"myattr\")", NULL);
 }
 
+static void
+test_style_sheets (TestFixture *fixture)
+{
+       test_utils_load_body (fixture);
+
+       test_utils_jsc_call_sync (fixture,
+               "var Test = {};\n"
+               "\n"
+               "Test.nStyles = function(iframe_id)\n"
+               "{\n"
+               "       return 
Evo.findIFrameDocument(iframe_id).head.getElementsByTagName(\"style\").length;\n"
+               "}\n"
+               "\n"
+               "Test.getStyle = function(iframe_id, style_sheet_id, selector, property_name)\n"
+               "{\n"
+               "       var styles = Evo.findIFrameDocument(iframe_id).head.getElementsByTagName(\"style\"), 
ii;\n"
+               "\n"
+               "       for (ii = 0; ii < styles.length; ii++) {\n"
+               "               if (styles[ii].id == style_sheet_id) {\n"
+               "                       break;\n"
+               "               }\n"
+               "       }\n"
+               "\n"
+               "       if (ii >= styles.length)\n"
+               "               return null;\n"
+               "\n"
+               "       styles = styles[ii].sheet;\n"
+               "\n"
+               "       for (ii = 0; ii < styles.cssRules.length; ii++) {\n"
+               "               if (styles.cssRules[ii].selectorText == selector) {\n"
+               "                       return styles.cssRules[ii].style.getPropertyValue(property_name);\n"
+               "               }\n"
+               "       }\n"
+               "\n"
+               "       return null;\n"
+               "}\n"
+               "\n"
+               "javascript:void(0);\n",
+               NULL);
+
+       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"\")"));
+       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
+       g_assert_cmpint (0, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
+       g_assert_cmpint (0, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"\", \"sheet1\", \"body\", 
\"color\")", NULL);
+
+       e_web_view_jsc_create_css_style_sheet (fixture->web_view, "", "sheet1", "body { color:green; }", 
NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"\")"));
+       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
+       g_assert_cmpint (0, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
+       g_assert_cmpint (0, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"\", \"sheet1\", \"body\", 
\"color\")", "green");
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm1_1\", \"sheet2\", \"body\", 
\"background-color\")", NULL);
+
+       e_web_view_jsc_add_css_rule_into_style_sheet (fixture->web_view, "frm1_1", "sheet2", "body", 
"background-color:black;", NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"\")"));
+       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
+       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
+       g_assert_cmpint (0, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"\", \"sheet1\", \"body\", 
\"color\")", "green");
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm1_1\", \"sheet2\", \"body\", 
\"background-color\")", "black");
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"\", \"sheet3\", \"body\", 
\"color\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm1\", \"sheet3\", \"body\", 
\"color\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm1_1\", \"sheet3\", \"body\", 
\"color\")", NULL);
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm2\", \"sheet3\", \"body\", 
\"color\")", NULL);
+
+       e_web_view_jsc_add_css_rule_into_style_sheet (fixture->web_view, "*", "sheet3", "body", 
"color:orange;", NULL);
+       test_utils_wait_noop (fixture);
+
+       g_assert_cmpint (3, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"\")"));
+       g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1\")"));
+       g_assert_cmpint (2, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm1_1\")"));
+       g_assert_cmpint (1, ==, test_utils_jsc_call_int32_sync (fixture, "Test.nStyles(\"frm2\")"));
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"\", \"sheet1\", \"body\", 
\"color\")", "green");
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm1_1\", \"sheet2\", \"body\", 
\"background-color\")", "black");
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"\", \"sheet3\", \"body\", 
\"color\")", "orange");
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm1\", \"sheet3\", \"body\", 
\"color\")", "orange");
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm1_1\", \"sheet3\", \"body\", 
\"color\")", "orange");
+       test_utils_jsc_call_string_and_verify (fixture, "Test.getStyle(\"frm2\", \"sheet3\", \"body\", 
\"color\")", "orange");
+}
+
 gint
 main (gint argc,
       gchar *argv[])
@@ -712,6 +816,7 @@ main (gint argc,
        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);
+       test_utils_add_test ("/EWebView/StyleSheets", test_style_sheets);
 
        res = g_test_run ();
 
diff --git a/src/web-extensions/ext-utils.js b/src/web-extensions/ext-utils.js
index 6062e60cc6..275b375aed 100644
--- a/src/web-extensions/ext-utils.js
+++ b/src/web-extensions/ext-utils.js
@@ -32,6 +32,16 @@ Evo.findIFrame = function(iframe_id)
        return Evo.findIFrameInDocument(document, iframe_id);
 }
 
+Evo.findIFrameDocument = function(iframe_id)
+{
+       var iframe = Evo.findIFrame(iframe_id);
+
+       if (iframe)
+               return iframe.contentDocument;
+
+       return document;
+}
+
 Evo.findElement = function(iframe_id, element_id)
 {
        var iframe;
@@ -79,6 +89,83 @@ Evo.SetElementAttribute = function(iframe_id, element_id, namespace_uri, qualifi
        }
 }
 
+Evo.createStyleSheet = function(doc, style_sheet_id, content)
+{
+       var node;
+
+       node = doc.createElement("style");
+       node.id = style_sheet_id;
+       node.media = "screen";
+       node.innerText = content;
+
+       doc.head.append(node);
+
+       return node;
+}
+
+Evo.CreateCSSStyleSheet = function(iframe_id, style_sheet_id, content)
+{
+       var doc = Evo.findIFrameDocument(iframe_id);
+       var styles = doc.head.getElementsByTagName("style"), ii;
+
+       for (ii = 0; ii < styles.length; ii++) {
+               if (styles[ii].id == style_sheet_id) {
+                       styles[ii].innerText = content;
+                       return;
+               }
+       }
+
+       Evo.createStyleSheet(doc, style_sheet_id, content);
+}
+
+Evo.addCSSRuleIntoStyleSheetDocument = function(doc, style_sheet_id, selector, style)
+{
+       var styles = doc.head.getElementsByTagName("style"), ii, styleobj = null;
+
+       for (ii = 0; ii < styles.length; ii++) {
+               if (styles[ii].id == style_sheet_id) {
+                       styleobj = styles[ii];
+                       break;
+               }
+       }
+
+       if (!styleobj) {
+               Evo.createStyleSheet(doc, style_sheet_id, selector + " { " + style + " }");
+               return;
+       }
+
+       for (ii = 0; ii < style.cssRules.length; ii++) {
+               if (style.cssRules[ii].selectorText == selector) {
+                       style.cssRules[ii].style.cssText = style;
+                       return;
+               }
+       }
+}
+
+Evo.addCSSRuleIntoStyleSheetDocumentRecursive = function(doc, style_sheet_id, selector, style)
+{
+       Evo.addCSSRuleIntoStyleSheetDocument(doc, style_sheet_id, selector, style);
+
+       var iframes, ii;
+
+       iframes = doc.getElementsByTagName("iframe");
+
+       for (ii = 0; ii < iframes.length; ii++) {
+               Evo.addCSSRuleIntoStyleSheetDocumentRecursive(iframes[ii].contentDocument, style_sheet_id, 
selector, style);
+       }
+}
+
+Evo.AddCSSRuleIntoStyleSheet = function(iframe_id, style_sheet_id, selector, style)
+{
+       if (iframe_id == "*") {
+               Evo.addCSSRuleIntoStyleSheetDocumentRecursive(document, style_sheet_id, selector, style);
+       } else {
+               var doc = Evo.findIFrameDocument(iframe_id);
+
+               Evo.addCSSRuleIntoStyleSheetDocument(doc, style_sheet_id, selector, style);
+       }
+}
+
 Evo.SetDocumentContent = function(content)
 {
        document.documentElement.innerHTML = content;
@@ -163,16 +250,27 @@ Evo.ElemClicked = function(elem)
 
 Evo.Initialize = function(elem)
 {
-       var elems, ii;
+       var doc, elems, ii;
 
        if (elem && elem instanceof HTMLIFrameElement && elem.contentDocument)
-               elems = elem.contentDocument.getElementsByTagName("iframe");
+               doc = elem.contentDocument;
        else
-               elems = document.getElementsByTagName("iframe");
+               doc = document;
+
+       elems = doc.getElementsByTagName("iframe");
 
        for (ii = 0; ii < elems.length; ii++) {
                elems[ii].onload = function() { Evo.PostContentLoadedAndInitialize(this) };
        }
+
+       if (!doc.body.hasAttribute("class"))
+               doc.body.className = "-e-web-view-background-color -e-web-view-text-color";
+
+       if (doc.documentElement.style.getPropertyValue("color") == "" ||
+           doc.documentElement.style.getPropertyValue("color") == "text") {
+               doc.documentElement.style.setProperty("color", "inherit");
+               doc.documentElement.style.setProperty("background-color", "inherit");
+       }
 }
 
 Evo.PostContentLoadedAndInitialize = function(elem)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]