您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
ConfigLzString/Refactor GM_config, this version uses lz-string to access data for a Library script
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.org/scripts/372760/634230/GM_config_lz-string.js
// ==UserScript== // @namespace http://tampermonkey.net/ // @exclude * // ==UserLibrary== // @name GM_config_lz-string // @description ConfigLzString/Refactor GM_config, this version uses lz-string to access data for a Library script // @author avan // @license MIT // @version 0.6 // ==/UserScript== // ==/UserLibrary== GM_configStruct.prototype.create = function() { switch (arguments.length) { case 1: var A = document.createTextNode(arguments[0]); break; default: var A = document.createElement(arguments[0]), B = arguments[1]; for (var b in B) { if (b.indexOf("on") == 0) A.addEventListener(b.substring(2), B[b], false); //else if (",style,accesskey,id,name,src,href,which,for".indexOf("," + b.toLowerCase()) != -1) else if (b.match(/^(style|accesskey|id|name|src|href|which|for|data-)/i)) A.setAttribute(b, B[b]); else A[b] = B[b]; } if (typeof arguments[2] == "string") A.innerHTML = arguments[2]; else for (var i = 2, len = arguments.length; i < len; ++i) A.appendChild(arguments[i]); } return A; }; GM_configStruct.prototype.read = function (store) { var rval, cKey, dValue; try { cKey = LZString.compressToUTF16(store || this.id); dValue = LZString.decompressFromUTF16(this.getValue(cKey, '{}')); rval = this.parser(dValue); } catch(e) { this.log("GM_config failed to read saved settings!"); rval = {}; } return rval; }; GM_configStruct.prototype.write = function (store, obj) { if (!obj) { var values = {}, forgotten = {}, fields = this.fields; for (var id in fields) { var field = fields[id]; var value = field.toValue(); if (field.save) { if (value !== null) { values[id] = value; field.value = value; } else values[id] = field.value; } else forgotten[id] = value; } } try { var cKey = LZString.compressToUTF16(store || this.id), cValue = LZString.compressToUTF16(this.stringify(obj || values)); this.setValue(cKey, cValue); } catch(e) { this.log("GM_config failed to save settings!"); } return forgotten; }; GM_configField.prototype.create = GM_configStruct.prototype.create; GM_configField.prototype.toNode = function() { var field = this.settings, value = this.value, options = field.options, type = field.type, className = field.class, style = field.style, id = this.id, configId = this.configId, labelPos = field.labelPos, create = this.create; function addLabel(pos, labelEl, parentNode, beforeEl) { if (!beforeEl) beforeEl = parentNode.firstChild; switch (pos) { case 'right': case 'below': if (pos == 'below') parentNode.appendChild(create('br', {})); parentNode.appendChild(labelEl); break; default: if (pos == 'above') parentNode.insertBefore(create('br', {}), beforeEl); parentNode.insertBefore(labelEl, beforeEl); } } var retNode = create('div', { className: 'config_var', id: configId + '_' + id + '_var', title: field.title || '', }), firstProp; // Retrieve the first prop for (var i in field) { firstProp = i; break; } var label = field.label && type != "button" ? create('label', { id: configId + '_' + id + '_field_label', for: configId + '_field_' + id, className: 'field_label' }, field.label) : null; var props = {className: className || '', style: style || ''}; for (var key in field) { var val = field[key]; if (key.match(/^data-/i) && !props[key]) props[key] = val; }; switch (type) { case 'textarea': props.innerHTML = value; props.id = configId + '_field_' + id; props.className = (props.className ? props.className + ' ' : '') + 'block'; props.cols = (field.cols ? field.cols : 20); props.rows = (field.rows ? field.rows : 2); retNode.appendChild((this.node = create('textarea', props))); break; case 'radio': props.id = configId + '_field_' + id; var wrap = create('div', props); this.node = wrap; for (var i = 0, len = options.length; i < len; ++i) { var radLabel = create('label', { className: 'radio_label' }, options[i]); var rad = wrap.appendChild(create('input', { value: options[i], type: 'radio', name: id, checked: options[i] == value })); var radLabelPos = labelPos && (labelPos == 'left' || labelPos == 'right') ? labelPos : firstProp == 'options' ? 'left' : 'right'; addLabel(radLabelPos, radLabel, wrap, rad); } retNode.appendChild(wrap); break; case 'select': props.id = configId + '_field_' + id; var wrap = create('select', props); this.node = wrap; for (var i = 0, len = options.length; i < len; ++i) { var option = options[i]; wrap.appendChild(create('option', { value: option, selected: option == value }, option)); } retNode.appendChild(wrap); break; default: // fields using input elements props.id = configId + '_field_' + id; props.type = type; props.value = type == 'button' ? field.label : value; switch (type) { case 'checkbox': props.checked = value; break; case 'button': props.size = field.size ? field.size : 25; if (field.script) field.click = field.script; if (field.click) props.onclick = field.click; break; case 'hidden': break; case 'password': props.size = field.size ? field.size : 25; break; default: // type = text, int, or float props.type = 'text'; props.size = field.size ? field.size : 25; } retNode.appendChild((this.node = create('input', props))); } if (label) { // If the label is passed first, insert it before the field // else insert it after if (!labelPos) labelPos = firstProp == "label" || type == "radio" ? "left" : "right"; addLabel(labelPos, label, retNode); } return retNode; }; var ConfigLzString = function () { GM_configStruct.apply(this, arguments); if (arguments.length > 0 && arguments[0].src) { this.srcs = arguments[0].src.replace(/ *[ ;,]+ */g, ' ').split(/[ ;,]/); } } ConfigLzString.prototype = GM_configStruct.prototype; ConfigLzString.prototype.open = function() { // Die if the menu is already open on this page // You can have multiple instances but you can't open the same instance twice var match = document.getElementById(this.id); if (match && (match.tagName == "IFRAME" || match.childNodes.length > 0)) return; // Sometimes "this" gets overwritten so create an alias var config = this; // Function to build the mighty config window :) function buildConfigWin(body, head) { var create = config.create, fields = config.fields, configId = config.id, bodyWrapper = create('div', { id: configId + '_wrapper' }); // Append the style which is our default style plus the user style head.appendChild( create('style', { type: 'text/css', textContent: config.css.basic + config.css.stylish })); // Add header and title bodyWrapper.appendChild(create('div', { id: configId + '_header', className: 'config_header block center' }, config.title)); // Append elements var section = bodyWrapper, secNum = 0; // Section count // loop through fields for (var id in fields) { var field = fields[id], settings = field.settings; if (settings.section) { // the start of a new section section = bodyWrapper.appendChild(create('div', { className: 'section_header_holder', id: configId + '_section_' + secNum })); if (Object.prototype.toString.call(settings.section) !== '[object Array]') settings.section = [settings.section]; if (settings.section[0]) section.appendChild(create('div', { className: 'section_header center', id: configId + '_section_header_' + secNum }, settings.section[0])); if (settings.section[1]) section.appendChild(create('p', { className: 'section_desc center', id: configId + '_section_desc_' + secNum }, settings.section[1])); ++secNum; } // Create field elements and append to current section section.appendChild((field.wrapper = field.toNode())); } // Add save and close buttons bodyWrapper.appendChild( create('div', { id: configId + '_buttons_holder' }, create('button', { id: configId + '_saveBtn', textContent: 'Save', title: 'Save settings', className: 'saveclose_buttons', onclick: function() { config.save() } }), create('button', { id: configId + '_closeBtn', textContent: 'Close', title: 'Close window', className: 'saveclose_buttons', onclick: function() { config.close() } }), create('div', { className: 'reset_holder block' }, create('a', { // Reset link id: configId + '_resetLink', textContent: 'Reset to defaults', href: '#', title: 'Reset fields to default values', className: 'reset', onclick: function(e) { e.preventDefault(); config.reset() } }) ))); body.appendChild(bodyWrapper); // Paint everything to window at once config.center(); // Show and center iframe window.addEventListener('resize', config.center, false); // Center frame on resize // Call the open() callback function config.onOpen(config.frame.contentDocument || config.frame.ownerDocument, config.frame.contentWindow || window, config.frame); // Close frame on window close window.addEventListener('beforeunload', function() { config.close(); }, false); // Now that everything is loaded, make it visible config.frame.style.display = "block"; config.isOpen = true; } // Change this in the onOpen callback using this.frame.setAttribute('style', '') var defaultStyle = 'bottom: auto; border: 1px solid #000; display: none; height: 75%;' + ' left: 0; margin: 0; max-height: 95%; max-width: 95%; opacity: 0;' + ' overflow: auto; padding: 0; position: fixed; right: auto; top: 0;' + ' width: 75%; z-index: 9999;'; // Either use the element passed to init() or create an iframe if (this.frame) { this.frame.id = this.id; // Allows for prefixing styles with the config id this.frame.setAttribute('style', defaultStyle); var head = this.frame.ownerDocument.getElementsByTagName('head')[0]; if (this.srcs && this.srcs.length > 0 ) { this.srcs.forEach(function(src) { head.appendChild(this.create('script', {src: src})); }) } buildConfigWin(this.frame, head); } else { // Create frame document.body.appendChild((this.frame = this.create('iframe', { id: this.id, style: defaultStyle }))); // In WebKit src can't be set until it is added to the page this.frame.src = 'about:blank'; // we wait for the iframe to load before we can modify it this.frame.addEventListener('load', function(e) { var frame = config.frame; var body = frame.contentDocument.getElementsByTagName('body')[0]; body.id = config.id; // Allows for prefixing styles with the config id var head = frame.contentDocument.getElementsByTagName('head')[0]; if (config.src) head.appendChild(config.create('script', {src: config.src})); if (config.srcs && config.srcs.length > 0 ) { config.srcs.forEach(function(src) { head.appendChild(config.create('script', {src: src})); }) } buildConfigWin(body, head); }, false); } };