OS2.spielplan: Unterschied zwischen den Versionen
Zur Navigation springen
Zur Suche springen
SLC (Diskussion | Beiträge) (Update Version 0.61 (Speicherfunktionen, Land- und Liga-Nummern)) |
SLC (Diskussion | Beiträge) (Update Version 0.70 (Class, define, setConst, Logging, Speicher umgebaut, FreeValue/SelValue/AutoReset, Menü-Optionen interaktiv abfragen)) |
||
| Zeile 4: | Zeile 4: | ||
|- bgcolor="#FFCC00" | |- bgcolor="#FFCC00" | ||
| '''Dateiname''' | | '''Dateiname''' | ||
| ''' | | '''OS2.spielplan.user.js''' | ||
|- bgcolor="#FFCC00" | |- bgcolor="#FFCC00" | ||
| '''Version''' | | '''Version''' | ||
| '''0. | | '''0.70''' | ||
|- bgcolor="#FFCC00" | |- bgcolor="#FFCC00" | ||
| '''Autor''' | | '''Autor''' | ||
| Zeile 19: | Zeile 19: | ||
|- bgcolor="#FFCC00" | |- bgcolor="#FFCC00" | ||
| '''Funktionalität''' | | '''Funktionalität''' | ||
| '''Trennstriche zwischen den Abrechnungsmonaten'''<br> '''Verkürzung von "Vorbericht(e)" und "Kommentar(e)"'''<br> '''Details zu den Spielen'''<br> '''Ergebnisse aufaddieren'''<br> '''Nachträgliche Vorschau: Bilanz'''<br> '''Benutzermenü für Optionen'''<br> '''Erweiterte Optionen auch auf der Seite'''<br> '''Link auf den jeweiligen Spieltag bzw. die jeweilige Runde''' | | '''Trennstriche zwischen den Abrechnungsmonaten'''<br> '''Verkürzung von "Vorbericht(e)" und "Kommentar(e)"'''<br> '''Details zu den Spielen'''<br> '''Ergebnisse aufaddieren'''<br> '''Nachträgliche Vorschau: Bilanz'''<br> '''Benutzermenü für Optionen'''<br> '''Erweiterte Optionen auch auf der Seite'''<br> '''Link auf den jeweiligen Spieltag bzw. die jeweilige Runde'''<br> '''Interaktive Menü-Optionen'''<br> '''Gemeinsame Code- und Datenbasis''' | ||
|- bgcolor="#FFCC00" | |- bgcolor="#FFCC00" | ||
| '''Letzte Änderung''' | | '''Letzte Änderung''' | ||
| Zeile 27: | Zeile 27: | ||
<pre> | <pre> | ||
// ==UserScript== | // ==UserScript== | ||
// @name | // @name OS2.spielplan | ||
// @namespace | // @namespace http://os.ongapo.com/ | ||
// @version | // @version 0.70 | ||
// @copyright | // @copyright 2013+ | ||
// @author | // @author Sven Loges (SLC) | ||
// @description Spielplan-Abschnitt aus dem Master-Script fuer Online Soccer 2.0 | // @description Spielplan-Abschnitt aus dem Master-Script fuer Online Soccer 2.0 | ||
// @include | // @include http*://os.ongapo.com/st.php?s=* | ||
// @include | // @include http*://os.ongapo.com/showteam.php?s=* | ||
// @include | // @include http*://www.os.ongapo.com/st.php?s=* | ||
// @include | // @include http*://www.os.ongapo.com/showteam.php?s=* | ||
// @include | // @include http*://online-soccer.eu/st.php?s=* | ||
// @include | // @include http*://online-soccer.eu/showteam.php?s=* | ||
// @include | // @include http*://www.online-soccer.eu/st.php?s=* | ||
// @include | // @include http*://www.online-soccer.eu/showteam.php?s=* | ||
// @grant | // @grant GM_getValue | ||
// @grant | // @grant GM_setValue | ||
// @grant | // @grant GM_deleteValue | ||
// @grant | // @grant GM_registerMenuCommand | ||
// @grant GM_info | |||
// ==/UserScript== | // ==/UserScript== | ||
| Zeile 52: | Zeile 53: | ||
// ==================== Konfigurations-Abschnitt fuer Optionen ==================== | // ==================== Konfigurations-Abschnitt fuer Optionen ==================== | ||
const __LOGLEVEL = 3; | |||
// Options-Typen | // Options-Typen | ||
| Zeile 71: | Zeile 74: | ||
const __OPTMEM = { | const __OPTMEM = { | ||
'normal' : { | 'normal' : { | ||
'Name' : "Browser", | |||
'Value' : localStorage, | |||
'Display' : "localStorage", | |||
'Prefix' : 'run' | |||
}, | |||
'begrenzt' : { | |||
'Name' : "Session", | 'Name' : "Session", | ||
'Value' : sessionStorage, | 'Value' : sessionStorage, | ||
'Display' : "sessionStorage", | 'Display' : "sessionStorage", | ||
'Prefix' : 'run' | 'Prefix' : 'run' | ||
}, | }, | ||
| Zeile 89: | Zeile 92: | ||
} | } | ||
}; | }; | ||
// Moegliche Optionen (hier die Standardwerte editieren oder ueber das Benutzermenu setzen): | // Moegliche Optionen (hier die Standardwerte editieren oder ueber das Benutzermenu setzen): | ||
| Zeile 153: | Zeile 154: | ||
'Type' : __OPTTYPES.MC, | 'Type' : __OPTTYPES.MC, | ||
'ValType' : "String", | 'ValType' : "String", | ||
'FreeValue' : true, | |||
'Choice' : [ "white", "yellow", "black", "blue", "cyan", "gold", "grey", "green", | 'Choice' : [ "white", "yellow", "black", "blue", "cyan", "gold", "grey", "green", | ||
"lime", "magenta", "maroon", "navy", "olive", "orange", "purple", | "lime", "magenta", "maroon", "navy", "olive", "orange", "purple", | ||
| Zeile 165: | Zeile 167: | ||
'Type' : __OPTTYPES.MC, | 'Type' : __OPTTYPES.MC, | ||
'ValType' : "String", | 'ValType' : "String", | ||
'FreeValue' : true, | |||
'Choice' : [ "thin", "medium", "thick" ], | 'Choice' : [ "thin", "medium", "thick" ], | ||
'Action' : __OPTACTION.NXT, | 'Action' : __OPTACTION.NXT, | ||
| Zeile 175: | Zeile 178: | ||
'Type' : __OPTTYPES.MC, | 'Type' : __OPTTYPES.MC, | ||
'ValType' : "Number", | 'ValType' : "Number", | ||
'FreeValue' : true, | |||
'SelValue' : false, | |||
'Choice' : [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ], | 'Choice' : [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ], | ||
'Default' : 10, | 'Default' : 10, | ||
| Zeile 199: | Zeile 204: | ||
'Serial' : true, | 'Serial' : true, | ||
'Permanent' : true, | 'Permanent' : true, | ||
'Default' : { 'Team' : undefined, 'Liga' : undefined, 'Land' : undefined, 'LdNr' : 0, 'LgNr' : 0 } | 'Default' : undefined, // new Team() // { 'Team' : undefined, 'Liga' : undefined, 'Land' : undefined, 'LdNr' : 0, 'LgNr' : 0 } | ||
'Submit' : undefined, | 'Submit' : undefined, | ||
'Cols' : 36, | 'Cols' : 36, | ||
| Zeile 228: | Zeile 233: | ||
'Name' : "oldStorage", | 'Name' : "oldStorage", | ||
'Type' : __OPTTYPES.SD, | 'Type' : __OPTTYPES.SD, | ||
'PreInit' : true, | |||
'AutoReset' : true, | 'AutoReset' : true, | ||
'Hidden' : true | 'Hidden' : true | ||
| Zeile 248: | Zeile 254: | ||
// ==================== Invarianter Abschnitt fuer Optionen ==================== | // ==================== Invarianter Abschnitt fuer Optionen ==================== | ||
// =============== | // Kompatibilitaetsfunktion zur Ermittlung des Namens einer Funktion (falle <Function>.name nicht vorhanden ist) | ||
if (Function.prototype.name === undefined) { | |||
Object.defineProperty(Function.prototype, 'name', { | |||
get : function() { | |||
return /function ([^(\s]*)/.exec(this.toString())[1]; | |||
} | |||
}); | |||
} | |||
// Ein Satz von Logfunktionen, die je nach Loglevel zur Verfuegung stehen. Aufruf: __LOG[level](text) | |||
const __LOG = { | |||
'logFun' : [ | |||
console.error, // [0] Alert | |||
console.error, // [1] Error | |||
console.log, // [2] Log: Release | |||
console.log, // [3] Log: Info | |||
console.log, // [4] Log: Debug | |||
console.log, // [5] Log: Verbose | |||
console.log // [6] Log: Very verbose | |||
], | |||
'init' : function(win, logLevel = 1) { | |||
for (level = 0; level < this.logFun.length; level++) { | |||
this[level] = ((level > logLevel) ? function() { } : this.logFun[level]); | |||
} | |||
}, | |||
'changed' : function(oldVal, newVal) { | |||
const __OLDVAL = safeStringify(oldVal); | |||
const __NEWVAL = safeStringify(newVal); | |||
return ((__OLDVAL !== __NEWVAL) ? __OLDVAL + " => " : "") + __NEWVAL; | |||
} | |||
}; | |||
__LOG.init(window, __LOGLEVEL); | |||
// Gibt eine Meldung in der Console aus und oeffnet ein Bestaetigungsfenster mit der Meldung | |||
// label: Eine Ueberschrift | |||
// message: Der Meldungs-Text | |||
// data: Ein Wert. Ist er angegeben, wird er in der Console ausgegeben | |||
function showAlert(label, message, data = undefined) { | |||
__LOG[1](label + ": " + message); | |||
if (data !== undefined) { | |||
__LOG[2](data); | |||
} | |||
alert(label + "\n\n" + message); | |||
} | } | ||
// | // ==================== Abschnitt fuer Klasse Class ==================== | ||
function Class(className, baseClass, initFun) { | |||
'use strict'; | |||
try { | |||
const __BASE = ((baseClass !== undefined) ? baseClass : Object); | |||
const __BASEPROTO = (__BASE ? __BASE.prototype : undefined); | |||
const __BASECLASS = (__BASEPROTO ? __BASEPROTO.__class : undefined); | |||
this.className = (className || '?'); | |||
this.baseClass = __BASECLASS; | |||
Object.setConst(this, 'baseProto', __BASEPROTO, false); | |||
if (! initFun) { | |||
const __BASEINIT = (__BASECLASS || { }).init; | |||
if (__BASEINIT) { | |||
} | initFun = function() { | ||
// Basisklassen-Init aufrufen... | |||
return __BASEINIT.call(this, arguments); | |||
}; | |||
} else { | |||
initFun = function() { | |||
// Basisklassen-Init fehlt (und Basisklasse ist nicht Object)... | |||
return false; | |||
}; | |||
} | |||
} | |||
console.assert((__BASE === null) || ((typeof __BASE) === 'function'), "No function:", __BASE); | |||
console.assert((typeof initFun) === 'function', "No function:", initFun); | |||
this.init = initFun; | |||
} catch (ex) { | |||
showAlert('[' + ex.lineNumber + "] Error in Class " + className, ex.message, ex); | |||
} | |||
} | } | ||
Class.define = function(subClass, baseClass, members = undefined, initFun = undefined, createProto = true) { | |||
return (subClass.prototype = subClass.subclass(baseClass, members, initFun, createProto)); | |||
}; | |||
Object.setConst = function(obj, item, value, config) { | |||
return Object.defineProperty(obj, item, { | |||
enumerable : false, | |||
configurable : (config || true), | |||
writable : false, | |||
value : value | |||
}); | |||
}; | |||
Object.setConst(Object.prototype, 'subclass', function(baseClass, members, initFun, createProto) { | |||
'use strict'; | |||
try { | |||
const __MEMBERS = (members || { }); | |||
const __CREATEPROTO = ((createProto === undefined) ? true : createProto); | |||
console.assert((typeof this) === 'function'); | |||
console.assert((typeof __MEMBERS) === 'object'); | |||
const __CLASS = new Class(this.name || __MEMBERS.__name, baseClass, initFun || __MEMBERS.__init); | |||
const __PROTO = (__CREATEPROTO ? Object.create(__CLASS.baseProto) : this.prototype); | |||
for (let item in __MEMBERS) { | |||
if ((item !== '__name') && (item !== '__init')) { | |||
Object.setConst(__PROTO, item, __MEMBERS[item]); | |||
} | |||
} | |||
Object.setConst(__PROTO, '__class', __CLASS, ! __CREATEPROTO); | |||
return __PROTO; | |||
return | |||
} catch (ex) { | } catch (ex) { | ||
showAlert('[' + ex.lineNumber + "] Error in subclassing", ex.message, ex); | |||
} | } | ||
} | }, false); | ||
Class.define(Object, null, { | |||
'__init' : function() { | |||
// Oberstes Basisklassen-Init... | |||
return true; | |||
}, | |||
'getClass' : function() { | |||
return this.__class; | |||
}, | |||
'getClassName' : function() { | |||
const __CLASS = this.getClass(); | |||
return (__CLASS ? __CLASS.getName() : undefined); | |||
}, | |||
'setConst' : function(item, value, config = undefined) { | |||
return Object.setConst(this, item, value, config); | |||
} | |||
}, undefined, false); | |||
Class.define(Function, Object); | |||
Class.define(Class, Object, { | |||
'getName' : function() { | |||
return this.className; | |||
} | |||
} ); | |||
// ==================== Ende Abschnitt fuer Klasse Class ==================== | |||
// ==================== Abschnitt fuer Klasse Delims ==================== | |||
// | // Basisklasse fuer die Verwaltung der Trennzeichen und Symbole von Pfaden | ||
// | // delim: Trennzeichen zwischen zwei Ebenen (oder Objekt/Delims mit entsprechenden Properties) | ||
// | // back: (Optional) Name des relativen Vaterverzeichnisses | ||
// | // root: (Optional) Kennung vor dem ersten Trenner am Anfang eines absoluten Pfads | ||
// | // home: (Optional) Kennung vor dem ersten Trenner am Anfang eines Pfads relativ zu Home | ||
function | function Delims(delim, back, root, home) { | ||
'use strict'; | |||
if ( | if ((typeof delim) === 'object') { | ||
// Erster Parameter ist Objekt mit den Properties... | |||
if (back === undefined) { | |||
back = delim.back; | |||
} | |||
if (root === undefined) { | |||
root = delim.root; | |||
} | |||
if (home === undefined) { | |||
home = delim.home; | |||
} | |||
delim = delim.delim; | |||
} | } | ||
this.setDelim(delim); | |||
this.setBack(back); | |||
this.setRoot(root); | |||
this.setHome(home); | |||
} | } | ||
Class.define(Delims, Object, { | |||
'setDelim' : function(delim = undefined) { | |||
function | this.delim = delim; | ||
}, | |||
'setBack' : function(back = undefined) { | |||
this.back = back; | |||
}, | |||
'setRoot' : function(root = undefined) { | |||
this.root = root; | |||
}, | |||
'setHome' : function(home = undefined) { | |||
this.home = home; | |||
} | |||
} ); | |||
// ==================== Ende Abschnitt fuer Klasse Delims ==================== | |||
// ==================== Abschnitt fuer Klasse UriDelims ==================== | |||
// Basisklasse fuer die Verwaltung der Trennzeichen und Symbole von URIs | |||
// delim: Trennzeichen zwischen zwei Ebenen (oder Objekt/Delims mit entsprechenden Properties) | |||
// back: (Optional) Name des relativen Vaterverzeichnisses | |||
// root: (Optional) Kennung vor dem ersten Trenner am Anfang eines absoluten Pfads | |||
// home: (Optional) Kennung vor dem ersten Trenner am Anfang eines Pfads relativ zu Home | |||
// scheme: (Optional) Trennzeichen fuer den Schema-/Protokollnamen vorne | |||
// host: (Optional) Prefix fuer Hostnamen hinter dem Scheme-Trenner | |||
// port: (Optional) Trennzeichen vor der Portangabe, falls vorhanden | |||
// query: (Optional) Trennzeichen fuer die Query-Parameter hinter dem Pfad | |||
// parSep: (Optional) Trennzeichen zwischen je zwei Parametern | |||
// parAss: (Optional) Trennzwischen zwischen Key und Value | |||
// node: (Optional) Trennzeichen fuer den Knotennamen hinten (Fragment, Kapitel) | |||
function UriDelims(delim, back, root, home, scheme, host, port, query, qrySep, qryAss, node) { | |||
'use strict'; | |||
if ((typeof delim) === 'object') { | |||
// Erster Parameter ist Objekt mit den Properties... | |||
if (scheme === undefined) { | |||
scheme = delim.scheme; | |||
} | |||
if (host === undefined) { | |||
host = delim.host; | |||
} | |||
if (port === undefined) { | |||
port = delim.port; | |||
} | |||
if (query === undefined) { | |||
query = delim.query; | |||
} | |||
if (qrySep === undefined) { | |||
qrySep = delim.qrySep; | |||
} | |||
if (qryAss === undefined) { | |||
qryAss = delim.qryAss; | |||
} | |||
if (node === undefined) { | |||
node = delim.node; | |||
} | |||
} | |||
Delims.call(this, delim, back, root, home); | |||
this.setScheme(scheme); | |||
this.setHost(host); | |||
this.setPort(port); | |||
this.setQuery(query); | |||
this.setQrySep(qrySep); | |||
this.setQryAss(qryAss); | |||
this.setNode(node); | |||
} | } | ||
Class.define(UriDelims, Delims, { | |||
'setScheme' : function(scheme = undefined) { | |||
this.scheme = scheme; | |||
function | }, | ||
'setHost' : function(host = undefined) { | |||
this.host = host; | |||
}, | |||
'setPort' : function(port = undefined) { | |||
this.port = port; | |||
}, | |||
'setQuery' : function(query = undefined) { | |||
this.query = query; | |||
}, | |||
'setQrySep' : function(qrySep = undefined) { | |||
this.qrySep = qrySep; | |||
}, | |||
'setQryAss' : function(qryAss = undefined) { | |||
this.qryAss = qryAss; | |||
}, | |||
'setNode' : function(node = undefined) { | |||
this.node = node; | |||
} | |||
} ); | |||
// ==================== Ende Abschnitt fuer Klasse UriDelims ==================== | |||
// ==================== Abschnitt fuer Klasse Path ==================== | |||
// Basisklasse fuer die Verwaltung eines Pfades | |||
// homePath: Absoluter Startpfad als String | |||
// delims: Objekt mit Trennern und Symbolen als Properties (oder Delims-Objekt) | |||
// 'delim': Trennzeichen zwischen zwei Ebenen | |||
// 'back': Name des relativen Vaterverzeichnisses | |||
// 'root': Kennung vor dem ersten Trenner am Anfang eines absoluten Pfads | |||
// 'home': Kennung vor dem ersten Trenner am Anfang eines Pfads relativ zu Home | |||
function Path(homePath, delims) { | |||
'use strict'; | |||
this.dirs = []; | |||
this.setDelims(delims); | |||
this.homeDirs = this.getDirs(homePath, { 'home' : "" }); | |||
this.home(); | |||
} | |||
Class.define(Path, Object, { | |||
'root' : function() { | |||
this.dirs.splice(0, this.dirs.length); | |||
}, | |||
'home' : function() { | |||
this.dirs = this.homeDirs.slice(); | |||
}, | |||
'up' : function() { | |||
this.dirs.pop(); | |||
}, | |||
'down' : function(subDir) { | |||
this.dirs.push(subDir); | |||
}, | |||
'setDelims' : function(delims = undefined) { | |||
this.setConst('delims', new Delims(delims)); | |||
}, | |||
'setDelim' : function(delim = undefined) { | |||
this.delims.setDelim(delim || '/'); | |||
}, | |||
'setBackDelim' : function(backDelim = undefined) { | |||
this.delims.setBack(backDelim || ".."); | |||
}, | |||
'setRootDelim' : function(rootDelim = undefined) { | |||
this.delims.setRoot(rootDelim || ""); | |||
}, | |||
'setHomeDelim' : function(homeDelim = undefined) { | |||
this.delims.setHome(homeDelim || '~'); | |||
}, | |||
'setSchemeDelim' : function(schemeDelim = undefined) { | |||
this.delims.setScheme(schemeDelim || ':'); | |||
}, | |||
'setHostDelim' : function(hostDelim = undefined) { | |||
this.delims.setHost(hostDelim || '//'); | |||
}, | |||
'setPortDelim' : function(portDelim = undefined) { | |||
this.delims.setHost(portDelim || ':'); | |||
}, | |||
'setQueryDelim' : function(queryDelim = undefined) { | |||
this.delims.setQuery(queryDelim || '?'); | |||
}, | |||
'setParSepDelim' : function(parSepDelim = undefined) { | |||
this.delims.setParSep(parSepDelim || '&'); | |||
}, | |||
'setParAssDelim' : function(parAssDelim = undefined) { | |||
this.delims.setParAss(parAssDelim || '='); | |||
}, | |||
'setNodeDelim' : function(nodeDelim = undefined) { | |||
this.delims.setNode(nodeDelim || '#'); | |||
}, | |||
'getLeaf' : function(dirs = undefined) { | |||
const __DIRS = (dirs || this.dirs); | |||
return ((__DIRS && __DIRS.length) ? __DIRS.slice(-1)[0] : ""); | |||
}, | |||
'getPath' : function(dirs = undefined, delims = undefined) { | |||
const __DELIMS = new Delims(delims); | |||
const __DELIM = (__DELIMS.delim || this.delims.delim); | |||
const __ROOTDELIM = ((__DELIMS.root !== undefined) ? __DELIMS.root : this.delims.root); | |||
const __DIRS = (dirs || this.dirs); | |||
return __ROOTDELIM + __DELIM + __DIRS.join(__DELIM); | |||
}, | |||
'getDirs' : function(path = undefined, delims = undefined) { | |||
const __DELIMS = new Delims(delims); | |||
const __DELIM = (__DELIMS.delim || this.delims.delim); | |||
const __ROOTDELIM = ((__DELIMS.root !== undefined) ? __DELIMS.root : this.delims.root); | |||
const __HOMEDELIM = ((__DELIMS.home !== undefined) ? __DELIMS.home : this.delims.home); | |||
const __DIRS = (path ? path.split(__DELIM) : []); | |||
const __FIRST = __DIRS[0]; | |||
if (__FIRST && (__FIRST !== __ROOTDELIM) && (__FIRST !== __HOMEDELIM)) { | |||
showAlert("Kein absoluter Pfad", this.getPath(__DIRS), this); | |||
} | |||
return __DIRS.slice(1); | |||
} | |||
} ); | |||
// ==================== Ende Abschnitt fuer Klasse Path ==================== | |||
// ==================== Abschnitt fuer Klasse URI ==================== | |||
// | // Basisklasse fuer die Verwaltung einer URI/URL | ||
// | // homePath: Absoluter Startpfad als String | ||
// | // delims: Objekt mit Trennern und Symbolen als Properties (oder Delims-Objekt) | ||
// | // 'delim': Trennzeichen zwischen zwei Ebenen | ||
function | // 'back': Name des relativen Vaterverzeichnisses | ||
// 'root': Kennung vor dem ersten Trenner am Anfang eines absoluten Pfads | |||
// 'home': Kennung vor dem ersten Trenner am Anfang eines Pfads relativ zu Home | |||
function URI(homePath, delims) { | |||
'use strict'; | |||
Path.call(this); | |||
const __HOSTPORT = this.getHostPort(homePath); | |||
this.scheme = this.getSchemePrefix(homePath); | |||
this.host = __HOSTPORT.host; | |||
this.port = this.parseValue(__HOSTPORT.port); | |||
this.query = this.parseQuery(this.getQueryString(homePath)); | |||
this.node = this.getNodeSuffix(homePath); | |||
this.homeDirs = this.getDirs(homePath, { 'home' : "" }); | |||
this.home(); | |||
} | } | ||
// | Class.define(URI, Path, { | ||
'setDelims' : function() { | |||
this.setConst('delims', new UriDelims('/', "..", "", '~', ':', "//", ':', '?', '&', '=', '#')); | |||
}, | |||
function | 'setSchemeDelim' : function(schemeDelim = undefined) { | ||
return ( | this.delims.setScheme(schemeDelim || ':'); | ||
} | }, | ||
'setQueryDelim' : function(queryDelim = undefined) { | |||
this.delims.setQuery(queryDelim || '?'); | |||
}, | |||
'setParSepDelim' : function(parSepDelim = undefined) { | |||
this.delims.setParSep(parSepDelim || '&'); | |||
}, | |||
'setParAssDelim' : function(parAssDelim = undefined) { | |||
this.delims.setParAss(parAssDelim || '='); | |||
}, | |||
'setNodeDelim' : function(nodeDelim = undefined) { | |||
this.delims.setNode(nodeDelim || '#'); | |||
}, | |||
'getServerPath' : function(path = undefined) { | |||
return this.stripHostPort(this.stripQueryString(this.stripNodeSuffix(this.stripSchemePrefix(path)))); | |||
}, | |||
'getHostPort' : function(path = undefined) { | |||
const __HOSTDELIM = this.delims.host; | |||
const __PORTDELIM = this.delims.port; | |||
const __ROOTDELIM = this.delims.root + this.delims.delim; | |||
const __NOSCHEME = this.stripSchemePrefix(path); | |||
const __INDEXHOST = (__NOSCHEME ? __NOSCHEME.indexOf(__HOSTDELIM) : -1); | |||
const __PATH = (~ __INDEXHOST) ? __NOSCHEME.substring(__INDEXHOST + __HOSTDELIM.length) : __NOSCHEME; | |||
const __INDEXHOSTPORT = (__PATH ? __PATH.indexOf(__ROOTDELIM) : -1); | |||
const __HOSTPORT = (~ __INDEXHOSTPORT) ? __PATH.substring(0, __INDEXHOSTPORT) : undefined; | |||
const __INDEXPORT = (__HOSTPORT ? __HOSTPORT.indexOf(__PORTDELIM) : -1); | |||
const __HOST = (~ __INDEXPORT) ? __HOSTPORT.substring(0, __INDEXPORT) : __HOSTPORT; | |||
const __PORT = (~ __INDEXPORT) ? __HOSTPORT.substring(__INDEXPORT + __PORTDELIM.length) : undefined; | |||
return { | |||
'host' : __HOST, | |||
'port' : __PORT | |||
}; | |||
}, | |||
'stripHostPort' : function(path = undefined) { | |||
const __HOSTDELIM = this.delims.host; | |||
const __ROOTDELIM = this.delims.root + this.delims.delim; | |||
const __INDEXHOST = (path ? path.indexOf(__HOSTDELIM) : -1); | |||
const __PATH = (~ __INDEXHOST) ? path.substring(__INDEXHOST + __HOSTDELIM.length) : path; | |||
const __INDEXHOSTPORT = (__PATH ? __PATH.indexOf(__ROOTDELIM) : -1); | |||
return (~ __INDEXHOSTPORT) ? __PATH.substring(__INDEXHOSTPORT) : __PATH; | |||
}, | |||
'getSchemePrefix' : function(path = undefined) { | |||
const __SCHEMEDELIM = this.delims.scheme; | |||
const __INDEXSCHEME = (path ? path.indexOf(__SCHEMEDELIM) : -1); | |||
return (~ __INDEXSCHEME) ? path.substring(0, __INDEXSCHEME) : undefined; | |||
}, | |||
'stripSchemePrefix' : function(path = undefined) { | |||
const __SCHEMEDELIM = this.delims.scheme; | |||
const __INDEXSCHEME = (path ? path.indexOf(__SCHEMEDELIM) : -1); | |||
return (~ __INDEXSCHEME) ? path.substring(__INDEXSCHEME + __INDEXSCHEME.length) : path; | |||
}, | |||
'getNodeSuffix' : function(path = undefined) { | |||
const __NODEDELIM = this.delims.node; | |||
function | const __INDEXNODE = (path ? path.lastIndexOf(__NODEDELIM) : -1); | ||
return (~ __INDEXNODE) ? path.substring(__INDEXNODE + __NODEDELIM.length) : undefined; | |||
}, | |||
'stripNodeSuffix' : function(path = undefined) { | |||
const __NODEDELIM = this.delims.node; | |||
const __INDEXNODE = (path ? path.lastIndexOf(__NODEDELIM) : -1); | |||
return (~ __INDEXNODE) ? path.substring(0, __INDEXNODE) : path; | |||
}, | |||
'getQueryString' : function(path = undefined) { | |||
const __QUERYDELIM = this.delims.query; | |||
const __PATH = this.stripNodeSuffix(path); | |||
const __INDEXQUERY = (__PATH ? __PATH.indexOf(__QUERYDELIM) : -1); | |||
return (~ __INDEXQUERY) ? __PATH.substring(__INDEXQUERY + __QUERYDELIM.length) : undefined; | |||
}, | |||
'stripQueryString' : function(path = undefined) { | |||
const __QUERYDELIM = this.delims.query; | |||
const __INDEXQUERY = (path ? path.indexOf(__QUERYDELIM) : -1); | |||
function | |||
return (~ __INDEXQUERY) ? path.substring(0, __INDEXQUERY) : path; | |||
}, | |||
'formatParams' : function(params, formatFun, delim = ' ', assign = '=') { | |||
const __PARAMS = []; | |||
for (let param in params) { | |||
__PARAMS.push(param + assign + formatFun(params[param])); | |||
} | |||
} | |||
return __PARAMS.join(delim); | |||
}, | |||
'parseParams' : function(params, parseFun, delim = ' ', assign = '=') { | |||
const __RET = { }; | |||
if (params) { | |||
function | const __PARAMS = params.split(delim); | ||
for (let index = 0; index < __PARAMS.length; index++) { | |||
const __PARAM = __PARAMS[index]; | |||
if (__PARAM) { | |||
const __INDEX = __PARAM.indexOf(assign); | |||
const __KEY = (~ __INDEX) ? __PARAM.substring(0, __INDEX) : __PARAM; | |||
const __VAL = (~ __INDEX) ? parseFun(__PARAM.substring(__INDEX + assign.length)) : true; | |||
__RET[__KEY] = __VAL; | |||
} | |||
} | |||
} | |||
return __RET; | |||
}, | |||
'rawValue' : function(value) { | |||
return value; | |||
}, | |||
'parseValue' : function(value) { | |||
const __VALUE = Number(value); | |||
if (__VALUE == value) { // schwacher Vergleich true, also Number | |||
return __VALUE; | |||
} else { | |||
const __LOWER = (value ? value.toLowerCase() : undefined); | |||
if ((__LOWER === "true") || (__LOWER === "false")) { | |||
return (value === "true"); | |||
} | |||
} | |||
return value; | |||
}, | |||
'getQuery' : function(delims = { }) { | |||
const __QRYSEP = ((delims.qrySep !== undefined) ? delims.qrySep : this.delims.qrySep); | |||
const __QRYASS = ((delims.qryAss !== undefined) ? delims.qryAss : this.delims.qryAss); | |||
return this.formatParams(this.query, this.rawValue, __QRYSEP, __QRYASS); | |||
}, | |||
'parseQuery' : function(path = undefined, delims = { }) { | |||
const __QRYSEP = ((delims.qrySep !== undefined) ? delims.qrySep : this.delims.qrySep); | |||
const __QRYASS = ((delims.qryAss !== undefined) ? delims.qryAss : this.delims.qryAss); | |||
return this.parseParams(path, this.parseValue, __QRYSEP, __QRYASS); | |||
}, | |||
'setQuery' : function(query) { | |||
this.query = query; | |||
}, | |||
'setQueryPar' : function(key, value) { | |||
this.query[key] = value; | |||
}, | |||
'getQueryPar' : function(key) { | |||
return this.query[key]; | |||
}, | |||
'getPath' : function(dirs = undefined, delims = undefined) { | |||
const __DELIMS = new UriDelims(delims); | |||
const __SCHEMEDELIM = ((__DELIMS.scheme !== undefined) ? __DELIMS.scheme : this.delims.scheme); | |||
const __HOSTDELIM = ((__DELIMS.host !== undefined) ? __DELIMS.host : this.delims.host); | |||
const __PORTDELIM = ((__DELIMS.port !== undefined) ? __DELIMS.port : this.delims.port); | |||
const __QUERYDELIM = ((__DELIMS.query !== undefined) ? __DELIMS.query : this.delims.query); | |||
const __NODEDELIM = ((__DELIMS.node !== undefined) ? __DELIMS.node : this.delims.node); | |||
const __SCHEMENAME = this.scheme; | |||
const __SCHEME = (__SCHEMENAME ? __SCHEMENAME + __SCHEMEDELIM : ""); | |||
const __HOSTNAME = this.host; | |||
const __HOST = (__HOSTNAME ? __HOSTDELIM + __HOSTNAME : ""); | |||
const __PORTNR = this.port; | |||
const __PORT = ((__HOSTNAME && __PORTNR) ? __PORTDELIM + __PORTNR : ""); | |||
const __QUERYSTR = this.getQuery(); | |||
const __QUERY = (__QUERYSTR ? __QUERYDELIM + __QUERYSTR : ""); | |||
const __NODENAME = this.node; | |||
const __NODE = (__NODENAME ? __NODEDELIM + __NODENAME : ""); | |||
return __SCHEME + __HOST + __PORT + Path.prototype.getPath.call(this, dirs, delims) + __QUERY + __NODE; | |||
}, | |||
'getDirs' : function(path = undefined, delims = undefined) { | |||
const __PATH = this.getServerPath(path); | |||
return Path.prototype.getDirs.call(this, __PATH); | |||
} | |||
} ); | |||
// ==================== Ende Abschnitt fuer Klasse URI ==================== | |||
// ==================== Abschnitt fuer Klasse Directory ==================== | |||
// Basisklasse fuer eine Verzeichnisstruktur | |||
// homePath: Absoluter Startpfad als String | |||
// delims: Objekt mit Trennern und Symbolen als Properties (oder Delims-Objekt) | |||
// 'delim': Trennzeichen zwischen zwei Ebenen | |||
// 'back': Name des relativen Vaterverzeichnisses | |||
// 'root': Kennung vor dem ersten Trenner am Anfang eines absoluten Pfads | |||
// 'home': Kennung vor dem ersten Trenner am Anfang eines Pfads relativ zu Home | |||
function Directory(homePath, delims) { | |||
'use strict'; | |||
Path.call(this, homePath, delims); | |||
} | } | ||
// ==================== Ende Abschnitt fuer | Class.define(Directory, Path, { | ||
'chDir' : function(subDir = undefined) { | |||
if (subDir === undefined) { | |||
this.root(); | |||
} else if ((typeof subDir) === 'object') { | |||
for (let sub of subDir) { | |||
this.chDir(sub); | |||
} | |||
} else { | |||
if (subDir === this.delims.home) { | |||
this.home(); | |||
} else if (subDir === this.delims.back) { | |||
this.up(); | |||
} else { | |||
this.down(subDir); | |||
} | |||
} | |||
}, | |||
'pwd' : function() { | |||
return this.getPath(); | |||
} | |||
} ); | |||
// ==================== Ende Abschnitt fuer Klasse Directory ==================== | |||
// ==================== Abschnitt fuer Klasse ObjRef ==================== | |||
// | // Basisklasse fuer eine Objekt-Referenz | ||
function ObjRef(rootObj) { | |||
'use strict'; | |||
function | |||
Directory.call(this, undefined, new Delims('/', "..", '/', '~')); | |||
this.setConst('rootObj', rootObj); // Wichtig: Verweis nicht verfolgen! Gefahr durch Zyklen! | |||
} | |||
Class.define(ObjRef, Directory, { | |||
'valueOf' : function() { | |||
let ret = this.rootObj; | |||
for (let name of this.dirs) { | |||
if (ret === undefined) { | |||
break; | |||
} | |||
ret = ret[name]; | |||
} | |||
return ret; | |||
} | } | ||
} ); | |||
// | // ==================== Ende Abschnitt fuer Klasse ObjRef ==================== | ||
// ==================== Abschnitt fuer diverse Utilities ==================== | |||
// Gibt einen Wert zurueck. Ist dieser nicht definiert oder null, wird ein Alternativwert geliefert | |||
// value: Ein Wert. Ist dieser nicht undefined oder null, wird er zurueckgeliefert (oder retValue) | |||
// defValue: Default-Wert fuer den Fall, dass nichts gesetzt ist | |||
// retValue: Falls definiert, Rueckgabe-Wert fuer den Fall, dass value nicht undefined oder null ist | |||
// return Der Wert. Sind weder value noch defValue definiert, dann undefined | |||
function getValue(value, defValue = undefined, retValue = undefined) { | |||
return ((value === undefined) || (value === null)) ? defValue : (retValue === undefined) ? value : retValue; | |||
} | } | ||
// | // Gibt einen Wert zurueck. Ist dieser nicht definiert, wird ein Alternativwert geliefert | ||
// | // value: Ein Wert. Ist dieser definiet und in den Grenzen, wird er zurueckgeliefert | ||
// | // minValue: Untere Grenze fuer den Wert, falls angegeben | ||
// return | // minValue: Obere Grenze fuer den Wert, falls angegeben | ||
function | // defValue: Default-Wert fuer den Fall, dass nichts gesetzt ist oder der Wert ausserhalb liegt | ||
// return Der Wert. Sind weder value (in den Grenzen) noch defValue definiert, dann undefined | |||
function getValueIn(value, minValue = undefined, maxValue = undefined, defValue = undefined) { | |||
const __VALUE = getValue(value, defValue); | |||
if ( | if ((minValue !== undefined) && (__VALUE < minValue)) { | ||
return defValue; | |||
} | |||
if ((maxValue !== undefined) && (__VALUE > maxValue)) { | |||
return defValue; | |||
} | } | ||
return __VALUE; | |||
} | |||
// Ermittelt den naechsten Wert aus einer Array-Liste | |||
// arr: Array-Liste mit den moeglichen Werte | |||
// value: Vorher gesetzter Wert | |||
// return Naechster Wert in der Array-Liste | |||
function getNextValue(arr, value) { | |||
const __POS = arr.indexOf(value) + 1; | |||
return arr[getValueIn(__POS, 0, arr.length - 1, 0)]; | |||
} | |||
// Gibt ein Produkt zurueck. Ist einer der Multiplikanten nicht definiert, wird ein Alternativwert geliefert | |||
// valueA: Ein Multipliksnt. Ist dieser undefined, wird als Produkt defValue zurueckgeliefert | |||
// valueB: Ein Multipliksnt. Ist dieser undefined, wird als Produkt defValue zurueckgeliefert | |||
// digits: Anzahl der Stellen nach dem Komma fuer das Produkt (Default: 0) | |||
// defValue: Default-Wert fuer den Fall, dass ein Multiplikant nicht gesetzt ist (Default: NaN) | |||
// return Das Produkt auf digits Stellen genau. Ist dieses nicht definiert, dann defValue | |||
function getMulValue(valueA, valueB, digits = 0, defValue = NaN) { | |||
let product = defValue; | |||
if ((valueA !== undefined) && (valueB !== undefined)) { | |||
product = parseFloat(valueA) * parseFloat(valueB); | |||
} | } | ||
return | return parseFloat(product.toFixed(digits)); | ||
} | } | ||
// | // Ueberprueft, ob ein Objekt einer bestimmten Klasse angehoert (ggfs. per Vererbung) | ||
// | // obj: Ein (generisches) Objekt | ||
// | // base: Eine Objektklasse (Konstruktor-Funktion) | ||
// return | // return true, wenn der Prototyp rekursiv gefunden werden konnte | ||
function | function instanceOf(obj, base) { | ||
while (obj !== null) { | |||
if (obj === base.prototype) | |||
return true; | |||
if ((typeof obj) === 'xml') { // Sonderfall mit Selbstbezug | |||
return (base.prototype === XML.prototype); | |||
} | |||
obj = Object.getPrototypeOf(obj); | |||
} | |||
return false; | |||
} | |||
// Liefert alle Basisklassen des Objekts (inkl. Vererbung) | |||
// obj: Ein (generisches) Objekt | |||
// return true, wenn der Prototyp rekursiv gefunden werden konnte | |||
function getPrototypes(obj) { | |||
let ret = []; | |||
while (obj !== null) { | |||
const __PROTO = Object.getPrototypeOf(obj); | |||
const | |||
if ( | ret.push(__PROTO); | ||
if ((typeof obj) === 'xml') { // Sonderfall mit Selbstbezug | |||
break; | |||
} | } | ||
obj = __PROTO; | |||
} | } | ||
return | return ret; | ||
} | } | ||
// | // Liefert alle Attribute/Properties des Objekts (inkl. Vererbung) | ||
/ | // obj: Ein (generisches) Objekt | ||
// return Array von Items (Property-Namen) | |||
function getAllProperties(obj) { | |||
let ret = []; | |||
// | |||
// | for (let o = obj; o !== null; o = Object.getPrototypeOf(o)) { | ||
ret = ret.concat(Object.getOwnPropertyNames(o)); | |||
function | |||
} | } | ||
if ( | return ret; | ||
} | |||
// Ueberpruefung, ob ein Item aktiv ist oder nicht | |||
// item: Name des betroffenen Items | |||
// inList: Checkliste der inkludierten Items (Positivliste, true fuer aktiv) | |||
// exList: Checkliste der exkludierten Items (Negativliste, true fuer inaktiv) | |||
// return Angabe, ob das Item aktiv ist | |||
function checkItem(item, inList = undefined, exList = undefined) { | |||
let active = true; | |||
if (inList !== undefined) { | |||
active = (inList[item] === true); // gesetzt und true | |||
} | |||
if (exList !== undefined) { | |||
if (exList[item] === true) { // gesetzt und true | |||
active = false; // NICHT anzeigen | |||
} | |||
} | } | ||
return active; | |||
return | |||
} | } | ||
// | // Fuegt Properties zu einem Objekt hinzu, die in einem zweiten stehen. Doppelte Werte werden ueberschrieben | ||
// | // data: Objekt, dem Daten hinzugefuegt werden | ||
// | // addData: Objekt, das zusaetzliche Properties enthaelt | ||
// return | // addList: Checkliste der zu setzenden Items (true fuer kopieren), falls angegeben | ||
function | // ignList: Checkliste der ignorierten Items (true fuer auslassen), falls angegeben | ||
// return Das gemergete Objekt mit allen Properties | |||
function addProps(data, addData, addList = undefined, ignList = undefined) { | |||
for (let item in getValue(addData, { })) { | |||
if (checkItem(item, addList, ignList)) { | |||
data[item] = addData[item]; | |||
} | |||
} | |||
return data; | |||
} | |||
// Gibt den Wert einer Property zurueck. Ist dieser nicht definiert oder null, wird er vorher gesetzt | |||
// obj: Ein Objekt. Ist dieses undefined oder null, wird defValue zurueckgeliefert | |||
// item: Key des Properties | |||
// defValue: Default-Wert fuer den Fall, dass nichts gesetzt ist | |||
// return Der Wert des Properties. Sind das obj oder das Property und defValue undefined oder null, dann undefined | |||
function getProp(obj, item, defValue = undefined) { | |||
if ((obj === undefined) || (obj === null)) { | |||
return defValue; | |||
} | } | ||
const __PROP = obj[item]; | |||
if ((__PROP !== undefined) && (__PROP !== null)) { | |||
return __PROP; | |||
} | |||
return | return (obj[item] = defValue); | ||
} | } | ||
// | // Sicheres obj.valueOf() fuer alle Daten | ||
// data: Objekt oder Wert | |||
// return Bei Objekten valueOf() oder das Objekt selber, bei Werten der Wert | |||
// | function valueOf(data) { | ||
// | return (((typeof data) === 'object') ? data.valueOf() : data); | ||
} | |||
function | |||
return | // Sicheres JSON.stringify(), das auch mit Zyklen umgehen kann | ||
// value: Auszugebene Daten. Siehe JSON.stringify() | |||
// replacer: Elementersetzer. Siehe JSON.stringify() | |||
// space: Verschoenerung. Siehe JSON.stringify() | |||
// cycleReplacer: Ersetzer im Falle von Zyklen | |||
// return String mit Ausgabe der Objektdaten | |||
function safeStringify(value, replacer = undefined, space = undefined, cycleReplacer = undefined) { | |||
return JSON.stringify(value, serializer(replacer, cycleReplacer), space); | |||
} | } | ||
// | // Hilfsfunktion fuer safeStringify(): Kapselt replacer und einen cycleReplacer fuer Zyklen | ||
// replacer: Elementersetzer. Siehe JSON.stringify() | |||
// | // cycleReplacer: Ersetzer im Falle von Zyklen | ||
// | // return Ersetzer-Funktion fuer JSON.stringify(), die beide Ersetzer vereint | ||
// | function serializer(replacer = undefined, cycleReplacer = undefined) { | ||
const __STACK = []; | |||
function | const __KEYS = []; | ||
const | |||
if (! cycleReplacer) { | |||
cycleReplacer = function(key, value) { | |||
if (__STACK[0] === value) { | |||
return "[~]"; | |||
} | |||
return "[~." + __KEYS.slice(0, __STACK.indexOf(value)).join('.') + ']'; | |||
}; | |||
} | |||
return function(key, value) { | |||
if (__STACK.length) { | |||
const __THISPOS = __STACK.indexOf(this); | |||
if (~ __THISPOS) { | |||
__STACK.splice(__THISPOS + 1); | |||
__KEYS.splice(__THISPOS, Infinity, key); | |||
} else { | |||
__STACK.push(this); | |||
__KEYS.push(key); | |||
} | |||
if (~ __STACK.indexOf(value)) { | |||
value = cycleReplacer.call(this, key, value); | |||
} | |||
} else { | |||
__STACK.push(value); | |||
} | |||
return ((! replacer) ? value : replacer.call(this, key, value)); | |||
}; | |||
} | } | ||
// | // Speichert einen beliebiegen (strukturierten) Wert unter einem Namen ab | ||
// | // name: GM_setValue-Name, unter dem die Daten gespeichert werden | ||
// | // value: Beliebiger (strukturierter) Wert | ||
// return String-Darstellung des Wertes | |||
function serialize(name, value) { | |||
const __STREAM = (value !== undefined) ? safeStringify(value) : value; | |||
// return | |||
function | |||
const | |||
__LOG[4](name + " >> " + __STREAM); | |||
GM_setValue(name, __STREAM); | |||
return __STREAM; | |||
} | } | ||
// | // Holt einen beliebiegen (strukturierter) Wert unter einem Namen zurueck | ||
// | // name: GM_setValue-Name, unter dem die Daten gespeichert werden | ||
// | // defValue: Default-Wert fuer den Fall, dass nichts gespeichert ist | ||
// return | // return Objekt, das unter dem Namen gespeichert war | ||
function | function deserialize(name, defValue = undefined) { | ||
const | const __STREAM = GM_getValue(name, defValue); | ||
__LOG[4](name + " << " + __STREAM); | |||
if ((__STREAM !== undefined) && __STREAM.length) { | |||
try { | |||
return JSON.parse(__STREAM); | |||
} catch (ex) { | |||
__LOG[1](name + ": " + ex.message); | |||
} | |||
} | } | ||
return | return undefined; | ||
} | } | ||
// | // Setzt eine Option dauerhaft und laedt die Seite neu | ||
// | // name: Name der Option als Speicherort | ||
// | // value: Zu setzender Wert | ||
// | // reload: Seite mit neuem Wert neu laden | ||
function | // return Gespeicherter Wert fuer setOptValue() | ||
function setStored(name, value, reload = false, serial = false) { | |||
if (serial) { | |||
serialize(name, value); | |||
} else { | |||
GM_setValue(name, value); | |||
} | |||
if ( | if (reload) { | ||
window.location.reload(); | |||
} | |||
return value; | |||
} | } | ||
// | // Setzt den naechsten Wert aus einer Array-Liste als Option | ||
// | // arr: Array-Liste mit den moeglichen Optionen | ||
// | // name: Name der Option als Speicherort | ||
// | // value: Vorher gesetzter Wert | ||
function | // reload: Seite mit neuem Wert neu laden | ||
// return Gespeicherter Wert fuer setOptValue() | |||
function setNextStored(arr, name, value, reload = false, serial = false) { | |||
return setStored(name, getNextValue(arr, value), reload, serial); | |||
} | } | ||
// | // Fuehrt die in einem Storage gespeicherte Operation aus | ||
// | // memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv | ||
// return Array von Objekten mit 'cmd' / 'key' / 'val' (derzeit maximal ein Kommando) oder undefined | |||
// | function getStoredCmds(memory = undefined) { | ||
const __STORAGE = getMemory(memory); | |||
// | const __MEMORY = __STORAGE.Value; | ||
function | const __RUNPREFIX = __STORAGE.Prefix; | ||
const __STOREDCMDS = []; | |||
if (__MEMORY !== undefined) { | |||
const __GETITEM = function(item) { | |||
return __MEMORY.getItem(__RUNPREFIX + item); | |||
}; | |||
const __DELITEM = function(item) { | |||
return __MEMORY.removeItem(__RUNPREFIX + item); | |||
}; | |||
const __CMD = ((__MEMORY !== undefined) ? __GETITEM('cmd') : undefined); | |||
if (__CMD !== undefined) { | |||
const __KEY = __GETITEM('key'); | |||
let value = __GETITEM('val'); | |||
try { | |||
value = JSON.parse(value); | |||
} catch (ex) { | |||
__LOG[1]("getStoredCmds(): " + __CMD + " '" + __KEY + "' hat illegalen Wert '" + value + "'"); | |||
// ... meist kann man den String selber aber speichern, daher kein "return"... | |||
} | |||
__STOREDCMDS.push({ | |||
'cmd' : __CMD, | |||
'key' : __KEY, | |||
'val' : value | |||
}); | |||
} | } | ||
__DELITEM('cmd'); | |||
__DELITEM('key'); | |||
__DELITEM('val'); | |||
} | } | ||
return | return (__STOREDCMDS.length ? __STOREDCMDS : undefined); | ||
} | } | ||
// | // Fuehrt die in einem Storage gespeicherte Operation aus | ||
// optSet: | // storedCmds: Array von Objekten mit 'cmd' / 'key' / 'val' (siehe getStoredCmds()) | ||
// | // optSet: Set mit den Optionen | ||
// beforeLoad: Angabe, ob nach der Speicherung noch loadOptions() aufgerufen wird | |||
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv | |||
// return Array von Operationen (wie storedCmds), die fuer die naechste Phase uebrig bleiben | |||
function runStoredCmds(storedCmds, optSet = undefined, beforeLoad = undefined) { | |||
const __BEFORELOAD = getValue(beforeLoad, true); | |||
const __STOREDCMDS = getValue(storedCmds, []); | |||
const __LOADEDCMDS = []; | |||
let invalidated = false; | |||
while (__STOREDCMDS.length) { | |||
const __STORED = __STOREDCMDS.shift(); | |||
const __CMD = __STORED.cmd; | |||
const __KEY = __STORED.key; | |||
const __VAL = __STORED.val; | |||
// | if (__BEFORELOAD) { | ||
if (__STOREDCMDS.length) { | |||
invalidateOpts(optSet); // alle Optionen invalidieren | |||
// | invalidated = true; | ||
} | |||
switch (__OPTACTION[__CMD]) { | |||
case __OPTACTION.SET : __LOG[4]("SET '" + __KEY + "' " + __VAL); | |||
setStored(__KEY, __VAL, false, false); | |||
break; | |||
case __OPTACTION.NXT : __LOG[4]("SETNEXT '" + __KEY + "' " + __VAL); | |||
//setNextStored(__CONFIG.Choice, __KEY, __VAL, false, false); | |||
setStored(__KEY, __VAL, false, false); | |||
break; | |||
case __OPTACTION.RST : __LOG[4]("RESET (delayed)"); | |||
__LOADEDCMDS.push(__STORED); | |||
break; | |||
default : break; | |||
} | |||
} else { | |||
switch (__OPTACTION[__CMD]) { | |||
case __OPTACTION.SET : | |||
case __OPTACTION.NXT : __LOG[2]("SET/SETNEXT (undefined)"); | |||
break; | |||
case __OPTACTION.RST : __LOG[4]("RESET"); | |||
resetOptions(optSet, false); | |||
loadOptions(optSet); // Reset auf umbenannte Optionen anwenden! | |||
break; | |||
default : break; | |||
} | |||
} | |||
} | |||
return (__LOADEDCMDS.length ? __LOADEDCMDS : undefined); | |||
} | |||
// Gibt eine Option sicher zurueck | |||
// opt: Config und Value der Option, ggfs. undefined | |||
// defOpt: Rueckgabewert, falls undefined | |||
// return Daten zur Option (oder defOpt) | |||
function getOpt(opt, defOpt = { }) { | |||
return getValue(opt, defOpt); | |||
} | |||
// Gibt eine Option sicher zurueck (Version mit Key) | |||
// optSet: Platz fuer die gesetzten Optionen (und Config) | |||
// item: Key der Option | |||
// defOpt: Rueckgabewert, falls nicht zu finden | |||
// return Daten zur Option (oder defOpt) | |||
function getOptByName(optSet, item, defOpt = { }) { | |||
if ((optSet !== undefined) && (item !== undefined)) { | |||
return getOpt(optSet[item], defOpt); | |||
} else { | } else { | ||
return defOpt; | |||
} | } | ||
} | |||
// | // Gibt die Konfigurationsdaten einer Option zurueck | ||
const | // opt: Config und Value der Option | ||
const | // defConfig: Rueckgabewert, falls Config nicht zu finden | ||
// return Konfigurationsdaten der Option | |||
function getOptConfig(opt, defConfig = { }) { | |||
return getValue(getOpt(opt).Config, defConfig); | |||
} | |||
// Setzt den Namen einer Option | |||
// opt: Config und Value der Option | |||
// name: Zu setzender Name der Option | |||
// reload: Seite mit neuem Wert neu laden | |||
// return Gesetzter Name der Option | |||
function setOptName(opt, name) { | |||
const __CONFIG = getOptConfig(opt); | |||
const __NAME = getOptName(opt); | |||
if (__NAME !== name) { | |||
__LOG[4]("RENAME " + __NAME + " => " + name); | |||
__CONFIG.Name = name; | |||
} | |||
return | return name; | ||
} | } | ||
// ==== | // Gibt den Namen einer Option zurueck | ||
// opt: Config und Value der Option | |||
// return Name der Option | |||
function getOptName(opt) { | |||
const __CONFIG = getOptConfig(opt); | |||
const __NAME = __CONFIG.Name; | |||
if (! __NAME) { | |||
const __SHARED = __CONFIG.Shared; | |||
if (__SHARED && ! opt.Loaded) { | |||
const __OBJREF = getSharedRef(__SHARED, opt.Item); | |||
return __OBJREF.getPath(); | |||
} | } | ||
showAlert("Error", "Option ohne Namen", safeStringify(__CONFIG)); | |||
} | } | ||
return | return __NAME; | ||
} | } | ||
// | // Setzt den Wert einer Option | ||
// | // opt: Config und Value der Option | ||
// | // name: Zu setzender Wert der Option | ||
// return | // return Gesetzter Wert | ||
function | function setOptValue(opt, value) { | ||
if (opt !== undefined) { | |||
if (! opt.ReadOnly) { | |||
__LOG[6](getOptName(opt) + ": " + __LOG.changed(opt.Value, value)); | |||
opt.Value = value; | |||
} | |||
return opt.Value; | |||
} else { | |||
return undefined; | |||
} | |||
} | } | ||
// | // Gibt den Wert einer Option zurueck | ||
// | // opt: Config und Value der Option | ||
// | // defValue: Default-Wert fuer den Fall, dass nichts gesetzt ist | ||
// | // load: Laedt die Option per loadOption(), falls noetig | ||
// | // force: Laedt auch Optionen mit 'AutoReset'-Attribut | ||
// return | // return Gesetzter Wert | ||
function | function getOptValue(opt, defValue = undefined, load = true, force = false) { | ||
let value; | |||
if (opt !== undefined) { | |||
if (load && ! opt.Loaded) { | |||
value = loadOption(opt, force); | |||
} else { | |||
value = opt.Value; | |||
} | |||
} | } | ||
return valueOf(getValue(value, defValue)); | |||
} | } | ||
// | // ==================== Ende Abschnitt fuer diverse Utilities ==================== | ||
// | |||
// | // ==================== Abschnitt fuer Speicher und die Scriptdatenbank ==================== | ||
// | // Namen des Default-, Temporaer- und Null-Memories... | ||
// | const __MEMNORMAL = 'normal'; | ||
const __MEMSESSION = 'begrenzt'; | |||
const __MEMINAKTIVE = 'inaktiv'; | |||
// Definition des Default-, Dauer- und Null-Memories... | |||
const __OPTMEMNORMAL = __OPTMEM[__MEMNORMAL]; | |||
const __OPTMEMSESSION = __OPTMEM[__MEMSESSION]; | |||
const __OPTMEMINAKTIVE = __OPTMEM[__MEMINAKTIVE]; | |||
// Medium fuer die Datenbank (Speicher) | |||
let myOptMem = __OPTMEMNORMAL; | |||
let myOptMemSize; | |||
// Infos ueber dieses Script-Modul | |||
const __DBMOD = new ScriptModule(); | |||
// Inhaltsverzeichnis der DB-Daten (indiziert durch die Script-Namen) | |||
const __DBTOC = { }; | |||
// Daten zu den Modulen (indiziert durch die Script-Namen) | |||
const __DBDATA = { }; | |||
} | |||
// | // ==================== Abschnitt fuer Speicher ==================== | ||
// Ermittelt fuer die uebergebene Speicher-Konfiguration einen Speicher | |||
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv | |||
// defMemory: Ersatz-Wert, falls memory undefined. Soll nur memory genutzt werden, dann z.B. null uebergeben! | |||
// return memory, falls okay, sonst einen Defaultwert | |||
function getMemory(memory = undefined, defMemory = getValue(myOptMem, __OPTMEMNORMAL)) { | |||
return getValue(memory, defMemory); | |||
} | } | ||
// | // Kompatibilitaetsfunktion: Testet, ob der uebergebene Speicher genutzt werden kann | ||
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv | |||
// | // return true, wenn der Speichertest erfolgreich war | ||
function canUseMemory(memory = undefined) { | |||
const __STORAGE = getMemory(memory, { }); | |||
// return | const __MEMORY = __STORAGE.Value; | ||
function | let ret = false; | ||
const | |||
if (__MEMORY !== undefined) { | |||
const __TESTPREFIX = 'canUseStorageTest'; | |||
const __TESTDATA = Math.random().toString(); | |||
const __TESTITEM = __TESTPREFIX + __TESTDATA; | |||
__MEMORY.setItem(__TESTITEM, __TESTDATA); | |||
ret = (__MEMORY.getItem(__TESTITEM) === __TESTDATA); | |||
__MEMORY.removeItem(__TESTITEM); | |||
} | |||
__LOG[2]("canUseStorage(" + __STORAGE.Name + ") = " + ret); | |||
return | return ret; | ||
} | } | ||
// | // Ermittelt die Groesse des benutzten Speichers | ||
// | // memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv | ||
// return Groesse des genutzten Speichers in Bytes | |||
// | function getMemSize(memory = undefined) { | ||
function | const __STORAGE = getMemory(memory); | ||
const | const __MEMORY = __STORAGE.Value; | ||
const | |||
//getMemUsage(__MEMORY); | |||
if (__MEMORY !== undefined) { | |||
const __SIZE = safeStringify(__MEMORY).length; | |||
return | __LOG[2]("MEM: " + __SIZE + " bytes"); | ||
return __SIZE; | |||
} else { | |||
return 0; | |||
} | |||
} | } | ||
// | // Gibt rekursiv und detailliert die Groesse des benutzten Speichers fuer ein Objekt aus | ||
// | // value: (Enumerierbares) Objekt oder Wert, dessen Groesse gemessen wird | ||
// | // out: Logfunktion, etwa console.log | ||
function | // depth: Gewuenschte Rekursionstiefe (0 = nur dieses Objekt, -1 = alle Ebenen) | ||
// name: Name des Objekts | |||
const | function getMemUsage(value = undefined, out = undefined, depth = -1, name = '$') { | ||
const __OUT = (out || __LOG[4]); | |||
if ((typeof value) === 'string') { | |||
const __SIZE = value.length; | |||
__OUT("USAGE: " + name + '\t' + __SIZE + '\t' + value.substr(0, 255)); | |||
} else if ((typeof value) === 'object') { | |||
if (depth === 0) { | |||
const __SIZE = safeStringify(value).length; | |||
__OUT("USAGE: " + name + '\t' + __SIZE); | |||
} else { | |||
depth--; | |||
for (let sub in value) { | |||
getMemUsage(value[sub], __OUT, depth, name + '.' + sub); | |||
} | |||
getMemUsage(value, __OUT, 0, name); | |||
} | |||
} else { | |||
const __DATA = (((typeof value) === 'function') ? "" : '\t' + value); | |||
__OUT("USAGE: " + name + '\t' + (typeof value) + __DATA); | |||
} | |||
} | |||
// Restauriert den vorherigen Speicher (der in einer Option definiert ist) | |||
// opt: Option zur Wahl des Speichers | |||
// return Gesuchter Speicher oder Null-Speicher ('inaktiv') | |||
function restoreMemoryByOpt(opt) { | |||
// Memory Storage fuer vorherige Speicherung... | |||
const __STORAGE = getOptValue(opt, __MEMNORMAL, true, true); | |||
return __OPTMEM[__STORAGE]; | |||
} | |||
// Initialisiert den Speicher (der in einer Option definiert ist) und merkt sich diesen ggfs. | |||
// opt: Option zur Wahl des Speichers | |||
// saveOpt: Option zur Speicherung der Wahl des Speichers (fuer restoreMemoryByOpt) | |||
// return Gesuchter Speicher oder Null-Speicher ('inaktiv'), falls speichern nicht moeglich ist | |||
function startMemoryByOpt(opt, saveOpt = undefined) { | |||
// Memory Storage fuer naechste Speicherung... | |||
let storage = getOptValue(opt, __MEMNORMAL); | |||
let optMem = __OPTMEM[storage]; | |||
if (! canUseMemory(optMem)) { | |||
if (storage !== __MEMINAKTIVE) { | |||
storage = __MEMINAKTIVE; | |||
optMem = __OPTMEM[storage]; | |||
} | } | ||
} | } | ||
return | if (saveOpt !== undefined) { | ||
setOpt(saveOpt, storage, false); | |||
} | |||
return optMem; | |||
} | } | ||
// | // ==================== Ende Abschnitt fuer Speicher ==================== | ||
// | // ==================== Abschnitt fuer die Scriptdatenbank ==================== | ||
// | // Initialisiert das Script-Modul und ermittelt die beschreibenden Daten | ||
// | // meta: Metadaten des Scripts (Default: GM_info.script) | ||
// return Beschreibende Daten fuer __DBMOD | |||
// return | function ScriptModule(meta) { | ||
function | 'use strict'; | ||
const | |||
const __META = getValue(meta, GM_info.script); | |||
const __PROPS = { | |||
'name' : true, | |||
'version' : true, | |||
'namespace' : true, | |||
'description' : true | |||
}; | |||
const __DBMOD = { }; | |||
__LOG[5](__META); | |||
// Infos zu diesem Script... | |||
addProps(__DBMOD, __META, __PROPS); | |||
// Voller Name fuer die Ausgabe... | |||
Object.defineProperty(__DBMOD, 'Name', { | |||
get : function() { | |||
return this.name + " (" + this.version + ')'; | |||
}, | |||
set : undefined | |||
}); | |||
__LOG[2](__DBMOD); | |||
return | return __DBMOD; | ||
} | } | ||
// | Class.define(ScriptModule, Object); | ||
// | |||
// Initialisiert die Scriptdatenbank, die einen Datenaustausch zwischen den Scripten ermoeglicht | |||
function | // optSet: Gesetzte Optionen (und Config) | ||
const | function initScriptDB(optSet) { | ||
// Speicher fuer die DB-Daten... | |||
const __DBMEM = myOptMem.Value; | |||
__DBTOC.versions = getValue((__DBMEM === undefined) ? undefined : JSON.parse(__DBMEM.getItem('__DBTOC.versions')), { }); | |||
__DBTOC.namespaces = getValue((__DBMEM === undefined) ? undefined : JSON.parse(__DBMEM.getItem('__DBTOC.namespaces')), { }); | |||
// Zunaechst den alten Eintrag entfernen... | |||
delete __DBTOC.versions[__DBMOD.name]; | |||
delete __DBTOC.namespaces[__DBMOD.name]; | |||
if (__DBMEM !== undefined) { | |||
// ... und die Daten der Fremdscripte laden... | |||
for (let module in __DBTOC.versions) { | |||
scriptDB(module, getValue(JSON.parse(__DBMEM.getItem('__DBDATA.' + module)), { })); | |||
} | |||
} | |||
} | |||
// Setzt die Daten dieses Scriptes in der Scriptdatenbank, die einen Datenaustausch zwischen den Scripten ermoeglicht | |||
// optSet: Gesetzte Optionen (und Config) | |||
function updateScriptDB(optSet) { | |||
// Eintrag ins Inhaltsverzeichnis... | |||
__DBTOC.versions[__DBMOD.name] = __DBMOD.version; | |||
__DBTOC.namespaces[__DBMOD.name] = __DBMOD.namespace; | |||
// | // Speicher fuer die DB-Daten... | ||
const __DBMEM = myOptMem.Value; | |||
const | |||
if (__DBMEM !== undefined) { | |||
// Permanente Speicherung der Eintraege... | |||
__DBMEM.setItem('__DBTOC.versions', safeStringify(__DBTOC.versions)); | |||
__DBMEM.setItem('__DBTOC.namespaces', safeStringify(__DBTOC.namespaces)); | |||
__DBMEM.setItem('__DBDATA.' + __DBMOD.name, safeStringify(optSet)); | |||
// | // Aktualisierung der Speichergroesse... | ||
myOptMemSize = getMemSize(myOptMem); | |||
} | |||
// Jetzt die inzwischen gefuellten Daten *dieses* Scripts ergaenzen... | |||
scriptDB(__DBMOD.name, getValue(optSet, { })); | |||
__LOG[2](__DBDATA); | |||
} | } | ||
// | // Holt die globalen Daten zu einem Modul aus der Scriptdatenbank | ||
// | // module: Gesetzte Optionen (und Config) | ||
// return | // initValue: Falls angegeben, zugewiesener Startwert | ||
function | // return Daten zu diesem Modul | ||
function scriptDB(module, initValue = undefined) { | |||
const __NAMESPACE = __DBTOC.namespaces[module]; | |||
const __DBMODS = getProp(__DBDATA, __NAMESPACE, { }); | |||
const | |||
const | |||
if (initValue !== undefined) { | |||
return (__DBMODS[module] = initValue); | |||
} else { | |||
return getProp(__DBMODS, module, { }); | |||
} | |||
} | } | ||
// | // ==================== Ende Abschnitt fuer die Scriptdatenbank ==================== | ||
// | // ==================== Ende Abschnitt fuer Speicher und die Scriptdatenbank ==================== | ||
// ==================== Abschnitt fuer das Benutzermenu ==================== | |||
if ( | // Zeigt den Eintrag im Menu einer Option | ||
// val: Derzeitiger Wert der Option | |||
// menuOn: Text zum Setzen im Menu | |||
// funOn: Funktion zum Setzen | |||
// keyOn: Hotkey zum Setzen im Menu | |||
// menuOff: Text zum Ausschalten im Menu | |||
// funOff: Funktion zum Ausschalten | |||
// keyOff: Hotkey zum Ausschalten im Menu | |||
function registerMenuOption(val, menuOn, funOn, keyOn, menuOff, funOff, keyOff) { | |||
const __ON = (val ? '*' : ""); | |||
const __OFF = (val ? "" : '*'); | |||
__LOG[3]("OPTION " + __ON + menuOn + __ON + " / " + __OFF + menuOff + __OFF); | |||
if (val) { | |||
GM_registerMenuCommand(menuOff, funOff, keyOff); | |||
} else { | |||
GM_registerMenuCommand(menuOn, funOn, keyOn); | |||
} | |||
} | |||
// Zeigt den Eintrag im Menu einer Option mit Wahl des naechsten Wertes | |||
// val: Derzeitiger Wert der Option | |||
// arr: Array-Liste mit den moeglichen Optionen | |||
// menu: Text zum Setzen im Menu ($ wird durch gesetzten Wert ersetzt) | |||
// fun: Funktion zum Setzen des naechsten Wertes | |||
// key: Hotkey zum Setzen des naechsten Wertes im Menu | |||
function registerNextMenuOption(val, arr, menu, fun, key) { | |||
const __MENU = menu.replace('$', val); | |||
let options = "OPTION " + __MENU; | |||
for (let value of arr) { | |||
if (value === val) { | |||
options += " / *" + value + '*'; | |||
} else { | |||
options += " / " + value; | |||
} | } | ||
} | } | ||
__LOG[3](options); | |||
GM_registerMenuCommand(__MENU, fun, key); | |||
} | } | ||
// | // Zeigt den Eintrag im Menu einer Option, falls nicht hidden | ||
// | // val: Derzeitiger Wert der Option | ||
// | // menu: Text zum Setzen im Menu ($ wird durch gesetzten Wert ersetzt) | ||
// fun: Funktion zum Setzen des naechsten Wertes | |||
// | // key: Hotkey zum Setzen des naechsten Wertes im Menu | ||
// | // hidden: Angabe, ob Menupunkt nicht sichtbar sein soll (Default: sichtbar) | ||
// | // serial: Serialization fuer komplexe Daten | ||
// | function registerDataOption(val, menu, fun, key, hidden = false, serial = true) { | ||
function | const __VALUE = ((serial && (val !== undefined)) ? safeStringify(val) : val); | ||
const | const __MENU = getValue(menu, "").replace('$', __VALUE); | ||
const | const __OPTIONS = (hidden ? "HIDDEN " : "") + "OPTION " + __MENU + | ||
getValue(__VALUE, "", " = " + __VALUE); | |||
const | |||
__LOG[hidden ? 4 : 3](__OPTIONS); | |||
if (! hidden) { | |||
GM_registerMenuCommand(__MENU, fun, key); | |||
} | } | ||
} | } | ||
// | // Zeigt den Eintrag im Menu einer Option | ||
// | // opt: Config und Value der Option | ||
function registerOption(opt) { | |||
const __CONFIG = getOptConfig(opt); | |||
const __VALUE = getOptValue(opt); | |||
const __LABEL = __CONFIG.Label; | |||
function | const __ACTION = opt.Action; | ||
const __HOTKEY = __CONFIG.Hotkey; | |||
const __HIDDEN = __CONFIG.HiddenMenu; | |||
const __SERIAL = __CONFIG.Serial; | |||
const | |||
if (! __CONFIG.HiddenMenu) { | |||
switch (__CONFIG.Type) { | |||
case __OPTTYPES.MC : registerNextMenuOption(__VALUE, __CONFIG.Choice, __LABEL, __ACTION, __HOTKEY); | |||
break; | |||
case __OPTTYPES.SW : registerMenuOption(__VALUE, __LABEL, __ACTION, __HOTKEY, | |||
__CONFIG.AltLabel, __ACTION, __CONFIG.AltHotkey); | |||
break; | |||
case __OPTTYPES.TF : registerMenuOption(__VALUE, __LABEL, __ACTION, __HOTKEY, | |||
__CONFIG.AltLabel, opt.AltAction, __CONFIG.AltHotkey); | |||
break; | |||
case __OPTTYPES.SD : registerDataOption(__VALUE, __LABEL, __ACTION, __HOTKEY, __HIDDEN, __SERIAL); | |||
break; | |||
case __OPTTYPES.SI : registerDataOption(__VALUE, __LABEL, __ACTION, __HOTKEY, __HIDDEN, __SERIAL); | |||
break; | |||
default : break; | |||
} | |||
} else { | |||
// Nur Anzeige im Log... | |||
registerDataOption(__VALUE, __LABEL, __ACTION, __HOTKEY, __HIDDEN, __SERIAL); | |||
} | |||
} | } | ||
// | // ==================== Ende Abschnitt fuer das Benutzermenu ==================== | ||
// Initialisiert die gesetzten Option | |||
// config: Konfiguration der Option | |||
// setValue: Zu uebernehmender Default-Wert (z.B. der jetzt gesetzte) | |||
// return Initialwert der gesetzten Option | |||
function initOptValue(config, setValue = undefined) { | |||
let value = getValue(setValue, config.Default); // Standard | |||
if (config.SharedData !== undefined) { | |||
} | value = config.SharedData; | ||
} | |||
switch (config.Type) { | |||
case __OPTTYPES.MC : if ((value === undefined) && (config.Choice !== undefined)) { | |||
value = config.Choice[0]; | |||
} | |||
break; | |||
case __OPTTYPES.SW : break; | |||
case __OPTTYPES.TF : break; | |||
case __OPTTYPES.SD : config.Serial = true; | |||
break; | |||
case __OPTTYPES.SI : break; | |||
default : break; | |||
} | |||
if (config.Serial || config.Hidden) { | |||
config.HiddenMenu = true; | |||
} | |||
return value; | |||
} | } | ||
// | // Initialisiert die Menue-Funktion einer Option | ||
// optAction: Typ der Funktion | |||
// item: Key der Option | |||
// optSet: Platz fuer die gesetzten Optionen (und Config) | |||
// optConfig: Konfiguration der Option | |||
// return Funktion fuer die Option | |||
function initOptAction(optAction, item = undefined, optSet = undefined, optConfig = undefined) { | |||
let fun; | |||
if (optAction !== undefined) { | |||
const __CONFIG = ((optConfig !== undefined) ? optConfig : getOptConfig(getOptByName(optSet, item))); | |||
const __RELOAD = getValue(getValue(__CONFIG, { }).ActionReload, true); | |||
switch (optAction) { | |||
case __OPTACTION.SET : fun = function() { | |||
return setOptByName(optSet, item, __CONFIG.SetValue, __RELOAD); | |||
}; | |||
break; | |||
case __OPTACTION.NXT : fun = function() { | |||
return promptNextOptByName(optSet, item, __CONFIG.SetValue, __RELOAD, | |||
__CONFIG.FreeValue, __CONFIG.SelValue, __CONFIG.MinChoice); | |||
}; | |||
break; | |||
case __OPTACTION.RST : fun = function() { | |||
return resetOptions(optSet, __RELOAD); | |||
}; | |||
break; | |||
default : break; | |||
} | |||
} | |||
// | return fun; | ||
// | } | ||
// | |||
// | // Gibt fuer einen 'Shared'-Eintrag eine ObjRef zurueck | ||
// shared: Object mit den Angaben 'namespace', 'module' und ggfs. 'item' | |||
// item: Key der Option | |||
// return ObjRef, die das Ziel definiert | |||
function getSharedRef(shared, item = undefined) { | |||
if (shared === undefined) { | |||
return undefined; | |||
} | |||
const __OBJREF = new ObjRef(__DBDATA); // Gemeinsame Daten | |||
const __PROPS = [ 'namespace', 'module', 'item' ]; | |||
// - | const __DEFAULTS = [ __DBMOD.namespace, __DBMOD.name, item ]; | ||
// | |||
// | for (let stage in __PROPS) { | ||
// | const __DEFAULT = __DEFAULTS[stage]; | ||
function | const __PROP = __PROPS[stage]; | ||
const __NAME = shared[__PROP]; | |||
' | if (__NAME === '$') { | ||
break; | |||
} | |||
__OBJREF.chDir(getValue(__NAME, __DEFAULT)); | |||
} | |||
return __OBJREF; | |||
} | |||
// Gibt diese Config oder, falls 'Shared', ein Referenz-Objekt mit gemeinsamen Daten zurueck | |||
// optConfig: Konfiguration der Option | |||
// item: Key der Option | |||
// return Entweder optConfig oder gemergete Daten auf Basis des in 'Shared' angegebenen Objekts | |||
function getSharedConfig(optConfig, item = undefined) { | |||
let config = getValue(optConfig, { }); | |||
const __SHARED = config.Shared; | |||
if (__SHARED !== undefined) { | |||
const __OBJREF = getSharedRef(__SHARED, item); // Gemeinsame Daten | |||
if (getValue(__SHARED.item, '$') !== '$') { // __REF ist ein Item | |||
const __REF = valueOf(__OBJREF); | |||
config = { }; // Neu aufbauen... | |||
addProps(config, getOptConfig(__REF)); | |||
addProps(config, optConfig); | |||
config.setConst('SharedData', getOptValue(__REF)); | |||
} else { // __REF enthaelt die Daten selbst | |||
if (! config.Name) { | |||
config.Name = __OBJREF.getPath(); | |||
} | |||
config.setConst('SharedData', __OBJREF); // Achtung: Ggfs. zirkulaer! | |||
} | |||
} | |||
return config; | |||
} | } | ||
// | // Initialisiert die gesetzten Optionen | ||
// | // optConfig: Konfiguration der Optionen | ||
// | // optSet: Platz fuer die gesetzten Optionen | ||
function | // preInit: Vorinitialisierung einzelner Optionen mit 'PreInit'-Attribut | ||
// return Gefuelltes Objekt mit den gesetzten Optionen | |||
function initOptions(optConfig, optSet = undefined, preInit = undefined) { | |||
let value; | |||
if (optSet === undefined) { | |||
optSet = { }; | |||
} | |||
for (let opt in optConfig) { | |||
const __OPTCONFIG = optConfig[opt]; | |||
const __PREINIT = getValue(__OPTCONFIG.PreInit, false, true); | |||
const __ISSHARED = getValue(__OPTCONFIG.Shared, false, true); | |||
if ((preInit === undefined) || (__PREINIT === preInit)) { | |||
const __CONFIG = getSharedConfig(__OPTCONFIG, opt); | |||
const __ALTACTION = getValue(__CONFIG.AltAction, __CONFIG.Action); | |||
// Gab es vorher einen Aufruf, der einen Stub-Eintrag erzeugt hat? Wurde ggfs. bereits geaendert... | |||
const __USESTUB = ((preInit === false) && __PREINIT); | |||
const __LOADED = (__USESTUB && optSet[opt].Loaded); | |||
const __VALUE = (__USESTUB ? optSet[opt].Value : undefined); | |||
optSet[opt] = { | |||
'Item' : opt, | |||
'Config' : __CONFIG, | |||
'Loaded' : (__ISSHARED || __LOADED), | |||
'Value' : initOptValue(__CONFIG, __VALUE), | |||
'SetValue' : __CONFIG.SetValue, | |||
} | 'ReadOnly' : (__ISSHARED || __CONFIG.ReadOnly), | ||
'Action' : initOptAction(__CONFIG.Action, opt, optSet, __CONFIG), | |||
'AltAction' : initOptAction(__ALTACTION, opt, optSet, __CONFIG) | |||
}; | |||
} else if (preInit) { // erstmal nur Stub | |||
optSet[opt] = { | |||
'Item' : opt, | |||
'Config' : __OPTCONFIG, | |||
'Loaded' : false, | |||
'Value' : initOptValue(__OPTCONFIG), | |||
'ReadOnly' : (__ISSHARED || __OPTCONFIG.ReadOnly) | |||
}; | |||
} | |||
} | } | ||
return optSet; | |||
} | } | ||
// | // Abhaengigkeiten: | ||
// | // ================ | ||
// | // initOptions (PreInit): | ||
// | // restoreMemoryByOpt: PreInit oldStorage | ||
function | // getStoredCmds: restoreMemoryByOpt | ||
// runStoredCmds (beforeLoad): getStoredCmds | |||
const | // loadOptions (PreInit): PreInit | ||
// startMemoryByOpt: storage oldStorage | |||
// initScriptDB: startMemoryByOpt | |||
// initOptions (Rest): PreInit | |||
// getMyTeam callback (getOptPrefix): initTeam | |||
// __MYTEAM (initTeam): initOptions | |||
// renameOptions: getOptPrefix | |||
// runStoredCmds (afterLoad): getStoredCmds, renameOptions | |||
// loadOptions (Rest): PreInit/Rest runStoredCmds | |||
// updateScriptDB: startMemoryByOpt | |||
// showOptions: startMemoryByOpt renameOptions | |||
// buildMenu: showOptions | |||
// buildForm: showOptions | |||
// Initialisiert die gesetzten Optionen und den Speicher und laedt die Optionen zum Start | |||
// optConfig: Konfiguration der Optionen | |||
// optSet: Platz fuer die gesetzten Optionen | |||
// return Gefuelltes Objekt mit den gesetzten Optionen | |||
function startOptions(optConfig, optSet = undefined, classification = undefined) { | |||
optSet = initOptions(optConfig, optSet, true); // PreInit | |||
// Memory Storage fuer vorherige Speicherung... | |||
myOptMemSize = getMemSize(myOptMem = restoreMemoryByOpt(optSet.oldStorage)); | |||
// Zwischengespeicherte Befehle auslesen... | |||
const __STOREDCMDS = getStoredCmds(myOptMem); | |||
// ... ermittelte Befehle ausführen... | |||
const __LOADEDCMDS = runStoredCmds(__STOREDCMDS, optSet, true); // BeforeLoad | |||
// Bisher noch nicht geladenene Optionen laden... | |||
loadOptions(optSet); | |||
// Memory Storage fuer naechste Speicherung... | |||
myOptMemSize = getMemSize(myOptMem = startMemoryByOpt(optSet.storage, optSet.oldStorage)); | |||
// Globale Daten ermitteln... | |||
initScriptDB(optSet); | |||
optSet = initOptions(optConfig, optSet, false); // Rest | |||
if (classification !== undefined) { | |||
// Umbenennungen durchfuehren... | |||
classification.renameOptions(); | |||
} | } | ||
// | // ... ermittelte Befehle ausführen... | ||
runStoredCmds(__LOADEDCMDS, optSet, false); // Rest | |||
// | // Als globale Daten speichern... | ||
updateScriptDB(optSet); | |||
return optSet; | |||
return | |||
} | } | ||
// | // Installiert die Visualisierung und Steuerung der Optionen | ||
// optSet: Platz fuer die gesetzten Optionen | |||
// | // optParams: Eventuell notwendige Parameter zur Initialisierung | ||
// | // 'hideMenu': Optionen werden zwar geladen und genutzt, tauchen aber nicht im Benutzermenu auf | ||
// | // 'menuAnchor': Startpunkt fuer das Optionsmenu auf der Seite | ||
// | // 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar) | ||
// | // 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar) | ||
// | // 'formWidth': Anzahl der Elemente pro Zeile | ||
// | // 'formBreak': Elementnummer des ersten Zeilenumbruchs | ||
function | function showOptions(optSet = undefined, optParams = { 'hideMenu' : false }) { | ||
if (! optParams.hideMenu) { | |||
buildMenu(optSet); | |||
} | |||
if ((optParams.menuAnchor !== undefined) && (myOptMem !== __OPTMEMINAKTIVE)) { | |||
buildForm(optParams.menuAnchor, optSet, optParams); | |||
} | |||
} | |||
} | } | ||
// | // Setzt eine Option auf einen vorgegebenen Wert | ||
// | // Fuer kontrollierte Auswahl des Values siehe setNextOpt() | ||
// | // opt: Config und vorheriger Value der Option | ||
function | // value: (Bei allen Typen) Zu setzender Wert | ||
return ( | // reload: Seite mit neuem Wert neu laden | ||
// return Gesetzter Wert | |||
function setOpt(opt, value, reload = false) { | |||
return setOptValue(opt, setStored(getOptName(opt), value, reload, getOptConfig(opt).Serial)); | |||
} | } | ||
// | // Ermittelt die naechste moegliche Option | ||
// | // opt: Config und Value der Option | ||
// | // value: Ggfs. zu setzender Wert | ||
// | // return Zu setzender Wert | ||
function | function getNextOpt(opt, value = undefined) { | ||
const __CONFIG = getOptConfig(opt); | |||
const __VALUE = getOptValue(opt, value); | |||
switch (__CONFIG.Type) { | |||
case __OPTTYPES.MC : return getValue(value, getNextValue(__CONFIG.Choice, __VALUE)); | |||
case __OPTTYPES.SW : return getValue(value, ! __VALUE); | |||
case __OPTTYPES.TF : return getValue(value, ! __VALUE); | |||
case __OPTTYPES.SD : return getValue(value, __VALUE); | |||
case __OPTTYPES.SI : break; | |||
default : break; | |||
} | } | ||
return | return __VALUE; | ||
} | } | ||
// | // Setzt die naechste moegliche Option | ||
// opt: Config und Value der Option | |||
// value: Default fuer ggfs. zu setzenden Wert | |||
// reload: Seite mit neuem Wert neu laden | |||
// return Gesetzter Wert | |||
function setNextOpt(opt, value = undefined, reload = false) { | |||
return setOpt(opt, getNextOpt(opt, value), reload); | |||
} | |||
// Setzt die naechste moegliche Option oder fragt ab einer gewissen Anzahl interaktiv ab | |||
// opt: Config und Value der Option | |||
// value: Default fuer ggfs. zu setzenden Wert | |||
// reload: Seite mit neuem Wert neu laden | |||
// freeValue: Angabe, ob Freitext zugelassen ist (Default: false) | |||
// minChoice: Ab wievielen Auswahlmoeglichkeiten soll abgefragt werden? (Default: 3) | |||
// return Gesetzter Wert | |||
function promptNextOpt(opt, value = undefined, reload = false, freeValue = false, selValue = true, minChoice = 3) { | |||
const __CONFIG = getOptConfig(opt); | |||
const __CHOICE = __CONFIG.Choice; | |||
const | if (value || (! __CHOICE) || (__CHOICE.length < minChoice)) { | ||
return setNextOpt(opt, value, reload); | |||
' | } | ||
const __VALUE = getOptValue(opt, value); | |||
try { | |||
const __NEXTVAL = getNextValue(__CHOICE, __VALUE); | |||
let message = ""; | |||
if (selValue) { | |||
for (let index = 0; index < __CHOICE.length; index++) { | |||
message += (index + 1) + ") " + __CHOICE[index] + '\n'; | |||
} | |||
message += "\nNummer eingeben:"; | |||
} else { | |||
message = __CHOICE.join(" / ") + "\n\nWert eingeben:"; | |||
} | |||
const __ANSWER = prompt(message, __NEXTVAL); | |||
if (__ANSWER) { | |||
const __INDEX = parseInt(__ANSWER, 10) - 1; | |||
let nextVal = (selValue ? __CHOICE[__INDEX] : undefined); | |||
if (nextVal === undefined) { | |||
const __VALTYPE = getValue(__CONFIG.ValType, 'String'); | |||
const __CASTVAL = this[__VALTYPE](__ANSWER); | |||
if (freeValue || (~ __CHOICE.indexOf(__CASTVAL))) { | |||
nextVal = __CASTVAL; | |||
} | |||
} | |||
if (nextVal !== __VALUE) { | |||
if (nextVal) { | |||
return setOpt(opt, nextVal, reload); | |||
} | |||
const __LABEL = __CONFIG.Label.replace('$', __VALUE); | |||
showAlert(__LABEL, "Ung\xFCltige Eingabe: " + __ANSWER); | |||
} | |||
} | |||
} catch (ex) { | |||
__LOG[1]("promptNextOpt: " + ex.message); | |||
} | |||
return __VALUE; | |||
} | |||
// Setzt eine Option auf einen vorgegebenen Wert (Version mit Key) | |||
// Fuer kontrollierte Auswahl des Values siehe setNextOptByName() | |||
// optSet: Platz fuer die gesetzten Optionen (und Config) | |||
// item: Key der Option | |||
// value: (Bei allen Typen) Zu setzender Wert | |||
// reload: Seite mit neuem Wert neu laden | |||
// return Gesetzter Wert | |||
function setOptByName(optSet, item, value, reload = false) { | |||
const __OPT = getOptByName(optSet, item); | |||
return setOpt(__OPT, value, reload); | |||
} | |||
// | // Ermittelt die naechste moegliche Option (Version mit Key) | ||
// | // optSet: Platz fuer die gesetzten Optionen (und Config) | ||
// | // item: Key der Option | ||
function | // value: Default fuer ggfs. zu setzenden Wert | ||
return | // return Zu setzender Wert | ||
function getNextOptByName(optSet, item, value = undefined) { | |||
const __OPT = getOptByName(optSet, item); | |||
return getNextOpt(__OPT, value); | |||
} | } | ||
// | // Setzt die naechste moegliche Option (Version mit Key) | ||
// | // optSet: Platz fuer die gesetzten Optionen (und Config) | ||
// return | // item: Key der Option | ||
function | // value: Default fuer ggfs. zu setzenden Wert | ||
return | // reload: Seite mit neuem Wert neu laden | ||
// return Gesetzter Wert | |||
function setNextOptByName(optSet, item, value = undefined, reload = false) { | |||
const __OPT = getOptByName(optSet, item); | |||
return setNextOpt(__OPT, value, reload); | |||
} | } | ||
// | // Setzt die naechste moegliche Option oder fragt ab einer gewissen Anzahl interaktiv ab (Version mit Key) | ||
// | // optSet: Platz fuer die gesetzten Optionen (und Config) | ||
// return | // item: Key der Option | ||
function | // value: Default fuer ggfs. zu setzenden Wert | ||
return | // reload: Seite mit neuem Wert neu laden | ||
// freeValue: Angabe, ob Freitext zugelassen ist (Default: false) | |||
// minChoice: Ab wievielen Auswahlmoeglichkeiten soll abgefragt werden? (Default: 3) | |||
// return Gesetzter Wert | |||
function promptNextOptByName(optSet, item, value = undefined, reload = false, freeValue = false, selValue = true, minChoice = 3) { | |||
const __OPT = getOptByName(optSet, item); | |||
return promptNextOpt(__OPT, value, reload, freeValue, selValue, minChoice); | |||
} | } | ||
// | // Baut das Benutzermenu auf | ||
// | // optSet: Gesetzte Optionen | ||
function buildMenu(optSet) { | |||
function | __LOG[3]("buildMenu()"); | ||
for (let opt in optSet) { | |||
registerOption(optSet[opt]); | |||
} | } | ||
} | } | ||
// | // Invalidiert eine (ueber Menu) gesetzte Option | ||
// | // opt: Zu invalidierende Option | ||
// | // force: Invalidiert auch Optionen mit 'AutoReset'-Attribut | ||
function | function invalidateOpt(opt, force = false) { | ||
const | if (! opt.ReadOnly) { | ||
const __CONFIG = getOptConfig(opt); | |||
// Wert "ungeladen"... | |||
opt.Loaded = (force || ! __CONFIG.AutoReset); | |||
if (opt.Loaded && __CONFIG.AutoReset) { | |||
// Nur zuruecksetzen, gilt als geladen... | |||
// | setOptValue(opt, initOptValue(__CONFIG)); | ||
} | |||
} | |||
} | |||
// Invalidiert die (ueber Menu) gesetzten Optionen | |||
// optSet: Set mit den Optionen | |||
// force: Invalidiert auch Optionen mit 'AutoReset'-Attribut | |||
// return Set mit den geladenen Optionen | |||
function invalidateOpts(optSet, force = false) { | |||
for (let opt in optSet) { | |||
const __OPT = optSet[opt]; | |||
if (__OPT.Loaded) { | |||
invalidateOpt(__OPT, force); | |||
} | |||
} | |||
return optSet; | |||
} | } | ||
// | // Laedt eine (ueber Menu) gesetzte Option | ||
// | // opt: Zu ladende Option | ||
// | // force: Laedt auch Optionen mit 'AutoReset'-Attribut | ||
function | // return Gesetzter Wert der gelandenen Option | ||
const | function loadOption(opt, force = false) { | ||
const __CONFIG = getOptConfig(opt); | |||
const __ISSHARED = getValue(__CONFIG.Shared, false, true); | |||
const __NAME = getOptName(opt); | |||
const __DEFAULT = getOptValue(opt, undefined, false, false); | |||
let value; | |||
if (opt.Loaded && ! __ISSHARED) { | |||
__LOG[1]("Error: Oprion '" + __NAME + "' bereits geladen!"); | |||
} | |||
if ( | if (opt.ReadOnly || __ISSHARED) { | ||
value = __DEFAULT; | |||
} else if (! force && __CONFIG.AutoReset) { | |||
value = initOptValue(__CONFIG); | |||
} else { | } else { | ||
value = (__CONFIG.Serial ? | |||
deserialize(__NAME, __DEFAULT) : | |||
GM_getValue(__NAME, __DEFAULT)); | |||
} | } | ||
__LOG[5]("LOAD " + __NAME + ": " + __LOG.changed(__DEFAULT, value)); | |||
// Wert als geladen markieren... | |||
opt.Loaded = true; | |||
// Wert intern setzen... | |||
return setOptValue(opt, value); | |||
} | } | ||
// | // Laedt die (ueber Menu) gesetzten Optionen | ||
// | // optSet: Set mit den Optionen | ||
// | // force: Laedt auch Optionen mit 'AutoReset'-Attribut | ||
// return Set mit den geladenen Optionen | |||
// return | function loadOptions(optSet, force = false) { | ||
function | for (let opt in optSet) { | ||
const __OPT = optSet[opt]; | |||
if (! __OPT.Loaded) { | |||
loadOption(__OPT, force); | |||
} | } | ||
} | } | ||
return | return optSet; | ||
} | } | ||
// | // Entfernt eine (ueber Menu) gesetzte Option (falls nicht 'Permanent') | ||
// | // opt: Gesetzte Option | ||
// | // force: Entfernt auch Optionen mit 'Permanent'-Attribut | ||
// | // reset: Setzt bei Erfolg auf Initialwert der Option | ||
function | function deleteOption(opt, force = false, reset = true) { | ||
const | const __CONFIG = getOptConfig(opt); | ||
if ( | if (force || ! __CONFIG.Permanent) { | ||
const __NAME = getOptName(opt); | |||
__LOG[4]("DELETE " + __NAME); | |||
GM_deleteValue(__NAME); | |||
if (reset) { | |||
setOptValue(opt, initOptValue(__CONFIG)); | |||
} | |||
} | } | ||
} | } | ||
// ============= | // Entfernt die (ueber Menu) gesetzten Optionen (falls nicht 'Permanent') | ||
// optSet: Gesetzte Optionen | |||
// optSelect: Liste von ausgewaehlten Optionen, true = entfernen, false = nicht entfernen | |||
// force: Entfernt auch Optionen mit 'Permanent'-Attribut | |||
// reset: Setzt bei Erfolg auf Initialwert der Option | |||
function deleteOptions(optSet, optSelect = undefined, force = false, reset = true) { | |||
const __DELETEALL = (optSelect === undefined) || (optSelect === true); | |||
const __OPTSELECT = getValue(optSelect, { }); | |||
for (let opt in optSet) { | |||
if (getValue(__OPTSELECT[opt], __DELETEALL)) { | |||
deleteOption(optSet[opt], force, reset); | |||
} | |||
} | |||
} | |||
// Benennt eine Option um und laedt sie ggfs. nach | |||
// opt: Gesetzte Option | |||
// name: Neu zu setzender Name (Speicheradresse) | |||
// reload: Wert nachladen statt beizubehalten | |||
// force: Laedt auch Optionen mit 'AutoReset'-Attribut | |||
// return Umbenannte Option | |||
function renameOption(opt, name, reload = false, force = false) { | |||
const __NAME = getOptName(opt); | |||
if (__NAME !== name) { | |||
deleteOption(opt, true, ! reload); | |||
setOptName(opt, name); | |||
if (reload) { | |||
loadOption(opt, force); | |||
if ( | |||
} | } | ||
} | } | ||
return opt; | |||
} | |||
// Ermittelt einen neuen Namen mit einem Prefix. Parameter fuer renameOptions() | |||
// name: Gesetzter Name (Speicheradresse) | |||
// prefix: Prefix, das vorangestellt werden soll | |||
// return Neu zu setzender Name (Speicheradresse) | |||
function prefixName(name, prefix) { | |||
return (prefix + name); | |||
} | |||
return | // Ermittelt einen neuen Namen mit einem Postfix. Parameter fuer renameOptions() | ||
// name: Gesetzter Name (Speicheradresse) | |||
// postfix: Postfix, das angehaengt werden soll | |||
// return Neu zu setzender Name (Speicheradresse) | |||
function postfixName(name, postfix) { | |||
return (name + postfix); | |||
} | } | ||
// | // Benennt selektierte Optionen nach einem Schema um und laedt sie ggfs. nach | ||
// | // optSet: Gesetzte Optionen | ||
function | // optSelect: Liste von ausgewaehlten Optionen, true = nachladen, false = nicht nachladen | ||
// 'reload': Option nachladen? | |||
// 'force': Option auch mit 'AutoReset'-Attribut nachladen? | |||
// renameParam: Wird an renameFun uebergeen | |||
// renameFun: function(name, param) zur Ermittlung des neuen Namens | |||
// - name: Neu zu setzender Name (Speicheradresse) | |||
// - param: Parameter "renameParam" von oben, z.B. Prefix oder Postfix | |||
function renameOptions(optSet, optSelect, renameParam = undefined, renameFun = prefixName) { | |||
if (renameFun === undefined) { | |||
__LOG[1]("RENAME: Illegale Funktion!"); | |||
} | |||
for (let opt in optSelect) { | |||
const __OPTPARAMS = optSelect[opt]; | |||
const __OPT = optSet[opt]; | |||
if (__OPT === undefined) { | |||
__LOG[1]("RENAME: Option '" + opt + "' nicht gefunden!"); | |||
if ( | |||
} else { | } else { | ||
// | const __NAME = getOptName(__OPT); | ||
const __NEWNAME = renameFun(__NAME, renameParam); | |||
const __ISSCALAR = ((typeof __OPTPARAMS) === 'boolean'); | |||
// Laedt die unter dem neuen Namen gespeicherten Daten nach? | |||
const __RELOAD = (__ISSCALAR ? __OPTPARAMS : __OPTPARAMS.reload); | |||
// Laedt auch Optionen mit 'AutoReset'-Attribut? | |||
const __FORCE = (__ISSCALAR ? true : __OPTPARAMS.force); | |||
renameOption(__OPT, __NEWNAME, __RELOAD, __FORCE); | |||
} | } | ||
} | } | ||
} | } | ||
// | // Setzt die Optionen in optSet auf die "Werkseinstellungen" des Skripts | ||
// | // optSet: Gesetzte Optionen | ||
function | // reload: Seite mit "Werkseinstellungen" neu laden | ||
function resetOptions(optSet, reload = true) { | |||
// Alle (nicht 'Permanent') gesetzten Optionen entfernen... | |||
deleteOptions(optSet, true, false, ! reload); | |||
if (reload) { | |||
// ... und Seite neu laden (mit "Werkseinstellungen")... | |||
window.location.reload(); | |||
} | } | ||
} | } | ||
// | // ==================== Abschnitt fuer diverse Utilities ==================== | ||
// Legt Input-Felder in einem Form-Konstrukt an, falls noetig | |||
// form: <form>...</form> | |||
// props: Map von name:value-Paaren | |||
// type: Typ der Input-Felder (Default: unsichtbare Daten) | |||
// return Ergaenztes Form-Konstrukt | |||
function addInputField(form, props, type = "hidden") { | |||
for (let fieldName in props) { | |||
let field = form[fieldName]; | |||
if (! field) { | |||
field = document.createElement("input"); | |||
field.type = type; | |||
field.name = fieldName; | |||
form.appendChild(field); | |||
} | |||
field.value = props[fieldName]; | |||
} | } | ||
return form; | |||
} | } | ||
// | // Legt unsichtbare Input-Daten in einem Form-Konstrukt an, falls noetig | ||
// form: <form>...</form> | |||
// props: Map von name:value-Paaren | |||
// return Ergaenztes Form-Konstrukt | |||
function addHiddenField(form, props) { | |||
return addInputField(form, props, "hidden"); | |||
} | |||
// = | // Hilfsfunktion fuer alle Browser: Fuegt fuer ein Event eine Reaktion ein | ||
// obj: Betroffenes Objekt, z.B. ein Eingabeelement | |||
// type: Name des Events, z.B. "click" | |||
// callback: Funktion als Reaktion | |||
// capture: Event fuer Parent zuerst (true) oder Child (false als Default) | |||
// return false bei Misserfolg | |||
function addEvent(obj, type, callback, capture = false) { | |||
if (obj.addEventListener) { | |||
return obj.addEventListener(type, callback, capture); | |||
} else if (obj.attachEvent) { | |||
return obj.attachEvent("on" + type, callback); | |||
} else { | |||
__LOG[1]("Could not add " + type + " event:"); | |||
__LOG[2](callback); | |||
return false; | |||
} | |||
} | |||
// Hilfsfunktion fuer alle Browser: Entfernt eine Reaktion fuer ein Event | |||
// obj: Betroffenes Objekt, z.B. ein Eingabeelement | |||
// type: Name des Events, z.B. "click" | |||
// callback: Funktion als Reaktion | |||
// capture: Event fuer Parent zuerst (true) oder Child (false als Default) | |||
// return false bei Misserfolg | |||
function removeEvent(obj, type, callback, capture = false) { | |||
if (obj.removeEventListener) { | |||
return obj.removeEventListener(type, callback, capture); | |||
} else if (obj.detachEvent) { | |||
return obj.detachEvent("on" + type, callback); | |||
} else { | |||
__LOG[1]("Could not remove " + type + " event:"); | |||
__LOG[2](callback); | |||
return false; | |||
} | |||
} | |||
// Hilfsfunktion fuer alle Browser: Fuegt fuer ein Event eine Reaktion ein | |||
// id: ID des betroffenen Eingabeelements | |||
// type: Name des Events, z.B. "click" | |||
// callback: Funktion als Reaktion | |||
// capture: Event fuer Parent zuerst (true) oder Child (false als Default) | |||
// return false bei Misserfolg | |||
function addDocEvent(id, type, callback, capture = false) { | |||
const __OBJ = document.getElementById(id); | |||
return addEvent(__OBJ, type, callback, capture); | |||
} | |||
const | // Hilfsfunktion fuer alle Browser: Entfernt eine Reaktion fuer ein Event | ||
// id: ID des betroffenen Eingabeelements | |||
// type: Name des Events, z.B. "click" | |||
// callback: Funktion als Reaktion | |||
// capture: Event fuer Parent zuerst (true) oder Child (false als Default) | |||
// return false bei Misserfolg | |||
function removeDocEvent(id, type, callback, capture = false) { | |||
const __OBJ = document.getElementById(id); | |||
return removeEvent(__OBJ, type, callback, capture); | |||
} | |||
// Hilfsfunktion fuer die Ermittlung eines Elements der Seite | |||
// name: Name des Elements (siehe "name=") | |||
// index: Laufende Nummer des Elements (0-based), Default: 0 | |||
// doc: Dokument (document) | |||
// return Gesuchtes Element mit der lfd. Nummer index oder undefined (falls nicht gefunden) | |||
function getElement(name, index = 0, doc = document) { | |||
const __TAGS = document.getElementsByName(name); | |||
const __TABLE = (__TAGS === undefined) ? undefined : __TAGS[index]; | |||
return __TABLE; | |||
} | |||
// Hilfsfunktion fuer die Ermittlung eines Elements der Seite (Default: Tabelle) | |||
// index: Laufende Nummer des Elements (0-based) | |||
// tag: Tag des Elements ("table") | |||
// doc: Dokument (document) | |||
// return Gesuchtes Element oder undefined (falls nicht gefunden) | |||
function getTable(index, tag = "table", doc = document) { | |||
const __TAGS = document.getElementsByTagName(tag); | |||
const __TABLE = (__TAGS === undefined) ? undefined : __TAGS[index]; | |||
return __TABLE; | |||
} | |||
// Hilfsfunktion fuer die Ermittlung der Zeilen einer Tabelle | |||
// index: Laufende Nummer des Elements (0-based) | |||
// doc: Dokument (document) | |||
// return Gesuchte Zeilen oder undefined (falls nicht gefunden) | |||
function getRows(index, doc = document) { | |||
const __TABLE = getTable(index, "table", doc); | |||
const __ROWS = (__TABLE === undefined) ? undefined : __TABLE.rows; | |||
return __ROWS; | |||
} | |||
// ==================== Abschnitt fuer Optionen auf der Seite ==================== | |||
// Liefert den Funktionsaufruf zur Option als String | |||
// opt: Auszufuehrende Option | |||
// isAlt: Angabe, ob AltAction statt Action gemeint ist | |||
// value: Ggfs. zu setzender Wert | |||
// serial: Serialization fuer String-Werte (Select, Textarea) | |||
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv | |||
// return String mit dem (reinen) Funktionsaufruf | |||
function getFormAction(opt, isAlt = false, value = undefined, serial = undefined, memory = undefined) { | |||
const __STORAGE = getMemory(memory); | |||
const __MEMORY = __STORAGE.Value; | |||
const __MEMSTR = __STORAGE.Display; | |||
const __RUNPREFIX = __STORAGE.Prefix; | |||
if (__MEMORY !== undefined) { | |||
const __RELOAD = "window.location.reload()"; | |||
const __SETITEM = function(item, val, quotes = true) { | |||
return (__MEMSTR + ".setItem('" + __RUNPREFIX + item + "', " + (quotes ? "'" + val + "'" : val) + "),"); | |||
}; | |||
const __SETITEMS = function(cmd, key = undefined, val = undefined) { | |||
return ('(' + __SETITEM('cmd', cmd) + ((key === undefined) ? "" : | |||
__SETITEM('key', key) + __SETITEM('val', val, false)) + __RELOAD + ')'); | |||
}; | |||
const __CONFIG = getOptConfig(opt); | |||
const __SERIAL = getValue(serial, getValue(__CONFIG.Serial, false)); | |||
const __THISVAL = ((__CONFIG.ValType === "String") ? "'\\x22' + this.value + '\\x22'" : "this.value"); | |||
const __TVALUE = getValue(__CONFIG.ValType, __THISVAL, "new " + __CONFIG.ValType + '(' + __THISVAL + ')'); | |||
const __VALSTR = ((value !== undefined) ? safeStringify(value) : __SERIAL ? "JSON.stringify(" + __TVALUE + ')' : __TVALUE); | |||
const __ACTION = (isAlt ? getValue(__CONFIG.AltAction, __CONFIG.Action) : __CONFIG.Action); | |||
if (__ACTION !== undefined) { | |||
switch (__ACTION) { | |||
case __OPTACTION.SET : //return "doActionSet('" + getOptName(opt) + "', " + getNextOpt(opt, __VALSTR) + ')'; | |||
return __SETITEMS('SET', getOptName(opt), __VALSTR); | |||
case __OPTACTION.NXT : //return "doActionNxt('" + getOptName(opt) + "', " + getNextOpt(opt, __VALSTR) + ')'; | |||
return __SETITEMS('NXT', getOptName(opt), __VALSTR); | |||
case __OPTACTION.RST : //return "doActionRst()"; | |||
return __SETITEMS('RST'); | |||
default : break; | |||
} | } | ||
} | |||
} | |||
if (__ZAT.gameType === "Liga") { | return undefined; | ||
if (__ZAT.ZAT < 70) { | } | ||
stats = addResultToStats(ligaStats, getOptValue(__OPTSET.longStats), __ZAT); | |||
} | // Liefert die Funktionsaufruf zur Option als String | ||
} else if ((__ZAT.gameType === "OSCQ") || (__ZAT.gameType === "OSEQ") || (__ZAT.gameType === "OSE")) { | // opt: Auszufuehrende Option | ||
if (__ZAT.hinRueck !== 1) { | // isAlt: Angabe, ob AltAction statt Action gemeint ist | ||
euroStats = emptyStats(); | // value: Ggfs. zu setzender Wert | ||
} | // type: Event-Typ fuer <input>, z.B. "click" fuer "onclick=" | ||
stats = addResultToStats(euroStats, getOptValue(__OPTSET.longStats), __ZAT); | // serial: Serialization fuer String-Werte (Select, Textarea) | ||
} else if (__ZAT.gameType === "OSC") { | // memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv | ||
// return String mit dem (reinen) Funktionsaufruf | |||
function getFormActionEvent(opt, isAlt = false, value = undefined, type = "click", serial = undefined, memory = undefined) { | |||
const __ACTION = getFormAction(opt, isAlt, value, serial, memory); | |||
return getValue(__ACTION, "", ' on' + type + '="' + __ACTION + '"'); | |||
} | |||
// Zeigt eine Option auf der Seite als Auswahlbox an | |||
// opt: Anzuzeigende Option | |||
// return String mit dem HTML-Code | |||
function getOptionSelect(opt) { | |||
const __CONFIG = getOptConfig(opt); | |||
const __NAME = getOptName(opt); | |||
const __VALUE = getOptValue(opt); | |||
const __ACTION = getFormActionEvent(opt, false, undefined, "change", undefined); | |||
const __FORMLABEL = getValue(__CONFIG.FormLabel, __CONFIG.Label); | |||
const __LABEL = '<label for="' + __NAME + '">' + __FORMLABEL + '</label>'; | |||
let element = '<select name="' + __NAME + '" id="' + __NAME + '"' + __ACTION + '>'; | |||
if (__CONFIG.FreeValue && ! (~ __CONFIG.Choice.indexOf(__VALUE))) { | |||
element += '\n<option value="' + __VALUE + '" SELECTED>' + __VALUE + '</option>'; | |||
} | |||
for (let value of __CONFIG.Choice) { | |||
element += '\n<option value="' + value + '"' + | |||
((value === __VALUE) ? ' SELECTED' : "") + | |||
'>' + value + '</option>'; | |||
} | |||
element += '\n</select>'; | |||
return __LABEL.replace('$', element); | |||
} | |||
// Zeigt eine Option auf der Seite als Radiobutton an | |||
// opt: Anzuzeigende Option | |||
// return String mit dem HTML-Code | |||
function getOptionRadio(opt) { | |||
const __CONFIG = getOptConfig(opt); | |||
const __NAME = getOptName(opt); | |||
const __VALUE = getOptValue(opt, false); | |||
const __ACTION = getFormActionEvent(opt, false, true, "click", false); | |||
const __ALTACTION = getFormActionEvent(opt, true, false, "click", false); | |||
const __ELEMENTON = '<input type="radio" name="' + __NAME + | |||
'" id="' + __NAME + 'ON" value="1"' + | |||
(__VALUE ? ' CHECKED' : __ACTION) + | |||
' /><label for="' + __NAME + 'ON">' + | |||
__CONFIG.Label + '</label>'; | |||
const __ELEMENTOFF = '<input type="radio" name="' + __NAME + | |||
'" id="' + __NAME + 'OFF" value="0"' + | |||
(__VALUE ? __ALTACTION : ' CHECKED') + | |||
' /><label for="' + __NAME + 'OFF">' + | |||
__CONFIG.AltLabel + '</label>'; | |||
return [ __ELEMENTON, __ELEMENTOFF ]; | |||
} | |||
// Zeigt eine Option auf der Seite als Checkbox an | |||
// opt: Anzuzeigende Option | |||
// return String mit dem HTML-Code | |||
function getOptionCheckbox(opt) { | |||
const __CONFIG = getOptConfig(opt); | |||
const __NAME = getOptName(opt); | |||
const __VALUE = getOptValue(opt, false); | |||
const __ACTION = getFormActionEvent(opt, __VALUE, ! __VALUE, "click", false); | |||
const __FORMLABEL = getValue(__CONFIG.FormLabel, __CONFIG.Label); | |||
return '<input type="checkbox" name="' + __NAME + | |||
'" id="' + __NAME + '" value="' + __VALUE + '"' + | |||
(__VALUE ? ' CHECKED' : "") + __ACTION + ' /><label for="' + | |||
__NAME + '">' + __FORMLABEL + '</label>'; | |||
} | |||
// Zeigt eine Option auf der Seite als Daten-Textfeld an | |||
// opt: Anzuzeigende Option | |||
// return String mit dem HTML-Code | |||
function getOptionTextarea(opt) { | |||
const __CONFIG = getOptConfig(opt); | |||
const __NAME = getOptName(opt); | |||
const __VALUE = getOptValue(opt); | |||
const __ACTION = getFormActionEvent(opt, false, undefined, "submit", undefined); | |||
const __SUBMIT = getValue(__CONFIG.Submit, ""); | |||
//const __ONSUBMIT = (__SUBMIT.length ? ' onKeyDown="' + __SUBMIT + '"': ""); | |||
const __ONSUBMIT = (__SUBMIT ? ' onKeyDown="' + __SUBMIT + '"': ""); | |||
const __FORMLABEL = getValue(__CONFIG.FormLabel, __CONFIG.Label); | |||
const __ELEMENTLABEL = '<label for="' + __NAME + '">' + __FORMLABEL + '</label>'; | |||
const __ELEMENTTEXT = '<textarea name="' + __NAME + '" id="' + __NAME + '" cols="' + __CONFIG.Cols + | |||
'" rows="' + __CONFIG.Rows + '"' + __ONSUBMIT + __ACTION + '>' + | |||
safeStringify(__VALUE, __CONFIG.Replace, __CONFIG.Space) + '</textarea>'; | |||
return [ __ELEMENTLABEL, __ELEMENTTEXT ]; | |||
} | |||
// Zeigt eine Option auf der Seite als Button an | |||
// opt: Anzuzeigende Option | |||
// return String mit dem HTML-Code | |||
function getOptionButton(opt) { | |||
const __CONFIG = getOptConfig(opt); | |||
const __NAME = getOptName(opt); | |||
const __VALUE = getOptValue(opt, false); | |||
const __ACTION = getFormActionEvent(opt, __VALUE, ! __VALUE, "click", false); | |||
const __BUTTONLABEL = (__VALUE ? __CONFIG.AltLabel : __CONFIG.Label); | |||
const __FORMLABEL = getValue(__CONFIG.FormLabel, __CONFIG.Label); | |||
return '<label for="' + __NAME + '">' + __FORMLABEL + | |||
'</label><input type="button" name="' + __NAME + | |||
'" id="' + __NAME + '" value="' + __BUTTONLABEL + '"' + | |||
__ACTION + '/>'; | |||
} | |||
// Zeigt eine Option auf der Seite an (je nach Typ) | |||
// opt: Anzuzeigende Option | |||
// return String mit dem HTML-Code | |||
function getOptionElement(opt) { | |||
const __CONFIG = getOptConfig(opt); | |||
const __TYPE = getValue(__CONFIG.FormType, __CONFIG.Type); | |||
let element = ""; | |||
if (! __CONFIG.Hidden) { | |||
switch (__TYPE) { | |||
case __OPTTYPES.MC : element = getOptionSelect(opt); | |||
break; | |||
case __OPTTYPES.SW : if (__CONFIG.FormLabel !== undefined) { | |||
element = getOptionCheckbox(opt); | |||
} else { | |||
element = getOptionRadio(opt); | |||
} | |||
break; | |||
case __OPTTYPES.TF : element = getOptionCheckbox(opt); | |||
break; | |||
case __OPTTYPES.SD : element = getOptionTextarea(opt); | |||
break; | |||
case __OPTTYPES.SI : element = getOptionButton(opt); | |||
break; | |||
default : break; | |||
} | |||
if (element.length === 2) { | |||
element = '<div>' + element[0] + '<br />' + element[1] + '</div>'; | |||
} | |||
} | |||
return element; | |||
} | |||
// Baut das Benutzermenu auf der Seite auf | |||
// optSet: Gesetzte Optionen | |||
// optParams: Eventuell notwendige Parameter | |||
// 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar) | |||
// 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar) | |||
// 'formWidth': Anzahl der Elemente pro Zeile | |||
// 'formBreak': Elementnummer des ersten Zeilenumbruchs | |||
// return String mit dem HTML-Code | |||
function getForm(optSet, optParams = { }) { | |||
const __FORM = '<form id="options" method="POST"><table><tbody><tr>'; | |||
const __FORMEND = '</tr></tbody></table></form>'; | |||
const __FORMWIDTH = getValue(optParams.formWidth, 3); | |||
const __FORMBREAK = getValue(optParams.formBreak, __FORMWIDTH); | |||
const __SHOWFORM = getOptValue(optSet.showForm, true) ? optParams.showForm : { 'showForm' : true }; | |||
let form = __FORM; | |||
let count = 0; // Bisher angezeigte Optionen | |||
let column = 0; // Spalte der letzten Option (1-basierend) | |||
for (let opt in optSet) { | |||
if (checkItem(opt, __SHOWFORM, optParams.hideForm)) { | |||
const __ELEMENT = getOptionElement(optSet[opt]); | |||
const __TDOPT = (~ __ELEMENT.indexOf('|')) ? "" : ' colspan="2"'; | |||
if (__ELEMENT) { | |||
if (++count > __FORMBREAK) { | |||
if (++column > __FORMWIDTH) { | |||
column = 1; | |||
} | |||
} | |||
if (column === 1) { | |||
form += '</tr><tr>'; | |||
} | |||
form += '\n<td' + __TDOPT + '>' + __ELEMENT.replace('|', '</td><td>') + '</td>'; | |||
} | |||
} | |||
} | |||
form += '\n' + __FORMEND; | |||
return form; | |||
} | |||
// Fuegt das Script in die Seite ein | |||
// optSet: Gesetzte Optionen | |||
// optParams: Eventuell notwendige Parameter | |||
// 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar) | |||
// 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar) | |||
// return String mit dem HTML-Code fuer das Script | |||
function getScript(optSet, optParams = { }) { | |||
//const __SCRIPT = '<script type="text/javascript">function activateMenu() { console.log("TADAAA!"); }</script>'; | |||
//const __SCRIPT = '<script type="text/javascript">\n\tfunction doActionNxt(key, value) { alert("SET " + key + " = " + value); }\n\tfunction doActionNxt(key, value) { alert("SET " + key + " = " + value); }\n\tfunction doActionRst(key, value) { alert("RESET"); }\n</script>'; | |||
//const __FORM = '<form method="POST"><input type="button" id="showOpts" name="showOpts" value="Optionen anzeigen" onclick="activateMenu()" /></form>'; | |||
const __SCRIPT = ""; | |||
//window.eval('function activateMenu() { console.log("TADAAA!"); }'); | |||
return __SCRIPT; | |||
} | |||
// Zeigt das Optionsmenu auf der Seite an (im Gegensatz zum Benutzermenu) | |||
// anchor: Element, das als Anker fuer die Anzeige dient | |||
// optSet: Gesetzte Optionen | |||
// optParams: Eventuell notwendige Parameter | |||
// 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar) | |||
// 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar) | |||
// 'formWidth': Anzahl der Elemente pro Zeile | |||
// 'formBreak': Elementnummer des ersten Zeilenumbruchs | |||
function buildForm(anchor, optSet, optParams = { }) { | |||
__LOG[3]("buildForm()"); | |||
const __FORM = getForm(optSet, optParams); | |||
const __SCRIPT = getScript(optSet, optParams); | |||
addForm(anchor, __FORM, __SCRIPT); | |||
} | |||
// Informationen zu hinzugefuegten Forms | |||
const __FORMS = { }; | |||
// Zeigt das Optionsmenu auf der Seite an (im Gegensatz zum Benutzermenu) | |||
// anchor: Element, das als Anker fuer die Anzeige dient | |||
// form: HTML-Form des Optionsmenu (hinten angefuegt) | |||
// script: Script mit Reaktionen | |||
function addForm(anchor, form = "", script = "") { | |||
const __OLDFORM = __FORMS[anchor]; | |||
const __REST = (__OLDFORM === undefined) ? anchor.innerHTML : | |||
anchor.innerHTML.substring(0, anchor.innerHTML.length - __OLDFORM.Script.length - __OLDFORM.Form.length); | |||
__FORMS[anchor] = { | |||
'Script' : script, | |||
'Form' : form | |||
}; | |||
anchor.innerHTML = __REST + script + form; | |||
} | |||
// ==================== Abschnitt fuer Klasse Classification ==================== | |||
// Basisklasse fuer eine Klassifikation der Optionen nach Kriterium (z.B. Erst- und Zweitteam oder Fremdteam) | |||
function Classification() { | |||
'use strict'; | |||
this.renameFun = prefixName; | |||
//this.renameParamFun = undefined; | |||
this.optSet = undefined; | |||
this.optSelect = { }; | |||
} | |||
Class.define(Classification, Object, { | |||
'renameOptions' : function() { | |||
const __PARAM = this.renameParamFun(); | |||
if (__PARAM !== undefined) { | |||
// Klassifizierte Optionen umbenennen... | |||
renameOptions(this.optSet, this.optSelect, __PARAM, this.renameFun); | |||
} | |||
}, | |||
'deleteOptions' : function() { | |||
return deleteOptions(this.optSet, this.optSelect, true, true); | |||
} | |||
} ); | |||
// ==================== Ende Abschnitt fuer Klasse Classification ==================== | |||
// ==================== Abschnitt fuer Klasse TeamClassification ==================== | |||
// Klasse fuer die Klassifikation der Optionen nach Team (Erst- und Zweitteam oder Fremdteam) | |||
function TeamClassification() { | |||
'use strict'; | |||
Classification.call(this); | |||
this.team = undefined; | |||
this.teamParams = undefined; | |||
} | |||
Class.define(TeamClassification, Classification, { | |||
'renameParamFun' : function() { | |||
const __MYTEAM = (this.team = getMyTeam(this.optSet, this.teamParams, this.team)); | |||
if (__MYTEAM.LdNr) { | |||
// Prefix fuer die Optionen mit gesonderten Behandlung... | |||
return __MYTEAM.LdNr.toString() + '.' + __MYTEAM.LgNr.toString() + ':'; | |||
} else { | |||
return undefined; | |||
} | |||
} | |||
} ); | |||
// ==================== Ende Abschnitt fuer Klasse TeamClassification ==================== | |||
// ==================== Abschnitt fuer Klasse Team ==================== | |||
// Klasse fuer Teamdaten | |||
function Team(team, land, liga) { | |||
'use strict'; | |||
this.Team = team; | |||
this.Land = land; | |||
this.Liga = liga; | |||
this.LdNr = getLandNr(land); | |||
this.LgNr = getLigaNr(liga); | |||
} | |||
Class.define(Team, Object, { | |||
'__TEAMITEMS' : { // Items, die in Team als Teamdaten gesetzt werden... | |||
'Team' : true, | |||
'Liga' : true, | |||
'Land' : true, | |||
'LdNr' : true, | |||
'LgNr' : true | |||
} | |||
} ); | |||
// ==================== Ende Abschnitt fuer Klasse Team ==================== | |||
// ==================== Spezialisierter Abschnitt fuer Optionen ==================== | |||
// Gesetzte Optionen (wird von initOptions() angelegt und von loadOptions() gefuellt): | |||
const __OPTSET = { }; | |||
// Teamparameter fuer getrennte Speicherung der Optionen fuer Erst- und Zweitteam... | |||
const __TEAMCLASS = new TeamClassification(); | |||
// Optionen mit Daten, die ZAT- und Team-bezogen gemerkt werden... | |||
__TEAMCLASS.optSelect = { | |||
'ligaSize' : true | |||
}; | |||
// Gibt die Teamdaten zurueck und aktualisiert sie ggfs. in der Option | |||
// optSet: Platz fuer die gesetzten Optionen | |||
// teamParams: Dynamisch ermittelte Teamdaten ('Team', 'Liga', 'Land', 'LdNr' und 'LgNr') | |||
// myTeam: Objekt fuer die Teamdaten | |||
// return Die Teamdaten oder undefined bei Fehler | |||
function getMyTeam(optSet = undefined, teamParams = undefined, myTeam = new Team()) { | |||
if (teamParams !== undefined) { | |||
addProps(myTeam, teamParams, myTeam.__TEAMITEMS); | |||
__LOG[2]("Ermittelt: " + safeStringify(myTeam)); | |||
// ... und abspeichern... | |||
setOpt(optSet.team, myTeam, false); | |||
} else { | |||
const __TEAM = getOptValue(optSet.team); // Gespeicherte Parameter | |||
if ((__TEAM !== undefined) && (__TEAM.Land !== undefined)) { | |||
addProps(myTeam, __TEAM, myTeam.__TEAMITEMS); | |||
__LOG[2]("Gespeichert: " + safeStringify(myTeam)); | |||
} else { | |||
__LOG[1]("Unbekannt: " + safeStringify(__TEAM)); | |||
} | |||
} | |||
//return ((myTeam.length > 0) ? myTeam : undefined); | |||
return myTeam; | |||
} | |||
// Behandelt die Optionen und laedt das Benutzermenu | |||
// optConfig: Konfiguration der Optionen | |||
// optSet: Platz fuer die gesetzten Optionen | |||
// optParams: Eventuell notwendige Parameter zur Initialisierung | |||
// 'hideMenu': Optionen werden zwar geladen und genutzt, tauchen aber nicht im Benutzermenu auf | |||
// 'Tab': Tabelle mit dem Spielplan | |||
// 'Zei': Startzeile des Spielplans mit dem ersten ZAT | |||
// 'Spa': Spalte der Tabellenzelle mit der Spielart (z.B. "Liga : Heim") | |||
// 'teamParams': Getrennte Daten-Option wird genutzt, hier: Team() mit 'LdNr'/'LgNr' des Erst- bzw. Zweitteams | |||
// 'menuAnchor': Startpunkt fuer das Optionsmenu auf der Seite | |||
// 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar) | |||
// 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar) | |||
// 'formWidth': Anzahl der Elemente pro Zeile | |||
// 'formBreak': Elementnummer des ersten Zeilenumbruchs | |||
// return Gefuelltes Objekt mit den gesetzten Optionen | |||
function buildOptions(optConfig, optSet = undefined, optParams = { 'hideMenu' : false }) { | |||
// Klassifikation ueber Land und Liga des Teams... | |||
__TEAMCLASS.optSet = optSet; // Classification mit optSet verknuepfen | |||
__TEAMCLASS.teamParams = optParams.teamParams; // Ermittelte Parameter | |||
optSet = startOptions(optConfig, optSet, __TEAMCLASS); | |||
// Werte aus der HTML-Seite ermitteln... | |||
const __BOXSAISONS = document.getElementsByTagName("option"); | |||
const __SAISON = getSaisonFromComboBox(__BOXSAISONS); | |||
const __LIGASIZE = getLigaSizeFromSpielplan(optParams.Tab.rows, optParams.Zei, optParams.Spa, getOptValue(optSet.saison)); | |||
// ... und abspeichern... | |||
setOpt(optSet.saison, __SAISON, false); | |||
setOpt(optSet.ligaSize, __LIGASIZE, false); | |||
showOptions(optSet, optParams); | |||
return optSet; | |||
} | |||
// ==================== Ende Abschnitt fuer Optionen ==================== | |||
// ==================== Abschnitt fuer Spielplan und ZATs ==================== | |||
// Beschreibungstexte aller Runden | |||
const __POKALRUNDEN = [ "", "1. Runde", "2. Runde", "3. Runde", "Achtelfinale", "Viertelfinale", "Halbfinale", "Finale" ]; | |||
const __QUALIRUNDEN = [ "", "Quali 1", "Quali 2", "Quali 3" ]; | |||
const __OSCRUNDEN = [ "", "Viertelfinale", "Halbfinale", "Finale" ]; | |||
const __OSERUNDEN = [ "", "Runde 1", "Runde 2", "Runde 3", "Runde 4", "Achtelfinale", "Viertelfinale", "Halbfinale", "Finale" ]; | |||
const __HINRUECK = [ " Hin", " R\xFCck", "" ]; | |||
// ==================== Abschnitt fuer Klasse RundenLink ==================== | |||
function RundenLink(saison, team) { | |||
'use strict'; | |||
this.uri = new URI("http://os.ongapo.com/?erganzeigen=1&stataktion=Statistik+ausgeben"); | |||
this.runde = 0; | |||
this.prop = ""; | |||
this.label = ""; | |||
if (saison) { | |||
this.setSaison(saison); | |||
} | |||
if (team) { | |||
this.setTeam(team); | |||
} | |||
} | |||
Class.define(RundenLink, Object, { | |||
'setSaison' : function(saison) { | |||
this.uri.setQueryPar('saauswahl', saison); | |||
}, | |||
'setTeam' : function(team) { | |||
this.uri.setQueryPar('landauswahl', team.LdNr); | |||
this.uri.setQueryPar('ligaauswahl', team.LgNr); | |||
}, | |||
'setPage' : function(page, label) { | |||
this.uri.home(); | |||
this.uri.down(page + ".php"); | |||
this.setLabel(label); | |||
}, | |||
'setRunde' : function(prop, runde) { | |||
this.prop = prop; | |||
this.runde = runde; | |||
}, | |||
'setLabel' : function(label) { | |||
this.label = (label || ""); | |||
}, | |||
'setAnzeigen' : function(show = true) { | |||
this.uri.setQueryPar('erganzeigen', (show ? 1 : 0)); | |||
}, | |||
'getLabel' : function() { | |||
return (this.label || "Link"); | |||
}, | |||
'getHTML' : function(target = undefined) { | |||
if ((this.runde <= 0) || (! this.uri.getLeaf())) { | |||
return this.label; | |||
} else { | |||
if (this.prop) { | |||
this.uri.setQueryPar(this.prop, this.runde); | |||
} | |||
return "<a " + URI.prototype.formatParams({ | |||
'href' : this.uri.getPath(), | |||
'target' : (target ? target : '_blank') | |||
}, function(value) { | |||
return '"' + value + '"'; | |||
}, ' ', '=') + '>' + this.getLabel() + "</a>"; | |||
} | |||
} | |||
}); | |||
// ==================== Ende Abschnitt fuer Klasse RundenLink ==================== | |||
// Liefert einen vor den ersten ZAT zurueckgesetzten Spielplanzeiger | |||
// saison: Enthaelt die Nummer der laufenden Saison | |||
// ligaSize: Anzahl der Teams in dieser Liga (Gegner + 1) | |||
// - ZATs pro Abrechnungsmonat | |||
// - Saison | |||
// - ZAT | |||
// - GameType | |||
// - Heim/Auswaerts | |||
// - Gegner | |||
// - Tore | |||
// - Gegentore | |||
// - Ligengroesse | |||
// - Ligaspieltag | |||
// - Pokalrunde | |||
// - Eurorunde | |||
// - Hin/Rueck | |||
// - ZAT Rueck | |||
// - ZAT Korr | |||
function firstZAT(saison, ligaSize) { | |||
return { | |||
'anzZATpMonth' : ((saison < 2) ? 7 : 6), // Erste Saison 7 ZAT, danach 6 ZAT... | |||
'saison' : saison, | |||
'ZAT' : 0, | |||
'gameType' : "spielfrei", | |||
'heim' : true, | |||
'gegner' : "", | |||
'gFor' : 0, | |||
'gAga' : 0, | |||
'ligaSize' : ligaSize, | |||
'ligaSpieltag' : 0, | |||
'pokalRunde' : 1, | |||
'euroRunde' : 0, | |||
'hinRueck' : 2, // 0: Hin, 1: Rueck, 2: unbekannt | |||
'ZATrueck' : 0, | |||
'ZATkorr' : 0 | |||
}; | |||
} | |||
// Liefert den ZAT als String | |||
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT | |||
// longStats: Formatiert die Langversion des Textes | |||
function getZAT(currZAT, longStats) { | |||
return (longStats ? currZAT.gameType + ' ' + (currZAT.heim ? "Heim" : "Ausw\xE4rts") + ' ' : "") + | |||
(longStats ? '[' + currZAT.ligaSpieltag + ' ' + currZAT.pokalRunde + ' ' + currZAT.euroRunde + "] " : "") + | |||
(longStats ? '[' + currZAT.ZATrueck + __HINRUECK[currZAT.hinRueck] + | |||
' ' + ((currZAT.ZATkorr < 0) ? "" : '+') + currZAT.ZATkorr + "] " : "") + | |||
(longStats ? currZAT.gegner + ((currZAT.gFor > -1) ? " (" + currZAT.gFor + " : " + currZAT.gAga + ')' : "") + ' ' : "") + | |||
'S' + currZAT.saison + "-Z" + ((currZAT.ZAT < 10) ? '0' : "") + currZAT.ZAT; | |||
} | |||
// Liefert die ZATs der Sonderspieltage fuer 10er- (2) und 20er-Ligen (4) | |||
// saison: Enthaelt die Nummer der laufenden Saison | |||
// return [ 10erHin, 10erRueck, 20erHin, 20erRueck ], ZAT-Nummern der Zusatzspieltage | |||
function getLigaExtra(saison) { | |||
if (saison < 3) { | |||
return [ 8, 64, 32, 46 ]; | |||
} else { | |||
return [ 9, 65, 33, 57 ]; | |||
} | |||
} | |||
// Spult die Daten um anzZAT ZATs vor und schreibt Parameter | |||
// anhand des Spielplans fort. Also Spieltag, Runde, etc. | |||
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT | |||
// anzZAT: Anzahl der ZAT, um die vorgespult wird | |||
function incZAT(currZAT, anzZAT = 1) { | |||
const __LIGAEXTRA = getLigaExtra(currZAT.saison); | |||
const __LIGAFIRST = 3 - (__LIGAEXTRA[0] % 2); | |||
for (let i = anzZAT; i > 0; i--) { | |||
currZAT.ZAT++; | |||
if ((currZAT.ZAT - __LIGAFIRST + 1) % 2 === 1) { | |||
currZAT.ligaSpieltag++; | |||
} else { | |||
const __POS = __LIGAEXTRA.indexOf(currZAT.ZAT); | |||
if (~ __POS) { | |||
if (__POS < 2 * (currZAT.ligaSize % 9)) { | |||
currZAT.ligaSpieltag++; | |||
} | |||
} | |||
} | |||
if ((currZAT.ZAT > 12) && ((currZAT.ZAT % 10) === 5)) { // passt fuer alle Saisons: 12, 20, 30, 40, 48, 58, 68 / 3, 15, 27, 39, 51, 63, 69 | |||
currZAT.pokalRunde++; | |||
} | |||
if (((currZAT.ZAT + currZAT.ZATkorr) % 6) === 4) { | |||
if (currZAT.ZAT < 63) { | |||
currZAT.ZATrueck = currZAT.ZAT + 2; | |||
currZAT.euroRunde++; | |||
currZAT.hinRueck = 0; | |||
} else { | |||
currZAT.euroRunde = 11; // Finale | |||
currZAT.hinRueck = 2; | |||
} | |||
} | |||
if (currZAT.ZAT === currZAT.ZATrueck) { | |||
currZAT.hinRueck = 1; // 5, 7; 11, 13; (17, 19) / 23, 25; 29, 31; 35, 37; 41, 43; 47, 49; 53, 55; 59, 61; 69 | |||
if (currZAT.saison < 3) { // 4, 6; 10, 14*; (16, 22*) / 24**, 26; 34, 36; 38*, 42; 44*, 50; 52, 54; 56*, 60; 62*, 66; 70 | |||
if (currZAT.ZAT === 22) { | |||
currZAT.ZATkorr = 4; | |||
} else if ((currZAT.ZAT - 6) % 20 > 6) { | |||
currZAT.ZATkorr = 2; | |||
} else { | |||
currZAT.ZATkorr = 0; | |||
} | |||
if ((currZAT.ZAT === 22) || (currZAT.ZAT === 30)) { | |||
currZAT.euroRunde--; // Frueher: 3. Quali-Rueckspiel erst knapp vor 1. Hauptrunde | |||
} | |||
} | |||
} | |||
} | |||
} | |||
// Liefert die Beschreibung des Spiels am aktuellen ZAT | |||
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT | |||
// showLink: Angabe, ob ein Link eingefuegt werden soll | |||
// return Beschreibung des Spiels | |||
function getZusatz(currZAT, showLink = true) { | |||
const __LINK = new RundenLink(currZAT.saison, __TEAMCLASS.team); | |||
if (currZAT.gameType === "Liga") { | |||
if (currZAT.ZAT < 70) { | |||
__LINK.setRunde("stauswahl", currZAT.ligaSpieltag); | |||
__LINK.setPage("ls", __LINK.runde + ". Spieltag"); | |||
} else { | |||
__LINK.setLabel("Relegation"); | |||
} | |||
} else if (currZAT.gameType === "LP") { | |||
__LINK.setRunde("stauswahl", currZAT.pokalRunde); | |||
__LINK.setPage("lp", __POKALRUNDEN[__LINK.runde]); | |||
} else if ((currZAT.gameType === "OSCQ") || (currZAT.gameType === "OSEQ")) { | |||
__LINK.setRunde("runde", currZAT.euroRunde); | |||
__LINK.setPage(((currZAT.gameType === "OSCQ") ? "oscq" : "oseq"), __QUALIRUNDEN[__LINK.runde] + __HINRUECK[currZAT.hinRueck]); | |||
} else if (currZAT.gameType === "OSC") { | |||
if (currZAT.euroRunde < 9) { | |||
const __GRUPPENPHASE = ((currZAT.euroRunde < 6) ? "HR-Grp. " : "ZR-Grp. "); | |||
__LINK.setRunde("", (currZAT.euroRunde % 3) * 2 + 1 + currZAT.hinRueck); | |||
__LINK.setPage(((currZAT.euroRunde < 6) ? "oschr" : "osczr"), __GRUPPENPHASE + "Spiel " + __LINK.runde); | |||
} else { | |||
__LINK.setPage("oscfr", __OSCRUNDEN[currZAT.euroRunde - 8] + __HINRUECK[currZAT.hinRueck]); | |||
} | |||
} else if (currZAT.gameType === "OSE") { | |||
__LINK.setRunde("runde", currZAT.euroRunde - 3); | |||
__LINK.setPage("ose", __OSERUNDEN[__LINK.runde] + __HINRUECK[currZAT.hinRueck]); | |||
} else { | |||
__LINK.setLabel(); // irgendwie besser lesbar! ("Friendly" bzw. "spielfrei"/"Frei"/"reserviert") | |||
} | |||
return (showLink ? __LINK.getHTML() : ""); | |||
} | |||
// ==================== Abschnitt fuer Statistiken des Spielplans ==================== | |||
// Liefert eine auf 0 zurueckgesetzte Ergebnissumme | |||
// - Siege | |||
// - Unentschieden | |||
// - Niederlagen | |||
// - Tore | |||
// - Gegentore | |||
// - Siegpunkte | |||
function emptyStats() { | |||
return { | |||
'S' : 0, | |||
'U' : 0, | |||
'N' : 0, | |||
'gFor' : 0, | |||
'gAga' : 0, | |||
'P' : 0 | |||
}; | |||
} | |||
// Liefert die Stats als String | |||
// stats: Enthaelt die summierten Stats | |||
// longStats: Formatiert die Langversion des Textes | |||
function getStats(stats, longStats) { | |||
return (longStats ? '[' + stats.S + ' ' + stats.U + ' ' + stats.N + "] " : "/ ") + | |||
stats.gFor + ':' + stats.gAga + ' ' + ((stats.gFor < stats.gAga) ? "" : (stats.gFor > stats.gAga) ? '+' : "") + | |||
(stats.gFor - stats.gAga) + " (" + stats.P + ')'; | |||
} | |||
// Summiert ein Ergebnis auf die Stats und liefert den neuen Text zurueck | |||
// stats: Enthaelt die summierten Stats | |||
// longStats: Formatiert die Langversion des Textes | |||
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT (mit dem Ergebnis) | |||
function addResultToStats(stats, longStats, currZAT) { | |||
let ret = ""; | |||
if (currZAT.gFor > -1) { | |||
let p = 0; | |||
if (currZAT.gFor > currZAT.gAga) { | |||
stats.S++; | |||
p = 3; | |||
} else if (currZAT.gFor === currZAT.gAga) { | |||
stats.U++; | |||
p = 1; | |||
} else { | |||
stats.N++; | |||
} | |||
stats.P += p; | |||
stats.gFor += currZAT.gFor; | |||
stats.gAga += currZAT.gAga; | |||
ret = getStats(stats, longStats); | |||
} | |||
return ret; | |||
} | |||
// ==================== Abschnitt fuer interne IDs auf den Seiten ==================== | |||
const __GAMETYPES = { // "Blind FSS gesucht!" | |||
'unbekannt' : -1, | |||
"reserviert" : 0, | |||
"Frei" : 0, | |||
"spielfrei" : 0, | |||
"Friendly" : 1, | |||
"Liga" : 2, | |||
"LP" : 3, | |||
"OSEQ" : 4, | |||
"OSE" : 5, | |||
"OSCQ" : 6, | |||
"OSC" : 7 | |||
}; | |||
const __LIGANRN = { | |||
'unbekannt' : 0, | |||
'1. Liga' : 1, | |||
'2. Liga A' : 2, | |||
'2. Liga B' : 3, | |||
'3. Liga A' : 4, | |||
'3. Liga B' : 5, | |||
'3. Liga C' : 6, | |||
'3. Liga D' : 7 | |||
}; | |||
const __LANDNRN = { | |||
'unbekannt' : 0, | |||
'Albanien' : 45, | |||
'Andorra' : 95, | |||
'Armenien' : 83, | |||
'Aserbaidschan' : 104, | |||
'Belgien' : 12, | |||
'Bosnien-Herzegowina' : 66, | |||
'Bulgarien' : 42, | |||
'D\xE4nemark' : 8, | |||
'Deutschland' : 6, | |||
'England' : 1, | |||
'Estland' : 57, | |||
'Far\xF6er' : 68, | |||
'Finnland' : 40, | |||
'Frankreich' : 32, | |||
'Georgien' : 49, | |||
'Griechenland' : 30, | |||
'Irland' : 5, | |||
'Island' : 29, | |||
'Israel' : 23, | |||
'Italien' : 10, | |||
'Kasachstan' : 105, | |||
'Kroatien' : 24, | |||
'Lettland' : 97, | |||
'Liechtenstein' : 92, | |||
'Litauen' : 72, | |||
'Luxemburg' : 93, | |||
'Malta' : 69, | |||
'Mazedonien' : 86, | |||
'Moldawien' : 87, | |||
'Niederlande' : 11, | |||
'Nordirland' : 4, | |||
'Norwegen' : 9, | |||
'\xD6sterreich' : 14, | |||
'Polen' : 25, | |||
'Portugal' : 17, | |||
'Rum\xE4nien' : 28, | |||
'Russland' : 19, | |||
'San Marino' : 98, | |||
'Schottland' : 2, | |||
'Schweden' : 27, | |||
'Schweiz' : 37, | |||
'Serbien und Montenegro' : 41, | |||
'Slowakei' : 70, | |||
'Slowenien' : 21, | |||
'Spanien' : 13, | |||
'Tschechien' : 18, | |||
'T\xFCrkei' : 39, | |||
'Ukraine' : 20, | |||
'Ungarn' : 26, | |||
'Wales' : 3, | |||
'Weissrussland' : 71, | |||
'Zypern' : 38 | |||
}; | |||
// ==================== Abschnitt fuer Daten des Spielplans ==================== | |||
// Gibt die ID fuer den Namen eines Wettbewerbs zurueck | |||
// gameType: Name des Wettbewerbs eines Spiels | |||
// return OS2-ID fuer den Spieltyp (1 bis 7), 0 fuer spielfrei/Frei/reserviert, -1 fuer ungueltig | |||
function getGameTypeID(gameType) { | |||
return getValue(__GAMETYPES[gameType], __GAMETYPES.unbekannt); | |||
} | |||
// Gibt die ID des Landes mit dem uebergebenen Namen zurueck. | |||
// land: Name des Landes | |||
// return OS2-ID des Landes, 0 fuer ungueltig | |||
function getLandNr(land) { | |||
return getValue(__LANDNRN[land], __LANDNRN.unbekannt); | |||
} | |||
// Gibt die ID der Liga mit dem uebergebenen Namen zurueck. | |||
// land: Name der Liga | |||
// return OS2-ID der Liga, 0 fuer ungueltig | |||
function getLigaNr(liga) { | |||
return getValue(__LIGANRN[liga], __LIGANRN.unbekannt); | |||
} | |||
// Ermittelt den Spielgegner aus einer Tabellenzelle und liefert den Namen zurueck | |||
// cell: Tabellenzelle mit dem Namen des Gegners | |||
// return Der Name des Gegners | |||
function getGegnerFromCell(cell) { | |||
const __GEGNER = cell.textContent; | |||
const __POS = __GEGNER.indexOf(" ("); | |||
if (~ __POS) { | |||
return __GEGNER.substr(0, __POS); | |||
} else { | |||
return __GEGNER; | |||
} | |||
} | |||
// Ermittelt das Spiel-Ergebnis aus einer Tabellenzelle, etwa "2 : 1", und liefert zwei Werte zurueck | |||
// cell: Tabellenzelle mit Eintrag "2 : 1" | |||
// return { '2', '1' } im Beispiel | |||
function getErgebnisFromCell(cell) { | |||
const __ERGEBNIS = cell.textContent.split(" : ", 2); | |||
return __ERGEBNIS; | |||
} | |||
// Ermittelt die Spielart aus einer Tabellenzelle, etwa "Liga : Heim", und liefert zwei Werte zurueck | |||
// cell: Tabellenzelle mit Eintrag "Liga : Heim" (Spielplan) oder "Liga Heim: " (Managerbuero) | |||
// return { "Liga", "Heim" } im Beispiel | |||
function getSpielArtFromCell(cell) { | |||
const __TEXT = cell.textContent.replace('\xA0', "").replace(':', "").replace(" ", ' '); | |||
const __SPIELART = __TEXT.split(' ', 2); | |||
return __SPIELART; | |||
} | |||
// Ermittelt den Namen des Spielgegners aus einer Tabellenzelle und setzt gegner im Spielplanzeiger | |||
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT | |||
// cell: Tabellenzelle mit dem Namen des Gegners | |||
function setGegnerFromCell(currZAT, cell) { | |||
const __GEGNER = getGegnerFromCell(cell); | |||
currZAT.gegner = __GEGNER; | |||
} | |||
// Ermittelt das Spiel-Ergebnis aus einer Tabellenzelle und setzt tore/gtore im Spielplanzeiger | |||
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT | |||
// cell: Tabellenzelle mit Eintrag "2 : 1" | |||
function setErgebnisFromCell(currZAT, cell) { | |||
const __ERGEBNIS = getErgebnisFromCell(cell); | |||
if (__ERGEBNIS.length === 2) { | |||
currZAT.gFor = parseInt(__ERGEBNIS[0], 10); | |||
currZAT.gAga = parseInt(__ERGEBNIS[1], 10); | |||
} else { | |||
currZAT.gFor = -1; | |||
currZAT.gAga = -1; | |||
} | |||
} | |||
// Ermittelt die Spielart aus einer Tabellenzelle und setzt gameType/heim im Spielplanzeiger | |||
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT | |||
// cell: Tabellenzelle mit Eintrag "Liga : Heim" oder "Liga Heim" | |||
function setSpielArtFromCell(currZAT, cell) { | |||
const __SPIELART = getSpielArtFromCell(cell); | |||
currZAT.gameType = __SPIELART[0]; | |||
currZAT.heim = (__SPIELART.length < 2) || (__SPIELART[1] === "Heim"); | |||
} | |||
// Gibt die ID fuer den Namen eines Wettbewerbs zurueck | |||
// cell: Tabellenzelle mit Link auf den Spielberichts-Link | |||
// gameType: Name des Wettbewerbs eines Spiels | |||
// label: Anzuklickender Text des neuen Links | |||
// return HTML-Link auf die Preview-Seite fuer diesen Spielbericht | |||
function getBilanzLinkFromCell(cell, gameType, label) { | |||
const __GAMETYPEID = getGameTypeID(gameType); | |||
let ret = ""; | |||
if (cell.textContent !== "Vorschau") { // Nur falls Link nicht bereits vorhanden | |||
if (__GAMETYPEID > 1) { // nicht moeglich fuer "Friendly" bzw. "spielfrei"/"Frei"/"reserviert" | |||
const __SEARCHFUN = ":os_bericht("; | |||
let paarung = cell.innerHTML.substr(cell.innerHTML.indexOf(__SEARCHFUN) + __SEARCHFUN.length); | |||
paarung = paarung.substr(0, paarung.indexOf(')')); | |||
paarung = paarung.substr(0, paarung.lastIndexOf(',')); | |||
paarung = paarung.substr(0, paarung.lastIndexOf(',')); | |||
ret = ' <a href="javascript:spielpreview(' + paarung + ',' + __GAMETYPEID + ')">' + label + "</a>"; | |||
} | |||
} | |||
return ret; | |||
} | |||
// Addiert einen Link auf die Bilanz hinter den Spielberichts-Link | |||
// cell: Tabellenzelle mit Link auf den Spielberichts-Link | |||
// gameType: Name des Wettbewerbs eines Spiels | |||
// label: Anzuklickender Text des neuen Links | |||
function addBilanzLinkToCell(cell, gameType, label) { | |||
const __BILANZLINK = getBilanzLinkFromCell(cell, gameType, label); | |||
if (__BILANZLINK !== "") { | |||
cell.innerHTML += __BILANZLINK; | |||
} | |||
} | |||
// ==================== Abschnitt fuer sonstige Parameter des Spielplans ==================== | |||
const __TEAMSEARCHHAUPT = { // Parameter zum Team "<b>Willkommen im Managerbüro von TEAM</b><br>LIGA LAND<a href=..." | |||
'Zeile' : 0, | |||
'Spalte' : 1, | |||
'start' : " von ", | |||
'middle' : "</b><br>", | |||
'liga' : ". Liga", | |||
'land' : ' ', | |||
'end' : "<a href=" | |||
}; | |||
const __TEAMSEARCHTEAM = { // Parameter zum Team "<b>TEAM - LIGA <a href=...>LAND</a></b>" | |||
'Zeile' : 0, | |||
'Spalte' : 0, | |||
'start' : "<b>", | |||
'middle' : " - ", | |||
'liga' : ". Liga", | |||
'land' : 'target="_blank">', | |||
'end' : "</a></b>" | |||
}; | |||
// Ermittelt, wie das eigene Team heisst und aus welchem Land bzw. Liga es kommt (zur Unterscheidung von Erst- und Zweitteam) | |||
// cell: Tabellenzelle mit den Parametern zum Team "startTEAMmiddleLIGA...landLANDend", LIGA = "#liga[ (A|B|C|D)]" | |||
// teamSeach: Muster fuer die Suche, die Eintraege fuer 'start', 'middle', 'liga', 'land' und 'end' enthaelt | |||
// return Im Beispiel { 'Team' : "TEAM", 'Liga' : "LIGA", 'Land' : "LAND", 'LdNr' : LAND-NUMMER, 'LgNr' : LIGA-NUMMER }, | |||
// z.B. { 'Team' : "Choromonets Odessa", 'Liga' : "1. Liga", 'Land' : "Ukraine", 'LdNr' : 20, 'LgNr' : 1 } | |||
function getTeamParamsFromTable(table, teamSearch = undefined) { | |||
const __TEAMSEARCH = getValue(teamSearch, __TEAMSEARCHHAUPT); | |||
const __TEAMCELLROW = getValue(__TEAMSEARCH.Zeile, 0); | |||
const __TEAMCELLCOL = getValue(__TEAMSEARCH.Spalte, 0); | |||
const __TEAMCELLSTR = (table === undefined) ? "" : table.rows[__TEAMCELLROW].cells[__TEAMCELLCOL].innerHTML; | |||
const __SEARCHSTART = __TEAMSEARCH.start; | |||
const __SEARCHMIDDLE = __TEAMSEARCH.middle; | |||
const __SEARCHLIGA = __TEAMSEARCH.liga; | |||
const __SEARCHLAND = __TEAMSEARCH.land; | |||
const __SEARCHEND = __TEAMSEARCH.end; | |||
const __INDEXSTART = __TEAMCELLSTR.indexOf(__SEARCHSTART); | |||
const __INDEXEND = __TEAMCELLSTR.indexOf(__SEARCHEND); | |||
let teamParams = __TEAMCELLSTR.substring(__INDEXSTART + __SEARCHSTART.length, __INDEXEND); | |||
const __INDEXLIGA = teamParams.indexOf(__SEARCHLIGA); | |||
const __INDEXMIDDLE = teamParams.indexOf(__SEARCHMIDDLE); | |||
let land = (~ __INDEXLIGA) ? teamParams.substring(__INDEXLIGA + __SEARCHLIGA.length) : undefined; | |||
const __TEAMNAME = (~ __INDEXMIDDLE) ? teamParams.substring(0, __INDEXMIDDLE) : undefined; | |||
let liga = ((~ __INDEXLIGA) && (~ __INDEXMIDDLE)) ? teamParams.substring(__INDEXMIDDLE + __SEARCHMIDDLE.length) : undefined; | |||
if (land !== undefined) { | |||
if (land.charAt(2) === ' ') { // Land z.B. hinter "2. Liga A " statt "1. Liga " | |||
land = land.substr(2); | |||
} | |||
if (liga !== undefined) { | |||
liga = liga.substring(0, liga.length - land.length); | |||
} | |||
const __INDEXLAND = land.indexOf(__SEARCHLAND); | |||
if (~ __INDEXLAND) { | |||
land = land.substr(__INDEXLAND + __SEARCHLAND.length); | |||
} | |||
} | |||
const __TEAM = new Team(__TEAMNAME, land, liga); | |||
return __TEAM; | |||
} | |||
// Verarbeitet die URL der Seite und ermittelt die Nummer der gewuenschten Unterseite | |||
// url: Adresse der Seite | |||
// leafs: Liste von Filenamen mit der Default-Seitennummer (falls Query-Parameter nicht gefunden) | |||
// item: Query-Parameter, der die Nummer der Unterseite angibt | |||
// return Parameter aus der URL der Seite als Nummer | |||
function getPageIdFromURL(url, leafs, item = "page") { | |||
const __URI = new URI(url); | |||
const __LEAF = __URI.getLeaf(); | |||
for (let leaf in leafs) { | |||
if (__LEAF === leaf) { | |||
const __DEFAULT = leafs[leaf]; | |||
return getValue(__URI.getQueryPar(item), __DEFAULT); | |||
} | |||
} | |||
return -1; | |||
} | |||
// Verarbeitet die URL der Seite und ermittelt die Nummer der gewuenschten Unterseite | |||
// saisons: Alle "option"-Eintraege der Combo-Box | |||
// return Nummer der ausgewaehlten Saison (Default: 0) | |||
function getSaisonFromComboBox(saisons) { | |||
let saison = 0; | |||
for (let i = 0; i < saisons.length; i++) { | |||
const __SAISON = saisons[i]; | |||
if (__SAISON.outerHTML.match(/selected/)) { | |||
saison = __SAISON.textContent; | |||
} | |||
} | |||
return saison; | |||
} | |||
// Ermittelt aus dem Spielplan die Ligengroesse ueber die Sonderspieltage | |||
// rows: Tabellenzeilen mit dem Spielplan | |||
// startIdx: Index der Zeile mit dem ersten ZAT | |||
// colArtIdx: Index der Spalte der Tabellenzelle mit der Spielart (z.B. "Liga : Heim") | |||
// saison: Enthaelt die Nummer der laufenden Saison | |||
// return 10 bei 36 Spielen, 18 bei 34 Spielen, 20 bei 38 Spielen | |||
function getLigaSizeFromSpielplan(rows, startIdx, colArtIdx, saison) { | |||
const __LIGAEXTRA = getLigaExtra(saison); | |||
const __TEST10ER = getSpielArtFromCell(rows[startIdx + __LIGAEXTRA[0] - 1].cells[colArtIdx]); | |||
const __TEST20ER = getSpielArtFromCell(rows[startIdx + __LIGAEXTRA[2] - 1].cells[colArtIdx]); | |||
if (__TEST20ER[0] === "Liga") { | |||
return 20; | |||
} else if (__TEST10ER[0] === "Liga") { | |||
return 10; | |||
} else { | |||
return 18; | |||
} | |||
} | |||
// ==================== Ende Abschnitt fuer Spielplan und ZATs ==================== | |||
// ==================== Hauptprogramm ==================== | |||
// Verarbeitet Ansicht "Saisonplan" | |||
function procSpielplan() { | |||
const __ROWOFFSETUPPER = 1; // Header-Zeile | |||
const __ROWOFFSETLOWER = 0; | |||
const __COLUMNINDEX = { | |||
'Art' : 1, | |||
'Geg' : 2, | |||
'Erg' : 3, | |||
'Ber' : 4, | |||
'Zus' : 5, | |||
'Kom' : 6 | |||
}; | |||
const __TEAMPARAMS = getTeamParamsFromTable(getTable(1), __TEAMSEARCHTEAM); // Link mit Team, Liga, Land... | |||
buildOptions(__OPTCONFIG, __OPTSET, { | |||
'Tab' : getTable(2), | |||
'Zei' : __ROWOFFSETUPPER, | |||
'Spa' : __COLUMNINDEX.Art, | |||
'teamParams' : __TEAMPARAMS, | |||
'menuAnchor' : getTable(0, "div"), | |||
'hideForm' : { | |||
'team' : true | |||
}, | |||
'formWidth' : 3, | |||
'formBreak' : 4 | |||
}); | |||
const __ZAT = firstZAT(getOptValue(__OPTSET.saison), getOptValue(__OPTSET.ligaSize)); | |||
const __ROWS = getRows(2); | |||
let ligaStats = emptyStats(); | |||
let euroStats = emptyStats(); | |||
for (let i = __ROWOFFSETUPPER; i < __ROWS.length - __ROWOFFSETLOWER; i++) { | |||
const __CELLS = __ROWS[i].cells; // Aktuelle Eintraege | |||
incZAT(__ZAT); | |||
setGegnerFromCell(__ZAT, __CELLS[__COLUMNINDEX.Geg]); | |||
setSpielArtFromCell(__ZAT, __CELLS[__COLUMNINDEX.Art]); | |||
setErgebnisFromCell(__ZAT, __CELLS[__COLUMNINDEX.Erg]); | |||
if (getOptValue(__OPTSET.shortKom)) { | |||
const __CELLKOM = __CELLS[__COLUMNINDEX.Kom]; | |||
const __CELLART = __CELLS[__COLUMNINDEX.Art]; | |||
__CELLKOM.innerHTML = __CELLKOM.innerHTML.replace("Vorbericht(e)", 'V').replace("Kommentar(e)", 'K').replace("&amp;", '/').replace('&', '/'); | |||
__CELLART.innerHTML = __CELLART.innerHTML.replace(": Heim", "(H)").replace(": Ausw\xE4rts", "(A)").replace("Friendly", "FSS"); | |||
} | |||
__CELLS[__COLUMNINDEX.Zus].className = __CELLS[__COLUMNINDEX.Art].className; | |||
if (__CELLS[__COLUMNINDEX.Zus].textContent === "") { | |||
const __CELLBER = __CELLS[__COLUMNINDEX.Ber]; | |||
let stats = ""; | |||
addBilanzLinkToCell(__CELLBER, __ZAT.gameType, "Bilanz"); | |||
if (getOptValue(__OPTSET.shortKom)) { | |||
__CELLBER.innerHTML = __CELLBER.innerHTML.replace("Klick", "(*)").replace("Bilanz", 'V').replace("Vorschau", 'V'); | |||
} | |||
if (__ZAT.gameType === "Liga") { | |||
if (__ZAT.ZAT < 70) { | |||
stats = addResultToStats(ligaStats, getOptValue(__OPTSET.longStats), __ZAT); | |||
} | |||
} else if ((__ZAT.gameType === "OSCQ") || (__ZAT.gameType === "OSEQ") || (__ZAT.gameType === "OSE")) { | |||
if (__ZAT.hinRueck !== 1) { | |||
euroStats = emptyStats(); | |||
} | |||
stats = addResultToStats(euroStats, getOptValue(__OPTSET.longStats), __ZAT); | |||
} else if (__ZAT.gameType === "OSC") { | |||
if ((__ZAT.hinRueck !== 1) && ((__ZAT.euroRunde >= 9) || ((__ZAT.euroRunde % 3) === 0))) { | if ((__ZAT.hinRueck !== 1) && ((__ZAT.euroRunde >= 9) || ((__ZAT.euroRunde % 3) === 0))) { | ||
euroStats = emptyStats(); | euroStats = emptyStats(); | ||
} | } | ||
stats = addResultToStats(euroStats, getOptValue(__OPTSET.longStats), __ZAT); | stats = addResultToStats(euroStats, getOptValue(__OPTSET.longStats), __ZAT); | ||
} | } | ||
if (getOptValue(__OPTSET.showStats)) { | |||
if (stats !== "") { | |||
stats = ' ' + stats; | |||
} | |||
} else { | |||
stats = ""; | |||
} | |||
__CELLS[__COLUMNINDEX.Zus].innerHTML = getZusatz(__ZAT, true) + stats; | |||
} | |||
if (getOptValue(__OPTSET.sepMonths) && (__ZAT.ZAT % __ZAT.anzZATpMonth === 0) && (i < __ROWS.length - __ROWOFFSETLOWER - 1)) { | |||
// Format der Trennlinie zwischen den Monaten... | |||
const __BORDERSTRING = getOptValue(__OPTSET.sepStyle) + ' ' + getOptValue(__OPTSET.sepColor) + ' ' + getOptValue(__OPTSET.sepWidth); | |||
/* | |||
for (let entry of __CELLS) { | |||
entry.style.borderBottom = __BORDERSTRING; | |||
} | |||
*/ | |||
for (let j = 0; j < __CELLS.length; j++) { | |||
__CELLS[j].style.borderBottom = __BORDERSTRING; | |||
} | |||
} | |||
} | |||
} | |||
try { | |||
// URL-Legende: | |||
// s=0: Teamuebersicht | |||
// s=1: Vertragsdaten | |||
// s=2: Einzelwerte | |||
// s=3: Statistik Saison | |||
// s=4: Statistik Gesamt | |||
// s=5: Teaminfo | |||
// s=6: Saisonplan | |||
// s=7: Vereinshistorie | |||
// s=8: Transferhistorie | |||
// s=9: Leihhistorie | |||
/ | // Verzweige in unterschiedliche Verarbeitungen je nach Wert von s: | ||
switch (getPageIdFromURL(window.location.href, { | |||
'showteam.php' : 0, // Teamansicht Hauptfenster | |||
'st.php' : 0 // Teamansicht Popupfenster | |||
}, 's')) { | |||
case 6 : procSpielplan(); break; | |||
default : break; | |||
} | } | ||
} catch (ex) { | |||
showAlert('[' + ex.lineNumber + "] " + __DBMOD.Name, ex.message, ex); | |||
} finally { | |||
__LOG[2]("SCRIPT END"); | |||
} | } | ||
// *** EOF *** | // *** EOF *** | ||
</pre> | </pre> | ||
Version vom 20. November 2016, 21:08 Uhr
| OS2.spielplan | |
| Dateiname | OS2.spielplan.user.js |
| Version | 0.70 |
| Autor | Sven Loges (SLC), Choromonets Odessa |
| Beschreibung | Strukturiert und erweitert die Spielplananzeige eines OS2-Teams |
| Webseiten | showteam.php?s=6 st.php?s=6 Saisonplan |
| Funktionalität | Trennstriche zwischen den Abrechnungsmonaten Verkürzung von "Vorbericht(e)" und "Kommentar(e)" Details zu den Spielen Ergebnisse aufaddieren Nachträgliche Vorschau: Bilanz Benutzermenü für Optionen Erweiterte Optionen auch auf der Seite Link auf den jeweiligen Spieltag bzw. die jeweilige Runde Interaktive Menü-Optionen Gemeinsame Code- und Datenbasis |
| Letzte Änderung | 20.11.2016 |
// ==UserScript==
// @name OS2.spielplan
// @namespace http://os.ongapo.com/
// @version 0.70
// @copyright 2013+
// @author Sven Loges (SLC)
// @description Spielplan-Abschnitt aus dem Master-Script fuer Online Soccer 2.0
// @include http*://os.ongapo.com/st.php?s=*
// @include http*://os.ongapo.com/showteam.php?s=*
// @include http*://www.os.ongapo.com/st.php?s=*
// @include http*://www.os.ongapo.com/showteam.php?s=*
// @include http*://online-soccer.eu/st.php?s=*
// @include http*://online-soccer.eu/showteam.php?s=*
// @include http*://www.online-soccer.eu/st.php?s=*
// @include http*://www.online-soccer.eu/showteam.php?s=*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_registerMenuCommand
// @grant GM_info
// ==/UserScript==
// ECMAScript 6: Erlaubt 'const', 'let', ...
/* jshint esnext: true */
/* jshint moz: true */
// ==================== Konfigurations-Abschnitt fuer Optionen ====================
const __LOGLEVEL = 3;
// Options-Typen
const __OPTTYPES = {
'MC' : "multiple choice",
'SW' : "switch",
'TF' : "true/false",
'SD' : "simple data",
'SI' : "simple option"
};
// Options-Typen
const __OPTACTION = {
'SET' : "set option value",
'NXT' : "set next option value",
'RST' : "reset options"
};
const __OPTMEM = {
'normal' : {
'Name' : "Browser",
'Value' : localStorage,
'Display' : "localStorage",
'Prefix' : 'run'
},
'begrenzt' : {
'Name' : "Session",
'Value' : sessionStorage,
'Display' : "sessionStorage",
'Prefix' : 'run'
},
'inaktiv' : {
'Name' : "inaktiv",
'Value' : undefined,
'Display' : "",
'Prefix' : ""
}
};
// Moegliche Optionen (hier die Standardwerte editieren oder ueber das Benutzermenu setzen):
const __OPTCONFIG = {
'longStats' : { // Detailliertere Ausgabe des Stands
'Name' : "longStats",
'Type' : __OPTTYPES.SW,
'Default' : false,
'Action' : __OPTACTION.NXT,
'Label' : "Lange Stats",
'Hotkey' : 'L',
'AltLabel' : "Kurze Stats",
'AltHotkey' : 'K',
'FormLabel' : "Lange Stats"
},
'showStats' : { // Ergebnisse aufaddieren und Stand anzeigen
'Name' : "showStats",
'Type' : __OPTTYPES.SW,
'Default' : true,
'Action' : __OPTACTION.NXT,
'Label' : "Stats ein",
'Hotkey' : 'S',
'AltLabel' : "Stats aus",
'AltHotkey' : 'S',
'FormLabel' : "Statistik"
},
'shortKom' : { // "Vorbericht(e) & Kommentar(e)" nicht ausschreiben
'Name' : "shortKom",
'Type' : __OPTTYPES.SW,
'Default' : true,
'Action' : __OPTACTION.NXT,
'Label' : "Kurze Texte",
'Hotkey' : 'T',
'AltLabel' : "Lange Texte",
'AltHotkey' : 'T',
'FormLabel' : "Abk\xFCrzungen"
},
'sepMonths' : { // Im Spielplan Trennstriche zwischen den Monaten
'Name' : "sepMonths",
'Type' : __OPTTYPES.SW,
'Default' : true,
'Action' : __OPTACTION.NXT,
'Label' : "Monate trennen",
'Hotkey' : 'M',
'AltLabel' : "Keine Monate",
'AltHotkey' : 'M',
'FormLabel' : "Monate trennen"
},
'sepStyle' : { // Stil der Trennlinie
'Name' : "sepStyle",
'Type' : __OPTTYPES.MC,
'ValType' : "String",
'Choice' : [ "solid", "hidden", "dotted", "dashed", "double", "groove", "ridge",
"inset", "outset", "none" ],
'Action' : __OPTACTION.NXT,
'Label' : "Stil: $",
'Hotkey' : 'i',
'FormLabel' : "Stil:|$"
},
'sepColor' : { // Farbe der Trennlinie
'Name' : "sepColor",
'Type' : __OPTTYPES.MC,
'ValType' : "String",
'FreeValue' : true,
'Choice' : [ "white", "yellow", "black", "blue", "cyan", "gold", "grey", "green",
"lime", "magenta", "maroon", "navy", "olive", "orange", "purple",
"red", "teal", "transparent" ],
'Action' : __OPTACTION.NXT,
'Label' : "Farbe: $",
'Hotkey' : 'F',
'FormLabel' : "Farbe:|$"
},
'sepWidth' : { // Dicke der Trennlinie
'Name' : "sepWidth",
'Type' : __OPTTYPES.MC,
'ValType' : "String",
'FreeValue' : true,
'Choice' : [ "thin", "medium", "thick" ],
'Action' : __OPTACTION.NXT,
'Label' : "Dicke: $",
'Hotkey' : 'D',
'FormLabel' : "Dicke:|$"
},
'saison' : { // Laufende Saison
'Name' : "saison",
'Type' : __OPTTYPES.MC,
'ValType' : "Number",
'FreeValue' : true,
'SelValue' : false,
'Choice' : [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ],
'Default' : 10,
'Action' : __OPTACTION.NXT,
'Label' : "Saison: $",
'Hotkey' : 'a',
'FormLabel' : "Saison:|$"
},
'ligaSize' : { // Ligengroesse
'Name' : "ligaSize",
'Type' : __OPTTYPES.MC,
'ValType' : "Number",
'AutoReset' : true,
'Choice' : [ 10, 18, 20 ],
'Action' : __OPTACTION.NXT,
'Label' : "Liga: $er",
'Hotkey' : 'i',
'FormLabel' : "Liga:|$er"
},
'team' : { // Datenspeicher fuer Daten des Erst- bzw. Zweitteams
'Name' : "team",
'Type' : __OPTTYPES.SD,
'Hidden' : false,
'Serial' : true,
'Permanent' : true,
'Default' : undefined, // new Team() // { 'Team' : undefined, 'Liga' : undefined, 'Land' : undefined, 'LdNr' : 0, 'LgNr' : 0 }
'Submit' : undefined,
'Cols' : 36,
'Rows' : 6,
'Replace' : null,
'Space' : 1,
'Label' : "Verein:"
},
'reset' : { // Optionen auf die "Werkseinstellungen" zuruecksetzen
'Name' : "reset",
'Type' : __OPTTYPES.SI,
'Action' : __OPTACTION.RST,
'Label' : "Standard-Optionen",
'Hotkey' : 'O',
'FormLabel' : ""
},
'storage' : { // Browserspeicher fuer die Klicks auf Optionen
'Name' : "storage",
'Type' : __OPTTYPES.MC,
'ValType' : "String",
'Choice' : Object.keys(__OPTMEM),
'Action' : __OPTACTION.NXT,
'Label' : "Speicher: $",
'Hotkey' : 'c',
'FormLabel' : "Speicher:|$"
},
'oldStorage' : { // Vorheriger Browserspeicher fuer die Klicks auf Optionen
'Name' : "oldStorage",
'Type' : __OPTTYPES.SD,
'PreInit' : true,
'AutoReset' : true,
'Hidden' : true
},
'showForm' : { // Optionen auf der Webseite (true = anzeigen, false = nicht anzeigen)
'Name' : "showForm",
'Type' : __OPTTYPES.SW,
'FormType' : __OPTTYPES.SI,
'Permanent' : true,
'Default' : false,
'Action' : __OPTACTION.NXT,
'Label' : "Optionen anzeigen",
'Hotkey' : 'a',
'AltLabel' : "Optionen verbergen",
'AltHotkey' : 'v',
'FormLabel' : ""
}
};
// ==================== Invarianter Abschnitt fuer Optionen ====================
// Kompatibilitaetsfunktion zur Ermittlung des Namens einer Funktion (falle <Function>.name nicht vorhanden ist)
if (Function.prototype.name === undefined) {
Object.defineProperty(Function.prototype, 'name', {
get : function() {
return /function ([^(\s]*)/.exec(this.toString())[1];
}
});
}
// Ein Satz von Logfunktionen, die je nach Loglevel zur Verfuegung stehen. Aufruf: __LOG[level](text)
const __LOG = {
'logFun' : [
console.error, // [0] Alert
console.error, // [1] Error
console.log, // [2] Log: Release
console.log, // [3] Log: Info
console.log, // [4] Log: Debug
console.log, // [5] Log: Verbose
console.log // [6] Log: Very verbose
],
'init' : function(win, logLevel = 1) {
for (level = 0; level < this.logFun.length; level++) {
this[level] = ((level > logLevel) ? function() { } : this.logFun[level]);
}
},
'changed' : function(oldVal, newVal) {
const __OLDVAL = safeStringify(oldVal);
const __NEWVAL = safeStringify(newVal);
return ((__OLDVAL !== __NEWVAL) ? __OLDVAL + " => " : "") + __NEWVAL;
}
};
__LOG.init(window, __LOGLEVEL);
// Gibt eine Meldung in der Console aus und oeffnet ein Bestaetigungsfenster mit der Meldung
// label: Eine Ueberschrift
// message: Der Meldungs-Text
// data: Ein Wert. Ist er angegeben, wird er in der Console ausgegeben
function showAlert(label, message, data = undefined) {
__LOG[1](label + ": " + message);
if (data !== undefined) {
__LOG[2](data);
}
alert(label + "\n\n" + message);
}
// ==================== Abschnitt fuer Klasse Class ====================
function Class(className, baseClass, initFun) {
'use strict';
try {
const __BASE = ((baseClass !== undefined) ? baseClass : Object);
const __BASEPROTO = (__BASE ? __BASE.prototype : undefined);
const __BASECLASS = (__BASEPROTO ? __BASEPROTO.__class : undefined);
this.className = (className || '?');
this.baseClass = __BASECLASS;
Object.setConst(this, 'baseProto', __BASEPROTO, false);
if (! initFun) {
const __BASEINIT = (__BASECLASS || { }).init;
if (__BASEINIT) {
initFun = function() {
// Basisklassen-Init aufrufen...
return __BASEINIT.call(this, arguments);
};
} else {
initFun = function() {
// Basisklassen-Init fehlt (und Basisklasse ist nicht Object)...
return false;
};
}
}
console.assert((__BASE === null) || ((typeof __BASE) === 'function'), "No function:", __BASE);
console.assert((typeof initFun) === 'function', "No function:", initFun);
this.init = initFun;
} catch (ex) {
showAlert('[' + ex.lineNumber + "] Error in Class " + className, ex.message, ex);
}
}
Class.define = function(subClass, baseClass, members = undefined, initFun = undefined, createProto = true) {
return (subClass.prototype = subClass.subclass(baseClass, members, initFun, createProto));
};
Object.setConst = function(obj, item, value, config) {
return Object.defineProperty(obj, item, {
enumerable : false,
configurable : (config || true),
writable : false,
value : value
});
};
Object.setConst(Object.prototype, 'subclass', function(baseClass, members, initFun, createProto) {
'use strict';
try {
const __MEMBERS = (members || { });
const __CREATEPROTO = ((createProto === undefined) ? true : createProto);
console.assert((typeof this) === 'function');
console.assert((typeof __MEMBERS) === 'object');
const __CLASS = new Class(this.name || __MEMBERS.__name, baseClass, initFun || __MEMBERS.__init);
const __PROTO = (__CREATEPROTO ? Object.create(__CLASS.baseProto) : this.prototype);
for (let item in __MEMBERS) {
if ((item !== '__name') && (item !== '__init')) {
Object.setConst(__PROTO, item, __MEMBERS[item]);
}
}
Object.setConst(__PROTO, '__class', __CLASS, ! __CREATEPROTO);
return __PROTO;
} catch (ex) {
showAlert('[' + ex.lineNumber + "] Error in subclassing", ex.message, ex);
}
}, false);
Class.define(Object, null, {
'__init' : function() {
// Oberstes Basisklassen-Init...
return true;
},
'getClass' : function() {
return this.__class;
},
'getClassName' : function() {
const __CLASS = this.getClass();
return (__CLASS ? __CLASS.getName() : undefined);
},
'setConst' : function(item, value, config = undefined) {
return Object.setConst(this, item, value, config);
}
}, undefined, false);
Class.define(Function, Object);
Class.define(Class, Object, {
'getName' : function() {
return this.className;
}
} );
// ==================== Ende Abschnitt fuer Klasse Class ====================
// ==================== Abschnitt fuer Klasse Delims ====================
// Basisklasse fuer die Verwaltung der Trennzeichen und Symbole von Pfaden
// delim: Trennzeichen zwischen zwei Ebenen (oder Objekt/Delims mit entsprechenden Properties)
// back: (Optional) Name des relativen Vaterverzeichnisses
// root: (Optional) Kennung vor dem ersten Trenner am Anfang eines absoluten Pfads
// home: (Optional) Kennung vor dem ersten Trenner am Anfang eines Pfads relativ zu Home
function Delims(delim, back, root, home) {
'use strict';
if ((typeof delim) === 'object') {
// Erster Parameter ist Objekt mit den Properties...
if (back === undefined) {
back = delim.back;
}
if (root === undefined) {
root = delim.root;
}
if (home === undefined) {
home = delim.home;
}
delim = delim.delim;
}
this.setDelim(delim);
this.setBack(back);
this.setRoot(root);
this.setHome(home);
}
Class.define(Delims, Object, {
'setDelim' : function(delim = undefined) {
this.delim = delim;
},
'setBack' : function(back = undefined) {
this.back = back;
},
'setRoot' : function(root = undefined) {
this.root = root;
},
'setHome' : function(home = undefined) {
this.home = home;
}
} );
// ==================== Ende Abschnitt fuer Klasse Delims ====================
// ==================== Abschnitt fuer Klasse UriDelims ====================
// Basisklasse fuer die Verwaltung der Trennzeichen und Symbole von URIs
// delim: Trennzeichen zwischen zwei Ebenen (oder Objekt/Delims mit entsprechenden Properties)
// back: (Optional) Name des relativen Vaterverzeichnisses
// root: (Optional) Kennung vor dem ersten Trenner am Anfang eines absoluten Pfads
// home: (Optional) Kennung vor dem ersten Trenner am Anfang eines Pfads relativ zu Home
// scheme: (Optional) Trennzeichen fuer den Schema-/Protokollnamen vorne
// host: (Optional) Prefix fuer Hostnamen hinter dem Scheme-Trenner
// port: (Optional) Trennzeichen vor der Portangabe, falls vorhanden
// query: (Optional) Trennzeichen fuer die Query-Parameter hinter dem Pfad
// parSep: (Optional) Trennzeichen zwischen je zwei Parametern
// parAss: (Optional) Trennzwischen zwischen Key und Value
// node: (Optional) Trennzeichen fuer den Knotennamen hinten (Fragment, Kapitel)
function UriDelims(delim, back, root, home, scheme, host, port, query, qrySep, qryAss, node) {
'use strict';
if ((typeof delim) === 'object') {
// Erster Parameter ist Objekt mit den Properties...
if (scheme === undefined) {
scheme = delim.scheme;
}
if (host === undefined) {
host = delim.host;
}
if (port === undefined) {
port = delim.port;
}
if (query === undefined) {
query = delim.query;
}
if (qrySep === undefined) {
qrySep = delim.qrySep;
}
if (qryAss === undefined) {
qryAss = delim.qryAss;
}
if (node === undefined) {
node = delim.node;
}
}
Delims.call(this, delim, back, root, home);
this.setScheme(scheme);
this.setHost(host);
this.setPort(port);
this.setQuery(query);
this.setQrySep(qrySep);
this.setQryAss(qryAss);
this.setNode(node);
}
Class.define(UriDelims, Delims, {
'setScheme' : function(scheme = undefined) {
this.scheme = scheme;
},
'setHost' : function(host = undefined) {
this.host = host;
},
'setPort' : function(port = undefined) {
this.port = port;
},
'setQuery' : function(query = undefined) {
this.query = query;
},
'setQrySep' : function(qrySep = undefined) {
this.qrySep = qrySep;
},
'setQryAss' : function(qryAss = undefined) {
this.qryAss = qryAss;
},
'setNode' : function(node = undefined) {
this.node = node;
}
} );
// ==================== Ende Abschnitt fuer Klasse UriDelims ====================
// ==================== Abschnitt fuer Klasse Path ====================
// Basisklasse fuer die Verwaltung eines Pfades
// homePath: Absoluter Startpfad als String
// delims: Objekt mit Trennern und Symbolen als Properties (oder Delims-Objekt)
// 'delim': Trennzeichen zwischen zwei Ebenen
// 'back': Name des relativen Vaterverzeichnisses
// 'root': Kennung vor dem ersten Trenner am Anfang eines absoluten Pfads
// 'home': Kennung vor dem ersten Trenner am Anfang eines Pfads relativ zu Home
function Path(homePath, delims) {
'use strict';
this.dirs = [];
this.setDelims(delims);
this.homeDirs = this.getDirs(homePath, { 'home' : "" });
this.home();
}
Class.define(Path, Object, {
'root' : function() {
this.dirs.splice(0, this.dirs.length);
},
'home' : function() {
this.dirs = this.homeDirs.slice();
},
'up' : function() {
this.dirs.pop();
},
'down' : function(subDir) {
this.dirs.push(subDir);
},
'setDelims' : function(delims = undefined) {
this.setConst('delims', new Delims(delims));
},
'setDelim' : function(delim = undefined) {
this.delims.setDelim(delim || '/');
},
'setBackDelim' : function(backDelim = undefined) {
this.delims.setBack(backDelim || "..");
},
'setRootDelim' : function(rootDelim = undefined) {
this.delims.setRoot(rootDelim || "");
},
'setHomeDelim' : function(homeDelim = undefined) {
this.delims.setHome(homeDelim || '~');
},
'setSchemeDelim' : function(schemeDelim = undefined) {
this.delims.setScheme(schemeDelim || ':');
},
'setHostDelim' : function(hostDelim = undefined) {
this.delims.setHost(hostDelim || '//');
},
'setPortDelim' : function(portDelim = undefined) {
this.delims.setHost(portDelim || ':');
},
'setQueryDelim' : function(queryDelim = undefined) {
this.delims.setQuery(queryDelim || '?');
},
'setParSepDelim' : function(parSepDelim = undefined) {
this.delims.setParSep(parSepDelim || '&');
},
'setParAssDelim' : function(parAssDelim = undefined) {
this.delims.setParAss(parAssDelim || '=');
},
'setNodeDelim' : function(nodeDelim = undefined) {
this.delims.setNode(nodeDelim || '#');
},
'getLeaf' : function(dirs = undefined) {
const __DIRS = (dirs || this.dirs);
return ((__DIRS && __DIRS.length) ? __DIRS.slice(-1)[0] : "");
},
'getPath' : function(dirs = undefined, delims = undefined) {
const __DELIMS = new Delims(delims);
const __DELIM = (__DELIMS.delim || this.delims.delim);
const __ROOTDELIM = ((__DELIMS.root !== undefined) ? __DELIMS.root : this.delims.root);
const __DIRS = (dirs || this.dirs);
return __ROOTDELIM + __DELIM + __DIRS.join(__DELIM);
},
'getDirs' : function(path = undefined, delims = undefined) {
const __DELIMS = new Delims(delims);
const __DELIM = (__DELIMS.delim || this.delims.delim);
const __ROOTDELIM = ((__DELIMS.root !== undefined) ? __DELIMS.root : this.delims.root);
const __HOMEDELIM = ((__DELIMS.home !== undefined) ? __DELIMS.home : this.delims.home);
const __DIRS = (path ? path.split(__DELIM) : []);
const __FIRST = __DIRS[0];
if (__FIRST && (__FIRST !== __ROOTDELIM) && (__FIRST !== __HOMEDELIM)) {
showAlert("Kein absoluter Pfad", this.getPath(__DIRS), this);
}
return __DIRS.slice(1);
}
} );
// ==================== Ende Abschnitt fuer Klasse Path ====================
// ==================== Abschnitt fuer Klasse URI ====================
// Basisklasse fuer die Verwaltung einer URI/URL
// homePath: Absoluter Startpfad als String
// delims: Objekt mit Trennern und Symbolen als Properties (oder Delims-Objekt)
// 'delim': Trennzeichen zwischen zwei Ebenen
// 'back': Name des relativen Vaterverzeichnisses
// 'root': Kennung vor dem ersten Trenner am Anfang eines absoluten Pfads
// 'home': Kennung vor dem ersten Trenner am Anfang eines Pfads relativ zu Home
function URI(homePath, delims) {
'use strict';
Path.call(this);
const __HOSTPORT = this.getHostPort(homePath);
this.scheme = this.getSchemePrefix(homePath);
this.host = __HOSTPORT.host;
this.port = this.parseValue(__HOSTPORT.port);
this.query = this.parseQuery(this.getQueryString(homePath));
this.node = this.getNodeSuffix(homePath);
this.homeDirs = this.getDirs(homePath, { 'home' : "" });
this.home();
}
Class.define(URI, Path, {
'setDelims' : function() {
this.setConst('delims', new UriDelims('/', "..", "", '~', ':', "//", ':', '?', '&', '=', '#'));
},
'setSchemeDelim' : function(schemeDelim = undefined) {
this.delims.setScheme(schemeDelim || ':');
},
'setQueryDelim' : function(queryDelim = undefined) {
this.delims.setQuery(queryDelim || '?');
},
'setParSepDelim' : function(parSepDelim = undefined) {
this.delims.setParSep(parSepDelim || '&');
},
'setParAssDelim' : function(parAssDelim = undefined) {
this.delims.setParAss(parAssDelim || '=');
},
'setNodeDelim' : function(nodeDelim = undefined) {
this.delims.setNode(nodeDelim || '#');
},
'getServerPath' : function(path = undefined) {
return this.stripHostPort(this.stripQueryString(this.stripNodeSuffix(this.stripSchemePrefix(path))));
},
'getHostPort' : function(path = undefined) {
const __HOSTDELIM = this.delims.host;
const __PORTDELIM = this.delims.port;
const __ROOTDELIM = this.delims.root + this.delims.delim;
const __NOSCHEME = this.stripSchemePrefix(path);
const __INDEXHOST = (__NOSCHEME ? __NOSCHEME.indexOf(__HOSTDELIM) : -1);
const __PATH = (~ __INDEXHOST) ? __NOSCHEME.substring(__INDEXHOST + __HOSTDELIM.length) : __NOSCHEME;
const __INDEXHOSTPORT = (__PATH ? __PATH.indexOf(__ROOTDELIM) : -1);
const __HOSTPORT = (~ __INDEXHOSTPORT) ? __PATH.substring(0, __INDEXHOSTPORT) : undefined;
const __INDEXPORT = (__HOSTPORT ? __HOSTPORT.indexOf(__PORTDELIM) : -1);
const __HOST = (~ __INDEXPORT) ? __HOSTPORT.substring(0, __INDEXPORT) : __HOSTPORT;
const __PORT = (~ __INDEXPORT) ? __HOSTPORT.substring(__INDEXPORT + __PORTDELIM.length) : undefined;
return {
'host' : __HOST,
'port' : __PORT
};
},
'stripHostPort' : function(path = undefined) {
const __HOSTDELIM = this.delims.host;
const __ROOTDELIM = this.delims.root + this.delims.delim;
const __INDEXHOST = (path ? path.indexOf(__HOSTDELIM) : -1);
const __PATH = (~ __INDEXHOST) ? path.substring(__INDEXHOST + __HOSTDELIM.length) : path;
const __INDEXHOSTPORT = (__PATH ? __PATH.indexOf(__ROOTDELIM) : -1);
return (~ __INDEXHOSTPORT) ? __PATH.substring(__INDEXHOSTPORT) : __PATH;
},
'getSchemePrefix' : function(path = undefined) {
const __SCHEMEDELIM = this.delims.scheme;
const __INDEXSCHEME = (path ? path.indexOf(__SCHEMEDELIM) : -1);
return (~ __INDEXSCHEME) ? path.substring(0, __INDEXSCHEME) : undefined;
},
'stripSchemePrefix' : function(path = undefined) {
const __SCHEMEDELIM = this.delims.scheme;
const __INDEXSCHEME = (path ? path.indexOf(__SCHEMEDELIM) : -1);
return (~ __INDEXSCHEME) ? path.substring(__INDEXSCHEME + __INDEXSCHEME.length) : path;
},
'getNodeSuffix' : function(path = undefined) {
const __NODEDELIM = this.delims.node;
const __INDEXNODE = (path ? path.lastIndexOf(__NODEDELIM) : -1);
return (~ __INDEXNODE) ? path.substring(__INDEXNODE + __NODEDELIM.length) : undefined;
},
'stripNodeSuffix' : function(path = undefined) {
const __NODEDELIM = this.delims.node;
const __INDEXNODE = (path ? path.lastIndexOf(__NODEDELIM) : -1);
return (~ __INDEXNODE) ? path.substring(0, __INDEXNODE) : path;
},
'getQueryString' : function(path = undefined) {
const __QUERYDELIM = this.delims.query;
const __PATH = this.stripNodeSuffix(path);
const __INDEXQUERY = (__PATH ? __PATH.indexOf(__QUERYDELIM) : -1);
return (~ __INDEXQUERY) ? __PATH.substring(__INDEXQUERY + __QUERYDELIM.length) : undefined;
},
'stripQueryString' : function(path = undefined) {
const __QUERYDELIM = this.delims.query;
const __INDEXQUERY = (path ? path.indexOf(__QUERYDELIM) : -1);
return (~ __INDEXQUERY) ? path.substring(0, __INDEXQUERY) : path;
},
'formatParams' : function(params, formatFun, delim = ' ', assign = '=') {
const __PARAMS = [];
for (let param in params) {
__PARAMS.push(param + assign + formatFun(params[param]));
}
return __PARAMS.join(delim);
},
'parseParams' : function(params, parseFun, delim = ' ', assign = '=') {
const __RET = { };
if (params) {
const __PARAMS = params.split(delim);
for (let index = 0; index < __PARAMS.length; index++) {
const __PARAM = __PARAMS[index];
if (__PARAM) {
const __INDEX = __PARAM.indexOf(assign);
const __KEY = (~ __INDEX) ? __PARAM.substring(0, __INDEX) : __PARAM;
const __VAL = (~ __INDEX) ? parseFun(__PARAM.substring(__INDEX + assign.length)) : true;
__RET[__KEY] = __VAL;
}
}
}
return __RET;
},
'rawValue' : function(value) {
return value;
},
'parseValue' : function(value) {
const __VALUE = Number(value);
if (__VALUE == value) { // schwacher Vergleich true, also Number
return __VALUE;
} else {
const __LOWER = (value ? value.toLowerCase() : undefined);
if ((__LOWER === "true") || (__LOWER === "false")) {
return (value === "true");
}
}
return value;
},
'getQuery' : function(delims = { }) {
const __QRYSEP = ((delims.qrySep !== undefined) ? delims.qrySep : this.delims.qrySep);
const __QRYASS = ((delims.qryAss !== undefined) ? delims.qryAss : this.delims.qryAss);
return this.formatParams(this.query, this.rawValue, __QRYSEP, __QRYASS);
},
'parseQuery' : function(path = undefined, delims = { }) {
const __QRYSEP = ((delims.qrySep !== undefined) ? delims.qrySep : this.delims.qrySep);
const __QRYASS = ((delims.qryAss !== undefined) ? delims.qryAss : this.delims.qryAss);
return this.parseParams(path, this.parseValue, __QRYSEP, __QRYASS);
},
'setQuery' : function(query) {
this.query = query;
},
'setQueryPar' : function(key, value) {
this.query[key] = value;
},
'getQueryPar' : function(key) {
return this.query[key];
},
'getPath' : function(dirs = undefined, delims = undefined) {
const __DELIMS = new UriDelims(delims);
const __SCHEMEDELIM = ((__DELIMS.scheme !== undefined) ? __DELIMS.scheme : this.delims.scheme);
const __HOSTDELIM = ((__DELIMS.host !== undefined) ? __DELIMS.host : this.delims.host);
const __PORTDELIM = ((__DELIMS.port !== undefined) ? __DELIMS.port : this.delims.port);
const __QUERYDELIM = ((__DELIMS.query !== undefined) ? __DELIMS.query : this.delims.query);
const __NODEDELIM = ((__DELIMS.node !== undefined) ? __DELIMS.node : this.delims.node);
const __SCHEMENAME = this.scheme;
const __SCHEME = (__SCHEMENAME ? __SCHEMENAME + __SCHEMEDELIM : "");
const __HOSTNAME = this.host;
const __HOST = (__HOSTNAME ? __HOSTDELIM + __HOSTNAME : "");
const __PORTNR = this.port;
const __PORT = ((__HOSTNAME && __PORTNR) ? __PORTDELIM + __PORTNR : "");
const __QUERYSTR = this.getQuery();
const __QUERY = (__QUERYSTR ? __QUERYDELIM + __QUERYSTR : "");
const __NODENAME = this.node;
const __NODE = (__NODENAME ? __NODEDELIM + __NODENAME : "");
return __SCHEME + __HOST + __PORT + Path.prototype.getPath.call(this, dirs, delims) + __QUERY + __NODE;
},
'getDirs' : function(path = undefined, delims = undefined) {
const __PATH = this.getServerPath(path);
return Path.prototype.getDirs.call(this, __PATH);
}
} );
// ==================== Ende Abschnitt fuer Klasse URI ====================
// ==================== Abschnitt fuer Klasse Directory ====================
// Basisklasse fuer eine Verzeichnisstruktur
// homePath: Absoluter Startpfad als String
// delims: Objekt mit Trennern und Symbolen als Properties (oder Delims-Objekt)
// 'delim': Trennzeichen zwischen zwei Ebenen
// 'back': Name des relativen Vaterverzeichnisses
// 'root': Kennung vor dem ersten Trenner am Anfang eines absoluten Pfads
// 'home': Kennung vor dem ersten Trenner am Anfang eines Pfads relativ zu Home
function Directory(homePath, delims) {
'use strict';
Path.call(this, homePath, delims);
}
Class.define(Directory, Path, {
'chDir' : function(subDir = undefined) {
if (subDir === undefined) {
this.root();
} else if ((typeof subDir) === 'object') {
for (let sub of subDir) {
this.chDir(sub);
}
} else {
if (subDir === this.delims.home) {
this.home();
} else if (subDir === this.delims.back) {
this.up();
} else {
this.down(subDir);
}
}
},
'pwd' : function() {
return this.getPath();
}
} );
// ==================== Ende Abschnitt fuer Klasse Directory ====================
// ==================== Abschnitt fuer Klasse ObjRef ====================
// Basisklasse fuer eine Objekt-Referenz
function ObjRef(rootObj) {
'use strict';
Directory.call(this, undefined, new Delims('/', "..", '/', '~'));
this.setConst('rootObj', rootObj); // Wichtig: Verweis nicht verfolgen! Gefahr durch Zyklen!
}
Class.define(ObjRef, Directory, {
'valueOf' : function() {
let ret = this.rootObj;
for (let name of this.dirs) {
if (ret === undefined) {
break;
}
ret = ret[name];
}
return ret;
}
} );
// ==================== Ende Abschnitt fuer Klasse ObjRef ====================
// ==================== Abschnitt fuer diverse Utilities ====================
// Gibt einen Wert zurueck. Ist dieser nicht definiert oder null, wird ein Alternativwert geliefert
// value: Ein Wert. Ist dieser nicht undefined oder null, wird er zurueckgeliefert (oder retValue)
// defValue: Default-Wert fuer den Fall, dass nichts gesetzt ist
// retValue: Falls definiert, Rueckgabe-Wert fuer den Fall, dass value nicht undefined oder null ist
// return Der Wert. Sind weder value noch defValue definiert, dann undefined
function getValue(value, defValue = undefined, retValue = undefined) {
return ((value === undefined) || (value === null)) ? defValue : (retValue === undefined) ? value : retValue;
}
// Gibt einen Wert zurueck. Ist dieser nicht definiert, wird ein Alternativwert geliefert
// value: Ein Wert. Ist dieser definiet und in den Grenzen, wird er zurueckgeliefert
// minValue: Untere Grenze fuer den Wert, falls angegeben
// minValue: Obere Grenze fuer den Wert, falls angegeben
// defValue: Default-Wert fuer den Fall, dass nichts gesetzt ist oder der Wert ausserhalb liegt
// return Der Wert. Sind weder value (in den Grenzen) noch defValue definiert, dann undefined
function getValueIn(value, minValue = undefined, maxValue = undefined, defValue = undefined) {
const __VALUE = getValue(value, defValue);
if ((minValue !== undefined) && (__VALUE < minValue)) {
return defValue;
}
if ((maxValue !== undefined) && (__VALUE > maxValue)) {
return defValue;
}
return __VALUE;
}
// Ermittelt den naechsten Wert aus einer Array-Liste
// arr: Array-Liste mit den moeglichen Werte
// value: Vorher gesetzter Wert
// return Naechster Wert in der Array-Liste
function getNextValue(arr, value) {
const __POS = arr.indexOf(value) + 1;
return arr[getValueIn(__POS, 0, arr.length - 1, 0)];
}
// Gibt ein Produkt zurueck. Ist einer der Multiplikanten nicht definiert, wird ein Alternativwert geliefert
// valueA: Ein Multipliksnt. Ist dieser undefined, wird als Produkt defValue zurueckgeliefert
// valueB: Ein Multipliksnt. Ist dieser undefined, wird als Produkt defValue zurueckgeliefert
// digits: Anzahl der Stellen nach dem Komma fuer das Produkt (Default: 0)
// defValue: Default-Wert fuer den Fall, dass ein Multiplikant nicht gesetzt ist (Default: NaN)
// return Das Produkt auf digits Stellen genau. Ist dieses nicht definiert, dann defValue
function getMulValue(valueA, valueB, digits = 0, defValue = NaN) {
let product = defValue;
if ((valueA !== undefined) && (valueB !== undefined)) {
product = parseFloat(valueA) * parseFloat(valueB);
}
return parseFloat(product.toFixed(digits));
}
// Ueberprueft, ob ein Objekt einer bestimmten Klasse angehoert (ggfs. per Vererbung)
// obj: Ein (generisches) Objekt
// base: Eine Objektklasse (Konstruktor-Funktion)
// return true, wenn der Prototyp rekursiv gefunden werden konnte
function instanceOf(obj, base) {
while (obj !== null) {
if (obj === base.prototype)
return true;
if ((typeof obj) === 'xml') { // Sonderfall mit Selbstbezug
return (base.prototype === XML.prototype);
}
obj = Object.getPrototypeOf(obj);
}
return false;
}
// Liefert alle Basisklassen des Objekts (inkl. Vererbung)
// obj: Ein (generisches) Objekt
// return true, wenn der Prototyp rekursiv gefunden werden konnte
function getPrototypes(obj) {
let ret = [];
while (obj !== null) {
const __PROTO = Object.getPrototypeOf(obj);
ret.push(__PROTO);
if ((typeof obj) === 'xml') { // Sonderfall mit Selbstbezug
break;
}
obj = __PROTO;
}
return ret;
}
// Liefert alle Attribute/Properties des Objekts (inkl. Vererbung)
// obj: Ein (generisches) Objekt
// return Array von Items (Property-Namen)
function getAllProperties(obj) {
let ret = [];
for (let o = obj; o !== null; o = Object.getPrototypeOf(o)) {
ret = ret.concat(Object.getOwnPropertyNames(o));
}
return ret;
}
// Ueberpruefung, ob ein Item aktiv ist oder nicht
// item: Name des betroffenen Items
// inList: Checkliste der inkludierten Items (Positivliste, true fuer aktiv)
// exList: Checkliste der exkludierten Items (Negativliste, true fuer inaktiv)
// return Angabe, ob das Item aktiv ist
function checkItem(item, inList = undefined, exList = undefined) {
let active = true;
if (inList !== undefined) {
active = (inList[item] === true); // gesetzt und true
}
if (exList !== undefined) {
if (exList[item] === true) { // gesetzt und true
active = false; // NICHT anzeigen
}
}
return active;
}
// Fuegt Properties zu einem Objekt hinzu, die in einem zweiten stehen. Doppelte Werte werden ueberschrieben
// data: Objekt, dem Daten hinzugefuegt werden
// addData: Objekt, das zusaetzliche Properties enthaelt
// addList: Checkliste der zu setzenden Items (true fuer kopieren), falls angegeben
// ignList: Checkliste der ignorierten Items (true fuer auslassen), falls angegeben
// return Das gemergete Objekt mit allen Properties
function addProps(data, addData, addList = undefined, ignList = undefined) {
for (let item in getValue(addData, { })) {
if (checkItem(item, addList, ignList)) {
data[item] = addData[item];
}
}
return data;
}
// Gibt den Wert einer Property zurueck. Ist dieser nicht definiert oder null, wird er vorher gesetzt
// obj: Ein Objekt. Ist dieses undefined oder null, wird defValue zurueckgeliefert
// item: Key des Properties
// defValue: Default-Wert fuer den Fall, dass nichts gesetzt ist
// return Der Wert des Properties. Sind das obj oder das Property und defValue undefined oder null, dann undefined
function getProp(obj, item, defValue = undefined) {
if ((obj === undefined) || (obj === null)) {
return defValue;
}
const __PROP = obj[item];
if ((__PROP !== undefined) && (__PROP !== null)) {
return __PROP;
}
return (obj[item] = defValue);
}
// Sicheres obj.valueOf() fuer alle Daten
// data: Objekt oder Wert
// return Bei Objekten valueOf() oder das Objekt selber, bei Werten der Wert
function valueOf(data) {
return (((typeof data) === 'object') ? data.valueOf() : data);
}
// Sicheres JSON.stringify(), das auch mit Zyklen umgehen kann
// value: Auszugebene Daten. Siehe JSON.stringify()
// replacer: Elementersetzer. Siehe JSON.stringify()
// space: Verschoenerung. Siehe JSON.stringify()
// cycleReplacer: Ersetzer im Falle von Zyklen
// return String mit Ausgabe der Objektdaten
function safeStringify(value, replacer = undefined, space = undefined, cycleReplacer = undefined) {
return JSON.stringify(value, serializer(replacer, cycleReplacer), space);
}
// Hilfsfunktion fuer safeStringify(): Kapselt replacer und einen cycleReplacer fuer Zyklen
// replacer: Elementersetzer. Siehe JSON.stringify()
// cycleReplacer: Ersetzer im Falle von Zyklen
// return Ersetzer-Funktion fuer JSON.stringify(), die beide Ersetzer vereint
function serializer(replacer = undefined, cycleReplacer = undefined) {
const __STACK = [];
const __KEYS = [];
if (! cycleReplacer) {
cycleReplacer = function(key, value) {
if (__STACK[0] === value) {
return "[~]";
}
return "[~." + __KEYS.slice(0, __STACK.indexOf(value)).join('.') + ']';
};
}
return function(key, value) {
if (__STACK.length) {
const __THISPOS = __STACK.indexOf(this);
if (~ __THISPOS) {
__STACK.splice(__THISPOS + 1);
__KEYS.splice(__THISPOS, Infinity, key);
} else {
__STACK.push(this);
__KEYS.push(key);
}
if (~ __STACK.indexOf(value)) {
value = cycleReplacer.call(this, key, value);
}
} else {
__STACK.push(value);
}
return ((! replacer) ? value : replacer.call(this, key, value));
};
}
// Speichert einen beliebiegen (strukturierten) Wert unter einem Namen ab
// name: GM_setValue-Name, unter dem die Daten gespeichert werden
// value: Beliebiger (strukturierter) Wert
// return String-Darstellung des Wertes
function serialize(name, value) {
const __STREAM = (value !== undefined) ? safeStringify(value) : value;
__LOG[4](name + " >> " + __STREAM);
GM_setValue(name, __STREAM);
return __STREAM;
}
// Holt einen beliebiegen (strukturierter) Wert unter einem Namen zurueck
// name: GM_setValue-Name, unter dem die Daten gespeichert werden
// defValue: Default-Wert fuer den Fall, dass nichts gespeichert ist
// return Objekt, das unter dem Namen gespeichert war
function deserialize(name, defValue = undefined) {
const __STREAM = GM_getValue(name, defValue);
__LOG[4](name + " << " + __STREAM);
if ((__STREAM !== undefined) && __STREAM.length) {
try {
return JSON.parse(__STREAM);
} catch (ex) {
__LOG[1](name + ": " + ex.message);
}
}
return undefined;
}
// Setzt eine Option dauerhaft und laedt die Seite neu
// name: Name der Option als Speicherort
// value: Zu setzender Wert
// reload: Seite mit neuem Wert neu laden
// return Gespeicherter Wert fuer setOptValue()
function setStored(name, value, reload = false, serial = false) {
if (serial) {
serialize(name, value);
} else {
GM_setValue(name, value);
}
if (reload) {
window.location.reload();
}
return value;
}
// Setzt den naechsten Wert aus einer Array-Liste als Option
// arr: Array-Liste mit den moeglichen Optionen
// name: Name der Option als Speicherort
// value: Vorher gesetzter Wert
// reload: Seite mit neuem Wert neu laden
// return Gespeicherter Wert fuer setOptValue()
function setNextStored(arr, name, value, reload = false, serial = false) {
return setStored(name, getNextValue(arr, value), reload, serial);
}
// Fuehrt die in einem Storage gespeicherte Operation aus
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
// return Array von Objekten mit 'cmd' / 'key' / 'val' (derzeit maximal ein Kommando) oder undefined
function getStoredCmds(memory = undefined) {
const __STORAGE = getMemory(memory);
const __MEMORY = __STORAGE.Value;
const __RUNPREFIX = __STORAGE.Prefix;
const __STOREDCMDS = [];
if (__MEMORY !== undefined) {
const __GETITEM = function(item) {
return __MEMORY.getItem(__RUNPREFIX + item);
};
const __DELITEM = function(item) {
return __MEMORY.removeItem(__RUNPREFIX + item);
};
const __CMD = ((__MEMORY !== undefined) ? __GETITEM('cmd') : undefined);
if (__CMD !== undefined) {
const __KEY = __GETITEM('key');
let value = __GETITEM('val');
try {
value = JSON.parse(value);
} catch (ex) {
__LOG[1]("getStoredCmds(): " + __CMD + " '" + __KEY + "' hat illegalen Wert '" + value + "'");
// ... meist kann man den String selber aber speichern, daher kein "return"...
}
__STOREDCMDS.push({
'cmd' : __CMD,
'key' : __KEY,
'val' : value
});
}
__DELITEM('cmd');
__DELITEM('key');
__DELITEM('val');
}
return (__STOREDCMDS.length ? __STOREDCMDS : undefined);
}
// Fuehrt die in einem Storage gespeicherte Operation aus
// storedCmds: Array von Objekten mit 'cmd' / 'key' / 'val' (siehe getStoredCmds())
// optSet: Set mit den Optionen
// beforeLoad: Angabe, ob nach der Speicherung noch loadOptions() aufgerufen wird
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
// return Array von Operationen (wie storedCmds), die fuer die naechste Phase uebrig bleiben
function runStoredCmds(storedCmds, optSet = undefined, beforeLoad = undefined) {
const __BEFORELOAD = getValue(beforeLoad, true);
const __STOREDCMDS = getValue(storedCmds, []);
const __LOADEDCMDS = [];
let invalidated = false;
while (__STOREDCMDS.length) {
const __STORED = __STOREDCMDS.shift();
const __CMD = __STORED.cmd;
const __KEY = __STORED.key;
const __VAL = __STORED.val;
if (__BEFORELOAD) {
if (__STOREDCMDS.length) {
invalidateOpts(optSet); // alle Optionen invalidieren
invalidated = true;
}
switch (__OPTACTION[__CMD]) {
case __OPTACTION.SET : __LOG[4]("SET '" + __KEY + "' " + __VAL);
setStored(__KEY, __VAL, false, false);
break;
case __OPTACTION.NXT : __LOG[4]("SETNEXT '" + __KEY + "' " + __VAL);
//setNextStored(__CONFIG.Choice, __KEY, __VAL, false, false);
setStored(__KEY, __VAL, false, false);
break;
case __OPTACTION.RST : __LOG[4]("RESET (delayed)");
__LOADEDCMDS.push(__STORED);
break;
default : break;
}
} else {
switch (__OPTACTION[__CMD]) {
case __OPTACTION.SET :
case __OPTACTION.NXT : __LOG[2]("SET/SETNEXT (undefined)");
break;
case __OPTACTION.RST : __LOG[4]("RESET");
resetOptions(optSet, false);
loadOptions(optSet); // Reset auf umbenannte Optionen anwenden!
break;
default : break;
}
}
}
return (__LOADEDCMDS.length ? __LOADEDCMDS : undefined);
}
// Gibt eine Option sicher zurueck
// opt: Config und Value der Option, ggfs. undefined
// defOpt: Rueckgabewert, falls undefined
// return Daten zur Option (oder defOpt)
function getOpt(opt, defOpt = { }) {
return getValue(opt, defOpt);
}
// Gibt eine Option sicher zurueck (Version mit Key)
// optSet: Platz fuer die gesetzten Optionen (und Config)
// item: Key der Option
// defOpt: Rueckgabewert, falls nicht zu finden
// return Daten zur Option (oder defOpt)
function getOptByName(optSet, item, defOpt = { }) {
if ((optSet !== undefined) && (item !== undefined)) {
return getOpt(optSet[item], defOpt);
} else {
return defOpt;
}
}
// Gibt die Konfigurationsdaten einer Option zurueck
// opt: Config und Value der Option
// defConfig: Rueckgabewert, falls Config nicht zu finden
// return Konfigurationsdaten der Option
function getOptConfig(opt, defConfig = { }) {
return getValue(getOpt(opt).Config, defConfig);
}
// Setzt den Namen einer Option
// opt: Config und Value der Option
// name: Zu setzender Name der Option
// reload: Seite mit neuem Wert neu laden
// return Gesetzter Name der Option
function setOptName(opt, name) {
const __CONFIG = getOptConfig(opt);
const __NAME = getOptName(opt);
if (__NAME !== name) {
__LOG[4]("RENAME " + __NAME + " => " + name);
__CONFIG.Name = name;
}
return name;
}
// Gibt den Namen einer Option zurueck
// opt: Config und Value der Option
// return Name der Option
function getOptName(opt) {
const __CONFIG = getOptConfig(opt);
const __NAME = __CONFIG.Name;
if (! __NAME) {
const __SHARED = __CONFIG.Shared;
if (__SHARED && ! opt.Loaded) {
const __OBJREF = getSharedRef(__SHARED, opt.Item);
return __OBJREF.getPath();
}
showAlert("Error", "Option ohne Namen", safeStringify(__CONFIG));
}
return __NAME;
}
// Setzt den Wert einer Option
// opt: Config und Value der Option
// name: Zu setzender Wert der Option
// return Gesetzter Wert
function setOptValue(opt, value) {
if (opt !== undefined) {
if (! opt.ReadOnly) {
__LOG[6](getOptName(opt) + ": " + __LOG.changed(opt.Value, value));
opt.Value = value;
}
return opt.Value;
} else {
return undefined;
}
}
// Gibt den Wert einer Option zurueck
// opt: Config und Value der Option
// defValue: Default-Wert fuer den Fall, dass nichts gesetzt ist
// load: Laedt die Option per loadOption(), falls noetig
// force: Laedt auch Optionen mit 'AutoReset'-Attribut
// return Gesetzter Wert
function getOptValue(opt, defValue = undefined, load = true, force = false) {
let value;
if (opt !== undefined) {
if (load && ! opt.Loaded) {
value = loadOption(opt, force);
} else {
value = opt.Value;
}
}
return valueOf(getValue(value, defValue));
}
// ==================== Ende Abschnitt fuer diverse Utilities ====================
// ==================== Abschnitt fuer Speicher und die Scriptdatenbank ====================
// Namen des Default-, Temporaer- und Null-Memories...
const __MEMNORMAL = 'normal';
const __MEMSESSION = 'begrenzt';
const __MEMINAKTIVE = 'inaktiv';
// Definition des Default-, Dauer- und Null-Memories...
const __OPTMEMNORMAL = __OPTMEM[__MEMNORMAL];
const __OPTMEMSESSION = __OPTMEM[__MEMSESSION];
const __OPTMEMINAKTIVE = __OPTMEM[__MEMINAKTIVE];
// Medium fuer die Datenbank (Speicher)
let myOptMem = __OPTMEMNORMAL;
let myOptMemSize;
// Infos ueber dieses Script-Modul
const __DBMOD = new ScriptModule();
// Inhaltsverzeichnis der DB-Daten (indiziert durch die Script-Namen)
const __DBTOC = { };
// Daten zu den Modulen (indiziert durch die Script-Namen)
const __DBDATA = { };
// ==================== Abschnitt fuer Speicher ====================
// Ermittelt fuer die uebergebene Speicher-Konfiguration einen Speicher
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
// defMemory: Ersatz-Wert, falls memory undefined. Soll nur memory genutzt werden, dann z.B. null uebergeben!
// return memory, falls okay, sonst einen Defaultwert
function getMemory(memory = undefined, defMemory = getValue(myOptMem, __OPTMEMNORMAL)) {
return getValue(memory, defMemory);
}
// Kompatibilitaetsfunktion: Testet, ob der uebergebene Speicher genutzt werden kann
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
// return true, wenn der Speichertest erfolgreich war
function canUseMemory(memory = undefined) {
const __STORAGE = getMemory(memory, { });
const __MEMORY = __STORAGE.Value;
let ret = false;
if (__MEMORY !== undefined) {
const __TESTPREFIX = 'canUseStorageTest';
const __TESTDATA = Math.random().toString();
const __TESTITEM = __TESTPREFIX + __TESTDATA;
__MEMORY.setItem(__TESTITEM, __TESTDATA);
ret = (__MEMORY.getItem(__TESTITEM) === __TESTDATA);
__MEMORY.removeItem(__TESTITEM);
}
__LOG[2]("canUseStorage(" + __STORAGE.Name + ") = " + ret);
return ret;
}
// Ermittelt die Groesse des benutzten Speichers
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
// return Groesse des genutzten Speichers in Bytes
function getMemSize(memory = undefined) {
const __STORAGE = getMemory(memory);
const __MEMORY = __STORAGE.Value;
//getMemUsage(__MEMORY);
if (__MEMORY !== undefined) {
const __SIZE = safeStringify(__MEMORY).length;
__LOG[2]("MEM: " + __SIZE + " bytes");
return __SIZE;
} else {
return 0;
}
}
// Gibt rekursiv und detailliert die Groesse des benutzten Speichers fuer ein Objekt aus
// value: (Enumerierbares) Objekt oder Wert, dessen Groesse gemessen wird
// out: Logfunktion, etwa console.log
// depth: Gewuenschte Rekursionstiefe (0 = nur dieses Objekt, -1 = alle Ebenen)
// name: Name des Objekts
function getMemUsage(value = undefined, out = undefined, depth = -1, name = '$') {
const __OUT = (out || __LOG[4]);
if ((typeof value) === 'string') {
const __SIZE = value.length;
__OUT("USAGE: " + name + '\t' + __SIZE + '\t' + value.substr(0, 255));
} else if ((typeof value) === 'object') {
if (depth === 0) {
const __SIZE = safeStringify(value).length;
__OUT("USAGE: " + name + '\t' + __SIZE);
} else {
depth--;
for (let sub in value) {
getMemUsage(value[sub], __OUT, depth, name + '.' + sub);
}
getMemUsage(value, __OUT, 0, name);
}
} else {
const __DATA = (((typeof value) === 'function') ? "" : '\t' + value);
__OUT("USAGE: " + name + '\t' + (typeof value) + __DATA);
}
}
// Restauriert den vorherigen Speicher (der in einer Option definiert ist)
// opt: Option zur Wahl des Speichers
// return Gesuchter Speicher oder Null-Speicher ('inaktiv')
function restoreMemoryByOpt(opt) {
// Memory Storage fuer vorherige Speicherung...
const __STORAGE = getOptValue(opt, __MEMNORMAL, true, true);
return __OPTMEM[__STORAGE];
}
// Initialisiert den Speicher (der in einer Option definiert ist) und merkt sich diesen ggfs.
// opt: Option zur Wahl des Speichers
// saveOpt: Option zur Speicherung der Wahl des Speichers (fuer restoreMemoryByOpt)
// return Gesuchter Speicher oder Null-Speicher ('inaktiv'), falls speichern nicht moeglich ist
function startMemoryByOpt(opt, saveOpt = undefined) {
// Memory Storage fuer naechste Speicherung...
let storage = getOptValue(opt, __MEMNORMAL);
let optMem = __OPTMEM[storage];
if (! canUseMemory(optMem)) {
if (storage !== __MEMINAKTIVE) {
storage = __MEMINAKTIVE;
optMem = __OPTMEM[storage];
}
}
if (saveOpt !== undefined) {
setOpt(saveOpt, storage, false);
}
return optMem;
}
// ==================== Ende Abschnitt fuer Speicher ====================
// ==================== Abschnitt fuer die Scriptdatenbank ====================
// Initialisiert das Script-Modul und ermittelt die beschreibenden Daten
// meta: Metadaten des Scripts (Default: GM_info.script)
// return Beschreibende Daten fuer __DBMOD
function ScriptModule(meta) {
'use strict';
const __META = getValue(meta, GM_info.script);
const __PROPS = {
'name' : true,
'version' : true,
'namespace' : true,
'description' : true
};
const __DBMOD = { };
__LOG[5](__META);
// Infos zu diesem Script...
addProps(__DBMOD, __META, __PROPS);
// Voller Name fuer die Ausgabe...
Object.defineProperty(__DBMOD, 'Name', {
get : function() {
return this.name + " (" + this.version + ')';
},
set : undefined
});
__LOG[2](__DBMOD);
return __DBMOD;
}
Class.define(ScriptModule, Object);
// Initialisiert die Scriptdatenbank, die einen Datenaustausch zwischen den Scripten ermoeglicht
// optSet: Gesetzte Optionen (und Config)
function initScriptDB(optSet) {
// Speicher fuer die DB-Daten...
const __DBMEM = myOptMem.Value;
__DBTOC.versions = getValue((__DBMEM === undefined) ? undefined : JSON.parse(__DBMEM.getItem('__DBTOC.versions')), { });
__DBTOC.namespaces = getValue((__DBMEM === undefined) ? undefined : JSON.parse(__DBMEM.getItem('__DBTOC.namespaces')), { });
// Zunaechst den alten Eintrag entfernen...
delete __DBTOC.versions[__DBMOD.name];
delete __DBTOC.namespaces[__DBMOD.name];
if (__DBMEM !== undefined) {
// ... und die Daten der Fremdscripte laden...
for (let module in __DBTOC.versions) {
scriptDB(module, getValue(JSON.parse(__DBMEM.getItem('__DBDATA.' + module)), { }));
}
}
}
// Setzt die Daten dieses Scriptes in der Scriptdatenbank, die einen Datenaustausch zwischen den Scripten ermoeglicht
// optSet: Gesetzte Optionen (und Config)
function updateScriptDB(optSet) {
// Eintrag ins Inhaltsverzeichnis...
__DBTOC.versions[__DBMOD.name] = __DBMOD.version;
__DBTOC.namespaces[__DBMOD.name] = __DBMOD.namespace;
// Speicher fuer die DB-Daten...
const __DBMEM = myOptMem.Value;
if (__DBMEM !== undefined) {
// Permanente Speicherung der Eintraege...
__DBMEM.setItem('__DBTOC.versions', safeStringify(__DBTOC.versions));
__DBMEM.setItem('__DBTOC.namespaces', safeStringify(__DBTOC.namespaces));
__DBMEM.setItem('__DBDATA.' + __DBMOD.name, safeStringify(optSet));
// Aktualisierung der Speichergroesse...
myOptMemSize = getMemSize(myOptMem);
}
// Jetzt die inzwischen gefuellten Daten *dieses* Scripts ergaenzen...
scriptDB(__DBMOD.name, getValue(optSet, { }));
__LOG[2](__DBDATA);
}
// Holt die globalen Daten zu einem Modul aus der Scriptdatenbank
// module: Gesetzte Optionen (und Config)
// initValue: Falls angegeben, zugewiesener Startwert
// return Daten zu diesem Modul
function scriptDB(module, initValue = undefined) {
const __NAMESPACE = __DBTOC.namespaces[module];
const __DBMODS = getProp(__DBDATA, __NAMESPACE, { });
if (initValue !== undefined) {
return (__DBMODS[module] = initValue);
} else {
return getProp(__DBMODS, module, { });
}
}
// ==================== Ende Abschnitt fuer die Scriptdatenbank ====================
// ==================== Ende Abschnitt fuer Speicher und die Scriptdatenbank ====================
// ==================== Abschnitt fuer das Benutzermenu ====================
// Zeigt den Eintrag im Menu einer Option
// val: Derzeitiger Wert der Option
// menuOn: Text zum Setzen im Menu
// funOn: Funktion zum Setzen
// keyOn: Hotkey zum Setzen im Menu
// menuOff: Text zum Ausschalten im Menu
// funOff: Funktion zum Ausschalten
// keyOff: Hotkey zum Ausschalten im Menu
function registerMenuOption(val, menuOn, funOn, keyOn, menuOff, funOff, keyOff) {
const __ON = (val ? '*' : "");
const __OFF = (val ? "" : '*');
__LOG[3]("OPTION " + __ON + menuOn + __ON + " / " + __OFF + menuOff + __OFF);
if (val) {
GM_registerMenuCommand(menuOff, funOff, keyOff);
} else {
GM_registerMenuCommand(menuOn, funOn, keyOn);
}
}
// Zeigt den Eintrag im Menu einer Option mit Wahl des naechsten Wertes
// val: Derzeitiger Wert der Option
// arr: Array-Liste mit den moeglichen Optionen
// menu: Text zum Setzen im Menu ($ wird durch gesetzten Wert ersetzt)
// fun: Funktion zum Setzen des naechsten Wertes
// key: Hotkey zum Setzen des naechsten Wertes im Menu
function registerNextMenuOption(val, arr, menu, fun, key) {
const __MENU = menu.replace('$', val);
let options = "OPTION " + __MENU;
for (let value of arr) {
if (value === val) {
options += " / *" + value + '*';
} else {
options += " / " + value;
}
}
__LOG[3](options);
GM_registerMenuCommand(__MENU, fun, key);
}
// Zeigt den Eintrag im Menu einer Option, falls nicht hidden
// val: Derzeitiger Wert der Option
// menu: Text zum Setzen im Menu ($ wird durch gesetzten Wert ersetzt)
// fun: Funktion zum Setzen des naechsten Wertes
// key: Hotkey zum Setzen des naechsten Wertes im Menu
// hidden: Angabe, ob Menupunkt nicht sichtbar sein soll (Default: sichtbar)
// serial: Serialization fuer komplexe Daten
function registerDataOption(val, menu, fun, key, hidden = false, serial = true) {
const __VALUE = ((serial && (val !== undefined)) ? safeStringify(val) : val);
const __MENU = getValue(menu, "").replace('$', __VALUE);
const __OPTIONS = (hidden ? "HIDDEN " : "") + "OPTION " + __MENU +
getValue(__VALUE, "", " = " + __VALUE);
__LOG[hidden ? 4 : 3](__OPTIONS);
if (! hidden) {
GM_registerMenuCommand(__MENU, fun, key);
}
}
// Zeigt den Eintrag im Menu einer Option
// opt: Config und Value der Option
function registerOption(opt) {
const __CONFIG = getOptConfig(opt);
const __VALUE = getOptValue(opt);
const __LABEL = __CONFIG.Label;
const __ACTION = opt.Action;
const __HOTKEY = __CONFIG.Hotkey;
const __HIDDEN = __CONFIG.HiddenMenu;
const __SERIAL = __CONFIG.Serial;
if (! __CONFIG.HiddenMenu) {
switch (__CONFIG.Type) {
case __OPTTYPES.MC : registerNextMenuOption(__VALUE, __CONFIG.Choice, __LABEL, __ACTION, __HOTKEY);
break;
case __OPTTYPES.SW : registerMenuOption(__VALUE, __LABEL, __ACTION, __HOTKEY,
__CONFIG.AltLabel, __ACTION, __CONFIG.AltHotkey);
break;
case __OPTTYPES.TF : registerMenuOption(__VALUE, __LABEL, __ACTION, __HOTKEY,
__CONFIG.AltLabel, opt.AltAction, __CONFIG.AltHotkey);
break;
case __OPTTYPES.SD : registerDataOption(__VALUE, __LABEL, __ACTION, __HOTKEY, __HIDDEN, __SERIAL);
break;
case __OPTTYPES.SI : registerDataOption(__VALUE, __LABEL, __ACTION, __HOTKEY, __HIDDEN, __SERIAL);
break;
default : break;
}
} else {
// Nur Anzeige im Log...
registerDataOption(__VALUE, __LABEL, __ACTION, __HOTKEY, __HIDDEN, __SERIAL);
}
}
// ==================== Ende Abschnitt fuer das Benutzermenu ====================
// Initialisiert die gesetzten Option
// config: Konfiguration der Option
// setValue: Zu uebernehmender Default-Wert (z.B. der jetzt gesetzte)
// return Initialwert der gesetzten Option
function initOptValue(config, setValue = undefined) {
let value = getValue(setValue, config.Default); // Standard
if (config.SharedData !== undefined) {
value = config.SharedData;
}
switch (config.Type) {
case __OPTTYPES.MC : if ((value === undefined) && (config.Choice !== undefined)) {
value = config.Choice[0];
}
break;
case __OPTTYPES.SW : break;
case __OPTTYPES.TF : break;
case __OPTTYPES.SD : config.Serial = true;
break;
case __OPTTYPES.SI : break;
default : break;
}
if (config.Serial || config.Hidden) {
config.HiddenMenu = true;
}
return value;
}
// Initialisiert die Menue-Funktion einer Option
// optAction: Typ der Funktion
// item: Key der Option
// optSet: Platz fuer die gesetzten Optionen (und Config)
// optConfig: Konfiguration der Option
// return Funktion fuer die Option
function initOptAction(optAction, item = undefined, optSet = undefined, optConfig = undefined) {
let fun;
if (optAction !== undefined) {
const __CONFIG = ((optConfig !== undefined) ? optConfig : getOptConfig(getOptByName(optSet, item)));
const __RELOAD = getValue(getValue(__CONFIG, { }).ActionReload, true);
switch (optAction) {
case __OPTACTION.SET : fun = function() {
return setOptByName(optSet, item, __CONFIG.SetValue, __RELOAD);
};
break;
case __OPTACTION.NXT : fun = function() {
return promptNextOptByName(optSet, item, __CONFIG.SetValue, __RELOAD,
__CONFIG.FreeValue, __CONFIG.SelValue, __CONFIG.MinChoice);
};
break;
case __OPTACTION.RST : fun = function() {
return resetOptions(optSet, __RELOAD);
};
break;
default : break;
}
}
return fun;
}
// Gibt fuer einen 'Shared'-Eintrag eine ObjRef zurueck
// shared: Object mit den Angaben 'namespace', 'module' und ggfs. 'item'
// item: Key der Option
// return ObjRef, die das Ziel definiert
function getSharedRef(shared, item = undefined) {
if (shared === undefined) {
return undefined;
}
const __OBJREF = new ObjRef(__DBDATA); // Gemeinsame Daten
const __PROPS = [ 'namespace', 'module', 'item' ];
const __DEFAULTS = [ __DBMOD.namespace, __DBMOD.name, item ];
for (let stage in __PROPS) {
const __DEFAULT = __DEFAULTS[stage];
const __PROP = __PROPS[stage];
const __NAME = shared[__PROP];
if (__NAME === '$') {
break;
}
__OBJREF.chDir(getValue(__NAME, __DEFAULT));
}
return __OBJREF;
}
// Gibt diese Config oder, falls 'Shared', ein Referenz-Objekt mit gemeinsamen Daten zurueck
// optConfig: Konfiguration der Option
// item: Key der Option
// return Entweder optConfig oder gemergete Daten auf Basis des in 'Shared' angegebenen Objekts
function getSharedConfig(optConfig, item = undefined) {
let config = getValue(optConfig, { });
const __SHARED = config.Shared;
if (__SHARED !== undefined) {
const __OBJREF = getSharedRef(__SHARED, item); // Gemeinsame Daten
if (getValue(__SHARED.item, '$') !== '$') { // __REF ist ein Item
const __REF = valueOf(__OBJREF);
config = { }; // Neu aufbauen...
addProps(config, getOptConfig(__REF));
addProps(config, optConfig);
config.setConst('SharedData', getOptValue(__REF));
} else { // __REF enthaelt die Daten selbst
if (! config.Name) {
config.Name = __OBJREF.getPath();
}
config.setConst('SharedData', __OBJREF); // Achtung: Ggfs. zirkulaer!
}
}
return config;
}
// Initialisiert die gesetzten Optionen
// optConfig: Konfiguration der Optionen
// optSet: Platz fuer die gesetzten Optionen
// preInit: Vorinitialisierung einzelner Optionen mit 'PreInit'-Attribut
// return Gefuelltes Objekt mit den gesetzten Optionen
function initOptions(optConfig, optSet = undefined, preInit = undefined) {
let value;
if (optSet === undefined) {
optSet = { };
}
for (let opt in optConfig) {
const __OPTCONFIG = optConfig[opt];
const __PREINIT = getValue(__OPTCONFIG.PreInit, false, true);
const __ISSHARED = getValue(__OPTCONFIG.Shared, false, true);
if ((preInit === undefined) || (__PREINIT === preInit)) {
const __CONFIG = getSharedConfig(__OPTCONFIG, opt);
const __ALTACTION = getValue(__CONFIG.AltAction, __CONFIG.Action);
// Gab es vorher einen Aufruf, der einen Stub-Eintrag erzeugt hat? Wurde ggfs. bereits geaendert...
const __USESTUB = ((preInit === false) && __PREINIT);
const __LOADED = (__USESTUB && optSet[opt].Loaded);
const __VALUE = (__USESTUB ? optSet[opt].Value : undefined);
optSet[opt] = {
'Item' : opt,
'Config' : __CONFIG,
'Loaded' : (__ISSHARED || __LOADED),
'Value' : initOptValue(__CONFIG, __VALUE),
'SetValue' : __CONFIG.SetValue,
'ReadOnly' : (__ISSHARED || __CONFIG.ReadOnly),
'Action' : initOptAction(__CONFIG.Action, opt, optSet, __CONFIG),
'AltAction' : initOptAction(__ALTACTION, opt, optSet, __CONFIG)
};
} else if (preInit) { // erstmal nur Stub
optSet[opt] = {
'Item' : opt,
'Config' : __OPTCONFIG,
'Loaded' : false,
'Value' : initOptValue(__OPTCONFIG),
'ReadOnly' : (__ISSHARED || __OPTCONFIG.ReadOnly)
};
}
}
return optSet;
}
// Abhaengigkeiten:
// ================
// initOptions (PreInit):
// restoreMemoryByOpt: PreInit oldStorage
// getStoredCmds: restoreMemoryByOpt
// runStoredCmds (beforeLoad): getStoredCmds
// loadOptions (PreInit): PreInit
// startMemoryByOpt: storage oldStorage
// initScriptDB: startMemoryByOpt
// initOptions (Rest): PreInit
// getMyTeam callback (getOptPrefix): initTeam
// __MYTEAM (initTeam): initOptions
// renameOptions: getOptPrefix
// runStoredCmds (afterLoad): getStoredCmds, renameOptions
// loadOptions (Rest): PreInit/Rest runStoredCmds
// updateScriptDB: startMemoryByOpt
// showOptions: startMemoryByOpt renameOptions
// buildMenu: showOptions
// buildForm: showOptions
// Initialisiert die gesetzten Optionen und den Speicher und laedt die Optionen zum Start
// optConfig: Konfiguration der Optionen
// optSet: Platz fuer die gesetzten Optionen
// return Gefuelltes Objekt mit den gesetzten Optionen
function startOptions(optConfig, optSet = undefined, classification = undefined) {
optSet = initOptions(optConfig, optSet, true); // PreInit
// Memory Storage fuer vorherige Speicherung...
myOptMemSize = getMemSize(myOptMem = restoreMemoryByOpt(optSet.oldStorage));
// Zwischengespeicherte Befehle auslesen...
const __STOREDCMDS = getStoredCmds(myOptMem);
// ... ermittelte Befehle ausführen...
const __LOADEDCMDS = runStoredCmds(__STOREDCMDS, optSet, true); // BeforeLoad
// Bisher noch nicht geladenene Optionen laden...
loadOptions(optSet);
// Memory Storage fuer naechste Speicherung...
myOptMemSize = getMemSize(myOptMem = startMemoryByOpt(optSet.storage, optSet.oldStorage));
// Globale Daten ermitteln...
initScriptDB(optSet);
optSet = initOptions(optConfig, optSet, false); // Rest
if (classification !== undefined) {
// Umbenennungen durchfuehren...
classification.renameOptions();
}
// ... ermittelte Befehle ausführen...
runStoredCmds(__LOADEDCMDS, optSet, false); // Rest
// Als globale Daten speichern...
updateScriptDB(optSet);
return optSet;
}
// Installiert die Visualisierung und Steuerung der Optionen
// optSet: Platz fuer die gesetzten Optionen
// optParams: Eventuell notwendige Parameter zur Initialisierung
// 'hideMenu': Optionen werden zwar geladen und genutzt, tauchen aber nicht im Benutzermenu auf
// 'menuAnchor': Startpunkt fuer das Optionsmenu auf der Seite
// 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar)
// 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar)
// 'formWidth': Anzahl der Elemente pro Zeile
// 'formBreak': Elementnummer des ersten Zeilenumbruchs
function showOptions(optSet = undefined, optParams = { 'hideMenu' : false }) {
if (! optParams.hideMenu) {
buildMenu(optSet);
}
if ((optParams.menuAnchor !== undefined) && (myOptMem !== __OPTMEMINAKTIVE)) {
buildForm(optParams.menuAnchor, optSet, optParams);
}
}
// Setzt eine Option auf einen vorgegebenen Wert
// Fuer kontrollierte Auswahl des Values siehe setNextOpt()
// opt: Config und vorheriger Value der Option
// value: (Bei allen Typen) Zu setzender Wert
// reload: Seite mit neuem Wert neu laden
// return Gesetzter Wert
function setOpt(opt, value, reload = false) {
return setOptValue(opt, setStored(getOptName(opt), value, reload, getOptConfig(opt).Serial));
}
// Ermittelt die naechste moegliche Option
// opt: Config und Value der Option
// value: Ggfs. zu setzender Wert
// return Zu setzender Wert
function getNextOpt(opt, value = undefined) {
const __CONFIG = getOptConfig(opt);
const __VALUE = getOptValue(opt, value);
switch (__CONFIG.Type) {
case __OPTTYPES.MC : return getValue(value, getNextValue(__CONFIG.Choice, __VALUE));
case __OPTTYPES.SW : return getValue(value, ! __VALUE);
case __OPTTYPES.TF : return getValue(value, ! __VALUE);
case __OPTTYPES.SD : return getValue(value, __VALUE);
case __OPTTYPES.SI : break;
default : break;
}
return __VALUE;
}
// Setzt die naechste moegliche Option
// opt: Config und Value der Option
// value: Default fuer ggfs. zu setzenden Wert
// reload: Seite mit neuem Wert neu laden
// return Gesetzter Wert
function setNextOpt(opt, value = undefined, reload = false) {
return setOpt(opt, getNextOpt(opt, value), reload);
}
// Setzt die naechste moegliche Option oder fragt ab einer gewissen Anzahl interaktiv ab
// opt: Config und Value der Option
// value: Default fuer ggfs. zu setzenden Wert
// reload: Seite mit neuem Wert neu laden
// freeValue: Angabe, ob Freitext zugelassen ist (Default: false)
// minChoice: Ab wievielen Auswahlmoeglichkeiten soll abgefragt werden? (Default: 3)
// return Gesetzter Wert
function promptNextOpt(opt, value = undefined, reload = false, freeValue = false, selValue = true, minChoice = 3) {
const __CONFIG = getOptConfig(opt);
const __CHOICE = __CONFIG.Choice;
if (value || (! __CHOICE) || (__CHOICE.length < minChoice)) {
return setNextOpt(opt, value, reload);
}
const __VALUE = getOptValue(opt, value);
try {
const __NEXTVAL = getNextValue(__CHOICE, __VALUE);
let message = "";
if (selValue) {
for (let index = 0; index < __CHOICE.length; index++) {
message += (index + 1) + ") " + __CHOICE[index] + '\n';
}
message += "\nNummer eingeben:";
} else {
message = __CHOICE.join(" / ") + "\n\nWert eingeben:";
}
const __ANSWER = prompt(message, __NEXTVAL);
if (__ANSWER) {
const __INDEX = parseInt(__ANSWER, 10) - 1;
let nextVal = (selValue ? __CHOICE[__INDEX] : undefined);
if (nextVal === undefined) {
const __VALTYPE = getValue(__CONFIG.ValType, 'String');
const __CASTVAL = this[__VALTYPE](__ANSWER);
if (freeValue || (~ __CHOICE.indexOf(__CASTVAL))) {
nextVal = __CASTVAL;
}
}
if (nextVal !== __VALUE) {
if (nextVal) {
return setOpt(opt, nextVal, reload);
}
const __LABEL = __CONFIG.Label.replace('$', __VALUE);
showAlert(__LABEL, "Ung\xFCltige Eingabe: " + __ANSWER);
}
}
} catch (ex) {
__LOG[1]("promptNextOpt: " + ex.message);
}
return __VALUE;
}
// Setzt eine Option auf einen vorgegebenen Wert (Version mit Key)
// Fuer kontrollierte Auswahl des Values siehe setNextOptByName()
// optSet: Platz fuer die gesetzten Optionen (und Config)
// item: Key der Option
// value: (Bei allen Typen) Zu setzender Wert
// reload: Seite mit neuem Wert neu laden
// return Gesetzter Wert
function setOptByName(optSet, item, value, reload = false) {
const __OPT = getOptByName(optSet, item);
return setOpt(__OPT, value, reload);
}
// Ermittelt die naechste moegliche Option (Version mit Key)
// optSet: Platz fuer die gesetzten Optionen (und Config)
// item: Key der Option
// value: Default fuer ggfs. zu setzenden Wert
// return Zu setzender Wert
function getNextOptByName(optSet, item, value = undefined) {
const __OPT = getOptByName(optSet, item);
return getNextOpt(__OPT, value);
}
// Setzt die naechste moegliche Option (Version mit Key)
// optSet: Platz fuer die gesetzten Optionen (und Config)
// item: Key der Option
// value: Default fuer ggfs. zu setzenden Wert
// reload: Seite mit neuem Wert neu laden
// return Gesetzter Wert
function setNextOptByName(optSet, item, value = undefined, reload = false) {
const __OPT = getOptByName(optSet, item);
return setNextOpt(__OPT, value, reload);
}
// Setzt die naechste moegliche Option oder fragt ab einer gewissen Anzahl interaktiv ab (Version mit Key)
// optSet: Platz fuer die gesetzten Optionen (und Config)
// item: Key der Option
// value: Default fuer ggfs. zu setzenden Wert
// reload: Seite mit neuem Wert neu laden
// freeValue: Angabe, ob Freitext zugelassen ist (Default: false)
// minChoice: Ab wievielen Auswahlmoeglichkeiten soll abgefragt werden? (Default: 3)
// return Gesetzter Wert
function promptNextOptByName(optSet, item, value = undefined, reload = false, freeValue = false, selValue = true, minChoice = 3) {
const __OPT = getOptByName(optSet, item);
return promptNextOpt(__OPT, value, reload, freeValue, selValue, minChoice);
}
// Baut das Benutzermenu auf
// optSet: Gesetzte Optionen
function buildMenu(optSet) {
__LOG[3]("buildMenu()");
for (let opt in optSet) {
registerOption(optSet[opt]);
}
}
// Invalidiert eine (ueber Menu) gesetzte Option
// opt: Zu invalidierende Option
// force: Invalidiert auch Optionen mit 'AutoReset'-Attribut
function invalidateOpt(opt, force = false) {
if (! opt.ReadOnly) {
const __CONFIG = getOptConfig(opt);
// Wert "ungeladen"...
opt.Loaded = (force || ! __CONFIG.AutoReset);
if (opt.Loaded && __CONFIG.AutoReset) {
// Nur zuruecksetzen, gilt als geladen...
setOptValue(opt, initOptValue(__CONFIG));
}
}
}
// Invalidiert die (ueber Menu) gesetzten Optionen
// optSet: Set mit den Optionen
// force: Invalidiert auch Optionen mit 'AutoReset'-Attribut
// return Set mit den geladenen Optionen
function invalidateOpts(optSet, force = false) {
for (let opt in optSet) {
const __OPT = optSet[opt];
if (__OPT.Loaded) {
invalidateOpt(__OPT, force);
}
}
return optSet;
}
// Laedt eine (ueber Menu) gesetzte Option
// opt: Zu ladende Option
// force: Laedt auch Optionen mit 'AutoReset'-Attribut
// return Gesetzter Wert der gelandenen Option
function loadOption(opt, force = false) {
const __CONFIG = getOptConfig(opt);
const __ISSHARED = getValue(__CONFIG.Shared, false, true);
const __NAME = getOptName(opt);
const __DEFAULT = getOptValue(opt, undefined, false, false);
let value;
if (opt.Loaded && ! __ISSHARED) {
__LOG[1]("Error: Oprion '" + __NAME + "' bereits geladen!");
}
if (opt.ReadOnly || __ISSHARED) {
value = __DEFAULT;
} else if (! force && __CONFIG.AutoReset) {
value = initOptValue(__CONFIG);
} else {
value = (__CONFIG.Serial ?
deserialize(__NAME, __DEFAULT) :
GM_getValue(__NAME, __DEFAULT));
}
__LOG[5]("LOAD " + __NAME + ": " + __LOG.changed(__DEFAULT, value));
// Wert als geladen markieren...
opt.Loaded = true;
// Wert intern setzen...
return setOptValue(opt, value);
}
// Laedt die (ueber Menu) gesetzten Optionen
// optSet: Set mit den Optionen
// force: Laedt auch Optionen mit 'AutoReset'-Attribut
// return Set mit den geladenen Optionen
function loadOptions(optSet, force = false) {
for (let opt in optSet) {
const __OPT = optSet[opt];
if (! __OPT.Loaded) {
loadOption(__OPT, force);
}
}
return optSet;
}
// Entfernt eine (ueber Menu) gesetzte Option (falls nicht 'Permanent')
// opt: Gesetzte Option
// force: Entfernt auch Optionen mit 'Permanent'-Attribut
// reset: Setzt bei Erfolg auf Initialwert der Option
function deleteOption(opt, force = false, reset = true) {
const __CONFIG = getOptConfig(opt);
if (force || ! __CONFIG.Permanent) {
const __NAME = getOptName(opt);
__LOG[4]("DELETE " + __NAME);
GM_deleteValue(__NAME);
if (reset) {
setOptValue(opt, initOptValue(__CONFIG));
}
}
}
// Entfernt die (ueber Menu) gesetzten Optionen (falls nicht 'Permanent')
// optSet: Gesetzte Optionen
// optSelect: Liste von ausgewaehlten Optionen, true = entfernen, false = nicht entfernen
// force: Entfernt auch Optionen mit 'Permanent'-Attribut
// reset: Setzt bei Erfolg auf Initialwert der Option
function deleteOptions(optSet, optSelect = undefined, force = false, reset = true) {
const __DELETEALL = (optSelect === undefined) || (optSelect === true);
const __OPTSELECT = getValue(optSelect, { });
for (let opt in optSet) {
if (getValue(__OPTSELECT[opt], __DELETEALL)) {
deleteOption(optSet[opt], force, reset);
}
}
}
// Benennt eine Option um und laedt sie ggfs. nach
// opt: Gesetzte Option
// name: Neu zu setzender Name (Speicheradresse)
// reload: Wert nachladen statt beizubehalten
// force: Laedt auch Optionen mit 'AutoReset'-Attribut
// return Umbenannte Option
function renameOption(opt, name, reload = false, force = false) {
const __NAME = getOptName(opt);
if (__NAME !== name) {
deleteOption(opt, true, ! reload);
setOptName(opt, name);
if (reload) {
loadOption(opt, force);
}
}
return opt;
}
// Ermittelt einen neuen Namen mit einem Prefix. Parameter fuer renameOptions()
// name: Gesetzter Name (Speicheradresse)
// prefix: Prefix, das vorangestellt werden soll
// return Neu zu setzender Name (Speicheradresse)
function prefixName(name, prefix) {
return (prefix + name);
}
// Ermittelt einen neuen Namen mit einem Postfix. Parameter fuer renameOptions()
// name: Gesetzter Name (Speicheradresse)
// postfix: Postfix, das angehaengt werden soll
// return Neu zu setzender Name (Speicheradresse)
function postfixName(name, postfix) {
return (name + postfix);
}
// Benennt selektierte Optionen nach einem Schema um und laedt sie ggfs. nach
// optSet: Gesetzte Optionen
// optSelect: Liste von ausgewaehlten Optionen, true = nachladen, false = nicht nachladen
// 'reload': Option nachladen?
// 'force': Option auch mit 'AutoReset'-Attribut nachladen?
// renameParam: Wird an renameFun uebergeen
// renameFun: function(name, param) zur Ermittlung des neuen Namens
// - name: Neu zu setzender Name (Speicheradresse)
// - param: Parameter "renameParam" von oben, z.B. Prefix oder Postfix
function renameOptions(optSet, optSelect, renameParam = undefined, renameFun = prefixName) {
if (renameFun === undefined) {
__LOG[1]("RENAME: Illegale Funktion!");
}
for (let opt in optSelect) {
const __OPTPARAMS = optSelect[opt];
const __OPT = optSet[opt];
if (__OPT === undefined) {
__LOG[1]("RENAME: Option '" + opt + "' nicht gefunden!");
} else {
const __NAME = getOptName(__OPT);
const __NEWNAME = renameFun(__NAME, renameParam);
const __ISSCALAR = ((typeof __OPTPARAMS) === 'boolean');
// Laedt die unter dem neuen Namen gespeicherten Daten nach?
const __RELOAD = (__ISSCALAR ? __OPTPARAMS : __OPTPARAMS.reload);
// Laedt auch Optionen mit 'AutoReset'-Attribut?
const __FORCE = (__ISSCALAR ? true : __OPTPARAMS.force);
renameOption(__OPT, __NEWNAME, __RELOAD, __FORCE);
}
}
}
// Setzt die Optionen in optSet auf die "Werkseinstellungen" des Skripts
// optSet: Gesetzte Optionen
// reload: Seite mit "Werkseinstellungen" neu laden
function resetOptions(optSet, reload = true) {
// Alle (nicht 'Permanent') gesetzten Optionen entfernen...
deleteOptions(optSet, true, false, ! reload);
if (reload) {
// ... und Seite neu laden (mit "Werkseinstellungen")...
window.location.reload();
}
}
// ==================== Abschnitt fuer diverse Utilities ====================
// Legt Input-Felder in einem Form-Konstrukt an, falls noetig
// form: <form>...</form>
// props: Map von name:value-Paaren
// type: Typ der Input-Felder (Default: unsichtbare Daten)
// return Ergaenztes Form-Konstrukt
function addInputField(form, props, type = "hidden") {
for (let fieldName in props) {
let field = form[fieldName];
if (! field) {
field = document.createElement("input");
field.type = type;
field.name = fieldName;
form.appendChild(field);
}
field.value = props[fieldName];
}
return form;
}
// Legt unsichtbare Input-Daten in einem Form-Konstrukt an, falls noetig
// form: <form>...</form>
// props: Map von name:value-Paaren
// return Ergaenztes Form-Konstrukt
function addHiddenField(form, props) {
return addInputField(form, props, "hidden");
}
// Hilfsfunktion fuer alle Browser: Fuegt fuer ein Event eine Reaktion ein
// obj: Betroffenes Objekt, z.B. ein Eingabeelement
// type: Name des Events, z.B. "click"
// callback: Funktion als Reaktion
// capture: Event fuer Parent zuerst (true) oder Child (false als Default)
// return false bei Misserfolg
function addEvent(obj, type, callback, capture = false) {
if (obj.addEventListener) {
return obj.addEventListener(type, callback, capture);
} else if (obj.attachEvent) {
return obj.attachEvent("on" + type, callback);
} else {
__LOG[1]("Could not add " + type + " event:");
__LOG[2](callback);
return false;
}
}
// Hilfsfunktion fuer alle Browser: Entfernt eine Reaktion fuer ein Event
// obj: Betroffenes Objekt, z.B. ein Eingabeelement
// type: Name des Events, z.B. "click"
// callback: Funktion als Reaktion
// capture: Event fuer Parent zuerst (true) oder Child (false als Default)
// return false bei Misserfolg
function removeEvent(obj, type, callback, capture = false) {
if (obj.removeEventListener) {
return obj.removeEventListener(type, callback, capture);
} else if (obj.detachEvent) {
return obj.detachEvent("on" + type, callback);
} else {
__LOG[1]("Could not remove " + type + " event:");
__LOG[2](callback);
return false;
}
}
// Hilfsfunktion fuer alle Browser: Fuegt fuer ein Event eine Reaktion ein
// id: ID des betroffenen Eingabeelements
// type: Name des Events, z.B. "click"
// callback: Funktion als Reaktion
// capture: Event fuer Parent zuerst (true) oder Child (false als Default)
// return false bei Misserfolg
function addDocEvent(id, type, callback, capture = false) {
const __OBJ = document.getElementById(id);
return addEvent(__OBJ, type, callback, capture);
}
// Hilfsfunktion fuer alle Browser: Entfernt eine Reaktion fuer ein Event
// id: ID des betroffenen Eingabeelements
// type: Name des Events, z.B. "click"
// callback: Funktion als Reaktion
// capture: Event fuer Parent zuerst (true) oder Child (false als Default)
// return false bei Misserfolg
function removeDocEvent(id, type, callback, capture = false) {
const __OBJ = document.getElementById(id);
return removeEvent(__OBJ, type, callback, capture);
}
// Hilfsfunktion fuer die Ermittlung eines Elements der Seite
// name: Name des Elements (siehe "name=")
// index: Laufende Nummer des Elements (0-based), Default: 0
// doc: Dokument (document)
// return Gesuchtes Element mit der lfd. Nummer index oder undefined (falls nicht gefunden)
function getElement(name, index = 0, doc = document) {
const __TAGS = document.getElementsByName(name);
const __TABLE = (__TAGS === undefined) ? undefined : __TAGS[index];
return __TABLE;
}
// Hilfsfunktion fuer die Ermittlung eines Elements der Seite (Default: Tabelle)
// index: Laufende Nummer des Elements (0-based)
// tag: Tag des Elements ("table")
// doc: Dokument (document)
// return Gesuchtes Element oder undefined (falls nicht gefunden)
function getTable(index, tag = "table", doc = document) {
const __TAGS = document.getElementsByTagName(tag);
const __TABLE = (__TAGS === undefined) ? undefined : __TAGS[index];
return __TABLE;
}
// Hilfsfunktion fuer die Ermittlung der Zeilen einer Tabelle
// index: Laufende Nummer des Elements (0-based)
// doc: Dokument (document)
// return Gesuchte Zeilen oder undefined (falls nicht gefunden)
function getRows(index, doc = document) {
const __TABLE = getTable(index, "table", doc);
const __ROWS = (__TABLE === undefined) ? undefined : __TABLE.rows;
return __ROWS;
}
// ==================== Abschnitt fuer Optionen auf der Seite ====================
// Liefert den Funktionsaufruf zur Option als String
// opt: Auszufuehrende Option
// isAlt: Angabe, ob AltAction statt Action gemeint ist
// value: Ggfs. zu setzender Wert
// serial: Serialization fuer String-Werte (Select, Textarea)
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
// return String mit dem (reinen) Funktionsaufruf
function getFormAction(opt, isAlt = false, value = undefined, serial = undefined, memory = undefined) {
const __STORAGE = getMemory(memory);
const __MEMORY = __STORAGE.Value;
const __MEMSTR = __STORAGE.Display;
const __RUNPREFIX = __STORAGE.Prefix;
if (__MEMORY !== undefined) {
const __RELOAD = "window.location.reload()";
const __SETITEM = function(item, val, quotes = true) {
return (__MEMSTR + ".setItem('" + __RUNPREFIX + item + "', " + (quotes ? "'" + val + "'" : val) + "),");
};
const __SETITEMS = function(cmd, key = undefined, val = undefined) {
return ('(' + __SETITEM('cmd', cmd) + ((key === undefined) ? "" :
__SETITEM('key', key) + __SETITEM('val', val, false)) + __RELOAD + ')');
};
const __CONFIG = getOptConfig(opt);
const __SERIAL = getValue(serial, getValue(__CONFIG.Serial, false));
const __THISVAL = ((__CONFIG.ValType === "String") ? "'\\x22' + this.value + '\\x22'" : "this.value");
const __TVALUE = getValue(__CONFIG.ValType, __THISVAL, "new " + __CONFIG.ValType + '(' + __THISVAL + ')');
const __VALSTR = ((value !== undefined) ? safeStringify(value) : __SERIAL ? "JSON.stringify(" + __TVALUE + ')' : __TVALUE);
const __ACTION = (isAlt ? getValue(__CONFIG.AltAction, __CONFIG.Action) : __CONFIG.Action);
if (__ACTION !== undefined) {
switch (__ACTION) {
case __OPTACTION.SET : //return "doActionSet('" + getOptName(opt) + "', " + getNextOpt(opt, __VALSTR) + ')';
return __SETITEMS('SET', getOptName(opt), __VALSTR);
case __OPTACTION.NXT : //return "doActionNxt('" + getOptName(opt) + "', " + getNextOpt(opt, __VALSTR) + ')';
return __SETITEMS('NXT', getOptName(opt), __VALSTR);
case __OPTACTION.RST : //return "doActionRst()";
return __SETITEMS('RST');
default : break;
}
}
}
return undefined;
}
// Liefert die Funktionsaufruf zur Option als String
// opt: Auszufuehrende Option
// isAlt: Angabe, ob AltAction statt Action gemeint ist
// value: Ggfs. zu setzender Wert
// type: Event-Typ fuer <input>, z.B. "click" fuer "onclick="
// serial: Serialization fuer String-Werte (Select, Textarea)
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
// return String mit dem (reinen) Funktionsaufruf
function getFormActionEvent(opt, isAlt = false, value = undefined, type = "click", serial = undefined, memory = undefined) {
const __ACTION = getFormAction(opt, isAlt, value, serial, memory);
return getValue(__ACTION, "", ' on' + type + '="' + __ACTION + '"');
}
// Zeigt eine Option auf der Seite als Auswahlbox an
// opt: Anzuzeigende Option
// return String mit dem HTML-Code
function getOptionSelect(opt) {
const __CONFIG = getOptConfig(opt);
const __NAME = getOptName(opt);
const __VALUE = getOptValue(opt);
const __ACTION = getFormActionEvent(opt, false, undefined, "change", undefined);
const __FORMLABEL = getValue(__CONFIG.FormLabel, __CONFIG.Label);
const __LABEL = '<label for="' + __NAME + '">' + __FORMLABEL + '</label>';
let element = '<select name="' + __NAME + '" id="' + __NAME + '"' + __ACTION + '>';
if (__CONFIG.FreeValue && ! (~ __CONFIG.Choice.indexOf(__VALUE))) {
element += '\n<option value="' + __VALUE + '" SELECTED>' + __VALUE + '</option>';
}
for (let value of __CONFIG.Choice) {
element += '\n<option value="' + value + '"' +
((value === __VALUE) ? ' SELECTED' : "") +
'>' + value + '</option>';
}
element += '\n</select>';
return __LABEL.replace('$', element);
}
// Zeigt eine Option auf der Seite als Radiobutton an
// opt: Anzuzeigende Option
// return String mit dem HTML-Code
function getOptionRadio(opt) {
const __CONFIG = getOptConfig(opt);
const __NAME = getOptName(opt);
const __VALUE = getOptValue(opt, false);
const __ACTION = getFormActionEvent(opt, false, true, "click", false);
const __ALTACTION = getFormActionEvent(opt, true, false, "click", false);
const __ELEMENTON = '<input type="radio" name="' + __NAME +
'" id="' + __NAME + 'ON" value="1"' +
(__VALUE ? ' CHECKED' : __ACTION) +
' /><label for="' + __NAME + 'ON">' +
__CONFIG.Label + '</label>';
const __ELEMENTOFF = '<input type="radio" name="' + __NAME +
'" id="' + __NAME + 'OFF" value="0"' +
(__VALUE ? __ALTACTION : ' CHECKED') +
' /><label for="' + __NAME + 'OFF">' +
__CONFIG.AltLabel + '</label>';
return [ __ELEMENTON, __ELEMENTOFF ];
}
// Zeigt eine Option auf der Seite als Checkbox an
// opt: Anzuzeigende Option
// return String mit dem HTML-Code
function getOptionCheckbox(opt) {
const __CONFIG = getOptConfig(opt);
const __NAME = getOptName(opt);
const __VALUE = getOptValue(opt, false);
const __ACTION = getFormActionEvent(opt, __VALUE, ! __VALUE, "click", false);
const __FORMLABEL = getValue(__CONFIG.FormLabel, __CONFIG.Label);
return '<input type="checkbox" name="' + __NAME +
'" id="' + __NAME + '" value="' + __VALUE + '"' +
(__VALUE ? ' CHECKED' : "") + __ACTION + ' /><label for="' +
__NAME + '">' + __FORMLABEL + '</label>';
}
// Zeigt eine Option auf der Seite als Daten-Textfeld an
// opt: Anzuzeigende Option
// return String mit dem HTML-Code
function getOptionTextarea(opt) {
const __CONFIG = getOptConfig(opt);
const __NAME = getOptName(opt);
const __VALUE = getOptValue(opt);
const __ACTION = getFormActionEvent(opt, false, undefined, "submit", undefined);
const __SUBMIT = getValue(__CONFIG.Submit, "");
//const __ONSUBMIT = (__SUBMIT.length ? ' onKeyDown="' + __SUBMIT + '"': "");
const __ONSUBMIT = (__SUBMIT ? ' onKeyDown="' + __SUBMIT + '"': "");
const __FORMLABEL = getValue(__CONFIG.FormLabel, __CONFIG.Label);
const __ELEMENTLABEL = '<label for="' + __NAME + '">' + __FORMLABEL + '</label>';
const __ELEMENTTEXT = '<textarea name="' + __NAME + '" id="' + __NAME + '" cols="' + __CONFIG.Cols +
'" rows="' + __CONFIG.Rows + '"' + __ONSUBMIT + __ACTION + '>' +
safeStringify(__VALUE, __CONFIG.Replace, __CONFIG.Space) + '</textarea>';
return [ __ELEMENTLABEL, __ELEMENTTEXT ];
}
// Zeigt eine Option auf der Seite als Button an
// opt: Anzuzeigende Option
// return String mit dem HTML-Code
function getOptionButton(opt) {
const __CONFIG = getOptConfig(opt);
const __NAME = getOptName(opt);
const __VALUE = getOptValue(opt, false);
const __ACTION = getFormActionEvent(opt, __VALUE, ! __VALUE, "click", false);
const __BUTTONLABEL = (__VALUE ? __CONFIG.AltLabel : __CONFIG.Label);
const __FORMLABEL = getValue(__CONFIG.FormLabel, __CONFIG.Label);
return '<label for="' + __NAME + '">' + __FORMLABEL +
'</label><input type="button" name="' + __NAME +
'" id="' + __NAME + '" value="' + __BUTTONLABEL + '"' +
__ACTION + '/>';
}
// Zeigt eine Option auf der Seite an (je nach Typ)
// opt: Anzuzeigende Option
// return String mit dem HTML-Code
function getOptionElement(opt) {
const __CONFIG = getOptConfig(opt);
const __TYPE = getValue(__CONFIG.FormType, __CONFIG.Type);
let element = "";
if (! __CONFIG.Hidden) {
switch (__TYPE) {
case __OPTTYPES.MC : element = getOptionSelect(opt);
break;
case __OPTTYPES.SW : if (__CONFIG.FormLabel !== undefined) {
element = getOptionCheckbox(opt);
} else {
element = getOptionRadio(opt);
}
break;
case __OPTTYPES.TF : element = getOptionCheckbox(opt);
break;
case __OPTTYPES.SD : element = getOptionTextarea(opt);
break;
case __OPTTYPES.SI : element = getOptionButton(opt);
break;
default : break;
}
if (element.length === 2) {
element = '<div>' + element[0] + '<br />' + element[1] + '</div>';
}
}
return element;
}
// Baut das Benutzermenu auf der Seite auf
// optSet: Gesetzte Optionen
// optParams: Eventuell notwendige Parameter
// 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar)
// 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar)
// 'formWidth': Anzahl der Elemente pro Zeile
// 'formBreak': Elementnummer des ersten Zeilenumbruchs
// return String mit dem HTML-Code
function getForm(optSet, optParams = { }) {
const __FORM = '<form id="options" method="POST"><table><tbody><tr>';
const __FORMEND = '</tr></tbody></table></form>';
const __FORMWIDTH = getValue(optParams.formWidth, 3);
const __FORMBREAK = getValue(optParams.formBreak, __FORMWIDTH);
const __SHOWFORM = getOptValue(optSet.showForm, true) ? optParams.showForm : { 'showForm' : true };
let form = __FORM;
let count = 0; // Bisher angezeigte Optionen
let column = 0; // Spalte der letzten Option (1-basierend)
for (let opt in optSet) {
if (checkItem(opt, __SHOWFORM, optParams.hideForm)) {
const __ELEMENT = getOptionElement(optSet[opt]);
const __TDOPT = (~ __ELEMENT.indexOf('|')) ? "" : ' colspan="2"';
if (__ELEMENT) {
if (++count > __FORMBREAK) {
if (++column > __FORMWIDTH) {
column = 1;
}
}
if (column === 1) {
form += '</tr><tr>';
}
form += '\n<td' + __TDOPT + '>' + __ELEMENT.replace('|', '</td><td>') + '</td>';
}
}
}
form += '\n' + __FORMEND;
return form;
}
// Fuegt das Script in die Seite ein
// optSet: Gesetzte Optionen
// optParams: Eventuell notwendige Parameter
// 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar)
// 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar)
// return String mit dem HTML-Code fuer das Script
function getScript(optSet, optParams = { }) {
//const __SCRIPT = '<script type="text/javascript">function activateMenu() { console.log("TADAAA!"); }</script>';
//const __SCRIPT = '<script type="text/javascript">\n\tfunction doActionNxt(key, value) { alert("SET " + key + " = " + value); }\n\tfunction doActionNxt(key, value) { alert("SET " + key + " = " + value); }\n\tfunction doActionRst(key, value) { alert("RESET"); }\n</script>';
//const __FORM = '<form method="POST"><input type="button" id="showOpts" name="showOpts" value="Optionen anzeigen" onclick="activateMenu()" /></form>';
const __SCRIPT = "";
//window.eval('function activateMenu() { console.log("TADAAA!"); }');
return __SCRIPT;
}
// Zeigt das Optionsmenu auf der Seite an (im Gegensatz zum Benutzermenu)
// anchor: Element, das als Anker fuer die Anzeige dient
// optSet: Gesetzte Optionen
// optParams: Eventuell notwendige Parameter
// 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar)
// 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar)
// 'formWidth': Anzahl der Elemente pro Zeile
// 'formBreak': Elementnummer des ersten Zeilenumbruchs
function buildForm(anchor, optSet, optParams = { }) {
__LOG[3]("buildForm()");
const __FORM = getForm(optSet, optParams);
const __SCRIPT = getScript(optSet, optParams);
addForm(anchor, __FORM, __SCRIPT);
}
// Informationen zu hinzugefuegten Forms
const __FORMS = { };
// Zeigt das Optionsmenu auf der Seite an (im Gegensatz zum Benutzermenu)
// anchor: Element, das als Anker fuer die Anzeige dient
// form: HTML-Form des Optionsmenu (hinten angefuegt)
// script: Script mit Reaktionen
function addForm(anchor, form = "", script = "") {
const __OLDFORM = __FORMS[anchor];
const __REST = (__OLDFORM === undefined) ? anchor.innerHTML :
anchor.innerHTML.substring(0, anchor.innerHTML.length - __OLDFORM.Script.length - __OLDFORM.Form.length);
__FORMS[anchor] = {
'Script' : script,
'Form' : form
};
anchor.innerHTML = __REST + script + form;
}
// ==================== Abschnitt fuer Klasse Classification ====================
// Basisklasse fuer eine Klassifikation der Optionen nach Kriterium (z.B. Erst- und Zweitteam oder Fremdteam)
function Classification() {
'use strict';
this.renameFun = prefixName;
//this.renameParamFun = undefined;
this.optSet = undefined;
this.optSelect = { };
}
Class.define(Classification, Object, {
'renameOptions' : function() {
const __PARAM = this.renameParamFun();
if (__PARAM !== undefined) {
// Klassifizierte Optionen umbenennen...
renameOptions(this.optSet, this.optSelect, __PARAM, this.renameFun);
}
},
'deleteOptions' : function() {
return deleteOptions(this.optSet, this.optSelect, true, true);
}
} );
// ==================== Ende Abschnitt fuer Klasse Classification ====================
// ==================== Abschnitt fuer Klasse TeamClassification ====================
// Klasse fuer die Klassifikation der Optionen nach Team (Erst- und Zweitteam oder Fremdteam)
function TeamClassification() {
'use strict';
Classification.call(this);
this.team = undefined;
this.teamParams = undefined;
}
Class.define(TeamClassification, Classification, {
'renameParamFun' : function() {
const __MYTEAM = (this.team = getMyTeam(this.optSet, this.teamParams, this.team));
if (__MYTEAM.LdNr) {
// Prefix fuer die Optionen mit gesonderten Behandlung...
return __MYTEAM.LdNr.toString() + '.' + __MYTEAM.LgNr.toString() + ':';
} else {
return undefined;
}
}
} );
// ==================== Ende Abschnitt fuer Klasse TeamClassification ====================
// ==================== Abschnitt fuer Klasse Team ====================
// Klasse fuer Teamdaten
function Team(team, land, liga) {
'use strict';
this.Team = team;
this.Land = land;
this.Liga = liga;
this.LdNr = getLandNr(land);
this.LgNr = getLigaNr(liga);
}
Class.define(Team, Object, {
'__TEAMITEMS' : { // Items, die in Team als Teamdaten gesetzt werden...
'Team' : true,
'Liga' : true,
'Land' : true,
'LdNr' : true,
'LgNr' : true
}
} );
// ==================== Ende Abschnitt fuer Klasse Team ====================
// ==================== Spezialisierter Abschnitt fuer Optionen ====================
// Gesetzte Optionen (wird von initOptions() angelegt und von loadOptions() gefuellt):
const __OPTSET = { };
// Teamparameter fuer getrennte Speicherung der Optionen fuer Erst- und Zweitteam...
const __TEAMCLASS = new TeamClassification();
// Optionen mit Daten, die ZAT- und Team-bezogen gemerkt werden...
__TEAMCLASS.optSelect = {
'ligaSize' : true
};
// Gibt die Teamdaten zurueck und aktualisiert sie ggfs. in der Option
// optSet: Platz fuer die gesetzten Optionen
// teamParams: Dynamisch ermittelte Teamdaten ('Team', 'Liga', 'Land', 'LdNr' und 'LgNr')
// myTeam: Objekt fuer die Teamdaten
// return Die Teamdaten oder undefined bei Fehler
function getMyTeam(optSet = undefined, teamParams = undefined, myTeam = new Team()) {
if (teamParams !== undefined) {
addProps(myTeam, teamParams, myTeam.__TEAMITEMS);
__LOG[2]("Ermittelt: " + safeStringify(myTeam));
// ... und abspeichern...
setOpt(optSet.team, myTeam, false);
} else {
const __TEAM = getOptValue(optSet.team); // Gespeicherte Parameter
if ((__TEAM !== undefined) && (__TEAM.Land !== undefined)) {
addProps(myTeam, __TEAM, myTeam.__TEAMITEMS);
__LOG[2]("Gespeichert: " + safeStringify(myTeam));
} else {
__LOG[1]("Unbekannt: " + safeStringify(__TEAM));
}
}
//return ((myTeam.length > 0) ? myTeam : undefined);
return myTeam;
}
// Behandelt die Optionen und laedt das Benutzermenu
// optConfig: Konfiguration der Optionen
// optSet: Platz fuer die gesetzten Optionen
// optParams: Eventuell notwendige Parameter zur Initialisierung
// 'hideMenu': Optionen werden zwar geladen und genutzt, tauchen aber nicht im Benutzermenu auf
// 'Tab': Tabelle mit dem Spielplan
// 'Zei': Startzeile des Spielplans mit dem ersten ZAT
// 'Spa': Spalte der Tabellenzelle mit der Spielart (z.B. "Liga : Heim")
// 'teamParams': Getrennte Daten-Option wird genutzt, hier: Team() mit 'LdNr'/'LgNr' des Erst- bzw. Zweitteams
// 'menuAnchor': Startpunkt fuer das Optionsmenu auf der Seite
// 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar)
// 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar)
// 'formWidth': Anzahl der Elemente pro Zeile
// 'formBreak': Elementnummer des ersten Zeilenumbruchs
// return Gefuelltes Objekt mit den gesetzten Optionen
function buildOptions(optConfig, optSet = undefined, optParams = { 'hideMenu' : false }) {
// Klassifikation ueber Land und Liga des Teams...
__TEAMCLASS.optSet = optSet; // Classification mit optSet verknuepfen
__TEAMCLASS.teamParams = optParams.teamParams; // Ermittelte Parameter
optSet = startOptions(optConfig, optSet, __TEAMCLASS);
// Werte aus der HTML-Seite ermitteln...
const __BOXSAISONS = document.getElementsByTagName("option");
const __SAISON = getSaisonFromComboBox(__BOXSAISONS);
const __LIGASIZE = getLigaSizeFromSpielplan(optParams.Tab.rows, optParams.Zei, optParams.Spa, getOptValue(optSet.saison));
// ... und abspeichern...
setOpt(optSet.saison, __SAISON, false);
setOpt(optSet.ligaSize, __LIGASIZE, false);
showOptions(optSet, optParams);
return optSet;
}
// ==================== Ende Abschnitt fuer Optionen ====================
// ==================== Abschnitt fuer Spielplan und ZATs ====================
// Beschreibungstexte aller Runden
const __POKALRUNDEN = [ "", "1. Runde", "2. Runde", "3. Runde", "Achtelfinale", "Viertelfinale", "Halbfinale", "Finale" ];
const __QUALIRUNDEN = [ "", "Quali 1", "Quali 2", "Quali 3" ];
const __OSCRUNDEN = [ "", "Viertelfinale", "Halbfinale", "Finale" ];
const __OSERUNDEN = [ "", "Runde 1", "Runde 2", "Runde 3", "Runde 4", "Achtelfinale", "Viertelfinale", "Halbfinale", "Finale" ];
const __HINRUECK = [ " Hin", " R\xFCck", "" ];
// ==================== Abschnitt fuer Klasse RundenLink ====================
function RundenLink(saison, team) {
'use strict';
this.uri = new URI("http://os.ongapo.com/?erganzeigen=1&stataktion=Statistik+ausgeben");
this.runde = 0;
this.prop = "";
this.label = "";
if (saison) {
this.setSaison(saison);
}
if (team) {
this.setTeam(team);
}
}
Class.define(RundenLink, Object, {
'setSaison' : function(saison) {
this.uri.setQueryPar('saauswahl', saison);
},
'setTeam' : function(team) {
this.uri.setQueryPar('landauswahl', team.LdNr);
this.uri.setQueryPar('ligaauswahl', team.LgNr);
},
'setPage' : function(page, label) {
this.uri.home();
this.uri.down(page + ".php");
this.setLabel(label);
},
'setRunde' : function(prop, runde) {
this.prop = prop;
this.runde = runde;
},
'setLabel' : function(label) {
this.label = (label || "");
},
'setAnzeigen' : function(show = true) {
this.uri.setQueryPar('erganzeigen', (show ? 1 : 0));
},
'getLabel' : function() {
return (this.label || "Link");
},
'getHTML' : function(target = undefined) {
if ((this.runde <= 0) || (! this.uri.getLeaf())) {
return this.label;
} else {
if (this.prop) {
this.uri.setQueryPar(this.prop, this.runde);
}
return "<a " + URI.prototype.formatParams({
'href' : this.uri.getPath(),
'target' : (target ? target : '_blank')
}, function(value) {
return '"' + value + '"';
}, ' ', '=') + '>' + this.getLabel() + "</a>";
}
}
});
// ==================== Ende Abschnitt fuer Klasse RundenLink ====================
// Liefert einen vor den ersten ZAT zurueckgesetzten Spielplanzeiger
// saison: Enthaelt die Nummer der laufenden Saison
// ligaSize: Anzahl der Teams in dieser Liga (Gegner + 1)
// - ZATs pro Abrechnungsmonat
// - Saison
// - ZAT
// - GameType
// - Heim/Auswaerts
// - Gegner
// - Tore
// - Gegentore
// - Ligengroesse
// - Ligaspieltag
// - Pokalrunde
// - Eurorunde
// - Hin/Rueck
// - ZAT Rueck
// - ZAT Korr
function firstZAT(saison, ligaSize) {
return {
'anzZATpMonth' : ((saison < 2) ? 7 : 6), // Erste Saison 7 ZAT, danach 6 ZAT...
'saison' : saison,
'ZAT' : 0,
'gameType' : "spielfrei",
'heim' : true,
'gegner' : "",
'gFor' : 0,
'gAga' : 0,
'ligaSize' : ligaSize,
'ligaSpieltag' : 0,
'pokalRunde' : 1,
'euroRunde' : 0,
'hinRueck' : 2, // 0: Hin, 1: Rueck, 2: unbekannt
'ZATrueck' : 0,
'ZATkorr' : 0
};
}
// Liefert den ZAT als String
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT
// longStats: Formatiert die Langversion des Textes
function getZAT(currZAT, longStats) {
return (longStats ? currZAT.gameType + ' ' + (currZAT.heim ? "Heim" : "Ausw\xE4rts") + ' ' : "") +
(longStats ? '[' + currZAT.ligaSpieltag + ' ' + currZAT.pokalRunde + ' ' + currZAT.euroRunde + "] " : "") +
(longStats ? '[' + currZAT.ZATrueck + __HINRUECK[currZAT.hinRueck] +
' ' + ((currZAT.ZATkorr < 0) ? "" : '+') + currZAT.ZATkorr + "] " : "") +
(longStats ? currZAT.gegner + ((currZAT.gFor > -1) ? " (" + currZAT.gFor + " : " + currZAT.gAga + ')' : "") + ' ' : "") +
'S' + currZAT.saison + "-Z" + ((currZAT.ZAT < 10) ? '0' : "") + currZAT.ZAT;
}
// Liefert die ZATs der Sonderspieltage fuer 10er- (2) und 20er-Ligen (4)
// saison: Enthaelt die Nummer der laufenden Saison
// return [ 10erHin, 10erRueck, 20erHin, 20erRueck ], ZAT-Nummern der Zusatzspieltage
function getLigaExtra(saison) {
if (saison < 3) {
return [ 8, 64, 32, 46 ];
} else {
return [ 9, 65, 33, 57 ];
}
}
// Spult die Daten um anzZAT ZATs vor und schreibt Parameter
// anhand des Spielplans fort. Also Spieltag, Runde, etc.
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT
// anzZAT: Anzahl der ZAT, um die vorgespult wird
function incZAT(currZAT, anzZAT = 1) {
const __LIGAEXTRA = getLigaExtra(currZAT.saison);
const __LIGAFIRST = 3 - (__LIGAEXTRA[0] % 2);
for (let i = anzZAT; i > 0; i--) {
currZAT.ZAT++;
if ((currZAT.ZAT - __LIGAFIRST + 1) % 2 === 1) {
currZAT.ligaSpieltag++;
} else {
const __POS = __LIGAEXTRA.indexOf(currZAT.ZAT);
if (~ __POS) {
if (__POS < 2 * (currZAT.ligaSize % 9)) {
currZAT.ligaSpieltag++;
}
}
}
if ((currZAT.ZAT > 12) && ((currZAT.ZAT % 10) === 5)) { // passt fuer alle Saisons: 12, 20, 30, 40, 48, 58, 68 / 3, 15, 27, 39, 51, 63, 69
currZAT.pokalRunde++;
}
if (((currZAT.ZAT + currZAT.ZATkorr) % 6) === 4) {
if (currZAT.ZAT < 63) {
currZAT.ZATrueck = currZAT.ZAT + 2;
currZAT.euroRunde++;
currZAT.hinRueck = 0;
} else {
currZAT.euroRunde = 11; // Finale
currZAT.hinRueck = 2;
}
}
if (currZAT.ZAT === currZAT.ZATrueck) {
currZAT.hinRueck = 1; // 5, 7; 11, 13; (17, 19) / 23, 25; 29, 31; 35, 37; 41, 43; 47, 49; 53, 55; 59, 61; 69
if (currZAT.saison < 3) { // 4, 6; 10, 14*; (16, 22*) / 24**, 26; 34, 36; 38*, 42; 44*, 50; 52, 54; 56*, 60; 62*, 66; 70
if (currZAT.ZAT === 22) {
currZAT.ZATkorr = 4;
} else if ((currZAT.ZAT - 6) % 20 > 6) {
currZAT.ZATkorr = 2;
} else {
currZAT.ZATkorr = 0;
}
if ((currZAT.ZAT === 22) || (currZAT.ZAT === 30)) {
currZAT.euroRunde--; // Frueher: 3. Quali-Rueckspiel erst knapp vor 1. Hauptrunde
}
}
}
}
}
// Liefert die Beschreibung des Spiels am aktuellen ZAT
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT
// showLink: Angabe, ob ein Link eingefuegt werden soll
// return Beschreibung des Spiels
function getZusatz(currZAT, showLink = true) {
const __LINK = new RundenLink(currZAT.saison, __TEAMCLASS.team);
if (currZAT.gameType === "Liga") {
if (currZAT.ZAT < 70) {
__LINK.setRunde("stauswahl", currZAT.ligaSpieltag);
__LINK.setPage("ls", __LINK.runde + ". Spieltag");
} else {
__LINK.setLabel("Relegation");
}
} else if (currZAT.gameType === "LP") {
__LINK.setRunde("stauswahl", currZAT.pokalRunde);
__LINK.setPage("lp", __POKALRUNDEN[__LINK.runde]);
} else if ((currZAT.gameType === "OSCQ") || (currZAT.gameType === "OSEQ")) {
__LINK.setRunde("runde", currZAT.euroRunde);
__LINK.setPage(((currZAT.gameType === "OSCQ") ? "oscq" : "oseq"), __QUALIRUNDEN[__LINK.runde] + __HINRUECK[currZAT.hinRueck]);
} else if (currZAT.gameType === "OSC") {
if (currZAT.euroRunde < 9) {
const __GRUPPENPHASE = ((currZAT.euroRunde < 6) ? "HR-Grp. " : "ZR-Grp. ");
__LINK.setRunde("", (currZAT.euroRunde % 3) * 2 + 1 + currZAT.hinRueck);
__LINK.setPage(((currZAT.euroRunde < 6) ? "oschr" : "osczr"), __GRUPPENPHASE + "Spiel " + __LINK.runde);
} else {
__LINK.setPage("oscfr", __OSCRUNDEN[currZAT.euroRunde - 8] + __HINRUECK[currZAT.hinRueck]);
}
} else if (currZAT.gameType === "OSE") {
__LINK.setRunde("runde", currZAT.euroRunde - 3);
__LINK.setPage("ose", __OSERUNDEN[__LINK.runde] + __HINRUECK[currZAT.hinRueck]);
} else {
__LINK.setLabel(); // irgendwie besser lesbar! ("Friendly" bzw. "spielfrei"/"Frei"/"reserviert")
}
return (showLink ? __LINK.getHTML() : "");
}
// ==================== Abschnitt fuer Statistiken des Spielplans ====================
// Liefert eine auf 0 zurueckgesetzte Ergebnissumme
// - Siege
// - Unentschieden
// - Niederlagen
// - Tore
// - Gegentore
// - Siegpunkte
function emptyStats() {
return {
'S' : 0,
'U' : 0,
'N' : 0,
'gFor' : 0,
'gAga' : 0,
'P' : 0
};
}
// Liefert die Stats als String
// stats: Enthaelt die summierten Stats
// longStats: Formatiert die Langversion des Textes
function getStats(stats, longStats) {
return (longStats ? '[' + stats.S + ' ' + stats.U + ' ' + stats.N + "] " : "/ ") +
stats.gFor + ':' + stats.gAga + ' ' + ((stats.gFor < stats.gAga) ? "" : (stats.gFor > stats.gAga) ? '+' : "") +
(stats.gFor - stats.gAga) + " (" + stats.P + ')';
}
// Summiert ein Ergebnis auf die Stats und liefert den neuen Text zurueck
// stats: Enthaelt die summierten Stats
// longStats: Formatiert die Langversion des Textes
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT (mit dem Ergebnis)
function addResultToStats(stats, longStats, currZAT) {
let ret = "";
if (currZAT.gFor > -1) {
let p = 0;
if (currZAT.gFor > currZAT.gAga) {
stats.S++;
p = 3;
} else if (currZAT.gFor === currZAT.gAga) {
stats.U++;
p = 1;
} else {
stats.N++;
}
stats.P += p;
stats.gFor += currZAT.gFor;
stats.gAga += currZAT.gAga;
ret = getStats(stats, longStats);
}
return ret;
}
// ==================== Abschnitt fuer interne IDs auf den Seiten ====================
const __GAMETYPES = { // "Blind FSS gesucht!"
'unbekannt' : -1,
"reserviert" : 0,
"Frei" : 0,
"spielfrei" : 0,
"Friendly" : 1,
"Liga" : 2,
"LP" : 3,
"OSEQ" : 4,
"OSE" : 5,
"OSCQ" : 6,
"OSC" : 7
};
const __LIGANRN = {
'unbekannt' : 0,
'1. Liga' : 1,
'2. Liga A' : 2,
'2. Liga B' : 3,
'3. Liga A' : 4,
'3. Liga B' : 5,
'3. Liga C' : 6,
'3. Liga D' : 7
};
const __LANDNRN = {
'unbekannt' : 0,
'Albanien' : 45,
'Andorra' : 95,
'Armenien' : 83,
'Aserbaidschan' : 104,
'Belgien' : 12,
'Bosnien-Herzegowina' : 66,
'Bulgarien' : 42,
'D\xE4nemark' : 8,
'Deutschland' : 6,
'England' : 1,
'Estland' : 57,
'Far\xF6er' : 68,
'Finnland' : 40,
'Frankreich' : 32,
'Georgien' : 49,
'Griechenland' : 30,
'Irland' : 5,
'Island' : 29,
'Israel' : 23,
'Italien' : 10,
'Kasachstan' : 105,
'Kroatien' : 24,
'Lettland' : 97,
'Liechtenstein' : 92,
'Litauen' : 72,
'Luxemburg' : 93,
'Malta' : 69,
'Mazedonien' : 86,
'Moldawien' : 87,
'Niederlande' : 11,
'Nordirland' : 4,
'Norwegen' : 9,
'\xD6sterreich' : 14,
'Polen' : 25,
'Portugal' : 17,
'Rum\xE4nien' : 28,
'Russland' : 19,
'San Marino' : 98,
'Schottland' : 2,
'Schweden' : 27,
'Schweiz' : 37,
'Serbien und Montenegro' : 41,
'Slowakei' : 70,
'Slowenien' : 21,
'Spanien' : 13,
'Tschechien' : 18,
'T\xFCrkei' : 39,
'Ukraine' : 20,
'Ungarn' : 26,
'Wales' : 3,
'Weissrussland' : 71,
'Zypern' : 38
};
// ==================== Abschnitt fuer Daten des Spielplans ====================
// Gibt die ID fuer den Namen eines Wettbewerbs zurueck
// gameType: Name des Wettbewerbs eines Spiels
// return OS2-ID fuer den Spieltyp (1 bis 7), 0 fuer spielfrei/Frei/reserviert, -1 fuer ungueltig
function getGameTypeID(gameType) {
return getValue(__GAMETYPES[gameType], __GAMETYPES.unbekannt);
}
// Gibt die ID des Landes mit dem uebergebenen Namen zurueck.
// land: Name des Landes
// return OS2-ID des Landes, 0 fuer ungueltig
function getLandNr(land) {
return getValue(__LANDNRN[land], __LANDNRN.unbekannt);
}
// Gibt die ID der Liga mit dem uebergebenen Namen zurueck.
// land: Name der Liga
// return OS2-ID der Liga, 0 fuer ungueltig
function getLigaNr(liga) {
return getValue(__LIGANRN[liga], __LIGANRN.unbekannt);
}
// Ermittelt den Spielgegner aus einer Tabellenzelle und liefert den Namen zurueck
// cell: Tabellenzelle mit dem Namen des Gegners
// return Der Name des Gegners
function getGegnerFromCell(cell) {
const __GEGNER = cell.textContent;
const __POS = __GEGNER.indexOf(" (");
if (~ __POS) {
return __GEGNER.substr(0, __POS);
} else {
return __GEGNER;
}
}
// Ermittelt das Spiel-Ergebnis aus einer Tabellenzelle, etwa "2 : 1", und liefert zwei Werte zurueck
// cell: Tabellenzelle mit Eintrag "2 : 1"
// return { '2', '1' } im Beispiel
function getErgebnisFromCell(cell) {
const __ERGEBNIS = cell.textContent.split(" : ", 2);
return __ERGEBNIS;
}
// Ermittelt die Spielart aus einer Tabellenzelle, etwa "Liga : Heim", und liefert zwei Werte zurueck
// cell: Tabellenzelle mit Eintrag "Liga : Heim" (Spielplan) oder "Liga Heim: " (Managerbuero)
// return { "Liga", "Heim" } im Beispiel
function getSpielArtFromCell(cell) {
const __TEXT = cell.textContent.replace('\xA0', "").replace(':', "").replace(" ", ' ');
const __SPIELART = __TEXT.split(' ', 2);
return __SPIELART;
}
// Ermittelt den Namen des Spielgegners aus einer Tabellenzelle und setzt gegner im Spielplanzeiger
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT
// cell: Tabellenzelle mit dem Namen des Gegners
function setGegnerFromCell(currZAT, cell) {
const __GEGNER = getGegnerFromCell(cell);
currZAT.gegner = __GEGNER;
}
// Ermittelt das Spiel-Ergebnis aus einer Tabellenzelle und setzt tore/gtore im Spielplanzeiger
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT
// cell: Tabellenzelle mit Eintrag "2 : 1"
function setErgebnisFromCell(currZAT, cell) {
const __ERGEBNIS = getErgebnisFromCell(cell);
if (__ERGEBNIS.length === 2) {
currZAT.gFor = parseInt(__ERGEBNIS[0], 10);
currZAT.gAga = parseInt(__ERGEBNIS[1], 10);
} else {
currZAT.gFor = -1;
currZAT.gAga = -1;
}
}
// Ermittelt die Spielart aus einer Tabellenzelle und setzt gameType/heim im Spielplanzeiger
// currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT
// cell: Tabellenzelle mit Eintrag "Liga : Heim" oder "Liga Heim"
function setSpielArtFromCell(currZAT, cell) {
const __SPIELART = getSpielArtFromCell(cell);
currZAT.gameType = __SPIELART[0];
currZAT.heim = (__SPIELART.length < 2) || (__SPIELART[1] === "Heim");
}
// Gibt die ID fuer den Namen eines Wettbewerbs zurueck
// cell: Tabellenzelle mit Link auf den Spielberichts-Link
// gameType: Name des Wettbewerbs eines Spiels
// label: Anzuklickender Text des neuen Links
// return HTML-Link auf die Preview-Seite fuer diesen Spielbericht
function getBilanzLinkFromCell(cell, gameType, label) {
const __GAMETYPEID = getGameTypeID(gameType);
let ret = "";
if (cell.textContent !== "Vorschau") { // Nur falls Link nicht bereits vorhanden
if (__GAMETYPEID > 1) { // nicht moeglich fuer "Friendly" bzw. "spielfrei"/"Frei"/"reserviert"
const __SEARCHFUN = ":os_bericht(";
let paarung = cell.innerHTML.substr(cell.innerHTML.indexOf(__SEARCHFUN) + __SEARCHFUN.length);
paarung = paarung.substr(0, paarung.indexOf(')'));
paarung = paarung.substr(0, paarung.lastIndexOf(','));
paarung = paarung.substr(0, paarung.lastIndexOf(','));
ret = ' <a href="javascript:spielpreview(' + paarung + ',' + __GAMETYPEID + ')">' + label + "</a>";
}
}
return ret;
}
// Addiert einen Link auf die Bilanz hinter den Spielberichts-Link
// cell: Tabellenzelle mit Link auf den Spielberichts-Link
// gameType: Name des Wettbewerbs eines Spiels
// label: Anzuklickender Text des neuen Links
function addBilanzLinkToCell(cell, gameType, label) {
const __BILANZLINK = getBilanzLinkFromCell(cell, gameType, label);
if (__BILANZLINK !== "") {
cell.innerHTML += __BILANZLINK;
}
}
// ==================== Abschnitt fuer sonstige Parameter des Spielplans ====================
const __TEAMSEARCHHAUPT = { // Parameter zum Team "<b>Willkommen im Managerbüro von TEAM</b><br>LIGA LAND<a href=..."
'Zeile' : 0,
'Spalte' : 1,
'start' : " von ",
'middle' : "</b><br>",
'liga' : ". Liga",
'land' : ' ',
'end' : "<a href="
};
const __TEAMSEARCHTEAM = { // Parameter zum Team "<b>TEAM - LIGA <a href=...>LAND</a></b>"
'Zeile' : 0,
'Spalte' : 0,
'start' : "<b>",
'middle' : " - ",
'liga' : ". Liga",
'land' : 'target="_blank">',
'end' : "</a></b>"
};
// Ermittelt, wie das eigene Team heisst und aus welchem Land bzw. Liga es kommt (zur Unterscheidung von Erst- und Zweitteam)
// cell: Tabellenzelle mit den Parametern zum Team "startTEAMmiddleLIGA...landLANDend", LIGA = "#liga[ (A|B|C|D)]"
// teamSeach: Muster fuer die Suche, die Eintraege fuer 'start', 'middle', 'liga', 'land' und 'end' enthaelt
// return Im Beispiel { 'Team' : "TEAM", 'Liga' : "LIGA", 'Land' : "LAND", 'LdNr' : LAND-NUMMER, 'LgNr' : LIGA-NUMMER },
// z.B. { 'Team' : "Choromonets Odessa", 'Liga' : "1. Liga", 'Land' : "Ukraine", 'LdNr' : 20, 'LgNr' : 1 }
function getTeamParamsFromTable(table, teamSearch = undefined) {
const __TEAMSEARCH = getValue(teamSearch, __TEAMSEARCHHAUPT);
const __TEAMCELLROW = getValue(__TEAMSEARCH.Zeile, 0);
const __TEAMCELLCOL = getValue(__TEAMSEARCH.Spalte, 0);
const __TEAMCELLSTR = (table === undefined) ? "" : table.rows[__TEAMCELLROW].cells[__TEAMCELLCOL].innerHTML;
const __SEARCHSTART = __TEAMSEARCH.start;
const __SEARCHMIDDLE = __TEAMSEARCH.middle;
const __SEARCHLIGA = __TEAMSEARCH.liga;
const __SEARCHLAND = __TEAMSEARCH.land;
const __SEARCHEND = __TEAMSEARCH.end;
const __INDEXSTART = __TEAMCELLSTR.indexOf(__SEARCHSTART);
const __INDEXEND = __TEAMCELLSTR.indexOf(__SEARCHEND);
let teamParams = __TEAMCELLSTR.substring(__INDEXSTART + __SEARCHSTART.length, __INDEXEND);
const __INDEXLIGA = teamParams.indexOf(__SEARCHLIGA);
const __INDEXMIDDLE = teamParams.indexOf(__SEARCHMIDDLE);
let land = (~ __INDEXLIGA) ? teamParams.substring(__INDEXLIGA + __SEARCHLIGA.length) : undefined;
const __TEAMNAME = (~ __INDEXMIDDLE) ? teamParams.substring(0, __INDEXMIDDLE) : undefined;
let liga = ((~ __INDEXLIGA) && (~ __INDEXMIDDLE)) ? teamParams.substring(__INDEXMIDDLE + __SEARCHMIDDLE.length) : undefined;
if (land !== undefined) {
if (land.charAt(2) === ' ') { // Land z.B. hinter "2. Liga A " statt "1. Liga "
land = land.substr(2);
}
if (liga !== undefined) {
liga = liga.substring(0, liga.length - land.length);
}
const __INDEXLAND = land.indexOf(__SEARCHLAND);
if (~ __INDEXLAND) {
land = land.substr(__INDEXLAND + __SEARCHLAND.length);
}
}
const __TEAM = new Team(__TEAMNAME, land, liga);
return __TEAM;
}
// Verarbeitet die URL der Seite und ermittelt die Nummer der gewuenschten Unterseite
// url: Adresse der Seite
// leafs: Liste von Filenamen mit der Default-Seitennummer (falls Query-Parameter nicht gefunden)
// item: Query-Parameter, der die Nummer der Unterseite angibt
// return Parameter aus der URL der Seite als Nummer
function getPageIdFromURL(url, leafs, item = "page") {
const __URI = new URI(url);
const __LEAF = __URI.getLeaf();
for (let leaf in leafs) {
if (__LEAF === leaf) {
const __DEFAULT = leafs[leaf];
return getValue(__URI.getQueryPar(item), __DEFAULT);
}
}
return -1;
}
// Verarbeitet die URL der Seite und ermittelt die Nummer der gewuenschten Unterseite
// saisons: Alle "option"-Eintraege der Combo-Box
// return Nummer der ausgewaehlten Saison (Default: 0)
function getSaisonFromComboBox(saisons) {
let saison = 0;
for (let i = 0; i < saisons.length; i++) {
const __SAISON = saisons[i];
if (__SAISON.outerHTML.match(/selected/)) {
saison = __SAISON.textContent;
}
}
return saison;
}
// Ermittelt aus dem Spielplan die Ligengroesse ueber die Sonderspieltage
// rows: Tabellenzeilen mit dem Spielplan
// startIdx: Index der Zeile mit dem ersten ZAT
// colArtIdx: Index der Spalte der Tabellenzelle mit der Spielart (z.B. "Liga : Heim")
// saison: Enthaelt die Nummer der laufenden Saison
// return 10 bei 36 Spielen, 18 bei 34 Spielen, 20 bei 38 Spielen
function getLigaSizeFromSpielplan(rows, startIdx, colArtIdx, saison) {
const __LIGAEXTRA = getLigaExtra(saison);
const __TEST10ER = getSpielArtFromCell(rows[startIdx + __LIGAEXTRA[0] - 1].cells[colArtIdx]);
const __TEST20ER = getSpielArtFromCell(rows[startIdx + __LIGAEXTRA[2] - 1].cells[colArtIdx]);
if (__TEST20ER[0] === "Liga") {
return 20;
} else if (__TEST10ER[0] === "Liga") {
return 10;
} else {
return 18;
}
}
// ==================== Ende Abschnitt fuer Spielplan und ZATs ====================
// ==================== Hauptprogramm ====================
// Verarbeitet Ansicht "Saisonplan"
function procSpielplan() {
const __ROWOFFSETUPPER = 1; // Header-Zeile
const __ROWOFFSETLOWER = 0;
const __COLUMNINDEX = {
'Art' : 1,
'Geg' : 2,
'Erg' : 3,
'Ber' : 4,
'Zus' : 5,
'Kom' : 6
};
const __TEAMPARAMS = getTeamParamsFromTable(getTable(1), __TEAMSEARCHTEAM); // Link mit Team, Liga, Land...
buildOptions(__OPTCONFIG, __OPTSET, {
'Tab' : getTable(2),
'Zei' : __ROWOFFSETUPPER,
'Spa' : __COLUMNINDEX.Art,
'teamParams' : __TEAMPARAMS,
'menuAnchor' : getTable(0, "div"),
'hideForm' : {
'team' : true
},
'formWidth' : 3,
'formBreak' : 4
});
const __ZAT = firstZAT(getOptValue(__OPTSET.saison), getOptValue(__OPTSET.ligaSize));
const __ROWS = getRows(2);
let ligaStats = emptyStats();
let euroStats = emptyStats();
for (let i = __ROWOFFSETUPPER; i < __ROWS.length - __ROWOFFSETLOWER; i++) {
const __CELLS = __ROWS[i].cells; // Aktuelle Eintraege
incZAT(__ZAT);
setGegnerFromCell(__ZAT, __CELLS[__COLUMNINDEX.Geg]);
setSpielArtFromCell(__ZAT, __CELLS[__COLUMNINDEX.Art]);
setErgebnisFromCell(__ZAT, __CELLS[__COLUMNINDEX.Erg]);
if (getOptValue(__OPTSET.shortKom)) {
const __CELLKOM = __CELLS[__COLUMNINDEX.Kom];
const __CELLART = __CELLS[__COLUMNINDEX.Art];
__CELLKOM.innerHTML = __CELLKOM.innerHTML.replace("Vorbericht(e)", 'V').replace("Kommentar(e)", 'K').replace("&", '/').replace('&', '/');
__CELLART.innerHTML = __CELLART.innerHTML.replace(": Heim", "(H)").replace(": Ausw\xE4rts", "(A)").replace("Friendly", "FSS");
}
__CELLS[__COLUMNINDEX.Zus].className = __CELLS[__COLUMNINDEX.Art].className;
if (__CELLS[__COLUMNINDEX.Zus].textContent === "") {
const __CELLBER = __CELLS[__COLUMNINDEX.Ber];
let stats = "";
addBilanzLinkToCell(__CELLBER, __ZAT.gameType, "Bilanz");
if (getOptValue(__OPTSET.shortKom)) {
__CELLBER.innerHTML = __CELLBER.innerHTML.replace("Klick", "(*)").replace("Bilanz", 'V').replace("Vorschau", 'V');
}
if (__ZAT.gameType === "Liga") {
if (__ZAT.ZAT < 70) {
stats = addResultToStats(ligaStats, getOptValue(__OPTSET.longStats), __ZAT);
}
} else if ((__ZAT.gameType === "OSCQ") || (__ZAT.gameType === "OSEQ") || (__ZAT.gameType === "OSE")) {
if (__ZAT.hinRueck !== 1) {
euroStats = emptyStats();
}
stats = addResultToStats(euroStats, getOptValue(__OPTSET.longStats), __ZAT);
} else if (__ZAT.gameType === "OSC") {
if ((__ZAT.hinRueck !== 1) && ((__ZAT.euroRunde >= 9) || ((__ZAT.euroRunde % 3) === 0))) {
euroStats = emptyStats();
}
stats = addResultToStats(euroStats, getOptValue(__OPTSET.longStats), __ZAT);
}
if (getOptValue(__OPTSET.showStats)) {
if (stats !== "") {
stats = ' ' + stats;
}
} else {
stats = "";
}
__CELLS[__COLUMNINDEX.Zus].innerHTML = getZusatz(__ZAT, true) + stats;
}
if (getOptValue(__OPTSET.sepMonths) && (__ZAT.ZAT % __ZAT.anzZATpMonth === 0) && (i < __ROWS.length - __ROWOFFSETLOWER - 1)) {
// Format der Trennlinie zwischen den Monaten...
const __BORDERSTRING = getOptValue(__OPTSET.sepStyle) + ' ' + getOptValue(__OPTSET.sepColor) + ' ' + getOptValue(__OPTSET.sepWidth);
/*
for (let entry of __CELLS) {
entry.style.borderBottom = __BORDERSTRING;
}
*/
for (let j = 0; j < __CELLS.length; j++) {
__CELLS[j].style.borderBottom = __BORDERSTRING;
}
}
}
}
try {
// URL-Legende:
// s=0: Teamuebersicht
// s=1: Vertragsdaten
// s=2: Einzelwerte
// s=3: Statistik Saison
// s=4: Statistik Gesamt
// s=5: Teaminfo
// s=6: Saisonplan
// s=7: Vereinshistorie
// s=8: Transferhistorie
// s=9: Leihhistorie
// Verzweige in unterschiedliche Verarbeitungen je nach Wert von s:
switch (getPageIdFromURL(window.location.href, {
'showteam.php' : 0, // Teamansicht Hauptfenster
'st.php' : 0 // Teamansicht Popupfenster
}, 's')) {
case 6 : procSpielplan(); break;
default : break;
}
} catch (ex) {
showAlert('[' + ex.lineNumber + "] " + __DBMOD.Name, ex.message, ex);
} finally {
__LOG[2]("SCRIPT END");
}
// *** EOF ***