Gelbooru KonaStyle

Change gelbooru.com theme to darker, similar to konachan style. Added filtration image options, images with blacklist tags will be remove from search result. Also adden upvote&downvote button to preview page. Added buttons to hide submenu and red message in header.

Mint 2015.03.22.. Lásd a legutóbbi verzió

// ==UserScript==
// @name         Gelbooru KonaStyle
// @namespace    http://Aestellar.homepage/
// @version      0.14
// @description  Change gelbooru.com theme to darker, similar to konachan style. Added filtration image options, images with blacklist tags will be remove from search result. Also adden upvote&downvote button to preview page. Added buttons to hide submenu and red message in header.
// @author       Aestellar
// @include       *://gelbooru.com/*
// @resource    gelbooruCss1 https://userstyles.org/styles/111063/gelbooru-konastyle-test.css
// @grant GM_getResourceText
// @grant GM_addStyle

// @run-at      document-start

// ==/UserScript==
(function(){
	var win = window;
	var ls = localStorage;
	if(!win){
		console.log(win + "Failed to load window object");
		return;
	}
	
	if(win.self != win.top){
		return;
	}

	var css = GM_getResourceText ("gelbooruCss1");
	addStyle(css);
	document.addEventListener("DOMContentLoaded",updateUI, false);
	
	function loadPrereq(){
		var hrefVar = win.location.href;
		if(/(htt[ps]:\/\/gelbooru\.com[\/]*)$/.test(hrefVar)){
			document.body.className = 'main-page';
		}
		var t = document.createElement('d');
		//Font awesome support Don't work with @resource
		t.innerHTML = '<link rel="stylesheet" type="text/css" media="screen" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.0.3/css/font-awesome.css" />';
		t = t.children[0];
		document.head.appendChild(t);
	}
	
	
	function submit(e){
		var textElt = qS('#stags')||qS('#tags');
		text = textElt.value;     
		console.log(text);
		text = applySearchFilters(text);
		textElt.value = text;
	}
	
	function applySearchFilters(text)
	{
		if (ls.getItem('onlyNewSearch')==='true') {
			if (!!getLastImageId()) {
				var newId = ' id:>' + getLastImageId() + ' ';
				if (text.indexOf(newId)===-1) {
					text+=newId; 
				}              
			}
		}
		return text;
	}
	
	function replaceSubmit(){
		var form = qS('.sidebar3 form');
		form.onsubmit = submit;
	}    
	
	function updateUI(){       
		loadPrereq();
		checkLastVisit();
		replaceSubmit();
		createSettingsWindow();   
		updateNav();
		updateThumbs();
	}                
	
	function updateThumbs(){
		var c = qS('.thumb');
		if (!c){           
			return;
		}

		var thumbsCont = c.parentNode;
		c = thumbsCont.parentNode;
		processThumbs(thumbsCont);

		observeDOM(c, function(e){
			var temp =e.forEach;
			if (!!temp) {
				e.forEach(function(elt){
					var test;
					var  t = elt.addedNodes;
					if (!!t) {
						t = t[0];

						if (!t) {
							return;
						}

						if (!t.getElementsByClassName){
							return;
						}
						test = t.getElementsByClassName('thumb');
						if (!!test.length) {                                

							processThumbs(t);
						}
					}
				});
			}
		});       
	}

	function thumbPaneIsDisabled(){
		return false;
	}

function getImageFromDoc(doc){
	var img = doc.getE
}
	function appendThumbPane(thumb){
		if (thumbPaneIsDisabled()) {
			return;
		}
		var test = makeDiv('thumb-pane');
		var url = getImageRefFromThumb(thumb);
		url = url.replace('thumbnails','images');
		url = url.replace('thumbnail_','');
		if(getTagListFromThumb(thumb).search('animated_gif')!=-1){
			makeRef('gif');
		}
		else{
			var ext = ['png','jpeg','jpg'];
			for (var i = ext.length - 1; i >= 0; i--) {
				makeRef(ext[i]);
			}
		}

		function makeRef(extension){
			var ref = document.createElement('a');
			ref.textContent  = extension;
			var url2 = url.replace('jpg',extension);
			ref.setAttribute('href', url2);
			test.appendChild(ref); 
		}

		//ref.textContent  = "Image";
		
		var dataId = getIdFromThumb(thumb);
		test.setAttribute('data-id', dataId);
		test.setAttribute('data-voted', 'false');



		// ref.addEventListener('click', function(e){
		// 	var p = e.target;
		// 	var full = p.getAttribute('href');


		// 	if (full==='#') {
		// 		p = p.parentNode;
		// 		var id = p.getAttribute('data-id');

		// 			var url = 'index.php?page=post&s=view&id='+id;
					

		// 			handleXHRDoc(url, function(doc){
		// 				var i =  doc.getElementById('image');
		// 				var src = i.getAttribute('src');
		// 				//src=src.replace('sample_','');
		// 				//src=src.replace('samples','images');
		// 				//console.log(doc.defaultView.image);

		// 				e.target.setAttribute('href', src);
		// 				e.target.classList.add('loaded');
		// 				e.target.click();
		// 			});

		// 	}
		// 	else{
		// 		window.open(full, '_black');
		// 	}
		// 	e.preventDefault();

		// }, false);


		var upBtn = document.createElement('span');
		var downBtn = document.createElement('span');

		makeSimpleButton(upBtn, 
			{name:'upBtn',
			glyph:'fa-thumbs-up',
			callback:voteUp
		});

		makeSimpleButton(downBtn, 
			{name:'downBtn',
			glyph:'fa-thumbs-down',
			callback:voteDown
		});

		test.insertBefore(upBtn,test.firstChild);
		//test.appendChild(ref);
		test.appendChild(downBtn);

		thumb.appendChild(test);


	}



	function voteImage(e, vote){
		var parent = e.bindedElt;
		var pane = parent.parentNode;
		if (pane.getAttribute('data-voted')!=='false') {
			return;
		}
		var id = pane.getAttribute('data-id');

		handleXHRDoc('index.php?page=post&s=vote&id='+id+'&type='+vote, function(doc){
			var score = doc.body.textContent;
			parent.textContent=score;
			pane.setAttribute('data-voted', 'true');
		}); 
	}

	function voteUp(e){
		voteImage(e, 'up');
	}

	function voteDown(e){
		voteImage(e, 'down');
	}


	function isImageFiltering(){
		return ls.getItem('disableImageFiltering')==='false';
	}

	function isPreviewPaneEnabled(){
		return ls.getItem('disablePreviewPane')==='false';
	}


	function processThumbs(container){
		if (!!container) {
			for (var i = 0; i <container.children.length; i++) {
				var loop = container.children[i];
				
				if(filterThumb(loop)){
					continue;
				}
				if (isPreviewPaneEnabled()) {
					appendThumbPane(loop);
				}
				

			}
		}
	}

	function increaseFilterCount(){
		var countElt = qS('#filterCount');
		var count = countElt.textContent;
		console.log(count);
		count = parseInt(count);
		console.log(count);
		count+=1;
		countElt.textContent=count;
	}

	function filterThumb(thumb){
		if (!isImageFiltering()) {
			return false;
		}

		var thumbTags = getTagListFromThumb(thumb);
		if (!!thumbTags) {
			if (isBannedThumb(thumbTags)) {
				hide(thumb);
				increaseFilterCount();
				return true;
			}
		}
		return false;

	}

	function isBannedThumb(thumbList){
		var bannedList = getBannedList();
		var loop;

		if (!bannedList) {
			return false;
		}
		bannedList = bannedList.replace('\n', ' ');
		bannedList = bannedList.replace(/\s+/g, ' ');
		bannedList = bannedList.replace(/(\s+)$/g, '');
		bannedList = bannedList.replace(/^(\s+)/g, '');
		bannedList = bannedList.split(' ');
		for (var i = bannedList.length - 1; i >= 0; i--) {
			loop = bannedList[i];
			if (thumbList.search(loop)!=-1) {
				return true;
			}
		}
		return false;

	}

	function getIdFromThumb(thumb){
		var id = thumb.getAttribute('id');
		if (!!id) {
			id = id.replace('s', '');
		}
		return id;
	}

	function getFullImagePathFromRef(ref){

	}

	function getImageRefFromThumb(thumb){
		var img = thumb.getElementsByTagName('img')[0];
		if (!!img) {
			return img.getAttribute('src');
		}
	}

	function getTagListFromThumb(thumb){
		if (!thumb) {
			return;
		}
		var thumbImg = thumb.getElementsByClassName('preview')[0];
		if (!!thumbImg) {
			return thumbImg.getAttribute('alt');
		}

	}

	function getBannedList(){
		var bannedList = ls.getItem('bannedTagsList');
		return bannedList;
	}

	function updateNav() {
		var navBar = qS('.flat-list');
		var settingsBtn = document.createElement("li");
		var navBtn = document.createElement("li");
		var advNav = document.createElement("li");
		navBar.insertBefore(settingsBtn, navBar.firstChild);
		navBar.insertBefore(advNav, navBar.firstChild);
		navBar.insertBefore(navBtn, navBar.firstChild);
		
		var s = {name:'settingsBtn',
		glyph:'fa-gear',         
		callback:showSettingsWindow};

		makeUserNavBar();     

		var sett = {name:'navCollapse', glyphOff:'fa-minus-square-o', glyphOn:'fa-plus-square-o',
		callbackOff:makeToggleFunc(['.submenu', '.noticeError'], show), callbackOn:makeToggleFunc(['.submenu', '.noticeError'], hide)};

		var sett2 = {name:'advNavCollapse', glyphOff:'fa-search-minus', glyphOn:'fa-search-plus',
		callbackOff:makeToggleFunc(['#usernavbar'], show), callbackOn:makeToggleFunc(['#usernavbar'], hide)};

		makeSimpleButton(settingsBtn, s);
		makeToggleButton(navBtn,sett);
		makeToggleButton(advNav,sett2);
	}

	function createSettingsWindow(){
		var mod = document.createElement('div');
		mod.className = 'modalDialog';
		mod.innerHTML = '<div class = modalDialogBox>\
		<span title="Close" class="close"></span>\
		</div>';
		document.body.appendChild(mod);
		mod.addEventListener('click',hideModalWindow,false);

		var close = qS('.modalDialog .close');

		makeSimpleButton(close,
			{name:'settingsBtn',
			glyph:'fa-times',
			callback:hideSettingsWindow
		});

		var dialog = qS('.modalDialogBox');
		dialog.appendChild(getSettingsInner());

	}

	function getSettingsInner(){
		var div = document.createElement('div');
		div.innerHTML = '<span class="modalName">Settings</span>';
		var textBlock = document.createElement('textarea');
		textBlock.className = 'bannedList';
		textBlock.value = getBannedList();
		textBlock.addEventListener('input',function(e){
			ls.setItem('bannedTagsList',e.target.value);
		},false);



		var settTab = new TabbedPane();
		div.appendChild(settTab.tabbedPane);

		var mainSetting = makeDiv('main-settings');

		var disableFilteringRule = makeDiv('settings-rule');
		disableFilteringRule.textContent = 'Disable image filtering: ';
		disableFilteringRule.appendChild(makeCheckBox('disableImageFiltering'));
		mainSetting.appendChild(disableFilteringRule);


		var disableThumbPane = makeDiv('settings-rule');
		disableThumbPane.textContent = 'Don\' show preview panel: ';
		disableThumbPane.appendChild(makeCheckBox('disablePreviewPane'));	
		mainSetting.appendChild(disableThumbPane);



		settTab.addTab('sett1', 'Settings', mainSetting);
		settTab.addTab('sett2','Banned tags', textBlock);
	//console.log(settTab);

	// var iTest = makeDiv('');
	// iTest.innerHTML = '<img src="http://i.nhentai.net/galleries/795920/cover.jpg">';
	// settTab.addTab('sett3','imageTest', iTest);
	settTab.selectDefault();


	return div;
}

function showSettingsWindow(e){
	var mod = qS('.modalDialog');
	mod.classList.add('modalActive');
}

function hideModalWindow(e){
	var mod = qS('.modalDialog');
	if (e && (e.target!== mod)) {
		return;
	};
	hideSettingsWindow(e);
};

function hideSettingsWindow(e){
	var mod = qS('.modalDialog');
	mod.classList.remove('modalActive');
}


function makeUserNavBar(){
	var userBar = document.createElement('ul');
	userBar.className = 'flat-list';
	userBar.setAttribute('id', 'usernavbar');
	var navBar = qS('.submenu'); 
	var navParent = navBar.parentNode;
	navParent.insertBefore(userBar,navBar.nextSibling);

	makeFitImageBtn(userBar);
	makeAdvSearchPane(userBar);

}   

function makeToggleFunc(sel,action){

	var activeFoo = function(){
		for (var i = sel.length - 1; i >= 0; i--) {
			action(qS(sel[i]));
		};            
	}
	return activeFoo;
}


function makeFitImageBtn(userBar){
	var fitBtn = document.createElement("li");
	userBar.appendChild(fitBtn);
	var imageFit = makeToggleButton(fitBtn, {name:'fitImage',
		glyphOff:'fa fa-compress',
		glyphOn:'fa fa-expand',
		callbackOff:fit,
		callbackOn:fit});
	var img = qS('#image');
	function fit(){
		var img = qS('#image');
		if (img === undefined) {         
			return;
		}

		img.removeAttribute('width');
		img.removeAttribute('height');

		if ((localStorage.getItem('fitImage')==='true')) {  
			img.style.maxWidth = '100%';         
		}

		else{
			img.style.maxWidth = '';
		}

		if(!!img){
			img.addEventListener('load', fit, false);          
		}
	}
}

function makeAdvSearchPane(userBar){
	var advSearch = document.createElement('div');
	advSearch.innerHTML = '<div id = "adv-search">\
	<li><span>Advanced Search: </span>\
	<span id = "only-new">Only new images </span></li>\
	<li><span>Filtered images: <span id="filterCount">0</span></span></li>\
	</div>';
	advSearch = advSearch.firstChild;
	userBar.appendChild(advSearch);
	var onlyNew = document.getElementById('only-new');

	makeToggleButton(onlyNew, {name:'onlyNewSearch',
		glyphOff:'fa-square-o',
		glyphOn:'fa-check-square-o'
	});
	return advSearch;
}

function makeCheckBox(rname){
	var box = makeSpan('checkbox-span');
	makeToggleButton(box, 
		{name:rname,
			glyphOff:'fa-square-o',
			glyphOn:'fa-check-square-o'
		});
	return box;
}

function makeToggleButton(elem, settings){
	var btn = new ButtonToggle(settings);
	btn.bindElement(elem);
	btn.load();
	elem.addEventListener('click', btn.handlerClick, false);
	return btn;
}

function makeSimpleButton(elem, settings){
	var btn = new ButtonSimple(settings);
	btn.bindElement(elem);
	elem.addEventListener('click', btn.handlerClick, false);
	return btn;            
}


function ButtonSimple(settings){
	var self = this;
	var modGliph = 'fa-lg';
	this.name = settings.name;

	this.glyphElt = document.createElement('i');
	this.active = false;
	this.bindedElt = null;
	this.callback = settings.callback;
	this.bindElement = function (elem) {
		self.bindedElt = elem;
		if (self.bindedElt.length > 0) {
			elem.insertChildBefore(self.glyphElt, elem.FirstChild);
		}
		else {
			elem.appendChild(self.glyphElt);
		}
	};            
	this.glyph = 'fa ' + settings.glyph + ' ' + modGliph;
	self.glyphElt.className = self.glyph;

	this.handlerClick = function (e) {
		self.callback(self);
	};
}

function ButtonToggle(settings) {
	var self = this;

	var modGliph = 'fa-lg';
	this.name = settings.name;

	this.active = false;
	this.bindedElt = null;
	this.glyphElt = document.createElement('i');
	this.bindElement = function (elem) {
		self.bindedElt = elem;
		if (self.bindedElt.length > 0) {
			elem.insertChildBefore(self.glyphElt, elem.FirstChild);
		}
		else {
			elem.appendChild(self.glyphElt);
		}
	};

	this.glyphOn = 'fa ' + settings.glyphOn + ' ' + modGliph;
	this.glyphOff = 'fa ' + settings.glyphOff + ' ' + modGliph;
	this.callbackOn = settings.callbackOn;
	this.callbackOff = settings.callbackOff;
	this.save = function () {
		localStorage.setItem(self.name, self.active);
	};
	this.load = function () {
		var t = localStorage.getItem(self.name);
		if (t === 'true') {
			self.setActive(true);
		}
		else {
			self.setActive(false);
		}
	};
	this.handlerClick = function (e) {
		if (self.active) {
			self.setActive(false);
		}

		else {
			self.setActive(true);
		}
	};

	this.setActive = function (val) {
		val = !!val;
		self.active = val;
		self.save(val);

		if (val) {
			if (!!self.bindedElt) {
				self.bindedElt.classList.add('activeBtn');                    
				self.glyphElt.className = self.glyphOn;
			}

			if (!!self.callbackOn) {
				self.callbackOn(self);
			}
		}

		else {
			if (!!self.bindedElt) {
				self.bindedElt.classList.remove('activeBtn');
				self.glyphElt.className = self.glyphOff;
			}

			if (!!self.callbackOff) {
				self.callbackOff(self);
			}
		}
	};
}


// LastVisit functions              
function checkLastVisit(){
	var timer = 7200000;
	var lastVisit = parseInt(ls.getItem('lastVisit'));
	var prevVisit = parseInt(ls.getItem('preLastVisit'));

	var currentVisit = new Date().valueOf();
	if ((!lastVisit)||(!prevVisit)) {
		updateLastVisit();      
	}
	if ((lastVisit + timer) < currentVisit) {
		updateLastVisit();
	}
}

function updateLastVisit(){
	var posts = 'http://gelbooru.com/index.php?page=post&s=list&tags=all';
	handleXHRDoc(posts, function(doc){
		var lastIdElt = doc.getElementsByClassName('thumb')[0];
		var lastID = lastIdElt.getAttribute('id');
		lastID = lastID.replace('s', '');

		if (!!ls.getItem('lastVisit')) {
			ls.setItem('preLastVisit',ls.getItem('lastVisit')); 
		}
		else{
			ls.setItem('preLastVisit',new Date().valueOf()); 
		}
		if (ls.getItem('lastImageId')) {
			ls.setItem('preImageId',ls.getItem('lastImageId'));
		}
		else{
			ls.setItem('preImageId',lastID);
		}

		localStorage.setItem('lastVisit',new Date().valueOf());
		localStorage.setItem('lastImageId', lastID);
	});
}

function getLastImageId(){
	var t = localStorage.getItem('preImageId');
	return parseInt(t);
}

})();

function handleXHRDoc(reqString, callback){
	var doc = document.implementation.createHTMLDocument("example");
	
	var xmlhttp = new XMLHttpRequest();
	xmlhttp.open('GET', reqString, true);
	xmlhttp.send(null);
	xmlhttp.onreadystatechange = handle;
	
	function handle(){              
		if (xmlhttp.readyState == 4) {
			if(xmlhttp.status == 200) {
				doc.documentElement.innerHTML = xmlhttp.responseText;
				console.log(doc);
				callback(doc);
			}
			
			else{
				console.log('Error xhr of ' + reqString);
			}
		}
	}    
}


//from http://stackoverflow.com/questions/2246901/how-can-i-use-jquery-in-greasemonkey-scripts-in-google-chrome
function load(a, b, c) {
	var d;
	d = document.createElement("script"), d.setAttribute("src", a), b !== null && d.addEventListener("load", b), c !== null && d.addEventListener("error", c), document.body.appendChild(d);
	return d;
} 
function execute(a) {
	var b, c;
	typeof a == "function" ? b = "(" + a + ")();" : b = a, c = document.createElement("script"), c.textContent = b, document.body.appendChild(c);
	return c;
}
function loadAndExecute(a, b) {
	return load(a, function () {
		return execute(b);
	});
}
//
function qS(selector){
	return document.querySelectorAll(selector)[0];
}

function hide(elt){
	if (!!elt) {
		elt.style.display = 'none';
	}
	else{
		console.log('Not found' + elt );
	}
	
}
function show(elt){
	if (!!elt) {
		elt.style.display = '';
	}
	else{
		console.log('Not found' + elt );
	}    
	
}

function removeAllChild(elem){
	while (elem.hasChildNodes()) {
		elem.removeChild(elem.lastChild);
	}
}

function hasClass(elem, name) {
	if (!!elem) {
		if (!!elem.classList) {
			if (elem.classList.contains(name)) {
				return true;
			}
		}
	}
	return false;
}    

function addStyle(css){
	if (typeof GM_addStyle != "undefined") {
		GM_addStyle(css);
	} else if (typeof PRO_addStyle != "undefined") {
		PRO_addStyle(css);
	} else if (typeof addStyle != "undefined") {
		addStyle(css);
	} else {
		var node = document.createElement("style");
		node.type = "text/css";
		node.appendChild(document.createTextNode(css));
		var heads = document.getElementsByTagName("head");
		if (heads.length > 0) {
			heads[0].appendChild(node); 
		} else {
			// no head yet, stick it whereever
			document.documentElement.appendChild(node);
		}
	}   
} 


function applyCSSRulesFromJS(){
	var style = document.createElement("style"); 
	style.appendChild(document.createTextNode(getCSSText()));

	// Add the <style> element to the page
	document.head.appendChild(style);

	return style.sheet;
}

function makeDiv(className){
	var div = document.createElement('div');
	div.className = className;
	return div;
}

function makeSpan(className){
	var div = document.createElement('span');
	div.className = className;
	return div;
}

function TabbedPane (){
	var self = this;
	var tabbedPane = makeDiv("tabbed-Pane");     
	var navPane = makeDiv("nav-Pane");
	var contentPane = makeDiv("content-Pane");
	tabbedPane.appendChild(navPane);
	tabbedPane.appendChild(contentPane);
	this.tabbedPane = tabbedPane;
	this.navPane = navPane;
	this.navMap= {};
	this.contentPane = contentPane;
	this.addTab = function(realName,visibleName,content){
		var head = makeDiv('tab-Head');
		head.textContent  = visibleName;
		var tab = new TabPane(self, realName, head, content);
		self.navMap[realName]= tab;
		self.navPane.appendChild(head);
		head.addEventListener('click', tab.clickHandler, false);
	};
	this.selectTab = function(tab){
		var loopTab;
		
		for (var key in self.navMap) {
			if (self.navMap.hasOwnProperty(key)){
				loopTab = self.navMap[key];
				loopTab.setSelected(false);
			}            
		}

		removeAllChild(self.contentPane);
		tab.setSelected(true);
		self.contentPane.appendChild(tab.content);
	};
	this.selectDefault = function(){
		for (var key in self.navMap) {
			if (self.navMap.hasOwnProperty(key)){
				self.navMap[key].clickHandler();
				break;
			}            
		}
	};
}

function TabPane(master,name,head,content){
	var self = this;
	this.name = name;
	this.masterPane = master;
	this.head = head;
	this.content = content;
	this.selected = false;
	this.setSelected = function(val){
		if (!!val) {
			self.head.classList.add('activeTab');
			self.selected = true;
		}
		else{
			self.head.classList.remove('activeTab');
			self.selected = false;
		}
	};
	this.clickHandler = function(e){
		self.setSelected(true);
		master.selectTab(self);
	};

}

var observeDOM = (function(){
	var MutationObserver = window.MutationObserver;

	return function(obj, callback){
			// define a new observer
			var obs = new MutationObserver(function(mutations, observer){
				if( mutations[0].addedNodes.length || mutations[0].removedNodes.length )
					//console.log(obj)
				callback(mutations);
			});
			// have the observer observe foo for changes in children
			obs.observe( obj, { childList:true, subtree:false });
		}
	})();