Local Image Viewer

View images in local directories. Can navigate, zoom, rotate.

От 18.05.2016. Виж последната версия.

// ==UserScript==
// @name        Local Image Viewer
// @description View images in local directories. Can navigate, zoom, rotate.
// @namespace   localimgviewer
// @include     file:///*
// @version     12
// @grant       GM_getValue
// @grant       GM_setValue
// ==/UserScript==

var fullAddress = window.location.href; // full address
var folderAddress = window.location.href;
var img = null;
var imageName = '';
var imageList = [];
var curPos = null, nextPos = null, prevPos = null;
var imgWidth = null, imgHeight = null;
var zoomAmount = 100;
var fitToScreen = false;
var imgRotation = 0;

if(isAnImage(fullAddress)) {
	folderAddress = fullAddress.substring(0, fullAddress.lastIndexOf('/')) + '/';
	img = document.getElementsByTagName('img')[0];
	img.removeAttribute('width'); img.removeAttribute('height'); img.removeAttribute('class');
	handleImage();
	hookKeys();
	createBox();
}
else {
	if(fullAddress[fullAddress.length - 1] != '/') window.location.assign(fullAddress + '/');
	populateImageArray();
	document.addEventListener('click', function() { populateImageArray(); });
}

function populateImageArray() {
	imageList = [];
	let links = document.getElementsByTagName('a');
	for(let i = 0, j = ''; i < links.length; i++) {
		j = links[i].getAttribute('href');
		j = j.indexOf('/') != -1 ? j.substring(j.lastIndexOf('/') + 1) : j; // if the href contains full addr, just get the string after last slash
		if(isAnImage(j)) imageList.push(j);
	}
	if(imageList.length) { curPos = 0; nextPos = 0; prevPos = imageList.length - 1; hookKeys(); }
	GM_setValue('imagelist_' + folderAddress, JSON.stringify(imageList));
}

function handleImage() {
	img.style.position = 'absolute';
	img.style.textAlign = 'center';
	img.style.margin = 'auto';
	img.style.top = '0';
	img.style.right = '0';
	img.style.bottom = '0';
	img.style.left = '0';
	document.body.style.background = '#222';

	imageName = fullAddress.substring(fullAddress.lastIndexOf('/') + 1);
	imageList = JSON.parse(GM_getValue('imagelist_' + folderAddress));
	curPos = imageList.indexOf(imageName);
	nextPos = curPos == imageList.length - 1 ? 0 : curPos + 1;
	prevPos = curPos == 0 ? imageList.length - 1 : curPos - 1;
	imgWidth = img.width;
	imgHeight = img.height;

	if(GM_getValue('zoomamount') != undefined) zoomAmount = parseInt(GM_getValue('zoomamount'));
	if(GM_getValue('fittoscreen') != undefined) fitToScreen = JSON.parse(GM_getValue('fittoscreen'));
	if(fitToScreen) { img.click(); img.click(); }
	else { img.width = imgWidth * zoomAmount / 100; img.height = imgHeight * zoomAmount / 100; }
	img.addEventListener('click', function() {
		if(img.width <= window.innerWidth && img.height <= window.innerHeight && img.width != imgWidth && img.height != imgHeight) fitToScreen = true;
		else if(img.width <= window.innerWidth && img.height <= window.innerHeight) return;
		else fitToScreen = false;
		zoomInfo();
	});
}

function isAnImage(x) {
	var ext = x.split('.').pop();
	if(ext == 'jpg' || ext == 'jpeg' || ext == 'bmp' || ext == 'png' || ext == 'gif' || ext == 'tga') return true;
	return false;
}

function hookKeys() {
	document.addEventListener('keydown', function(e) {
		let key = e.keyCode || e.which;
		let spKeys = e.ctrlKey || e.shiftKey || e.altKey;
		// console.log('keydown key: ' + key + ' spkeys: ' + spKeys);
		if(spKeys) return;
		if(document.activeElement.tagName == 'INPUT') {
			if(key == 27) toggleJumpForm(); // key ESC
			return;
		}
		if(key == 39) window.location.assign(imageList[nextPos]); // right arrow key
		else if(key == 37) window.location.assign(imageList[prevPos]); // left arrow key
		else if(key == 220) { if(fullAddress != folderAddress) window.location.assign(folderAddress); } // \ key
		else if(key == 188 || key == 190 || key == 191) {
			if(key == 188) imgRotation -= 10; // , key
			else if(key == 190) imgRotation += 10; // . key
			else if(key == 191) imgRotation = 0; // / key
			imgRotation %= 360;
			img.style.transform = 'rotate(' + imgRotation  + 'deg)';
		}
	});
	document.addEventListener('keypress', function(e) {
		let key = e.keyCode || e.which;
		let spKeys = e.ctrlKey || e.shiftKey || e.altKey;
		// console.log('keypress key: ' + key + ' spkeys: ' + spKeys);
		if(spKeys) return;
		if(document.activeElement.tagName == 'INPUT') return;
		if(key == 48 || key == 45 || key == 61) {
			if(key == 48) { fitToScreen = fitToScreen ? false : true; zoomAmount = 100; } // 0 key
			else if(key == 45) { zoomAmount -= zoomAmount <= 5 ? 0 : 5; fitToScreen = false; } // - key
			else if(key == 61) { zoomAmount += zoomAmount >= 1000 ? 0 : 5; fitToScreen = false; }// = key
			img.width = imgWidth * zoomAmount / 100;
			img.height = imgHeight * zoomAmount / 100;
			zoomInfo();	
		}
		else if(key == 103) toggleJumpForm(); // G key
	});
}

function zoomInfo() {
	let text = '';
	if(fitToScreen) { img.click(); img.click(); text = 'Fit to Screen'; zoomAmount = Math.ceil(img.width/imgWidth * 100); }
	else {
		if(img.width == imgWidth && img.height == imgHeight) zoomAmount = 100;
		if(zoomAmount == 100) text = 'Original';
		else text = zoomAmount + '%' + ' Zoom';
	}
	document.getElementById('zoomInfo').innerHTML = 'Size: ' + text + ' (' + img.width + 'x' + img.height + ')';
	GM_setValue('zoomamount', zoomAmount);
	GM_setValue('fittoscreen', fitToScreen);
}

function createBox() {
	let div = document.createElement('div');
	div.id = 'imgViewer';
	div.style = 'z-index: 5; margin: 10px; padding: 10px 20px; border: 1px solid #555; border-radius: 10px; top: 0; left: 0; position: fixed; display: inline-block; opacity: 0.8; background-color: #111; color: #AAA; font-family: Georgia';
	div.innerHTML += '<span style="font-weight: bold; color: #FFF;">Image ' + (curPos + 1) + '/' + imageList.length + '</span> ';
	div.innerHTML += '<br><span style="color: #AF3;">' + decodeURIComponent(imageName) + '</span>';
	div.innerHTML += '<br><span style="font-family: sans-serif; font-size: 70%;" id="zoomInfo"></span>';
	div.innerHTML += '<br><br><span style="font-size: 75%;">Prev: ' + decodeURIComponent(imageList[prevPos]) + '<br>Next: ' + decodeURIComponent(imageList[nextPos]) + '</span>';
	document.body.appendChild(div);

	let jump = document.createElement('div');
	jump.id = 'jumpToImage';
	jump.style = 'z-index: 10; top: 22px; left: 15px; position: fixed;';
	jump.innerHTML += '<a href="#" onclick="return false;" style="color: #3AF; text-decoration: none;">&#9660;</a>';
	jump.innerHTML += '<form name="jumpToImage" onsubmit="return doImageJump();" method="post" style="display: none; background-color: #3AF; padding: 3px; border-radius: 3px; margin-left: 15px"><input name="page" type="number" style="width: 60px;"></input><input type="submit" value="Jump"></input></form>';
	document.body.appendChild(jump);

	zoomInfo();
	if(GM_getValue('imgviewerboxopacity') != undefined) {
		div.style.opacity = GM_getValue('imgviewerboxopacity');
		jump.style.opacity = GM_getValue('imgviewerboxopacity');
	}
	div.addEventListener("click", function() {
		let opac = parseFloat(this.style.opacity);
		opac = opac >= 1.0 ? 0.0 : opac + 0.2;
		this.style.opacity = opac;
		jump.style.opacity = opac;
		GM_setValue('imgviewerboxopacity', opac);
	});
	jump.getElementsByTagName('a')[0].addEventListener("click", function() {
		toggleJumpForm();
		return false;
	});
}

window.toggleJumpForm = function() {
	let jumpForm = document.forms["jumpToImage"];
	jumpForm.style.display = jumpForm.style.display == 'block' ? 'none' : 'block';
	document.forms["jumpToImage"]["page"].focus();
};

window.doImageJump = function() {
	let page = document.forms["jumpToImage"]["page"].value;
	if(page == '') { alert('Type the image number and press Jump'); return false; }
	page = parseInt(page);
	if(page <= 0 || page > imageList.length) alert('Image #' + page + ' doesn\'t exist');
	else window.location.assign(imageList[page - 1]);
	return false;
};