GM_config_lz-string

ConfigLzString/Refactor GM_config, this version uses lz-string to access data for a Library script

Dit script moet niet direct worden geïnstalleerd - het is een bibliotheek voor andere scripts om op te nemen met de meta-richtlijn // @require https://update.greasyfork.org/scripts/372760/634230/GM_config_lz-string.js

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==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);
	}
};