1
- #! /usr/bin/python3
1
+ #! /usr/bin/python
2
2
3
3
import os
4
4
import gi
9
9
gi .require_version ('Gtk' , '3.0' )
10
10
gi .require_version ('Gdk' , '3.0' )
11
11
gi .require_version ('GLib' , '2.0' )
12
- gi .require_version ('WebKit ' , '3 .0' )
12
+ gi .require_version ('WebKit2 ' , '4 .0' )
13
13
14
- from gi .repository import Gtk , Gdk , GLib , WebKit , Soup
14
+ from gi .repository import Gtk , Gdk , GLib , WebKit2
15
15
16
16
17
17
class DevdocsDesktop :
@@ -23,31 +23,34 @@ def __init__(self):
23
23
self .args = argparse .ArgumentParser (prog = 'devdocs-desktop' )
24
24
self .args .add_argument ('s' , metavar = 'STR' , help = 'the string to search' , nargs = '?' , default = '' )
25
25
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
30
29
31
30
self .main = Gtk .Builder ()
32
31
self .main .add_from_file (self .file_path ('ui/main.ui' ))
33
32
self .main .connect_signals (self )
34
33
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 )
36
37
self .webview .load_uri (self .url_with_search ())
37
38
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 )
42
45
self .webview .connect ('context-menu' , self .on_webview_context_menu )
43
46
44
47
self .scrolled = self .main .get_object ('scrolled_main' )
45
48
self .scrolled .add (self .webview )
46
49
47
- self .header_back = self .main .get_object ('header_button_back' )
50
+ self .header_back = self .main .get_object ('header_button_back' )
48
51
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' )
51
54
52
55
self .header_search = self .main .get_object ('header_search_entry' )
53
56
self .header_search .get_style_context ().remove_class ('search' )
@@ -57,7 +60,7 @@ def __init__(self):
57
60
self .window .show_all ()
58
61
59
62
self .create_settings_path ()
60
- self .set_webview_settings ()
63
+ self .inject_custom_styles ()
61
64
self .enable_persistent_cookies ()
62
65
63
66
def run (self ):
@@ -67,48 +70,36 @@ def quit(self):
67
70
Gtk .main_quit ()
68
71
69
72
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 )
75
74
return url
76
75
77
76
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 ())
82
79
83
80
def settings_path (self , filepath = '' ):
84
- root = os .path .expanduser ('~' ) + '/.devdocs-desktop'
81
+ root = "%s/.devdocs-desktop" % os .path .expanduser ('~' )
85
82
return os .path .join (root , filepath )
86
83
87
84
def file_path (self , filepath ):
88
85
root = os .path .dirname (os .path .realpath (__file__ ))
89
86
return os .path .join (root , filepath )
90
87
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 )
94
93
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 )
99
95
100
96
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
109
100
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 )
112
103
113
104
def toggle_save_button (self , visible ):
114
105
self .header_save .set_visible (visible )
@@ -118,8 +109,8 @@ def on_window_main_destroy(self, _event):
118
109
self .quit ()
119
110
120
111
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 ()
123
114
visible = self .header_search .get_visible ()
124
115
125
116
if kname == 'Escape' and visible :
@@ -160,55 +151,60 @@ def on_menu_main_link_clicked(self, widget):
160
151
link = '' if link == 'home' else link
161
152
162
153
self .header_search .set_text ('' )
163
- self .js_click_element ( 'a[href="/' + link + '"]' )
154
+ self .js_open_link ( link )
164
155
165
156
def on_header_button_save_clicked (self , _widget ):
166
157
self .toggle_save_button (False )
167
158
self .js_click_element ('._sidebar-footer ._settings-btn' )
168
159
self .header_title .set_label ('Downloading...' )
169
160
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
172
163
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 ()
179
167
180
- return True
168
+ if not self .app_url in uri :
169
+ decision .ignore ()
170
+ webbrowser .open (uri )
181
171
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 )
184
175
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 )
189
179
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 )
193
183
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 )
196
186
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
199
189
200
190
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 ()
206
202
207
- if new_open or download :
208
- item . destroy ( )
203
+ if not action in include :
204
+ menu . remove ( item )
209
205
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 )
212
208
213
209
def js_form_input (self , text ):
214
210
script = """
@@ -218,15 +214,17 @@ def js_form_input(self, text):
218
214
if (fi) { fi.value = '%s' };
219
215
if (fe) { fe.dispatchEvent(ev); }
220
216
"""
221
- script = script % (text )
222
217
223
- self .webview .execute_script (script )
218
+ script = script % text
219
+ self .webview .run_javascript (script )
224
220
225
221
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 )
228
224
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 )
230
228
231
229
232
230
if __name__ == '__main__' :
0 commit comments