====== Pan page ====== ===== Description ===== Adds the ability to pan the page like you would in a Image/PDF viewer. Great for tablet users. ;-) ===== JavaScript ===== /* @licstart The following is the entire license notice for the JavaScript code in this page. Copyright (C) 2009 Aldrik Dunbar The JavaScript code in this page is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License (GNU GPL) as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. The code is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU GPL for more details. As additional permission under GNU GPL version 3 section 7, you may distribute non-source (e.g., minimized or compacted) forms of that code without the copy of the GNU GPL normally required by section 4, provided you include this license notice and a URL through which recipients can access the Corresponding Source. @licend The above is the entire license notice for the JavaScript code in this page. USAGE: Add script to the load_start_handler eg. set load_start_handler = script $XDG_DATA_HOME/uzbl/scripts/mouse_pan.js SETTINGS: The following setting that can be added to your config. pan_button: (default = 1) The mouse button used to pan. 0: Left, 1: Middle, 2: Right, etc. pan_speed: (default = 1) Pan speed multiplier. an_accel: (default = 0) Acceleration factor. pan_invert: (default = 0) Inverts pan movement. pan_emulate_click: (default = 1) Treat double click of pan_button as a single click. KNOWN ISSUES: Using full page zoom and pan_accel results in crazy speed When using pan_button = 1, frames need to be focused manually */ (function() { var button, speed, accel, invert, emulate_click, pan_event; var update_settings = (function() { var run = Uzbl.run; delete Uzbl; return function(event) { button = Number(run("print @pan_button") || 1); speed = Number(run("print @pan_speed")) || 1; accel = (Number(run("print @pan_accel")) || 0) + 1; invert = (run("print @pan_invert") === "1") || false; emulate_click = (run("print @pan_emulate_click") !== "0"); pan_event = event; }; })(); // WebKit does not seem to support dblclick on right click natively var context_dblclick = { gtk_double_click_time: 250, gtk_double_click_distance: 5, // timer: false, firstX: 0, firstY: 0, test: function(event) { var offsetX = this.firstX - event.clientX; var offsetY = this.firstY - event.clientY; if (this.timer && offsetX <= this.gtk_double_click_distance && offsetX >= -this.gtk_double_click_distance && offsetY <= this.gtk_double_click_distance && offsetY >= -this.gtk_double_click_distance) { return true; } else { return false; } }, remember: function(event) { this.firstX = event.clientX; this.firstY = event.clientY; this.timer = setTimeout(function() { this.timer = false; }, this.gtk_double_click_time); } }; var accelerator = function(offset) { var value = Math.pow(Math.abs(offset), accel) * speed; if ((!invert && offset >= 0) || (invert && !(offset >= 0))) { return value; } else { return -value; } }; var start = function(event){ update_settings(event); if (event.button === button) { if (event.type === "contextmenu" && emulate_click) { if (context_dblclick.test(event)) { return stop(); } else { context_dblclick.remember(event); } } event.view.document.querySelector("html").style.cursor = "move"; event.preventDefault(); event.stopPropagation(); } else { pan_event = null; } }; var move = function(event) { if (pan_event) { var offsetX = pan_event.clientX - event.clientX; var offsetY = pan_event.clientY - event.clientY; if (offsetX || offsetY) { pan_event = event; var scrollX = accelerator(offsetX); var scrollY = accelerator(offsetY); event.view.scrollBy(scrollX, scrollY); } } }; var stop = function(event){ pan_event = null; event.view.document.querySelector("html").style.cursor = "default"; }; var click = function(event){ if (event.button === button && !event.dont_pan) { event.preventDefault(); event.stopPropagation(); } }; var dblclick = function(event){ if (emulate_click && event.button === button) { event.preventDefault(); event.stopPropagation(); var evt = event.view.document.createEvent("MouseEvents"); evt.initMouseEvent(button === 2 ? "contextmenu" : "click", event.bubbles, event.cancelable, event.view, button === 2 ? 0 : 1 /*event.detail*/, event.screenX, event.screenY, event.clientX, event.clientY, event.ctrlKey, event.altKey, event.shiftKey, event.metaKey, button, event.relatedTarget); evt.dont_pan = true; event.target.dispatchEvent(evt); } }; var make_panable = function(view, remove) { var action = remove ? "removeEventListener" : "addEventListener"; view[action]("mousedown", start, true); view[action]("contextmenu", start, true); view[action]("mousemove", move, true); view[action]("mouseup", stop, true); view[action]("click", click, true); view[action]("dblclick", dblclick, true); }; // No (non standard) DOMFrameContentLoaded event in WebKit var poll_frame = function(frame) { var test = function() { if (frame.contentDocument.readyState.match(/loaded|complete/)) { clearInterval(timer); make_panable(frame.contentWindow); frame.contentWindow.addEventListener("unload", function(event) { poll_frame(frame); }, true); } } var timer = setInterval(test, 10); }; var init_frames = function() { var frame; var frames = document.querySelectorAll("frame"); var len = frames.length; if (len) { make_panable(window, true); for (var i = 0; (frame = frames[i++]);) { poll_frame(frame); } } }; window.addEventListener("DOMContentLoaded", init_frames, true); make_panable(window); })(); // vim: set noet ff=unix ==== Installation ==== Save the above script to a directory of your choice and have it executed on the LOAD_COMMIT event and set setting (see comment at the top of the script) to your preference eg. @on_event LOAD_COMMIT script @scripts_dir/mouse_pan.js set pan_button = 2 set pan_speed = 2 set pan_accel = 0.5