Gelbooru Image Viewer

Adds a fullscreen image view option when you click on images

Per 28-11-2016. Zie de nieuwste versie.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @id             gelbooru-slide
// @name           Gelbooru Image Viewer
// @version        1.2
// @namespace      intermission
// @author         intermission
// @license        CC0; https://wiki.creativecommons.org/wiki/CC0
// @description    Adds a fullscreen image view option when you click on images
// @include        http://gelbooru.com/index.php?*
// @include        https://gelbooru.com/index.php?*
// @run-at         document-start
// @grant          GM_registerMenuCommand
// ==/UserScript==

(function(){
	"use strict";
	var d = document, array = a => [].slice.call(a), observer, request, mouseUp, slideEl, slider, slidin, base = a => a.split("/").pop().split(".")[0].split("_").pop(), keyDown, find, current, preload, stor = localStorage, l, ns = "gelbooru-slide", toggle = stor[ns] == "true", cache;
	
	if (!stor[ns]) stor[ns] = "false";
	
	GM_registerMenuCommand("Current image mode: " + (toggle ? "Always original size" : "Sample only"), () => {
		stor[ns] = toggle ? "false" : "true";
		location.reload();
	});
	
	l = toggle ? ["ul>li>a[style*='font-weight:']", "href"] : ["#image", "src"];
	
	current = a => d.querySelector("img.preview[src*='" + base(slideEl.src) + "']").parentNode;
	
	mouseUp = e => e.button == 0 && (e.preventDefault(), e.stopPropagation(), slider(e.target.parentNode));
	
	cache = (a, b) => {
		let id = a.href.match(/id=([0-9]+)/)[1], val = toggle ? "original" : "sample";
		if (!b) {
			let temp;
			try { temp = JSON.parse(stor[ns + id])[val] } catch(e) {}
			return temp || "loading";
		}
		else {
			let obj, temp;
			try { temp = JSON.parse(stor[ns + id]) } catch(e) {}
			obj = temp || {};
			obj[val] = b;
			stor[ns + id] = JSON.stringify(obj);
			return b;
		}
	};
	
	find = function(el, method) {
		var a;
		el = el.parentNode;
		do {
			try {
				el = el[(method ? "next" : "previous") + "ElementSibling"];
				a = el.querySelector`a[data-full]`;
			} catch(err) {
				return false;
			}
			if (a) break;
			a = false;
		} while(!a);
		return a;
	};
	
	preload = function() {
		var curr = current(), a = find(curr, true), b = find(curr, false);
		a && request(a);
		b && request(b);
		return;
	};
	
	keyDown = function(e) {
		var move;
		switch(e.keyCode) {
			case 32:
			case 39:
				move = true;
				break;
			case 37:
				move = false;
				break;
			case 38:
				window.location = current().href;
				break;
			case 40:
				e.preventDefault();
				slideEl.click();
				break;
		}
		if (typeof move != "undefined") {
			e = find(current(), move);
			if (e) slideEl.slide(e.firstElementChild.src);
			preload();
		}
	};
	
	slider = function(a) {
		var list;
		list = array(d.querySelectorAll`body > *`);
		if (slidin) {
			let center;
			slidin = !(a = current());
			slideEl = slideEl.remove();
			list.forEach(a => a.dataset.slide = "false");
			a.classList.add`outlined`;
			d.removeEventListener("keydown", keyDown, false);
			center = a.offsetTop + a.offsetHeight / 2 - window.innerHeight / 2;
			window.scrollTo(0, center < 0 ? 0 : center);
		} else {
			slidin = true;
			list.forEach(a => a.dataset.slide = "true");
			array(d.querySelectorAll`span>a.outlined`).map(a => a.classList.remove`outlined`);
			slideEl = d.createElement`img`;
			slideEl.id = "slide";
			slideEl.alt = "Loading...";
			Object.defineProperty(slideEl, "slide", {
				value: function(src) {
					var data;
					this.src = src;
					data = current().dataset.full;
					if (data == "loading") request(current());
					else this.src = data;
				}
			});
			slideEl.onclick = _ => slider(a);
			d.body.appendChild(slideEl);
			slideEl.slide(a.firstElementChild.src);
			d.addEventListener("keydown", keyDown, false);
			preload();
		} return;
	};
	
	request = function(node) {
		if (node.dataset.alreadyLoading || node.dataset.full != "loading" ) return;
		node.dataset.alreadyLoading = "true";
		return fetch(node.href)
			.then(x => x.text().then(text => {
				var doc = (new DOMParser()).parseFromString(text, "text/html"), img, _base;
				if (img = doc.querySelector(l[0])) {
					_base = base(img[l[1]]);
					node.dataset.full = cache(node, img[l[1]]);
					if (slideEl && slideEl.src.indexOf(_base) > -1)
						slideEl.slide(img[l[1]]);
				} else {
					node.removeAttribute`data-already-loading`;
					fetch`/intermission.php`.then(x2 => request(node))
				}
			})).catch(err => {
				console.error("Failed HTTP request\nDo you have an internet connection?\n", err);
				node.removeAttribute`data-already-loading`;
			});
	};
	
	observer = new MutationObserver(function(mutations) {
		function process(node) {
			let a;
			try {
				if (node.matches`span.thumb[id^='s']` && (a = node.firstElementChild) && !a.dataset.full) {
					if (node.querySelector`img[alt*='webm']`) return;
					a.dataset.full = cache(a);
					a.onclick = mouseUp;
				}
			} catch(e) {}
		};
		mutations.forEach(function(mutation) {
			array(mutation.addedNodes).forEach(process);
		}); 
	});
	observer.observe(d, {
		childList: true,
		subtree: true
	});
	
	d.addEventListener("animationend", e => e.animationName == 'Outlined' && e.target.classList.remove`outlined`, false);
	
	{
		let css = d.createElement`style`;
		css.textContent =
		`@keyframes Outlined {
			0% {
				outline: 6px solid orange
			}
			60% {
				outline: 6px solid orange
			}
			100% {
				outline: 6px solid transparent
			}
		}
		[data-slide="true"] {
			display: none ! important
		}
		#slide {
			width: 100vw;
			height: 100vh;
			object-fit: contain
		}
		.outlined {
			outline: 6px solid transparent;
			animation-duration: 4s;
			animation-name: Outlined
		}`;
		d.head.appendChild(css);
	}
}())