// ==UserScript==
// @name Gelbooru KonaStyle
// @namespace http://Aestellar.homepage/
// @version 0.15
// @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==
/*jshint multistr: true */
(function(){
var win = window;
var ls = localStorage;
var css = GM_getResourceText ("gelbooruCss1");
var searcher;
if(!win){
console.log(win + "Failed to load window object");
return;
}
if(win.self != win.top){
return;
}
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 fontAwesomeLoader = document.createElement('div');
//Font awesome support Don't work with @resource
fontAwesomeLoader.innerHTML = '<link rel="stylesheet" type="text/css" media="screen" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.0.3/css/font-awesome.css" />';
fontAwesomeLoader = fontAwesomeLoader.children[0];
document.head.appendChild(fontAwesomeLoader);
}
function updateUI(){
loadPrereq();
checkLastVisit();
searcher = new SearchWidget();
searcher.init();
createSettingsWindow();
updateNav();
updateThumbs();
}
function SearchWidget (){
this.searchElt = undefined;
this.searchForm = undefined;
this.filtersList = [];
var self = this;
this.submit = function(e){
var text = self.searchElt.value;
text = self.applySearchFilters(text);
self.searchElt.value = text;
};
this.applySearchFilters = function(text){
for (var i = 0; i < this.filtersList.length; i++) {
text = this.filtersList[i](text);
}
return text;
};
this.init = function(){
this.searchElt = qS('#stags')||qS('#tags');
if (!this.searchElt) {
throw new Error('Search field not found');
}
this._createFilters();
this.searchForm = qS('.sidebar3 form');
if (!this.searchForm) {
throw new Error('Search form not found');
}
this.searchForm.onsubmit = this.submit;
};
this._createFilters = function(){
var newImageFilter = function(text){
if (ls.getItem('onlyNewSearch')==='true') {
if (!!getLastImageId()) {
var newId = ' id:>' + getLastImageId() + ' ';
if (text.indexOf(newId)===-1) {
text+=newId;
}
}
}
return text;
};
this.filtersList.push(newImageFilter);
};
}
function updateThumbs(){
var c = qS('.thumb');
if (!c){
return;
}
var thumbsContainer = c.parentNode;
c = thumbsContainer.parentNode;
processThumbs(thumbsContainer);
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 appendThumbPane(thumb){
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 if (getTagListFromThumb(thumb).search('webm')!=-1) {
makeRef('webm');
}
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);
}
var dataId = getIdFromThumb(thumb);
test.setAttribute('data-id', dataId);
test.setAttribute('data-voted', '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;
count = parseInt(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];
loop = new RegExp('\\b'+ loop + '\\b');
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 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 getFavoritesTagsList(){
var favoritesList = ls.getItem('favoritesTagsList');
return favoritesList;
}
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(makeSettingsInner());
}
function makeSettingsInner(){
var div = document.createElement('div');
div.innerHTML = '<span class="modalName">Settings</span>';
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);
var bannedTagsTab = document.createElement('textarea');
bannedTagsTab.className = 'bannedList';
bannedTagsTab.value = getBannedList();
bannedTagsTab.addEventListener('input',function(e){
ls.setItem('bannedTagsList',e.target.value);
},false);
var favoritesTagsTab = document.createElement('textarea');
favoritesTagsTab.className = 'bannedList';
favoritesTagsTab.value = getFavoritesTagsList();
favoritesTagsTab.addEventListener('input',function(e){
ls.setItem('favoritesTagsList',e.target.value);
},false);
settTab.addTab('sett1', 'Settings', mainSetting);
settTab.addTab('sett2','Banned tags', bannedTagsTab);
//settTab.addTab('sett3','Favorites tags', favoritesTagsTab);
//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);
fitBtn.title = 'Autofit image or webm to page width';
var imageFit = makeToggleButton(fitBtn, {name:'fitImage',
glyphOff:'fa fa-compress',
glyphOn:'fa fa-expand',
callbackOff:fitImage,
callbackOn:fitImage});
function fitImage(){
var img = qS('#image')||qS('#gelcomVideoPlayer');
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', fitImage, 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 });
}
})();