diff options
author | Marcos ChavarrÃa Teijeiro <chavarria1991@gmail.com> | 2014-10-21 12:45:42 +0200 |
---|---|---|
committer | David King <amigadave@amigadave.com> | 2015-02-16 20:00:56 +0000 |
commit | 58dfe5f6d6da94b3d4455386b8ace8900a9fb475 (patch) | |
tree | e74803561cf096ec69f05d938ebdc7d2666395ce | |
parent | aef8f4da00070af48dd8a2c37d5dc1b17e02aed9 (diff) | |
download | yelp-58dfe5f6d6da94b3d4455386b8ace8900a9fb475.tar.gz |
yelp-view: Implement web extension to deal with DOM tree
-rw-r--r-- | configure.ac | 5 | ||||
-rw-r--r-- | libyelp/Makefile.am | 5 | ||||
-rw-r--r-- | libyelp/web-extension/Makefile.am | 8 | ||||
-rw-r--r-- | libyelp/web-extension/yelp-web-extension.c | 144 | ||||
-rw-r--r-- | libyelp/yelp-view.c | 140 |
5 files changed, 214 insertions, 88 deletions
diff --git a/configure.ac b/configure.ac index 75e58257..5c3562e5 100644 --- a/configure.ac +++ b/configure.ac @@ -46,6 +46,10 @@ AX_COMPILER_FLAGS([], [], [$ax_is_release]) LT_PREREQ([2.2.6]) LT_INIT +PKG_CHECK_MODULES([YELP_EXTENSION], [webkit2gtk-web-extension-4.0 >= 2.7.2]) +AC_SUBST(YELP_EXTENSION_CFLAGS) +AC_SUBST(YELP_EXTENSION_LIBS) + # i18n stuff AX_REQUIRE_DEFINED([IT_PROG_INTLTOOL]) IT_PROG_INTLTOOL([0.41.0]) @@ -216,6 +220,7 @@ data/xslt/man2html.xsl data/xslt/yelp-common.xsl po/Makefile.in tests/Makefile +libyelp/web-extension/Makefile yelp.desktop.in ]) diff --git a/libyelp/Makefile.am b/libyelp/Makefile.am index 0ae9d607..e721fd5a 100644 --- a/libyelp/Makefile.am +++ b/libyelp/Makefile.am @@ -1,3 +1,5 @@ +SUBDIRS = web-extension + lib_LTLIBRARIES = libyelp.la libyelp_la_SOURCES = \ @@ -53,6 +55,9 @@ libyelp_la_CFLAGS = \ -DDATADIR=\""$(datadir)"\" \ -DYELP_ICON_PATH=\"$(YELP_ICON_PATH)\" +libyelp_la_CPPFLAGS = \ + -DYELP_WEB_EXTENSIONS_DIR=\""$(pkglibdir)/"web-extensions\" + libyelp_la_LIBADD = $(YELP_LIBS) libyelp_headers = \ diff --git a/libyelp/web-extension/Makefile.am b/libyelp/web-extension/Makefile.am new file mode 100644 index 00000000..0cafe7af --- /dev/null +++ b/libyelp/web-extension/Makefile.am @@ -0,0 +1,8 @@ + +webextension_LTLIBRARIES = libyelpwebextension.la +webextensiondir = $(pkglibdir)/web-extensions + +libyelpwebextension_la_SOURCES = yelp-web-extension.c +libyelpwebextension_la_CFLAGS = $(YELP_EXTENSION_CFLAGS) +libyelpwebextension_la_LIBADD = $(YELP_EXTENSION_LIBS) +libyelpwebextension_la_LDFLAGS = -module -avoid-version -no-undefined diff --git a/libyelp/web-extension/yelp-web-extension.c b/libyelp/web-extension/yelp-web-extension.c new file mode 100644 index 00000000..76ef1158 --- /dev/null +++ b/libyelp/web-extension/yelp-web-extension.c @@ -0,0 +1,144 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * Copyright (C) 2014 Igalia S.L. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <webkit2/webkit-web-extension.h> +#include <string.h> + +#define WEBKIT_DOM_USE_UNSTABLE_API +#include <webkitdom/WebKitDOMElementUnstable.h> + +static gboolean +web_page_context_menu (WebKitWebPage *web_page, + WebKitContextMenu *context_menu, + WebKitWebHitTestResult *hit_test_result) +{ + WebKitDOMNode *node, *cur, *link_node = NULL, *code_node = NULL, *code_title_node = NULL; + gchar *popup_link_text = NULL; + GVariantDict user_data_dict; + + node = webkit_web_hit_test_result_get_node (hit_test_result); + + for (cur = node; cur != NULL; cur = webkit_dom_node_get_parent_node (cur)) { + if (WEBKIT_DOM_IS_ELEMENT (cur) && + webkit_dom_element_webkit_matches_selector (WEBKIT_DOM_ELEMENT (cur), + "a", NULL)) + link_node = cur; + + if (WEBKIT_DOM_IS_ELEMENT (cur) && + webkit_dom_element_webkit_matches_selector (WEBKIT_DOM_ELEMENT (cur), + "div.code", NULL)) { + WebKitDOMNode *title; + code_node = WEBKIT_DOM_NODE ( + webkit_dom_element_query_selector (WEBKIT_DOM_ELEMENT (cur), + "pre.contents", NULL)); + title = webkit_dom_node_get_parent_node (cur); + if (WEBKIT_DOM_IS_ELEMENT (title) && + webkit_dom_element_webkit_matches_selector (WEBKIT_DOM_ELEMENT (title), + "div.contents", NULL)) { + title = webkit_dom_node_get_previous_sibling (title); + if (WEBKIT_DOM_IS_ELEMENT (title) && + webkit_dom_element_webkit_matches_selector (WEBKIT_DOM_ELEMENT (title), + "div.title", NULL)) { + code_title_node = title; + } + } + } + } + + if (webkit_hit_test_result_context_is_link (WEBKIT_HIT_TEST_RESULT (hit_test_result)) && link_node) { + WebKitDOMNode *child; + gchar *tmp; + gint i, tmpi; + gboolean ws; + + child = WEBKIT_DOM_NODE ( + webkit_dom_element_query_selector (WEBKIT_DOM_ELEMENT (link_node), + "span.title", NULL)); + if (child) + popup_link_text = webkit_dom_node_get_text_content (child); + + if (!popup_link_text) + popup_link_text = webkit_dom_node_get_text_content (link_node); + + tmp = g_new0 (gchar, strlen (popup_link_text) + 1); + ws = FALSE; + for (i = 0, tmpi = 0; popup_link_text[i] != '\0'; i++) { + if (popup_link_text[i] == ' ' || popup_link_text[i] == '\n') { + if (!ws) { + tmp[tmpi] = ' '; + tmpi++; + ws = TRUE; + } + } + else { + tmp[tmpi] = popup_link_text[i]; + tmpi++; + ws = FALSE; + } + } + tmp[tmpi] = '\0'; + g_free (popup_link_text); + popup_link_text = tmp; + } + + if (!(popup_link_text || code_node || code_title_node)) + return FALSE; + + g_variant_dict_init (&user_data_dict, NULL); + + if (popup_link_text) { + g_variant_dict_insert_value (&user_data_dict, "link-title", + g_variant_new_take_string (popup_link_text)); + } + + if (code_node) { + gchar *code_code = webkit_dom_node_get_text_content (code_node); + g_variant_dict_insert_value (&user_data_dict, "code-text", + g_variant_new_take_string (code_code)); + } + + if (code_title_node) { + gchar *code_title = webkit_dom_node_get_text_content (code_title_node); + g_variant_dict_insert_value (&user_data_dict, "code-title", + g_variant_new_take_string (code_title)); + } + + webkit_context_menu_set_user_data (context_menu, g_variant_dict_end (&user_data_dict)); + + return FALSE; +} + +static void +web_page_created_callback (WebKitWebExtension *extension, + WebKitWebPage *web_page, + gpointer user_data) +{ + g_signal_connect (web_page, "context-menu", + G_CALLBACK (web_page_context_menu), + NULL); +} + +G_MODULE_EXPORT void +webkit_web_extension_initialize (WebKitWebExtension *extension) +{ + g_signal_connect (extension, "page-created", + G_CALLBACK (web_page_created_callback), + NULL); +} diff --git a/libyelp/yelp-view.c b/libyelp/yelp-view.c index 73977132..686ab8c5 100644 --- a/libyelp/yelp-view.c +++ b/libyelp/yelp-view.c @@ -127,6 +127,7 @@ static void document_callback (YelpDocument *document, YelpDocumentSignal signal, YelpView *view, GError *error); +static void yelp_view_register_extensions (void); static gchar *nautilus_sendto = NULL; @@ -206,9 +207,8 @@ struct _YelpViewPrivate { gchar *popup_link_uri; gchar *popup_link_text; gchar *popup_image_uri; - WebKitDOMNode *popup_code_node; - WebKitDOMNode *popup_code_title; gchar *popup_code_text; + gchar *popup_code_title; YelpViewState state; YelpViewState prevstate; @@ -428,6 +428,7 @@ yelp_view_finalize (GObject *object) g_free (priv->popup_link_text); g_free (priv->popup_image_uri); g_free (priv->popup_code_text); + g_free (priv->popup_code_title); g_free (priv->page_id); g_free (priv->root_title); @@ -465,6 +466,8 @@ yelp_view_class_init (YelpViewClass *klass) NULL); settings_show_text_cursor (settings); + yelp_view_register_extensions (); + klass->external_uri = view_external_uri; object_class->dispose = yelp_view_dispose; @@ -765,6 +768,16 @@ yelp_view_get_active_link_text (YelpView *view) /******************************************************************************/ +static void +yelp_view_register_extensions (void) +{ + WebKitWebContext *context = webkit_web_context_get_default (); + + webkit_web_context_set_web_extensions_directory (context, YELP_WEB_EXTENSIONS_DIR); +} + +/******************************************************************************/ + static gboolean view_external_uri (YelpView *view, YelpUri *uri) @@ -1166,10 +1179,13 @@ popup_copy_code (GtkAction *action, YelpView *view) { YelpViewPrivate *priv = GET_PRIV (view); - GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); - gchar *content = webkit_dom_node_get_text_content (priv->popup_code_node); - gtk_clipboard_set_text (clipboard, content, -1); - g_free (content); + GtkClipboard *clipboard; + + if (!priv->popup_code_text) + return; + + clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); + gtk_clipboard_set_text (clipboard, priv->popup_code_text, -1); } static void @@ -1180,8 +1196,9 @@ popup_save_code (GtkAction *action, GtkWidget *dialog, *window; gint res; - g_free (priv->popup_code_text); - priv->popup_code_text = webkit_dom_node_get_text_content (priv->popup_code_node); + if (!priv->popup_code_text) + return; + if (!g_str_has_suffix (priv->popup_code_text, "\n")) { gchar *tmp = g_strconcat (priv->popup_code_text, "\n", NULL); g_free (priv->popup_code_text); @@ -1199,11 +1216,10 @@ popup_save_code (GtkAction *action, GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL); gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE); - if (priv->popup_code_title) { - gchar *filename = webkit_dom_node_get_text_content (priv->popup_code_title); - gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), filename); - g_free (filename); - } + + if (priv->popup_code_title) + gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), priv->popup_code_title); + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS)); @@ -1244,11 +1260,6 @@ popup_save_code (GtkAction *action, g_object_unref (file); } - priv->popup_code_node = NULL; - priv->popup_code_title = NULL; - g_free (priv->popup_code_text); - priv->popup_code_text = NULL; - gtk_widget_destroy (dialog); } @@ -1269,36 +1280,15 @@ view_populate_context_menu (YelpView *view, YelpViewPrivate *priv = GET_PRIV (view); WebKitContextMenuItem *item; GtkAction *action; - WebKitDOMNode *node, *cur, *link_node = NULL, *code_node = NULL, *code_title_node = NULL; + GVariant *dom_info_variant; + GVariantDict dom_info_dict; webkit_context_menu_remove_all (context_menu); - for (cur = node; cur != NULL; cur = webkit_dom_node_get_parent_node (cur)) { - if (WEBKIT_DOM_IS_ELEMENT (cur) && - webkit_dom_element_webkit_matches_selector ((WebKitDOMElement *) cur, - "a", NULL)) - link_node = cur; - - if (WEBKIT_DOM_IS_ELEMENT (cur) && - webkit_dom_element_webkit_matches_selector ((WebKitDOMElement *) cur, - "div.code", NULL)) { - WebKitDOMNode *title; - code_node = (WebKitDOMNode *) - webkit_dom_element_query_selector ((WebKitDOMElement *) cur, - "pre.contents", NULL); - title = webkit_dom_node_get_parent_node (cur); - if (title != NULL && WEBKIT_DOM_IS_ELEMENT (title) && - webkit_dom_element_webkit_matches_selector ((WebKitDOMElement *) title, - "div.contents", NULL)) { - title = webkit_dom_node_get_previous_sibling (title); - if (title != NULL && WEBKIT_DOM_IS_ELEMENT (title) && - webkit_dom_element_webkit_matches_selector ((WebKitDOMElement *) title, - "div.title", NULL)) { - code_title_node = title; - } - } - } - } + /* We extract the info about the dom tree that we build in the web-extension.*/ + dom_info_variant = webkit_context_menu_get_user_data (context_menu); + if (dom_info_variant) + g_variant_dict_init (&dom_info_dict, dom_info_variant); if (webkit_hit_test_result_context_is_link (hit_test_result)) { gchar *uri; @@ -1306,46 +1296,13 @@ view_populate_context_menu (YelpView *view, g_free (priv->popup_link_uri); priv->popup_link_uri = uri; - g_free (priv->popup_link_text); - priv->popup_link_text = NULL; - if (link_node != NULL) { - WebKitDOMNode *child; - gchar *tmp; - gint i, tmpi; - gboolean ws; - - child = (WebKitDOMNode *) - webkit_dom_element_query_selector (WEBKIT_DOM_ELEMENT (link_node), - "span.title", NULL); - if (child != NULL) - priv->popup_link_text = webkit_dom_node_get_text_content (child); - - if (priv->popup_link_text == NULL) - priv->popup_link_text = webkit_dom_node_get_text_content (link_node); - - tmp = g_new0 (gchar, strlen(priv->popup_link_text) + 1); - ws = FALSE; - for (i = 0, tmpi = 0; priv->popup_link_text[i] != '\0'; i++) { - if (priv->popup_link_text[i] == ' ' || priv->popup_link_text[i] == '\n') { - if (!ws) { - tmp[tmpi] = ' '; - tmpi++; - ws = TRUE; - } - } - else { - tmp[tmpi] = priv->popup_link_text[i]; - tmpi++; - ws = FALSE; - } - } - tmp[tmpi] = '\0'; - g_free (priv->popup_link_text); - priv->popup_link_text = tmp; - } - else { + g_clear_pointer (&priv->popup_link_text, g_free); + if (dom_info_variant) + g_variant_dict_lookup (&dom_info_dict, "link-title", "s", + &(priv->popup_link_text)); + + if (!priv->popup_link_text) priv->popup_link_text = g_strdup (uri); - } if (g_str_has_prefix (priv->popup_link_uri, "mailto:")) { gchar *label = g_strdup_printf (_("Send email to %s"), @@ -1462,13 +1419,20 @@ view_populate_context_menu (YelpView *view, webkit_context_menu_append (context_menu, item); } - if (code_node != NULL) { + g_clear_pointer (&priv->popup_code_title, g_free); + if (dom_info_variant) + g_variant_dict_lookup (&dom_info_dict, "code-title", + "s", &(priv->popup_code_title)); + + g_clear_pointer (&priv->popup_code_text, g_free); + if (dom_info_variant) + g_variant_dict_lookup (&dom_info_dict, "code-text", + "s", &(priv->popup_code_text)); + + if (priv->popup_code_text) { item = webkit_context_menu_item_new_separator (); webkit_context_menu_append (context_menu, item); - priv->popup_code_node = code_node; - priv->popup_code_title = code_title_node; - action = gtk_action_group_get_action (priv->popup_actions, "CopyCode"); item = webkit_context_menu_item_new (action); |