Bearbeiten von „OS2.spielplan“
Zur Navigation springen
Zur Suche springen
Die Bearbeitung kann rückgängig gemacht werden. Bitte prüfe den Vergleich unten, um sicherzustellen, dass du dies tun möchtest, und veröffentliche dann unten deine Änderungen, um die Bearbeitung rückgängig zu machen.
Aktuelle Version | Dein Text | ||
Zeile 1: | Zeile 1: | ||
[[Kategorie:Greasemonkey]] | [[Kategorie:Greasemonkey]] | ||
{| style="background-color:white; font-size:11px; float: right; margin:3px 3px 3px 10px; border:1px solid #999; border-color: #9C1818; border-collapse:collapse;" width=500 cellpadding=3 cellspacing=0 | {| style="background-color:white; font-size:11px; float: right; margin:3px 3px 3px 10px; border:1px solid #999; border-color: #9C1818; border-collapse:collapse;" width=500 cellpadding=3 cellspacing=0 | ||
| colspan="2" style="padding:0.3em; background-color:#9C1818; font-size: 18px; color:#FFFFFF" align=center| '''OS2.spielplan''' | | colspan="2" style="padding:0.3em; background-color:#9C1818; font-size: 18px; color:#FFFFFF" align=center| '''OS2.spielplan''' | ||
Zeile 8: | Zeile 7: | ||
|- bgcolor="#FFCC00" | |- bgcolor="#FFCC00" | ||
| '''Version''' | | '''Version''' | ||
| '''0. | | '''0.70''' | ||
|- bgcolor="#FFCC00" | |- bgcolor="#FFCC00" | ||
| '''Autor''' | | '''Autor''' | ||
Zeile 20: | 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'''<br> '''Interaktive Menü-Optionen'''<br> '''Gemeinsame Code- und Datenbasis | | '''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 32: | Zeile 31: | ||
// @name OS2.spielplan | // @name OS2.spielplan | ||
// @namespace http://os.ongapo.com/ | // @namespace http://os.ongapo.com/ | ||
// @version 0. | // @version 0.70 | ||
// @copyright 2013+ | // @copyright 2013+ | ||
// @author Sven Loges (SLC) | // @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 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_getValue | ||
// @grant GM_setValue | // @grant GM_setValue | ||
Zeile 50: | Zeile 50: | ||
// ==/UserScript== | // ==/UserScript== | ||
// ECMAScript 6: | // ECMAScript 6: Erlaubt 'const', 'let', ... | ||
/* jshint esnext: true */ | /* jshint esnext: true */ | ||
/* jshint moz: true */ | /* jshint moz: true */ | ||
Zeile 144: | Zeile 144: | ||
'Name' : "sepStyle", | 'Name' : "sepStyle", | ||
'Type' : __OPTTYPES.MC, | 'Type' : __OPTTYPES.MC, | ||
'ValType' : | 'ValType' : "String", | ||
'Choice' : [ | 'Choice' : [ "solid", "hidden", "dotted", "dashed", "double", "groove", "ridge", | ||
"inset", "outset", "none" ], | |||
'Action' : __OPTACTION.NXT, | 'Action' : __OPTACTION.NXT, | ||
'Label' : "Stil: $", | 'Label' : "Stil: $", | ||
Zeile 155: | Zeile 155: | ||
'Name' : "sepColor", | 'Name' : "sepColor", | ||
'Type' : __OPTTYPES.MC, | 'Type' : __OPTTYPES.MC, | ||
'ValType' : | 'ValType' : "String", | ||
'FreeValue' : true, | 'FreeValue' : true, | ||
'Choice' : [ | 'Choice' : [ "white", "yellow", "black", "blue", "cyan", "gold", "grey", "green", | ||
"lime", "magenta", "maroon", "navy", "olive", "orange", "purple", | |||
"red", "teal", "transparent" ], | |||
'Action' : __OPTACTION.NXT, | 'Action' : __OPTACTION.NXT, | ||
'Label' : "Farbe: $", | 'Label' : "Farbe: $", | ||
Zeile 168: | Zeile 168: | ||
'Name' : "sepWidth", | 'Name' : "sepWidth", | ||
'Type' : __OPTTYPES.MC, | 'Type' : __OPTTYPES.MC, | ||
'ValType' : | 'ValType' : "String", | ||
'FreeValue' : true, | 'FreeValue' : true, | ||
'Choice' : [ | 'Choice' : [ "thin", "medium", "thick" ], | ||
'Action' : __OPTACTION.NXT, | 'Action' : __OPTACTION.NXT, | ||
'Label' : "Dicke: $", | 'Label' : "Dicke: $", | ||
Zeile 176: | Zeile 176: | ||
'FormLabel' : "Dicke:|$" | 'FormLabel' : "Dicke:|$" | ||
}, | }, | ||
'saison' : { // | 'saison' : { // Laufende Saison | ||
'Name' : "saison", | 'Name' : "saison", | ||
'Type' : __OPTTYPES.MC, | 'Type' : __OPTTYPES.MC, | ||
'ValType' : | 'ValType' : "Number", | ||
'FreeValue' : true, | 'FreeValue' : true, | ||
'SelValue' : false, | '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' : | 'Default' : 10, | ||
'Action' : __OPTACTION.NXT, | 'Action' : __OPTACTION.NXT, | ||
'Label' : "Saison: $", | 'Label' : "Saison: $", | ||
'Hotkey' : ' | 'Hotkey' : 'a', | ||
'FormLabel' : "Saison:|$" | 'FormLabel' : "Saison:|$" | ||
}, | }, | ||
Zeile 192: | Zeile 192: | ||
'Name' : "ligaSize", | 'Name' : "ligaSize", | ||
'Type' : __OPTTYPES.MC, | 'Type' : __OPTTYPES.MC, | ||
'ValType' : | 'ValType' : "Number", | ||
'AutoReset' : true, | 'AutoReset' : true, | ||
'Choice' : [ 10, 18, 20 ], | 'Choice' : [ 10, 18, 20 ], | ||
Zeile 206: | Zeile 206: | ||
'Serial' : true, | 'Serial' : true, | ||
'Permanent' : true, | 'Permanent' : true, | ||
'Default' : undefined, // new Team() // { 'Team' : undefined, 'Liga' : undefined, 'Land' : undefined | 'Default' : undefined, // new Team() // { 'Team' : undefined, 'Liga' : undefined, 'Land' : undefined, 'LdNr' : 0, 'LgNr' : 0 } | ||
'Submit' : undefined, | 'Submit' : undefined, | ||
'Cols' : 36, | 'Cols' : 36, | ||
Zeile 215: | Zeile 215: | ||
}, | }, | ||
'reset' : { // Optionen auf die "Werkseinstellungen" zuruecksetzen | 'reset' : { // Optionen auf die "Werkseinstellungen" zuruecksetzen | ||
'Name' : "reset", | 'Name' : "reset", | ||
'Type' : __OPTTYPES.SI, | 'Type' : __OPTTYPES.SI, | ||
Zeile 224: | Zeile 223: | ||
}, | }, | ||
'storage' : { // Browserspeicher fuer die Klicks auf Optionen | 'storage' : { // Browserspeicher fuer die Klicks auf Optionen | ||
'Name' : "storage", | 'Name' : "storage", | ||
'Type' : __OPTTYPES.MC, | 'Type' : __OPTTYPES.MC, | ||
'ValType' : | 'ValType' : "String", | ||
'Choice' : Object.keys(__OPTMEM), | 'Choice' : Object.keys(__OPTMEM), | ||
'Action' : __OPTACTION.NXT, | 'Action' : __OPTACTION.NXT, | ||
Zeile 235: | Zeile 233: | ||
}, | }, | ||
'oldStorage' : { // Vorheriger Browserspeicher fuer die Klicks auf Optionen | 'oldStorage' : { // Vorheriger Browserspeicher fuer die Klicks auf Optionen | ||
'Name' : "oldStorage", | 'Name' : "oldStorage", | ||
'Type' : __OPTTYPES.SD, | 'Type' : __OPTTYPES.SD, | ||
Zeile 243: | Zeile 240: | ||
}, | }, | ||
'showForm' : { // Optionen auf der Webseite (true = anzeigen, false = nicht anzeigen) | 'showForm' : { // Optionen auf der Webseite (true = anzeigen, false = nicht anzeigen) | ||
'Name' : "showForm", | 'Name' : "showForm", | ||
'Type' : __OPTTYPES.SW, | 'Type' : __OPTTYPES.SW, | ||
Zeile 249: | Zeile 245: | ||
'Permanent' : true, | 'Permanent' : true, | ||
'Default' : false, | 'Default' : false, | ||
'Action' : __OPTACTION.NXT, | 'Action' : __OPTACTION.NXT, | ||
'Label' : "Optionen anzeigen", | 'Label' : "Optionen anzeigen", | ||
'Hotkey' : 'a', | 'Hotkey' : 'a', | ||
'AltLabel' : "Optionen verbergen", | 'AltLabel' : "Optionen verbergen", | ||
'AltHotkey' : 'v', | 'AltHotkey' : 'v', | ||
Zeile 261: | Zeile 255: | ||
// ==================== Invarianter Abschnitt fuer Optionen ==================== | // ==================== Invarianter Abschnitt fuer Optionen ==================== | ||
// Kompatibilitaetsfunktion zur Ermittlung des Namens einer Funktion (falle <Function>.name nicht vorhanden ist) | // Kompatibilitaetsfunktion zur Ermittlung des Namens einer Funktion (falle <Function>.name nicht vorhanden ist) | ||
Zeile 299: | Zeile 265: | ||
} | } | ||
// | // 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 | // Gibt eine Meldung in der Console aus und oeffnet ein Bestaetigungsfenster mit der Meldung | ||
Zeile 325: | Zeile 295: | ||
// message: Der Meldungs-Text | // message: Der Meldungs-Text | ||
// data: Ein Wert. Ist er angegeben, wird er in der Console ausgegeben | // data: Ein Wert. Ist er angegeben, wird er in der Console ausgegeben | ||
function showAlert(label, message, data = undefined) { | function showAlert(label, message, data = undefined) { | ||
__LOG[ | __LOG[1](label + ": " + message); | ||
if (data !== undefined) { | if (data !== undefined) { | ||
Zeile 334: | Zeile 303: | ||
alert(label + "\n\n" + message); | alert(label + "\n\n" + message); | ||
} | } | ||
Zeile 400: | Zeile 336: | ||
console.assert((__BASE === null) || ((typeof __BASE) === 'function'), "No function:", __BASE); | console.assert((__BASE === null) || ((typeof __BASE) === 'function'), "No function:", __BASE); | ||
console.assert((typeof initFun) === 'function', " | console.assert((typeof initFun) === 'function', "No function:", initFun); | ||
this.init = initFun; | this.init = initFun; | ||
Zeile 428: | Zeile 364: | ||
const __CREATEPROTO = ((createProto === undefined) ? true : createProto); | const __CREATEPROTO = ((createProto === undefined) ? true : createProto); | ||
console.assert((typeof this) === 'function' | console.assert((typeof this) === 'function'); | ||
console.assert((typeof __MEMBERS) === 'object' | console.assert((typeof __MEMBERS) === 'object'); | ||
const __CLASS = new Class(this.name || __MEMBERS.__name, baseClass, initFun || __MEMBERS.__init); | const __CLASS = new Class(this.name || __MEMBERS.__name, baseClass, initFun || __MEMBERS.__init); | ||
Zeile 472: | Zeile 408: | ||
return this.className; | return this.className; | ||
} | } | ||
}); | } ); | ||
// ==================== Ende Abschnitt fuer Klasse Class ==================== | // ==================== Ende Abschnitt fuer Klasse Class ==================== | ||
Zeile 519: | Zeile 455: | ||
this.home = home; | this.home = home; | ||
} | } | ||
}); | } ); | ||
// ==================== Ende Abschnitt fuer Klasse Delims ==================== | // ==================== Ende Abschnitt fuer Klasse Delims ==================== | ||
Zeile 598: | Zeile 534: | ||
this.node = node; | this.node = node; | ||
} | } | ||
}); | } ); | ||
// ==================== Ende Abschnitt fuer Klasse UriDelims ==================== | // ==================== Ende Abschnitt fuer Klasse UriDelims ==================== | ||
Zeile 697: | Zeile 633: | ||
return __DIRS.slice(1); | return __DIRS.slice(1); | ||
} | } | ||
}); | } ); | ||
// ==================== Ende Abschnitt fuer Klasse Path ==================== | // ==================== Ende Abschnitt fuer Klasse Path ==================== | ||
Zeile 756: | Zeile 692: | ||
const __NOSCHEME = this.stripSchemePrefix(path); | const __NOSCHEME = this.stripSchemePrefix(path); | ||
const __INDEXHOST = (__NOSCHEME ? __NOSCHEME.indexOf(__HOSTDELIM) : -1); | const __INDEXHOST = (__NOSCHEME ? __NOSCHEME.indexOf(__HOSTDELIM) : -1); | ||
const __PATH = | const __PATH = (~ __INDEXHOST) ? __NOSCHEME.substring(__INDEXHOST + __HOSTDELIM.length) : __NOSCHEME; | ||
const __INDEXHOSTPORT = (__PATH ? __PATH.indexOf(__ROOTDELIM) : -1); | const __INDEXHOSTPORT = (__PATH ? __PATH.indexOf(__ROOTDELIM) : -1); | ||
const __HOSTPORT = | const __HOSTPORT = (~ __INDEXHOSTPORT) ? __PATH.substring(0, __INDEXHOSTPORT) : undefined; | ||
const __INDEXPORT = (__HOSTPORT ? __HOSTPORT.indexOf(__PORTDELIM) : -1); | const __INDEXPORT = (__HOSTPORT ? __HOSTPORT.indexOf(__PORTDELIM) : -1); | ||
const __HOST = | const __HOST = (~ __INDEXPORT) ? __HOSTPORT.substring(0, __INDEXPORT) : __HOSTPORT; | ||
const __PORT = | const __PORT = (~ __INDEXPORT) ? __HOSTPORT.substring(__INDEXPORT + __PORTDELIM.length) : undefined; | ||
return { | return { | ||
Zeile 772: | Zeile 708: | ||
const __ROOTDELIM = this.delims.root + this.delims.delim; | const __ROOTDELIM = this.delims.root + this.delims.delim; | ||
const __INDEXHOST = (path ? path.indexOf(__HOSTDELIM) : -1); | const __INDEXHOST = (path ? path.indexOf(__HOSTDELIM) : -1); | ||
const __PATH = | const __PATH = (~ __INDEXHOST) ? path.substring(__INDEXHOST + __HOSTDELIM.length) : path; | ||
const __INDEXHOSTPORT = (__PATH ? __PATH.indexOf(__ROOTDELIM) : -1); | const __INDEXHOSTPORT = (__PATH ? __PATH.indexOf(__ROOTDELIM) : -1); | ||
return | return (~ __INDEXHOSTPORT) ? __PATH.substring(__INDEXHOSTPORT) : __PATH; | ||
}, | }, | ||
'getSchemePrefix' : function(path = undefined) { | 'getSchemePrefix' : function(path = undefined) { | ||
Zeile 781: | Zeile 717: | ||
const __INDEXSCHEME = (path ? path.indexOf(__SCHEMEDELIM) : -1); | const __INDEXSCHEME = (path ? path.indexOf(__SCHEMEDELIM) : -1); | ||
return | return (~ __INDEXSCHEME) ? path.substring(0, __INDEXSCHEME) : undefined; | ||
}, | }, | ||
'stripSchemePrefix' : function(path = undefined) { | 'stripSchemePrefix' : function(path = undefined) { | ||
Zeile 787: | Zeile 723: | ||
const __INDEXSCHEME = (path ? path.indexOf(__SCHEMEDELIM) : -1); | const __INDEXSCHEME = (path ? path.indexOf(__SCHEMEDELIM) : -1); | ||
return | return (~ __INDEXSCHEME) ? path.substring(__INDEXSCHEME + __INDEXSCHEME.length) : path; | ||
}, | }, | ||
'getNodeSuffix' : function(path = undefined) { | 'getNodeSuffix' : function(path = undefined) { | ||
Zeile 793: | Zeile 729: | ||
const __INDEXNODE = (path ? path.lastIndexOf(__NODEDELIM) : -1); | const __INDEXNODE = (path ? path.lastIndexOf(__NODEDELIM) : -1); | ||
return | return (~ __INDEXNODE) ? path.substring(__INDEXNODE + __NODEDELIM.length) : undefined; | ||
}, | }, | ||
'stripNodeSuffix' : function(path = undefined) { | 'stripNodeSuffix' : function(path = undefined) { | ||
Zeile 799: | Zeile 735: | ||
const __INDEXNODE = (path ? path.lastIndexOf(__NODEDELIM) : -1); | const __INDEXNODE = (path ? path.lastIndexOf(__NODEDELIM) : -1); | ||
return | return (~ __INDEXNODE) ? path.substring(0, __INDEXNODE) : path; | ||
}, | }, | ||
'getQueryString' : function(path = undefined) { | 'getQueryString' : function(path = undefined) { | ||
Zeile 806: | Zeile 742: | ||
const __INDEXQUERY = (__PATH ? __PATH.indexOf(__QUERYDELIM) : -1); | const __INDEXQUERY = (__PATH ? __PATH.indexOf(__QUERYDELIM) : -1); | ||
return | return (~ __INDEXQUERY) ? __PATH.substring(__INDEXQUERY + __QUERYDELIM.length) : undefined; | ||
}, | }, | ||
'stripQueryString' : function(path = undefined) { | 'stripQueryString' : function(path = undefined) { | ||
Zeile 812: | Zeile 748: | ||
const __INDEXQUERY = (path ? path.indexOf(__QUERYDELIM) : -1); | const __INDEXQUERY = (path ? path.indexOf(__QUERYDELIM) : -1); | ||
return | return (~ __INDEXQUERY) ? path.substring(0, __INDEXQUERY) : path; | ||
}, | }, | ||
'formatParams' : function(params, formatFun, delim = ' ', assign = '=') { | 'formatParams' : function(params, formatFun, delim = ' ', assign = '=') { | ||
Zeile 834: | Zeile 770: | ||
if (__PARAM) { | if (__PARAM) { | ||
const __INDEX = __PARAM.indexOf(assign); | const __INDEX = __PARAM.indexOf(assign); | ||
const __KEY = | const __KEY = (~ __INDEX) ? __PARAM.substring(0, __INDEX) : __PARAM; | ||
const __VAL = | const __VAL = (~ __INDEX) ? parseFun(__PARAM.substring(__INDEX + assign.length)) : true; | ||
__RET[__KEY] = __VAL; | __RET[__KEY] = __VAL; | ||
Zeile 855: | Zeile 791: | ||
const __LOWER = (value ? value.toLowerCase() : undefined); | const __LOWER = (value ? value.toLowerCase() : undefined); | ||
if ((__LOWER === | if ((__LOWER === "true") || (__LOWER === "false")) { | ||
return (value === | return (value === "true"); | ||
} | } | ||
} | } | ||
Zeile 908: | Zeile 844: | ||
return Path.prototype.getDirs.call(this, __PATH); | return Path.prototype.getDirs.call(this, __PATH); | ||
} | } | ||
}); | } ); | ||
// ==================== Ende Abschnitt fuer Klasse URI ==================== | // ==================== Ende Abschnitt fuer Klasse URI ==================== | ||
Zeile 948: | Zeile 884: | ||
return this.getPath(); | return this.getPath(); | ||
} | } | ||
}); | } ); | ||
// ==================== Ende Abschnitt fuer Klasse Directory ==================== | // ==================== Ende Abschnitt fuer Klasse Directory ==================== | ||
Zeile 976: | Zeile 912: | ||
return ret; | return ret; | ||
} | } | ||
}); | } ); | ||
// ==================== Ende Abschnitt fuer Klasse ObjRef ==================== | // ==================== Ende Abschnitt fuer Klasse ObjRef ==================== | ||
Zeile 1.021: | Zeile 957: | ||
// Gibt ein Produkt zurueck. Ist einer der Multiplikanten nicht definiert, wird ein Alternativwert geliefert | // Gibt ein Produkt zurueck. Ist einer der Multiplikanten nicht definiert, wird ein Alternativwert geliefert | ||
// valueA: Ein | // valueA: Ein Multipliksnt. Ist dieser undefined, wird als Produkt defValue zurueckgeliefert | ||
// valueB: Ein | // valueB: Ein Multipliksnt. Ist dieser undefined, wird als Produkt defValue zurueckgeliefert | ||
// digits: Anzahl der Stellen nach dem Komma fuer das Produkt (Default: 0) | // 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) | // defValue: Default-Wert fuer den Fall, dass ein Multiplikant nicht gesetzt ist (Default: NaN) | ||
Zeile 1.031: | Zeile 967: | ||
if ((valueA !== undefined) && (valueB !== undefined)) { | if ((valueA !== undefined) && (valueB !== undefined)) { | ||
product = parseFloat(valueA) * parseFloat(valueB); | product = parseFloat(valueA) * parseFloat(valueB); | ||
} | } | ||
Zeile 1.040: | Zeile 972: | ||
} | } | ||
// Ueberprueft, ob ein Objekt einer bestimmten Klasse angehoert (ggfs. per Vererbung) | |||
// obj: Ein (generisches) Objekt | |||
// Ueberprueft, ob ein Objekt einer bestimmten Klasse angehoert (ggfs. per Vererbung) | |||
// obj: Ein (generisches) Objekt | |||
// base: Eine Objektklasse (Konstruktor-Funktion) | // base: Eine Objektklasse (Konstruktor-Funktion) | ||
// return true, wenn der Prototyp rekursiv gefunden werden konnte | // return true, wenn der Prototyp rekursiv gefunden werden konnte | ||
function instanceOf(obj, base) { | function instanceOf(obj, base) { | ||
while (obj !== null) { | while (obj !== null) { | ||
if (obj === base.prototype) | if (obj === base.prototype) | ||
return true; | return true; | ||
if ((typeof obj) === 'xml') { // Sonderfall mit Selbstbezug | if ((typeof obj) === 'xml') { // Sonderfall mit Selbstbezug | ||
return (base.prototype === XML.prototype); | return (base.prototype === XML.prototype); | ||
Zeile 1.114: | Zeile 1.029: | ||
let active = true; | let active = true; | ||
if (inList) { | if (inList !== undefined) { | ||
active = (inList[item] === true); // gesetzt und true | active = (inList[item] === true); // gesetzt und true | ||
} | } | ||
if (exList) { | if (exList !== undefined) { | ||
if (exList[item] === true) { // gesetzt und true | if (exList[item] === true) { // gesetzt und true | ||
active = false; // NICHT anzeigen | active = false; // NICHT anzeigen | ||
Zeile 1.136: | Zeile 1.051: | ||
if (checkItem(item, addList, ignList)) { | if (checkItem(item, addList, ignList)) { | ||
data[item] = addData[item]; | data[item] = addData[item]; | ||
} | } | ||
} | } | ||
Zeile 1.232: | Zeile 1.132: | ||
} | } | ||
// | // Speichert einen beliebiegen (strukturierten) Wert unter einem Namen ab | ||
// | // name: GM_setValue-Name, unter dem die Daten gespeichert werden | ||
// value: | // value: Beliebiger (strukturierter) Wert | ||
// return | // return String-Darstellung des Wertes | ||
function | function serialize(name, value) { | ||
const __STREAM = (value !== undefined) ? safeStringify(value) : value; | |||
__LOG[4](name + " >> " + __STREAM); | |||
GM_setValue(name, __STREAM); | |||
return | 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 (! | 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(); | |||
if ( | |||
} | } | ||
return value; | |||
return | |||
} | } | ||
// | // Setzt den naechsten Wert aus einer Array-Liste als Option | ||
// name: | // arr: Array-Liste mit den moeglichen Optionen | ||
// value: | // name: Name der Option als Speicherort | ||
// return | // 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 | 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 | |||
// return | function getStoredCmds(memory = undefined) { | ||
function | 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) { | ||
// return | const __BEFORELOAD = getValue(beforeLoad, true); | ||
function | 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); | ||
// return | } | ||
const | // Setzt den Namen einer Option | ||
const | // 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 | return __NAME; | ||
} | } | ||
// | // Setzt den Wert einer Option | ||
// opt: Config und Value der Option | // opt: Config und Value der Option | ||
// | // name: Zu setzender Wert der Option | ||
// return | // 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; | |||
return | |||
} else { | } else { | ||
return | return undefined; | ||
} | } | ||
} | } | ||
// Gibt | // Gibt den Wert einer Option zurueck | ||
// opt: Config und Value der Option | // opt: Config und Value der Option | ||
// | // defValue: Default-Wert fuer den Fall, dass nichts gesetzt ist | ||
// return | // load: Laedt die Option per loadOption(), falls noetig | ||
function | // 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 | 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; | ||
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; | |||
const | |||
__LOG[2]("MEM: " + __SIZE + " bytes"); | |||
return __SIZE; | |||
} else { | |||
return 0; | |||
} | |||
} | |||
// | // Gibt rekursiv und detailliert die Groesse des benutzten Speichers fuer ein Objekt aus | ||
const | // 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 | const __SIZE = value.length; | ||
__OUT("USAGE: " + name + '\t' + __SIZE + '\t' + value.substr(0, 255)); | |||
const | } 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 | // return Gesuchter Speicher oder Null-Speicher ('inaktiv') | ||
function | function restoreMemoryByOpt(opt) { | ||
const __STORAGE = | // 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 | 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 = { }; | |||
const | |||
__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; | |||
return | |||
} | } | ||
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[ | __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 | ||
function | // menuOn: Text zum Setzen im Menu | ||
// funOn: Funktion zum Setzen | |||
const | // 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); | |||
if ( | |||
} | } | ||
} | } | ||
// | // Zeigt den Eintrag im Menu einer Option mit Wahl des naechsten Wertes | ||
// | // val: Derzeitiger Wert der Option | ||
function | // 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); | |||
function | const __VALUE = getOptValue(opt); | ||
const | const __LABEL = __CONFIG.Label; | ||
const | const __ACTION = opt.Action; | ||
const __HOTKEY = __CONFIG.Hotkey; | |||
const __HIDDEN = __CONFIG.HiddenMenu; | |||
const __SERIAL = __CONFIG.Serial; | |||
if ( | 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 { | } else { | ||
// Nur Anzeige im Log... | |||
registerDataOption(__VALUE, __LABEL, __ACTION, __HOTKEY, __HIDDEN, __SERIAL); | |||
} | } | ||
} | } | ||
// ==================== Ende Abschnitt fuer | // ==================== 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 ( | 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 | |||
// return | function initOptAction(optAction, item = undefined, optSet = undefined, optConfig = undefined) { | ||
function | 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 | 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; | ||
// return | } | ||
function | |||
const __OBJREF = new ObjRef(__DBDATA); // Gemeinsame Daten | |||
const | const __PROPS = [ 'namespace', 'module', 'item' ]; | ||
const | 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 | ||
// return | // item: Key der Option | ||
function | // return Entweder optConfig oder gemergete Daten auf Basis des in 'Shared' angegebenen Objekts | ||
function getSharedConfig(optConfig, item = undefined) { | |||
const | 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 | |||
// Initialisiert die gesetzten | // optSet: Platz fuer die gesetzten Optionen | ||
// | // preInit: Vorinitialisierung einzelner Optionen mit 'PreInit'-Attribut | ||
// | // return Gefuelltes Objekt mit den gesetzten Optionen | ||
// return | function initOptions(optConfig, optSet = undefined, preInit = undefined) { | ||
function | let value; | ||
let value | |||
if ( | 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); | |||
return | 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(); | |||
} | } | ||
return | // ... 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 | ||
function | // '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 ( | if ((optParams.menuAnchor !== undefined) && (myOptMem !== __OPTMEMINAKTIVE)) { | ||
buildForm(optParams.menuAnchor, optSet, optParams); | |||
} | } | ||
} | |||
return | // 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 | |||
// return | function getNextOpt(opt, value = undefined) { | ||
function | 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 | return setOpt(__OPT, value, reload); | ||
} | } | ||
// | // Ermittelt die naechste moegliche Option (Version mit Key) | ||
// optSet: Platz fuer die gesetzten Optionen | // 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 | |||
function | |||
return getNextOpt(__OPT, value); | |||
} | } | ||
// Setzt | // Setzt die naechste moegliche Option (Version mit Key) | ||
// | // optSet: Platz fuer die gesetzten Optionen (und Config) | ||
// | // item: Key der Option | ||
// value: | // value: Default fuer ggfs. zu setzenden Wert | ||
// reload: Seite mit neuem Wert neu laden | // reload: Seite mit neuem Wert neu laden | ||
// return Gesetzter Wert | // return Gesetzter Wert | ||
function | function setNextOptByName(optSet, item, value = undefined, reload = false) { | ||
return | 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 | |||
// Setzt die naechste moegliche Option oder fragt ab einer gewissen Anzahl interaktiv ab | |||
// | |||
// value: Default fuer ggfs. zu setzenden Wert | |||
// reload: Seite mit neuem Wert neu laden | // reload: Seite mit neuem Wert neu laden | ||
// freeValue: Angabe, ob Freitext zugelassen ist (Default: false) | // freeValue: Angabe, ob Freitext zugelassen ist (Default: false) | ||
// minChoice: Ab wievielen Auswahlmoeglichkeiten soll abgefragt werden? (Default: 3) | // minChoice: Ab wievielen Auswahlmoeglichkeiten soll abgefragt werden? (Default: 3) | ||
// return Gesetzter Wert | // return Gesetzter Wert | ||
function | function promptNextOptByName(optSet, item, value = undefined, reload = false, freeValue = false, selValue = true, minChoice = 3) { | ||
const | 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) { | |||
const | 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 ( | if (opt.Loaded && __CONFIG.AutoReset) { | ||
// Nur zuruecksetzen, gilt als geladen... | |||
setOptValue(opt, initOptValue(__CONFIG)); | |||
} | } | ||
} | |||
} | |||
const | // 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 ( | 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; | |||
return | // Wert intern setzen... | ||
return setOptValue(opt, value); | |||
} | } | ||
// | // Laedt die (ueber Menu) gesetzten Optionen | ||
// optSet: Set mit den Optionen | |||
// optSet: | // 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]; | |||
// return | if (! __OPT.Loaded) { | ||
function | loadOption(__OPT, force); | ||
const __OPT = | } | ||
} | |||
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 deleteOption(opt, force = false, reset = true) { | ||
function | const __CONFIG = getOptConfig(opt); | ||
const | |||
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 | // 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) { | 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: | // opt: Gesetzte Option | ||
// force: | // name: Neu zu setzender Name (Speicheradresse) | ||
// return | // reload: Wert nachladen statt beizubehalten | ||
function | // 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 | return opt; | ||
} | } | ||
// | // Ermittelt einen neuen Namen mit einem Prefix. Parameter fuer renameOptions() | ||
// | // name: Gesetzter Name (Speicheradresse) | ||
// | // prefix: Prefix, das vorangestellt werden soll | ||
// return | // return Neu zu setzender Name (Speicheradresse) | ||
function | 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 ==================== | ||
for (let | // Legt Input-Felder in einem Form-Konstrukt an, falls noetig | ||
// form: <form>...</form> | |||
// props: Map von name:value-Paaren | |||
if (! | // 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 | 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 | |||
// return | function addHiddenField(form, props) { | ||
function | return addInputField(form, props, "hidden"); | ||
} | |||
if ( | // 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; | |||
return | |||
} | } | ||
} | } | ||
// Entfernt | // 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 | // 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 | // return false bei Misserfolg | ||
function addDocEvent(id, type, callback, capture = false) { | |||
const | 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 | ||
function | // capture: Event fuer Parent zuerst (true) oder Child (false als Default) | ||
return ( | // 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: Name des Elements (siehe "name=") | ||
// | // index: Laufende Nummer des Elements (0-based), Default: 0 | ||
// return | // doc: Dokument (document) | ||
function | // 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 | // 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 | // ==================== 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 | ||
// return | // serial: Serialization fuer String-Werte (Select, Textarea) | ||
function | // 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; | |||
return | 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 | 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 | ||
// type: | // isAlt: Angabe, ob AltAction statt Action gemeint ist | ||
// | // value: Ggfs. zu setzender Wert | ||
// | // type: Event-Typ fuer <input>, z.B. "click" fuer "onclick=" | ||
// return | // serial: Serialization fuer String-Werte (Select, Textarea) | ||
function | // 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 | 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 + '>'; | |||
return | 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 | 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 | 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 | const __VALUE = getOptValue(opt, false); | ||
const | const __ACTION = getFormActionEvent(opt, __VALUE, ! __VALUE, "click", false); | ||
const __FORMLABEL = getValue(__CONFIG.FormLabel, __CONFIG.Label); | |||
return | 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 | const __VALUE = getOptValue(opt); | ||
const | 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 | 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 | const __VALUE = getOptValue(opt, false); | ||
const | const __ACTION = getFormActionEvent(opt, __VALUE, ! __VALUE, "click", false); | ||
const __BUTTONLABEL = (__VALUE ? __CONFIG.AltLabel : __CONFIG.Label); | |||
const __FORMLABEL = getValue(__CONFIG.FormLabel, __CONFIG.Label); | |||
return | 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 | ||
// return | function getOptionElement(opt) { | ||
function | const __CONFIG = getOptConfig(opt); | ||
const | const __TYPE = getValue(__CONFIG.FormType, __CONFIG.Type); | ||
const | 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 | 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 | 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 | //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 | 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 | ||
function | // '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(); | |||
function | |||
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)); | |||
function | |||
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'; | |||
function | |||
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... | ||
// optSet: | __TEAMCLASS.optSelect = { | ||
// | 'ligaSize' : true | ||
}; | |||
// | |||
// return | // Gibt die Teamdaten zurueck und aktualisiert sie ggfs. in der Option | ||
function | // 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 | //return ((myTeam.length > 0) ? myTeam : undefined); | ||
return myTeam; | |||
} | } | ||
// | // Behandelt die Optionen und laedt das Benutzermenu | ||
// | // optConfig: Konfiguration der Optionen | ||
// optSet: | // optSet: Platz fuer die gesetzten Optionen | ||
// optParams: Eventuell notwendige Parameter | // 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) | // 'showForm': Checkliste der auf der Seite sichtbaren Optionen (true fuer sichtbar) | ||
// 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar) | // 'hideForm': Checkliste der auf der Seite unsichtbaren Optionen (true fuer unsichtbar) | ||
// 'formWidth': Anzahl der Elemente pro Zeile | // 'formWidth': Anzahl der Elemente pro Zeile | ||
// 'formBreak': Elementnummer des ersten Zeilenumbruchs | // 'formBreak': Elementnummer des ersten Zeilenumbruchs | ||
function | // 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 | 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; | |||
} | } | ||
// ==================== Abschnitt fuer | // ==================== 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( | 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>"; | |||
} | |||
} | |||
}); | |||
// Klasse | // ==================== 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 (( | 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); | |||
// | |||
// | |||
function | |||
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 + ')'; | |||
} | |||
function | // 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 | function getLandNr(land) { | ||
return ( | return getValue(__LANDNRN[land], __LANDNRN.unbekannt); | ||
} | } | ||
// | // Gibt die ID der Liga mit dem uebergebenen Namen zurueck. | ||
// | // land: Name der Liga | ||
// return | // return OS2-ID der Liga, 0 fuer ungueltig | ||
function | function getLigaNr(liga) { | ||
if ( | return getValue(__LIGANRN[liga], __LIGANRN.unbekannt); | ||
return | } | ||
// 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 { | } else { | ||
return | 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) { | ||
function | const __ERGEBNIS = cell.textContent.split(" : ", 2); | ||
const | |||
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 | // currZAT: Enthaelt den Spielplanzeiger auf den aktuellen ZAT | ||
// | // cell: Tabellenzelle mit Eintrag "2 : 1" | ||
function setErgebnisFromCell(currZAT, cell) { | |||
function | const __ERGEBNIS = getErgebnisFromCell(cell); | ||
const | |||
if ( | 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); | |||
if ( | |||
const | 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 | 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; | |||
return | 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 | 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))) { | |||
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 *** | // *** EOF *** | ||
</pre> | </pre> |