// ==UserScript==
// @name Furaffinity-Custom-Settings
// @namespace Violentmonkey Scripts
// @grant none
// @version 4.2.2
// @author Midori Dragon
// @description Library to create Custom settings on Furaffinitiy
// @icon https://www.furaffinity.net/themes/beta/img/banners/fa_logo.png
// @license MIT
// @homepageURL https://greasyfork.org/scripts/475041-furaffinity-custom-settings
// @supportURL https://greasyfork.org/scripts/475041-furaffinity-custom-settings/feedback
// ==/UserScript==
// jshint esversion: 8
(() => {
"use strict";
var __webpack_modules__ = {
622: (module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.d(__webpack_exports__, {
A: () => __WEBPACK_DEFAULT_EXPORT__
});
var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(601), _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__), _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(314), ___CSS_LOADER_EXPORT___ = __webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__)()(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default());
___CSS_LOADER_EXPORT___.push([ module.id, '.switch-cs {\n position: relative;\n display: inline-block;\n width: 52px;\n height: 28px;\n margin: 6px 8px 6px 0;\n}\n\n.switch-cs input {\n opacity: 0;\n width: 0;\n height: 0;\n}\n\n.slider-cs {\n position: absolute;\n cursor: pointer;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: #ccc;\n transition: .4s;\n border-radius: 34px;\n}\n\n.slider-cs:before {\n position: absolute;\n content: "";\n height: 20px;\n width: 20px;\n left: 4px;\n bottom: 4px;\n background-color: white;\n transition: .4s;\n border-radius: 50%;\n}\n\ninput:checked+.slider-cs {\n background-color: #4CAF50;\n}\n\ninput:checked+.slider-cs:before {\n transform: translateX(26px);\n}\n\n.section-header.cs {\n display: flex;\n align-items: center;\n}\n\n.section-body.cs {\n opacity: 1;\n transition: opacity 0.3s linear;\n}\n\n.section-body.cs.collapsed {\n opacity: 0.4;\n pointer-events: none;\n}\n', "" ]);
const __WEBPACK_DEFAULT_EXPORT__ = ___CSS_LOADER_EXPORT___;
},
314: module => {
module.exports = function(cssWithMappingToString) {
var list = [];
list.toString = function toString() {
return this.map((function(item) {
var content = "", needLayer = void 0 !== item[5];
if (item[4]) content += "@supports (".concat(item[4], ") {");
if (item[2]) content += "@media ".concat(item[2], " {");
if (needLayer) content += "@layer".concat(item[5].length > 0 ? " ".concat(item[5]) : "", " {");
content += cssWithMappingToString(item);
if (needLayer) content += "}";
if (item[2]) content += "}";
if (item[4]) content += "}";
return content;
})).join("");
};
list.i = function i(modules, media, dedupe, supports, layer) {
if ("string" == typeof modules) modules = [ [ null, modules, void 0 ] ];
var alreadyImportedModules = {};
if (dedupe) for (var k = 0; k < this.length; k++) {
var id = this[k][0];
if (null != id) alreadyImportedModules[id] = true;
}
for (var _k = 0; _k < modules.length; _k++) {
var item = [].concat(modules[_k]);
if (!dedupe || !alreadyImportedModules[item[0]]) {
if (void 0 !== layer) if (void 0 === item[5]) item[5] = layer; else {
item[1] = "@layer".concat(item[5].length > 0 ? " ".concat(item[5]) : "", " {").concat(item[1], "}");
item[5] = layer;
}
if (media) if (!item[2]) item[2] = media; else {
item[1] = "@media ".concat(item[2], " {").concat(item[1], "}");
item[2] = media;
}
if (supports) if (!item[4]) item[4] = "".concat(supports); else {
item[1] = "@supports (".concat(item[4], ") {").concat(item[1], "}");
item[4] = supports;
}
list.push(item);
}
}
};
return list;
};
},
601: module => {
module.exports = function(i) {
return i[1];
};
},
72: module => {
var stylesInDOM = [];
function getIndexByIdentifier(identifier) {
for (var result = -1, i = 0; i < stylesInDOM.length; i++) if (stylesInDOM[i].identifier === identifier) {
result = i;
break;
}
return result;
}
function modulesToDom(list, options) {
for (var idCountMap = {}, identifiers = [], i = 0; i < list.length; i++) {
var item = list[i], id = options.base ? item[0] + options.base : item[0], count = idCountMap[id] || 0, identifier = "".concat(id, " ").concat(count);
idCountMap[id] = count + 1;
var indexByIdentifier = getIndexByIdentifier(identifier), obj = {
css: item[1],
media: item[2],
sourceMap: item[3],
supports: item[4],
layer: item[5]
};
if (-1 !== indexByIdentifier) {
stylesInDOM[indexByIdentifier].references++;
stylesInDOM[indexByIdentifier].updater(obj);
} else {
var updater = addElementStyle(obj, options);
options.byIndex = i;
stylesInDOM.splice(i, 0, {
identifier,
updater,
references: 1
});
}
identifiers.push(identifier);
}
return identifiers;
}
function addElementStyle(obj, options) {
var api = options.domAPI(options);
api.update(obj);
return function updater(newObj) {
if (newObj) {
if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap && newObj.supports === obj.supports && newObj.layer === obj.layer) return;
api.update(obj = newObj);
} else api.remove();
};
}
module.exports = function(list, options) {
var lastIdentifiers = modulesToDom(list = list || [], options = options || {});
return function update(newList) {
newList = newList || [];
for (var i = 0; i < lastIdentifiers.length; i++) {
var index = getIndexByIdentifier(lastIdentifiers[i]);
stylesInDOM[index].references--;
}
for (var newLastIdentifiers = modulesToDom(newList, options), _i = 0; _i < lastIdentifiers.length; _i++) {
var _index = getIndexByIdentifier(lastIdentifiers[_i]);
if (0 === stylesInDOM[_index].references) {
stylesInDOM[_index].updater();
stylesInDOM.splice(_index, 1);
}
}
lastIdentifiers = newLastIdentifiers;
};
};
},
659: module => {
var memo = {};
module.exports = function insertBySelector(insert, style) {
var target = function getTarget(target) {
if (void 0 === memo[target]) {
var styleTarget = document.querySelector(target);
if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) try {
styleTarget = styleTarget.contentDocument.head;
} catch (e) {
styleTarget = null;
}
memo[target] = styleTarget;
}
return memo[target];
}(insert);
if (!target) throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");
target.appendChild(style);
};
},
540: module => {
module.exports = function insertStyleElement(options) {
var element = document.createElement("style");
options.setAttributes(element, options.attributes);
options.insert(element, options.options);
return element;
};
},
56: (module, __unused_webpack_exports, __webpack_require__) => {
module.exports = function setAttributesWithoutAttributes(styleElement) {
var nonce = true ? __webpack_require__.nc : 0;
if (nonce) styleElement.setAttribute("nonce", nonce);
};
},
825: module => {
module.exports = function domAPI(options) {
if ("undefined" == typeof document) return {
update: function update() {},
remove: function remove() {}
};
var styleElement = options.insertStyleElement(options);
return {
update: function update(obj) {
!function apply(styleElement, options, obj) {
var css = "";
if (obj.supports) css += "@supports (".concat(obj.supports, ") {");
if (obj.media) css += "@media ".concat(obj.media, " {");
var needLayer = void 0 !== obj.layer;
if (needLayer) css += "@layer".concat(obj.layer.length > 0 ? " ".concat(obj.layer) : "", " {");
css += obj.css;
if (needLayer) css += "}";
if (obj.media) css += "}";
if (obj.supports) css += "}";
var sourceMap = obj.sourceMap;
if (sourceMap && "undefined" != typeof btoa) css += "\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), " */");
options.styleTagTransform(css, styleElement, options.options);
}(styleElement, options, obj);
},
remove: function remove() {
!function removeStyleElement(styleElement) {
if (null === styleElement.parentNode) return false;
styleElement.parentNode.removeChild(styleElement);
}(styleElement);
}
};
};
},
113: module => {
module.exports = function styleTagTransform(css, styleElement) {
if (styleElement.styleSheet) styleElement.styleSheet.cssText = css; else {
for (;styleElement.firstChild; ) styleElement.removeChild(styleElement.firstChild);
styleElement.appendChild(document.createTextNode(css));
}
};
}
}, __webpack_module_cache__ = {};
function __webpack_require__(moduleId) {
var cachedModule = __webpack_module_cache__[moduleId];
if (void 0 !== cachedModule) return cachedModule.exports;
var module = __webpack_module_cache__[moduleId] = {
id: moduleId,
exports: {}
};
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
return module.exports;
}
__webpack_require__.n = module => {
var getter = module && module.__esModule ? () => module.default : () => module;
__webpack_require__.d(getter, {
a: getter
});
return getter;
};
__webpack_require__.d = (exports, definition) => {
for (var key in definition) if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) Object.defineProperty(exports, key, {
enumerable: true,
get: definition[key]
});
};
__webpack_require__.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
__webpack_require__.nc = void 0;
var LogLevel, SettingType;
__webpack_require__.d({}, {
x: () => showResetButtonSetting
});
!function(LogLevel) {
LogLevel[LogLevel.Error = 1] = "Error";
LogLevel[LogLevel.Warning = 2] = "Warning";
LogLevel[LogLevel.Info = 3] = "Info";
}(LogLevel || (LogLevel = {}));
class Logger {
static log(logLevel = LogLevel.Warning, ...args) {
if (null == window.__FF_GLOBAL_LOG_LEVEL__) window.__FF_GLOBAL_LOG_LEVEL__ = LogLevel.Error;
if (!(logLevel > window.__FF_GLOBAL_LOG_LEVEL__)) switch (logLevel) {
case LogLevel.Error:
console.error(...args);
break;
case LogLevel.Warning:
console.warn(...args);
break;
case LogLevel.Info:
console.log(...args);
}
}
static setLogLevel(logLevel) {
window.__FF_GLOBAL_LOG_LEVEL__ = logLevel;
}
static logError(...args) {
Logger.log(LogLevel.Error, ...args);
}
static logWarning(...args) {
Logger.log(LogLevel.Warning, ...args);
}
static logInfo(...args) {
Logger.log(LogLevel.Info, ...args);
}
}
!function(SettingType) {
SettingType[SettingType.Number = 0] = "Number";
SettingType[SettingType.Boolean = 1] = "Boolean";
SettingType[SettingType.Action = 2] = "Action";
SettingType[SettingType.Text = 3] = "Text";
SettingType[SettingType.Option = 4] = "Option";
}(SettingType || (SettingType = {}));
function makeIdCompatible(id) {
const sanitizedString = id.replace(/[^a-zA-Z0-9-_\.]/g, "-").replace(/^-+|-+$/g, "").replace(/^-*(?=\d)/, "id-");
return /^[0-9]/.test(sanitizedString) ? "id-" + sanitizedString : sanitizedString;
}
class SettingAction extends EventTarget {
constructor(providerId, name) {
super();
this.description = "";
Object.setPrototypeOf(this, SettingAction.prototype);
this.name = name;
this.id = providerId + "-" + makeIdCompatible(this.name);
this.type = SettingType.Action;
this.defaultValue = "";
this.loadFromSyncedStorage();
this.settingElem = this._settingInputElem = this.create();
}
get value() {
var _a;
return null !== (_a = this._settingInputElem.textContent) && void 0 !== _a ? _a : "";
}
set value(newValue) {
this._settingInputElem.textContent = newValue;
}
get onInput() {
return this._onInput;
}
set onInput(handler) {
this._onInput = handler;
}
create() {
const settingElem = document.createElement("button");
settingElem.id = this.id;
settingElem.type = "button";
settingElem.className = "button standard mobile-fix";
settingElem.textContent = this.name;
settingElem.addEventListener("click", this.invokeInput.bind(this));
return settingElem;
}
loadFromSyncedStorage() {}
toString() {
return `${this.name} = ${this.value}`;
}
invokeInput() {
var _a;
null === (_a = this._onInput) || void 0 === _a || _a.call(this, this._settingInputElem);
this.dispatchEvent(new Event("input"));
}
}
class GMInfo {
static isBrowserEnvironment() {
return "undefined" != typeof browser && void 0 !== browser.runtime || "undefined" != typeof chrome && void 0 !== chrome.runtime;
}
static getBrowserAPI() {
if ("undefined" != typeof GM_info && null != GM_info) return GM_info; else if ("undefined" != typeof browser && void 0 !== browser.runtime) return browser; else if ("undefined" != typeof chrome && void 0 !== chrome.runtime) return chrome; else throw new Error("Unsupported browser for SyncedStorage.");
}
static get scriptName() {
if (GMInfo.isBrowserEnvironment()) return GMInfo.getBrowserAPI().runtime.getManifest().name; else return GMInfo.getBrowserAPI().script.name;
}
static get scriptVersion() {
if (GMInfo.isBrowserEnvironment()) return GMInfo.getBrowserAPI().runtime.getManifest().version; else return GMInfo.getBrowserAPI().script.version;
}
static get scriptDescription() {
if (GMInfo.isBrowserEnvironment()) return GMInfo.getBrowserAPI().runtime.getManifest().description; else return GMInfo.getBrowserAPI().script.description;
}
static get scriptAuthor() {
if (GMInfo.isBrowserEnvironment()) return GMInfo.getBrowserAPI().runtime.getManifest().author; else return GMInfo.getBrowserAPI().script.author;
}
static get scriptNamespace() {
if (!GMInfo.isBrowserEnvironment()) return GMInfo.getBrowserAPI().script.namespace;
}
static get scriptSource() {
if (!GMInfo.isBrowserEnvironment()) return GMInfo.getBrowserAPI().script.source;
}
static get scriptIcon() {
if (GMInfo.isBrowserEnvironment()) {
const manifest = GMInfo.getBrowserAPI().runtime.getManifest();
let largestIcon = 0;
for (const key of Object.keys(manifest.icons)) {
const size = parseInt(key);
if (size > largestIcon) largestIcon = size;
}
return manifest.icons[largestIcon.toString()];
} else return GMInfo.getBrowserAPI().script.icon;
}
static get scriptIcon64() {
if (GMInfo.isBrowserEnvironment()) {
const manifest = GMInfo.getBrowserAPI().runtime.getManifest();
return null == manifest.icons ? void 0 : manifest.icons[64];
} else return GMInfo.getBrowserAPI().script.icon64;
}
static get scriptAntifeature() {
if (!GMInfo.isBrowserEnvironment()) return GMInfo.getBrowserAPI().script.antifeature;
}
static get scriptOptions() {
if (!GMInfo.isBrowserEnvironment()) return GMInfo.getBrowserAPI().script.options;
}
static get scriptMetaStr() {
if (GMInfo.isBrowserEnvironment()) return JSON.stringify(GMInfo.getBrowserAPI().runtime.getManifest()); else return GMInfo.getBrowserAPI().scriptMetaStr;
}
static get scriptHandler() {
if (GMInfo.isBrowserEnvironment()) return "undefined" != typeof browser ? "Firefox" : "Chrome"; else return GMInfo.getBrowserAPI().scriptHandler;
}
static get scriptUpdateURL() {
if (GMInfo.isBrowserEnvironment()) return GMInfo.getBrowserAPI().runtime.getManifest().update_url; else return GMInfo.getBrowserAPI().scriptUpdateURL;
}
static get scriptWillUpdate() {
if (!GMInfo.isBrowserEnvironment()) return GMInfo.getBrowserAPI().scriptWillUpdate;
}
static get scriptResources() {
if (!GMInfo.isBrowserEnvironment()) return GMInfo.getBrowserAPI().scriptResources;
}
static get downloadMode() {
if (!GMInfo.isBrowserEnvironment()) return GMInfo.getBrowserAPI().downloadMode;
}
}
var __awaiter = function(thisArg, _arguments, P, generator) {
return new (P || (P = Promise))((function(resolve, reject) {
function fulfilled(value) {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}
function rejected(value) {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
}
function step(result) {
result.done ? resolve(result.value) : function adopt(value) {
return value instanceof P ? value : new P((function(resolve) {
resolve(value);
}));
}(result.value).then(fulfilled, rejected);
}
step((generator = generator.apply(thisArg, _arguments || [])).next());
}));
};
class SyncedStorage {
static setItem(key, value) {
return __awaiter(this, void 0, void 0, (function*() {
if (!GMInfo.isBrowserEnvironment()) {
Logger.logWarning("SyncedStorage is only available in browser extensions.");
return;
}
Logger.logInfo(`Setting item in synced storage: ${key}=${value}`);
const api = GMInfo.getBrowserAPI();
if (null != api.storage) return new Promise(((resolve, reject) => {
api.storage.sync.set({
[key]: value
}, (() => {
if (null != api.runtime.lastError) return reject(api.runtime.lastError);
resolve();
}));
})); else Logger.logError("Unsupported storage API.");
}));
}
static getItem(key) {
return __awaiter(this, void 0, void 0, (function*() {
if (!GMInfo.isBrowserEnvironment()) {
Logger.logWarning("SyncedStorage is only available in browser extensions.");
return;
}
Logger.logInfo(`Getting item from synced storage: ${key}`);
const api = GMInfo.getBrowserAPI();
if (null != api.storage) return new Promise(((resolve, reject) => {
api.storage.sync.get(key, (result => {
if (null != api.runtime.lastError) return reject(api.runtime.lastError);
resolve(result[key]);
}));
})); else Logger.logError("Unsupported storage API.");
}));
}
static removeItem(key) {
return __awaiter(this, void 0, void 0, (function*() {
if (!GMInfo.isBrowserEnvironment()) {
Logger.logWarning("SyncedStorage is only available in browser extensions.");
return;
}
Logger.logInfo(`Removing item from synced storage: ${key}`);
const api = GMInfo.getBrowserAPI();
if (null != api.storage) return new Promise(((resolve, reject) => {
api.storage.sync.remove(key, (() => {
if (null != api.runtime.lastError) return reject(api.runtime.lastError);
resolve();
}));
})); else Logger.logError("Unsupported storage API.");
}));
}
}
class SettingBoolean extends EventTarget {
constructor(providerId, name) {
super();
this.description = "";
Object.setPrototypeOf(this, SettingBoolean.prototype);
this.name = name;
this.id = providerId + "-" + makeIdCompatible(this.name);
this.type = SettingType.Boolean;
this._defaultValue = false;
this.loadFromSyncedStorage();
this.settingElem = this.create();
this._settingInputElem = this.settingElem.querySelector("input");
}
get value() {
const localValue = localStorage.getItem(this.id);
if (null == localValue) return this.defaultValue; else return "true" === localValue || "1" === localValue;
}
set value(newValue) {
if (newValue === this.defaultValue) {
localStorage.removeItem(this.id);
SyncedStorage.removeItem(this.id);
} else {
localStorage.setItem(this.id, newValue.toString());
SyncedStorage.setItem(this.id, newValue);
}
this._settingInputElem.checked = newValue;
this.invokeInput(this._settingInputElem);
}
get defaultValue() {
return this._defaultValue;
}
set defaultValue(value) {
this._defaultValue = value;
this.value = this.value;
}
get onInput() {
return this._onInput;
}
set onInput(handler) {
this._onInput = handler;
}
create() {
const container = document.createElement("div"), settingElem = document.createElement("input");
settingElem.id = this.id;
settingElem.type = "checkbox";
settingElem.style.cursor = "pointer";
settingElem.style.marginRight = "4px";
settingElem.addEventListener("change", (() => this.value = settingElem.checked));
container.appendChild(settingElem);
const settingElemLabel = document.createElement("label");
settingElemLabel.textContent = this.name;
settingElemLabel.style.cursor = "pointer";
settingElemLabel.style.userSelect = "none";
settingElemLabel.htmlFor = this.id;
container.appendChild(settingElemLabel);
return container;
}
loadFromSyncedStorage() {
SyncedStorage.getItem(this.id).then((value => {
if (null != value) localStorage.setItem(this.id, value.toString());
}));
}
toString() {
return `${this.name} = ${this.value}`;
}
invokeInput(elem) {
var _a;
null === (_a = this.onInput) || void 0 === _a || _a.call(this, elem);
this.dispatchEvent(new CustomEvent("input", {
detail: elem
}));
}
}
class SettingNumber extends EventTarget {
constructor(providerId, name) {
super();
this.description = "";
Object.setPrototypeOf(this, SettingNumber.prototype);
this.name = name;
this.id = providerId + "-" + makeIdCompatible(this.name);
this.type = SettingType.Number;
this._defaultValue = 0;
this.min = 0;
this.max = 32767;
this.step = 1;
this.loadFromSyncedStorage();
this.settingElem = this._settingInputElem = this.create();
}
get value() {
var _a;
return parseInt(null !== (_a = localStorage.getItem(this.id)) && void 0 !== _a ? _a : this.defaultValue.toString()) || this.defaultValue;
}
set value(newValue) {
if ((newValue = Math.min(Math.max(newValue, this.min), this.max)) === this.defaultValue) {
localStorage.removeItem(this.id);
SyncedStorage.removeItem(this.id);
} else {
localStorage.setItem(this.id, newValue.toString());
SyncedStorage.setItem(this.id, newValue);
}
this._settingInputElem.value = newValue.toString();
this.invokeInput(this._settingInputElem);
}
get defaultValue() {
return this._defaultValue;
}
set defaultValue(value) {
this._defaultValue = value;
this.value = this.value;
}
get onInput() {
return this._onInput;
}
set onInput(handler) {
this._onInput = handler;
}
create() {
const settingElem = document.createElement("input");
settingElem.id = this.id;
settingElem.type = "text";
settingElem.className = "textbox";
settingElem.addEventListener("keydown", (event => {
const currentValue = parseInt(settingElem.value) || this.defaultValue;
if ("ArrowUp" === event.key) this.value = Math.min(currentValue + this.step, this.max); else if ("ArrowDown" === event.key) this.value = Math.max(currentValue - this.step, this.min);
}));
settingElem.addEventListener("input", (() => {
const inputValue = settingElem.value.replace(/[^0-9]/g, ""), numericValue = parseInt(inputValue) || this.defaultValue;
this.value = Math.min(Math.max(numericValue, this.min), this.max);
}));
return settingElem;
}
loadFromSyncedStorage() {
SyncedStorage.getItem(this.id).then((value => {
if (null != value) localStorage.setItem(this.id, value.toString());
}));
}
toString() {
return `${this.name} = ${this.value}`;
}
invokeInput(elem) {
var _a;
null === (_a = this.onInput) || void 0 === _a || _a.call(this, elem);
this.dispatchEvent(new CustomEvent("input", {
detail: elem
}));
}
}
class SettingText extends EventTarget {
constructor(providerId, name) {
super();
this.description = "";
Object.setPrototypeOf(this, SettingText.prototype);
this.name = name;
this.id = providerId + "-" + makeIdCompatible(this.name);
this.type = SettingType.Text;
this._defaultValue = "";
this.loadFromSyncedStorage();
this.settingElem = this.create();
this._settingInputElem = this.settingElem.querySelector("input");
this._errorMessage = this.settingElem.querySelector(".error-message");
}
get value() {
var _a;
return null !== (_a = localStorage.getItem(this.id)) && void 0 !== _a ? _a : this.defaultValue;
}
set value(newValue) {
if (null == this.verifyRegex || this.verifyRegex.test(newValue)) {
this._errorMessage.style.display = "none";
try {
if (newValue === this.defaultValue) {
localStorage.removeItem(this.id);
SyncedStorage.removeItem(this.id);
} else {
localStorage.setItem(this.id, newValue);
SyncedStorage.setItem(this.id, newValue);
}
} catch (error) {
Logger.logError(error);
}
this._settingInputElem.value = newValue;
this.invokeInput(this._settingInputElem);
} else this._errorMessage.style.display = "block";
}
get defaultValue() {
return this._defaultValue;
}
set defaultValue(value) {
this._defaultValue = value;
this.value = this.value;
}
get onInput() {
return this._onInput;
}
set onInput(handler) {
this._onInput = handler;
}
create() {
const container = document.createElement("div");
container.style.position = "relative";
const settingElem = document.createElement("input");
settingElem.id = this.id;
settingElem.type = "text";
settingElem.className = "textbox";
settingElem.addEventListener("input", (() => {
if (null != this.verifyRegex && !this.verifyRegex.test(settingElem.value)) this._errorMessage.style.display = "block"; else this._errorMessage.style.display = "none";
this.value = settingElem.value;
}));
container.appendChild(settingElem);
const errorMessage = document.createElement("div");
errorMessage.className = "error-message";
errorMessage.style.color = "red";
errorMessage.style.display = "none";
errorMessage.style.position = "absolute";
errorMessage.style.top = "100%";
errorMessage.style.left = "0";
errorMessage.textContent = "Invalid input";
container.appendChild(errorMessage);
return container;
}
loadFromSyncedStorage() {
SyncedStorage.getItem(this.id).then((value => {
if (null != value) localStorage.setItem(this.id, value.toString());
}));
}
toString() {
return `${this.name} = ${this.value}`;
}
invokeInput(elem) {
var _a;
null === (_a = this.onInput) || void 0 === _a || _a.call(this, elem);
this.dispatchEvent(new CustomEvent("input", {
detail: elem
}));
}
}
var injectStylesIntoStyleTag = __webpack_require__(72), injectStylesIntoStyleTag_default = __webpack_require__.n(injectStylesIntoStyleTag), styleDomAPI = __webpack_require__(825), styleDomAPI_default = __webpack_require__.n(styleDomAPI), insertBySelector = __webpack_require__(659), insertBySelector_default = __webpack_require__.n(insertBySelector), setAttributesWithoutAttributes = __webpack_require__(56), setAttributesWithoutAttributes_default = __webpack_require__.n(setAttributesWithoutAttributes), insertStyleElement = __webpack_require__(540), insertStyleElement_default = __webpack_require__.n(insertStyleElement), styleTagTransform = __webpack_require__(113), styleTagTransform_default = __webpack_require__.n(styleTagTransform), Style = __webpack_require__(622), options = {};
options.styleTagTransform = styleTagTransform_default();
options.setAttributes = setAttributesWithoutAttributes_default();
options.insert = insertBySelector_default().bind(null, "head");
options.domAPI = styleDomAPI_default();
options.insertStyleElement = insertStyleElement_default();
injectStylesIntoStyleTag_default()(Style.A, options);
Style.A && Style.A.locals && Style.A.locals;
class SettingOption extends EventTarget {
constructor(providerId, name) {
super();
this.description = "";
Object.setPrototypeOf(this, SettingOption.prototype);
this.name = name;
this.id = providerId + "-" + makeIdCompatible(this.name);
this.type = SettingType.Option;
this._defaultValue = "0";
this.loadFromSyncedStorage();
this.settingElem = this.create();
this._settingInputElem = this.settingElem.querySelector("select");
}
get value() {
var _a;
return null !== (_a = localStorage.getItem(this.id)) && void 0 !== _a ? _a : this.defaultValue;
}
set value(newValue) {
try {
if (newValue == this.defaultValue) {
localStorage.removeItem(this.id);
SyncedStorage.removeItem(this.id);
} else {
localStorage.setItem(this.id, newValue.toString());
SyncedStorage.setItem(this.id, newValue.toString());
}
} catch (error) {
Logger.logError(error);
}
this._settingInputElem.value = newValue.toString();
this.invokeInput(this._settingInputElem);
}
get defaultValue() {
return this._defaultValue;
}
set defaultValue(value) {
this._defaultValue = value;
this.value = this.value;
}
get options() {
var _a;
const options = {};
for (const option of Array.from(this._settingInputElem.options)) options[option.value] = null !== (_a = option.textContent) && void 0 !== _a ? _a : "";
return options;
}
set options(newValue) {
const currValue = this.value;
this._settingInputElem.innerHTML = "";
for (const [value, text] of Object.entries(newValue)) this.addOption(value, text);
if (Array.from(this._settingInputElem.options).some((x => x.value === currValue.toString()))) this.value = currValue; else this.value = this.defaultValue;
}
get onInput() {
return this._onInput;
}
set onInput(handler) {
this._onInput = handler;
}
addOption(value, text) {
if (null != this._settingInputElem.options.namedItem(value.toString())) {
Logger.logWarning(`Option with value "${value}" already exists.`);
return;
}
const option = document.createElement("option");
option.value = value.toString();
option.textContent = text.toString();
this._settingInputElem.options.add(option);
}
removeOption(value) {
const option = this._settingInputElem.options.namedItem(value.toString());
if (null != option) this._settingInputElem.removeChild(option); else Logger.logWarning(`Option with value "${value}" does not exist.`);
}
create() {
const container = document.createElement("div");
container.style.position = "relative";
const settingElem = document.createElement("select");
settingElem.id = this.id;
settingElem.className = "styled";
settingElem.addEventListener("change", (() => {
this.value = settingElem.value;
}));
container.appendChild(settingElem);
return container;
}
loadFromSyncedStorage() {
SyncedStorage.getItem(this.id).then((value => {
if (null != value) localStorage.setItem(this.id, value.toString());
}));
}
toString() {
return `${this.name} = ${this.value}`;
}
invokeInput(elem) {
var _a;
null === (_a = this.onInput) || void 0 === _a || _a.call(this, elem);
this.dispatchEvent(new CustomEvent("input", {
detail: elem
}));
}
}
class Settings {
constructor(provider, headerName) {
this.settings = {};
this.showFeatureEnabledSetting = true;
this._settingClassMapping = {
[SettingType.Number]: SettingNumber,
[SettingType.Boolean]: SettingBoolean,
[SettingType.Action]: SettingAction,
[SettingType.Text]: SettingText,
[SettingType.Option]: SettingOption
};
this._menuName = "Extension Settings";
this._menuNameId = makeIdCompatible("Extension Settings");
this._provider = provider;
this._providerId = makeIdCompatible(provider);
this._headerName = headerName;
this._isFeatureEnabledSetting = new SettingBoolean(this.providerId, `${headerName} Enabled`);
this._isFeatureEnabledSetting.defaultValue = true;
}
get menuName() {
return this._menuName;
}
get menuNameId() {
return this._menuNameId;
}
get provider() {
return this._provider;
}
get providerId() {
return this._providerId;
}
get headerName() {
return this._headerName;
}
get isFeatureEnabled() {
return this._isFeatureEnabledSetting.value;
}
newSetting(type, name) {
const newSetting = new (0, this._settingClassMapping[type])(this.providerId, name);
this.settings[name] = newSetting;
return newSetting;
}
loadSettings() {
try {
this.addExSettingsMenu(this.menuName, this.provider, this.menuNameId, this.providerId);
if (window.location.toString().includes("controls/settings")) {
this.addExSettingsMenuSidebar(this.menuName, this.provider, this.menuNameId, this.providerId);
if (window.location.toString().includes("?extension=" + this.providerId)) this.loadSettingValues(this.headerName, Object.values(this.settings));
}
} catch (error) {
Logger.logError(error);
}
}
loadSettingValues(headerName, settings) {
var _a;
if (0 === settings.length) return;
if (null != document.getElementById(headerName + "_settingscontainer")) return;
const columnPage = document.getElementById("columnpage"), content = null == columnPage ? void 0 : columnPage.querySelector('div[class="content"]');
if (null == content) {
Logger.logError("Failed to load settings. No content found.");
return;
}
const nonExSettings = content.querySelectorAll('section:not([class="exsettings"])');
for (const section of Array.from(null != nonExSettings ? nonExSettings : [])) null === (_a = section.parentNode) || void 0 === _a || _a.removeChild(section);
const section = document.createElement("section");
section.id = headerName + "_settingscontainer";
section.className = "exsettings";
const headerContainer = document.createElement("div");
headerContainer.className = "section-header cs";
const header = document.createElement("h2");
header.textContent = headerName;
const bodyContainer = document.createElement("div");
bodyContainer.className = "section-body cs";
if (this._isFeatureEnabledSetting.value) bodyContainer.classList.remove("collapsed"); else bodyContainer.classList.add("collapsed");
if (this.showFeatureEnabledSetting) headerContainer.appendChild(this.createFeatureEnableSetting(bodyContainer));
headerContainer.appendChild(header);
section.appendChild(headerContainer);
for (const setting of settings) bodyContainer.appendChild(this.createSettingContainer(setting));
section.appendChild(bodyContainer);
content.appendChild(section);
}
createFeatureEnableSetting(bodyContainer) {
const enableFeatureSettingContainerElem = document.createElement("label");
enableFeatureSettingContainerElem.classList.add("switch-cs");
const enableFeatureSettingInput = document.createElement("input");
enableFeatureSettingInput.type = "checkbox";
enableFeatureSettingInput.id = "toggleSwitch";
enableFeatureSettingInput.checked = this._isFeatureEnabledSetting.value;
enableFeatureSettingInput.addEventListener("input", (() => {
this._isFeatureEnabledSetting.value = enableFeatureSettingInput.checked;
if (enableFeatureSettingInput.checked) bodyContainer.classList.remove("collapsed"); else bodyContainer.classList.add("collapsed");
}));
const enableFeatureSettingSpan = document.createElement("span");
enableFeatureSettingSpan.classList.add("slider-cs");
enableFeatureSettingContainerElem.appendChild(enableFeatureSettingInput);
enableFeatureSettingContainerElem.appendChild(enableFeatureSettingSpan);
return enableFeatureSettingContainerElem;
}
toString() {
if (0 === Object.keys(this.settings).length) return `${this.menuName} has no settings.`;
let settingsString = "(";
Object.keys(this.settings).forEach((key => {
if (this.settings[key].type !== SettingType.Action) settingsString += `"${this.settings[key].toString()}", `;
}));
settingsString = settingsString.slice(0, -2) + ")";
return settingsString;
}
createSettingContainer(setting) {
const settingContainer = document.createElement("div");
settingContainer.className = "control-panel-item-container";
const settingName = document.createElement("div");
settingName.className = "control-panel-item-name";
const settingNameText = document.createElement("h4");
settingNameText.textContent = setting.name;
settingName.appendChild(settingNameText);
settingContainer.appendChild(settingName);
const settingDesc = document.createElement("div");
settingDesc.className = "control-panel-item-description";
const settingDescText = document.createTextNode(setting.description);
settingDesc.appendChild(settingDescText);
settingContainer.appendChild(settingDesc);
if (showResetButtonSetting.value) {
settingDesc.appendChild(document.createElement("br"));
settingDesc.appendChild(this.createSettingReset(setting));
}
const settingOption = document.createElement("div");
settingOption.className = "control-panel-item-options";
settingOption.appendChild(setting.settingElem);
settingContainer.appendChild(settingOption);
return settingContainer;
}
createSettingReset(setting) {
const settingDescReset = document.createElement("a");
settingDescReset.id = setting.id + "_settingreset";
settingDescReset.textContent = "Reset this Setting";
settingDescReset.style.cursor = "pointer";
settingDescReset.style.color = "aqua";
settingDescReset.style.textDecoration = "underline";
settingDescReset.style.fontStyle = "italic";
settingDescReset.style.fontSize = "14px";
settingDescReset.addEventListener("click", (() => {
setting.value = setting.defaultValue;
}));
return settingDescReset;
}
addExSettingsMenu(name, provider, nameId, providerId) {
var _a;
try {
const navBar = document.querySelector('ul[class="navhideonmobile"]'), settings = null === (_a = null == navBar ? void 0 : navBar.querySelector('a[href="/controls/settings/"]')) || void 0 === _a ? void 0 : _a.parentNode;
if (null == settings) {
Logger.logError(`Failed to add extension ${name} to settings menu`);
return;
}
const exSettingNamePresent = null != document.getElementById(nameId), exSettingProviderPresent = null != document.getElementById(providerId);
if (!exSettingNamePresent) {
const exSettingsHeader = document.createElement("h3");
exSettingsHeader.id = nameId;
exSettingsHeader.textContent = name;
settings.appendChild(exSettingsHeader);
}
if (!exSettingProviderPresent) {
const currExSettings = document.createElement("a");
currExSettings.id = providerId;
currExSettings.textContent = provider;
currExSettings.href = "/controls/settings?extension=" + providerId;
currExSettings.style.cursor = "pointer";
settings.appendChild(currExSettings);
}
} catch (error) {
Logger.logError(error);
}
}
addExSettingsMenuSidebar(name, provider, nameId, providerId) {
try {
const settings = document.getElementById("controlpanelnav");
if (null == settings) {
Logger.logError(`Failed to add extension ${name} to settings sidebar`);
return;
}
const exSettingNamePresent = null != document.getElementById(nameId + "_side"), exSettingProviderPresent = null != document.getElementById(providerId + "_side");
if (!exSettingNamePresent) {
const exSettingsHeader = document.createElement("h3");
exSettingsHeader.id = nameId + "_side";
exSettingsHeader.textContent = name;
settings.appendChild(exSettingsHeader);
}
if (!exSettingProviderPresent) {
const currExSettings = document.createElement("a");
currExSettings.id = providerId + "_side";
currExSettings.textContent = provider;
currExSettings.href = "/controls/settings?extension=" + providerId;
currExSettings.style.cursor = "pointer";
settings.appendChild(currExSettings);
settings.appendChild(document.createElement("br"));
}
} catch (error) {
Logger.logError(error);
}
}
}
var _a;
Object.defineProperties(window, {
FACustomSettings: {
get: () => Settings
},
FASettingType: {
get: () => SettingType
}
});
const customSettings = new Settings("Custom-Furaffinity-Settings", "Global Custom-Furaffinity-Settings");
customSettings.showFeatureEnabledSetting = false;
const loggingSetting = customSettings.newSetting(window.FASettingType.Option, "Logging");
loggingSetting.description = "Sets the logging level.";
loggingSetting.defaultValue = LogLevel.Error;
loggingSetting.options = {
[LogLevel.Error]: LogLevel[LogLevel.Error],
[LogLevel.Warning]: LogLevel[LogLevel.Warning],
[LogLevel.Info]: LogLevel[LogLevel.Info]
};
loggingSetting.addEventListener("input", (() => Logger.setLogLevel(parseInt(loggingSetting.value.toString()))));
Logger.setLogLevel(parseInt(loggingSetting.value.toString()));
const showResetButtonSetting = customSettings.newSetting(SettingType.Boolean, "Show Reset Button");
showResetButtonSetting.description = 'Set wether the "Reset this Setting" button is shown in other Settings.';
showResetButtonSetting.defaultValue = true;
customSettings.loadSettings();
let color = "color: blue";
if (null === (_a = window.matchMedia) || void 0 === _a ? void 0 : _a.call(window, "(prefers-color-scheme: dark)").matches) color = "color: aqua";
const settingString = `GlobalSettings: ${customSettings.toString()}`;
console.info(`%c${settingString}`, color);
})();