User Tools

Site Tools


pan

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
pan.txt · Last modified: 2016/08/31 14:10 (external edit)