diff options
author | Silvio Rhatto <rhatto@riseup.net> | 2017-09-21 21:39:54 -0300 |
---|---|---|
committer | Silvio Rhatto <rhatto@riseup.net> | 2017-09-21 21:39:54 -0300 |
commit | fc24ecca542a10deefc789342f373e8d6a4a43cb (patch) | |
tree | f3e11c3a14e156a145778c200219c86058e9805c /config.dot/luakit.link/webview.lua | |
parent | 562adce657add8aaf2c80597fc54fa0a906c2287 (diff) | |
download | luakit-fc24ecca542a10deefc789342f373e8d6a4a43cb.tar.gz luakit-fc24ecca542a10deefc789342f373e8d6a4a43cb.tar.bz2 |
Stable config
Diffstat (limited to 'config.dot/luakit.link/webview.lua')
-rw-r--r-- | config.dot/luakit.link/webview.lua | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/config.dot/luakit.link/webview.lua b/config.dot/luakit.link/webview.lua new file mode 100644 index 0000000..e3fbfe6 --- /dev/null +++ b/config.dot/luakit.link/webview.lua @@ -0,0 +1,360 @@ +-------------------------- +-- WebKit WebView class -- +-------------------------- + +local window = require("window") +local lousy = require("lousy") +local globals = require("globals") + +-- Webview class table +local webview = {} + +lousy.signal.setup(webview, true) + +local web_module = require_web_module("webview_wm") + +web_module:add_signal("form-active", function (_, page_id) + for _, w in pairs(window.bywidget) do + if w.view.id == page_id then + w.view:emit_signal("form-active") + end + end +end) + +web_module:add_signal("navigate", function (_, page_id, uri) + msg.verbose("Got luakit:// -> file:// navigation: %s", uri) + for _, w in pairs(window.bywidget) do + if w.view.id == page_id then w.view.uri = uri end + end +end) + +local webview_state = setmetatable({}, { __mode = "k" }) + +-- Table of functions which are called on new webview widgets. +local init_funcs = { + -- Set useragent + set_useragent = function (view) + view.user_agent = globals.useragent + end, + + -- Update window and tab titles + title_update = function (view) + view:add_signal("property::title", function (v) + local w = webview.window(v) + if w and w.view == v then + w:update_win_title() + end + end) + end, + + -- Clicking a form field automatically enters insert mode. + form_insert_mode = function (view) + -- Emit root-active event in button release to prevent "missing" + -- buttons or links when the input bar hides. + view:add_signal("button-press", function (v, _, button, context) + if button == 1 then + v:emit_signal(context.editable and "form-active" or "root-active") + end + end) + view:add_signal("form-active", function (v) + local w = webview.window(v) + if not w.mode.passthrough then + w:set_mode("insert") + end + end) + view:add_signal("root-active", function (v) + local w = webview.window(v) + if w.mode.reset_on_focus ~= false then + w:set_mode() + end + end) + view:add_signal("load-status", function (v, status, _, err) + if status == "finished" or (status == "failed" and err == "Load request cancelled") then + web_module:emit_signal(v, "load-finished") + end + end) + end, + + -- Try to match a button event to a users button binding else let the + -- press hit the webview. + button_bind_match = function (view) + view:add_signal("button-release", function (v, mods, button, context) + local w = webview.window(v) + if w:hit(mods, button, { context = context }) then + return true + end + end) + end, + + -- Reset the mode on navigation + mode_reset_on_nav = function (view) + view:add_signal("load-status", function (v, status) + local w = webview.window(v) + if status == "provisional" and w and w.view == v then + if w.mode.reset_on_navigation ~= false then + w:set_mode() + end + end + end) + end, + + -- Action to take on mime type decision request. + mime_decision = function (view) + -- Return true to accept or false to reject from this signal. + view:add_signal("mime-type-decision", function (_, uri, mime) + msg.info("Requested link: %s (%s)", uri, mime) + -- i.e. block binary files like *.exe + --if mime == "application/octet-stream" then + -- return false + --end + end) + end, + + -- Action to take on window open request. + --window_decision = function (view, w) + -- view:add_signal("new-window-decision", function (v, uri, reason) + -- if reason == "link-clicked" then + -- window.new({uri}) + -- else + -- w:new_tab(uri) + -- end + -- return true + -- end) + --end, + + create_webview = function (view) + -- Return a newly created webview in a new tab + view:add_signal("create-web-view", function (v) + return webview.window(v):new_tab(nil, { private = v.private }) + end) + end, + + popup_fix_open_link_label = function (view) + view:add_signal("populate-popup", function (_, menu) + for _, item in ipairs(menu) do + if type(item) == "table" then + -- Optional underscore represents alt-key shortcut letter + item[1] = string.gsub(item[1], "New (_?)Window", "New %1Tab") + end + end + end) + end, +} + +-- These methods are present when you index a window instance and no window +-- method is found in `window.methods`. The window then checks if there is an +-- active webview and calls the following methods with the given view instance +-- as the first argument. All methods must take `view` & `w` as the first two +-- arguments. +webview.methods = { + -- Reload with or without ignoring cache + reload = function (view, _, bypass_cache) + if bypass_cache then + view:reload_bypass_cache() + else + view:reload() + end + end, + + -- Toggle source view + toggle_source = function (view, _, show) + if show == nil then + view.view_source = not view.view_source + else + view.view_source = show + end + view:reload() + end, + + -- Zoom functions + zoom_in = function (view, _, step) + step = step or globals.zoom_step or 0.1 + view.zoom_level = view.zoom_level + step + end, + + zoom_out = function (view, _, step) + step = step or globals.zoom_step or 0.1 + view.zoom_level = math.max(0.01, view.zoom_level) - step + end, + + zoom_set = function (view, _, level) + view.zoom_level = level or 1.0 + end, + + -- History traversing functions + back = function (view, _, n) + view:go_back(n or 1) + view:emit_signal("go-back-forward", -(n or 1)) + end, + + forward = function (view, _, n) + view:go_forward(n or 1) + view:emit_signal("go-back-forward", (n or 1)) + end, +} + +function webview.methods.scroll(view, w, new) + local s = view.scroll + for _, axis in ipairs{ "x", "y" } do + -- Relative px movement + if rawget(new, axis.."rel") then + s[axis] = s[axis] + new[axis.."rel"] + + -- Relative page movement + elseif rawget(new, axis .. "pagerel") then + s[axis] = s[axis] + math.ceil(s[axis.."page_size"] * new[axis.."pagerel"]) + + -- Absolute px movement + elseif rawget(new, axis) then + local n = new[axis] + if n == -1 then + local dir = axis == "x" and "Width" or "Height" + local js = string.format([=[ + Math.max(window.document.documentElement.scroll%s - window.inner%s, 0) + ]=], dir, dir) + w.view:eval_js(js, { callback = function (max) + s[axis] = max + end}) + else + s[axis] = n + end + + -- Absolute page movement + elseif rawget(new, axis.."page") then + s[axis] = math.ceil(s[axis.."page_size"] * new[axis.."page"]) + + -- Absolute percent movement + elseif rawget(new, axis .. "pct") then + local dir = axis == "x" and "Width" or "Height" + local js = string.format([=[ + Math.max(window.document.documentElement.scroll%s - window.inner%s, 0) + ]=], dir, dir) + w.view:eval_js(js, { callback = function (max) + s[axis] = math.ceil(max * (new[axis.."pct"]/100)) + end}) + end + end +end + +local wrap_widget_metatable +do + local wrapped = false + wrap_widget_metatable = function (view) + if wrapped then return end + wrapped = true + + local mt = getmetatable(view) + local oi = mt.__index + mt.__index = function (w, k) + if (k == "uri" or k == "session_state") and oi(w, "type") == "webview" then + local ws = webview_state[w] + if not next(ws.blockers) then return oi(w, k) end + local ql = ws.queued_location or {} + if k == "uri" then + return ql.uri or oi(w, k) + end + if k == "session_state" then + return ql.session_state or oi(w, k) + end + end + return oi(w, k) + end + end +end + +function webview.new(opts) + assert(opts) + local view = widget{type = "webview", private = opts.private} + + webview_state[view] = { blockers = {} } + wrap_widget_metatable(view) + + -- Call webview init functions + for _, func in pairs(init_funcs) do + func(view) + end + webview.emit_signal("init", view) + + return view +end + +luakit.idle_add(function () + local undoclose = package.loaded.undoclose + if not undoclose then return end + undoclose.add_signal("save", function (view) + if view.private then return false end + end) +end) + +function webview.window(view) + assert(type(view) == "widget" and view.type == "webview") + return window.ancestor(view) +end + +function webview.modify_load_block(view, name, enable) + assert(type(view) == "widget" and view.type == "webview") + assert(type(name) == "string") + + local ws = webview_state[view] + ws.blockers[name] = enable and true or nil + msg.verbose("%s %s %s", view, name, enable and "block" or "unblock") + + if not next(ws.blockers) and ws.queued_location then + msg.verbose("fully unblocked %s", view) + local queued = ws.queued_location + ws.queued_location = nil + webview.set_location(view, queued) + end +end + +function webview.set_location(view, arg) + assert(type(view) == "widget" and view.type == "webview") + assert(type(arg) == "string" or type(arg) == "table") + + -- Always execute JS URIs immediately, even when webview is blocked + if type(arg) == "string" and arg:match("^javascript:") then + local js = string.match(arg, "^javascript:(.+)$") + return view:eval_js(luakit.uri_decode(js)) + end + + if type(arg) == "string" then arg = { uri = arg } end + assert(arg.uri or arg.session_state) + + local ws = webview_state[view] + if next(ws.blockers) then + ws.queued_location = arg + if arg.uri then view:emit_signal("property::uri") end + return + end + + if arg.session_state then + view.session_state = arg.session_state + if view.uri == "about:blank" and arg.uri then + view.uri = arg.uri + end + else + view.uri = arg.uri + end +end + +-- Insert webview method lookup on window structure +table.insert(window.indexes, 1, function (w, k) + if k == "view" then + local view = w.tabs[w.tabs:current()] + if view and type(view) == "widget" and view.type == "webview" then + w.view = view + return view + end + end + -- Lookup webview method + local func = webview.methods[k] + if not func then return end + local view = w.view + if view then + return function (_, ...) return func(view, w, ...) end + end +end) + +return webview + +-- vim: et:sw=4:ts=8:sts=4:tw=80 |