[epiphany] overview: Use the new JavaScriptCore GLib API instead of DOM API
- From: Carlos Garcia Campos <carlosgc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [epiphany] overview: Use the new JavaScriptCore GLib API instead of DOM API
- Date: Thu, 19 Apr 2018 08:11:40 +0000 (UTC)
commit 095d4b09a7fdd3b314f2f0b2ed58c4617c4a1a82
Author: Carlos Garcia Campos <cgarcia igalia com>
Date: Tue Mar 27 16:59:41 2018 +0200
overview: Use the new JavaScriptCore GLib API instead of DOM API
https://bugzilla.gnome.org/show_bug.cgi?id=794395
embed/ephy-about-handler.c | 21 +-
embed/ephy-embed-shell.c | 38 --
embed/web-extension/ephy-web-extension.c | 60 ++-
embed/web-extension/ephy-web-overview-model.c | 311 +++++++++++---
embed/web-extension/ephy-web-overview-model.h | 10 +-
embed/web-extension/ephy-web-overview.c | 451 --------------------
embed/web-extension/ephy-web-overview.h | 38 --
embed/web-extension/meson.build | 1 -
.../resources/epiphany-web-extension.gresource.xml | 1 +
embed/web-extension/resources/js/overview.js | 225 ++++++++++
10 files changed, 528 insertions(+), 628 deletions(-)
---
diff --git a/embed/ephy-about-handler.c b/embed/ephy-about-handler.c
index 8459c78..1331bcc 100644
--- a/embed/ephy-about-handler.c
+++ b/embed/ephy-about-handler.c
@@ -437,22 +437,7 @@ history_service_query_urls_cb (EphyHistoryService *history,
" <meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n"
" <meta name=\"viewport\" content=\"width=device-width\">"
" <link href=\""EPHY_PAGE_TEMPLATE_ABOUT_CSS "\" rel=\"stylesheet\"
type=\"text/css\">\n"
- " <script>\n"
- " document.onkeypress = function listenKeypress(event) {\n"
- " // Remove from overview when Del is pressed\n"
- " if (event.which == 127) {\n"
- " var focused = document.activeElement;\n"
- " if (focused.className == \"overview-item\") {\n"
- " removeFromOverview(focused, event);\n"
- " }\n"
- " }\n"
- " }\n"
- " function removeFromOverview(elem, event) {\n"
- " event.preventDefault();\n"
- " elem.className +=\" overview-removed \";\n"
- " window.webkit.messageHandlers.overview.postMessage(elem.href);\n"
- " }\n"
- " </script>\n"
+ " <script> </script>\n"
"</head>\n"
"<body>\n",
lang, lang,
@@ -468,7 +453,7 @@ history_service_query_urls_cb (EphyHistoryService *history,
128,
0);
g_string_append_printf (data_str,
- " <div class=\"overview-empty\">\n"
+ " <div id=\"overview\" class=\"overview-empty\">\n"
" <img src=\"file://%s\"/>\n"
" <div><h1>%s</h1></div>\n"
" <div><p>%s</p></div>\n"
@@ -498,7 +483,7 @@ history_service_query_urls_cb (EphyHistoryService *history,
g_string_append_printf (data_str,
"<a class=\"overview-item\" title=\"%s\" href=\"%s\">"
- " <div class=\"overview-close-button\"
onclick=\"removeFromOverview(this.parentNode, event)\" title=\"%s\">✖</div>"
+ " <div class=\"overview-close-button\" title=\"%s\">✖</div>"
" <span class=\"overview-thumbnail\"%s></span>"
" <span class=\"overview-title\">%s</span>"
"</a>",
diff --git a/embed/ephy-embed-shell.c b/embed/ephy-embed-shell.c
index fb3767f..e39655d 100644
--- a/embed/ephy-embed-shell.c
+++ b/embed/ephy-embed-shell.c
@@ -49,7 +49,6 @@
#define PAGE_SETUP_FILENAME "page-setup-gtk.ini"
#define PRINT_SETTINGS_FILENAME "print-settings.ini"
-#define OVERVIEW_RELOAD_DELAY 500
typedef struct {
WebKitWebContext *web_context;
@@ -63,8 +62,6 @@ typedef struct {
EphyDownloadsManager *downloads_manager;
EphyPermissionsManager *permissions_manager;
EphyAboutHandler *about_handler;
- guint update_overview_timeout_id;
- guint hiding_overview_item;
GDBusServer *dbus_server;
GList *web_extensions;
EphyFiltersManager *filters_manager;
@@ -159,11 +156,6 @@ ephy_embed_shell_dispose (GObject *object)
g_clear_object (&priv->cancellable);
}
- if (priv->update_overview_timeout_id > 0) {
- g_source_remove (priv->update_overview_timeout_id);
- priv->update_overview_timeout_id = 0;
- }
-
g_clear_object (&priv->encodings);
g_clear_object (&priv->page_setup);
g_clear_object (&priv->print_settings);
@@ -275,37 +267,15 @@ history_service_urls_visited_cb (EphyHistoryService *history,
ephy_embed_shell_update_overview_urls (shell);
}
-static gboolean
-ephy_embed_shell_update_overview_timeout_cb (EphyEmbedShell *shell)
-{
- EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
-
- priv->update_overview_timeout_id = 0;
-
- if (priv->hiding_overview_item > 0)
- return FALSE;
-
- ephy_embed_shell_update_overview_urls (shell);
-
- return FALSE;
-}
-
static void
history_set_url_hidden_cb (EphyHistoryService *service,
gboolean success,
gpointer result_data,
EphyEmbedShell *shell)
{
- EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
-
- priv->hiding_overview_item--;
-
if (!success)
return;
- if (priv->update_overview_timeout_id > 0)
- return;
-
ephy_embed_shell_update_overview_urls (shell);
}
@@ -319,19 +289,11 @@ web_extension_overview_message_received_cb (WebKitUserContentManager *manager,
url_to_remove = jsc_value_to_string (webkit_javascript_result_get_js_value (message));
- priv->hiding_overview_item++;
ephy_history_service_set_url_hidden (priv->global_history_service,
url_to_remove, TRUE, NULL,
(EphyHistoryJobCallback)history_set_url_hidden_cb,
shell);
g_free (url_to_remove);
-
- if (priv->update_overview_timeout_id > 0)
- g_source_remove (priv->update_overview_timeout_id);
-
- /* Wait for the CSS animations to finish before refreshing */
- priv->update_overview_timeout_id =
- g_timeout_add (OVERVIEW_RELOAD_DELAY, (GSourceFunc)ephy_embed_shell_update_overview_timeout_cb, shell);
}
static void
diff --git a/embed/web-extension/ephy-web-extension.c b/embed/web-extension/ephy-web-extension.c
index 3987cd6..3e3db73 100644
--- a/embed/web-extension/ephy-web-extension.c
+++ b/embed/web-extension/ephy-web-extension.c
@@ -33,9 +33,10 @@
#include "ephy-sync-utils.h"
#include "ephy-uri-helpers.h"
#include "ephy-uri-tester.h"
-#include "ephy-web-overview.h"
+#include "ephy-web-overview-model.h"
#include <gio/gio.h>
+#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <jsc/jsc.h>
#include <libsoup/soup.h>
@@ -393,19 +394,6 @@ web_page_form_controls_associated (WebKitWebPage *web_page,
g_object_unref (js_context);
}
-static void
-web_page_uri_changed (WebKitWebPage *web_page,
- GParamSpec *param_spec,
- EphyWebExtension *extension)
-{
- EphyWebOverview *overview = NULL;
-
- if (g_strcmp0 (webkit_web_page_get_uri (web_page), "ephy-about:overview") == 0)
- overview = ephy_web_overview_new (web_page, extension->overview_model);
-
- g_object_set_data_full (G_OBJECT (web_page), "ephy-web-overview", overview, g_object_unref);
-}
-
static gboolean
web_page_context_menu (WebKitWebPage *web_page,
WebKitContextMenu *context_menu,
@@ -505,9 +493,6 @@ ephy_web_extension_page_created_cb (EphyWebExtension *extension,
g_signal_connect (web_page, "send-request",
G_CALLBACK (web_page_send_request),
extension);
- g_signal_connect (web_page, "notify::uri",
- G_CALLBACK (web_page_uri_changed),
- extension);
g_signal_connect (web_page, "context-menu",
G_CALLBACK (web_page_context_menu),
extension);
@@ -583,7 +568,7 @@ handle_method_call (GDBusConnection *connection,
const char *path;
g_variant_get (parameters, "(&s&s)", &url, &path);
- ephy_web_overview_model_set_url_thumbnail (extension->overview_model, url, path);
+ ephy_web_overview_model_set_url_thumbnail (extension->overview_model, url, path, TRUE);
}
g_dbus_method_invocation_return_value (invocation, NULL);
} else if (g_strcmp0 (method_name, "HistorySetURLTitle") == 0) {
@@ -808,6 +793,12 @@ js_log (const char *message)
LOG ("%s", message);
}
+static char *
+js_gettext (const char *message)
+{
+ return g_strdup (g_dgettext (GETTEXT_PACKAGE, message));
+}
+
static void
js_auto_fill (JSCValue *js_element,
const char *value)
@@ -883,6 +874,39 @@ window_object_cleared_cb (WebKitScriptWorld *world,
jsc_value_object_set_property (js_ephy, "log", js_function);
g_object_unref (js_function);
+ js_function = jsc_value_new_function (js_context,
+ "gettext",
+ G_CALLBACK (js_gettext), NULL, NULL,
+ G_TYPE_STRING, 1,
+ G_TYPE_STRING);
+ jsc_value_object_set_property (js_ephy, "_", js_function);
+ g_object_unref (js_function);
+
+ if (g_strcmp0 (webkit_web_page_get_uri (page), "ephy-about:overview") == 0) {
+ JSCValue *js_overview;
+ JSCValue *js_overview_ctor;
+ JSCValue *jsc_overview_model;
+
+ bytes = g_resources_lookup_data ("/org/gnome/epiphany-web-extension/js/overview.js",
G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
+ data = g_bytes_get_data (bytes, &data_size);
+ result = jsc_context_evaluate_with_source_uri (js_context, data, data_size,
"resource:///org/gnome/epiphany-web-extension/js/overview.js");
+ g_bytes_unref (bytes);
+ g_object_unref (result);
+
+ jsc_overview_model = ephy_web_overview_model_export_to_js_context (extension->overview_model,
+ js_context);
+
+ js_overview_ctor = jsc_value_object_get_property (js_ephy, "Overview");
+ js_overview = jsc_value_constructor_call (js_overview_ctor,
+ JSC_TYPE_VALUE, jsc_overview_model,
+ G_TYPE_NONE);
+ jsc_value_object_set_property (js_ephy, "overview", js_overview);
+
+ g_object_unref (js_overview);
+ g_object_unref (jsc_overview_model);
+ g_object_unref (js_overview_ctor);
+ }
+
ephy_permissions_manager_export_to_js_context (extension->permissions_manager,
js_context,
js_ephy);
diff --git a/embed/web-extension/ephy-web-overview-model.c b/embed/web-extension/ephy-web-overview-model.c
index 606e213..3acd921 100644
--- a/embed/web-extension/ephy-web-overview-model.c
+++ b/embed/web-extension/ephy-web-overview-model.c
@@ -28,19 +28,13 @@ struct _EphyWebOverviewModel {
GList *items;
GHashTable *thumbnails;
-};
-
-G_DEFINE_TYPE (EphyWebOverviewModel, ephy_web_overview_model, G_TYPE_OBJECT)
-enum {
- URLS_CHANGED,
- THUMBNAIL_CHANGED,
- TITLE_CHANGED,
-
- LAST_SIGNAL
+ GHashTable *urls_listeners;
+ GHashTable *thumbnail_listeners;
+ GHashTable *title_listeners;
};
-static guint signals[LAST_SIGNAL];
+G_DEFINE_TYPE (EphyWebOverviewModel, ephy_web_overview_model, G_TYPE_OBJECT)
static void
ephy_web_overview_model_dispose (GObject *object)
@@ -57,6 +51,10 @@ ephy_web_overview_model_dispose (GObject *object)
model->thumbnails = NULL;
}
+ g_clear_pointer (&model->urls_listeners, g_hash_table_destroy);
+ g_clear_pointer (&model->thumbnail_listeners, g_hash_table_destroy);
+ g_clear_pointer (&model->title_listeners, g_hash_table_destroy);
+
G_OBJECT_CLASS (ephy_web_overview_model_parent_class)->dispose (object);
}
@@ -66,31 +64,6 @@ ephy_web_overview_model_class_init (EphyWebOverviewModelClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = ephy_web_overview_model_dispose;
-
- signals[URLS_CHANGED] =
- g_signal_new ("urls-changed",
- EPHY_TYPE_WEB_OVERVIEW_MODEL,
- G_SIGNAL_RUN_LAST,
- 0, NULL, NULL, NULL,
- G_TYPE_NONE, 0);
-
- signals[THUMBNAIL_CHANGED] =
- g_signal_new ("thumbnail-changed",
- EPHY_TYPE_WEB_OVERVIEW_MODEL,
- G_SIGNAL_RUN_LAST,
- 0, NULL, NULL, NULL,
- G_TYPE_NONE, 2,
- G_TYPE_STRING,
- G_TYPE_STRING);
-
- signals[TITLE_CHANGED] =
- g_signal_new ("title-changed",
- EPHY_TYPE_WEB_OVERVIEW_MODEL,
- G_SIGNAL_RUN_LAST,
- 0, NULL, NULL, NULL,
- G_TYPE_NONE, 2,
- G_TYPE_STRING,
- G_TYPE_STRING);
}
static void
@@ -100,6 +73,112 @@ ephy_web_overview_model_init (EphyWebOverviewModel *model)
g_str_equal,
(GDestroyNotify)g_free,
(GDestroyNotify)g_free);
+ model->urls_listeners = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ g_object_unref,
+ NULL);
+ model->thumbnail_listeners = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ g_object_unref,
+ NULL);
+ model->title_listeners = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ g_object_unref,
+ NULL);
+}
+
+static GPtrArray *
+ephy_web_overview_model_urls_to_js_value (EphyWebOverviewModel *model,
+ JSCContext *js_context)
+{
+ GPtrArray *urls;
+ GList *l;
+
+ urls = g_ptr_array_new_with_free_func (g_object_unref);
+ for (l = model->items; l; l = g_list_next (l)) {
+ EphyWebOverviewModelItem *item = (EphyWebOverviewModelItem *)l->data;
+ JSCValue *js_item, *value;
+
+ js_item = jsc_value_new_object (js_context, NULL, NULL);
+ value = jsc_value_new_string (js_context, item->url);
+ jsc_value_object_set_property (js_item, "url", value);
+ g_object_unref (value);
+
+ value = jsc_value_new_string (js_context, item->title);
+ jsc_value_object_set_property (js_item, "title", value);
+ g_object_unref (value);
+
+ g_ptr_array_add (urls, js_item);
+ }
+
+ return urls;
+}
+
+static void
+ephy_web_overview_model_notify_urls_changed (EphyWebOverviewModel *model)
+{
+ GHashTableIter iter;
+ gpointer key;
+ GPtrArray *urls = NULL;
+
+ g_hash_table_iter_init (&iter, model->urls_listeners);
+ while (g_hash_table_iter_next (&iter, &key, NULL)) {
+ JSCValue *value;
+
+ value = jsc_weak_value_get_value (JSC_WEAK_VALUE (key));
+ if (value && jsc_value_is_function (value)) {
+ if (!urls)
+ urls = ephy_web_overview_model_urls_to_js_value (model, jsc_value_get_context (value));
+ jsc_value_function_call (value, G_TYPE_PTR_ARRAY, urls, G_TYPE_NONE);
+ }
+ if (value)
+ g_object_unref (value);
+ }
+
+ if (urls)
+ g_ptr_array_unref (urls);
+}
+
+static void
+ephy_web_overview_model_notify_thumbnail_changed (EphyWebOverviewModel *model,
+ const char *url,
+ const char *path)
+{
+ GHashTableIter iter;
+ gpointer key;
+
+ g_hash_table_iter_init (&iter, model->thumbnail_listeners);
+ while (g_hash_table_iter_next (&iter, &key, NULL)) {
+ JSCValue *value;
+
+ value = jsc_weak_value_get_value (JSC_WEAK_VALUE (key));
+ if (value) {
+ if (jsc_value_is_function (value))
+ jsc_value_function_call (value, G_TYPE_STRING, url, G_TYPE_STRING, path, G_TYPE_NONE);
+ g_object_unref (value);
+ }
+ }
+}
+
+static void
+ephy_web_overview_model_notify_title_changed (EphyWebOverviewModel *model,
+ const char *url,
+ const char *title)
+{
+ GHashTableIter iter;
+ gpointer key;
+
+ g_hash_table_iter_init (&iter, model->title_listeners);
+ while (g_hash_table_iter_next (&iter, &key, NULL)) {
+ JSCValue *value;
+
+ value = jsc_weak_value_get_value (JSC_WEAK_VALUE (key));
+ if (value) {
+ if (jsc_value_is_function (value))
+ jsc_value_function_call (value, G_TYPE_STRING, url, G_TYPE_STRING, title, G_TYPE_NONE);
+ g_object_unref (value);
+ }
+ }
}
EphyWebOverviewModel *
@@ -116,41 +195,26 @@ ephy_web_overview_model_set_urls (EphyWebOverviewModel *model,
g_list_free_full (model->items, (GDestroyNotify)ephy_web_overview_model_item_free);
model->items = urls;
- g_signal_emit (model, signals[URLS_CHANGED], 0);
-}
-
-GList *
-ephy_web_overview_model_get_urls (EphyWebOverviewModel *model)
-{
- g_assert (EPHY_IS_WEB_OVERVIEW_MODEL (model));
-
- return model->items;
+ ephy_web_overview_model_notify_urls_changed (model);
}
void
ephy_web_overview_model_set_url_thumbnail (EphyWebOverviewModel *model,
const char *url,
- const char *path)
+ const char *path,
+ gboolean notify)
{
const char *thumbnail_path;
g_assert (EPHY_IS_WEB_OVERVIEW_MODEL (model));
- thumbnail_path = ephy_web_overview_model_get_url_thumbnail (model, url);
+ thumbnail_path = g_hash_table_lookup (model->thumbnails, url);
if (g_strcmp0 (thumbnail_path, path) == 0)
return;
g_hash_table_insert (model->thumbnails, g_strdup (url), g_strdup (path));
- g_signal_emit (model, signals[THUMBNAIL_CHANGED], 0, url, path);
-}
-
-const char *
-ephy_web_overview_model_get_url_thumbnail (EphyWebOverviewModel *model,
- const char *url)
-{
- g_assert (EPHY_IS_WEB_OVERVIEW_MODEL (model));
-
- return g_hash_table_lookup (model->thumbnails, url);
+ if (notify)
+ ephy_web_overview_model_notify_thumbnail_changed (model, url, path);
}
void
@@ -178,7 +242,7 @@ ephy_web_overview_model_set_url_title (EphyWebOverviewModel *model,
}
if (changed)
- g_signal_emit (model, signals[TITLE_CHANGED], 0, url, title);
+ ephy_web_overview_model_notify_title_changed (model, url, title);
}
void
@@ -206,7 +270,7 @@ ephy_web_overview_model_delete_url (EphyWebOverviewModel *model,
}
if (changed)
- g_signal_emit (model, signals[URLS_CHANGED], 0);
+ ephy_web_overview_model_notify_urls_changed (model);
}
void
@@ -236,7 +300,7 @@ ephy_web_overview_model_delete_host (EphyWebOverviewModel *model,
}
if (changed)
- g_signal_emit (model, signals[URLS_CHANGED], 0);
+ ephy_web_overview_model_notify_urls_changed (model);
}
void
@@ -249,7 +313,7 @@ ephy_web_overview_model_clear (EphyWebOverviewModel *model)
g_list_free_full (model->items, (GDestroyNotify)ephy_web_overview_model_item_free);
model->items = NULL;
- g_signal_emit (model, signals[URLS_CHANGED], 0);
+ ephy_web_overview_model_notify_urls_changed (model);
}
EphyWebOverviewModelItem *
@@ -276,3 +340,130 @@ ephy_web_overview_model_item_free (EphyWebOverviewModelItem *item)
g_slice_free (EphyWebOverviewModelItem, item);
}
+
+static void
+js_web_overview_model_set_thumbnail (EphyWebOverviewModel *model,
+ const char *url,
+ const char *path)
+{
+ ephy_web_overview_model_set_url_thumbnail (model, url, path, FALSE);
+}
+
+static char *
+js_web_overview_model_get_thumbnail (EphyWebOverviewModel *model,
+ const char *url)
+{
+ return g_strdup (g_hash_table_lookup (model->thumbnails, url));
+}
+
+static GPtrArray *
+js_web_overview_model_get_urls (EphyWebOverviewModel *model)
+{
+ return ephy_web_overview_model_urls_to_js_value (model, jsc_context_get_current ());
+}
+
+static void
+js_event_listener_destroyed (JSCWeakValue *weak_value,
+ GHashTable *listeners)
+{
+ g_hash_table_remove (listeners, weak_value);
+}
+
+static void
+js_web_overview_model_add_urls_changed_event_listener (EphyWebOverviewModel *model,
+ JSCValue *js_function)
+{
+ JSCWeakValue *weak_value;
+
+ if (!jsc_value_is_function (js_function)) {
+ jsc_context_throw (jsc_context_get_current (), "Invalid type passed to onurlschanged");
+ return;
+ }
+
+ weak_value = jsc_weak_value_new (js_function);
+ g_signal_connect (weak_value, "cleared",
+ G_CALLBACK (js_event_listener_destroyed),
+ model->urls_listeners);
+ g_hash_table_add (model->urls_listeners, weak_value);
+}
+
+static void
+js_web_overview_model_add_thumbnail_changed_event_listener (EphyWebOverviewModel *model,
+ JSCValue *js_function)
+{
+ JSCWeakValue *weak_value;
+
+ if (!jsc_value_is_function (js_function)) {
+ jsc_context_throw (jsc_context_get_current (), "Invalid type passed to onthumbnailchanged");
+ return;
+ }
+
+ weak_value = jsc_weak_value_new (js_function);
+ g_signal_connect (weak_value, "cleared",
+ G_CALLBACK (js_event_listener_destroyed),
+ model->thumbnail_listeners);
+ g_hash_table_add (model->thumbnail_listeners, weak_value);
+}
+
+static void
+js_web_overview_model_add_title_changed_event_listener (EphyWebOverviewModel *model,
+ JSCValue *js_function)
+{
+ JSCWeakValue *weak_value;
+
+ if (!jsc_value_is_function (js_function)) {
+ jsc_context_throw (jsc_context_get_current (), "Invalid type passed to ontitlechanged");
+ return;
+ }
+
+ weak_value = jsc_weak_value_new (js_function);
+ g_signal_connect (weak_value, "cleared",
+ G_CALLBACK (js_event_listener_destroyed),
+ model->title_listeners);
+ g_hash_table_add (model->title_listeners, weak_value);
+}
+
+JSCValue *
+ephy_web_overview_model_export_to_js_context (EphyWebOverviewModel *model,
+ JSCContext *js_context)
+{
+ JSCClass *js_class;
+
+ js_class = jsc_context_register_class (js_context, "OverviewModel", NULL, NULL, NULL);
+ jsc_class_add_method (js_class,
+ "setThumbnail",
+ G_CALLBACK (js_web_overview_model_set_thumbnail), NULL, NULL,
+ G_TYPE_NONE, 2,
+ G_TYPE_STRING, G_TYPE_STRING);
+ jsc_class_add_method (js_class,
+ "getThumbnail",
+ G_CALLBACK (js_web_overview_model_get_thumbnail), NULL, NULL,
+ G_TYPE_STRING, 1,
+ G_TYPE_STRING);
+ jsc_class_add_property (js_class,
+ "urls",
+ G_TYPE_PTR_ARRAY,
+ G_CALLBACK (js_web_overview_model_get_urls),
+ NULL,
+ NULL, NULL);
+ jsc_class_add_property (js_class,
+ "onurlschanged",
+ JSC_TYPE_VALUE,
+ NULL,
+ G_CALLBACK (js_web_overview_model_add_urls_changed_event_listener),
+ NULL, NULL);
+ jsc_class_add_property (js_class,
+ "onthumbnailchanged",
+ JSC_TYPE_VALUE,
+ NULL,
+ G_CALLBACK (js_web_overview_model_add_thumbnail_changed_event_listener),
+ NULL, NULL);
+ jsc_class_add_property (js_class,
+ "ontitlechanged",
+ JSC_TYPE_VALUE,
+ NULL,
+ G_CALLBACK (js_web_overview_model_add_title_changed_event_listener),
+ NULL, NULL);
+
+ return jsc_value_new_object (js_context, model, js_class);
+}
diff --git a/embed/web-extension/ephy-web-overview-model.h b/embed/web-extension/ephy-web-overview-model.h
index 5fb6a6d..df8dcd8 100644
--- a/embed/web-extension/ephy-web-overview-model.h
+++ b/embed/web-extension/ephy-web-overview-model.h
@@ -21,6 +21,7 @@
#pragma once
#include <glib-object.h>
+#include <jsc/jsc.h>
G_BEGIN_DECLS
@@ -31,12 +32,10 @@ G_DECLARE_FINAL_TYPE (EphyWebOverviewModel, ephy_web_overview_model, EPHY, WEB_O
EphyWebOverviewModel *ephy_web_overview_model_new (void);
void ephy_web_overview_model_set_urls (EphyWebOverviewModel *model,
GList *urls);
-GList *ephy_web_overview_model_get_urls (EphyWebOverviewModel *model);
void ephy_web_overview_model_set_url_thumbnail (EphyWebOverviewModel *model,
const char *url,
- const char *path);
-const char *ephy_web_overview_model_get_url_thumbnail (EphyWebOverviewModel *model,
- const char *url);
+ const char *path,
+ gboolean notify);
void ephy_web_overview_model_set_url_title (EphyWebOverviewModel *model,
const char *url,
const char *title);
@@ -58,4 +57,7 @@ EphyWebOverviewModelItem *ephy_web_overview_model_item_new (const char
const char *title);
void ephy_web_overview_model_item_free (EphyWebOverviewModelItem *item);
+JSCValue *ephy_web_overview_model_export_to_js_context (EphyWebOverviewModel *model,
+ JSCContext *js_context);
+
G_END_DECLS
diff --git a/embed/web-extension/meson.build b/embed/web-extension/meson.build
index 06368d9..ad2b272 100644
--- a/embed/web-extension/meson.build
+++ b/embed/web-extension/meson.build
@@ -9,7 +9,6 @@ web_extension_sources = [
'ephy-uri-tester.c',
'ephy-web-extension.c',
'ephy-web-extension-main.c',
- 'ephy-web-overview.c',
'ephy-web-overview-model.c',
resources
]
diff --git a/embed/web-extension/resources/epiphany-web-extension.gresource.xml
b/embed/web-extension/resources/epiphany-web-extension.gresource.xml
index 657d576..97166cf 100644
--- a/embed/web-extension/resources/epiphany-web-extension.gresource.xml
+++ b/embed/web-extension/resources/epiphany-web-extension.gresource.xml
@@ -2,5 +2,6 @@
<gresources>
<gresource prefix="/org/gnome/epiphany-web-extension">
<file compressed="true">js/ephy.js</file>
+ <file compressed="true">js/overview.js</file>
</gresource>
</gresources>
diff --git a/embed/web-extension/resources/js/overview.js b/embed/web-extension/resources/js/overview.js
new file mode 100644
index 0000000..ced2ee6
--- /dev/null
+++ b/embed/web-extension/resources/js/overview.js
@@ -0,0 +1,225 @@
+Ephy.Overview = class Overview
+{
+ constructor(model)
+ {
+ this._model = model;
+ this._items = [];
+
+ // Event handlers are weak references in EphyWebOverviewModel, we need to keep
+ // a strong reference to them while Ephy.Overview is alive.
+ this._onURLsChangedFunction = this._onURLsChanged.bind(this);
+ this._model.onurlschanged = this._onURLsChangedFunction;
+ this._onThumbnailChangedFunction = this._onThumbnailChanged.bind(this);
+ this._model.onthumbnailchanged = this._onThumbnailChangedFunction;
+ this._onTitleChangedFunction = this._onTitleChanged.bind(this);
+ this._model.ontitlechanged = this._onTitleChangedFunction;
+ document.addEventListener('DOMContentLoaded', this._initialize.bind(this), false);
+ document.addEventListener('keypress', this._onKeyPress.bind(this), false);
+ }
+
+ // Private
+
+ _initialize()
+ {
+ let anchors = document.getElementsByTagName('a');
+ for (let i = 0; i < anchors.length; i++) {
+ let anchor = anchors[i];
+ if (anchor.className != 'overview-item')
+ continue;
+
+ let item = new Ephy.Overview.Item(anchor);
+
+ let closeButton = anchor.getElementsByClassName('overview-close-button')[0];
+ closeButton.onclick = (event) => {
+ this._removeItem(anchor);
+ event.preventDefault();
+ };
+
+ // URLs and titles are always sent from the UI process, but thumbnails
+ // aren't, so update the model with the thumbnail if there's one.
+ let thumbnailPath = item.thumbnailPath();
+ if (thumbnailPath)
+ this._model.setThumbnail(item.url(), thumbnailPath);
+ else
+ item.setThumbnailPath(this._model.getThumbnail(item.url()));
+
+ this._items.push(item);
+ }
+ let items = this._model.urls;
+ if (items.length > this._items.length)
+ this._onURLsChanged(items);
+ }
+
+ _onKeyPress(event)
+ {
+ if (event.which != 127)
+ return;
+
+ let item = document.activeElement;
+ if (item.classList.contains('overview-item')) {
+ this._removeItem(item);
+ event.preventDefault();
+ }
+ }
+
+ _removeItem(item)
+ {
+ item.classList.add('overview-removed');
+ // Animation takes 0.75s, remove the item after 1s to ensure the animation finished.
+ setTimeout(() => {
+ item.parentNode.removeChild(item);
+ for (let i = 0; i < this._items.length; i++) {
+ if (this._items[i].url() == item.href) {
+ this._items.splice(i, 1);
+ break;
+ }
+ }
+ window.webkit.messageHandlers.overview.postMessage(item.href);
+ }, 1000);
+ }
+
+ _onURLsChanged(urls)
+ {
+ let overview = document.getElementById('overview');
+ if (overview.classList.contains('overview-empty')) {
+ while (overview.lastChild)
+ overview.removeChild(overview.lastChild);
+ overview.classList.remove('overview-empty');
+ }
+
+ for (let i = 0; i < urls.length; i++) {
+ let url = urls[i];
+
+ let item;
+ if (this._items[i]) {
+ item = this._items[i];
+ } else {
+ Ephy.log('create an item for the url ' + url.url);
+ let anchor = document.createElement('a');
+ anchor.classList.add('overview-item');
+ let closeButton = document.createElement('div');
+ closeButton.title = Ephy._("Remove from overview");
+ closeButton.onclick = (event) => {
+ this._removeItem(anchor);
+ event.preventDefault();
+ };
+ closeButton.innerHTML = '✖';
+ closeButton.classList.add('overview-close-button');
+ anchor.appendChild(closeButton);
+ let thumbnailSpan = document.createElement('span');
+ thumbnailSpan.classList.add('overview-thumbnail');
+ anchor.appendChild(thumbnailSpan);
+ let titleSpan = document.createElement('span');
+ titleSpan.classList.add('overview-title');
+ anchor.appendChild(titleSpan);
+ document.getElementById('overview').appendChild(anchor);
+ item = new Ephy.Overview.Item(anchor);
+ this._items.push(item);
+ }
+
+ item.setURL(url.url);
+ item.setTitle(url.title);
+ item.setThumbnailPath(this._model.getThumbnail(url.url));
+ }
+
+ while (this._items.length > urls.length) {
+ let item = this._items.pop();
+ item.detachFromParent();
+ }
+ }
+
+ _onThumbnailChanged(url, path)
+ {
+ for (let i = 0; i < this._items.length; i++) {
+ let item = this._items[i];
+ if (item.url() == url) {
+ item.setThumbnailPath(path);
+ return;
+ }
+ }
+ }
+
+ _onTitleChanged(url, title)
+ {
+ for (let i = 0; i < this._items.length; i++) {
+ let item = this._items[i];
+ if (item.url() == url) {
+ item.setTitle(title);
+ return;
+ }
+ }
+ }
+};
+
+Ephy.Overview.Item = class OverviewItem
+{
+ constructor(item)
+ {
+ this._item = item;
+ this._title = null;
+ this._thumbnail = null;
+
+ for (let i = 0; i < this._item.childNodes.length; i++) {
+ let child = this._item.childNodes[i];
+ if (!(child instanceof Element))
+ continue;
+
+ if (child.classList.contains('overview-title'))
+ this._title = child;
+ else if (child.classList.contains('overview-thumbnail'))
+ this._thumbnail = child;
+ }
+ }
+
+ // Public
+
+ url()
+ {
+ return this._item.href;
+ }
+
+ setURL(url)
+ {
+ this._item.href = url;
+ }
+
+ title()
+ {
+ return this._item.title;
+ }
+
+ setTitle(title)
+ {
+ this._item.title = title;
+ this._title.textContent = title;
+ }
+
+ thumbnailPath()
+ {
+ let style = this._thumbnail.style;
+ if (style.isPropertyImplicit('background'))
+ return null;
+
+ let background = style.getPropertyValue('background');
+ if (!background)
+ return null;
+
+ if (background.startsWith('url(file://'))
+ return background.replace('url(file://', '').replace(') no-repeat', '');
+
+ return null;
+ }
+
+ setThumbnailPath(path)
+ {
+ if (path)
+ this._thumbnail.style.background = 'url(file://' + path + ') no-repeat';
+ else
+ this._thumbnail.style.background = null;
+ }
+
+ detachFromParent()
+ {
+ this._item.parentNode.removeChild(this._item);
+ }
+};
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]