1- #! /usr/bin/python3
1+ #! /usr/bin/python
22
33import os
44import gi
99gi .require_version ('Gtk' , '3.0' )
1010gi .require_version ('Gdk' , '3.0' )
1111gi .require_version ('GLib' , '2.0' )
12- gi .require_version ('WebKit ' , '3 .0' )
12+ gi .require_version ('WebKit2 ' , '4 .0' )
1313
14- from gi .repository import Gtk , Gdk , GLib , WebKit , Soup
14+ from gi .repository import Gtk , Gdk , GLib , WebKit2
1515
1616
1717class DevdocsDesktop :
@@ -23,31 +23,34 @@ def __init__(self):
2323 self .args = argparse .ArgumentParser (prog = 'devdocs-desktop' )
2424 self .args .add_argument ('s' , metavar = 'STR' , help = 'the string to search' , nargs = '?' , default = '' )
2525
26- self .app_url = 'https://devdocs.io'
27- self .do_link = False
28- self .search = self .args .parse_args ().s
29- self .session = WebKit .get_default_session ()
26+ self .app_url = 'https://devdocs.io'
27+ self .search = self .args .parse_args ().s
28+ self .open_link = False
3029
3130 self .main = Gtk .Builder ()
3231 self .main .add_from_file (self .file_path ('ui/main.ui' ))
3332 self .main .connect_signals (self )
3433
35- self .webview = WebKit .WebView ()
34+ self .cookies = WebKit2 .WebContext .get_default ().get_cookie_manager ()
35+ self .manager = WebKit2 .UserContentManager ()
36+ self .webview = WebKit2 .WebView .new_with_user_content_manager (self .manager )
3637 self .webview .load_uri (self .url_with_search ())
3738
38- self .webview .connect ('navigation-requested' , self .on_webview_nav_requested )
39- self .webview .connect ('load-committed' , self .on_webview_load_commited )
40- self .webview .connect ('load-finished' , self .on_webview_load_finished )
41- self .webview .connect ('title-changed' , self .on_webview_title_changed )
39+ self .history = self .webview .get_back_forward_list ()
40+ self .history .connect ('changed' , self .on_history_changed )
41+
42+ self .webview .connect ('notify::uri' , self .on_webview_uri_changed )
43+ self .webview .connect ('notify::title' , self .on_webview_title_changed )
44+ self .webview .connect ('decide-policy' , self .on_webview_decide_policy )
4245 self .webview .connect ('context-menu' , self .on_webview_context_menu )
4346
4447 self .scrolled = self .main .get_object ('scrolled_main' )
4548 self .scrolled .add (self .webview )
4649
47- self .header_back = self .main .get_object ('header_button_back' )
50+ self .header_back = self .main .get_object ('header_button_back' )
4851 self .header_forward = self .main .get_object ('header_button_forward' )
49- self .header_title = self .main .get_object ('header_label_title' )
50- self .header_save = self .main .get_object ('header_button_save' )
52+ self .header_title = self .main .get_object ('header_label_title' )
53+ self .header_save = self .main .get_object ('header_button_save' )
5154
5255 self .header_search = self .main .get_object ('header_search_entry' )
5356 self .header_search .get_style_context ().remove_class ('search' )
@@ -57,7 +60,7 @@ def __init__(self):
5760 self .window .show_all ()
5861
5962 self .create_settings_path ()
60- self .set_webview_settings ()
63+ self .inject_custom_styles ()
6164 self .enable_persistent_cookies ()
6265
6366 def run (self ):
@@ -67,48 +70,36 @@ def quit(self):
6770 Gtk .main_quit ()
6871
6972 def url_with_search (self ):
70- url = self .app_url
71-
72- if self .search != '' :
73- url = url + '#q=' + self .search
74-
73+ url = "%s#q=%s" % (self .app_url , self .search )
7574 return url
7675
7776 def create_settings_path (self ):
78- directory = self .settings_path ()
79-
80- if not os .path .exists (directory ):
81- os .makedirs (directory )
77+ if not os .path .exists (self .settings_path ()):
78+ os .makedirs (self .settings_path ())
8279
8380 def settings_path (self , filepath = '' ):
84- root = os .path .expanduser ('~' ) + '/.devdocs-desktop'
81+ root = "%s/.devdocs-desktop" % os .path .expanduser ('~' )
8582 return os .path .join (root , filepath )
8683
8784 def file_path (self , filepath ):
8885 root = os .path .dirname (os .path .realpath (__file__ ))
8986 return os .path .join (root , filepath )
9087
91- def set_webview_settings (self ):
92- userstyle = 'file://' + self .file_path ('styles/user.css' )
93- settings = self .webview .get_settings ()
88+ def inject_custom_styles (self ):
89+ style = open (self .file_path ('styles/user.css' ), 'r' ).read ()
90+ frame = WebKit2 .UserContentInjectedFrames .ALL_FRAMES
91+ level = WebKit2 .UserStyleLevel .USER
92+ style = WebKit2 .UserStyleSheet (style , frame , level , None , None )
9493
95- settings .set_property ('enable-webaudio' , True )
96- settings .set_property ('enable-media-stream' , True )
97- settings .set_property ('user-stylesheet-uri' , userstyle )
98- settings .set_property ('javascript-can-access-clipboard' , True )
94+ self .manager .add_style_sheet (style )
9995
10096 def enable_persistent_cookies (self ):
101- cookiefile = self .settings_path ('cookies.txt' )
102- cookiejar = Soup .CookieJarText .new (cookiefile , False )
103- cookiejar .set_accept_policy (Soup .CookieJarAcceptPolicy .ALWAYS )
104- self .session .add_feature (cookiejar )
105-
106- def update_history_buttons (self ):
107- back = self .webview .can_go_back ()
108- self .header_back .set_sensitive (back )
97+ filepath = self .settings_path ('cookies.txt' )
98+ storage = WebKit2 .CookiePersistentStorage .TEXT
99+ policy = WebKit2 .CookieAcceptPolicy .ALWAYS
109100
110- forward = self .webview . can_go_forward ( )
111- self .header_forward . set_sensitive ( forward )
101+ self .cookies . set_accept_policy ( policy )
102+ self .cookies . set_persistent_storage ( filepath , storage )
112103
113104 def toggle_save_button (self , visible ):
114105 self .header_save .set_visible (visible )
@@ -118,8 +109,8 @@ def on_window_main_destroy(self, _event):
118109 self .quit ()
119110
120111 def on_window_main_key_release_event (self , _widget , event ):
121- kname = Gdk .keyval_name (event .keyval )
122- text = self .header_search .get_text ()
112+ kname = Gdk .keyval_name (event .keyval )
113+ text = self .header_search .get_text ()
123114 visible = self .header_search .get_visible ()
124115
125116 if kname == 'Escape' and visible :
@@ -160,55 +151,60 @@ def on_menu_main_link_clicked(self, widget):
160151 link = '' if link == 'home' else link
161152
162153 self .header_search .set_text ('' )
163- self .js_click_element ( 'a[href="/' + link + '"]' )
154+ self .js_open_link ( link )
164155
165156 def on_header_button_save_clicked (self , _widget ):
166157 self .toggle_save_button (False )
167158 self .js_click_element ('._sidebar-footer ._settings-btn' )
168159 self .header_title .set_label ('Downloading...' )
169160
170- def on_webview_nav_requested (self , _widget , _frame , request ):
171- uri = request . get_uri ()
161+ def on_webview_decide_policy (self , _widget , decision , dtype ):
162+ types = WebKit2 . PolicyDecisionType
172163
173- if self .do_link :
174- if self .app_url in uri :
175- link = uri .split (self .app_url )[- 1 ]
176- self .js_click_element ('a[href="' + link + '"]' )
177- else :
178- webbrowser .open (uri )
164+ if self .open_link and dtype == types .NAVIGATION_ACTION :
165+ self .open_link = False
166+ uri = decision .get_request ().get_uri ()
179167
180- return True
168+ if not self .app_url in uri :
169+ decision .ignore ()
170+ webbrowser .open (uri )
181171
182- self .do_link = False
183- return False
172+ def on_webview_title_changed (self , _widget , _title ):
173+ title = self .webview .get_title ()
174+ self .header_title .set_label (title )
184175
185- def on_webview_load_commited (self , _widget , frame ):
186- self .do_link = False
187- self .update_history_buttons ()
188- self .toggle_save_button (frame .get_uri ().endswith ('settings' ))
176+ def on_webview_uri_changed (self , _widget , _uri ):
177+ save = self .webview .get_uri ().endswith ('settings' )
178+ self .toggle_save_button (save )
189179
190- def on_webview_load_finished (self , _widget , frame ):
191- self .update_history_buttons ()
192- self .toggle_save_button ( frame . get_uri (). endswith ( 'settings' ) )
180+ def on_history_changed (self , _list , _added , _removed ):
181+ back = self .webview . can_go_back ()
182+ self .header_back . set_sensitive ( back )
193183
194- def on_webview_title_changed ( self , _widget , _frame , title ):
195- self .header_title . set_label ( title )
184+ forward = self . webview . can_go_forward ()
185+ self .header_forward . set_sensitive ( forward )
196186
197- def on_webview_open_link (self , _widget ):
198- self .do_link = True
187+ def on_webview_open_link (self , action ):
188+ self .open_link = True
199189
200190 def on_webview_context_menu (self , _widget , menu , _coords , _keyboard ):
201- for item in menu .get_children ():
202- label = item .get_label ()
203- lnk_open = '_Open' in label
204- new_open = '_Window' in label
205- download = '_Download' in label
191+ actions = WebKit2 .ContextMenuAction
192+ include = [
193+ actions .GO_BACK , actions .GO_FORWARD , actions .STOP , actions .RELOAD ,
194+ actions .COPY , actions .CUT , actions .PASTE , actions .DELETE , actions .SELECT_ALL ,
195+ actions .OPEN_LINK , actions .COPY_LINK_TO_CLIPBOARD ,
196+ actions .COPY_IMAGE_TO_CLIPBOARD , actions .COPY_IMAGE_URL_TO_CLIPBOARD ,
197+ actions .COPY_VIDEO_LINK_TO_CLIPBOARD , actions .COPY_AUDIO_LINK_TO_CLIPBOARD
198+ ]
199+
200+ for item in menu .get_items ():
201+ action = item .get_stock_action ()
206202
207- if new_open or download :
208- item . destroy ( )
203+ if not action in include :
204+ menu . remove ( item )
209205
210- if lnk_open :
211- item .connect ('select ' , self .on_webview_open_link )
206+ if action == actions . OPEN_LINK :
207+ item .get_action (). connect ('activate ' , self .on_webview_open_link )
212208
213209 def js_form_input (self , text ):
214210 script = """
@@ -218,15 +214,17 @@ def js_form_input(self, text):
218214 if (fi) { fi.value = '%s' };
219215 if (fe) { fe.dispatchEvent(ev); }
220216 """
221- script = script % (text )
222217
223- self .webview .execute_script (script )
218+ script = script % text
219+ self .webview .run_javascript (script )
224220
225221 def js_click_element (self , selector ):
226- script = "var sl = $('%s'); if (sl) { sl.click(); }"
227- script = script % ( selector )
222+ script = "var sl = $('%s'); if (sl) { sl.click(); }" % selector
223+ self . webview . run_javascript ( script )
228224
229- self .webview .execute_script (script )
225+ def js_open_link (self , link ):
226+ link = """a[href="/%s"]""" % link .split (self .app_url )[- 1 ]
227+ self .js_click_element (link )
230228
231229
232230if __name__ == '__main__' :
0 commit comments