adji

Adji's a Decisive and Joyful Internet browser
git clone https://noxz.tech/git/adji.git
Log | Files | Tags | LICENSE

commit: a04b3e456f992a763edac7bfbd4ee4a161a92d1c
parent: ba55c293c35cd727259f2d40c5e909ee052a7de3
author: Chris Noxz <chris@noxz.tech>
date:   Mon, 20 Mar 2023 14:31:27 +0100
add selection search in ctx menu

This feature requires JavaScript for DOM access, and is tested accordingly
Mbrowser.c69+++++++++++++++++++-
Mbrowser.h25+++++++
2 files changed, 91 insertions(+), 3 deletions(-)
diff --git a/browser.c b/browser.c
@@ -223,8 +223,12 @@ void
 create_context_menu(struct Client *c, WebKitContextMenu *context_menu,
                     WebKitHitTestResult *hit_test_result)
 {
-	GAction                *a;                  /* action: freed when quit */
-	if (webkit_hit_test_result_context_is_link(hit_test_result)) {
+	GAction                *a;                  /* context menu item action */
+	guint                   x;                  /* hit test result context */
+
+	x = webkit_hit_test_result_get_context(hit_test_result);
+
+	if (x & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK) {
 		CB(
 		    (a = (GAction*)g_simple_action_new("open-external", NULL)),
 		    "activate",
@@ -234,10 +238,31 @@ create_context_menu(struct Client *c, WebKitContextMenu *context_menu,
 		webkit_context_menu_insert(
 		    context_menu,
 		    webkit_context_menu_item_new_from_gaction(
-		        a, "Open link externally", NULL
+		        a, "Open Link Externally", NULL
 		    ),
 		    2
 		);
+		g_object_unref(a);
+	}
+
+	if (x & WEBKIT_HIT_TEST_RESULT_CONTEXT_SELECTION) {
+		/* requires javascript for DOM access from here on */
+		if (!webkit_settings_get_enable_javascript(c->settings))
+			return;
+		CB(
+		    (a = (GAction*)g_simple_action_new("selection-search", NULL)),
+		    "activate",
+		    cb_selection_search,
+		    c
+		);
+		webkit_context_menu_insert(
+		    context_menu,
+		    webkit_context_menu_item_new_from_gaction(
+		        a, "Search Selection", NULL
+		    ),
+		    x & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK ? 3 : 1
+		);
+		g_object_unref(a);
 	}
 }
 
@@ -948,6 +973,44 @@ search(struct Client *c, enum inpage_search_type type)
 	}
 }
 
+void
+selection_search(struct Client *c)
+{
+	webkit_web_view_run_javascript(
+	    WEBKIT_WEB_VIEW(c->wv),
+	    "window.getSelection().toString();",
+	    NULL,
+	    cb_selection_search_finished,
+	    c
+	);
+}
+
+void
+selection_search_finished(struct Client *c, GAsyncResult *result)
+{
+	WebKitJavascriptResult *r;
+	JSCValue               *v = NULL;
+	gchar                  *s,
+	                       *u;
+
+	if ((r = webkit_web_view_run_javascript_finish(
+	    WEBKIT_WEB_VIEW(c->wv), result, NULL
+	    )) == NULL)
+		return;
+
+	v = webkit_javascript_result_get_js_value(r);
+
+	if (jsc_value_is_string(v)
+	    && strlen(s = jsc_value_to_string(v))
+	    && !jsc_context_get_exception(jsc_value_get_context(v))
+	    && (u = resolve_uri(s)) != NULL)
+		client_create(u, NULL, TRUE, FALSE);
+
+	webkit_javascript_result_unref(r);
+	g_free(u);
+	g_free(s);
+}
+
 void
 set_default_web_context(void)
 {
diff --git a/browser.h b/browser.h
@@ -215,6 +215,8 @@ static void run_user_scripts(WebKitWebView *);
 static void save_history(const gchar *);
 static void save_state(void);
 static void search(struct Client *, enum inpage_search_type);
+static void selection_search(struct Client *);
+static void selection_search_finished(struct Client *, GAsyncResult *);
 static void set_default_web_context(void);
 static void set_hover_uri(struct Client *, WebKitHitTestResult *);
 static void set_javascript_policy(struct Client *, enum javascript_policy);
@@ -247,6 +249,8 @@ static void cb_notebook_modified(GtkNotebook *, GtkWidget *, guint, gpointer);
 static void cb_notebook_switch_page(GtkNotebook *, GtkWidget *, guint,
                                     gpointer);
 static gboolean cb_open_external(GSimpleAction *, GVariant *, gpointer);
+static gboolean cb_selection_search(GSimpleAction *, GVariant *, gpointer);
+static void cb_selection_search_finished(GObject *, GAsyncResult *, gpointer);
 static void cb_quit(GObject *, gpointer);
 static gboolean cb_tab_hid(GtkWidget *, GdkEvent *, gpointer);
 static void cb_title_changed(GObject *, GParamSpec *, gpointer);
@@ -405,6 +409,27 @@ cb_quit(GObject *obj, gpointer data)
 	quit();
 }
 
+gboolean
+cb_selection_search(GSimpleAction *action, GVariant *parameter, gpointer data)
+{
+	(void)action;
+	(void)parameter;
+
+	selection_search((struct Client *)data);
+	return FALSE;
+}
+
+void
+cb_selection_search_finished(GObject *object, GAsyncResult *result,
+                             gpointer data)
+{
+	struct Client *c = (struct Client *)data;
+
+	(void)object;
+
+	selection_search_finished(c, result);
+}
+
 gboolean
 cb_tab_hid(GtkWidget *widget, GdkEvent *event, gpointer data)
 {