mirror of
https://github.com/stashapp/CommunityScripts.git
synced 2026-02-04 10:49:10 -06:00
* Fix #437 * Bump version --------- Co-authored-by: Luke Tanner <luke.c.tanner@gmail.com> Co-authored-by: DogmaDragon <103123951+DogmaDragon@users.noreply.github.com>
764 lines
30 KiB
JavaScript
764 lines
30 KiB
JavaScript
(async () => {
|
|
while (!window.csLib) {
|
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
}
|
|
|
|
function waitForElementClass(selector, callback) {
|
|
csLib.waitForElement(`.${selector}`, callback);
|
|
}
|
|
|
|
const svgChevDN =
|
|
'<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="chevron-down" class="svg-inline--fa fa-chevron-down fa-icon collapse-icon fa-fw" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M201.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L224 338.7 54.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z"></path></svg>';
|
|
const svgChevUP =
|
|
'<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="chevron-right" class="svg-inline--fa fa-chevron-right fa-icon collapse-icon fa-fw" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path fill="currentColor" d="M310.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-192 192c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L242.7 256 73.4 86.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l192 192z"></path></svg>';
|
|
const svgBTN =
|
|
'<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 102 123" width="20" height="20"><title>paint-icon-svg</title><style> .s0 { fill: #fafafa } .s1 { fill: #efaa3a } .s2 { fill: #25a700 } .s3 { fill: #e22952 } .s4 { fill: #42a3cc } </style><path id="Layer" class="s0" d="m42.6 114.5q3 0.4 6.1 0.4 3 0 6-0.4 3-0.4 6-1.2 2.9-0.8 5.7-1.9 1.1-0.5 2.2-1 1.1-0.5 2.1-1 1.1-0.6 2.1-1.2 1-0.6 2-1.2l0.7 6.9q-0.8 0.5-1.6 0.9-0.9 0.4-1.7 0.8-0.8 0.5-1.7 0.8-0.9 0.4-1.7 0.8-3.2 1.3-6.5 2.2-3.4 0.9-6.8 1.3-3.4 0.5-6.9 0.5-3.4-0.1-6.8-0.5-3.7-0.5-7.2-1.7-3.6-1.1-6.9-2.8-3.3-1.6-6.3-3.8-3-2.2-5.6-4.9-2.8-2.8-5.1-6-2.3-3.1-4.2-6.6-1.8-3.4-3.2-7.1-1.3-3.7-2.1-7.6-1-4.7-1.2-9.5-0.1-4.8 0.6-9.5 0.8-4.7 2.3-9.3 1.6-4.5 4-8.7 2.3-4.2 5.4-7.9 3.1-3.8 6.8-6.9 3.7-3.1 7.9-5.6 4.1-2.4 8.7-4 1.5-0.6 3-1 1.5-0.4 3.1-0.7 1.6-0.2 3.2-0.2 1.5-0.1 3.1 0.1 1.4 0.2 2.7 0.6 1.3 0.4 2.6 1.1 1.2 0.7 2.2 1.6 1 1 1.9 2.1 0 0 0.1 0.1 0 0.1 0 0.2 0.1 0 0.1 0.1 0.1 0.1 0.1 0.2c2.9 6.6-0.6 10.8-4 14.8-2 2.3-3.8 4.5-2.7 6.6 0.4 0.9 1.6 1.5 3.2 2q1 0.2 2 0.3 1 0.1 2 0.1 1 0 2 0 1-0.1 2-0.3c2.5-0.4 5.2-1 7.8-1.5 1.5-0.4 3-0.7 4.5-1l-2 6.8-1.3 0.3c-2.5 0.5-5.1 1.1-8.1 1.6q-1.3 0.2-2.6 0.3-1.3 0.1-2.6 0.1-1.3 0-2.7-0.2-1.3-0.2-2.6-0.5c-3.3-0.8-5.9-2.6-7.2-5.1-3-5.9 0.1-9.6 3.5-13.6 2-2.4 4.2-5 3.2-7.9q-0.5-0.6-1-1-0.6-0.5-1.2-0.8-0.7-0.3-1.4-0.5-0.6-0.2-1.4-0.3-1.2-0.1-2.4-0.1-1.2 0.1-2.4 0.2-1.2 0.2-2.3 0.5-1.2 0.3-2.3 0.8-4 1.5-7.7 3.6-3.7 2.2-7 4.9-3.2 2.8-6 6.1-2.7 3.3-4.8 7-2 3.7-3.4 7.7-1.4 4-2 8.2-0.7 4.2-0.6 8.4 0.2 4.3 1 8.4 0.7 3.4 1.9 6.7 1.2 3.3 2.9 6.3 1.6 3.1 3.6 5.9 2.1 2.8 4.5 5.3 2.3 2.3 4.9 4.2 2.5 1.9 5.4 3.4 2.8 1.4 5.9 2.4 3 0.9 6.2 1.4z"/><path id="Layer" fill-rule="evenodd" class="s1" d="m22.1 55.7c1.3 3.4 4.6 5.6 8.2 5.7 3.6 0.1 6.9-2 8.4-5.3 1.5-3.4 0.8-7.2-1.7-9.9-2.5-2.6-6.3-3.5-9.7-2.2-1.1 0.4-2.2 1.1-3 1.9-0.9 0.8-1.6 1.8-2.1 2.9-0.4 1.1-0.7 2.2-0.7 3.4 0 1.2 0.2 2.4 0.6 3.5z"/><path id="Layer" fill-rule="evenodd" class="s2" d="m16.8 82.5c1.3 3.4 4.5 5.7 8.2 5.8 3.7 0.1 7.1-2 8.6-5.3 1.5-3.4 0.8-7.3-1.7-10-2.6-2.7-6.5-3.6-9.9-2.3-1.1 0.5-2.1 1.1-3 1.9-0.9 0.9-1.6 1.9-2 2.9-0.5 1.1-0.8 2.3-0.8 3.5-0.1 1.2 0.2 2.4 0.6 3.5z"/><path id="Layer" fill-rule="evenodd" class="s3" d="m62.1 81.7q0.6 1.6 1.7 2.9 1.1 1.3 2.6 2.2 1.4 0.9 3.1 1.3 1.7 0.3 3.4 0.2l-2.1-20.7q-0.4 0-0.7 0.1-0.4 0-0.7 0.1-0.4 0.1-0.7 0.2-0.3 0.1-0.7 0.2c-1.2 0.5-2.4 1.2-3.4 2.2-1 0.9-1.8 2-2.4 3.3-0.5 1.2-0.8 2.6-0.8 4-0.1 1.3 0.1 2.7 0.6 4z"/><path id="Layer" fill-rule="evenodd" class="s0" d="m100.3 17.7c2.4 7.9 1.5 18.1-6.8 21.8q-0.8 0.4-1.6 0.6-0.9 0.2-1.7 0.2-0.8 0.1-1.7 0-0.8-0.1-1.6-0.4-1.4-0.4-2.7-1.1-1.3-0.8-2.4-1.8-1-0.9-1.9-2.1-0.9-1.2-1.5-2.5c-5.6-12.7 10.4-20.2 11.1-32.4 3.6 4.2 8.5 10.5 10.8 17.7zm-0.1 45.2l-4 54.6q0 0.5-0.1 1-0.1 0.5-0.3 1-0.2 0.5-0.4 1-0.3 0.5-0.6 0.9c-0.7 0.6-1.4 1-2.3 1.3-0.8 0.2-1.7 0.2-2.6 0-0.8-0.2-1.6-0.6-2.3-1.2-0.6-0.6-1.1-1.3-1.4-2.1q-0.1-0.4-0.2-0.9-0.1-0.4-0.2-0.8 0-0.4-0.1-0.8 0-0.5 0-0.9l-5.4-52.9q2.4 0.5 4.9 0.7 2.5 0.3 5 0.3 2.5 0 5-0.3 2.5-0.3 5-0.9zm-5.5-17.8c2.5 7.5 2.8 8.2 6 14.5-6.5 1.8-13.4 1.5-20.4 0l4.3-14.5c3.2 1.6 7.7 1 10.2 0z"/><path id="Layer" fill-rule="evenodd" class="s4" d="m40.8 101.6c1.3 3.4 4.5 5.7 8.2 5.8 3.7 0.1 7.1-2 8.6-5.4 1.5-3.3 0.8-7.3-1.7-9.9-2.6-2.7-6.5-3.6-9.9-2.3-1.1 0.5-2.1 1.1-3 1.9-0.9 0.9-1.6 1.8-2 2.9-0.5 1.1-0.8 2.3-0.8 3.5-0.1 1.2 0.2 2.4 0.6 3.5z"/></svg>';
|
|
|
|
let menuCreated = false;
|
|
|
|
function menuOrderListReset(element) {
|
|
const defaultOrder = [
|
|
"Scenes",
|
|
"Images",
|
|
"Groups",
|
|
"Markers",
|
|
"Galleries",
|
|
"Performers",
|
|
"Studios",
|
|
"Tags",
|
|
];
|
|
const ul = element.querySelector("ul");
|
|
const lis = Array.from(ul.querySelectorAll("li"));
|
|
|
|
// Sort the li elements based on their text content
|
|
lis.sort((a, b) => {
|
|
const aIndex = defaultOrder.indexOf(a.textContent);
|
|
const bIndex = defaultOrder.indexOf(b.textContent);
|
|
return aIndex - bIndex;
|
|
});
|
|
|
|
// Append the sorted li elements to the ul in their new order
|
|
lis.forEach((li) => ul.appendChild(li));
|
|
}
|
|
|
|
function menuOrderResetButton(elementToAppend) {
|
|
if (!document.getElementById("themeSwitchPlugin-menuOrderReset")) {
|
|
const resetButton = document.createElement("button");
|
|
resetButton.id = "themeSwitchPlugin-menuOrderReset";
|
|
resetButton.className = "btn btn-primary";
|
|
resetButton.innerHTML = "Reset Menu Order";
|
|
resetButton.addEventListener("click", function () {
|
|
localStorage.removeItem(
|
|
"themeSwitchPlugin-menu-changeOrderOfNavButtons"
|
|
);
|
|
document
|
|
.getElementById("themeSwitchPlugin-menu-changeOrderOfNavButtons")
|
|
.remove();
|
|
menuOrderListReset(elementToAppend);
|
|
resetButton.remove();
|
|
});
|
|
elementToAppend.appendChild(resetButton);
|
|
}
|
|
}
|
|
|
|
function buldDragCSS(themename, key) {
|
|
const container = document.querySelector(".draggable-ul-container");
|
|
const list = container.querySelectorAll("li");
|
|
let css = "";
|
|
|
|
for (let i = 0; i < list.length; i++) {
|
|
const item = list[i];
|
|
const key = item.getAttribute("data-rb-event-key");
|
|
const order = i - list.length;
|
|
css += `div.nav-link[data-rb-event-key="${key}"] { order: ${order}; }`;
|
|
}
|
|
|
|
const style = document.createElement("style");
|
|
style.type = "text/css";
|
|
style.id = key;
|
|
style.innerHTML = `nav .navbar-nav:first-child {
|
|
display: flex;
|
|
flex-direction: row;
|
|
}
|
|
${css}`;
|
|
|
|
const existing = document.getElementById(key);
|
|
if (existing) {
|
|
existing.remove();
|
|
}
|
|
|
|
document.getElementsByTagName("head")[0].appendChild(style);
|
|
|
|
const data = {
|
|
name: themename,
|
|
css: css,
|
|
key: key,
|
|
id: key,
|
|
applied: "true",
|
|
};
|
|
|
|
localStorage.setItem(key, JSON.stringify(data));
|
|
menuOrderResetButton(container.parentElement);
|
|
}
|
|
|
|
function enableDragSort(listClass) {
|
|
const sortableLists = document.getElementsByClassName(listClass);
|
|
Array.prototype.map.call(sortableLists, (list) => {
|
|
enableDragList(list);
|
|
});
|
|
}
|
|
|
|
function enableDragList(list) {
|
|
Array.prototype.map.call(list.children, (item) => {
|
|
enableDragItem(item);
|
|
});
|
|
}
|
|
|
|
function enableDragItem(item) {
|
|
item.setAttribute("draggable", true);
|
|
item.addEventListener("touchstart", handleTouchStart, { passive: true });
|
|
item.addEventListener("touchmove", handleTouchMove, { passive: true });
|
|
item.addEventListener("touchend", handleTouchEnd, { passive: true });
|
|
item.ondrag = handleDrag;
|
|
item.ondragend = handleDrop;
|
|
}
|
|
|
|
let touchEndY = null;
|
|
|
|
function handleTouchStart(event) {
|
|
event.preventDefault();
|
|
touchStartY = event.touches[0].clientY;
|
|
}
|
|
|
|
function handleTouchMove(event) {
|
|
event.preventDefault();
|
|
touchEndY = event.changedTouches[0].clientY;
|
|
const selectedItem = event.target,
|
|
list = selectedItem.parentNode;
|
|
selectedItem.classList.add("drag-sort-active");
|
|
let swapItem =
|
|
document.elementFromPoint(
|
|
selectedItem.getBoundingClientRect().x,
|
|
touchEndY
|
|
) === null
|
|
? selectedItem
|
|
: document.elementFromPoint(
|
|
selectedItem.getBoundingClientRect().x,
|
|
touchEndY
|
|
);
|
|
|
|
if (list === swapItem.parentNode) {
|
|
swapItem =
|
|
swapItem !== selectedItem.nextSibling ? swapItem : swapItem.nextSibling;
|
|
list.insertBefore(selectedItem, swapItem);
|
|
}
|
|
}
|
|
|
|
function handleTouchEnd(event) {
|
|
event.preventDefault();
|
|
touchEndY = event.changedTouches[0].clientY;
|
|
handleDragTouch(event.target);
|
|
}
|
|
|
|
function handleDragTouch(item) {
|
|
const selectedItem = item,
|
|
list = selectedItem.parentNode;
|
|
selectedItem.classList.remove("drag-sort-active");
|
|
let swapItem =
|
|
document.elementFromPoint(
|
|
selectedItem.getBoundingClientRect().x,
|
|
touchEndY
|
|
) === null
|
|
? selectedItem
|
|
: document.elementFromPoint(
|
|
selectedItem.getBoundingClientRect().x,
|
|
touchEndY
|
|
);
|
|
|
|
if (list === swapItem.parentNode) {
|
|
swapItem =
|
|
swapItem !== selectedItem.nextSibling ? swapItem : swapItem.nextSibling;
|
|
list.insertBefore(selectedItem, swapItem);
|
|
}
|
|
setTimeout(() => {
|
|
buldDragCSS(
|
|
"Change the order of navigation bar buttons",
|
|
"themeSwitchPlugin-menu-changeOrderOfNavButtons"
|
|
);
|
|
}, 100);
|
|
}
|
|
|
|
function handleDrag(item) {
|
|
const selectedItem = item.target,
|
|
list = selectedItem.parentNode,
|
|
x = event.clientX,
|
|
y = event.clientY;
|
|
|
|
selectedItem.classList.add("drag-sort-active");
|
|
let swapItem =
|
|
document.elementFromPoint(x, y) === null
|
|
? selectedItem
|
|
: document.elementFromPoint(x, y);
|
|
|
|
if (list === swapItem.parentNode) {
|
|
swapItem =
|
|
swapItem !== selectedItem.nextSibling ? swapItem : swapItem.nextSibling;
|
|
list.insertBefore(selectedItem, swapItem);
|
|
}
|
|
}
|
|
|
|
function handleDrop(item) {
|
|
item.target.classList.remove("drag-sort-active");
|
|
setTimeout(() => {
|
|
buldDragCSS(
|
|
"Change the order of navigation bar buttons",
|
|
"themeSwitchPlugin-menu-changeOrderOfNavButtons"
|
|
);
|
|
}, 100);
|
|
}
|
|
|
|
(() => {
|
|
enableDragSort("drag-sort-enable");
|
|
})();
|
|
|
|
waitForElementClass("draggable-ul-container", function () {
|
|
enableDragSort("draggable-ul-container");
|
|
});
|
|
|
|
function setObject(key, category, active) {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
localStorage.setItem(
|
|
key,
|
|
JSON.stringify({ category: category, active: active })
|
|
);
|
|
resolve();
|
|
} catch (error) {
|
|
reject(error);
|
|
}
|
|
});
|
|
}
|
|
|
|
function checkActive(key) {
|
|
let object = JSON.parse(localStorage.getItem(key));
|
|
if (object && object.active === true) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function addStyleSheet(key, path) {
|
|
console.log(key, path);
|
|
const styleSheet = document.createElement("link");
|
|
const serverURL =
|
|
window.location.origin +
|
|
document.querySelector("base")?.getAttribute("href") ?? "/";
|
|
styleSheet.setAttribute(
|
|
"href",
|
|
`${serverURL}plugin/themeSwitch/assets${path}`
|
|
);
|
|
styleSheet.setAttribute("rel", "stylesheet");
|
|
styleSheet.setAttribute("type", "text/css");
|
|
styleSheet.id = key;
|
|
document.getElementsByTagName("head")[0].appendChild(styleSheet);
|
|
}
|
|
|
|
async function applyCSS(category, key, path, pluginId, pluginSrc) {
|
|
if (category === "Themes") {
|
|
// Turn Off old Theme
|
|
let regex = /(themeSwitchPlugin-theme-.*)/;
|
|
|
|
for (let i = 0; i < localStorage.length; i++) {
|
|
let storageKey = localStorage.key(i);
|
|
let match = storageKey.match(regex);
|
|
if (
|
|
match &&
|
|
storageKey !== key &&
|
|
JSON.parse(localStorage.getItem(storageKey)).active === true
|
|
) {
|
|
setObject(storageKey, category, false);
|
|
let element = document.getElementById(storageKey);
|
|
if (element && !pluginId) {
|
|
element.remove();
|
|
} else {
|
|
const oldThemePluginId = getDataFromKey(storageKey, "pluginId");
|
|
if (oldThemePluginId) {
|
|
await enablePlugin(oldThemePluginId, false);
|
|
setTimeout(() => {
|
|
location.reload();
|
|
}, 1000);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const theme = JSON.parse(localStorage.getItem(key));
|
|
|
|
if (!theme && key != "themeSwitchPlugin-theme-default") {
|
|
setObject(key, category, true).then(() => {
|
|
addStyleSheet(key, path);
|
|
});
|
|
} else if (!theme && key === "themeSwitchPlugin-theme-default") {
|
|
setObject(key, category, true);
|
|
} else if (theme && key === "themeSwitchPlugin-theme-default") {
|
|
setObject(key, category, true);
|
|
} else if (theme && key !== "themeSwitchPlugin-theme-default") {
|
|
setObject(key, category, true).then(async () => {
|
|
if (pluginId) {
|
|
if (!(await isPluginInstalled(pluginId))) {
|
|
await installPlugin(pluginId, pluginSrc);
|
|
}
|
|
await enablePlugin(pluginId, true);
|
|
setTimeout(() => {
|
|
location.reload();
|
|
}, 1000);
|
|
} else if (path) {
|
|
addStyleSheet(key, path);
|
|
}
|
|
});
|
|
}
|
|
} else {
|
|
// CSS Other than themes
|
|
const storageObject = JSON.parse(localStorage.getItem(key));
|
|
if (!storageObject || storageObject.active === false) {
|
|
setObject(key, category, true).then(() => {
|
|
addStyleSheet(key, path);
|
|
});
|
|
} else if (storageObject.active && !document.getElementById(key)) {
|
|
addStyleSheet(key, path);
|
|
} else {
|
|
setObject(key, category, false).then(() => {
|
|
document.getElementById(key).remove();
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
function expandCollapse(category, name, span, collapse) {
|
|
let categorySpanClick = document.getElementById(span);
|
|
let categoryCollapseClick = document.getElementById(collapse);
|
|
let expanded =
|
|
categoryCollapseClick.getAttribute("aria-expanded") === "true";
|
|
|
|
if (expanded) {
|
|
categoryCollapseClick.setAttribute("aria-expanded", "false");
|
|
categoryCollapseClick.classList.add("expanding");
|
|
setTimeout(function () {
|
|
categoryCollapseClick.classList.remove("show");
|
|
categoryCollapseClick.classList.remove("expanding");
|
|
categorySpanClick.innerHTML = svgChevUP + category;
|
|
}, 300);
|
|
} else {
|
|
categoryCollapseClick.setAttribute("aria-expanded", "true");
|
|
categoryCollapseClick.classList.add("expanding");
|
|
setTimeout(function () {
|
|
categoryCollapseClick.classList.add("show");
|
|
categoryCollapseClick.classList.remove("expanding");
|
|
categorySpanClick.innerHTML = svgChevDN + category;
|
|
}, 300);
|
|
}
|
|
}
|
|
|
|
const getInstalledPlugins = async () =>
|
|
csLib
|
|
.callGQL({ query: `query Plugins{plugins{id}}` })
|
|
.then((data) => data.plugins.map((plugin) => plugin.id))
|
|
.catch((err) => console.error(err));
|
|
|
|
const isPluginInstalled = async (plugin) =>
|
|
getInstalledPlugins().then((plugins) => plugins.includes(plugin));
|
|
|
|
async function enablePlugin(plugin, state) {
|
|
const query =
|
|
"mutation SetPluginsEnabled($enabledMap: BoolMap!) { setPluginsEnabled(enabledMap: $enabledMap) }";
|
|
const variables = { enabledMap: {} };
|
|
variables.enabledMap[plugin] = state;
|
|
await csLib
|
|
.callGQL({ query, variables })
|
|
.catch((err) => console.error(err));
|
|
}
|
|
|
|
async function installPlugin(plugin, src) {
|
|
const query =
|
|
"mutation InstallPluginPackages($packages: [PackageSpecInput!]!) {installPackages(type: Plugin, packages: $packages)}";
|
|
const variables = {
|
|
packages: [
|
|
{
|
|
id: plugin,
|
|
sourceURL: src,
|
|
},
|
|
],
|
|
};
|
|
await csLib
|
|
.callGQL({ query, variables })
|
|
.catch((err) => console.error(err));
|
|
}
|
|
|
|
function createBTNMenu() {
|
|
return new Promise(function (resolve, reject) {
|
|
waitForElementClass("top-nav", function () {
|
|
if (!document.getElementById("themeSwitchPlugin")) {
|
|
const pluginDiv = document.createElement("div");
|
|
pluginDiv.className = "mr-2 dropdown";
|
|
pluginDiv.innerHTML =
|
|
'<button id="themeSwitchPlugin" aria-haspopup="true" aria-expanded="false" type="button" class="dropdown-toggle minimal d-flex align-items-center h-100 btn btn-primary" title="Theme Switcher">' +
|
|
svgBTN +
|
|
"</button>";
|
|
|
|
const themesDiv = document.createElement("div");
|
|
themesDiv.className = "dropdown-menu theme-plugin-menu";
|
|
|
|
document.addEventListener("click", function (event) {
|
|
const isClickInside =
|
|
pluginDiv.contains(event.target) ||
|
|
themesDiv.contains(event.target);
|
|
const isClickInsideThemesDiv = themesDiv.contains(event.target);
|
|
const themeSwitchPlugin =
|
|
document.getElementById("themeSwitchPlugin");
|
|
const expanded =
|
|
themeSwitchPlugin.getAttribute("aria-expanded") === "true";
|
|
|
|
if (expanded && !isClickInsideThemesDiv) {
|
|
themeSwitchPlugin.setAttribute("aria-expanded", "false");
|
|
themesDiv.classList.remove("show");
|
|
themesDiv.style =
|
|
"position: absolute; to0px; left: 0px; margin: 0px; opacity: 0; pointer-events: none;";
|
|
} else if (!expanded && isClickInside) {
|
|
themeSwitchPlugin.setAttribute("aria-expanded", "true");
|
|
themesDiv.classList.add("show");
|
|
themesDiv.style =
|
|
"position: absolute; top: 133%; left: 0px; margin: 0px; opacity: 1; pointer-events: auto; width: max-content; min-width: 20rem; left: -575%;";
|
|
} else if (!isClickInside && !isClickInsideThemesDiv) {
|
|
themeSwitchPlugin.setAttribute("aria-expanded", "false");
|
|
themesDiv.classList.remove("show");
|
|
themesDiv.style =
|
|
"position: absolute; top: 0px; left: 0px; margin: 0px; opacity: 0; pointer-events: none;";
|
|
}
|
|
});
|
|
|
|
const accordion = document.createElement("div");
|
|
accordion.className = "criterion-list accordion";
|
|
accordion.style = "max-width: 20rem !important;";
|
|
const header = document.createElement("div");
|
|
header.innerHTML = "Theme/CSS Switcher";
|
|
header.className = "modal-header";
|
|
accordion.append(header);
|
|
|
|
Object.entries(window.themeSwitchCSS).forEach(
|
|
([category, themesInCategory], i) => {
|
|
const categoryDiv = document.createElement("div");
|
|
categoryDiv.className = "card";
|
|
categoryDiv.setAttribute("data-type", category);
|
|
categoryDiv.setAttribute(
|
|
"id",
|
|
"themeSwitchPlugin-card-" + category
|
|
);
|
|
categoryDiv.style = "padding: 2px !important;";
|
|
const categoryHeader = document.createElement("div");
|
|
categoryHeader.className = "card-header";
|
|
categoryHeader.style = "padding: 0.375rem 0.625rem !important;";
|
|
const categorySpan = document.createElement("span");
|
|
categorySpan.innerHTML = svgChevUP + category;
|
|
categorySpan.setAttribute(
|
|
"id",
|
|
"themeSwitchPlugin-span-" + category
|
|
);
|
|
const collapseDiv = document.createElement("div");
|
|
collapseDiv.className = "collapse";
|
|
collapseDiv.setAttribute("aria-expanded", "false");
|
|
collapseDiv.setAttribute(
|
|
"id",
|
|
"themeSwitchPlugin-collapse-" + category
|
|
);
|
|
categoryDiv.addEventListener(
|
|
"click",
|
|
(function () {
|
|
return function (event) {
|
|
if (!event.target.closest(".collapse")) {
|
|
expandCollapse(
|
|
category,
|
|
"themeSwitchPlugin-card-" + category,
|
|
"themeSwitchPlugin-span-" + category,
|
|
"themeSwitchPlugin-collapse-" + category
|
|
);
|
|
}
|
|
};
|
|
})(i),
|
|
{ capture: true }
|
|
);
|
|
|
|
const cardBody = document.createElement("div");
|
|
cardBody.className = "card-body";
|
|
const editorDiv = document.createElement("div");
|
|
editorDiv.className = "criterion-editor";
|
|
const blankDiv = document.createElement("div");
|
|
const optionListFilter = document.createElement("div");
|
|
optionListFilter.className = "option-list-filter";
|
|
blankDiv.append(optionListFilter);
|
|
editorDiv.append(blankDiv);
|
|
cardBody.append(editorDiv);
|
|
collapseDiv.append(cardBody);
|
|
categoryHeader.append(categorySpan, collapseDiv);
|
|
const fieldset = document.createElement("fieldset");
|
|
fieldset.className = "checkbox-switch";
|
|
|
|
// Loop over themes in each category
|
|
themesInCategory.forEach((theme) => {
|
|
if (category === "Navigation") {
|
|
} else {
|
|
const forRow = document.createElement("div");
|
|
forRow.className = "checkbox-switch-form-row";
|
|
const legend = document.createElement("legend");
|
|
legend.innerHTML = theme.displayName;
|
|
legend.className = "legend-right";
|
|
const input = document.createElement("input");
|
|
|
|
if (category === "Themes") {
|
|
input.type = "radio";
|
|
input.name = "themeGroup";
|
|
const active = checkActive(theme.key);
|
|
input.checked = active;
|
|
} else {
|
|
input.type = "checkbox";
|
|
const active = checkActive(theme.key);
|
|
input.checked = active;
|
|
}
|
|
const themeData = {
|
|
category: category,
|
|
key: theme.key,
|
|
...(theme.path
|
|
? { path: theme.path }
|
|
: theme.pluginId
|
|
? {
|
|
pluginId: theme.pluginId,
|
|
pluginSrc: theme.pluginSrc,
|
|
}
|
|
: {}),
|
|
};
|
|
|
|
input.setAttribute("id", category + "-" + theme.key);
|
|
input.addEventListener(
|
|
"click",
|
|
(function (themeData) {
|
|
return async function () {
|
|
applyCSS(
|
|
themeData.category,
|
|
themeData.key,
|
|
themeData.path,
|
|
themeData.pluginId,
|
|
themeData.pluginSrc
|
|
);
|
|
};
|
|
})(themeData),
|
|
false
|
|
);
|
|
|
|
const label = document.createElement("label");
|
|
label.setAttribute("for", category + "-" + theme.key);
|
|
label.title = "Turn " + theme.displayName + " on/off";
|
|
label.className = "checkbox-right";
|
|
|
|
// Append the legend, input, and label elements to the fieldset element
|
|
forRow.appendChild(legend);
|
|
forRow.appendChild(input);
|
|
forRow.appendChild(label);
|
|
fieldset.appendChild(forRow);
|
|
optionListFilter.appendChild(fieldset);
|
|
categoryDiv.append(categoryHeader);
|
|
accordion.append(categoryDiv);
|
|
}
|
|
});
|
|
|
|
Object.entries(themesInCategory).forEach(([themeId, theme]) => {
|
|
if (category === "Navigation") {
|
|
const forRow = document.createElement("div");
|
|
forRow.className = "switch-form-row";
|
|
const legend = document.createElement("legend");
|
|
legend.innerHTML = theme.displayName;
|
|
legend.className = "legend-left";
|
|
|
|
const draggableStylesheetContent = localStorage.getItem(
|
|
"themeSwitchPlugin-menu-changeOrderOfNavButtons"
|
|
);
|
|
if (draggableStylesheetContent) {
|
|
// Read the stylesheet content and create an array called "elements"
|
|
var reset = true;
|
|
var navMenuItems = [];
|
|
const css = JSON.parse(draggableStylesheetContent).css;
|
|
const regex = /data-rb-event-key="\/([^"]+)"/g;
|
|
let match;
|
|
while ((match = regex.exec(css))) {
|
|
const key = match[1];
|
|
if (match[1] === "scenes/markers") {
|
|
const name = "Markers";
|
|
navMenuItems.push({ name, key });
|
|
} else {
|
|
const name =
|
|
match[1].charAt(0).toUpperCase() + match[1].slice(1);
|
|
navMenuItems.push({ name, key });
|
|
}
|
|
}
|
|
navMenuItems.sort((a, b) => a.order - b.order);
|
|
} else {
|
|
var navMenuItems = [
|
|
{ name: "Scenes", key: "scenes" },
|
|
{ name: "Images", key: "images" },
|
|
{ name: "Groups", key: "groups" },
|
|
{ name: "Markers", key: "scenes/markers" },
|
|
{ name: "Galleries", key: "galleries" },
|
|
{ name: "Performers", key: "performers" },
|
|
{ name: "Studios", key: "studios" },
|
|
{ name: "Tags", key: "tags" },
|
|
];
|
|
}
|
|
// const label = document.createElement("label");
|
|
legend.setAttribute("for", category + "-" + theme.key);
|
|
optionListFilter.appendChild(legend);
|
|
const formCheck = document.createElement("ul");
|
|
formCheck.className = "draggable-ul-container";
|
|
for (let i = 0; i < navMenuItems.length; i++) {
|
|
const li = document.createElement("li");
|
|
li.className = "draggable-li";
|
|
li.setAttribute(
|
|
"data-rb-event-key",
|
|
"/" + navMenuItems[i].key
|
|
);
|
|
li.setAttribute("draggable", true);
|
|
const newSpan = document.createElement("span");
|
|
newSpan.className = "grippy";
|
|
li.appendChild(newSpan);
|
|
const textNode = document.createTextNode(
|
|
navMenuItems[i].name
|
|
);
|
|
li.appendChild(textNode);
|
|
formCheck.appendChild(li);
|
|
}
|
|
|
|
optionListFilter.appendChild(formCheck);
|
|
|
|
if (reset) {
|
|
menuOrderResetButton(optionListFilter);
|
|
}
|
|
fieldset.appendChild(forRow);
|
|
optionListFilter.appendChild(fieldset);
|
|
categoryDiv.append(categoryHeader);
|
|
accordion.append(categoryDiv);
|
|
}
|
|
});
|
|
}
|
|
);
|
|
themesDiv.append(accordion);
|
|
pluginDiv.append(themesDiv);
|
|
|
|
waitForElementClass("navbar-buttons", function () {
|
|
const mainDiv =
|
|
document.getElementsByClassName("navbar-buttons")[0];
|
|
const secondLastChild =
|
|
mainDiv.childNodes[mainDiv.childNodes.length - 4];
|
|
mainDiv.insertBefore(pluginDiv, secondLastChild);
|
|
|
|
// Resolving the promise once everything is set up
|
|
menuCreated = true;
|
|
resolve();
|
|
});
|
|
} else {
|
|
// Rejecting the promise if the element already exists
|
|
reject(new Error("Element already exists"));
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function getDataFromKey(key, field) {
|
|
for (const [, categoryThemes] of Object.entries(window.themeSwitchCSS)) {
|
|
for (const theme of categoryThemes) {
|
|
if (key === theme.key) {
|
|
return theme[field];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function init() {
|
|
// Apply active Themes and stylesheets
|
|
let selectedTheme;
|
|
|
|
const regex = /(themeSwitchPlugin(?!-theme-default).*)/;
|
|
const defaultRegex = /(themeSwitchPlugin-theme-default)/;
|
|
let defaultFound = false;
|
|
let appliedThemeOtherThanDefault = [];
|
|
|
|
for (let i = 0; i < localStorage.length; i++) {
|
|
let key = localStorage.key(i);
|
|
let defaultMatch = key.match(defaultRegex);
|
|
if (defaultMatch) {
|
|
defaultFound = true;
|
|
}
|
|
|
|
let match = key.match(regex);
|
|
if (match) {
|
|
selectedTheme = JSON.parse(localStorage.getItem(key));
|
|
if (selectedTheme.active === true) {
|
|
appliedThemeOtherThanDefault.push("True");
|
|
applyCSS(selectedTheme.category, key, getDataFromKey(key, "path"));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!defaultFound) {
|
|
let setDefaultActive;
|
|
if (appliedThemeOtherThanDefault.length > 0) {
|
|
setDefaultActive = false;
|
|
} else {
|
|
setDefaultActive = true;
|
|
}
|
|
setObject("themeSwitchPlugin-theme-default", "Themes", setDefaultActive);
|
|
}
|
|
}
|
|
|
|
const StashPages = [
|
|
"stash:page:scenes",
|
|
"stash:page:scene",
|
|
"stash:page:images",
|
|
"stash:page:image",
|
|
"stash:page:groups",
|
|
"stash:page:group",
|
|
"stash:page:markers",
|
|
"stash:page:galleries",
|
|
"stash:page:performers",
|
|
"stash:page:performer",
|
|
"stash:page:studios",
|
|
"stash:page:studio",
|
|
"stash:page:tags",
|
|
"stash:page:tag",
|
|
"stash:page:settings",
|
|
"stash:page:stats",
|
|
"stash:page:home",
|
|
];
|
|
|
|
function createMenuAndInit() {
|
|
if (!menuCreated) {
|
|
createBTNMenu()
|
|
.then(function () {
|
|
console.log("Theme Plugin: Menu created successfully");
|
|
})
|
|
.catch(function (error) {
|
|
console.error("Theme Plugin: Error creating menu:", error.message);
|
|
});
|
|
menuCreated = true;
|
|
}
|
|
init();
|
|
}
|
|
|
|
PluginApi.Event.addEventListener("stash:location", (e) =>
|
|
createMenuAndInit()
|
|
);
|
|
createMenuAndInit();
|
|
|
|
// Reset menuCreated flag on hard refresh
|
|
window.addEventListener("beforeunload", function () {
|
|
menuCreated = false;
|
|
});
|
|
})();
|