GreaseMonkey Script Configurator
Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @require https://update.greasyfork.org/scripts/1884/4836/GM_config.js
// ==UserScript==
// @name GM_config
// @namespace http://userscripts.org/users/23652
// @description GreaseMonkey Script Configurator
// @include http://*
// @include https://*
// @include file:*
// @copyright JoeSimmons & Sizzlemctwizzle & IzzySoft
// @version 1.2.57
// @license LGPL version 3 or any later version; http://www.gnu.org/copyleft/lgpl.html
// ==/UserScript==
/* Instructions ---------------------------------------------------------------------------------------------------
GM_config is cross-browser compatible.
To use it in a Greasemonkey/Tampermonkey/Violentmonkey script, you can just @require it.
If you can't @require it, you will need to manually include the code at the beginning of your user script.
In non-Greasemonkey, stored settings will only be accessible on the same domain in which they were saved.
---------------------------------------------------------------------------------------------------------------- */
/* CHANGELOG --------------------------------------------------------------------------
1.2.57
- Fixed TypeError with the "options" setting of a "select" field
The "options" setting needs to be a JSON object, not an array
1.2.56
- started keeping changelog in source
- added type "password"
- fixed error when user doesn't define any sections
------------------------------------------------------------------------------------- */
var GM_config = {
storage: 'GM_config',
init: function() {
// loop through GM_config.init() arguments
for(var i=0,l=arguments.length,arg; i<l; ++i) {
arg=arguments[i];
switch(typeof arg) {
case 'object': for(var j in arg) { // could be a callback functions or settings object
switch(j) {
case "open": GM_config.onOpen=arg[j]; delete arg[j]; break; // called when frame is gone
case "close": GM_config.onClose=arg[j]; delete arg[j]; break; // called when settings have been saved
case "save": GM_config.onSave=arg[j]; delete arg[j]; break; // store the settings objects
default: var settings = arg;
}
} break;
case 'function': GM_config.onOpen = arg; break; // passing a bare function is set to open
// could be custom CSS or the title string
case 'string': if(arg.indexOf('{') !== -1 && arg.indexOf('}') !== -1) var css = arg;
else GM_config.title = arg;
break;
}
}
if(!GM_config.title) GM_config.title = 'Settings - Anonymous Script'; // if title wasn't passed through init()
// give the script a unique saving ID for non-firefox browsers
GM_config.storage = GM_config.title.replace(/\W+/g, "").toLowerCase();
var stored = GM_config.read(); // read the stored settings
GM_config.passed_values = {};
for(var i in settings) {
GM_config.doSettingValue(settings, stored, i, null, false);
if(settings[i].kids) for(var kid in settings[i].kids) GM_config.doSettingValue(settings, stored, kid, i, true);
}
GM_config.values = GM_config.passed_values;
GM_config.settings = settings;
if (css) GM_config.css.stylish = css;
},
open: function() {
if(document.evaluate("//iframe[@id='GM_config']",document,null,9,null).singleNodeValue) return;
// Create frame
document.body.appendChild((GM_config.frame=GM_config.create('iframe',{id:'GM_config', style:'position: fixed; top: 0; left: 0; opacity: 0; display: none; z-index: 999999; width: 75%; height: 75%; max-height: 95%; max-width: 95%; border:3px ridge #000000; overflow: auto;'})));
GM_config.frame.src = 'about:blank'; // In WebKit src cant be set until it is added to the page
GM_config.frame.addEventListener('load', function() {
var obj = GM_config, doc = this.contentDocument, frameBody = doc.getElementsByTagName('body')[0], create=obj.create, settings=obj.settings, anch, secNo;
obj.frame.contentDocument.getElementsByTagName('head')[0].appendChild(create('style',{type:'text/css',textContent:obj.css.basic + "\n\n" + obj.css.stylish}));
// Add header and title
frameBody.appendChild(create('div', {id:'header',className:'config_header block center', innerHTML:obj.title}));
// Append elements
anch = frameBody; // define frame body
secNo = 0; // anchor to append elements
for(var i in settings) {
var type, field = settings[i], value = obj.values[i], section = (field.section ? field.section : ["Main Options"]),
headerExists = doc.evaluate(".//div[@class='section_header_holder' and starts-with(@id, 'section_')]", frameBody, null, 9, null).singleNodeValue;
if(typeof field.section !== "undefined" || headerExists === null) {
anch = frameBody.appendChild(create('div', {className:'section_header_holder', id:'section_'+secNo, kids:new Array(
create('a', {className:'section_header center', href:"javascript:void(0);", id:'c_section_kids_'+secNo, textContent:section[0], onclick:function(){GM_config.toggle(this.id.substring(2));}}),
create('div', {id:'section_kids_'+secNo, className:'section_kids', style:obj.getValue('section_kids_'+secNo, "")==""?"":"display: none;"})
)}));
if(section[1]) anch.appendChild(create('p', {className:'section_desc center',innerHTML:section[1]}));
secNo++;
}
anch.childNodes[1].appendChild(GM_config.addToFrame(field, i, false));
}
// Add save and close buttons
frameBody.appendChild(obj.create('div', {id:'buttons_holder', kids:new Array(
obj.create('button',{id:'saveBtn',textContent:'Save',title:'Save options and close window',className:'saveclose_buttons',onclick:function(){GM_config.close(true)}}),
obj.create('button',{id:'cancelBtn', textContent:'Cancel',title:'Close window',className:'saveclose_buttons',onclick:function(){GM_config.close(false)}}),
obj.create('div', {className:'reset_holder block', kids:new Array(
obj.create('a',{id:'resetLink',textContent:'Restore to default',href:'#',title:'Restore settings to default configuration',className:'reset',onclick:obj.reset})
)}))}));
obj.center(); // Show and center it
window.addEventListener('resize', obj.center, false); // Center it on resize
if (obj.onOpen) obj.onOpen(); // Call the open() callback function
// Close frame on window close
window.addEventListener('beforeunload', function(){GM_config.remove(this);}, false);
}, false);
},
close: function(save) {
if(save) {
var type, fields = GM_config.settings, typewhite=/radio|text|hidden|password|checkbox/;
for(f in fields) {
var field = GM_config.frame.contentDocument.getElementById('field_'+f), kids=fields[f].kids;
if(typewhite.test(field.type)) type=field.type;
else type=field.tagName.toLowerCase();
GM_config.doSave(f, field, type);
if(kids) for(var kid in kids) {
var field = GM_config.frame.contentDocument.getElementById('field_'+kid);
if(typewhite.test(field.type)) type=field.type;
else type=field.tagName.toLowerCase();
GM_config.doSave(kid, field, type, f);
}
}
if(GM_config.onSave) GM_config.onSave(); // Call the save() callback function
GM_config.save();
}
if(GM_config.frame) GM_config.remove(GM_config.frame);
delete GM_config.frame;
if(GM_config.onClose) GM_config.onClose(); // Call the close() callback function
},
set: function(name,val) {
GM_config.values[name] = val;
},
get: function(name) {
return GM_config.values[name];
},
isGM: (typeof window.opera === "undefined" && typeof window.chrome === "undefined" && typeof GM_info === "object" && typeof GM_registerMenuCommand === "function"),
log: function(str) {
if(this.isGM) return GM_log(str);
else if(window.opera) return window.opera.postError(str);
else return console.log(str);
},
getValue : function(name, d) {
var r, def = (typeof d !== "undefined" ? d : "");
switch(this.isGM === true) {
case true: r = GM_getValue(name, def); break;
case false: r = localStorage.getItem(name) || def; break;
}
return r;
},
setValue : function(name, value) {
switch(this.isGM === true) {
case true: GM_setValue(name, value); break;
case false: localStorage.setItem(name, value); break;
}
},
deleteValue : function(name) {
switch(this.isGM === true) {
case true: GM_deleteValue(name); break;
case false: localStorage.removeItem(name); break;
}
},
save: function(store, obj) {
try {
var val = JSON.stringify(obj || GM_config.values);
GM_config.setValue((store||GM_config.storage),val);
} catch(e) {
GM_config.log("GM_config failed to save settings!\n" + e);
}
},
read: function(store) {
var val = GM_config.getValue((store || GM_config.storage), '{}');
switch(typeof val) {
case "string": var rval = JSON.parse(val); break;
case "object": var rval = val; break;
default: var rval = {};
}
return rval;
},
reset: function(e) {
e.preventDefault();
var type, obj = GM_config, fields = obj.settings;
for(f in fields) {
var field = obj.frame.contentDocument.getElementById('field_'+f), kids=fields[f].kids;
if(field.type=='radio'||field.type=='text'||field.type=='checkbox') type=field.type;
else type=field.tagName.toLowerCase();
GM_config.doReset(field, type, null, f, null, false);
if(kids) for(var kid in kids) {
var field = GM_config.frame.contentDocument.getElementById('field_'+kid);
if(field.type=='radio'||field.type=='text'||field.type=='checkbox') type=field.type;
else type=field.tagName.toLowerCase();
GM_config.doReset(field, type, f, kid, true);
}
}
},
addToFrame : function(field, i, k) {
var elem, obj = this, anch = this.frame, value = obj.values[i], Options = field.options, label = field.label, create=obj.create, isKid = (k !== null && k === true);
switch(field.type) {
case 'textarea':
elem = create(isKid ? "span" : "div", {title:field.title||'', kids:new Array(
create('span', {textContent:label, className:'field_label'}),
create('textarea', {id:'field_'+i,innerHTML:value, cols:(field.cols?field.cols:20), rows:(field.rows?field.rows:2)})
), className: 'config_var'});
break;
case 'radio':
var boxes = new Array();
for (var j = 0,len = Options.length; j<len; j++) {
boxes.push(create('span', {textContent:Options[j]}));
boxes.push(create('input', {value:Options[j], type:'radio', name:i, checked:Options[j]==value?true:false}));
}
elem = create(isKid ? "span" : "div", {title:field.title||'', kids:new Array(
create('span', {textContent:label, className:'field_label'}),
create('span', {id:'field_'+i, kids:boxes})
), className: 'config_var'});
break;
case 'select':
var options = [];
if(typeof Options === "object" && typeof Options.push !== "function") for(var j in Options) options.push(create('option',{textContent:Options[j],value:j,selected:(j==value)}));
else options.push(create("option", {textContent:"Error - \"options\" needs to be a JSON object.", value:"error", selected:"selected"}));
elem = create(isKid ? "span" : "div", {title:field.title||'', kids:new Array(
create('span', {textContent:label, className:'field_label'}),
create('select',{id:'field_'+i, kids:options})
), className: 'config_var'});
break;
case 'checkbox':
elem = create(isKid ? "span" : "div", {title:field.title||'', kids:new Array(
create('label', {textContent:label, className:'field_label', "for":'field_'+i}),
create('input', {id:'field_'+i, type:'checkbox', value:value, checked:value})
), className: 'config_var'});
break;
case 'button':
var tmp;
elem = create(isKid ? "span" : "div", {kids:new Array(
(tmp=create('input', {id:'field_'+i, type:'button', value:label, size:(field.size?field.size:25), title:field.title||''}))
), className: 'config_var'});
if(field.script) obj.addEvent(tmp, 'click', field.script);
break;
case 'hidden':
elem = create(isKid ? "span" : "div", {title:field.title||'', kids:new Array(
create('input', {id:'field_'+i, type:'hidden', value:value})
), className: 'config_var'});
break;
case 'password':
elem = create(isKid ? "span" : "div", {title:field.title||'', kids:new Array(
create('span', {textContent:label, className:'field_label'}),
create('input', {id:'field_'+i, type:'password', value:value, size:(field.size?field.size:25)})
), className: 'config_var'});
break;
default:
elem = create(isKid ? "span" : "div", {title:field.title||'', kids:new Array(
create('span', {textContent:label, className:'field_label'}),
create('input', {id:'field_'+i, type:'text', value:value, size:(field.size?field.size:25)})
), className: 'config_var'});
}
if(field.kids) {
var kids=field.kids;
for(var kid in kids) elem.appendChild(obj.addToFrame(kids[kid], kid, true));
}
return elem;
},
doSave : function(f, field, type, oldf) {
var isNum=/^[\d\.]+$/, set = oldf ? GM_config.settings[oldf]["kids"] : GM_config.settings;
switch(type) {
case 'text':
GM_config.values[f] = ((set[f].type=='text') ? field.value : ((isNum.test(field.value) && ",int,float".indexOf(","+set[f].type)!=-1) ? parseFloat(field.value) : false));
if(set[f]===false) {
alert('Invalid type for field: '+f+'\nPlease use type: '+set[f].type);
return;
}
break;
case 'hidden': case 'password':
GM_config.values[f] = field.value.toString();
break;
case 'textarea':
GM_config.values[f] = field.value;
break;
case 'checkbox':
GM_config.values[f] = field.checked;
break;
case 'select':
GM_config.values[f] = field.options[field.selectedIndex].value;
break;
case 'span':
var radios = field.getElementsByTagName('input');
if(radios.length>0) for(var i=radios.length-1; i>=0; i--) {
if(radios[i].checked) GM_config.values[f] = radios[i].value;
}
break;
}
},
doSettingValue : function(settings, stored, i, oldi, k) {
var set = k!=null && k==true && oldi!=null ? settings[oldi]["kids"][i] : settings[i];
if(",save,open,close".indexOf(","+i) == -1) {
// The code below translates to:
// if a setting was passed to init but wasn't stored then
// if a default value wasn't passed through init() then use null
// else use the default value passed through init()
// else use the stored value
try {
var value = (stored[i]==undefined ? (set["default"]==undefined ? null : set["default"]) : stored[i]);
} catch(e) {
var value = (stored[i]=="undefined" ? (set["default"]=="undefined" ? null : set["default"]) : stored[i]);
}
// If the value isn't stored and no default was passed through init()
// try to predict a default value based on the type
if (value === null) {
switch(set["type"]) {
case 'radio': case 'select':
value = set.options[0]; break;
case 'checkbox':
value = false; break;
case 'int': case 'float':
value = 0; break;
default:
value = (typeof stored[i]=="function") ? stored[i] : "";
}
}
}
GM_config.passed_values[i] = value;
},
doReset : function(field, type, oldf, f, k) {
var isKid = k!=null && k==true, obj=GM_config,
set = isKid ? obj.settings[oldf]["kids"][f] : obj.settings[f];
switch(type) {
case 'text':
field.value = set['default'] || '';
break;
case 'hidden': case 'password':
field.value = set['default'] || '';
break;
case 'textarea':
field.value = set['default'] || '';
break;
case 'checkbox':
field.checked = set['default'] || false;
break;
case 'select':
if(set['default']) {
for(var i=field.options.length-1; i>=0; i--)
if(field.options[i].value==set['default']) field.selectedIndex=i;
}
else field.selectedIndex=0;
break;
case 'span':
var radios = field.getElementsByTagName('input');
if(radios.length>0) for(var i=radios.length-1; i>=0; i--) {
if(radios[i].value==set['default']) {
radios[i].checked=true;
}
}
break;
}
},
values: {},
settings: {},
css: {
basic: 'body {background:#FFFFFF;}\n' +
'.indent40 {margin-left:40%;}\n' +
'* {font-family: arial, tahoma, sans-serif, myriad pro;}\n' +
'.field_label {font-weight:bold; font-size:12px; margin-right:6px;}\n' +
'.block {display:block;}\n' +
'.saveclose_buttons {\n' +
'margin:16px 10px 10px 10px;\n' +
'padding:2px 12px 2px 12px;\n' +
'}\n' +
'.reset, #buttons_holder, .reset a {text-align:right; color:#000000;}\n' +
'.config_header {font-size:20pt; margin:0;}\n' +
'.config_desc, .section_desc, .reset {font-size:9pt;}\n' +
'.center {text-align:center;}\n' +
'.section_header_holder {margin-top:8px;}\n' +
'.config_var {margin:0 0 4px 0; display:block;}\n' +
'.config_var {font-size: 13px !important;}\n' +
'.section_header {font-size:13pt; background:#414141; color:#FFFFFF; border:1px solid #000000; margin:0;}\n' +
'.section_desc {font-size:9pt; background:#EFEFEF; color:#575757; border:1px solid #CCCCCC; margin:0 0 6px 0;}\n' +
'input[type="radio"] {margin-right:8px;}',
stylish: ''
},
create: function(a,b) {
var ret=window.document.createElement(a);
if(b) for(var prop in b) {
if(prop.indexOf('on')==0) ret.addEventListener(prop.substring(2),b[prop],false);
else if(prop=="kids" && (prop=b[prop])) for(var i=0; i<prop.length; i++) ret.appendChild(prop[i]);
else if(",style,accesskey,id,name,src,href,for".indexOf(","+prop.toLowerCase())!=-1) ret.setAttribute(prop, b[prop]);
else ret[prop]=b[prop];
}
return ret;
},
center: function() {
var node = GM_config.frame, style = node.style, beforeOpacity = style.opacity;
if(style.display=='none') style.opacity='0';
style.display = '';
style.top = Math.floor((window.innerHeight/2)-(node.offsetHeight/2)) + 'px';
style.left = Math.floor((window.innerWidth/2)-(node.offsetWidth/2)) + 'px';
style.opacity = '1';
},
run: function() {
var script=GM_config.getAttribute('script');
if(script && typeof script=='string' && script!='') {
func = new Function(script);
window.setTimeout(func, 0);
}
},
addEvent: function(el, ev, scr) {
if(el) el.addEventListener(ev, function() {
typeof scr === 'function' ? window.setTimeout(scr, 0) : eval(scr)
}, false);
},
remove: function(el) {
if(el && el.parentNode) el.parentNode.removeChild(el);
},
toggle : function(e) {
var node=GM_config.frame.contentDocument.getElementById(e);
node.style.display=(node.style.display!='none')?'none':'';
GM_config.setValue(e, node.style.display);
},
};
/* EXAMPLE CODE BELOW --------------------------
GM_config.init("Test", {
"one" : {
"label" : "Option One",
"type" : "checkbox",
"default" : false
},
"two" : {
"label" : "Option Two",
"type" : "checkbox",
"default" : false
},
"three" : {
"label" : "Option Three",
"type" : "password"
},
"four" : {
"label" : "Option Four",
"type" : "select",
"options" : {
"one" : "One",
"two" : "Two"
}
}
});
GM_config.open();
------------------------------------------------- */