// ==UserScript==
// @name EhxVisited
// @namespace https://sleazyfork.org/en/users/285675-hauffen
// @version 2.45.41
// @description E-H Visited, combined with ExVisited, and then better.
// @author Hauffen
// @require https://code.jquery.com/jquery-3.3.1.min.js
// @include /https?:\/\/(e-|ex)hentai\.org\/.*/
// ==/UserScript==
(function() {
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction || {READ_WRITE: "readwrite"};
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
if (!window.indexedDB) {
console.warn("Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available.");
return;
}
/*═════════════════════════════╗
║ Configuration Defaults ║
╚═════════════════════════════*/
var setStore = JSON.parse(localStorage.getItem("ehx-settings")) ? JSON.parse(localStorage.getItem("ehx-settings")) : JSON.parse('{"softHide":false, "minAdd":true, "minShow":false, "cssTT":false, "repPub":false, "visHide":false, "hidShow":false, "pFilter":false, "pLimit":0, "stFilter":false, "stLimit":0, "titleShow":true}');
var filters = localStorage.getItem("ehx-filters") ? localStorage.getItem("ehx-filters") : "#\\[Erocolor\\]";
var cssA = JSON.parse(localStorage.getItem("ehx-css")) ? JSON.parse(localStorage.getItem("ehx-css")) : JSON.parse('{"visible":"box-shadow: inset 0 0 0 500px rgba(2, 129, 255, .2) !important;", "hidden":"box-shadow: inset 0 0 0 500px rgba(255, 40, 0, .2) !important;", "filter":"box-shadow: inset 0 0 0 500px rgba(200, 0, 100, .2) !important;", "page":"box-shadow: inset 0 0 0 500px rgba(0, 0, 180, .2) !important;", "rating":"box-shadow: inset 0 0 0 500px rgba(180, 80, 60, .2) !important;"}');
var cssV = localStorage.getItem("ehx-cssv") ? localStorage.getItem("ehx-cssv") : "box-shadow: inset 0 0 0 500px rgba(2, 129, 255, .2) !important;";
var cssH = localStorage.getItem("ehx-cssh") ? localStorage.getItem("ehx-cssh") : "box-shadow: inset 0 0 0 500px rgba(255, 40, 0, .2) !important;";
var cssD = (setStore.softHide) ? "opacity:0.2; -webkit-opacity: 0.2;" : "display: none;";
/*════════════════════════════*/
let db = null;
var filterArr = [];
var pIS = 0; // Post Infinite Scroll
var observer = new MutationObserver(e => {
pIS = true; // Triggered on mutation, should never be false at this point though
addCSS();
});
var spl = document.URL.split("/");
var d1 = spl[3];
var galleries = JSON.parse('{"data":{}}');
var hidden = JSON.parse('{"data":{}}');
var ehxClearConfirm = 0, ehxhClearConfirm = 0;
if (d1 == "g") addGallery(); // Add the current page to galleries
if (d1.substr(0, 1) == "?" || d1.substr(0, 1) == "w" || d1.substr(0, 1) == "#" || d1.substr(0, 1) == "f" || d1.substr(0, 1) == "t" || !d1) {
populateFilter();
populate();
}
/**
* Populate the custom filter array with user input converted into regular expressions
*/
function populateFilter() {
if (filters != "") {
var tempArr = filters.split("\n");
for(var i = 0; i < tempArr.length; i++) {
if (tempArr[i].startsWith("#")) continue;
filterArr.push(new RegExp(tempArr[i], "i"));
}
}
}
/**
* Add a gallery to our IndexedDB
*/
function addGallery() {
const request = indexedDB.open("ehxvisited", 1);
request.onupgradeneeded = e => { // Generate our database if it's not there
db = e.target.result;
if (!db.objectStoreNames.contains('galleries')) {
db.createObjectStore('galleries', {keyPath: 'id'});
}
if (!db.objectStoreNames.contains('hidden')) {
db.createObjectStore('hidden', {keyPath: 'id'});
}
};
request.onsuccess = e => {
db = e.target.result;
var objStore = db.transaction('galleries', 'readwrite').objectStore('galleries');
var openRequest = objStore.openCursor(spl[4] + "." + spl[5]);
openRequest.onsuccess = e => {
var cursor = openRequest.result;
if (cursor) { // Update entry if key exists
cursor.update({id: spl[4] + "." + spl[5], visited: Date.now()});
console.log("EhxVisited: Updated " + spl[4] + "." + spl[5]);
} else { // Otherwise, add entry
objStore.add({id: spl[4] + "." + spl[5], visited: Date.now()});
console.log("EhxVisited: Added " + spl[4] + "." + spl[5]);
}
};
openRequest.onerror = e => {
console.log(`EhxVisited: Something bad happened with gallery ${spl[4]}.${spl[5]}: ${e.target.error}`);
};
};
};
/**
* Updates the hidden gallery count in the header object
*/
function updateGListing() {
// There's probably a better way to do this portion rather than iterate through all current objects, but runtime is negligible
var list = $(".itg .gl1t").length > 0 ? $(".itg .gl1t") : $("table.itg>tbody>tr").has('.glhide, .gldown, th'); // Get the proper elements depending on our view mode
var hAmount, vAmount, fAmount, pAmount, rAmount, hCount;
hAmount = vAmount = fAmount = pAmount = rAmount = hCount = 0;
for (var i = 0; i < list.length; i++) {
if ($(list[i]).hasClass("ehx-hidden")) { // Count generic Hidden galleries
if ($(list[i]).hasClass("ehx-visited")) vAmount++;
hCount++;
}
if ($(list[i]).attr("data-jqstyle") != undefined) { // Count elements via JQ Style tags
if ($(list[i]).attr("data-jqstyle").match('h')) hAmount++;
if ($(list[i]).attr("data-jqstyle").match('f')) fAmount++;
if ($(list[i]).attr("data-jqstyle").match('p')) pAmount++;
if ($(list[i]).attr("data-jqstyle").match('r')) rAmount++;
}
if($(".ehx-show").text() === "Show") { // If Visited Galleries are hidden, count those as well
if ($(list[i]).hasClass("ehx-visited")) {
vAmount++;
hCount++;
}
}
}
if(!setStore.softHide) {
$("#hideCount").html("There " + (hCount > 1 || hCount == 0 ? 'are ' : 'is ') + "<span>" + hCount + " hidden " + (hCount > 1 || hCount == 0 ? 'galleries' : 'gallery') + "</span> on this page.");
} else {
$("#hideCount").html("There are <span>0 hidden galleries</span> on this page.");
}
$("#hideCount > span").prop("title", "Hidden: " + hAmount + " | Visited: " + vAmount + " | Filtered: " + fAmount + " | Page Limit: " + pAmount + " | Rating Limit: " + rAmount);
}
/**
* Convert the star count of a specified element to a double
* @param {Object} el - A specific element within the DOM
*/
function getStarNumber(el) {
var stars = $(el).find(".ir").css("background-position");
switch(stars) {
case "0px -1px":
return 5;
case "0px -21px":
return 4.5;
case "-16px -1px":
return 4;
case "-16px -21px":
return 3.5;
case "-32px -1px":
return 3;
case "-32px -21px":
return 2.5;
case "-48px -1px":
return 2;
case "-48px -21px":
return 1.5;
case "-64px -1px":
return 1;
case "-64px -21px":
return 0.5;
default:
return 0;
}
}
/**
* Check a specified element through the filters individually, then apply jqstyle tags for CSS
* @param {Object} el - A specific element within the DOM
*/
function filterCheck(el) {
if (filterArr.length > 0) {
if(filterArr.some(rx => rx.test($(el).find('.glink').text()))) { // Test our gallery name through our regex filters
if(!$(el).hasClass('ehx-hidden')) {
$(el).addClass("ehx-hidden");
}
addStyle($(el), "f");
}
}
// Filter our galleries through the star limit filter
if (setStore.stFilter && setStore.stLimit > 0) {
if (getStarNumber(el) < setStore.stLimit) {
if(!$(el).hasClass('ehx-hidden')) {
$(el).addClass("ehx-hidden");
}
addStyle($(el), "r");
}
}
var pages = 0; // Page Count is stored in a lot of different random elements throughout, there are probably better selectors for this
if ($(".gl1e").length) { pages = $(el).find('.gl3e > div:nth-child(5)').text().split(" ")[0]; }
else if ($(".gl1c").length) { pages = $(el).find('.gl4c > div:nth-child(2)').text().split(" ")[0]; }
else if ($(".gl1t").length) { pages = $(el).find('.gl5t > div:nth-child(2) > div:nth-child(2)').text().split(" ")[0]; }
else { pages = $(el).find('.gl2m > div:nth-child(2) > div:nth-child(2) > div:nth-child(2) > div:nth-child(2)').text().split(" ")[0]; }
if (setStore.pFilter && setStore.pLimit > 0) {
if(parseInt(pages) < parseInt(setStore.pLimit)) {
if(!$(el).hasClass('ehx-hidden')) {
$(el).addClass("ehx-hidden");
}
addStyle($(el), "p");
}
}
}
/**
* Adds the specified style flag to a specified element
* @param {Object} el - A specific element within the DOM
* @param {String} flag - A character to mark an element for JQ Styling CSS rules
*/
function addStyle(el, flag) {
if ($(el).attr("data-jqstyle") != undefined) {
$(el).attr("data-jqstyle", $(el).attr("data-jqstyle") + flag);
} else {
$(el).attr("data-jqstyle", flag);
}
}
/**
* Removes the specified style flag from a specified element
* @param {Object} el - A specific element within the DOM
* @param {string} flag - A JQ Style flag to remove from an element
*/
function removeStyle(el, flag) {
if ($(el).attr("data-jqstyle") != undefined) {
$(el).attr("data-jqstyle", $(el).attr("data-jqstyle").replace(flag, ''));
} else {
$(el).attr("data-jqstyle", "");
}
}
/**
* Toggles a specified element's hidden status
* @param {String} tga - Full gallery URL
* @param {Object} el - A specific element within the DOM
*/
function toggleElement(tga, el) {
const request = indexedDB.open("ehxvisited", 1);
var tgid = tga.split('/')[4] + "." + tga.split('/')[5];
request.onsuccess = e => {
db = e.target.result;
var objStore = db.transaction("hidden", "readwrite").objectStore("hidden");
var openReq = objStore.openCursor(tgid);
openReq.onsuccess = e => {
var cursor = e.target.result;
if (cursor) { // Gallery already exists within our hidden table
cursor.delete();
console.log("EhxVisited: Removed " + tgid + " from hidden list.");
$(el).removeClass("ehx-hidden");
removeStyle($(el), "h");
delete hidden.data[tgid]; // Remove gallery listing from our local store of hidden galleries
} else {
objStore.put({id: tgid}); // Put the gallery into our hidden table
console.log("EhxVisited: Added " + tgid + " to hidden list.");
$(el).addClass("ehx-hidden");
addStyle($(el), "h");
hidden.data[tgid] = 1; // Add gallery listing to our local store of hidden galleries
}
updateGListing();
$("#hLength").text(Object.keys(hidden.data).length);
}
}
}
/**
* Fill our local gallery listings so we can preform easier operations on the data.
* Also set up the majority of our global HTML elements and their functions.
*/
function populate() {
const request = indexedDB.open("ehxvisited", 1);
request.onupgradeneeded = e => {
db = e.target.result;
if (!db.objectStoreNames.contains('galleries')) {
db.createObjectStore('galleries', {keyPath: 'id'});
}
if (!db.objectStoreNames.contains('hidden')) {
db.createObjectStore('hidden', {keyPath: 'id'});
}
};
request.onsuccess = e => {
db = e.target.result;
var objStore = db.transaction("galleries", "readonly").objectStore("galleries");
var openReq = objStore.getAll();
openReq.onsuccess = f => {
console.log("EhxVisited: Populated global variables.");
var transform = f.target.result;
for (var i = 0; i < transform.length; i++) {
galleries.data[transform[i].id] = transform[i].visited; // Force matrix data into array data
}
var gLength = Object.keys(galleries.data).length
var objStore2 = db.transaction("hidden", "readonly").objectStore("hidden");
var openReq2 = objStore2.getAll();
openReq2.onsuccess = g => {
var transform2 = g.target.result;
for (i = 0; i < transform2.length; i++) {
hidden.data[transform2[i].id] = 1; // Force matrix data into array data
}
var hLength = Object.keys(hidden.data).length
$("#toppane").append("<ehx class='ehx-controls'>Galleries visited: <span id='gLength'>" + gLength + "</span> ( <span id='ehx-menu-control'></span><a href='javascript:;' class='ehx-settings'>Settings</a> )<br/>Hidden Galleries: <span id='hLength'>" + hLength + "</span><span id='ehxh-menu-control'></span></ehx>");
if (!setStore.softHide) {
$("#ehx-menu-control").append("<a href='javascript:;' class='ehx-show'>Hide</a> / ");
$("#ehxh-menu-control").append(" ( <a href='javascript:;' class='ehxh-show'>Show</a> )");
}
$(".ehx-settings").click(e => {
e.preventDefault();
settings();
return false;
});
$(".ehx-show").click(e => {
var disp = $(".ehx-visited.ehx-hidden").css("display");
if ($(".ehx-show").text() === "Show") {
$(".ehx-visited").css({display: ""});
$(".ehx-visited.ehx-hidden").css({display: disp});
} else {
$(".ehx-visited").css({display: "none"});
$(".ehx-visited.ehx-hidden").css({display: disp});
}
$(".ehx-show").text((i, t) => {
return t === "Show" ? "Hide" : "Show";
});
updateGListing();
setStore.visHide = $(".ehx-show")[0].innerText === "Show" ? true : false;
localStorage.setItem("ehx-settings", JSON.stringify(setStore)); // Update our stored settings
});
$(".ehxh-show").click(e => {
if ($(".ehxh-show").text() === "Show") {
if ($(".gl1t").length == 0) { // For table view modes
$(".ehx-hidden").css({display: $(".ehx-hidden").parent().find("tr").not(".ehx-hidden").css("display")}); // Copy the display CSS of our closest element
$(".ehx-visited.ehx-hidden").css({display: $(".ehx-hidden").parent().find("tr").not(".ehx-hidden").css("display")});
} else { // Default display CSS for thumbnail
$(".ehx-hidden").css({display: 'flex'});
$(".ehx-visited.ehx-hidden").css({display: 'flex'});
}
} else {
$(".ehx-hidden").css({display: ""});
$(".ehx-visited.ehx-hidden").css({display: ""});
}
$(".ehxh-show").text((i, t) => { // Toggle text
return t === "Show" ? "Hide" : "Show";
});
updateGListing();
setStore.hidShow = $(".ehxh-show")[0].innerText === "Hide" ? true : false;
localStorage.setItem("ehx-settings", JSON.stringify(setStore));
});
addCSS();
$(".ehx-controls").append("<br /><span id='hideCount'><span></span></span>");
updateGListing();
}
}
}
}
/**
* Our main function that does basically everything that we see.
* Appends our custom HTML objects to the main page.
* Adds CSS to elements based on whether they can be found in the populated local gallery listing.
*/
function addCSS() {
observer.disconnect(); // Disconnect the observer, or else all the CSS changes will trigger the mutation observer
var img_hide = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAIhSURBVDjLlZPrThNRFIWJicmJz6BWiYbIkYDEG0JbBiitDQgm0PuFXqSAtKXtpE2hNuoPTXwSnwtExd6w0pl2OtPlrphKLSXhx07OZM769qy19wwAGLhM1ddC184+d18QMzoq3lfsD3LZ7Y3XbE5DL6Atzuyilc5Ciyd7IHVfgNcDYTQ2tvDr5crn6uLSvX+Av2Lk36FFpSVENDe3OxDZu8apO5rROJDLo30+Nlvj5RnTlVNAKs1aCVFr7b4BPn6Cls21AWgEQlz2+Dl1h7IdA+i97A/geP65WhbmrnZZ0GIJpr6OqZqYAd5/gJpKox4Mg7pD2YoC2b0/54rJQuJZdm6Izcgma4TW1WZ0h+y8BfbyJMwBmSxkjw+VObNanp5h/adwGhaTXF4NWbLj9gEONyCmUZmd10pGgf1/vwcgOT3tUQE0DdicwIod2EmSbwsKE1P8QoDkcHPJ5YESjgBJkYQpIEZ2KEB51Y6y3ojvY+P8XEDN7uKS0w0ltA7QGCWHCxSWWpwyaCeLy0BkA7UXyyg8fIzDoWHeBaDN4tQdSvAVdU1Aok+nsNTipIEVnkywo/FHatVkBoIhnFisOBoZxcGtQd4B0GYJNZsDSiAEadUBCkstPtN3Avs2Msa+Dt9XfxoFSNYF/Bh9gP0bOqHLAm2WUF1YQskwrVFYPWkf3h1iXwbvqGfFPSGW9Eah8HSS9fuZDnS32f71m8KFY7xs/QZyu6TH2+2+FAAAAABJRU5ErkJggg==";
var list = $("table.itg>tbody>tr").has('.glhide, .gldown, th'); // Present only in list views
var thumb = $(".itg .gl1t"); // Present only in thumbnail view
var gid, galleryId, onFavs, d;
if (list.length > 0) {
if ($('.gl1e').length) { // Extended
if ($('h1').text() === "Favorites") {
onFavs = 1;
}
for (var i = 0; i < list.length; i++) {
gid = $(list[i]).find(".gl1e a").attr("href").split("/");
galleryId = gid[4] + "." + gid[5];
if ($(list[i])[0].children.length === 2 && onFavs) {
$(list[i]).append('<td></td>');
}
if(galleries.data[galleryId] != undefined) {
if (!$(list[i]).hasClass('ehx-visited')) {
d = new Date(galleries.data[galleryId]);
$(list[i]).addClass("ehx-visited");
if (setStore.cssTT) $(list[i]).find('.glname').attr("title", 'EhxVisited: ' + timeDifference(galleries.data[galleryId]) + " (" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ") " + d.getFullYear().toString() + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate());
// Check for fav pages
if ($(list[i]).find('.gl3e').children('div').length >= 7) { // Date favourited div is present
$(list[i]).find('.gl3e > div:last-child').append("<br><ehx class='ehx-extended-favs'>\uD83D\uDC41" + timeDifference(galleries.data[galleryId]) + "<br>" + d.getFullYear().toString() + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate() + " (" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ")</ehx>");
} else {
$(list[i]).find('.gl3e').append("<ehx class='ehx-extended'>\uD83D\uDC41" + timeDifference(galleries.data[galleryId]) + "<br>" + d.getFullYear().toString() + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate() + " (" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ")</ehx>");
}
}
} else {
if (setStore.cssTT) $(list[i]).find('.glname').attr("title", "Never Visited");
}
if(hidden.data[galleryId] != undefined) {
if(!$(list[i]).hasClass('ehx-hidden')) {
$(list[i]).addClass("ehx-hidden");
}
addStyle($(list[i]), "h");
}
if($(list[i])[0].childElementCount < 3) { // Don't append anything if it's already been appended
$("<img class='imgHide' src='" + img_hide + "' style='cursor:pointer !important; padding:4px 0px 0px 4px;' title='Show/Hide gallery'>").prependTo($(list[i]).find("a").first().parent().parent().parent()).on('click', e => {
var el = $(e.currentTarget).parent();
toggleElement($(el).find("a").attr("href"), $(el));
})
}
filterCheck($(list[i]));
}
updateGListing();
} else if ($('.gl1c').length) { // Compact
var borderColour = $('.gl1c').first().css('border-top-color'); // Border colour is different between domains
if (!pIS && $('table.itg tbody>tr:first-child')[0].children.length < 5) { // Apend our table columns to the table head
$('table.itg tbody>tr:first-child th:nth-child(4)').after('<th style="text-align:center;" title="EhxVisited: Click to Show/Hide">✖</th>');
$('table.itg tbody>tr:first-child th:nth-child(2)').after('<th>Visited</th>');
pIS = true;
}
if ($('h1').text() === "Favorites") {
onFavs = 1;
}
for (i = 1; i < list.length; i++) {
gid = $(list[i]).find(".glname a").attr("href").split("/");
galleryId = gid[4] + "." + gid[5];
if ($(list[i])[0].children.length === 4 || $(list[i])[0].children.length === 5 && onFavs) {
if ($(list[i])[0].children.length === 4 && onFavs) {
$(list[i]).append('<td></td>');
}
if(galleries.data[galleryId] != undefined) {
d = new Date(galleries.data[galleryId]);
$(list[i]).addClass("ehx-visited");
if (setStore.cssTT) $(list[i]).find('.glname').attr("title", 'EhxVisited: ' + timeDifference(galleries.data[galleryId]) + " (" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ") " + d.getFullYear().toString() + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate());
$(list[i]).children('.gl2c').after('<td class="ehx-compact" style="border-color:' + borderColour + ';"><ehx>' + timeDifference(galleries.data[galleryId], true) + "<br>(" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ')<br>' + d.getFullYear().toString().substr(2) + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate() + '</ehx></td>');
} else {
if (setStore.cssTT) $(list[i]).find('.glname').attr("title", "Never Visited");
$(list[i]).children('.gl2c').after('<td class="ehx-compact" style="border-color:' + borderColour + ';"></td>');
}
}
if(hidden.data[galleryId] != undefined) {
if(!$(list[i]).hasClass('ehx-hidden')) {
$(list[i]).addClass("ehx-hidden");
}
addStyle($(list[i]), "h");
}
if($(list[i])[0].childElementCount < 6) { // Don't append anything if it's already been appended
$("<td class='hideContainer' style='border-bottom: 1px solid #6f6f6f4d; border-top: 1px solid #6f6f6f4d;'><img class='imgHide' src='" + img_hide + "' style='cursor:pointer !important; vertical-align:center;' title='Show/Hide gallery'></td>").appendTo($(list[i]).find("a").first().closest("tr")).on('click', e => {
var el = $(e.currentTarget).closest("tr");
toggleElement($(el).find($(".gl3c > a")).attr("href"), $(el));
})
}
filterCheck($(list[i]));
}
updateGListing();
} else { // Minimal
if(!pIS) { // Append our table columns to the table head
$('table.itg tbody>tr:first-child th:nth-child(6)').after('<th style="text-align:center;" title="EhxVisited: Click to Show/Hide">✖</th>');
if (setStore.minAdd) {
$('table.itg tbody>tr:first-child th:nth-child(2)').after('<th title="EhxVisited: Hover for timestamps">\uD83D\uDC41</th>');
}
pIS = true;
}
if (setStore.repPub) {
$('table.itg tbody>tr:first-child')[0].children[1].innerText = "Visited"
}
if ($('h1').text() === "Favorites") {
onFavs = 1;
}
for (i = 1; i < list.length; i++) {
gid = $(list[i]).find(".glname a").attr("href").split("/");
galleryId = gid[4] + "." + gid[5];
if(hidden.data[galleryId] != undefined) {
if(!$(list[i]).hasClass('ehx-hidden')) {
$(list[i]).addClass("ehx-hidden");
}
addStyle($(list[i]), "h");
}
if ($(list[i])[0].children.length === 6 || $(list[i])[0].children.length === 7 && onFavs) {
if ($(list[i])[0].children.length === 6 && onFavs) {
$(list[i]).append('<td></td>');
}
if (setStore.minAdd) { // Append viewed column
if (galleries.data[galleryId] != undefined) {
d = new Date(galleries.data[galleryId]);
$(list[i]).addClass("ehx-visited");
if (setStore.cssTT) $(list[i]).find('.glname').attr("title", 'EhxVisited: ' + timeDifference(galleries.data[galleryId]) + " (" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ") " + d.getFullYear().toString() + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate());
if (setStore.minShow) { // Show text in appended column
$(list[i]).children('.gl2m').after('<td class="ehx-minimal-text"><ehx>' + timeDifference(galleries.data[galleryId], true) + "<br>(" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ')<br>' + d.getFullYear().toString().substr(2) + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate() + '</ehx></td>');
} else { // Show icon in appended column
$(list[i]).children('.gl2m').after('<td class="ehx-minimal" title="EhxVisited: ' + timeDifference(galleries.data[galleryId]) + " (" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ") " + d.getFullYear().toString() + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate() + '"><ehx>\uD83D\uDC41</ehx></td>');
}
if (setStore.repPub) {
$(list[i]).find(".gl2m").text(d.getFullYear().toString() + "\u2011" + ('0' + (d.getMonth() + 1)).slice(-2) + "\u2011" + d.getDate() + " " + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0'));
}
} else { // Not viewed
$(list[i]).children('.gl2m').after('<td class="ehx-minimal"></td>'); // Only append another table cell to the row
if (setStore.repPub) $(list[i]).find(".gl2m").text("Never Visited");
if (setStore.cssTT) $(list[i]).find('.glname').attr("title", "Never Visited");
}
} else { // Append nothing, highlight only
if (galleries.data[galleryId] != undefined) {
d = new Date(galleries.data[galleryId]);
$(list[i]).addClass("ehx-visited");
$(list[i]).children('.glname')[0].setAttribute("title", 'EhxVisited: ' + timeDifference(galleries.data[galleryId]) + " (" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ") " + d.getFullYear().toString() + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate());
}
}
if($(list[i])[0].childElementCount < 8 || ($(list[i])[0].childElementCount < 8 && !setStore.minAdd)) { // Don't append anything if it's already been appended // I'll have to look at this conditional again, seems redundant
$("<td class='hideContainer'><img class='imgHide' src='" + img_hide + "' style='cursor:pointer !important; vertical-align:middle;' title='Show/Hide gallery'></td>").appendTo($(list[i]).find("a").first().closest("tr")).on('click', e => {
var el = $(e.currentTarget).closest("tr");
toggleElement($(el).find($(".gl3m > a")).attr("href"), $(el));
})
}
filterCheck($(list[i]));
}
}
updateGListing();
}
} else if (thumb.length > 0) { // Thumbnail
for (i = 0; i < thumb.length; i++) {
gid = $(thumb[i]).find(".gl3t a").attr("href").split("/");
galleryId = gid[4] + "." + gid[5];
if(galleries.data[galleryId] != undefined) {
if (!$(thumb[i]).hasClass('ehx-visited')) {
d = new Date(galleries.data[galleryId]);
$(thumb[i]).addClass("ehx-visited");
if (setStore.cssTT) {
$(thumb[i]).find('.glname').attr("title", 'EhxVisited: ' + timeDifference(galleries.data[galleryId]) + " (" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ") " + d.getFullYear().toString() + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate());
}
$(thumb[i]).children('.gl5t').after("<ehx class='ehx-thumbnail'>\uD83D\uDC41" + timeDifference(galleries.data[galleryId]) + " (" + d.getHours().toString().padStart(2, '0') + ":" + d.getMinutes().toString().padStart(2, '0') + ") " + d.getFullYear().toString() + "\u2011" + (d.getMonth() + 1) + "\u2011" + d.getDate() + "</ehx>");
}
} else {
if (setStore.cssTT) {
$(thumb[i]).find('.glname').attr("title", "Never Visited");
}
}
if(hidden.data[galleryId] != undefined) {
if(!$(thumb[i]).hasClass('ehx-hidden')) {
$(thumb[i]).addClass("ehx-hidden");
}
addStyle($(thumb[i]), "h");
}
if($(thumb[i]).find(".gl5t").children().length < 3) { // Don't append anything if it's already been appended
$("<div class='hideContainer'><img class='imgHide' src='" + img_hide + "' style='cursor:pointer !important; position:absolute; bottom:3px; left:2px;' title='Show/Hide gallery'></div>").appendTo($(thumb[i]).find(".gl5t")).on('click', e => {
var el = $(e.currentTarget).parent().parent();
toggleElement($(el).find("a").attr("href"), $(el));
})
}
filterCheck($(thumb[i]));
}
updateGListing();
} else {
console.log("EhxVisited: Something went wrong or an invalid view"); // This happens when you use empty() on itg, which can happen with other scripts
}
if (setStore.visHide) {
$(".ehx-visited").css({display: "none"});
$(".ehx-show").text("Show");
}
if (setStore.hidShow) {
if ($(".ehx-hidden").length < 25) { $(".ehx-hidden").css({display: $(".ehx-hidden").siblings().not(".ehx-hidden").css("display")}) } // Make sure there are elements on the page
else { // Unless you're an idiot and hid everything on the page
if ($(".gl1t").length) { $(".ehx-hidden").css({display: "flex"}); } // Use the default values
else { $(".ehx-hidden").css({display: "table-row"}); }
}
$(".ehxh-show").text("Hide");
}
observer.observe($('.itg').get(0), { // Reconnect the observer for changes
childList: true,
subtree: true
});
}
/**
* Get time difference in words
* @param {Date} previous - Previous date to compare against Date.now()
* @param {Boolean} abbreviate - Should the text string have abbreviatated text
*/
function timeDifference(previous, abbreviate) {
var msPerMinute = 60 * 1000;
var msPerHour = msPerMinute * 60;
var msPerDay = msPerHour * 24;
var msPerMonth = msPerDay * 30;
var msPerYear = msPerDay * 365;
var elapsed = Date.now() - previous;
if (elapsed < msPerMinute) {
return Math.round(elapsed / 1000) + ((typeof abbreviate !== 'undefined') ? ' sec' : ' seconds ago');
} else if (elapsed < msPerHour) {
return Math.round(elapsed / msPerMinute) + ((typeof abbreviate !== 'undefined') ? ' min' : ' minutes ago');
} else if (elapsed < msPerDay) {
return Math.round(elapsed / msPerHour) + ((typeof abbreviate !== 'undefined') ? ' hrs' : ' hours ago');
} else if (elapsed < msPerMonth) {
return Math.round(elapsed / msPerDay) + ((typeof abbreviate !== 'undefined') ? ' days' : ' days ago');
} else if (elapsed < msPerYear) {
return Math.round(elapsed / msPerMonth) + ((typeof abbreviate !== 'undefined') ? ' mos' : ' months ago');
} else {
return Math.round(elapsed / msPerYear) + ((typeof abbreviate !== 'undefined') ? ' yrs' : ' years ago');
}
}
/**
* Generates a text area with formatted gallery data for export
* @param {String} message - A message to display as the legend or title of the text area
* @param {IndexedDB Matrix} items - Raw IndexedDB getAll output
*/
function ehxExport(message, items) {
var data = "";
for (var i in items) {
data += items[i].id + ":" + items[i].visited + ";";
}
if ($('.ehx-exported-data').length) { // Remove any data if it exists for whatever reason
$('.ehx-exported-data').remove();
}
$('.section-container').prepend('<section class="ehx-exported-data"><fieldset><legend>' + message + '</legend><div><textarea class="ehx-exported-data-text">' + data + '</textarea></div></fieldset></section>');
}
$(".itg").on("mousedown", "a", e => {
if (e.which === 3) return; // Ignore right-clicks
if (e.currentTarget.href.split('/')[3] === "g") {
galleries.data[e.currentTarget.href.split('/')[4] + "." + e.currentTarget.href.split('/')[5]] = Date.now();
$("#gLength").text(Object.keys(galleries.data).length);
addCSS();
}
});
/**
* Import user data into our indexedDB
* @param {String} store - An object store within the indexedDB
* @param {JSON Array} items - String of exported data to import
*/
function ehxImport(store, items) {
var objStore2 = db.transaction(store, 'readwrite').objectStore(store);
var count = 0, sp = "";
/**
* Push entries into the specified indexedDB store
*/
function insertNext() {
if (count < sp.length) {
var str = sp[count].split(":");
objStore2.put({id: str[0], visited: parseInt(str[1])}).onsuccess = insertNext; // Update the record if it's there, or add it if it's not, then continue
++count;
} else {
console.log("EhxVisited: Merge Completed");
}
}
if (typeof items == "undefined") {
var c = prompt("EhxVisited:\nPaste here to import " + (store == 'hidden' ? 'hidden ' : '') + "galleries.");
if (c) {
sp = c.split(";");
sp = sp.filter(Boolean); // Filter out any null ("") entries
insertNext();
alert("EhxVisited:\nImported " + sp.length + " entries.");
location.reload();
}
} else {
sp = items.split(";");
sp = sp.filter(Boolean); // Filter out any null ("") entries
insertNext();
alert("EhxVisited:\nImported " + sp.length + " entries."); // Change this probably
}
}
/**
* Open the Settings menu and set up all necessary menu functions
*/
function settings() {
const req = indexedDB.open("ehxvisited", 1);
req.onsuccess = e => {
if (db == null) db = e.target.result;
var objStore = db.transaction('galleries', 'readwrite').objectStore('galleries');
var openReq = objStore.getAll();
openReq.onsuccess = e => {
var len = e.target.result;
// There's probably a much easier way to do this, or at least a nicer looking, more technical way
var container = $(`
<div class="overlay">
<div class="settings">
<nav class="topNav">
<span style="float:left;margin-left:3px;font-weight:lighter;opacity:0.5;-webkit-opacity:0.5;">All Settings Will Be Applied On Close</span>
<div>
<div class="mencon">
<button class="menu">Export</button>
<div class="dropdown">
<a id="ehx-export" href="javascript:;">Export Galleries</a>
<a id="ehxh-export" href="javascript:;">Export Hidden Galleries</a>
</div>
</div>
<div class="mencon">
<button class="menu">Import</button>
<div class="dropdown">
<a id="ehx-import" href="javascript:;">Import Galleries</a>
<a id="ehxh-import" href="javascript:;">Import Hidden Galleries</a>
</div>
</div>
<a id="settings-close" href="javascript:;">🞫</a>
</div>
</nav>
<div class="section-container">
<section>
<fieldset>
<legend>Settings</legend>
<div>
<label>
<input type="checkbox" id="softHide" ` + (setStore.softHide ? `checked` : ``) + `>Soft Hide Galleries
</label>
<span>: Darken hidden galleries instead of removing them from view</span>
</div>
<div>
<label>
<input type="checkbox" id="minAdd" ` + (setStore.minAdd ? `checked` : ``) + `>Minimal Add Column
</label>
<span>: Show visits in an additional column in Minimal/Minimal+ view modes</span>
<div class="suboptions">
<div>
<span class="branch">∟</span>
<label>
<input type="checkbox" id="minShow" ` + (setStore.minShow ? `checked` : ``) + `>Minimal Show Text
</label>
<span>: Show visits as text instead of hovering tooltip in Minimal/Minimal+ view modes</span>
</div>
</div>
</div>
<div>
<label>
<input type="checkbox" id="cssTT" ` + (setStore.cssTT ? `checked` : ``) + `>CSS Tooltips
</label>
<span>: Replace gallery link tooltips with visited information in all view modes</span>
</div>
<div>
<label>
<input type="checkbox" id="repPub" ` + (setStore.repPub ? `checked` : ``) + `>Replace Published
</label>
<span>: Replace date published with date visited in Minimal/Minimal+ view modes</span>
</div>
<div>
<label>
<input type="checkbox" id="titleShow" ` + (setStore.titleShow ? `checked`: ``) + `>Show Full Title
</label>
<span>: Show the full title of a gallery on hover in Thumbnail view</span>
</div>
</fieldset>
<fieldset>
<legend>Custom CSS</legend>
<h3>Visited Galleries
<div class="control" id="visControls">
<button id="resV">Reset CSS</button>
<button class="ehx-clear">Clear Data</button>
</div>
</h3>
<textarea id="visited" class="field" spellcheck="false" placeholder="Insert CSS">` + cssA.visible + `</textarea>
<h3>Hidden Galleries
<div class="control sControls" id="hideControls">
<button id="resH">Reset CSS</button>
<button class="ehxh-clear">Clear Data</button>
</div>
</h3>
<textarea id="hidden" class="field" spellcheck="false" placeholder="Insert CSS">` + cssA.hidden + `</textarea>
<div class="suboptions2">
<button class="collapsible">Filtered Galleries</button>
<div class="content">
<textarea id="filtered" class="field" spellcheck="false">` + cssA.filter + `</textarea>
<div class="control sControls">
<button id="resF">Reset CSS</button>
</div>
</div>
<button class="collapsible">Page Filtered</button>
<div class="content">
<textarea id="page" class="field" spellcheck="false"placeholder="Insert CSS">` + cssA.page + `</textarea>
<div class="control sControls">
<button id="resP">Reset CSS</button>
</div>
</div>
<button class="collapsible">Rating Filtered</button>
<div class="content">
<textarea id="rating" class="field" spellcheck="false" placeholder="Insert CSS">` + cssA.rating + `</textarea>
<div class="control sControls">
<button id="resR">Reset CSS</button>
</div>
</div>
</div>
</fieldset>
<fieldset>
<legend>Filters</legend>
Use one <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions">regular expression</a> per line to filter out matching galleries.
<ul style="margin: 3px 0px; padding-left: 30px;">
<li>E.G. <code>Ongoing</code> will filter out every gallery with <code>ongoing</code>, case-insensitive, in the title. <code>\\[Digital\\]</code> will filter out every gallery with <code>[Digital]</code>, case-insensitive, in the title.</li>
<li>Lines starting with <code>#</code> will be ignored.</li>
</ul>
<textarea id="galFilter">` + filters + `</textarea>
<div>
<label>
<input type="checkbox" id="pFilt" ` + (setStore.pFilter ? `checked` : ``) + `>Page Limit
</label>
<span>: Filter out any gallery with pages less than:
<input id="pLim" type="number" min="1" value="` + setStore.pLimit + `" ` + (setStore.pFilter ? `` : `disabled`) + `/>
</span>
</div>
<div>
<label>
<input type="checkbox" id="stFilt" ` + (setStore.stFilter ? `checked` : ``) + `>Minimum Rating
</label>
<span>: Filter out any gallery with a rating less than:
<select id="stLim" ` + (setStore.stFilter ? `` : `disabled`) + `>
<option>5</option>
<option>4.5</option>
<option>4</option>
<option>3.5</option>
<option>3</option>
<option>2.5</option>
<option>2</option>
<option>1.5</option>
<option>1</option>
</select>
</span>
</div>
</fieldset>
</section>
</div>
</div>
</div>`);
$("body").append(container);
if (!$("#minAdd").prop("checked")) { $("#minShow").prop("disabled", true); }
$("#resV").click(e => { $("#visited").val("box-shadow: inset 0 0 0 500px rgba(2, 129, 255, .2) !important;"); }); // Default Values
$("#resH").click(e => { $("#hidden").val("box-shadow: inset 0 0 0 500px rgba(255, 40, 0, .2) !important;"); });
$("#resF").click(e => { $("#filtered").val("box-shadow: inset 0 0 0 500px rgba(200, 0, 100, .2) !important;"); });
$("#resP").click(e => { $("#page").val("box-shadow: inset 0 0 0 500px rgba(0, 0, 180, .2) !important;"); });
$("#resR").click(e => { $("#rating").val("box-shadow: inset 0 0 0 500px rgba(180, 80, 60, .2) !important;"); });
$("#stLim").val(setStore.stLimit);
$(document).on("change", "input", e => { // Put the change listener on document since I suck at event propogation and bubbling
if ($("#minAdd").prop('checked')) {
$("#minShow").prop("disabled", false);
} else {
$("#minShow").prop("disabled", true);
}
if ($("#pFilt").prop('checked')) {
$("#pLim").prop("disabled", false);
} else {
$("#pLim").prop("disabled", true);
}
if ($("#stFilt").prop('checked')) {
$("#stLim").prop("disabled", false);
} else {
$("#stLim").prop("disabled", true);
}
});
$("#settings-close").click(e => applySettings());
$("body").click(e => {
if (e.target.className == "overlay") { // Exit if settings menu isn't clicked
applySettings();
} else if (e.target.className != "show" && e.target.className != "menu") {
$(".show").removeClass("show");
}
});
/**
* Parse our HTML options into a temporary JSON array and then stringify it into localStorage
*/
function applySettings() {
var tempSto = {
"softHide": $("#softHide").prop('checked'),
"minAdd": $("#minAdd").prop('checked'),
"minShow": $("#minShow").prop('checked'),
"cssTT": $("#cssTT").prop('checked'),
"repPub": $("#repPub").prop('checked'),
"visHide": $(".ehx-show").text() === "Show" ? true : false,
"hidShow": $(".ehxh-show").text() === "Hide" ? true : false,
"pFilter": $("#pFilt").prop('checked'),
"pLimit": $("#pFilt").prop('checked') ? $("#pLim").val() : "0",
"stFilter": $("#stFilt").prop('checked'),
"stLimit": $("#stFilt").prop('checked') ? $("#stLim option:selected").text() : "0",
"titleShow": $("#titleShow").prop('checked')
}
localStorage.setItem("ehx-settings", JSON.stringify(tempSto)); // Write settings to localStorage
var tempCss = {
"visible": $("#visited").val(),
"hidden": $("#hidden").val(),
"filter": $("#filtered").val(),
"page": $("#page").val(),
"rating": $("#rating").val()
}
localStorage.setItem("ehx-css", JSON.stringify(tempCss));
localStorage.setItem("ehx-filters", $("#galFilter").val().replace(/^\s*[\r\n]/gm, '')); // Remove null entries because bad things happen if they're there
$(".overlay").remove(); // Not entirely necessary, but slightly cosmetic
location.reload(); // Force reload to apply settings, I'll probably change this into just a button and not force reload
}
$(".collapsible").click(e => { // Expand our custom filtering CSS boxes
if ($(".active").length && !$(".active").is(e.target)) { // If a menu is open and it isn't the one we're clicking, close it
$(".active").next().css("max-height", "");
$(".active").toggleClass("active");
}
e.target.classList.toggle("active");
var content = e.target.nextElementSibling;
if (content.style.maxHeight){
content.style.maxHeight = null;
} else {
content.style.maxHeight = "500px";
}
});
$("#ehx-import").click(e => ehxImport('galleries'));
$("#ehxh-import").click(e => ehxImport('hidden'));
$("#ehx-export").click(e => {
ehxExport('Exported Entries:', len);
});
$("#ehxh-export").click(e => {
var objStore2 = db.transaction('hidden', 'readwrite').objectStore('hidden');
var openReq = objStore2.getAll();
openReq.onsuccess = e => {
ehxExport('Exported Entries:', e.target.result);
}
});
$(".ehx-clear").click(e => {
if (!ehxClearConfirm) { // Make sure to double check before deleting
ehxClearConfirm = 1;
$('.ehx-clear').append(': Are you sure?');
ehxExport('Backup your current data:', len);
} else {
var objStore2 = db.transaction('galleries', 'readwrite').objectStore('galleries');
var openReq = objStore2.clear();
openReq.onsuccess = e => {
alert("EhxVisited:\nCleared all entries.");
location.reload();
}
}
});
$(".ehxh-clear").click(e => {
var objStore2 = db.transaction('hidden', 'readwrite').objectStore('hidden');
var openReq = objStore2.getAll();
openReq.onsuccess = e => {
if (!ehxhClearConfirm) { // Make sure to double check before deleting
ehxhClearConfirm = 1;
$('.ehxh-clear').append(': Are you sure?');
ehxExport('Backup your current data:', e.target.result);
} else {
var objStore3 = db.transaction('hidden', 'readwrite').objectStore('hidden');
var openReq = objStore3.clear();
openReq.onsuccess = e => {
alert("EhxVisited:\nCleared all entries.");
location.reload();
}
}
}
});
// Fancy function to make sure there's not more than one top menu item open
$(".menu").click(e => {
if ($(".show").length) {
if ($(".show").prev().is(e.target)) { $(e.target).next().toggleClass("show"); }
else {
$(".show").removeClass("show");
$(e.target).next().toggleClass("show");
}
} else {
$(e.target).next().toggleClass("show");
}
});
}
}
}
// The giant CSS block
$(`<style data-jqstyle='ehxVisited'>
#hideCount > span { border-bottom: 1px dotted currentColor; }
#settings-close {
text-decoration: none;
position: absolute;
top: -2px;
right: 1.5px;
font-size: 1.4em;
}
#visControls { top: -6px; } `
+ (setStore.titleShow ? `div.gl4t:hover { overflow: visible; z-index: 3; position: relative; background: rgba(0, 0, 0, 0.5); height: auto; }` : ``) + `
ehx { font-family:` + $('body').css('font-family') + `, arial, symbola; }
table.itg > tbody > tr.ehx-visited, .gl1t.ehx-visited { ` + cssA.visible + ` }
input[type="checkbox"] {
-webkit-appearance: none;
border: 1px solid #F1F1F1BB;
padding: 5px;
top: 4px;
background-color: transparent;
}
input[type="checkbox"]:checked:after {
content: '\\2714';
position: absolute;
top: -8px;
left: 1px;
font-size: 1.1em;
}
input[type="checkbox"]:focus { outline: none; }
input[type="checkbox"]:hover { cursor: pointer; }
nav > div {
text-align: right;
margin-right: 30px;
}
nav > div button {
border: none !important;
padding: 1px 20px 1px 10px !important;
position: relative;
}
table.itg > tbody > tr.ehx-visited.ehx-hidden, .gl1t.ehx-visited.ehx-hidden { ` + cssA.hidden + ` }
.active:after { content: '\\2212' !important; }
.branch {
position: absolute;
left: 10px;
top: 1px;
margin-left: -3px;
}
.collapsible {
cursor: pointer;
width: 100%;
border: 0;
outline: none;
text-align: left;
font-size: 1.25em;
background-color: rgba(0, 0, 0, 0);
color: inherit;
font-weight: bold;
padding:5px 3px;
position: relative;
}
.collapsible:after {
content: '\\002B';
font-weight:bold;
float:right;
margin-right:5px;
}
.collapsible:before {
content: '';
position: absolute;
padding: 4px;
border-bottom: 1px solid threedface;
border-left: 1px solid threedface;
top: 5px;
left: -11px;
}
.collapsible:hover { background-color: rgba(255, 255, 255, 0.1); }
.content {
max-height: 0;
overflow: hidden;
transition: all .2s ease-in-out;
border-bottom: 1px solid threedface;
}
.content button {
margin-top: 3px;
margin-right: 10px;
}
.control {
position: relative;
float: right;
right: -5px;
}
.dropdown {
display: none;
position: absolute;
z-index: 999;
min-width: 150px;
padding: 2px;
border-radius: 1px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
right: 0px;
border: 1px solid threedface;
background: ` + $(".ido").css("background") + `;
background: ` + $(".ido").css("backgroundColor") + `;
}
.dropdown a {
display: block;
text-decoration: none;
padding-right:2px;
}
.dropdown a:hover { background: rgba(255,255,255,0.2); }
.ehx-compact {
border-style: solid;
border-width: 1px 0;
text-align: center;
}
.ehx-controls {
padding: 3px 1px;
text-align: center;
display: block;
}
.ehx-exported-data { display: block; }
.ehx-extended {
width: 120px;
position: absolute;
left: 3px;
top: 172px;
text-align: center;
font-size: 8pt;
line-height: 1.5;
}
.ehx-extended-favs {
padding: 3px 1px;
display: block;
line-height: 1.5;
}
.ehx-hidden { ` + cssD + cssA.hidden + ` }
.ehx-hidden[data-jqstyle*="f"] {` + cssA.filter + `}
.ehx-hidden[data-jqstyle*="p"] {` + cssA.page + `}
.ehx-hidden[data-jqstyle*="r"] {` + cssA.rating + `}
.ehx-minimal {
border-left: 1px solid #6f6f6f4d;
}
.ehx-minimal-text {
text-align: center;
display: block;
}
.ehx-thumbnail {
display: block;
text-align: center;
margin: 3px 0 5px;
line-height: 12px;
}
.ehx-visited .gl3e { min-height: 206px; }
.ehx-visited .gl4e { min-height: 264px !important; }
.gl2c { width: 115px; }
.mencon {
display: inline-block;
position: relative;
}
.menu:after {
content: '\\2335';
position: absolute;
right: 5px;
bottom: 1px;
}
.overlay {
background: rgba(0,0,0,0.5);
display: -webkit-flex;
display: flex;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 100;
font-size: 9pt;
}
.overlay button:not(.collapsible) {
background-color: transparent;
border-radius: 6px;
border: 1px solid threedface;
cursor: pointer;
font-weight: bold;
padding: 3px 20px;
text-decoration: none;
color: inherit;
margin-left: 5px;
}
.overlay button:not(.collapsible):hover { background-color: rgba(255, 255, 255, 0.1); }
.overlay button:not(.collapsible):focus { outline: none; }
.sControls { top: -3px; }
.section-container {
text-align: left;
overflow: auto;
}
.section-container textarea:disabled, .section-container input:disabled, .section-container select:disabled {
opacity: 0.6;
-webkit-opacity: 0.6;
}
.section-container input[type="number"] {
border: 1px solid #8d8d8d;
margin-left:0px;
text-align: center;
width: 50px;
}
.section-container select { margin-left: 0px; }
.section-container code {
color: #000;
background-color: #FFF;
}
.section-container fieldset { padding-right: 18px; }
.settings {
background: ` + $(".ido").css("background") + `;
background: ` + $(".ido").css("backgroundColor") + `;
box-sizing: border-box;
height: 555px;
max-height: 100%;
width: 900px;
max-width: 100%;
margin: auto;
padding: 5px;
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
box-shadow: 0px 0px 20px 0px rgba(0,0,0,0.5);
}
.settings nav {
text-align: right;
padding-bottom: 5px;
font-weight: bold;
position: relative;
}
.settings legend {
font-size: 10pt;
font-weight: bold;
}
.settings label {
font-weight: bold;
text-decoration: underline;
cursor: pointer;
}
.settings h3 {
margin: 3px;
position: relative;
}
.settings input { vertical-align: -1px; }
.settings textarea {
width: 100%;
height: 50px;
resize: vertical;
}
.show { display:block }
.suboptions { position: relative; }
.suboptions > div {
position: relative;
padding-left: 1.4em;
}
.suboptions2 {
margin-left: 4px;
padding-left: 10px;
margin-right: -9px;
}
</style>`).appendTo("head");
})();