// ==UserScript==
// @name ESJ Zone: Auto Expand Collapsed Chapters
// @name:zh-TW ESJ Zone:自動打開摺疊章節
// @name:zh-CN ESJ Zone:自动打开折叠章节
// @description Expand the collapsed, last read chapters (alternatively, all chapters) automatically.
// @description:zh-TW 自動展開已折疊的最後閱讀章節(或展開所有章節)。
// @description:zh-CN 自动展开已折叠的最后阅读章节(或展开所有章节)。
// @icon https://icons.duckduckgo.com/ip3/www.esjzone.cc.ico
// @author Jason Kwok
// @namespace https://jasonhk.dev/
// @version 1.1.0
// @license MIT
// @match https://www.esjzone.cc/detail/*.html
// @match https://www.esjzone.me/detail/*.html
// @run-at document-end
// @inject-into page
// @grant GM.getValue
// @grant GM.setValue
// @grant GM.registerMenuCommand
// @require https://unpkg.com/[email protected]/dist/i18n.object.min.js
// @require https://unpkg.com/[email protected]/uuid-random.min.js
// @supportURL https://greasyfork.org/scripts/487306/feedback
// ==/UserScript==
const LL = (function()
{
const translations =
{
"en": {
COMMAND: {
SETTINGS: "Change Theme Settings",
},
SETTINGS: {
TITLE: "Theme Settings",
LIGHT_THEME: "Light Theme",
WHITE: "White",
BLUE: "Blue",
GREEN: "Green",
GRAY: "Pink",
LIGHT_GRAY: "Light Gray",
DARK_THEME: "Dark Theme",
BLACK: "Black",
DARK_GRAY: "Dark Gray",
CANCEL: "Cancel",
SAVE: "Save",
},
},
"zh-TW": {
COMMAND: {
SETTINGS: "更改主題設定",
},
SETTINGS: {
TITLE: "主題設定",
LIGHT_THEME: "明亮主題",
WHITE: "白色",
BLUE: "藍色",
GREEN: "綠色",
PINK: "粉紅色",
LIGHT_GRAY: "淺灰色",
DARK_THEME: "黑暗主題",
BLACK: "黑色",
DARK_GRAY: "深灰色",
CANCEL: "取消",
SAVE: "儲存",
},
},
"zh-CN": {
COMMAND: {
SETTINGS: "更改主题设定",
},
SETTINGS: {
TITLE: "主题设定",
LIGHT_THEME: "明亮主题",
WHITE: "白色",
BLUE: "蓝色",
GREEN: "绿色",
PINK: "粉红色",
LIGHT_GRAY: "浅灰色",
DARK_THEME: "黑暗主题",
BLACK: "黑色",
DARK_GRAY: "深灰色",
CANCEL: "取消",
SAVE: "储存",
},
},
};
let locale = "en";
for (let _locale of navigator.languages.map((language) => new Intl.Locale(language)))
{
if (_locale.language === "zh")
{
_locale = new Intl.Locale("zh", { region: _locale.maximize().region });
}
;
if (_locale.baseName in translations)
{
locale = _locale.baseName;
break;
}
}
return i18nObject(locale, translations[locale]);
})();
const isGreasemonkey = (GM.info.scriptHandler === "Greasemonkey");
if (isGreasemonkey)
{
window.eval(`
$(document.body)
.on("hide.bs.modal", (ev) =>
{
const event = new CustomEvent("hide.bs.modal", { ...ev, bubbles: true });
ev.target.dispatchEvent(event);
})
.on("hidden.bs.modal", (ev) =>
{
const event = new CustomEvent("hidden.bs.modal", { ...ev, bubbles: true });
ev.target.dispatchEvent(event);
});
`);
}
else
{
$(document.body)
.on("hide.bs.modal", (ev) =>
{
const event = new CustomEvent("hide.bs.modal", { ...ev, bubbles: true });
ev.target.dispatchEvent(event);
})
.on("hidden.bs.modal", (ev) =>
{
const event = new CustomEvent("hidden.bs.modal", { ...ev, bubbles: true });
ev.target.dispatchEvent(event);
});
}
const query = matchMedia("(prefers-color-scheme: dark)");
query.addEventListener("change", updateTheme);
updateTheme(query);
GM.registerMenuCommand(LL.COMMAND.SETTINGS(), async () =>
{
await showThemeSettings();
updateTheme(query);
});
function getLightTheme()
{
return GM.getValue("light_theme", "mycolor-0");
}
function getDarkTheme()
{
return GM.getValue("dark_theme", "mycolor-1");
}
function setThemeSettings(lightTheme, darkTheme)
{
return Promise.all([GM.setValue("light_theme", lightTheme), GM.setValue("dark_theme", darkTheme)]);
}
function getExpectedTheme(isDarkMode)
{
return isDarkMode ? getDarkTheme() : getLightTheme();
}
function getCurrentTheme()
{
return document.querySelector(".customizer-color-switch [id^=mycolor-].active").id;
}
function setTheme(name)
{
document.querySelector(`.customizer-color-switch #${name}`).click();
}
async function updateTheme({ matches: isDarkMode })
{
const expectedTheme = await getExpectedTheme(isDarkMode);
if (getCurrentTheme() !== expectedTheme)
{
setTheme(expectedTheme);
}
}
async function showThemeSettings()
{
return new Promise(async (resolve) =>
{
const [lightTheme, darkTheme] = await Promise.all([getLightTheme(), getDarkTheme()]);
const form = document.createElement("form");
form.id = uuid();
form.classList.add("modal", "fade");
form.addEventListener("submit", async (event) =>
{
event.preventDefault();
const settings = new FormData(form);
await setThemeSettings(settings.get("light_theme"), settings.get("dark_theme"));
isGreasemonkey ? window.eval(`$("#${form.id}").modal("hide")`) : $(form).modal("hide");
});
form.addEventListener("hide.bs.modal", () => resolve());
form.addEventListener("hidden.bs.modal", () => form.remove());
const modalDialog = document.createElement("div");
modalDialog.classList.add("modal-dialog");
const modalContent = document.createElement("div");
modalContent.classList.add("modal-content");
const modalHeader = document.createElement("div");
modalHeader.classList.add("modal-header");
const modalTitle = document.createElement("h4");
modalTitle.classList.add("modal-title");
modalTitle.innerText = LL.SETTINGS.TITLE();
const closeButton = document.createElement("button");
closeButton.classList.add("close");
closeButton.type = "button";
closeButton.dataset.dismiss = "modal";
closeButton.innerHTML = `<span aria-hidden="true">×</span>`;
const modalBody = document.createElement("div");
modalBody.classList.add("modal-body");
const lightThemeFormGroup = document.createElement("div");
lightThemeFormGroup.classList.add("form-group");
const lightThemeLabel = document.createElement("label");
lightThemeLabel.htmlFor = "light-theme-select";
lightThemeLabel.innerText = LL.SETTINGS.LIGHT_THEME();
const lightThemeSelect = document.createElement("select");
lightThemeSelect.id = "light-theme-select";
lightThemeSelect.classList.add("form-control");
lightThemeSelect.name = "light_theme";
const whiteThemeOption = document.createElement("option");
whiteThemeOption.value = "mycolor-0";
whiteThemeOption.selected = (lightTheme === "mycolor-0");
whiteThemeOption.innerText = LL.SETTINGS.WHITE();
const blueThemeOption = document.createElement("option");
blueThemeOption.value = "mycolor-2";
blueThemeOption.selected = (lightTheme === "mycolor-2");
blueThemeOption.innerText = LL.SETTINGS.BLUE();
const greenThemeOption = document.createElement("option");
greenThemeOption.value = "mycolor-3";
greenThemeOption.selected = (lightTheme === "mycolor-3");
greenThemeOption.innerText = LL.SETTINGS.GREEN();
const pinkThemeOption = document.createElement("option");
pinkThemeOption.value = "mycolor-4";
pinkThemeOption.selected = (lightTheme === "mycolor-4");
pinkThemeOption.innerText = LL.SETTINGS.PINK();
const lightGrayThemeOption = document.createElement("option");
lightGrayThemeOption.value = "mycolor-5";
lightGrayThemeOption.selected = (lightTheme === "mycolor-5");
lightGrayThemeOption.innerText = LL.SETTINGS.LIGHT_GRAY();
const darkThemeFormGroup = document.createElement("div");
darkThemeFormGroup.classList.add("form-group");
const darkThemeLabel = document.createElement("label");
darkThemeLabel.htmlFor = "dark-theme-select";
darkThemeLabel.innerText = LL.SETTINGS.DARK_THEME();
const darkThemeSelect = document.createElement("select");
darkThemeSelect.id = "dark-theme-select";
darkThemeSelect.classList.add("form-control");
darkThemeSelect.name = "dark_theme";
const blackThemeOption = document.createElement("option");
blackThemeOption.value = "mycolor-1";
blackThemeOption.selected = (darkTheme === "mycolor-1");
blackThemeOption.innerText = LL.SETTINGS.BLACK();
const darkGrayThemeOption = document.createElement("option");
darkGrayThemeOption.value = "mycolor-6";
darkGrayThemeOption.selected = (darkTheme === "mycolor-6");
darkGrayThemeOption.innerText = LL.SETTINGS.DARK_GRAY();
const modalFooter = document.createElement("div");
modalFooter.classList.add("modal-footer");
const cancelButton = document.createElement("button");
cancelButton.classList.add("btn", "btn-default");
cancelButton.type = "button";
cancelButton.dataset.dismiss = "modal";
cancelButton.innerText = LL.SETTINGS.CANCEL();
const saveButton = document.createElement("button");
saveButton.classList.add("btn", "btn-primary");
cancelButton.type = "submit";
saveButton.innerText = LL.SETTINGS.SAVE();
modalHeader.append(modalTitle, closeButton);
lightThemeSelect.append(whiteThemeOption, blueThemeOption, greenThemeOption, pinkThemeOption, lightGrayThemeOption);
lightThemeFormGroup.append(lightThemeLabel, lightThemeSelect);
darkThemeSelect.append(blackThemeOption, darkGrayThemeOption);
darkThemeFormGroup.append(darkThemeLabel, darkThemeSelect);
modalBody.append(lightThemeFormGroup, darkThemeFormGroup);
modalFooter.append(cancelButton, saveButton);
modalContent.append(modalHeader, modalBody, modalFooter);
modalDialog.append(modalContent);
form.append(modalDialog);
document.body.append(form);
isGreasemonkey ? window.eval(`$("#${form.id}").modal("show")`) : $(form).modal("show");
});
}