settings

轻小说文库++的脚本设置界面

目前为 2022-09-17 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.gf.qytechs.cn/scripts/450210/1094631/settings.js

/* eslint-disable no-multi-spaces */
/* eslint-disable no-implicit-globals */
/* eslint-disable userscripts/no-invalid-headers */
/* eslint-disable userscripts/no-invalid-grant */

// ==UserScript==
// @name               settings
// @displayname        设置界面
// @namespace          Wenku8++
// @version            0.2.12
// @description        轻小说文库++的脚本设置界面
// @author             PY-DNG
// @license            GPL-v3
// @regurl             https?://www\.wenku8\.net/.*
// @require            https://gf.qytechs.cn/scripts/449412-basic-functions/code/Basic%20Functions.js?version=1085783
// @require            https://gf.qytechs.cn/scripts/449583-configmanager/code/ConfigManager.js?version=1085836
// @grant              GM_getValue
// @grant              GM_setValue
// @grant              GM_deleteValue
// @grant              GM_listValues
// @grant              ML_listModules
// @grant              ML_getModule
// @grant              ML_disableModule
// @grant              ML_enableModule
// @grant              ML_uninstallModule
// @grant              ML_moduleLoaded
// @protect
// ==/UserScript==

/*
计划任务:
[ ] 模块列表排序显示
[o] 不可用按钮灰选
[o] 模块详细信息展示
[ ] 模块运行状态展示
*/

(function __MAIN__() {
	const ASSETS = require('assets');
	const alertify = require('alertify');
	const tippy = require('tippy');
	const SPanel = require('SidePanel');
	const SettingPanel = require('SettingPanel');
	const mousetip = require('mousetip');
	const CONST = {
		Text: {
			Button: '设置',
			Title: '脚本设置',
			ModuleManage: '模块管理',
			OpenModuleDialog: '点此打开管理面板',
			ModuleSettings: '模块设置',
			Module: '模块',
			Operation: '操作',
			DisableModule: '禁用模块',
			EnableModule: '启用模块',
			NotDisablable: '不可禁用',
			UninstallModule: '卸载模块',
			NotUninstallable: '不可卸载',
			AlertTitle: '模块设置界面',
			NoLoadNoSettings: '模块并未在此页面上运行,无法获取设置',
			NoSettings: '该模块当前并没有提供设置选项',
			ModuleDetail: '<span class="{CT}">名称:</span><span name="name"></span></br><span class="{CT}">描述:</span><span name="description"></span></br><span class="{CT}">版本:</span><span name="version"></span></br><span class="{CT}">作者:</span><span name="author"></span></br><span class="{CT}">版权:</span><span name="license"></span></br><span class="{CT}">来源:</span><span name="src"></span></br><span class="{CT}">是否已启用:</span><span name="enabled"></span>'.replaceAll('{CT}', ASSETS.ClassName.Text),
			Boolean: {
				'true': '是',
				'false': '否'
			},
		},
		Faicon: {
			Info: 'fa-solid fa-circle-info'
		},
		Config_Ruleset: {
			'version-key': 'config-version',
			'ignores': ["LOCAL-CDN"],
			'defaultValues': {
				//'config-key': {},
			},
			'updaters': {
				/*'config-key': [
					function() {
						// This function contains updater for config['config-key'] from v0 to v1
					},
					function() {
						// This function contains updater for config['config-key'] from v1 to v2
					}
				]*/
			}
		}
	};

	const UMManager = new UserModuleManager();
	SPanel.add({
		faicon: 'fa-solid fa-gear',
		tip: CONST.Text.Button,
		onclick: UMManager.show
	});

	exports = {
		isSettingPage: isSettingPage,
		insertLines: insertLines,
		registerSettings: UMManager.registerModuleSettings
	};

	function main() {
		// Get elements
		const content = $('#content');

		// Insert settings
		const title = [
			[{html: CONST.Text.Title, colSpan: 3, class: 'foot', key: 'settitle'}],
			[{html: CONST.Text.ModuleManage, colSpan: 1}, {html: CONST.Text.OpenModuleDialog, colSpan: 2, onclick: UMManager.show}],
			//[{html: CONST.Text.XXXX, colSpan: 1, key: 'xxxxxxxx'}, {html: CONST.Text.XXXX, colSpan: 2, key: 'xxxxxxxx'}],
		]
		const elements = insertLines(title);

		// scrollIntoView if need
		getUrlArgv('tosettings') === 'true' && elements.settitle.scrollIntoView();
	}

	// Module manager user interface
	function UserModuleManager() {
		const UMM = this;
		const moduleSettingFuncs = {};

		UMM.show = show;

		UMM.registerModuleSettings = registerModuleSettings;

		UMM.showModuleSettings = showModuleSettings;

		function show() {
			//box.set('message', 'No implemented yet!').show();
			const modules = ML_listModules();

			// Make panel
			const SetPanel = new SettingPanel.SettingPanel({
				header: CONST.Text.ModuleManage,
				tables: []
			});

			// Make table
			const table = new SetPanel.PanelTable({});

			// Make header
			table.appendRow({
				blocks: [{
					isHeader: true,
					colSpan: 1,
					width: '60%',
					innerText: CONST.Text.Module,
				},{
					isHeader: true,
					colSpan: 4,
					width: '40%',
					innerText: CONST.Text.Operation,
				}]
			});

			// Make module rows
			for (const module of modules) {
				const row = new SetPanel.PanelRow({
					blocks: [{
						colSpan: 1,
						rowSpan: 1,
						children: [
							(() => {
								const icon = $CrE('i');
								icon.className = CONST.Faicon.Info;
								icon.style.marginRight = '0.5em';
								icon.classList.add(ASSETS.ClassName.Text);

								tippy(icon, {
									content: makeContent(),
									onTrigger: (instance, event) => {
										instance.setContent(makeContent());
									}
								});
								return icon;

								function makeContent() {
									const m = ML_getModule(module.identifier);
									const tip = $CrE('div');
									tip.innerHTML = CONST.Text.ModuleDetail;
									tip.childNodes.forEach((elm) => {
										if (!elm instanceof HTMLElement) {return;}
										const name = elm.getAttribute('name');
										if (name && m.hasOwnProperty(name)) {
											elm.innerText = ({
												string: (s) => (s),
												boolean: (b) => (CONST.Text.Boolean[b.toString()])
											})[typeof m[name]](m[name]);
										}
									});

									return tip;
								}
							}) (),
							(() => {
								const span = $CrE('span');
								span.innerText = module.displayname || module.name;
								return span;
							}) (),
						],
					},{
						colSpan: 1,
						rowSpan: 1,
						children: [makeBtn(
							CONST.Text.ModuleSettings,
							showModuleSettings.bind(null, module.identifier)
						)]
					},{
						colSpan: 1,
						rowSpan: 1,
						children: [makeBtn(
							canDisable(module) ? CONST.Text.DisableModule : CONST.Text.NotDisablable,
							canDisable(module) ? ML_disableModule.bind(null, module.identifier) : null,
							!canDisable(module)
						)]
					},{
						colSpan: 1,
						rowSpan: 1,
						children: [makeBtn(
							CONST.Text.EnableModule,
							ML_enableModule.bind(null, module.identifier)
						)]
					},{
						colSpan: 1,
						rowSpan: 1,
						children: [makeBtn(
							canUninstall(module) ? CONST.Text.UninstallModule : CONST.Text.NotUninstallable,
							canUninstall(module) ? ML_uninstallModule.bind(null, module.identifier) : null,
							!canUninstall(module)
						)]
					}]
				});
				table.appendRow(row);
			}
			SetPanel.appendTable(table);

			function makeBtn(text, onclick, disabled) {
				const span = $CrE('span');
				span.innerText = text;
				onclick && span.addEventListener('click', onclick);
				span.classList.add(ASSETS.ClassName.Button);
				disabled && span.classList.add(ASSETS.ClassName.Disabled);
				return span;
			}

			function canUninstall(module) {
				return !(module.flags & ASSETS.FLAG.NO_UNINSTALL);
			}

			function canDisable(module) {
				return !(module.flags & ASSETS.FLAG.NO_DISABLE);
			}
		}

		function registerModuleSettings(id, func) {
			moduleSettingFuncs[id] = func;
		}

		function showModuleSettings(id) {
			const func = moduleSettingFuncs[id];
			if (typeof func === 'function') {
				func();
				return true;
			} else {
				if (!ML_moduleLoaded(id)) {
					alertify.alert(CONST.Text.AlertTitle, CONST.Text.NoLoadNoSettings);
				} else {
					alertify.alert(CONST.Text.AlertTitle, CONST.Text.NoSettings);
				}
				return false;
			}
		}
	}

	function insertLines(lines, tbody) {
		!tbody && (tbody = $(content, 'table>tbody'));
		const elements = {};
		for (const line of lines) {
			const tr = $CrE('tr');
			for (const item of line) {
				const td = $CrE('td');
				item.html && (td.innerHTML = item.html);
				item.colSpan && (td.colSpan = item.colSpan);
				item.class && (td.className = item.class);
				item.id && (td.id = item.id);
				item.tiptitle && mousetip.settip(td, item.tiptitle);
				item.key && (elements[item.key] = td);
				if (item.onclick) {
					td.style.color = 'grey';
					td.style.textAlign = 'center';
					td.addEventListener('click', item.onclick);
				}
				td.style.padding = '3px';
				tr.appendChild(td);
			}
			tbody.appendChild(tr);
		}
		return elements;
	}

	function isSettingPage(callback) {
		const page = getAPI()[0] === 'userdetail.php';
		page && callback && callback();
		return page;
	}

	function htmlEncode(text) {
		const span = $CrE('div');
		span.innerText = text;
		return span.innerHTML;
	}

	// Change location.href without reloading using history.pushState/replaceState
	function setPageUrl() {
		let win, url, push;
		switch (arguments.length) {
			case 1:
				win = window;
				url = arguments[0];
				push = false;
				break;
			case 2:
				win = arguments[0];
				url = arguments[1];
				push = false;
				break;
			case 3:
				win = arguments[0];
				url = arguments[1];
				push = arguments[2];
		}
		return win.history[push ? 'pushState' : 'replaceState']({modified: true, ...history.state}, '', url);
	}
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址