|
1 -------------------------- |
|
2 -- WebKit WebView class -- |
|
3 -------------------------- |
|
4 |
|
5 -- Webview class table |
|
6 webview = {} |
|
7 |
|
8 -- Table of functions which are called on new webview widgets. |
|
9 webview.init_funcs = { |
|
10 -- Set global properties |
|
11 set_global_props = function (view, w) |
|
12 -- Set proxy options |
|
13 local proxy = globals.http_proxy or os.getenv("http_proxy") |
|
14 if proxy then view:set_prop('proxy-uri', proxy) end |
|
15 view:set_prop('user-agent', globals.useragent) |
|
16 |
|
17 -- Set ssl options |
|
18 if globals.ssl_strict ~= nil then |
|
19 view:set_prop('ssl-strict', globals.ssl_strict) |
|
20 end |
|
21 if globals.ca_file and os.exists(globals.ca_file) then |
|
22 view:set_prop('ssl-ca-file', globals.ca_file) |
|
23 -- Warning: update the following variable if 'ssl-ca-file' is |
|
24 -- changed anywhere else. |
|
25 w.checking_ssl = true |
|
26 end |
|
27 end, |
|
28 |
|
29 -- Update window and tab titles |
|
30 title_update = function (view, w) |
|
31 view:add_signal("property::title", function (v) |
|
32 w:update_tab_labels() |
|
33 if w:is_current(v) then |
|
34 w:update_win_title() |
|
35 end |
|
36 end) |
|
37 end, |
|
38 |
|
39 -- Update uri label in statusbar |
|
40 uri_update = function (view, w) |
|
41 view:add_signal("property::uri", function (v) |
|
42 w:update_tab_labels() |
|
43 if w:is_current(v) then |
|
44 w:update_uri(v) |
|
45 end |
|
46 end) |
|
47 end, |
|
48 |
|
49 -- Update scroll widget |
|
50 scroll_update = function (view, w) |
|
51 view:add_signal("expose", function (v) |
|
52 if w:is_current(v) then |
|
53 w:update_scroll(v) |
|
54 end |
|
55 end) |
|
56 end, |
|
57 |
|
58 -- Update progress widget |
|
59 progress_update = function (view, w) |
|
60 for _, sig in ipairs({"load-status", "property::progress"}) do |
|
61 view:add_signal(sig, function (v) |
|
62 if w:is_current(v) then |
|
63 w:update_progress(v) |
|
64 w:update_ssl(v) |
|
65 end |
|
66 end) |
|
67 end |
|
68 end, |
|
69 |
|
70 -- Display hovered link in statusbar |
|
71 link_hover_display = function (view, w) |
|
72 view:add_signal("link-hover", function (v, link) |
|
73 if w:is_current(v) and link then |
|
74 w.sbar.l.uri.text = "Link: " .. lousy.util.escape(link) |
|
75 end |
|
76 end) |
|
77 view:add_signal("link-unhover", function (v) |
|
78 if w:is_current(v) then |
|
79 w:update_uri(v) |
|
80 end |
|
81 end) |
|
82 end, |
|
83 |
|
84 -- Clicking a form field automatically enters insert mode |
|
85 form_insert_mode = function (view, w) |
|
86 view:add_signal("form-active", function () |
|
87 (w.search_state or {}).marker = nil |
|
88 w:set_mode("insert") |
|
89 end) |
|
90 view:add_signal("root-active", function () |
|
91 (w.search_state or {}).marker = nil |
|
92 w:set_mode() |
|
93 end) |
|
94 end, |
|
95 |
|
96 -- Stop key events hitting the webview if the user isn't in insert mode |
|
97 mode_key_filter = function (view, w) |
|
98 view:add_signal("key-press", function () |
|
99 if not w:is_mode("insert") then return true end |
|
100 end) |
|
101 end, |
|
102 |
|
103 -- Try to match a button event to a users button binding else let the |
|
104 -- press hit the webview. |
|
105 button_bind_match = function (view, w) |
|
106 -- Match button press |
|
107 view:add_signal("button-release", function (v, mods, button) |
|
108 (w.search_state or {}).marker = nil |
|
109 if w:hit(mods, button) then return true end |
|
110 end) |
|
111 end, |
|
112 |
|
113 -- Reset the mode on navigation |
|
114 mode_reset_on_nav = function (view, w) |
|
115 view:add_signal("load-status", function (v, status) |
|
116 if w:is_current(v) and status == "provisional" then w:set_mode() end |
|
117 end) |
|
118 end, |
|
119 |
|
120 -- Domain properties |
|
121 domain_properties = function (view, w) |
|
122 view:add_signal("load-status", function (v, status) |
|
123 if status ~= "provisional" then return end |
|
124 local domain = (v.uri and string.match(v.uri, "^%a+://([^/]*)/?")) or "about:blank" |
|
125 if string.match(domain, "^www.") then domain = string.sub(domain, 5) end |
|
126 local props = lousy.util.table.join(domain_props.all or {}, domain_props[domain] or {}) |
|
127 for k, v in pairs(props) do |
|
128 info("Domain prop: %s = %s (%s)", k, tostring(v), domain) |
|
129 view:set_prop(k, v) |
|
130 end |
|
131 end) |
|
132 end, |
|
133 |
|
134 -- Action to take on mime type decision request. |
|
135 mime_decision = function (view, w) |
|
136 -- Return true to accept or false to reject from this signal. |
|
137 view:add_signal("mime-type-decision", function (v, link, mime) |
|
138 info("Requested link: %s (%s)", link, mime) |
|
139 -- i.e. block binary files like *.exe |
|
140 --if mime == "application/octet-stream" then |
|
141 -- return false |
|
142 --end |
|
143 end) |
|
144 end, |
|
145 |
|
146 -- Action to take on window open request. |
|
147 window_decision = function (view, w) |
|
148 -- 'link' contains the download link |
|
149 -- 'reason' contains the reason of the request (i.e. "link-clicked") |
|
150 -- return TRUE to handle the request by yourself or FALSE to proceed |
|
151 -- with default behaviour |
|
152 view:add_signal("new-window-decision", function (v, link, reason) |
|
153 info("New window decision: %s (%s)", link, reason) |
|
154 if reason == "link-clicked" then |
|
155 window.new({ link }) |
|
156 return true |
|
157 end |
|
158 w:new_tab(link) |
|
159 end) |
|
160 end, |
|
161 |
|
162 create_webview = function (view, w) |
|
163 -- Return a newly created webview in a new tab |
|
164 view:add_signal("create-web-view", function (v) |
|
165 return w:new_tab() |
|
166 end) |
|
167 end, |
|
168 |
|
169 -- Action to take on download request. |
|
170 download_request = function (view, w) |
|
171 -- 'link' contains the download link |
|
172 -- 'filename' contains the suggested filename (from server or webkit) |
|
173 view:add_signal("download-request", function (v, link, filename) |
|
174 if not filename then return end |
|
175 -- Make download dir |
|
176 os.execute(string.format("mkdir -p %q", globals.download_dir)) |
|
177 local dl = globals.download_dir .. "/" .. filename |
|
178 local wget = string.format("wget -q %q -O %q", link, dl) |
|
179 info("Launching: %s", wget) |
|
180 luakit.spawn(wget) |
|
181 end) |
|
182 end, |
|
183 |
|
184 -- Creates context menu popup from table (and nested tables). |
|
185 -- Use `true` for menu separators. |
|
186 populate_popup = function (view, w) |
|
187 view:add_signal("populate-popup", function (v) |
|
188 return { |
|
189 true, |
|
190 { "_Toggle Source", function () w:toggle_source() end }, |
|
191 { "_Zoom", { |
|
192 { "Zoom _In", function () w:zoom_in(globals.zoom_step) end }, |
|
193 { "Zoom _Out", function () w:zoom_out(globals.zoom_step) end }, |
|
194 true, |
|
195 { "Zoom _Reset", function () w:zoom_reset() end }, }, }, |
|
196 } |
|
197 end) |
|
198 end, |
|
199 |
|
200 -- Action to take on resource request. |
|
201 resource_request_decision = function (view, w) |
|
202 view:add_signal("resource-request-starting", function(v, uri) |
|
203 if luakit.verbose then print("Requesting: "..uri) end |
|
204 -- Return false to cancel the request. |
|
205 end) |
|
206 end, |
|
207 } |
|
208 |
|
209 -- These methods are present when you index a window instance and no window |
|
210 -- method is found in `window.methods`. The window then checks if there is an |
|
211 -- active webview and calls the following methods with the given view instance |
|
212 -- as the first argument. All methods must take `view` & `w` as the first two |
|
213 -- arguments. |
|
214 webview.methods = { |
|
215 reload = function (view, w) |
|
216 view:reload() |
|
217 end, |
|
218 |
|
219 -- Property functions |
|
220 get = function (view, w, k) |
|
221 return view:get_prop(k) |
|
222 end, |
|
223 |
|
224 set = function (view, w, k, v) |
|
225 view:set_prop(k, v) |
|
226 end, |
|
227 |
|
228 -- evaluate javascript code and return string result |
|
229 eval_js = function (view, w, script, file) |
|
230 return view:eval_js(script, file or "(inline)") |
|
231 end, |
|
232 |
|
233 -- evaluate javascript code from file and return string result |
|
234 eval_js_from_file = function (view, w, file) |
|
235 local fh, err = io.open(file) |
|
236 if not fh then return error(err) end |
|
237 local script = fh:read("*a") |
|
238 fh:close() |
|
239 return view:eval_js(script, file) |
|
240 end, |
|
241 |
|
242 -- close the current tab |
|
243 close_tab = function (view, w) |
|
244 w.tabs:remove(view) |
|
245 view.uri = "about:blank" |
|
246 view:destroy() |
|
247 w:update_tab_count() |
|
248 w:update_tab_labels() |
|
249 end, |
|
250 |
|
251 -- Toggle source view |
|
252 toggle_source = function (view, w, show) |
|
253 if show == nil then show = not view:get_view_source() end |
|
254 view:set_view_source(show) |
|
255 end, |
|
256 |
|
257 -- Zoom functions |
|
258 zoom_in = function (view, w, step) |
|
259 view:set_prop("zoom-level", view:get_prop("zoom-level") + step) |
|
260 end, |
|
261 |
|
262 zoom_out = function (view, w, step) |
|
263 local value = view:get_prop("zoom-level") - step |
|
264 view:set_prop("zoom-level", ((value > 0.01) and value) or 0.01) |
|
265 end, |
|
266 |
|
267 zoom_reset = function (view, w) |
|
268 view:set_prop("zoom-level", 1.0) |
|
269 end, |
|
270 |
|
271 -- Searching functions |
|
272 start_search = function (view, w, text) |
|
273 if string.match(text, "^[\?\/]") then |
|
274 w:set_mode("search") |
|
275 local i = w.ibar.input |
|
276 i.text = text |
|
277 i:focus() |
|
278 i:set_position(-1) |
|
279 else |
|
280 return error("invalid search term, must start with '?' or '/'") |
|
281 end |
|
282 end, |
|
283 |
|
284 search = function (view, w, text, forward) |
|
285 if forward == nil then forward = true end |
|
286 |
|
287 -- Get search state (or new state) |
|
288 if not w.search_state then w.search_state = {} end |
|
289 local s = w.search_state |
|
290 |
|
291 -- Get search term |
|
292 text = text or s.last_search |
|
293 if not text or #text == 0 then |
|
294 return w:clear_search() |
|
295 end |
|
296 s.last_search = text |
|
297 |
|
298 if s.forward == nil then |
|
299 -- Haven't searched before, save some state. |
|
300 s.forward = forward |
|
301 s.marker = view:get_scroll_vert() |
|
302 else |
|
303 -- Invert direction if originally searching in reverse |
|
304 forward = (s.forward == forward) |
|
305 end |
|
306 |
|
307 view:search(text, false, forward, true); |
|
308 end, |
|
309 |
|
310 clear_search = function (view, w) |
|
311 view:clear_search() |
|
312 w.search_state = {} |
|
313 end, |
|
314 |
|
315 -- Webview scroll functions |
|
316 scroll_vert = function (view, w, value) |
|
317 local cur, max = view:get_scroll_vert() |
|
318 if type(value) == "string" then |
|
319 value = lousy.util.parse_scroll(cur, max, value) |
|
320 end |
|
321 view:set_scroll_vert(value) |
|
322 end, |
|
323 |
|
324 scroll_horiz = function (view, w, value) |
|
325 local cur, max = view:get_scroll_horiz() |
|
326 if type(value) == "string" then |
|
327 value = lousy.util.parse_scroll(cur, max, value) |
|
328 end |
|
329 view:set_scroll_horiz(value) |
|
330 end, |
|
331 |
|
332 -- vertical scroll of a multiple of the view_size |
|
333 scroll_page = function (view, w, value) |
|
334 local cur, max, size = view:get_scroll_vert() |
|
335 view:set_scroll_vert(cur + (size * value)) |
|
336 end, |
|
337 |
|
338 -- History traversing functions |
|
339 back = function (view, w, n) |
|
340 view:go_back(n or 1) |
|
341 end, |
|
342 |
|
343 forward = function (view, w, n) |
|
344 view:go_forward(n or 1) |
|
345 end, |
|
346 } |
|
347 |
|
348 function webview.new(w, uri) |
|
349 local view = widget{type = "webview"} |
|
350 |
|
351 -- Call webview init functions |
|
352 for k, func in pairs(webview.init_funcs) do |
|
353 func(view, w) |
|
354 end |
|
355 |
|
356 if uri then view.uri = uri end |
|
357 view.show_scrollbars = false |
|
358 return view |
|
359 end |
|
360 |
|
361 -- Insert webview method lookup on window structure |
|
362 table.insert(window.indexes, 1, function (w, k) |
|
363 -- Get current webview |
|
364 local view = w.tabs:atindex(w.tabs:current()) |
|
365 if not view then return end |
|
366 -- Lookup webview method |
|
367 local func = webview.methods[k] |
|
368 if not func then return end |
|
369 -- Return webview method wrapper function |
|
370 return function (_, ...) return func(view, w, ...) end |
|
371 end) |
|
372 |
|
373 -- vim: et:sw=4:ts=8:sts=4:tw=80 |