Adds the ability to pan the page like you would in a Image/PDF viewer. Great for tablet users.
/*
@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
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