[evolution/wip/mcrha/webkit-jsc-api] NeedInput and Selection



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]