Bearbeiten von „OS2.jugend

Zur Navigation springen Zur Suche springen
Warnung: Du bist nicht angemeldet. Deine IP-Adresse wird bei Bearbeitungen öffentlich sichtbar. Melde dich an oder erstelle ein Benutzerkonto, damit Bearbeitungen deinem Benutzernamen zugeordnet werden. Ein eigenes Benutzerkonto hat eine ganze Reihe von Vorteilen.

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]]
[[Kategorie:Greasemonkey WE]]
{| 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.jugend'''
| colspan="2" style="padding:0.3em; background-color:#9C1818; font-size: 18px; color:#FFFFFF" align=center| '''OS2.jugend'''
Zeile 8: Zeile 7:
|- bgcolor="#FFCC00"
|- bgcolor="#FFCC00"
| '''Version'''
| '''Version'''
| '''0.73 (WebExtensions)'''
| '''0.53'''
|- bgcolor="#FFCC00"
|- bgcolor="#FFCC00"
| '''Autor'''
| '''Autor'''
Zeile 27: Zeile 26:
| '''ju.php?page=2'''
| '''ju.php?page=2'''
| '''Jugendteam-Spielereinzelwerte'''
| '''Jugendteam-Spielereinzelwerte'''
|-
| '''ju.php?page=3'''
| '''Jugendteam-Opt. Skill'''
|-
| '''ju.php?page=4'''
| '''Jugendteam-Optionen'''
|}
|}
|- bgcolor="#FFCC00"
|- bgcolor="#FFCC00"
| '''Funktionalität'''
| '''Funktionalität'''
| '''Trennstriche zwischen den Jahrgängen'''<br> '''Aktueller Skill, Opti und MW'''<br> '''Prognose von Opti und MW für Ende Jahrgang 18'''<br> '''Optionen und Menu'''<br> '''Neue Marktwertformel'''<br> '''Automatische Ermittlung des ZATs'''<br> '''Hidden-Optionen und Datenspeicher'''<br> '''Geburtstage und dezimales Alter'''<br> '''Erweiterte Optionen auch auf der Seite'''<br> '''Zusatzspalten Talent/Quote/Aufw./Geb./Alter'''<br> '''Zusatzspalten Quote/Alter/Pos in der Übersicht'''<br> '''Zusatzspalten Alter ersetzen/Aufwertungen kurz+TOR'''<br> '''Zusatzspalten fix/tr./%H/%N/Prios jetzt und Ende'''<br> '''Interaktive Menü-Optionen'''<br> '''Gemeinsame Code- und Datenbasis'''<br> '''Qualitätsbalken'''<br> '''Markierung der Primärskills bei Einzelwerten und Aufwertungen'''<br> '''Beachtung von Jugendförderung und Doppelpositionen'''<br> '''Warnung vor Ende 18 in letzter Periode und mehr am letzten ZAT'''<br> '''Reguläre Ausdrücke im @include'''<br> '''Neues Design und Seite "Opt. Skill"'''<br> '''Gruppierung nach Jahrgängen U13 bis U18 (per Option)'''<br> '''Warnung vor Ende 18 auch im Managerbüro (per Option)'''<br> '''Warnung vor Sperre des Ziehens im Falle eines Aufstiegs'''<br> '''Neuer Jahrgang U19'''
| '''Trennstriche zwischen den Jahrgängen'''<br> '''Aktueller Skill, Opti und MW'''<br> '''Prognose von Opti und MW für Ende Jahrgang 18'''<br> '''Optionen und Menu'''<br> '''Neue Marktwertformel'''<br> '''Automatische Ermittlung des ZATs'''<br> '''Hidden-Optionen und Datenspeicher'''<br> '''Geburtstage und dezimales Alter'''<br> '''Erweiterte Optionen auch auf der Seite'''<br> '''Zusatzspalten Talent/Quote/Aufw./Geb./Alter'''<br> '''Zusatzspalten Quote/Alter/Pos in der Übersicht'''<br> '''Zusatzspalten Alter ersetzen/Aufwertungen kurz+TOR'''<br> '''Zusatzspalten fix/tr./%H/%N/Prios jetzt und Ende'''<br> '''Interaktive Menü-Optionen'''<br> '''Gemeinsame Code- und Datenbasis'''<br> '''Qualitätsbalken'''<br> '''Markierung der Primärskills bei Einzelwerten und Aufwertungen'''<br> '''Beachtung von Jugendförderung und Doppelpositionen'''<br> '''Warnung vor Ende 18 in letzer Periode und mehr am letzten ZAT'''<br> '''Reguläre Ausdrücke im @include'''


|- bgcolor="#FFCC00"
|- bgcolor="#FFCC00"
Zeile 48: Zeile 41:
// @name        OS2.jugend
// @name        OS2.jugend
// @namespace    http://os.ongapo.com/
// @namespace    http://os.ongapo.com/
// @version      0.73
// @version      0.53
// @copyright    2013+
// @copyright    2013+
// @author      Sven Loges (SLC) / Andreas Eckes (Strindheim BK)
// @author      Andreas Eckes (Strindheim BK) / Sven Loges (SLC)
// @description  Jugendteam-Script fuer Online Soccer 2.0
// @description  Jugendteam-Script fuer Online Soccer 2.0
// @include      /^https?://(www\.)?(os\.ongapo\.com|online-soccer\.eu|os-zeitungen\.com)/haupt\.php(\?changetosecond=\w+(&\S+)*)?$/
// @include      /^https?://(www\.)?(os\.ongapo\.com|online-soccer\.eu|os-zeitungen\.com)/haupt\.php(\?changetosecond=\w+(&\S+)*)?$/
// @include      /^https?://(www\.)?(os\.ongapo\.com|online-soccer\.eu|os-zeitungen\.com)/ju\.php(\?page=\d+(&\S+)*)?$/
// @include      /^https?://(www\.)?(os\.ongapo\.com|online-soccer\.eu|os-zeitungen\.com)/ju\.php(\?page=\d+(&\S+)*)?$/
// @grant        GM.getValue
// @grant        GM.setValue
// @grant        GM.deleteValue
// @grant        GM.registerMenuCommand
// @grant        GM.info
// @require      https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
// @grant        GM_getValue
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_setValue
Zeile 67: Zeile 54:
// ==/UserScript==
// ==/UserScript==


// ECMAScript 6:
// ECMAScript 6: Erlaubt 'const', 'let', ...
/* jshint esnext: true */
/* jshint esnext: true */
/* jshint moz: true */
/* jshint moz: true */
Zeile 73: Zeile 60:
// ==================== Konfigurations-Abschnitt fuer Optionen ====================
// ==================== Konfigurations-Abschnitt fuer Optionen ====================


const __LOGLEVEL = 3;
const __LOGLEVEL = 6;


// Options-Typen
// Options-Typen
Zeile 124: Zeile 111:
                   'AltHotkey' : 'k',
                   'AltHotkey' : 'k',
                   'FormLabel' : "Prognose Einzelwerte"
                   'FormLabel' : "Prognose Einzelwerte"
              },
    'zeigeJahrgang' : {  // Auswahl, ob ueber jedem Jahrgang die Ueberschriften gezeigt werden sollen oder alles in einem Block (true = Jahrgaenge, false = ein Block)
                  'Name'      : "showGroupTitle",
                  'Type'      : __OPTTYPES.SW,
                  'Default'  : true,
                  'Action'    : __OPTACTION.NXT,
                  'Label'    : "Jahrgangs\xFCberschriften",
                  'Hotkey'    : 'J',
                  'AltLabel'  : "Nur Trennlinie benutzen",
                  'AltHotkey' : 'j',
                  'FormLabel' : "Jahrg\xE4nge gruppieren"
              },
    'zeigeUxx' : {        // Auswahl, ob in der Ueberschrift ueber jedem Jahrgang zusaetzlich zur Saison noch der Jahrgang in der Form 'Uxx' angegeben wird
                  'Name'      : "showUxx",
                  'Type'      : __OPTTYPES.SW,
                  'Default'  : true,
                  'Action'    : __OPTACTION.NXT,
                  'Label'    : "Jahrg\xE4nge anzeigen",
                  'Hotkey'    : 'U',
                  'AltLabel'  : "Nur Saisons anzeigen",
                  'AltHotkey' : 'u',
                  'FormLabel' : "Jahrg\xE4nge U13 bis U19"
              },
    'zeigeWarnung' : {    // Auswahl, ob eine Warnung erscheint, wenn Talente gezogen werden sollten
                  'Name'      : "showWarning",
                  'Type'      : __OPTTYPES.SW,
                  'Default'  : true,
                  'Action'    : __OPTACTION.NXT,
                  'Label'    : "Ziehwarnung ein",
                  'Hotkey'    : 'Z',
                  'AltLabel'  : "Ziehwarnung aus",
                  'AltHotkey' : 'Z',
                  'FormLabel' : "Ziehwarnung"
              },
    'zeigeWarnungMonat' : {  // Auswahl, ob eine Warnung erscheint, wenn zum naechsten Abrechnungs-ZAT Talente gezogen werden sollten
                  'Name'      : "showWarningMonth",
                  'Type'      : __OPTTYPES.SW,
                  'Default'  : true,
                  'Action'    : __OPTACTION.NXT,
                  'Label'    : "Ziehwarnung Monat ein",
                  'Hotkey'    : 'Z',
                  'AltLabel'  : "Ziehwarnung Monat aus",
                  'AltHotkey' : 'Z',
                  'FormLabel' : "Ziehwarnung Monat"
              },
    'zeigeWarnungHome' : {  // Auswahl, ob eine Meldung im Managerbuero erscheint, wenn Talente gezogen werden sollten
                  'Name'      : "showWarningHome",
                  'Type'      : __OPTTYPES.SW,
                  'Default'  : true,
                  'Action'    : __OPTACTION.NXT,
                  'Label'    : "Ziehwarnung B\xFCro ein",
                  'Hotkey'    : 'z',
                  'AltLabel'  : "Ziehwarnung B\xFCro aus",
                  'AltHotkey' : 'z',
                  'FormLabel' : "Ziehwarnung B\xFCro"
              },
    'zeigeWarnungDialog' : {  // Auswahl, ob die Meldung im Managerbuero als Dialog erscheinen soll
                  'Name'      : "showWarningDialog",
                  'Type'      : __OPTTYPES.SW,
                  'Default'  : false,
                  'Action'    : __OPTACTION.NXT,
                  'Label'    : "Ziehwarnung B\xFCro als Dialog",
                  'Hotkey'    : 'z',
                  'AltLabel'  : "Ziehwarnung B\xFCro als Textmeldung",
                  'AltHotkey' : 'z',
                  'FormLabel' : "Ziehwarnung B\xFCro Dialog"
              },
    'zeigeWarnungAufstieg' : {  // Auswahl, ob eine Warnung in der Uebersicht erscheint, wenn Talente nach Aufstieg nicht mehr gezogen werden koennen
                  'Name'      : "showWarningAufstieg",
                  'Type'      : __OPTTYPES.SW,
                  'Default'  : true,
                  'Action'    : __OPTACTION.NXT,
                  'Label'    : "Ziehwarnung Aufstieg ein",
                  'Hotkey'    : 'ä',
                  'AltLabel'  : "Ziehwarnung Aufstieg aus",
                  'AltHotkey' : 'ä',
                  'FormLabel' : "Ziehwarnung Aufstieg"
              },
    'zeigeWarnungLegende' : {  // Auswahl, ob eine extra Meldung in Teamuebersicht erscheint, die dort als Legende dient
                  'Name'      : "showWarningLegende",
                  'Type'      : __OPTTYPES.SW,
                  'Default'  : true,
                  'Action'    : __OPTACTION.NXT,
                  'Label'    : "Ziehwarnung Legende ein",
                  'Hotkey'    : 'L',
                  'AltLabel'  : "Ziehwarnung Legende aus",
                  'AltHotkey' : 'L',
                  'FormLabel' : "Ziehwarnung Legende"
               },
               },
     'zeigeBalken' : {    // Spaltenauswahl fuer den Qualitaetsbalken des Talents (true = anzeigen, false = nicht anzeigen)
     'zeigeBalken' : {    // Spaltenauswahl fuer den Qualitaetsbalken des Talents (true = anzeigen, false = nicht anzeigen)
Zeile 224: Zeile 123:
                   'FormLabel' : "Balken Qualit\xE4t"
                   'FormLabel' : "Balken Qualit\xE4t"
               },
               },
     'absBalken' : {       // Spaltenauswahl fuer den Guetebalken des Talents absolut statt nach Foerderung (true = absolut, false = relativ nach Foerderung)
     'absBalken' : {     // Spaltenauswahl fuer den Guetebalken des Talents absolut statt nach Foerderung (true = absolut, false = relativ nach Foerderung)
                   'Name'      : "absBar",
                   'Name'      : "absBar",
                   'Type'      : __OPTTYPES.SW,
                   'Type'      : __OPTTYPES.SW,
Zeile 427: Zeile 326:
                   'Name'      : "anzOpti",
                   'Name'      : "anzOpti",
                   'Type'      : __OPTTYPES.MC,
                   'Type'      : __OPTTYPES.MC,
                   'ValType'  : 'Number',
                   'ValType'  : "Number",
                   'SelValue'  : false,
                   'SelValue'  : false,
                   'Choice'    : [ 0, 1, 2, 3, 4, 5, 6 ],
                   'Choice'    : [ 0, 1, 2, 3, 4, 5, 6 ],
Zeile 440: Zeile 339:
                   'Name'      : "anzMW",
                   'Name'      : "anzMW",
                   'Type'      : __OPTTYPES.MC,
                   'Type'      : __OPTTYPES.MC,
                   'ValType'  : 'Number',
                   'ValType'  : "Number",
                   'SelValue'  : false,
                   'SelValue'  : false,
                   'Choice'    : [ 0, 1, 2, 3, 4, 5, 6 ],
                   'Choice'    : [ 0, 1, 2, 3, 4, 5, 6 ],
Zeile 509: Zeile 408:
                   'Name'      : "anzOptiEnde",
                   'Name'      : "anzOptiEnde",
                   'Type'      : __OPTTYPES.MC,
                   'Type'      : __OPTTYPES.MC,
                   'ValType'  : 'Number',
                   'ValType'  : "Number",
                   'SelValue'  : false,
                   'SelValue'  : false,
                   'Choice'    : [ 0, 1, 2, 3, 4, 5, 6 ],
                   'Choice'    : [ 0, 1, 2, 3, 4, 5, 6 ],
Zeile 523: Zeile 422:
                   'Name'      : "anzMWEnde",
                   'Name'      : "anzMWEnde",
                   'Type'      : __OPTTYPES.MC,
                   'Type'      : __OPTTYPES.MC,
                   'ValType'  : 'Number',
                   'ValType'  : "Number",
                   'SelValue'  : false,
                   'SelValue'  : false,
                   'Choice'    : [ 0, 1, 2, 3, 4, 5, 6 ],
                   'Choice'    : [ 0, 1, 2, 3, 4, 5, 6 ],
Zeile 535: Zeile 434:
                   'Name'      : "charEnde",
                   'Name'      : "charEnde",
                   'Type'      : __OPTTYPES.MC,
                   'Type'      : __OPTTYPES.MC,
                   'ValType'  : 'String',
                   'ValType'  : "String",
                   'FreeValue' : true,
                   'FreeValue' : true,
                   'MinChoice' : 0,
                   'MinChoice' : 0,
Zeile 547: Zeile 446:
                   'Name'      : "sepStyle",
                   'Name'      : "sepStyle",
                   'Type'      : __OPTTYPES.MC,
                   'Type'      : __OPTTYPES.MC,
                   'ValType'  : 'String',
                   'ValType'  : "String",
                   'Choice'    : [ 'solid', 'hidden', 'dotted', 'dashed', 'double', 'groove', 'ridge',
                   'Choice'    : [ "solid", "hidden", "dotted", "dashed", "double", "groove", "ridge",
                                   'inset', 'outset', 'none' ],
                                   "inset", "outset", "none" ],
                   'Action'    : __OPTACTION.NXT,
                   'Action'    : __OPTACTION.NXT,
                   'Label'    : "Stil: $",
                   'Label'    : "Stil: $",
Zeile 558: Zeile 457:
                   'Name'      : "sepColor",
                   'Name'      : "sepColor",
                   'Type'      : __OPTTYPES.MC,
                   'Type'      : __OPTTYPES.MC,
                   'ValType'  : 'String',
                   'ValType'  : "String",
                   'FreeValue' : true,
                   'FreeValue' : true,
                   'Choice'    : [ 'white', 'yellow', 'black', 'blue', 'cyan', 'gold', 'grey', 'green',
                   'Choice'    : [ "white", "yellow", "black", "blue", "cyan", "gold", "grey", "green",
                                   'lime', 'magenta', 'maroon', 'navy', 'olive', 'orange', 'purple',
                                   "lime", "magenta", "maroon", "navy", "olive", "orange", "purple",
                                   'red', 'teal', 'transparent' ],
                                   "red", "teal", "transparent" ],
                   'Action'    : __OPTACTION.NXT,
                   'Action'    : __OPTACTION.NXT,
                   'Label'    : "Farbe: $",
                   'Label'    : "Farbe: $",
Zeile 571: Zeile 470:
                   'Name'      : "sepWidth",
                   'Name'      : "sepWidth",
                   'Type'      : __OPTTYPES.MC,
                   'Type'      : __OPTTYPES.MC,
                   'ValType'  : 'String',
                   'ValType'  : "String",
                   'FreeValue' : true,
                   'FreeValue' : true,
                   'Choice'    : [ 'thin', 'medium', 'thick' ],
                   'Choice'    : [ "thin", "medium", "thick" ],
                   'Action'    : __OPTACTION.NXT,
                   'Action'    : __OPTACTION.NXT,
                   'Label'    : "Dicke: $",
                   'Label'    : "Dicke: $",
Zeile 582: Zeile 481:
                   'Name'      : "saison",
                   'Name'      : "saison",
                   'Type'      : __OPTTYPES.MC,
                   'Type'      : __OPTTYPES.MC,
                   'ValType'  : 'Number',
                   'ValType'  : "Number",
                   'FreeValue' : true,
                   'FreeValue' : true,
                   'SelValue'  : false,
                   'SelValue'  : false,
                   'Choice'    : [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 ],
                   'Choice'    : [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ],
                   'Default'  : 16,
                   'Default'  : 11,
                   'Action'    : __OPTACTION.NXT,
                   'Action'    : __OPTACTION.NXT,
                   'Label'    : "Saison: $",
                   'Label'    : "Saison: $",
Zeile 595: Zeile 494:
                   'Name'      : "currZAT",
                   'Name'      : "currZAT",
                   'Type'      : __OPTTYPES.MC,
                   'Type'      : __OPTTYPES.MC,
                   'ValType'  : 'Number',
                   'ValType'  : "Number",
                   'Permanent' : true,
                   'Permanent' : true,
                   'SelValue'  : false,
                   'SelValue'  : false,
Zeile 613: Zeile 512:
                   'Name'      : "dataZAT",
                   'Name'      : "dataZAT",
                   'Type'      : __OPTTYPES.SD,
                   'Type'      : __OPTTYPES.SD,
                   'ValType'  : 'Number',
                   'ValType'  : "Number",
                   'Hidden'    : true,
                   'Hidden'    : true,
                   'Serial'    : true,
                   'Serial'    : true,
Zeile 630: Zeile 529:
                   'Name'      : "oldDataZAT",
                   'Name'      : "oldDataZAT",
                   'Type'      : __OPTTYPES.SD,
                   'Type'      : __OPTTYPES.SD,
                   'ValType'  : 'Number',
                   'ValType'  : "Number",
                   'Hidden'    : true,
                   'Hidden'    : true,
                   'Serial'    : true,
                   'Serial'    : true,
Zeile 647: Zeile 546:
                   'Name'      : "donation",
                   'Name'      : "donation",
                   'Type'      : __OPTTYPES.MC,
                   'Type'      : __OPTTYPES.MC,
                   'ValType'  : 'Number',
                   'ValType'  : "Number",
                   'Permanent' : true,
                   'Permanent' : true,
                   'SelValue'  : false,
                   'SelValue'  : false,
Zeile 732: Zeile 631:
                   'Label'    : "Aufwertungen:"
                   'Label'    : "Aufwertungen:"
               },
               },
     'ziehAnz' : {        // Datenspeicher fuer Anzahl zu ziehender Jugendspieler bis zur naechsten Abrechnung
     'zatAges' : {        // Datenspeicher fuer (gebrochene) Alter der Jugendspieler
                   'Name'      : "drawCounts",
                   'Name'      : "zatAges",
                   'Type'      : __OPTTYPES.SD,
                   'Type'      : __OPTTYPES.SD,
                   'Hidden'    : true,
                   'Hidden'    : true,
                   'Serial'    : true,
                   'Serial'    : true,
                   'AutoReset' : false,
                   'AutoReset' : true,
                   'Permanent' : true,
                   'Permanent' : true,
                   'Default'  : [],
                   'Default'  : [],
                   'Submit'    : undefined,
                   'Submit'    : undefined,
                   'Cols'      : 25,
                   'Cols'      : 36,
                   'Rows'      : 1,
                   'Rows'      : 2,
                   'Replace'  : null,
                   'Replace'  : null,
                   'Space'    : 0,
                   'Space'    : 0,
                  'Label'    : "Zu ziehen:"
                   'Label'    : "ZAT-Alter:"
              },
    'ziehAnzAufstieg' : { // Datenspeicher fuer Anzahl zu ziehender Jugendspieler bis zur naechsten Abrechnung im Falle eines Aufstiegs
                  'Name'      : "drawCountsAufstieg",
                  'Type'      : __OPTTYPES.MC,
                  'ValType'  : 'Number',
                  'Hidden'    : true,
                  'AutoReset' : false,
                  'Permanent' : true,
                  'FreeValue' : true,
                  'SelValue'  : false,
                  'Choice'    : [ 0, 1, 2, 3, 4, 5 ],
                  'Default'  : 0,
                  'Action'    : __OPTACTION.NXT,
                  'Label'    : "Zu ziehen bei Aufstieg: $",
                  'Hotkey'    : 'z',
                  'FormLabel' : "Zu ziehen bei Aufstieg:|$"
              },
    'zatAges' : {        // Datenspeicher fuer (gebrochene) Alter der Jugendspieler
                  'Name'      : "zatAges",
                  'Type'      : __OPTTYPES.SD,
                  'Hidden'    : true,
                  'Serial'    : true,
                  'AutoReset' : true,
                  'Permanent' : true,
                  'Default'  : [],
                  'Submit'    : undefined,
                  'Cols'      : 36,
                  'Rows'      : 2,
                  'Replace'  : null,
                  'Space'    : 0,
                   'Label'    : "ZAT-Alter:"
               },
               },
     'trainiert' : {      // Datenspeicher fuer Trainingsquoten der Jugendspieler
     'trainiert' : {      // Datenspeicher fuer Trainingsquoten der Jugendspieler
Zeile 858: Zeile 726:
               },
               },
     'reset' : {          // Optionen auf die "Werkseinstellungen" zuruecksetzen
     'reset' : {          // Optionen auf die "Werkseinstellungen" zuruecksetzen
                  'FormPrio'  : undefined,
                   'Name'      : "reset",
                   'Name'      : "reset",
                   'Type'      : __OPTTYPES.SI,
                   'Type'      : __OPTTYPES.SI,
Zeile 867: Zeile 734:
               },
               },
     'storage' : {        // Browserspeicher fuer die Klicks auf Optionen
     'storage' : {        // Browserspeicher fuer die Klicks auf Optionen
                  'FormPrio'  : undefined,
                   'Name'      : "storage",
                   'Name'      : "storage",
                   'Type'      : __OPTTYPES.MC,
                   'Type'      : __OPTTYPES.MC,
                   'ValType'  : 'String',
                   'ValType'  : "String",
                   'Choice'    : Object.keys(__OPTMEM),
                   'Choice'    : Object.keys(__OPTMEM),
                   'Action'    : __OPTACTION.NXT,
                   'Action'    : __OPTACTION.NXT,
Zeile 878: Zeile 744:
               },
               },
     'oldStorage' : {      // Vorheriger Browserspeicher fuer die Klicks auf Optionen
     'oldStorage' : {      // Vorheriger Browserspeicher fuer die Klicks auf Optionen
                  'FormPrio'  : undefined,
                   'Name'      : "oldStorage",
                   'Name'      : "oldStorage",
                   'Type'      : __OPTTYPES.SD,
                   'Type'      : __OPTTYPES.SD,
Zeile 886: Zeile 751:
               },
               },
     'showForm' : {        // Optionen auf der Webseite (true = anzeigen, false = nicht anzeigen)
     'showForm' : {        // Optionen auf der Webseite (true = anzeigen, false = nicht anzeigen)
                  'FormPrio'  : 1,
                   'Name'      : "showForm",
                   'Name'      : "showForm",
                   'Type'      : __OPTTYPES.SW,
                   'Type'      : __OPTTYPES.SW,
Zeile 892: Zeile 756:
                   'Permanent' : true,
                   'Permanent' : true,
                   'Default'  : false,
                   'Default'  : false,
                  'Title'    : "$V Optionen",
                   'Action'    : __OPTACTION.NXT,
                   'Action'    : __OPTACTION.NXT,
                   'Label'    : "Optionen anzeigen",
                   'Label'    : "Optionen anzeigen",
                   'Hotkey'    : 'O',
                   'Hotkey'    : 'O',
                  'AltTitle'  : "$V schlie\xDFen",
                   'AltLabel'  : "Optionen verbergen",
                   'AltLabel'  : "Optionen verbergen",
                   'AltHotkey' : 'O',
                   'AltHotkey' : 'O',
Zeile 907: Zeile 769:
// Ein Satz von Logfunktionen, die je nach Loglevel zur Verfuegung stehen. Aufruf: __LOG[level](text)
// Ein Satz von Logfunktionen, die je nach Loglevel zur Verfuegung stehen. Aufruf: __LOG[level](text)
const __LOG = {
const __LOG = {
                   'logFun'   : [
                   'logFun'   : [
                                    console.error,  // [0] Alert
                                  console.error,  // [0] Alert
                                    console.error,  // [1] Error
                                  console.error,  // [1] Error
                                    console.log,    // [2] Log: Release
                                  console.log,    // [2] Log: Release
                                    console.log,    // [3] Log: Info
                                  console.log,    // [3] Log: Info
                                    console.log,    // [4] Log: Debug
                                  console.log,    // [4] Log: Debug
                                    console.log,    // [5] Log: Verbose
                                  console.log,    // [5] Log: Verbose
                                    console.log,    // [6] Log: Very verbose
                                  console.log     // [6] Log: Very verbose
                                    console.warn    // [7] Log: Testing
                              ],
                                ],
                   'init'     : function(win, logLevel = 1) {
                   'init'     : function(win, logLevel = 1) {
                                  for (level = 0; level < this.logFun.length; level++) {
                                    for (let level = 0; level < this.logFun.length; level++) {
                                      this[level] = ((level > logLevel) ? function() { } : this.logFun[level]);
                                        this[level] = ((level > logLevel) ? function() { } : this.logFun[level]);
                                  }
                                    }
                              },
                                },
                   'changed' : function(oldVal, newVal) {
                  'stringify' : safeStringify,      // JSON.stringify
                                  const __OLDVAL = safeStringify(oldVal);
                   'changed'   : function(oldVal, newVal) {
                                  const __NEWVAL = safeStringify(newVal);
                                    const __OLDVAL = this.stringify(oldVal);
                                    const __NEWVAL = this.stringify(newVal);


                                    return ((__OLDVAL !== __NEWVAL) ? __OLDVAL + " => " : "") + __NEWVAL;
                                  return ((__OLDVAL !== __NEWVAL) ? __OLDVAL + " => " : "") + __NEWVAL;
                                }
                              }
               };
               };


Zeile 968: Zeile 828:
// 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
// return Liefert die Parameter zurueck
function showAlert(label, message, data = undefined) {
function showAlert(label, message, data = undefined) {
     __LOG[0](label + ": " + message);
     __LOG[1](label + ": " + message);


     if (data !== undefined) {
     if (data !== undefined) {
Zeile 977: Zeile 836:


     alert(label + "\n\n" + message);
     alert(label + "\n\n" + message);
    return arguments;
}
// Gibt eine Meldung in der Console aus und oeffnet ein Bestaetigungsfenster
// mit der Meldung zu einer Exception oder einer Fehlermeldung
// label: Eine Ueberschrift
// ex: Exception oder sonstiges Fehlerobjekt
// return Liefert die showAlert()-Parameter zurueck
function showException(label, ex) {
    if (ex && ex.message) {  // Exception
        showAlert(label, ex.message, ex);
    } else {  // sonstiger Fehler
        showAlert(label, ex);
    }
}
// Standard-Callback-Funktion fuer onRejected, also abgefangener Fehler
// in einer Promise bei Exceptions oder Fehler bzw. Rejections
// error: Parameter von reject() im Promise-Objekt, der von Promise.catch() erhalten wurde
// return Liefert die showAlert()-Parameter zurueck
function defaultCatch(error) {
    try {
        const __LABEL = `[${error.lineNumber}] ${__DBMOD.Name}`;
        if (error && error.message) {  // Exception
            return showException(__LABEL, error.message, error);
        } else {
            return showException(__LABEL, error);
        }
    } catch (ex) {
        return showException(`[${ex.lineNumber}] ${__DBMOD.Name}`, ex.message, ex);
    }
}
}


Zeile 1.115: Zeile 941:
                                         return this.className;
                                         return this.className;
                                     }
                                     }
                 });
                 } );


// ==================== Ende Abschnitt fuer Klasse Class ====================
// ==================== Ende Abschnitt fuer Klasse Class ====================
Zeile 1.162: Zeile 988:
                                     this.home = home;
                                     this.home = home;
                                 }
                                 }
           });
           } );


// ==================== Ende Abschnitt fuer Klasse Delims ====================
// ==================== Ende Abschnitt fuer Klasse Delims ====================
Zeile 1.241: Zeile 1.067:
                                     this.node = node;
                                     this.node = node;
                                 }
                                 }
           });
           } );


// ==================== Ende Abschnitt fuer Klasse UriDelims ====================
// ==================== Ende Abschnitt fuer Klasse UriDelims ====================
Zeile 1.340: Zeile 1.166:
                                         return __DIRS.slice(1);
                                         return __DIRS.slice(1);
                                     }
                                     }
                 });
                 } );


// ==================== Ende Abschnitt fuer Klasse Path ====================
// ==================== Ende Abschnitt fuer Klasse Path ====================
Zeile 1.498: Zeile 1.324:
                                             const __LOWER = (value ? value.toLowerCase() : undefined);
                                             const __LOWER = (value ? value.toLowerCase() : undefined);


                                             if ((__LOWER === 'true') || (__LOWER === 'false')) {
                                             if ((__LOWER === "true") || (__LOWER === "false")) {
                                                 return (value === 'true');
                                                 return (value === "true");
                                             }
                                             }
                                         }
                                         }
Zeile 1.551: Zeile 1.377:
                                         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 1.591: Zeile 1.417:
                                   return this.getPath();
                                   return this.getPath();
                               }
                               }
                 });
                 } );


// ==================== Ende Abschnitt fuer Klasse Directory ====================
// ==================== Ende Abschnitt fuer Klasse Directory ====================
Zeile 1.619: Zeile 1.445:
                                     return ret;
                                     return ret;
                                 }
                                 }
                 });
                 } );


// ==================== Ende Abschnitt fuer Klasse ObjRef ====================
// ==================== Ende Abschnitt fuer Klasse ObjRef ====================
Zeile 1.664: Zeile 1.490:


// 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 Multiplikant. Ist dieser undefined, wird als Produkt defValue zurueckgeliefert
// valueA: Ein Multipliksnt. Ist dieser undefined, wird als Produkt defValue zurueckgeliefert
// valueB: Ein Multiplikant. Ist dieser undefined, wird als Produkt defValue zurueckgeliefert
// valueB: Ein Multipliksnt. Ist dieser undefined, wird als Produkt defValue zurueckgeliefert
// digits: Anzahl der Stellen nach dem Komma fuer das Produkt (Default: 0)
// 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.681: Zeile 1.507:


     return parseFloat(product.toFixed(digits));
     return parseFloat(product.toFixed(digits));
}
// Gibt eine Ordinalzahl zur uebergebenen Zahl zurueck
// value: Eine ganze Zahl
// defValue: Default-Wert fuer den Fall, dass der Wert nicht gesetzt ist (Default: '*')
// return Die Ordinalzahl als String der Form "n." oder defValue, falls nicht angegeben
function getOrdinal(value, defValue = '*') {
    return getValue(value, defValue, value + '.');
}
}


Zeile 1.705: Zeile 1.523:
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.785: Zeile 1.602:
}
}


// Entfernt Properties in einem Objekt
// Entfernt Properties in einem Objekt.
// data: Objekt, deren Properties bearbeitet werden
// data: Objekt, deren Properties bearbeitet werden
// delList: Checkliste der zu loeschenden Items (true fuer loeschen), falls angegeben
// delList: Checkliste der zu loeschenden Items (true fuer loeschen), falls angegeben
Zeile 1.875: Zeile 1.692:
}
}


// Replacer fuer JSON.stringify() oder safeStringify(), der Arrays kompakter darstellt
// Replacer fuer JSON.stringify() oder safeStringify(), der Arrays kompakter darstellt.
// key: Der uebergebene Schluessel
// key: Der uebergebene Schluessel
// value: Der uebergebene Wert
// value: Der uebergebene Wert
Zeile 1.887: Zeile 1.704:
}
}


// Replacer fuer JSON.stringify() oder safeStringify(), der Arrays kompakter darstellt
// Replacer fuer JSON.stringify() oder safeStringify(), der Arrays kompakter darstellt.
// key: Der uebergebene Schluessel
// key: Der uebergebene Schluessel
// value: Der uebergebene Wert
// value: Der uebergebene Wert
Zeile 1.901: Zeile 1.718:


     return value;
     return value;
}
// Moegliche einfache Ersetzungen mit '$'...
let textSubst;
// Substituiert '$'-Parameter in einem Text
// text: Urspruenglicher Text mit '$'-Befehlen
// par1: Der (erste) uebergebene Parameter
// return Fuer Arrays eine kompakte Darstellung, sonst derselbe Wert
function substParam(text, par1) {
    let ret = getValue(text, "");
    if (! textSubst) {
        textSubst  = {
                'n' : __DBMOD.name,
                'v' : __DBMOD.version,
                'V' : __DBMOD.Name
            };
    }
    for (let ch in textSubst) {
        const __SUBST = textSubst[ch];
        ret = ret.replace('$' + ch, __SUBST);
    }
    return ret.replace('$', par1);
}
}


// Fuegt in die uebergebene Zahl Tausender-Trennpunkte ein
// Fuegt in die uebergebene Zahl Tausender-Trennpunkte ein
// Wandelt einen etwaig vorhandenen Dezimalpunkt in ein Komma um
// Wandelt einen etwaig vorhandenen Dezimalpunkt in ein Komma um
// numberString: Dezimalzahl als String
// return Diese Dezimalzahl als String mit Tausender-Trennpunkten und Komma statt Dezimalpunkt
function getNumberString(numberString) {
function getNumberString(numberString) {
     if (numberString.lastIndexOf('.') !== -1) {
     if (numberString.lastIndexOf(".") !== -1) {
         // Zahl enthaelt Dezimalpunkt
         // Zahl enthaelt Dezimalpunkt
         const __VORKOMMA = numberString.substring(0, numberString.lastIndexOf('.'));
         const __VORKOMMA = numberString.substring(0, numberString.lastIndexOf("."));
         const __NACHKOMMA = numberString.substring(numberString.lastIndexOf('.') + 1, numberString.length);
         const __NACHKOMMA = numberString.substring(numberString.lastIndexOf(".") + 1, numberString.length);


         return getNumberString(__VORKOMMA) + ',' + __NACHKOMMA;
         return getNumberString(__VORKOMMA) + "," + __NACHKOMMA;
     } else {
     } else {
         // Kein Dezimalpunkt, fuege Tausender-Trennpunkte ein:
         // Kein Dezimalpunkt, fuege Tausender-Trennpunkte ein:
Zeile 1.949: Zeile 1.737:
         for (let i = 0; i < __TEMP.length; i++) {
         for (let i = 0; i < __TEMP.length; i++) {
             if ((i > 0) && (i % 3 === 0)) {
             if ((i > 0) && (i % 3 === 0)) {
                 result += '.';
                 result += ".";
             }
             }
             result += __TEMP.substr(i, 1);
             result += __TEMP.substr(i, 1);
Zeile 1.959: Zeile 1.747:


// Dreht den uebergebenen String um
// Dreht den uebergebenen String um
// string: Eine Zeichenkette
// return Dieselbe Zeichenkette rueckwaerts
function reverseString(string) {
function reverseString(string) {
     let result = "";
     let result = "";
Zeile 1.969: Zeile 1.755:


     return result;
     return result;
}
// Speichert einen String/Integer/Boolean-Wert unter einem Namen ab
// name: GM.setValue()-Name, unter dem die Daten gespeichert werden
// value: Zu speichernder String/Integer/Boolean-Wert
// return Promise auf ein Objekt, das 'name' und 'value' der Operation enthaelt
function storeValue(name, value) {
    __LOG[4](name + " >> " + value);
    return GM.setValue(name, value).then(voidValue => {
            __LOG[5]("OK " + name + " >> " + value);
            return Promise.resolve({
                    'name'  : name,
                    'value' : value
                });
        }, defaultCatch);
}
// Holt einen String/Integer/Boolean-Wert unter einem Namen zurueck
// name: GM.getValue()-Name, unter dem die Daten gespeichert wurden
// defValue: Default-Wert fuer den Fall, dass nichts gespeichert ist
// return Promise fuer den String/Integer/Boolean-Wert, der unter dem Namen gespeichert war
function summonValue(name, defValue = undefined) {
    return GM.getValue(name, defValue).then(value => {
            __LOG[4](name + " << " + value);
            return Promise.resolve(value);
        }, ex => {
            __LOG[0](name + ": " + ex.message);
            return Promise.reject(ex);
        }, defaultCatch);
}
}


// Speichert einen beliebiegen (strukturierten) Wert unter einem Namen ab
// Speichert einen beliebiegen (strukturierten) Wert unter einem Namen ab
// name: GM.setValue()-Name, unter dem die Daten gespeichert werden
// name: GM_setValue-Name, unter dem die Daten gespeichert werden
// value: Beliebiger (strukturierter) Wert
// value: Beliebiger (strukturierter) Wert
// return Promise auf ein Objekt, das 'name' und 'value' in der String-Darstellung des Wertes enthaelt
// return String-Darstellung des Wertes
function serialize(name, value) {
function serialize(name, value) {
     const __STREAM = ((value !== undefined) ? safeStringify(value) : value);
     const __STREAM = ((value !== undefined) ? safeStringify(value) : value);


     return storeValue(name, __STREAM);
     __LOG[4](name + " >> " + __STREAM);
 
    GM_setValue(name, __STREAM);
 
    return __STREAM;
}
}


// Holt einen beliebiegen (strukturierter) Wert unter einem Namen zurueck
// Holt einen beliebiegen (strukturierter) Wert unter einem Namen zurueck
// name: GM.getValue()-Name, unter dem die Daten gespeichert wurden
// name: GM_setValue-Name, unter dem die Daten gespeichert werden
// defValue: Default-Wert fuer den Fall, dass nichts gespeichert ist
// defValue: Default-Wert fuer den Fall, dass nichts gespeichert ist
// return Promise fuer das Objekt, das unter dem Namen gespeichert war
// return Objekt, das unter dem Namen gespeichert war
function deserialize(name, defValue = undefined) {
function deserialize(name, defValue = undefined) {
     return summonValue(name).then(stream => {
     const __STREAM = GM_getValue(name);
            if (stream && stream.length) {
 
                return JSON.parse(stream);
    __LOG[4](name + " << " + __STREAM);
            } else {
                return defValue;
            }
        });
}


// Setzt die Seite gemaess der Aenderungen zurueck...
    if ((__STREAM !== undefined) && __STREAM.length) {
// reload: Seite wird ganz neu geladen
        try {
function refreshPage(reload = true) {
            return JSON.parse(__STREAM);
    if (reload) {
        } catch (ex) {
        __LOG[2]("Seite wird neu geladen...");
            __LOG[1](name + ": " + ex.message);
         window.location.reload();
         }
     }
     }
    return defValue;
}
}


Zeile 2.041: Zeile 1.795:
// value: Zu setzender Wert
// value: Zu setzender Wert
// reload: Seite mit neuem Wert neu laden
// reload: Seite mit neuem Wert neu laden
// serial: Serialization fuer komplexe Daten
// onFulfilled: Reaktion auf Speicherung im resolve-Fall (1. Promise.then()-Parameter)
// onRejected: Reaktion auf Speicherung im reject-Fall (2. Promise.then()-Parameter)
// return Gespeicherter Wert fuer setOptValue()
// return Gespeicherter Wert fuer setOptValue()
function setStored(name, value, reload = false, serial = false, onFulfilled = undefined, onRejected = undefined) {
function setStored(name, value, reload = false, serial = false) {
     (serial ? serialize(name, value)
     if (serial) {
            : storeValue(name, value))
        serialize(name, value);
                .then(onFulfilled, onRejected)
    } else {
                .then(() => refreshPage(reload), defaultCatch); // Ende der Kette...
        GM_setValue(name, value);
    }
 
    if (reload) {
        window.location.reload();
    }


     return value;
     return value;
Zeile 2.059: Zeile 1.815:
// value: Vorher gesetzter Wert
// value: Vorher gesetzter Wert
// reload: Seite mit neuem Wert neu laden
// reload: Seite mit neuem Wert neu laden
// serial: Serialization fuer komplexe Daten
// onFulfilled: Reaktion auf Speicherung im resolve-Fall (1. Promise.then()-Parameter)
// onRejected: Reaktion auf Speicherung im reject-Fall (2. Promise.then()-Parameter)
// return Gespeicherter Wert fuer setOptValue()
// return Gespeicherter Wert fuer setOptValue()
function setNextStored(arr, name, value, reload = false, serial = false, onFulfilled = undefined, onRejected = undefined) {
function setNextStored(arr, name, value, reload = false, serial = false) {
     return setStored(name, getNextValue(arr, value), reload, serial, onFulfilled, onRejected);
     return setStored(name, getNextValue(arr, value), reload, serial);
}
}


Zeile 2.092: Zeile 1.845:
                 value = JSON.parse(value);
                 value = JSON.parse(value);
             } catch (ex) {
             } catch (ex) {
                 __LOG[0]("getStoredCmds(): " + __CMD + " '" + __KEY + "' hat illegalen Wert '" + value + "'");
                 __LOG[1]("getStoredCmds(): " + __CMD + " '" + __KEY + "' hat illegalen Wert '" + value + "'");
                 // ... meist kann man den String selber aber speichern, daher kein "return"...
                 // ... meist kann man den String selber aber speichern, daher kein "return"...
             }
             }
Zeile 2.113: Zeile 1.866:
// Fuehrt die in einem Storage gespeicherte Operation aus
// Fuehrt die in einem Storage gespeicherte Operation aus
// storedCmds: Array von Objekten mit 'cmd' / 'key' / 'val' (siehe getStoredCmds())
// storedCmds: Array von Objekten mit 'cmd' / 'key' / 'val' (siehe getStoredCmds())
// optSet: Object mit den Optionen
// optSet: Set mit den Optionen
// beforeLoad: Angabe, ob nach der Speicherung noch loadOptions() aufgerufen wird
// beforeLoad: Angabe, ob nach der Speicherung noch loadOptions() aufgerufen wird
// onFulfilled: Reaktion auf Speicherung im resolve-Fall (1. Promise.then()-Parameter)
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
// onRejected: Reaktion auf Speicherung im reject-Fall (2. Promise.then()-Parameter)
// return Array von Operationen (wie storedCmds), die fuer die naechste Phase uebrig bleiben
// return Promise auf ein Array von Operationen (wie storedCmds), die fuer die naechste Phase uebrig bleiben
function runStoredCmds(storedCmds, optSet = undefined, beforeLoad = undefined) {
async function runStoredCmds(storedCmds, optSet = undefined, beforeLoad = undefined, onFulfilled = undefined, onRejected = undefined) {
     const __BEFORELOAD = getValue(beforeLoad, true);
     const __BEFORELOAD = getValue(beforeLoad, true);
     const __STOREDCMDS = getValue(storedCmds, []);
     const __STOREDCMDS = getValue(storedCmds, []);
Zeile 2.132: Zeile 1.884:
         if (__BEFORELOAD) {
         if (__BEFORELOAD) {
             if (__STOREDCMDS.length) {
             if (__STOREDCMDS.length) {
                 await invalidateOpts(optSet);  // alle Optionen invalidieren
                 invalidateOpts(optSet);  // alle Optionen invalidieren
                 invalidated = true;
                 invalidated = true;
             }
             }
             switch (__OPTACTION[__CMD]) {
             switch (__OPTACTION[__CMD]) {
             case __OPTACTION.SET : __LOG[4]("SET '" + __KEY + "' " + __VAL);
             case __OPTACTION.SET : __LOG[4]("SET '" + __KEY + "' " + __VAL);
                                   setStored(__KEY, __VAL, false, false, onFulfilled, onRejected);
                                   setStored(__KEY, __VAL, false, false);
                                   break;
                                   break;
             case __OPTACTION.NXT : __LOG[4]("SETNEXT '" + __KEY + "' " + __VAL);
             case __OPTACTION.NXT : __LOG[4]("SETNEXT '" + __KEY + "' " + __VAL);
                                   //setNextStored(__CONFIG.Choice, __KEY, __VAL, false, false, onFulfilled, onRejected);
                                   //setNextStored(__CONFIG.Choice, __KEY, __VAL, false, false);
                                   setStored(__KEY, __VAL, false, false, onFulfilled, onRejected);
                                   setStored(__KEY, __VAL, false, false);
                                   break;
                                   break;
             case __OPTACTION.RST : __LOG[4]("RESET (delayed)");
             case __OPTACTION.RST : __LOG[4]("RESET (delayed)");
Zeile 2.154: Zeile 1.906:
                                   break;
                                   break;
             case __OPTACTION.RST : __LOG[4]("RESET");
             case __OPTACTION.RST : __LOG[4]("RESET");
                                   await resetOptions(optSet, false);
                                   resetOptions(optSet, false);
                                   await loadOptions(optSet);  // Reset auf umbenannte Optionen anwenden!
                                   loadOptions(optSet);  // Reset auf umbenannte Optionen anwenden!
                                   break;
                                   break;
             default :              break;
             default :              break;
Zeile 2.257: Zeile 2.009:
// force: Laedt auch Optionen mit 'AutoReset'-Attribut
// force: Laedt auch Optionen mit 'AutoReset'-Attribut
// return Gesetzter Wert
// return Gesetzter Wert
function getOptValue(opt, defValue = undefined, load = true, asyncLoad = false, force = false) {
function getOptValue(opt, defValue = undefined, load = true, force = false) {
     let value;
     let value;


     if (opt !== undefined) {
     if (opt !== undefined) {
         if (load && ! opt.Loaded) {
         if (load && ! opt.Loaded) {
             if (! opt.Promise) {
             value = loadOption(opt, force);
                loadOption(opt, force);
            }
            if (! asyncLoad) {
                __LOG[0]("Warnung: getOptValue(" + getOptName(opt) + ") fordert zum Nachladen auf, daher nur Default-Wert!");
            }
         } else {
         } else {
             value = opt.Value;
             value = opt.Value;
Zeile 2.388: Zeile 2.135:
// Restauriert den vorherigen Speicher (der in einer Option definiert ist)
// Restauriert den vorherigen Speicher (der in einer Option definiert ist)
// opt: Option zur Wahl des Speichers
// opt: Option zur Wahl des Speichers
// return Promise auf gesuchten Speicher oder Null-Speicher ('inaktiv')
// return Gesuchter Speicher oder Null-Speicher ('inaktiv')
async function restoreMemoryByOpt(opt) {
function restoreMemoryByOpt(opt) {
     // Memory Storage fuer vorherige Speicherung...
     // Memory Storage fuer vorherige Speicherung...
     const __STORAGE = await getOptValue(opt, __MEMNORMAL, true, true, true);
     const __STORAGE = getOptValue(opt, __MEMNORMAL, true, true);


     return __OPTMEM[__STORAGE];
     return __OPTMEM[__STORAGE];
Zeile 2.399: Zeile 2.146:
// opt: Option zur Wahl des Speichers
// opt: Option zur Wahl des Speichers
// saveOpt: Option zur Speicherung der Wahl des Speichers (fuer restoreMemoryByOpt)
// saveOpt: Option zur Speicherung der Wahl des Speichers (fuer restoreMemoryByOpt)
// onFulfilled: Reaktion auf Speicherung im resolve-Fall (1. Promise.then()-Parameter)
// onRejected: Reaktion auf Speicherung im reject-Fall (2. Promise.then()-Parameter)
// return Gesuchter Speicher oder Null-Speicher ('inaktiv'), falls speichern nicht moeglich ist
// return Gesuchter Speicher oder Null-Speicher ('inaktiv'), falls speichern nicht moeglich ist
function startMemoryByOpt(opt, saveOpt = undefined, onFulfilled = undefined, onRejected = undefined) {
function startMemoryByOpt(opt, saveOpt = undefined) {
     // Memory Storage fuer naechste Speicherung...
     // Memory Storage fuer naechste Speicherung...
     let storage = getOptValue(opt, __MEMNORMAL);
     let storage = getOptValue(opt, __MEMNORMAL);
Zeile 2.415: Zeile 2.160:


     if (saveOpt !== undefined) {
     if (saveOpt !== undefined) {
         setOpt(saveOpt, storage, false, onFulfilled, onRejected);
         setOpt(saveOpt, storage, false);
     }
     }


Zeile 2.426: Zeile 2.171:


// Initialisiert das Script-Modul und ermittelt die beschreibenden Daten
// Initialisiert das Script-Modul und ermittelt die beschreibenden Daten
// meta: Metadaten des Scripts (Default: GM.info.script)
// meta: Metadaten des Scripts (Default: GM_info.script)
// return Beschreibende Daten fuer __DBMOD
// return Beschreibende Daten fuer __DBMOD
function ScriptModule(meta) {
function ScriptModule(meta) {
     'use strict';
     'use strict';


     const __META = getValue(meta, GM.info.script);
     const __META = getValue(meta, GM_info.script);
     const __PROPS = {
     const __PROPS = {
                 'name'        : true,
                 'name'        : true,
Zeile 2.537: Zeile 2.282:
// funOff: Funktion zum Ausschalten
// funOff: Funktion zum Ausschalten
// keyOff: Hotkey zum Ausschalten im Menu
// keyOff: Hotkey zum Ausschalten im Menu
// return Promise von GM.registerMenuCommand()
function registerMenuOption(val, menuOn, funOn, keyOn, menuOff, funOff, keyOff) {
function registerMenuOption(val, menuOn, funOn, keyOn, menuOff, funOff, keyOff) {
     const __ON  = (val ? '*' : "");
     const __ON  = (val ? '*' : "");
Zeile 2.545: Zeile 2.289:


     if (val) {
     if (val) {
         return GM.registerMenuCommand(menuOff, funOff, keyOff).then(result => menuOn);
         GM_registerMenuCommand(menuOff, funOff, keyOff);
     } else {
     } else {
         return GM.registerMenuCommand(menuOn, funOn, keyOn).then(result => menuOff);
         GM_registerMenuCommand(menuOn, funOn, keyOn);
     }
     }
}
}
Zeile 2.557: Zeile 2.301:
// fun: Funktion zum Setzen des naechsten Wertes
// fun: Funktion zum Setzen des naechsten Wertes
// key: Hotkey zum Setzen des naechsten Wertes im Menu
// key: Hotkey zum Setzen des naechsten Wertes im Menu
// return Promise von GM.registerMenuCommand()
function registerNextMenuOption(val, arr, menu, fun, key) {
function registerNextMenuOption(val, arr, menu, fun, key) {
     const __MENU = substParam(menu, val);
     const __MENU = menu.replace('$', val);
     let options = "OPTION " + __MENU;
     let options = "OPTION " + __MENU;


Zeile 2.571: Zeile 2.314:
     __LOG[3](options);
     __LOG[3](options);


     return GM.registerMenuCommand(__MENU, fun, key).then(result => __MENU);
     GM_registerMenuCommand(__MENU, fun, key);
}
}


Zeile 2.581: Zeile 2.324:
// hidden: Angabe, ob Menupunkt nicht sichtbar sein soll (Default: sichtbar)
// hidden: Angabe, ob Menupunkt nicht sichtbar sein soll (Default: sichtbar)
// serial: Serialization fuer komplexe Daten
// serial: Serialization fuer komplexe Daten
// return Promise von GM.registerMenuCommand() (oder String-Version des Wertes)
function registerDataOption(val, menu, fun, key, hidden = false, serial = true) {
function registerDataOption(val, menu, fun, key, hidden = false, serial = true) {
     const __VALUE = ((serial && (val !== undefined)) ? safeStringify(val) : val);
     const __VALUE = ((serial && (val !== undefined)) ? safeStringify(val) : val);
     const __MENU = substParam(menu, __VALUE);
     const __MENU = getValue(menu, "").replace('$', __VALUE);
     const __OPTIONS = (hidden ? "HIDDEN " : "") + "OPTION " + __MENU +
     const __OPTIONS = (hidden ? "HIDDEN " : "") + "OPTION " + __MENU +
                       getValue(__VALUE, "", " = " + __VALUE);
                       getValue(__VALUE, "", " = " + __VALUE);
Zeile 2.590: Zeile 2.332:
     __LOG[hidden ? 4 : 3](__OPTIONS);
     __LOG[hidden ? 4 : 3](__OPTIONS);


     if (hidden) {
     if (! hidden) {
         return Promise.resolve(__VALUE);
         GM_registerMenuCommand(__MENU, fun, key);
    } else {
        return GM.registerMenuCommand(__MENU, fun, key).then(result => __MENU);
     }
     }
}
}
Zeile 2.599: Zeile 2.339:
// Zeigt den Eintrag im Menu einer Option
// Zeigt den Eintrag im Menu einer Option
// opt: Config und Value der Option
// opt: Config und Value der Option
// return Promise von GM.registerMenuCommand() (oder String-Version des Wertes)
function registerOption(opt) {
function registerOption(opt) {
     const __CONFIG = getOptConfig(opt);
     const __CONFIG = getOptConfig(opt);
Zeile 2.611: Zeile 2.350:
     if (! __CONFIG.HiddenMenu) {
     if (! __CONFIG.HiddenMenu) {
         switch (__CONFIG.Type) {
         switch (__CONFIG.Type) {
         case __OPTTYPES.MC : return registerNextMenuOption(__VALUE, __CONFIG.Choice, __LABEL, __ACTION, __HOTKEY);
         case __OPTTYPES.MC : registerNextMenuOption(__VALUE, __CONFIG.Choice, __LABEL, __ACTION, __HOTKEY);
         case __OPTTYPES.SW : return registerMenuOption(__VALUE, __LABEL, __ACTION, __HOTKEY,
                            break;
                                                      __CONFIG.AltLabel, __ACTION, __CONFIG.AltHotkey);
         case __OPTTYPES.SW : registerMenuOption(__VALUE, __LABEL, __ACTION, __HOTKEY,
         case __OPTTYPES.TF : return registerMenuOption(__VALUE, __LABEL, __ACTION, __HOTKEY,
                                                __CONFIG.AltLabel, __ACTION, __CONFIG.AltHotkey);
                                                      __CONFIG.AltLabel, opt.AltAction, __CONFIG.AltHotkey);
                            break;
         case __OPTTYPES.SD : return registerDataOption(__VALUE, __LABEL, __ACTION, __HOTKEY, __HIDDEN, __SERIAL);
         case __OPTTYPES.TF : registerMenuOption(__VALUE, __LABEL, __ACTION, __HOTKEY,
         case __OPTTYPES.SI : return registerDataOption(__VALUE, __LABEL, __ACTION, __HOTKEY, __HIDDEN, __SERIAL);
                                                __CONFIG.AltLabel, opt.AltAction, __CONFIG.AltHotkey);
         default :            return Promise.resolve(__VALUE);
                            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...
         // Nur Anzeige im Log...
         return registerDataOption(__VALUE, __LABEL, __ACTION, __HOTKEY, __HIDDEN, __SERIAL);
         registerDataOption(__VALUE, __LABEL, __ACTION, __HOTKEY, __HIDDEN, __SERIAL);
     }
     }
}
}
Zeile 2.674: Zeile 2.418:
         switch (optAction) {
         switch (optAction) {
         case __OPTACTION.SET : fun = function() {
         case __OPTACTION.SET : fun = function() {
                                       return setOptByName(optSet, item, __CONFIG.SetValue, __RELOAD).catch(defaultCatch);
                                       return setOptByName(optSet, item, __CONFIG.SetValue, __RELOAD);
                                   };
                                   };
                               break;
                               break;
         case __OPTACTION.NXT : fun = function() {
         case __OPTACTION.NXT : fun = function() {
                                       return promptNextOptByName(optSet, item, __CONFIG.SetValue, __RELOAD,
                                       return promptNextOptByName(optSet, item, __CONFIG.SetValue, __RELOAD,
                                                   __CONFIG.FreeValue, __CONFIG.SelValue, __CONFIG.MinChoice).catch(defaultCatch);
                                                   __CONFIG.FreeValue, __CONFIG.SelValue, __CONFIG.MinChoice);
                                   };
                                   };
                               break;
                               break;
         case __OPTACTION.RST : fun = function() {
         case __OPTACTION.RST : fun = function() {
                                       return resetOptions(optSet, __RELOAD).then(
                                       return resetOptions(optSet, __RELOAD);
                                              result => __LOG[3]("RESETTING (" + result + ")..."),
                                              defaultCatch);
                                   };
                                   };
                               break;
                               break;
Zeile 2.740: Zeile 2.482:
             addProps(config, getOptConfig(__REF));
             addProps(config, getOptConfig(__REF));
             addProps(config, optConfig);
             addProps(config, optConfig);
             config.setConst('SharedData', getOptValue(__REF), false);   // Wert muss schon da sein, NICHT nachladen, sonst ggfs. Promise
             config.setConst('SharedData', getOptValue(__REF));
         } else {  // __OBJREF enthaelt die Daten selbst
         } else {  // __OBJREF enthaelt die Daten selbst
             if (! config.Name) {
             if (! config.Name) {
Zeile 2.774: Zeile 2.516:
             // Gab es vorher einen Aufruf, der einen Stub-Eintrag erzeugt hat, und wurden Daten geladen?
             // Gab es vorher einen Aufruf, der einen Stub-Eintrag erzeugt hat, und wurden Daten geladen?
             const __LOADED = ((preInit === false) && optSet[opt].Loaded);
             const __LOADED = ((preInit === false) && optSet[opt].Loaded);
            const __PROMISE = ((__LOADED || ! optSet[opt]) ? undefined : optSet[opt].Promise);
             const __VALUE = (__LOADED ? optSet[opt].Value : undefined);
             const __VALUE = (__LOADED ? optSet[opt].Value : undefined);


Zeile 2.781: Zeile 2.522:
                 'Config'    : __CONFIG,
                 'Config'    : __CONFIG,
                 'Loaded'    : (__ISSHARED || __LOADED),
                 'Loaded'    : (__ISSHARED || __LOADED),
                'Promise'  : __PROMISE,
                 'Value'    : initOptValue(__CONFIG, __VALUE),
                 'Value'    : initOptValue(__CONFIG, __VALUE),
                 'SetValue'  : __CONFIG.SetValue,
                 'SetValue'  : __CONFIG.SetValue,
Zeile 2.793: Zeile 2.533:
                 'Config'    : __OPTCONFIG,
                 'Config'    : __OPTCONFIG,
                 'Loaded'    : false,
                 'Loaded'    : false,
                'Promise'  : undefined,
                 'Value'    : initOptValue(__OPTCONFIG),
                 'Value'    : initOptValue(__OPTCONFIG),
                 'ReadOnly'  : (__ISSHARED || __OPTCONFIG.ReadOnly)
                 'ReadOnly'  : (__ISSHARED || __OPTCONFIG.ReadOnly)
Zeile 2.826: Zeile 2.565:
// optConfig: Konfiguration der Optionen
// optConfig: Konfiguration der Optionen
// optSet: Platz fuer die gesetzten Optionen
// optSet: Platz fuer die gesetzten Optionen
// return Promise auf gefuelltes Objekt mit den gesetzten Optionen
// return Gefuelltes Objekt mit den gesetzten Optionen
async function startOptions(optConfig, optSet = undefined, classification = undefined) {
function startOptions(optConfig, optSet = undefined, classification = undefined) {
     optSet = initOptions(optConfig, optSet, true);  // PreInit
     optSet = initOptions(optConfig, optSet, true);  // PreInit


     // Memory Storage fuer vorherige Speicherung...
     // Memory Storage fuer vorherige Speicherung...
     myOptMemSize = getMemSize(myOptMem = await restoreMemoryByOpt(optSet.oldStorage));
     myOptMemSize = getMemSize(myOptMem = restoreMemoryByOpt(optSet.oldStorage));


     // Zwischengespeicherte Befehle auslesen...
     // Zwischengespeicherte Befehle auslesen...
Zeile 2.837: Zeile 2.576:


     // ... ermittelte Befehle ausfuehren...
     // ... ermittelte Befehle ausfuehren...
     const __LOADEDCMDS = await runStoredCmds(__STOREDCMDS, optSet, true);  // BeforeLoad
     const __LOADEDCMDS = runStoredCmds(__STOREDCMDS, optSet, true);  // BeforeLoad


     // Bisher noch nicht geladenene Optionen laden...
     // Bisher noch nicht geladenene Optionen laden...
     await loadOptions(optSet);
     loadOptions(optSet);


     // Memory Storage fuer naechste Speicherung...
     // Memory Storage fuer naechste Speicherung...
Zeile 2.852: Zeile 2.591:
     if (classification !== undefined) {
     if (classification !== undefined) {
         // Umbenennungen durchfuehren...
         // Umbenennungen durchfuehren...
         await classification.renameOptions();
         classification.renameOptions();
     }
     }


     // ... ermittelte Befehle ausfuehren...
     // ... ermittelte Befehle ausfuehren...
     await runStoredCmds(__LOADEDCMDS, optSet, false);  // Rest
     runStoredCmds(__LOADEDCMDS, optSet, false);  // Rest


     // Als globale Daten speichern...
     // Als globale Daten speichern...
Zeile 2.873: Zeile 2.612:
// 'formWidth': Anzahl der Elemente pro Zeile
// 'formWidth': Anzahl der Elemente pro Zeile
// 'formBreak': Elementnummer des ersten Zeilenumbruchs
// 'formBreak': Elementnummer des ersten Zeilenumbruchs
// return Liefert die gesetzten Optionen zurueck
function showOptions(optSet = undefined, optParams = { 'hideMenu' : false }) {
function showOptions(optSet = undefined, optParams = { 'hideMenu' : false }) {
     if (! optParams.hideMenu) {
     if (! optParams.hideMenu) {
         buildMenu(optSet).then(() => __LOG[3]("Menu OK"));
         buildMenu(optSet);
     }
     }


Zeile 2.882: Zeile 2.620:
         buildForm(optParams.menuAnchor, optSet, optParams);
         buildForm(optParams.menuAnchor, optSet, optParams);
     }
     }
    return optSet;
}
}


Zeile 2.891: Zeile 2.627:
// value: (Bei allen Typen) Zu setzender Wert
// value: (Bei allen Typen) Zu setzender Wert
// reload: Seite mit neuem Wert neu laden
// reload: Seite mit neuem Wert neu laden
// onFulfilled: Reaktion auf Speicherung im resolve-Fall (1. Promise.then()-Parameter)
// onRejected: Reaktion auf Speicherung im reject-Fall (2. Promise.then()-Parameter)
// return Gesetzter Wert
// return Gesetzter Wert
function setOpt(opt, value, reload = false, onFulfilled = undefined, onRejected = undefined) {
function setOpt(opt, value, reload = false) {
     return setOptValue(opt, setStored(getOptName(opt), value, reload, getOptConfig(opt).Serial, onFulfilled, onRejected));
     return setOptValue(opt, setStored(getOptName(opt), value, reload, getOptConfig(opt).Serial));
}
}


Zeile 2.922: Zeile 2.656:
// value: Default fuer ggfs. zu setzenden Wert
// value: Default fuer ggfs. zu setzenden Wert
// reload: Seite mit neuem Wert neu laden
// reload: Seite mit neuem Wert neu laden
// onFulfilled: Reaktion auf Speicherung im resolve-Fall (1. Promise.then()-Parameter)
// onRejected: Reaktion auf Speicherung im reject-Fall (2. Promise.then()-Parameter)
// return Gesetzter Wert
// return Gesetzter Wert
function setNextOpt(opt, value = undefined, reload = false, onFulfilled = undefined, onRejected = undefined) {
function setNextOpt(opt, value = undefined, reload = false) {
     return setOpt(opt, getNextOpt(opt, value), reload, onFulfilled, onRejected);
     return setOpt(opt, getNextOpt(opt, value), reload);
}
}


Zeile 2.935: Zeile 2.667:
// 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)
// onFulfilled: Reaktion auf Speicherung im resolve-Fall (1. Promise.then()-Parameter)
// onRejected: Reaktion auf Speicherung im reject-Fall (2. Promise.then()-Parameter)
// return Gesetzter Wert
// return Gesetzter Wert
function promptNextOpt(opt, value = undefined, reload = false, freeValue = false, selValue = true, minChoice = 3, onFulfilled = undefined, onRejected = undefined) {
function promptNextOpt(opt, value = undefined, reload = false, freeValue = false, selValue = true, minChoice = 3) {
     const __CONFIG = getOptConfig(opt);
     const __CONFIG = getOptConfig(opt);
     const __CHOICE = __CONFIG.Choice;
     const __CHOICE = __CONFIG.Choice;


     if (value || (! __CHOICE) || (__CHOICE.length < minChoice)) {
     if (value || (! __CHOICE) || (__CHOICE.length < minChoice)) {
         return setNextOpt(opt, value, reload, onFulfilled, onRejected);
         return setNextOpt(opt, value, reload);
     }
     }


Zeile 2.978: Zeile 2.708:
             if (nextVal !== __VALUE) {
             if (nextVal !== __VALUE) {
                 if (nextVal) {
                 if (nextVal) {
                     return setOpt(opt, nextVal, reload, onFulfilled, onRejected);
                     return setOpt(opt, nextVal, reload);
                 }
                 }


                 const __LABEL = substParam(__CONFIG.Label, __VALUE);
                 const __LABEL = __CONFIG.Label.replace('$', __VALUE);


                 showAlert(__LABEL, "Ung\xFCltige Eingabe: " + __ANSWER);
                 showAlert(__LABEL, "Ung\xFCltige Eingabe: " + __ANSWER);
Zeile 2.987: Zeile 2.717:
         }
         }
     } catch (ex) {
     } catch (ex) {
         __LOG[0]("promptNextOpt: " + ex.message);
         __LOG[1]("promptNextOpt: " + ex.message);
     }
     }


Zeile 2.999: Zeile 2.729:
// value: (Bei allen Typen) Zu setzender Wert
// value: (Bei allen Typen) Zu setzender Wert
// reload: Seite mit neuem Wert neu laden
// reload: Seite mit neuem Wert neu laden
// onFulfilled: Reaktion auf Speicherung im resolve-Fall (1. Promise.then()-Parameter)
// onRejected: Reaktion auf Speicherung im reject-Fall (2. Promise.then()-Parameter)
// return Gesetzter Wert
// return Gesetzter Wert
function setOptByName(optSet, item, value, reload = false, onFulfilled = undefined, onRejected = undefined) {
function setOptByName(optSet, item, value, reload = false) {
     const __OPT = getOptByName(optSet, item);
     const __OPT = getOptByName(optSet, item);


     return setOpt(__OPT, value, reload, onFulfilled, onRejected);
     return setOpt(__OPT, value, reload);
}
}


Zeile 3.024: Zeile 2.752:
// value: Default fuer ggfs. zu setzenden Wert
// value: Default fuer ggfs. zu setzenden Wert
// reload: Seite mit neuem Wert neu laden
// reload: Seite mit neuem Wert neu laden
// onFulfilled: Reaktion auf Speicherung im resolve-Fall (1. Promise.then()-Parameter)
// onRejected: Reaktion auf Speicherung im reject-Fall (2. Promise.then()-Parameter)
// return Gesetzter Wert
// return Gesetzter Wert
function setNextOptByName(optSet, item, value = undefined, reload = false, onFulfilled = undefined, onRejected = undefined) {
function setNextOptByName(optSet, item, value = undefined, reload = false) {
     const __OPT = getOptByName(optSet, item);
     const __OPT = getOptByName(optSet, item);


     return setNextOpt(__OPT, value, reload, onFulfilled, onRejected);
     return setNextOpt(__OPT, value, reload);
}
}


Zeile 3.040: Zeile 2.766:
// 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)
// onFulfilled: Reaktion auf Speicherung im resolve-Fall (1. Promise.then()-Parameter)
// onRejected: Reaktion auf Speicherung im reject-Fall (2. Promise.then()-Parameter)
// return Gesetzter Wert
// return Gesetzter Wert
function promptNextOptByName(optSet, item, value = undefined, reload = false, freeValue = false, selValue = true, minChoice = 3, onFulfilled = undefined, onRejected = undefined) {
function promptNextOptByName(optSet, item, value = undefined, reload = false, freeValue = false, selValue = true, minChoice = 3) {
     const __OPT = getOptByName(optSet, item);
     const __OPT = getOptByName(optSet, item);


     return promptNextOpt(__OPT, value, reload, freeValue, selValue, minChoice, onFulfilled, onRejected);
     return promptNextOpt(__OPT, value, reload, freeValue, selValue, minChoice);
}
}


// Baut das Benutzermenu auf (asynchron im Hintergrund)
// Baut das Benutzermenu auf
// optSet: Gesetzte Optionen
// optSet: Gesetzte Optionen
// return Promise auf void
function buildMenu(optSet) {
async function buildMenu(optSet) {
     __LOG[3]("buildMenu()");
     __LOG[3]("buildMenu()");


     for (let opt in optSet) {
     for (let opt in optSet) {
         await registerOption(optSet[opt]).then(
         registerOption(optSet[opt]);
                result => __LOG[6](`REGISTEROPTION[${opt}] = ${result}`),
                defaultCatch);
     }
     }
}
}
Zeile 3.065: Zeile 2.786:
// opt: Zu invalidierende Option
// opt: Zu invalidierende Option
// force: Invalidiert auch Optionen mit 'AutoReset'-Attribut
// force: Invalidiert auch Optionen mit 'AutoReset'-Attribut
// return Promise auf resultierenden Wert
function invalidateOpt(opt, force = false) {
function invalidateOpt(opt, force = false) {
     return Promise.resolve(opt.Promise).then(value => {
     if (opt.Loaded && ! opt.ReadOnly) {
            if (opt.Loaded && ! opt.ReadOnly) {
        const __CONFIG = getOptConfig(opt);
                const __CONFIG = getOptConfig(opt);


                // Wert "ungeladen"...
        // Wert "ungeladen"...
                opt.Loaded = (force || ! __CONFIG.AutoReset);
        opt.Loaded = (force || ! __CONFIG.AutoReset);


                if (opt.Loaded && __CONFIG.AutoReset) {
        if (opt.Loaded && __CONFIG.AutoReset) {
                    // Nur zuruecksetzen, gilt als geladen...
            // Nur zuruecksetzen, gilt als geladen...
                    setOptValue(opt, initOptValue(__CONFIG));
            setOptValue(opt, initOptValue(__CONFIG));
                }
        }
            }
    }
 
            return getOptValue(opt);
        }, defaultCatch);
}
}


// Invalidiert die (ueber Menu) gesetzten Optionen
// Invalidiert die (ueber Menu) gesetzten Optionen
// optSet: Object mit den Optionen
// optSet: Set mit den Optionen
// force: Invalidiert auch Optionen mit 'AutoReset'-Attribut
// force: Invalidiert auch Optionen mit 'AutoReset'-Attribut
// return Promise auf Object mit den geladenen Optionen
// return Set mit den geladenen Optionen
async function invalidateOpts(optSet, force = false) {
function invalidateOpts(optSet, force = false) {
     for (let opt in optSet) {
     for (let opt in optSet) {
         const __OPT = optSet[opt];
         const __OPT = optSet[opt];


         await invalidateOpt(__OPT, force);
         invalidateOpt(__OPT, force);
     }
     }


Zeile 3.101: Zeile 2.817:
// opt: Zu ladende Option
// opt: Zu ladende Option
// force: Laedt auch Optionen mit 'AutoReset'-Attribut
// force: Laedt auch Optionen mit 'AutoReset'-Attribut
// return Promise auf gesetzten Wert der gelandenen Option
// return Gesetzter Wert der gelandenen Option
function loadOption(opt, force = false) {
function loadOption(opt, force = false) {
     if (! opt.Promise) {
     const __CONFIG = getOptConfig(opt);
        const __CONFIG = getOptConfig(opt);
    const __ISSHARED = getValue(__CONFIG.Shared, false, true);
        const __ISSHARED = getValue(__CONFIG.Shared, false, true);
    const __NAME = getOptName(opt);
        const __NAME = getOptName(opt);
    const __DEFAULT = getOptValue(opt, undefined, false, false);
        const __DEFAULT = getOptValue(opt, undefined, false, false, false);
    let value;
        let value;


        if (opt.Loaded && ! __ISSHARED) {
    if (opt.Loaded && ! __ISSHARED) {
            const __ERROR = "Error: Oprion '" + __NAME + "' bereits geladen!";
        __LOG[1]("Error: Oprion '" + __NAME + "' bereits geladen!");
    }


            __LOG[0](__MESSAGE);
    if (opt.ReadOnly || __ISSHARED) {
 
        value = __DEFAULT;
            return Promise.reject(__MESSAGE);
    } else if (! force && __CONFIG.AutoReset) {
        }
        value = initOptValue(__CONFIG);
 
    } else {
        if (opt.ReadOnly || __ISSHARED) {
        value = (__CONFIG.Serial ?
            value = __DEFAULT;
                        deserialize(__NAME, __DEFAULT) :
        } else if (! force && __CONFIG.AutoReset) {
                        GM_getValue(__NAME, __DEFAULT));
            value = initOptValue(__CONFIG);
    }
        } else {
            value = (__CONFIG.Serial ?
                            deserialize(__NAME, __DEFAULT) :
                            GM.getValue(__NAME, __DEFAULT));
        }
 
        opt.Promise = Promise.resolve(value).then(value => {
                // Paranoide Sicherheitsabfrage (das sollte nie passieren!)...
                if (opt.Loaded || ! opt.Promise) {
                    showAlert("Error", "Unerwarteter Widerspruch zwischen opt.Loaded und opt.Promise", safeStringify(opt));
                }
                __LOG[5]("LOAD " + __NAME + ": " + __LOG.changed(__DEFAULT, value));


                // Wert intern setzen...
    __LOG[5]("LOAD " + __NAME + ": " + __LOG.changed(__DEFAULT, value));
                const __VAL = setOptValue(opt, value);


                // Wert als geladen markieren...
    // Wert als geladen markieren...
                opt.Promise = undefined;
    opt.Loaded = true;
                opt.Loaded = true;
 
                return __VAL;
            }, defaultCatch);
    }


     return opt.Promise;
    // Wert intern setzen...
     return setOptValue(opt, value);
}
}


// Laedt die (ueber Menu) gesetzten Optionen
// Laedt die (ueber Menu) gesetzten Optionen
// optSet: Object mit den Optionen
// optSet: Set mit den Optionen
// force: Laedt auch Optionen mit 'AutoReset'-Attribut
// force: Laedt auch Optionen mit 'AutoReset'-Attribut
// return Array mit Promises neuer Ladevorgaenge (fuer Objekte mit 'name' und 'value')
// return Set mit den geladenen Optionen
function loadOptions(optSet, force = false) {
function loadOptions(optSet, force = false) {
    const __PROMISES = [];
     for (let opt in optSet) {
     for (let opt in optSet) {
         const __OPT = optSet[opt];
         const __OPT = optSet[opt];


         if (! __OPT.Loaded) {
         if (! __OPT.Loaded) {
             const __PROMISE = loadOption(__OPT, force).then(value => {
             loadOption(__OPT, force);
                    __LOG[5]("LOADED " + opt + " << " + value);
 
                    return Promise.resolve({
                            'name'  : opt,
                            'value' : value
                        });
                }, defaultCatch);
 
            __PROMISES.push(__PROMISE);
         }
         }
     }
     }


     return Promise.all(__PROMISES);
     return optSet;
}
}


Zeile 3.180: Zeile 2.868:
// force: Entfernt auch Optionen mit 'Permanent'-Attribut
// force: Entfernt auch Optionen mit 'Permanent'-Attribut
// reset: Setzt bei Erfolg auf Initialwert der Option (auch fuer nicht 'AutoReset')
// reset: Setzt bei Erfolg auf Initialwert der Option (auch fuer nicht 'AutoReset')
// return Promise von GM.deleteValue() (oder void)
function deleteOption(opt, force = false, reset = true) {
function deleteOption(opt, force = false, reset = true) {
     const __CONFIG = getOptConfig(opt);
     const __CONFIG = getOptConfig(opt);
Zeile 3.189: Zeile 2.876:
         __LOG[4]("DELETE " + __NAME);
         __LOG[4]("DELETE " + __NAME);


         return GM.deleteValue(__NAME).then(voidValue => {
         GM_deleteValue(__NAME);
                if (reset || __CONFIG.AutoReset) {
 
                    setOptValue(opt, initOptValue(__CONFIG));
        if (reset || __CONFIG.AutoReset) {
                }
            setOptValue(opt, initOptValue(__CONFIG));
            }, defaultCatch);
        }
     }
     }
    return Promise.resolve();
}
}


Zeile 3.204: Zeile 2.889:
// force: Entfernt auch Optionen mit 'Permanent'-Attribut
// force: Entfernt auch Optionen mit 'Permanent'-Attribut
// reset: Setzt bei Erfolg auf Initialwert der Option
// reset: Setzt bei Erfolg auf Initialwert der Option
// return Promise auf diesen Vorgang
function deleteOptions(optSet, optSelect = undefined, force = false, reset = true) {
async function deleteOptions(optSet, optSelect = undefined, force = false, reset = true) {
     const __DELETEALL = ((optSelect === undefined) || (optSelect === true));
     const __DELETEALL = ((optSelect === undefined) || (optSelect === true));
     const __OPTSELECT = getValue(optSelect, { });
     const __OPTSELECT = getValue(optSelect, { });
Zeile 3.211: Zeile 2.895:
     for (let opt in optSet) {
     for (let opt in optSet) {
         if (getValue(__OPTSELECT[opt], __DELETEALL)) {
         if (getValue(__OPTSELECT[opt], __DELETEALL)) {
             await deleteOption(optSet[opt], force, reset);
             deleteOption(optSet[opt], force, reset);
         }
         }
     }
     }
    return Promise.resolve();
}
}


Zeile 3.223: Zeile 2.905:
// reload: Wert nachladen statt beizubehalten
// reload: Wert nachladen statt beizubehalten
// force: Laedt auch Optionen mit 'AutoReset'-Attribut
// force: Laedt auch Optionen mit 'AutoReset'-Attribut
// return Promise auf umbenannte Option
// return Umbenannte Option
async function renameOption(opt, name, reload = false, force = false) {
function renameOption(opt, name, reload = false, force = false) {
     const __NAME = getOptName(opt);
     const __NAME = getOptName(opt);


     if (__NAME !== name) {
     if (__NAME !== name) {
         await deleteOption(opt, true, ! reload);
         deleteOption(opt, true, ! reload);


         setOptName(opt, name);
         setOptName(opt, name);


         await invalidateOpt(opt, opt.Loaded);
         invalidateOpt(opt, opt.Loaded);


         if (reload) {
         if (reload) {
             opt.Loaded = false;
             opt.Loaded = false;


             await loadOption(opt, force);
             loadOption(opt, force);
         }
         }
     }
     }


     return Promise.resolve(opt);
     return opt;
}
}


Zeile 3.269: Zeile 2.951:
// - name: Neu zu setzender Name (Speicheradresse)
// - name: Neu zu setzender Name (Speicheradresse)
// - param: Parameter "renameParam" von oben, z.B. Prefix oder Postfix
// - param: Parameter "renameParam" von oben, z.B. Prefix oder Postfix
// return Promise auf diesen Vorgang
function renameOptions(optSet, optSelect, renameParam = undefined, renameFun = prefixName) {
async function renameOptions(optSet, optSelect, renameParam = undefined, renameFun = prefixName) {
     if (renameFun === undefined) {
     if (renameFun === undefined) {
         __LOG[0]("RENAME: Illegale Funktion!");
         __LOG[1]("RENAME: Illegale Funktion!");
     }
     }
     for (let opt in optSelect) {
     for (let opt in optSelect) {
Zeile 3.279: Zeile 2.960:


         if (__OPT === undefined) {
         if (__OPT === undefined) {
             __LOG[0]("RENAME: Option '" + opt + "' nicht gefunden!");
             __LOG[1]("RENAME: Option '" + opt + "' nicht gefunden!");
         } else {
         } else {
             const __NAME = getOptName(__OPT);
             const __NAME = getOptName(__OPT);
Zeile 3.289: Zeile 2.970:
             const __FORCE = (__ISSCALAR ? true : __OPTPARAMS.force);
             const __FORCE = (__ISSCALAR ? true : __OPTPARAMS.force);


             await renameOption(__OPT, __NEWNAME, __RELOAD, __FORCE);
             renameOption(__OPT, __NEWNAME, __RELOAD, __FORCE);
         }
         }
     }
     }
Zeile 3.297: Zeile 2.978:
// optSet: Gesetzte Optionen
// optSet: Gesetzte Optionen
// reload: Seite mit "Werkseinstellungen" neu laden
// reload: Seite mit "Werkseinstellungen" neu laden
// return Promise auf diesen Vorgang
function resetOptions(optSet, reload = true) {
async function resetOptions(optSet, reload = true) {
     // Alle (nicht 'Permanent') gesetzten Optionen entfernen...
     // Alle (nicht 'Permanent') gesetzten Optionen entfernen...
     await deleteOptions(optSet, true, false, ! reload);
     deleteOptions(optSet, true, false, ! reload);


     // ... und ggfs. Seite neu laden (mit "Werkseinstellungen")...
     if (reload) {
    refreshPage(reload);
        // ... und Seite neu laden (mit "Werkseinstellungen")...
        window.location.reload();
    }
}
}


Zeile 3.313: Zeile 2.995:
// type: Typ der Input-Felder (Default: unsichtbare Daten)
// type: Typ der Input-Felder (Default: unsichtbare Daten)
// return Ergaenztes Form-Konstrukt
// return Ergaenztes Form-Konstrukt
function addInputField(form, props, type = 'hidden') {
function addInputField(form, props, type = "hidden") {
     for (let fieldName in props) {
     for (let fieldName in props) {
         let field = form[fieldName];
         let field = form[fieldName];
         if (! field) {
         if (! field) {
             field = document.createElement('input');
             field = document.createElement("input");
             field.type = type;
             field.type = type;
             field.name = fieldName;
             field.name = fieldName;
Zeile 3.333: Zeile 3.015:
// return Ergaenztes Form-Konstrukt
// return Ergaenztes Form-Konstrukt
function addHiddenField(form, props) {
function addHiddenField(form, props) {
     return addInputField(form, props, 'hidden');
     return addInputField(form, props, "hidden");
}
}


Zeile 3.346: Zeile 3.028:
         return obj.addEventListener(type, callback, capture);
         return obj.addEventListener(type, callback, capture);
     } else if (obj.attachEvent) {
     } else if (obj.attachEvent) {
         return obj.attachEvent('on' + type, callback);
         return obj.attachEvent("on" + type, callback);
     } else {
     } else {
         __LOG[0]("Could not add " + type + " event:");
         __LOG[1]("Could not add " + type + " event:");
         __LOG[2](callback);
         __LOG[2](callback);


Zeile 3.365: Zeile 3.047:
         return obj.removeEventListener(type, callback, capture);
         return obj.removeEventListener(type, callback, capture);
     } else if (obj.detachEvent) {
     } else if (obj.detachEvent) {
         return obj.detachEvent('on' + type, callback);
         return obj.detachEvent("on" + type, callback);
     } else {
     } else {
         __LOG[0]("Could not remove " + type + " event:");
         __LOG[1]("Could not remove " + type + " event:");
         __LOG[2](callback);
         __LOG[2](callback);


Zeile 3.415: Zeile 3.097:
// doc: Dokument (document)
// doc: Dokument (document)
// return Gesuchtes Element oder undefined (falls nicht gefunden)
// return Gesuchtes Element oder undefined (falls nicht gefunden)
function getTable(index, tag = 'table', doc = document) {
function getTable(index, tag = "table", doc = document) {
     const __TAGS = doc.getElementsByTagName(tag);
     const __TAGS = doc.getElementsByTagName(tag);
     const __TABLE = (__TAGS ? __TAGS[index] : undefined);
     const __TABLE = (__TAGS ? __TAGS[index] : undefined);
Zeile 3.439: Zeile 3.121:
// return Gesuchte Zeilen oder undefined (falls nicht gefunden)
// return Gesuchte Zeilen oder undefined (falls nicht gefunden)
function getRows(index, doc = document) {
function getRows(index, doc = document) {
     const __TABLE = getTable(index, 'table', doc);
     const __TABLE = getTable(index, "table", doc);
     const __ROWS = (__TABLE ? __TABLE.rows : undefined);
     const __ROWS = (__TABLE ? __TABLE.rows : undefined);


Zeile 3.482: Zeile 3.164:
         const __CONFIG = getOptConfig(opt);
         const __CONFIG = getOptConfig(opt);
         const __SERIAL = getValue(serial, getValue(__CONFIG.Serial, false));
         const __SERIAL = getValue(serial, getValue(__CONFIG.Serial, false));
         const __THISVAL = ((__CONFIG.ValType === 'String') ? "'\\x22' + this.value + '\\x22'" : "this.value");
         const __THISVAL = ((__CONFIG.ValType === "String") ? "'\\x22' + this.value + '\\x22'" : "this.value");
         const __TVALUE = getValue(__CONFIG.ValType, __THISVAL, "new " + __CONFIG.ValType + '(' + __THISVAL + ')');
         const __TVALUE = getValue(__CONFIG.ValType, __THISVAL, "new " + __CONFIG.ValType + '(' + __THISVAL + ')');
         const __VALSTR = ((value !== undefined) ? safeStringify(value) : __SERIAL ? "JSON.stringify(" + __TVALUE + ')' : __TVALUE);
         const __VALSTR = ((value !== undefined) ? safeStringify(value) : __SERIAL ? "JSON.stringify(" + __TVALUE + ')' : __TVALUE);
Zeile 3.511: Zeile 3.193:
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
// memory: __OPTMEM.normal = unbegrenzt gespeichert (localStorage), __OPTMEM.begrenzt = bis Browserende gespeichert (sessionStorage), __OPTMEM.inaktiv
// return String mit dem (reinen) Funktionsaufruf
// return String mit dem (reinen) Funktionsaufruf
function getFormActionEvent(opt, isAlt = false, value = undefined, type = 'click', serial = undefined, memory = undefined) {
function getFormActionEvent(opt, isAlt = false, value = undefined, type = "click", serial = undefined, memory = undefined) {
     const __ACTION = getFormAction(opt, isAlt, value, serial, memory);
     const __ACTION = getFormAction(opt, isAlt, value, serial, memory);


Zeile 3.517: Zeile 3.199:
}
}


// Hilfsfunktion: Wendet eine Konvertierung auf jede "Zeile" innerhalb eines Textes an
// Zeigt eine Option auf der Seite als Auswahlbox an
// text: Urspruenglicher Text
// convFun: function(line, index, arr): Konvertiert line in "Zeile" line des Arrays arr
// separator: Zeilentrenner im Text (Default: '\n')
// thisArg: optionaler this-Parameter fuer die Konvertierung
// limit: optionale Begrenzung der Zeilen
// return String mit dem neuen Text
function eachLine(text, convFun, separator = '\n', thisArg = undefined, limit = undefined) {
    const __ARR = text.split(separator, limit);
    const __RES = __ARR.map(convFun, thisArg);
 
    return __RES.join(separator);
}
 
// Hilfsfunktion: Ergaenzt einen HTML-Code um einen Titel (ToolTip)
// html: Urspruenglicher HTML-Code (z.B. ein HTML-Element oder Text)
// title: Im ToolTip angezeigter Text
// separator: Zeilentrenner im Text (Default: '|')
// limit: optionale Begrenzung der Zeilen
// return String mit dem neuen HTML-Code
function withTitle(html, title, separator = '|', limit = undefined) {
    if (title && title.length) {
        return eachLine(html, line => '<abbr title="' + title + '">' + line + '</abbr>', separator, undefined, limit);
    } else {
        return html;
    }
}
 
// Hilfsfunktion: Ermittelt einen Label- oder FormLabel-Eintrag (Default)
// label: Config-Eintrag fuer Label oder FormLabel
// defLabel: Ersatzwert, falls label nicht angegeben
// isSelect: Angabe, ob ein Parameter angezeigt wird (Default: false)
// isForm: Angabe, ob ein FormLabel gesucht ist (Default: true)
// return Vollstaendiger Label- oder FormLabel-Eintrag
function formatLabel(label, defLabel = undefined, isSelect = false, isForm = true) {
    const __LABEL = getValue(label, defLabel);
 
    if (isSelect && __LABEL && (substParam(__LABEL, '_') === __LABEL)) {
        return __LABEL + (isForm ? "|$" : " $");
    } else {
        return __LABEL;
    }
}
 
// Zeigt eine Option auf der Seite als Auswahlbox an
// opt: Anzuzeigende Option
// opt: Anzuzeigende Option
// return String mit dem HTML-Code
// return String mit dem HTML-Code
Zeile 3.568: Zeile 3.206:
     const __NAME = getOptName(opt);
     const __NAME = getOptName(opt);
     const __VALUE = getOptValue(opt);
     const __VALUE = getOptValue(opt);
     const __ACTION = getFormActionEvent(opt, false, undefined, 'change', undefined);
     const __ACTION = getFormActionEvent(opt, false, undefined, "change", undefined);
     const __FORMLABEL = formatLabel(__CONFIG.FormLabel, __CONFIG.Label, true);
     const __FORMLABEL = getValue(__CONFIG.FormLabel, __CONFIG.Label);
    const __TITLE = substParam(getValue(__CONFIG.Title, __CONFIG.Label), __VALUE);
     const __LABEL = '<label for="' + __NAME + '">' + __FORMLABEL + '</label>';
     const __LABEL = '<label for="' + __NAME + '">' + __FORMLABEL + '</label>';
     let element = '<select name="' + __NAME + '" id="' + __NAME + '"' + __ACTION + '>';
     let element = '<select name="' + __NAME + '" id="' + __NAME + '"' + __ACTION + '>';
Zeile 3.584: Zeile 3.221:
     element += '\n</select>';
     element += '\n</select>';


     return withTitle(substParam(__LABEL, element), __TITLE);
     return __LABEL.replace('$', element);
}
}


Zeile 3.594: Zeile 3.231:
     const __NAME = getOptName(opt);
     const __NAME = getOptName(opt);
     const __VALUE = getOptValue(opt, false);
     const __VALUE = getOptValue(opt, false);
     const __ACTION = getFormActionEvent(opt, false, true, 'click', false);
     const __ACTION = getFormActionEvent(opt, false, true, "click", false);
     const __ALTACTION = getFormActionEvent(opt, true, false, 'click', false);
     const __ALTACTION = getFormActionEvent(opt, true, false, "click", false);
    const __FORMLABEL = formatLabel(__CONFIG.FormLabel); // nur nutzen, falls angegeben
    const __TITLE = getValue(__CONFIG.Title, '$');
    const __TITLEON = substParam(__TITLE, __CONFIG.Label);
    const __TITLEOFF = substParam(getValue(__CONFIG.AltTitle, __TITLE), __CONFIG.AltLabel);
     const __ELEMENTON  = '<input type="radio" name="' + __NAME +
     const __ELEMENTON  = '<input type="radio" name="' + __NAME +
                         '" id="' + __NAME + 'ON" value="1"' +
                         '" id="' + __NAME + 'ON" value="1"' +
Zeile 3.610: Zeile 3.243:
                         ' /><label for="' + __NAME + 'OFF">' +
                         ' /><label for="' + __NAME + 'OFF">' +
                         __CONFIG.AltLabel + '</label>';
                         __CONFIG.AltLabel + '</label>';
    const __ELEMENT = [
                          withTitle(__FORMLABEL, __VALUE ? __TITLEON : __TITLEOFF),
                          withTitle(__ELEMENTON, __TITLEON),
                          withTitle(__ELEMENTOFF, __TITLEOFF)
                      ];


     return ((__FORMLABEL && __FORMLABEL.length) ? __ELEMENT : __ELEMENT.slice(1, 3));
     return [ __ELEMENTON, __ELEMENTOFF ];
}
}


Zeile 3.626: Zeile 3.254:
     const __NAME = getOptName(opt);
     const __NAME = getOptName(opt);
     const __VALUE = getOptValue(opt, false);
     const __VALUE = getOptValue(opt, false);
     const __ACTION = getFormActionEvent(opt, __VALUE, ! __VALUE, 'click', false);
     const __ACTION = getFormActionEvent(opt, __VALUE, ! __VALUE, "click", false);
     const __VALUELABEL = (__VALUE ? __CONFIG.Label : getValue(__CONFIG.AltLabel, __CONFIG.Label));
     const __FORMLABEL = getValue(__CONFIG.FormLabel, __CONFIG.Label);
    const __FORMLABEL = formatLabel(__CONFIG.FormLabel, __CONFIG.Label);
    const __TITLE = substParam(getValue(__VALUE ? __CONFIG.Title : getValue(__CONFIG.AltTitle, __CONFIG.Title), '$'), __VALUELABEL);


     return withTitle('<input type="checkbox" name="' + __NAME +
     return '<input type="checkbox" name="' + __NAME +
                    '" id="' + __NAME + '" value="' + __VALUE + '"' +
          '" id="' + __NAME + '" value="' + __VALUE + '"' +
                    (__VALUE ? ' CHECKED' : "") + __ACTION + ' /><label for="' +
          (__VALUE ? ' CHECKED' : "") + __ACTION + ' /><label for="' +
                    __NAME + '">' + __FORMLABEL + '</label>', __TITLE);
          __NAME + '">' + __FORMLABEL + '</label>';
}
}


Zeile 3.644: Zeile 3.270:
     const __NAME = getOptName(opt);
     const __NAME = getOptName(opt);
     const __VALUE = getOptValue(opt);
     const __VALUE = getOptValue(opt);
     const __ACTION = getFormActionEvent(opt, false, undefined, 'submit', undefined);
     const __ACTION = getFormActionEvent(opt, false, undefined, "submit", undefined);
     const __SUBMIT = getValue(__CONFIG.Submit, "");
     const __SUBMIT = getValue(__CONFIG.Submit, "");
     //const __ONSUBMIT = (__SUBMIT.length ? ' onKeyDown="' + __SUBMIT + '"': "");
     //const __ONSUBMIT = (__SUBMIT.length ? ' onKeyDown="' + __SUBMIT + '"': "");
     const __ONSUBMIT = (__SUBMIT ? ' onKeyDown="' + __SUBMIT + '"': "");
     const __ONSUBMIT = (__SUBMIT ? ' onKeyDown="' + __SUBMIT + '"': "");
     const __FORMLABEL = formatLabel(__CONFIG.FormLabel, __CONFIG.Label);
     const __FORMLABEL = getValue(__CONFIG.FormLabel, __CONFIG.Label);
    const __TITLE = substParam(getValue(__CONFIG.Title, '$'), __FORMLABEL);
     const __ELEMENTLABEL = '<label for="' + __NAME + '">' + __FORMLABEL + '</label>';
     const __ELEMENTLABEL = '<label for="' + __NAME + '">' + __FORMLABEL + '</label>';
     const __ELEMENTTEXT = '<textarea name="' + __NAME + '" id="' + __NAME + '" cols="' + __CONFIG.Cols +
     const __ELEMENTTEXT = '<textarea name="' + __NAME + '" id="' + __NAME + '" cols="' + __CONFIG.Cols +
Zeile 3.655: Zeile 3.280:
                           safeStringify(__VALUE, __CONFIG.Replace, __CONFIG.Space) + '</textarea>';
                           safeStringify(__VALUE, __CONFIG.Replace, __CONFIG.Space) + '</textarea>';


     return [ withTitle(__ELEMENTLABEL, __TITLE), __ELEMENTTEXT ];
     return [ __ELEMENTLABEL, __ELEMENTTEXT ];
}
}


Zeile 3.665: Zeile 3.290:
     const __NAME = getOptName(opt);
     const __NAME = getOptName(opt);
     const __VALUE = getOptValue(opt, false);
     const __VALUE = getOptValue(opt, false);
     const __ACTION = getFormActionEvent(opt, __VALUE, ! __VALUE, 'click', false);
     const __ACTION = getFormActionEvent(opt, __VALUE, ! __VALUE, "click", false);
     const __BUTTONLABEL = (__VALUE ? getValue(__CONFIG.AltLabel, __CONFIG.Label) : __CONFIG.Label);
     const __BUTTONLABEL = (__VALUE ? __CONFIG.AltLabel : __CONFIG.Label);
     const __FORMLABEL = formatLabel(__CONFIG.FormLabel, __BUTTONLABEL);
     const __FORMLABEL = getValue(__CONFIG.FormLabel, __CONFIG.Label);
    const __BUTTONTITLE = substParam(getValue(__VALUE ? getValue(__CONFIG.AltTitle, __CONFIG.Title) : __CONFIG.Title, '$'), __BUTTONLABEL);


     return '<label for="' + __NAME + '">' + __FORMLABEL + '</label>' +
     return '<label for="' + __NAME + '">' + __FORMLABEL +
          withTitle('<input type="button" name="" + ' + __NAME +
          '</label><input type="button" name="' + __NAME +
                    '" id="' + __NAME + '" value="' + __BUTTONLABEL +
          '" id="' + __NAME + '" value="' + __BUTTONLABEL + '"' +
                    '"' + __ACTION + '/>', __BUTTONTITLE);
          __ACTION + '/>';
}
}


Zeile 3.703: Zeile 3.327:
         }
         }


         if ((typeof element) !== 'string') {
         if (element.length === 2) {
             element = '<div>' + Array.from(element).join('<br />') + '</div>';
             element = '<div>' + element[0] + '<br />' + element[1] + '</div>';
         }
         }
     }
     }


     return element;
     return element;
}
// Gruppiert die Daten eines Objects nach einem Kriterium
// data: Object mit Daten
// byFun: function(val), die das Kriterium ermittelt. Default: value
// filterFun: function(key, index, arr), die das Kriterium key im Array arr an der Stelle index vergleicht. Default: Wert identisch
// sortFun: function(a, b), nach der die Kriterien sortiert werden. Default: Array.sort()
// return Neues Object mit Eintraegen der Form <Kriterium> : [ <alle Keys zu diesem Kriterium> ]
function groupData(data, byFun, filterFun, sortFun) {
    const __BYFUN = (byFun || (val => val));
    const __FILTERFUN = (filterFun || ((key, index, arr) => (arr[index] === key)));
    const __KEYS = Object.keys(data);
    const __VALS = Object.values(data);
    const __BYKEYS = __VALS.map(__BYFUN);
    const __BYKEYSET = new Set(__BYKEYS);
    const __BYKEYARRAY = [...__BYKEYSET];
    const __SORTEDKEYS = __BYKEYARRAY.sort(sortFun);
    const __GROUPEDKEYS = __SORTEDKEYS.map(byVal => __KEYS.filter((key, index, arr) => __FILTERFUN(byVal, index, __BYKEYS)));
    const __ASSIGN = ((keyArr, valArr) => Object.assign({ }, ...keyArr.map((key, index) => ({ [key] : valArr[index] }))));
    return __ASSIGN(__SORTEDKEYS, __GROUPEDKEYS);
}
}


Zeile 3.746: Zeile 3.349:
     const __FORMBREAK = getValue(optParams.formBreak, __FORMWIDTH);
     const __FORMBREAK = getValue(optParams.formBreak, __FORMWIDTH);
     const __SHOWFORM = getOptValue(optSet.showForm, true) ? optParams.showForm : { 'showForm' : true };
     const __SHOWFORM = getOptValue(optSet.showForm, true) ? optParams.showForm : { 'showForm' : true };
    const __PRIOOPTS = groupData(optSet, opt => getOptConfig(opt).FormPrio);
     let form = __FORM;
     let form = __FORM;
     let count = 0;  // Bisher angezeigte Optionen
     let count = 0;  // Bisher angezeigte Optionen
     let column = 0;  // Spalte der letzten Option (1-basierend)
     let column = 0;  // Spalte der letzten Option (1-basierend)


     for (let optKeys of Object.values(__PRIOOPTS)) {
     for (let opt in optSet) {
         for (let optKey of optKeys) {
         if (checkItem(opt, __SHOWFORM, optParams.hideForm)) {
            if (checkItem(optKey, __SHOWFORM, optParams.hideForm)) {
            const __ELEMENT = getOptionElement(optSet[opt]);
                const __ELEMENT = getOptionElement(optSet[optKey]);
            const __TDOPT = ((~ __ELEMENT.indexOf('|')) ? "" : ' colspan="2"');
                const __TDOPT = ((~ __ELEMENT.indexOf('|')) ? "" : ' colspan="2"');


                if (__ELEMENT) {
            if (__ELEMENT) {
                    if (++count > __FORMBREAK) {
                if (++count > __FORMBREAK) {
                        if (++column > __FORMWIDTH) {
                    if (++column > __FORMWIDTH) {
                            column = 1;
                        column = 1;
                        }
                     }
                     }
                    if (column === 1) {
                        form += '</tr><tr>';
                    }
                    form += '\n<td' + __TDOPT + '>' + __ELEMENT.replace('|', '</td><td>') + '</td>';
                 }
                 }
                if (column === 1) {
                    form += '</tr><tr>';
                }
                form += '\n<td' + __TDOPT + '>' + __ELEMENT.replace('|', '</td><td>') + '</td>';
             }
             }
         }
         }
Zeile 3.848: Zeile 3.448:
                                           if (__PARAM !== undefined) {
                                           if (__PARAM !== undefined) {
                                               // Klassifizierte Optionen umbenennen...
                                               // Klassifizierte Optionen umbenennen...
                                               return renameOptions(this.optSet, this.optSelect, __PARAM, this.renameFun);
                                               renameOptions(this.optSet, this.optSelect, __PARAM, this.renameFun);
                                          } else {
                                              return Promise.resolve();
                                           }
                                           }
                                       },
                                       },
Zeile 3.858: Zeile 3.456:
                                           return deleteOptions(this.optSet, __OPTSELECT, true, true);
                                           return deleteOptions(this.optSet, __OPTSELECT, true, true);
                                       }
                                       }
                 });
                 } );


// ==================== Ende Abschnitt fuer Klasse Classification ====================
// ==================== Ende Abschnitt fuer Klasse Classification ====================
Zeile 3.885: Zeile 3.483:
                                           }
                                           }
                                       }
                                       }
                 });
                 } );


// ==================== Ende Abschnitt fuer Klasse TeamClassification ====================
// ==================== Ende Abschnitt fuer Klasse TeamClassification ====================
Zeile 3.910: Zeile 3.508:
                                         'LgNr' : true
                                         'LgNr' : true
                                     }
                                     }
                 });
                 } );


// ==================== Ende Abschnitt fuer Klasse Team ====================
// ==================== Ende Abschnitt fuer Klasse Team ====================
Zeile 3.938: Zeile 3.536:
                                         'Flags'  : true
                                         'Flags'  : true
                                     }
                                     }
                 });
                 } );


// ==================== Ende Abschnitt fuer Klasse Verein ====================
// ==================== Ende Abschnitt fuer Klasse Verein ====================
Zeile 3.952: Zeile 3.550:
// Optionen mit Daten, die ZAT- und Team-bezogen gemerkt werden...
// Optionen mit Daten, die ZAT- und Team-bezogen gemerkt werden...
__TEAMCLASS.optSelect = {
__TEAMCLASS.optSelect = {
                            'datenZat'       : true,
                      'datenZat'     : true,
                            'oldDatenZat'     : true,
                      'oldDatenZat' : true,
                            'fingerprints'   : true,
                      'fingerprints' : true,
                            'birthdays'       : true,
                      'birthdays'   : true,
                            'tClasses'       : true,
                      'tClasses'     : true,
                            'progresses'     : true,
                      'progresses'   : true,
                            'ziehAnz'        : true,
                      'zatAges'     : true,
                            'ziehAnzAufstieg' : true,
                      'trainiert'   : true,
                            'zatAges'         : true,
                      'positions'   : true,
                            'trainiert'       : true,
                      'skills'       : true,
                            'positions'       : true,
                      'foerderung'   : true
                            'skills'         : true,
                  };
                            'foerderung'     : true
                        };


// Gibt die Teamdaten zurueck und aktualisiert sie ggfs. in der Option
// Gibt die Teamdaten zurueck und aktualisiert sie ggfs. in der Option
Zeile 3.976: Zeile 3.572:
         addProps(myTeam, teamParams, myTeam.__TEAMITEMS);
         addProps(myTeam, teamParams, myTeam.__TEAMITEMS);
         __LOG[2]("Ermittelt: " + safeStringify(myTeam));
         __LOG[2]("Ermittelt: " + safeStringify(myTeam));
         // ... und abspeichern, falls erweunscht...
         // ... und abspeichern...
         if (optSet && optSet.team) {
         setOpt(optSet.team, myTeam, false);
            setOpt(optSet.team, myTeam, false);
        }
     } else {
     } else {
         const __TEAM = ((optSet && optSet.team) ? getOptValue(optSet.team) : undefined);  // Gespeicherte Parameter
         const __TEAM = getOptValue(optSet.team);  // Gespeicherte Parameter


         if ((__TEAM !== undefined) && (__TEAM.Land !== undefined)) {
         if ((__TEAM !== undefined) && (__TEAM.Land !== undefined)) {
Zeile 3.987: Zeile 3.581:
             __LOG[2]("Gespeichert: " + safeStringify(myTeam));
             __LOG[2]("Gespeichert: " + safeStringify(myTeam));
         } else {
         } else {
             __LOG[6]("Team nicht ermittelt: " + safeStringify(__TEAM));
             __LOG[1]("Unbekannt: " + safeStringify(__TEAM));
         }
         }
     }
     }
Zeile 4.005: Zeile 3.599:
// 'formWidth': Anzahl der Elemente pro Zeile
// 'formWidth': Anzahl der Elemente pro Zeile
// 'formBreak': Elementnummer des ersten Zeilenumbruchs
// 'formBreak': Elementnummer des ersten Zeilenumbruchs
// return Promise auf gefuelltes Objekt mit den gesetzten Optionen
// return Gefuelltes Objekt mit den gesetzten Optionen
function buildOptions(optConfig, optSet = undefined, optParams = { 'hideMenu' : false }) {
function buildOptions(optConfig, optSet = undefined, optParams = { 'hideMenu' : false }) {
     // Klassifikation ueber Land und Liga des Teams...
     // Klassifikation ueber Land und Liga des Teams...
Zeile 4.011: Zeile 3.605:
     __TEAMCLASS.teamParams = optParams.teamParams;  // Ermittelte Parameter
     __TEAMCLASS.teamParams = optParams.teamParams;  // Ermittelte Parameter


     return startOptions(optConfig, optSet, __TEAMCLASS).then(optSet => {
     optSet = startOptions(optConfig, optSet, __TEAMCLASS);
                    if (optParams.getDonation) {
 
                        // Jugendfoerderung aus der Options-HTML-Seite ermitteln...
    if (optParams.getDonation) {
                        const __BOXDONATION = document.getElementsByTagName('option');
        // Jugendfoerderung aus der Options-HTML-Seite ermitteln...
                        const __DONATION = getSelectionFromComboBox(__BOXDONATION, 10000, 'Number');
        const __BOXDONATION = document.getElementsByTagName('option');
        const __DONATION = getSelectionFromComboBox(__BOXDONATION, 10000, 'Number');
 
        __LOG[3]("Jugendf\xF6rderung: " + __DONATION + " Euro");


                        __LOG[3]("Jugendf\xF6rderung: " + __DONATION + " Euro");
        // ... und abspeichern...
        setOpt(optSet.foerderung, __DONATION, false);
    }


                        // ... und abspeichern...
    showOptions(optSet, optParams);
                        setOpt(optSet.foerderung, __DONATION, false);
                    }


                    return showOptions(optSet, optParams);
    return optSet;
                }, defaultCatch);
}
}


Zeile 4.034: Zeile 3.630:


// Erschafft die Spieler-Objekte und fuellt sie mit Werten
// Erschafft die Spieler-Objekte und fuellt sie mit Werten
// playerRows: Array von Zeilen mit Array cells (Spielertabelle)
// reloadData: true = Teamuebersicht, false = Spielereinzelwerte
// optSet: Gesetzte Optionen (und Config)
function init(playerRows, optSet, colIdx, offsetUpper = 1, offsetLower = 0, reloadData = false) {
// colIdx: Liste von Spaltenindices der gesuchten Werte
     storePlayerDataFromHTML(playerRows, optSet, colIdx, offsetUpper, offsetLower, reloadData);
// offsetUpper: Ignorierte Zeilen oberhalb der Daten
// offsetLower: Ignorierte Zeilen unterhalb der Daten
// page: 1: Teamuebersicht, 2: Spielereinzelwerte, 3: Opt. Skill, 4: Optionen, Default: 0
function init(playerRows, optSet, colIdx, offsetUpper = 1, offsetLower = 0, page = 0) {
     storePlayerDataFromHTML(playerRows, optSet, colIdx, offsetUpper, offsetLower, page);


     const __SAISON = getOptValue(optSet.saison);
     const __SAISON = getOptValue(optSet.saison);
     const __AKTZAT = getOptValue(optSet.aktuellerZat);
     const __CURRZAT = getOptValue(optSet.aktuellerZat);
    const __GEALTERT = ((__AKTZAT >= 72) ? (getIntFromHTML(playerRows[playerRows.length - offsetLower - 1].cells, colIdx.Age) < 13) : false);
    const __CURRZAT = (__GEALTERT ? 0 : __AKTZAT);
    const __LGNR = __TEAMCLASS.team.LgNr;
    const __KLASSE = (__LGNR > 1) ? (__LGNR > 3) ? 3 : 2 : 1;
     const __DONATION = getOptValue(optSet.foerderung);
     const __DONATION = getOptValue(optSet.foerderung);
     const __BIRTHDAYS = getOptValue(optSet.birthdays, []);
     const __BIRTHDAYS = getOptValue(optSet.birthdays, []);
Zeile 4.057: Zeile 3.644:
     const __POSITIONS = getOptValue(optSet.positions, []);
     const __POSITIONS = getOptValue(optSet.positions, []);
     const __SKILLS = getOptValue(optSet.skills, []);
     const __SKILLS = getOptValue(optSet.skills, []);
    const __ISSKILLPAGE = (page === 2);
     const __BASEDATA = [ __BIRTHDAYS, __TCLASSES, __PROGRESSES ];  // fuer initPlayer
     const __BASEDATA = [ __BIRTHDAYS, __TCLASSES, __PROGRESSES ];  // fuer initPlayer
     const __DATA = (__ISSKILLPAGE ? [ __SKILLS, __BASEDATA ] : [ __BASEDATA, __SKILLS ]);  // fuer initPlayer: [0] = von HTML-Seite, [1] = aus gespeicherten Daten
     const __DATA = (reloadData ? [ __BASEDATA, __SKILLS ] : [ __SKILLS, __BASEDATA ]);  // fuer initPlayer: [0] = von HTML-Seite, [1] = aus gespeicherten Daten
     const __IDMAP = getPlayerIdMap(optSet);
     const __IDMAP = getPlayerIdMap(optSet);
     const __CATIDS = __IDMAP.catIds;
     const __CATIDS = __IDMAP.catIds;
Zeile 4.066: Zeile 3.652:
     __LOG[5](__IDMAP);
     __LOG[5](__IDMAP);


     for (let i = offsetUpper, j = 0; i < playerRows.length - offsetLower; i++) {
     for (let i = offsetUpper, j = 0; i < playerRows.length - offsetLower; i++, j++) {
         const __CELLS = playerRows[i].cells;
         const __CELLS = playerRows[i].cells;
        const __LAND = getStringFromHTML(__CELLS, colIdx.Land);
        const __AGE = getIntFromHTML(__CELLS, colIdx.Age);
        const __ISGOALIE = isGoalieFromHTML(__CELLS, colIdx.Age);
        const __NEWPLAYER = new PlayerRecord(__LAND, __AGE, __ISGOALIE, __SAISON, __CURRZAT, __DONATION);


         if (__CELLS.length > 1) {
         __NEWPLAYER.initPlayer(__DATA[0], j, ! reloadData);
            const __LAND = getStringFromHTML(__CELLS, colIdx.Land);
            const __AGE = getIntFromHTML(__CELLS, colIdx.Age);
            const __ISGOALIE = isGoalieFromHTML(__CELLS, colIdx.Age);
            const __AKTION = getElementFromHTML(__CELLS, colIdx.Akt);


            const __NEWPLAYER = new PlayerRecord(__LAND, __AGE, __ISGOALIE, __SAISON, __CURRZAT, __DONATION);
        const __IDX = selectPlayerIndex(__NEWPLAYER, j, __CATIDS);


            __NEWPLAYER.initPlayer(__DATA[0], j, __ISSKILLPAGE);
        __NEWPLAYER.initPlayer(__DATA[1], __IDX, reloadData);


            const __IDX = selectPlayerIndex(__NEWPLAYER, j, __CATIDS);
        __NEWPLAYER.prognoseSkills();


             __NEWPLAYER.initPlayer(__DATA[1], __IDX, ! __ISSKILLPAGE);
        if (reloadData) {
 
             __NEWPLAYER.setZusatz(__ZATAGES[__IDX], __TRAINIERT[__IDX], __POSITIONS[__IDX]);
            __NEWPLAYER.prognoseSkills();
        }


            if (! __ISSKILLPAGE) {
        __PLAYERS[j] = __NEWPLAYER;
                __NEWPLAYER.setZusatz(__ZATAGES[__IDX], __TRAINIERT[__IDX], __POSITIONS[__IDX]);
            }
 
            __NEWPLAYER.createWarnDraw(__AKTION, __KLASSE);
 
            __PLAYERS[j++] = __NEWPLAYER;
        }
     }
     }


     if (__ISSKILLPAGE) {
     if (reloadData) {
        setPlayerData(__PLAYERS, optSet);
    } else {
         calcPlayerData(__PLAYERS, optSet);
         calcPlayerData(__PLAYERS, optSet);
    } else {
        setPlayerData(__PLAYERS, optSet);
     }
     }


Zeile 4.136: Zeile 3.715:


// Berechnet die Identifikations-IDs (Fingerprints) der Spieler neu und speichert diese
// Berechnet die Identifikations-IDs (Fingerprints) der Spieler neu und speichert diese
// players: Array von PlayerRecord mit den Spielerdaten
// optSet: Gesetzte Optionen (und Config)
function storePlayerIds(players, optSet) {
function storePlayerIds(players, optSet) {
     const __FINGERPRINTS = [];
     const __FINGERPRINTS = [];
Zeile 4.153: Zeile 3.730:


// Sucht fuer den Spieler den Eintrag aus catIds heraus und gibt den (geloeschten) Index zurueck
// Sucht fuer den Spieler den Eintrag aus catIds heraus und gibt den (geloeschten) Index zurueck
// player: PlayerRecord mit den Daten eines Spielers
// index: Position des Spielers im neuen Array von Spielerdaten
// catIds: PlayerIdMap zum Finden des Spielers ueber die Spielerdaten
// return Original-Index der Daten dieses Spielers im Array von Spielerdaten
function selectPlayerIndex(player, index, catIds) {
function selectPlayerIndex(player, index, catIds) {
     const __MYCAT = player.getCat();
     const __MYCAT = player.getCat();
Zeile 4.172: Zeile 3.745:


// Speichtert die abgeleiteten Werte in den Spieler-Objekten
// Speichtert die abgeleiteten Werte in den Spieler-Objekten
// players: Array von PlayerRecord mit den Spielerdaten
// optSet: Gesetzte Optionen (und Config)
function setPlayerData(players, optSet) {
function setPlayerData(players, optSet) {
    const __ZIEHANZAHL = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
    let ziehAnzAufstieg = 0;
     const __ZATAGES = [];
     const __ZATAGES = [];
     const __TRAINIERT = [];
     const __TRAINIERT = [];
Zeile 4.185: Zeile 3.754:


         if (__ZUSATZ.zatAge !== undefined) {  // braucht Geburtstag fuer gueltige Werte!
         if (__ZUSATZ.zatAge !== undefined) {  // braucht Geburtstag fuer gueltige Werte!
             const __INDEX = players[i].calcZiehIndex()// Lfd. Nummer des Abrechnungsmonats (0-basiert)
             __ZATAGES[i]    = __ZUSATZ.zatAge;
        }
        __TRAINIERT[i] = __ZUSATZ.trainiert;
        __POSITIONS[i] = __ZUSATZ.bestPos;
    }


            if ((__INDEX >= 0) && (__INDEX < __ZIEHANZAHL.length)) {
                __ZIEHANZAHL[__INDEX]++;
            }
            __ZATAGES[i] = __ZUSATZ.zatAge;
        }
        if (players[i].isZiehAufstieg()) {
            ziehAnzAufstieg++;
        }
        __TRAINIERT[i] = __ZUSATZ.trainiert;
        __POSITIONS[i] = __ZUSATZ.bestPos;
    }
    setOpt(optSet.ziehAnz, __ZIEHANZAHL, false);
    setOpt(optSet.ziehAnzAufstieg, ziehAnzAufstieg, false);
     setOpt(optSet.zatAges, __ZATAGES, false);
     setOpt(optSet.zatAges, __ZATAGES, false);
     setOpt(optSet.trainiert, __TRAINIERT, false);
     setOpt(optSet.trainiert, __TRAINIERT, false);
Zeile 4.208: Zeile 3.766:


// Berechnet die abgeleiteten Werte in den Spieler-Objekten neu und speichert diese
// Berechnet die abgeleiteten Werte in den Spieler-Objekten neu und speichert diese
// players: Array von PlayerRecord mit den Spielerdaten
// optSet: Gesetzte Optionen (und Config)
function calcPlayerData(players, optSet) {
function calcPlayerData(players, optSet) {
     const __ZATAGES = [];
     const __ZATAGES = [];
Zeile 4.219: Zeile 3.775:


         if (__ZUSATZ.zatAge !== undefined) {  // braucht Geburtstag fuer gueltige Werte!
         if (__ZUSATZ.zatAge !== undefined) {  // braucht Geburtstag fuer gueltige Werte!
             __ZATAGES[i] = __ZUSATZ.zatAge;
             __ZATAGES[i]   = __ZUSATZ.zatAge;
         }
         }
         __TRAINIERT[i] = __ZUSATZ.trainiert;
         __TRAINIERT[i] = __ZUSATZ.trainiert;
         __POSITIONS[i] = __ZUSATZ.bestPos;
         __POSITIONS[i] = __ZUSATZ.bestPos;
     }
     }


Zeile 4.230: Zeile 3.786:
}
}


// Ermittelt die fuer diese Seite relevanten Werte in den Spieler-Objekten aus den Daten der Seite und speichert diese
// Ermittelt die Werte in den Spieler-Objekten aus den Daten der Seite und speichert diese
// playerRows: Array von Zeilen mit Array cells (Spielertabelle)
// reloadData: true = Teamuebersicht, false = Spielereinzelwerte
// optSet: Gesetzte Optionen (und Config)
function storePlayerDataFromHTML(playerRows, optSet, colIdx, offsetUpper = 1, offsetLower = 0, reloadData = false) {
// colIdx: Liste von Spaltenindices der gesuchten Werte
     if (reloadData) {
// offsetUpper: Ignorierte Zeilen oberhalb der Daten
        const __BIRTHDAYS = [];
// offsetLower: Ignorierte Zeilen unterhalb der Daten
        const __TCLASSES = [];
// page: 1: Teamuebersicht, 2: Spielereinzelwerte, 3: Opt. Skill, 4: Optionen, Default: 0
        const __PROGRESSES = [];
function storePlayerDataFromHTML(playerRows, optSet, colIdx, offsetUpper = 1, offsetLower = 0, page = 0) {
     const __COLDEFS = [ { }, {
                                'birthdays'  : { 'name' : 'birthdays', 'getFun' : getIntFromHTML, 'params' : [ colIdx.Geb ] },
                                'tClasses'  : { 'name' : 'tClasses', 'getFun' : getTalentFromHTML, 'params' : [ colIdx.Tal ] },
                                'progresses' : { 'name' : 'progresses', 'getFun' : getAufwertFromHTML, 'params' : [ colIdx.Auf, getOptValue(optSet.shortAufw, true) ] }
                            }, {
                                'skills'    : { 'name' : 'skills', 'getFun' : getSkillsFromHTML, 'params' : [ colIdx ]}
                            } ][getValueIn(page, 1, 2, 0)];


    return storePlayerDataColsFromHTML(playerRows, optSet, __COLDEFS, offsetUpper, offsetLower);
        for (let i = offsetUpper, j = 0; i < playerRows.length - offsetLower; i++, j++) {
}
            const __CELLS = playerRows[i].cells;


// Ermittelt bestimmte Werte in den Spieler-Objekten aus den Daten der Seite und speichert diese
            __BIRTHDAYS[j] = getIntFromHTML(__CELLS, colIdx.Geb);
// playerRows: Array von Zeilen mit Array cells (Spielertabelle)
            __TCLASSES[j] = getTalentFromHTML(__CELLS, colIdx.Tal);
// optSet: Gesetzte Optionen (und Config)
            __PROGRESSES[j] = getAufwertFromHTML(__CELLS, colIdx.Auf, getOptValue(optSet.shortAufw, true));
// colDefs: Informationen zu ausgewaehlten Datenspalten
        }
// offsetUpper: Ignorierte Zeilen oberhalb der Daten
        setOpt(optSet.birthdays, __BIRTHDAYS, false);
// offsetLower: Ignorierte Zeilen unterhalb der Daten
        setOpt(optSet.tClasses, __TCLASSES, false);
function storePlayerDataColsFromHTML(playerRows, optSet, colDefs, offsetUpper = 1, offsetLower = 0) {
        setOpt(optSet.progresses, __PROGRESSES, false);
    const __DATA = { };
    } else {
        const __SKILLS = [];


    for (let key in colDefs) {
        for (let i = offsetUpper, j = 0; i < playerRows.length - offsetLower; i++, j++) {
        __DATA[key] = [];
            const __CELLS = playerRows[i].cells;
    }


    for (let i = offsetUpper, j = 0; i < playerRows.length - offsetLower; i++) {
             __SKILLS[j] = getSkillsFromHTML(__CELLS, colIdx);
        const __CELLS = playerRows[i].cells;
 
        if (__CELLS.length > 1) {
             for (let key in colDefs) {
                const __COLDEF = colDefs[key];
 
                __DATA[key][j] = __COLDEF.getFun(__CELLS, ...__COLDEF.params);
            }
            j++;
         }
         }
    }
         setOpt(optSet.skills, __SKILLS, false);
 
    for (let key in colDefs) {
        const __COLDEF = colDefs[key];
 
        __LOG[7]('Schreibe ' + __COLDEF.name + ': ' + __DATA[key]);
 
         setOpt(optSet[__COLDEF.name], __DATA[key], false);
     }
     }
}
}
Zeile 4.290: Zeile 3.822:
     }
     }


     for (let i = offsetUpper, newVal, oldVal = formatFun((rows[i].cells[colIdxSort] || { }).textContent); i < rows.length - offsetLower - 1; i++, oldVal = newVal) {
     for (let i = offsetUpper, newVal, oldVal = formatFun(rows[i].cells[colIdxSort].textContent); i < rows.length - offsetLower - 1; i++, oldVal = newVal) {
         newVal = formatFun((rows[i + 1].cells[colIdxSort] || { }).textContent);
         newVal = formatFun(rows[i + 1].cells[colIdxSort].textContent);
         if (newVal !== oldVal) {
         if (newVal !== oldVal) {
             for (let j = offsetLeft; j < rows[i].cells.length - offsetRight; j++) {
             for (let j = offsetLeft; j < rows[i].cells.length - offsetRight; j++) {
Zeile 4.322: Zeile 3.854:


     this.colIdx = colIdx;
     this.colIdx = colIdx;
    this.saison = getOptValue(optSet.saison);
    this.gt = getOptValue(optSet.zeigeJahrgang);
    this.gtUxx = getOptValue(optSet.zeigeUxx);


     this.fpId = (__BIRTHDAYS && __TCLASSES && __POSITIONS && getValue(__SHOWCOL.zeigeId, __SHOWALL) && getOptValue(optSet.zeigeId));
     this.fpId = (__BIRTHDAYS && __TCLASSES && __POSITIONS && getValue(__SHOWCOL.zeigeId, __SHOWALL) && getOptValue(optSet.zeigeId));
    this.warn = (__ZATAGES && getValue(__SHOWCOL.zeigeWarnung, __SHOWALL) && getOptValue(optSet.zeigeWarnung));
    this.warnMonth = (__ZATAGES && getValue(__SHOWCOL.zeigeWarnungMonat, __SHOWALL) && getOptValue(optSet.zeigeWarnungMonat));
    this.warnHome = (__ZATAGES && getValue(__SHOWCOL.zeigeWarnungHome, __SHOWALL) && getOptValue(optSet.zeigeWarnungHome));
    this.warnDialog = (__ZATAGES && getValue(__SHOWCOL.zeigeWarnungDialog, __SHOWALL) && getOptValue(optSet.zeigeWarnungDialog));
    this.warnAufstieg = (__ZATAGES && getValue(__SHOWCOL.zeigeWarnungAufstieg, __SHOWALL) && getOptValue(optSet.zeigeWarnungAufstieg));
    this.warnLegende = (__ZATAGES && getValue(__SHOWCOL.zeigeWarnungLegende, __SHOWALL) && getOptValue(optSet.zeigeWarnungLegende));
     this.bar = (__PROJECTION && getValue(__SHOWCOL.zeigeBalken, __SHOWALL) && getOptValue(optSet.zeigeBalken));
     this.bar = (__PROJECTION && getValue(__SHOWCOL.zeigeBalken, __SHOWALL) && getOptValue(optSet.zeigeBalken));
     this.barAbs = getOptValue(optSet.absBalken);
     this.barAbs = getOptValue(optSet.absBalken);
Zeile 4.515: Zeile 4.037:
                           },  // Ende addTitles()
                           },  // Ende addTitles()
         'addValues'      : function(player, playerRow, color = "#FFFFFF") {
         'addValues'      : function(player, playerRow, color = "#FFFFFF") {
                              // Warnlevel des Spielers anpassen...
                              const __WARNDRAW = player.warnDraw || player.warnDrawAufstieg || __NOWARNDRAW;
                              __WARNDRAW.setWarn(this.warn, this.warnMonth, this.warnAufstieg);
                               const __IDXPRI = getIdxPriSkills(player.getPos());
                               const __IDXPRI = getIdxPriSkills(player.getPos());
                               const __COLOR = __WARNDRAW.getColor(player.isGoalie ? getColor('TOR') : color); // Angepasst an Ziehwarnung
                              const __COLALERT = getColor('STU');  // rot
                               const __COLOR = ((player.zatLeft < 1) ? __COLALERT : player.isGoalie ? getColor('TOR') : color);
                               const __POS1COLOR = getColor((player.getPosPercent() > 99.99) ? 'LEI' : player.getPos());
                               const __POS1COLOR = getColor((player.getPosPercent() > 99.99) ? 'LEI' : player.getPos());
                               const __OSBLAU = getColor("");
                               const __OSBLAU = getColor("");
Zeile 4.560: Zeile 4.079:
                                   this.addAndFillCell(playerRow, player.getAge(), __COLOR, null, 2);
                                   this.addAndFillCell(playerRow, player.getAge(), __COLOR, null, 2);
                               }
                               }
                               if (__WARNDRAW.monthDraw()) {  // Abrechnungszeitraum vor dem letztmoeglichen Ziehen...
                               if (player.zatLeft < 6) {  // Abrechnungszeitraum vor dem letztmoeglichen Ziehen...
                                   formatCell(playerRow.cells[this.colIdx.Age], true, __WARNDRAW.colAlert, null, 1.0);
                                   formatCell(playerRow.cells[this.colIdx.Age], true, __COLALERT, null);
                               }
                               }
                               if (this.fix) {
                               if (this.fix) {
Zeile 4.611: Zeile 4.130:
                               }
                               }


                               // Einzelwerte mit Ende 18
                               // Werte mit Ende 18
                               if (this.colIdx.Einz) {
                               if (this.substSkills) {
                                  if (this.substSkills) {
                                  convertArrayFromHTML(playerRow.cells, this.colIdx.Einz, player.skillsEnd, function(value, cell, unused, index) {
                                      convertArrayFromHTML(playerRow.cells, this.colIdx.Einz, player.skillsEnd, function(value, cell, unused, index) {
                                                                                                                if (~ __IDXPRI.indexOf(index)) {
                                                                                                                    formatCell(cell, true, __OSBLAU, __POS1COLOR);
                                                                                                                }
                                                                                                                return value;
                                                                                                            });
                              } else if (this.colIdx.Einz) {
                                  convertArrayFromHTML(playerRow.cells, this.colIdx.Einz, player.skills.length, function(value, cell, unused, index) {
                                                                                                                     if (~ __IDXPRI.indexOf(index)) {
                                                                                                                     if (~ __IDXPRI.indexOf(index)) {
                                                                                                                         formatCell(cell, true, __OSBLAU, __POS1COLOR, 1.0);
                                                                                                                         formatCell(cell, true);
                                                                                                                     }
                                                                                                                     }
                                                                                                                     return value;
                                                                                                                     return value;
                                                                                                                 });
                                                                                                                 });
                                  } else {
                                      convertArrayFromHTML(playerRow.cells, this.colIdx.Einz, player.skills.length, function(value, cell, unused, index) {
                                                                                                                        if (~ __IDXPRI.indexOf(index)) {
                                                                                                                            formatCell(cell, true, __POS1COLOR, null, 1.0);
                                                                                                                        }
                                                                                                                        return value;
                                                                                                                    });
                                  }
                               }
                               }
                               if (this.trE) {
                               if (this.trE) {
Zeile 4.670: Zeile 4.187:
                                   }
                                   }
                               }
                               }
                           }, // Ende addValues(player, playerRow)
                           }  // Ende addValues(player, playerRow)
        'setGroupTitle'  : function(tableRow) {
     } );
                              if (this.gtUxx) {
                                  const __CELL = tableRow.cells[0];
                                  const __SAI = __CELL.innerHTML.match(/Saison (\d+)/)[1];
                                  const __JG = 13 + this.saison - __SAI;
 
                                  __CELL.innerHTML = __CELL.innerHTML.replace('Jahrgang', 'U' + __JG + ' - $&');
                              }
 
                              tableRow.style.display = (this.gt ? '' : 'none');
                          }  // Ende setGroupTitle(tableRow)
     });


// Klasse PlayerRecord ******************************************************************
// Klasse PlayerRecord ******************************************************************
Zeile 4.723: Zeile 4.229:
     // this.trainiert: Anzahl der erfolgreichen Trainingspunkte
     // this.trainiert: Anzahl der erfolgreichen Trainingspunkte
     // indirekt this.zatAge und this.bestPos
     // indirekt this.zatAge und this.bestPos
    // in this.createWarnDraw() definiert:
    // this.warnDraw: Behandlung von Warnungen Ende 18
    // this.warnDrawAufstieg: Behandlung von Warnungen bei Aufstieg


     // in this.getPos() definiert:
     // in this.getPos() definiert:
Zeile 4.768: Zeile 4.270:
                                       return result;
                                       return result;
                                   },  // Ende this.toString()
                                   },  // Ende this.toString()
         'initPlayer'            : function(data, index, isSkillData = false) {  // isSkillData: true = Skilldaten, false = Basiswerte (Geb., Talent, Aufwertungen) oder keine
         'initPlayer'            : function(data, index, skillData = false) {  // skillData: true = Skilldaten, false = Basiswerte (Geb., Talent, Aufwertungen)
                                       if (data !== undefined) {
                                       if (data !== undefined) {
                                           if (isSkillData) {
                                           if (skillData) {
                                               this.setSkills(data[index]);
                                               this.setSkills(data[index]);
                                           } else if (data.length >= 2){
                                           } else {
                                               this.setGeb(data[0][index]);
                                               this.setGeb(data[0][index]);
                                               this.talent = data[1][index];
                                               this.talent = data[1][index];
                                               this.aufwert = data[2][index];
                                               this.aufwert = data[2][index];
                                          } else {
                                              // keine Daten
                                           }
                                           }
                                       }
                                       }
                                   },  // Ende this.initPlayer()
                                   },  // Ende this.initPlayer()
        'createWarnDraw'        : function(ziehmich = null, klasse = 1) {  // ziehmich: input Element zum Ziehen; klasse: Spielklasse 1, 2, 3
                                      // Objekte fuer die Verwaltung der Ziehwarnungen...
                                      this.warnDraw = undefined;
                                      this.warnDrawAufstieg = undefined;
                                      if (ziehmich) {
                                          const __LASTZAT = this.currZAT + this.getZatLeft();
                                          if (__LASTZAT < 72) {  // U19
                                              this.warnDraw = new WarnDrawPlayer(this, getColor('STU'));  // rot
                                              __LOG[4](this.getAge().toFixed(2), "rot");
                                          } else if (__LASTZAT < Math.max(2, klasse) * 72) {  // Rest bis inkl. U18 (Liga 1 und 2) bzw. U17 (Liga 3)
                                              // do nothing
                                          } else if (__LASTZAT < (klasse + 1) * 72) {  // U17/U16 je nach Liga 2/3
                                              this.warnDrawAufstieg = new WarnDrawPlayer(this, getColor('OMI'));  // magenta
                                              this.warnDrawAufstieg.setAufstieg();
                                              __LOG[4](this.getAge().toFixed(2), "magenta");
                                          }
                                      }
                                  },  // Ende this.createWarnDraw()
         'setSkills'            : function(skills) {
         'setSkills'            : function(skills) {
                                       // Berechnet die Opti-Werte, sortiert das Positionsfeld und berechnet die Einzelskills mit Ende 18
                                       // Berechnet die Opti-Werte, sortiert das Positionsfeld und berechnet die Einzelskills mit Ende 18
Zeile 4.887: Zeile 4.368:
                                       if (when === this.__TIME.end) {
                                       if (when === this.__TIME.end) {
                                           return (18 - 12) * 72 - 1;  // (max.) Trainings-ZATs bis Ende 18
                                           return (18 - 12) * 72 - 1;  // (max.) Trainings-ZATs bis Ende 18
                                       } else if (this.zatAge !== undefined) {
                                       } else {
                                           return this.zatAge;
                                           return this.zatAge;
                                      } else {
                                          __LOG[4]("Empty getZatAge()");
                                          return NaN;
                                       }
                                       }
                                   },
                                   },
Zeile 4.904: Zeile 4.381:


                                       return this.zatLeft;
                                       return this.zatLeft;
                                  },
        'calcZiehIndex'        : function() {
                                      //const __RESTZAT = this.getZatAge(this.__TIME.end) - this.getZatAge() + this.currZAT;
                                      //const __INDEX = parseInt(__RESTZAT / 6 + 1) - 1;  // Lfd. Nummer des Abrechnungsmonats (0-basiert)
                                      return (this.warnDraw && this.warnDraw.calcZiehIndex(this.currZAT));
                                  },
        'isZiehAufstieg'        : function() {
                                      return (this.warnDrawAufstieg && this.warnDrawAufstieg.isZiehAufstieg());
                                   },
                                   },
         'getAge'                : function(when = this.__TIME.now) {
         'getAge'                : function(when = this.__TIME.now) {
Zeile 4.963: Zeile 4.431:
                                   },
                                   },
         'getTalent'            : function() {
         'getTalent'            : function() {
                                       return (this.talent < 0) ? 'wenig' : (this.talent > 0) ? 'hoch' : 'normal';
                                       return (this.talent < 0) ? "wenig" : (this.talent > 0) ? "hoch" : "normal";
                                   },
                                   },
         'getAufwert'            : function() {
         'getAufwert'            : function() {
Zeile 5.015: Zeile 4.483:
                                       const __SUMPRISKILLS = this.getSkillSum(when, getIdxPriSkills(pos), 2 * 4);
                                       const __SUMPRISKILLS = this.getSkillSum(when, getIdxPriSkills(pos), 2 * 4);
                                       const __OVERFLOW = Math.max(0, __SUMPRISKILLS - this.__MAXPRISKILLS);
                                       const __OVERFLOW = Math.max(0, __SUMPRISKILLS - this.__MAXPRISKILLS);
/*if (this.zatGeb === 24) {
 
    console.error("__OVERFLOW = " + __OVERFLOW);
    console.error("__SUMALLSKILLS = " + __SUMALLSKILLS);
    console.error("__SUMPRISKILLS = " + __SUMPRISKILLS);
    console.error("getOpti(" + pos + ") = " + ((4 * (__SUMPRISKILLS - __OVERFLOW) + __SUMALLSKILLS) / 27));
}*/
                                       return (4 * (__SUMPRISKILLS - __OVERFLOW) + __SUMALLSKILLS) / 27;
                                       return (4 * (__SUMPRISKILLS - __OVERFLOW) + __SUMALLSKILLS) / 27;
                                   },
                                   },
Zeile 5.128: Zeile 4.591:
                                       return ((__RET.length === 1) ? __RET[0] : undefined);
                                       return ((__RET.length === 1) ? __RET[0] : undefined);
                                   }
                                   }
     });
     } );


// Klasse WarnDrawPlayer *****************************************************************
// Funktionen fuer die HTML-Seite *******************************************************


function WarnDrawPlayer(player, alertColor) {
// Liest eine Zahl aus der Spalte einer Zeile der Tabelle aus (z.B. Alter, Geburtsdatum)
     'use strict';
// cells: Die Zellen einer Zeile
 
// colIdxInt: Spaltenindex der gesuchten Werte
     this.player = player;
// return Spalteneintrag als Zahl (-1 fuer "keine Zahl", undefined fuer "nicht gefunden")
function getIntFromHTML(cells, colIdxInt) {
     const __CELL = getValue(cells[colIdxInt], { });
     const __TEXT = __CELL.textContent;


     if (this.player !== undefined) {
     if (__TEXT !== undefined) {
         // Default Warnlevel...
         try {
        this.setZatLeft(player.getZatLeft());
            const __VALUE = parseInt(__TEXT, 10);
        this.currZAT = player.currZAT;
        this.setWarn(true, true, true);
        this.colAlert = alertColor || this.alertColor();
    } else {
        // Kein Warnlevel...
        this.setZatLeft(undefined);
        this.currZAT = undefined;
        this.setWarn(false, false, false);
        this.colAlert = undefined;
    }
}


Class.define(WarnDrawPlayer, Object, {
            if (! isNaN(__VALUE)) {
        '__MONATEBISABR'    : 1,
                return __VALUE;
        '__ZATWARNVORLAUF'  : 1,
            }
        '__ZATMONATVORLAUF' : 6,
         } catch (ex) { }
        'setZatLeft'        : function(zatLeft) {
                                  this.zatLeft = zatLeft;
                              },
        'setWarn'          : function(warn, warnMonth, warnAufstieg) {
                                  this.warn = (this.aufstieg ? warnAufstieg : warn);
                                  this.warnMonth = warnMonth;
                              },
         'alertColor'        : function() {
                                  return getColor('STU');  // rot
                              },
        'getColor'          : function(color) {
                                  return ((this.mustDraw() && this.colAlert) ? this.colAlert : color);
                              },
        'calcZiehIndex'    : function(currZAT) {
                                  const __RESTZAT = this.zatLeft + currZAT;
                                  const __INDEX = parseInt(__RESTZAT / 6 + 1) - this.__MONATEBISABR;  // Lfd. Nummer des Abrechnungsmonats (0-basiert)


                                  return __INDEX;
         return -1;
                              },
    }
         'isZiehAufstieg'    : function() {
                                  return this.aufstieg;
                              },
        'setAufstieg'      : function() {
                                  this.aufstieg = true;


                                  if (this.isZiehAufstieg()) {
    return undefined;
                                      this.setZatLeft(72 - this.currZAT - this.__ZATWARNVORLAUF);
}
                                  }


                                  return this.zatLeft;
// Liest eine Dezimalzahl aus der Spalte einer Zeile der Tabelle aus
                              },
// cells: Die Zellen einer Zeile
        'mustDraw'          : function() {
// colIdxInt: Spaltenindex der gesuchten Werte
                                  return ((this.warn || this.warnMonth) && (this.zatLeft < this.__ZATWARNVORLAUF));
// return Spalteneintrag als Dezimalzahl (undefined fuer "keine Zahl" oder "nicht gefunden")
                              },
function getFloatFromHTML(cells, colIdxFloat) {
        'monthDraw'        : function() {
    const __CELL = getValue(cells[colIdxFloat], { });
                                  return (this.mustDraw() || (this.warn && (this.aufstieg || this.warnMonth) && (this.zatLeft < this.__ZATMONATVORLAUF))); // Abrechnungszeitraum vor dem letztmoeglichen Ziehen...
     const __TEXT = __CELL.textContent;
                              }
     });


const __NOWARNDRAW = new WarnDrawPlayer(undefined, undefined); // inaktives Objekt
    if (__TEXT !== undefined) {
        try {
            return parseFloat(__TEXT);
        } catch (ex) { }
    }


// Klasse WarnDrawMessage *****************************************************************
    return undefined;
}


function WarnDrawMessage(optSet, currZAT) {
// Liest einen String aus der Spalte einer Zeile der Tabelle aus
     'use strict';
// cells: Die Zellen einer Zeile
 
// colIdxStr: Spaltenindex der gesuchten Werte
     this.optSet = optSet;
// return Spalteneintrag als String ("" fuer "nicht gefunden")
function getStringFromHTML(cells, colIdxStr) {
     const __CELL = getValue(cells[colIdxStr], { });
     const __TEXT = __CELL.textContent;


     this.warn = getOptValue(this.optSet.zeigeWarnung, true);
     return getValue(__TEXT.toString(), "");
    this.warnMonth = getOptValue(this.optSet.zeigeWarnungMonat, true);
}
    this.warnHome = getOptValue(this.optSet.zeigeWarnungHome, true);
    this.warnDialog = getOptValue(this.optSet.zeigeWarnungDialog, false);
    this.warnAufstieg = getOptValue(this.optSet.zeigeWarnungAufstieg, true);
    this.warnLegende = getOptValue(this.optSet.zeigeWarnungLegende, true);


    this.out = {
// Ermittelt den ausgewaehlten Wert eines Selects (Combo-Box) und gibt diesen zurueck
                  'supertag' : true,
// element: "select"-Element oder dessen Name auf der HTML-Seite mit 'option'-Eintraegen der Combo-Box
                  'top'     : true,
// defValue: Default-Wert, falls nichts selektiert ist
                  'link'     : true,
// return Ausgewaehlter Wert
                  'label'   : true,
function getSelection(element, defValue = undefined, valType = 'String') {
                  'bottom'  : true
     const __ELEMENT = ((typeof element) === 'string' ? document.getElementsByName(element) : element);
              };
    const __ENTRY = (__ELEMENT ? __ELEMENT.selectedOptions[0] : undefined);


     this.setOptionHome();
     return this[valType](getValue(__ENTRY, defValue, __ENTRY.textContent));
}


    this.startMessage(currZAT);
// Ermittelt den ausgewaehlten Wert einer Combo-Box und gibt diesen zurueck
}
// comboBox: Alle 'option'-Eintraege der Combo-Box
// defValue: Default-Wert, falls nichts selektiert ist
// return Ausgewaehlter Wert
function getSelectionFromComboBox(comboBox, defValue = undefined, valType = 'String') {
    let selection;


Class.define(WarnDrawMessage, Object, {
    for (let i = 0; i < comboBox.length; i++) {
        '__ZATWARNVORLAUF'  : 1,
        const __ENTRY = comboBox[i];
        '__ZATMONATVORLAUF' : 6,
        'startMessage'      : function(currZAT) {
                                  this.setZat(currZAT);
                                  this.createMessage();
                              },
        'setZat'            : function(currZAT) {
                                  this.currZAT = currZAT;


                                  if (currZAT === undefined) {
        if (__ENTRY.outerHTML.match(/selected/)) {
                                      this.abrZAT = undefined;
            selection = __ENTRY.textContent;
                                      this.rest  = undefined;
        }
                                      this.anzahl = undefined;
    }
                                  } else {
                                      this.configureZat();
                                  }
                              },
        'setOptionHome'    : function() {
                                  this.warnOption = this.hasHome();
                              },
        'setOptionLegende'  : function() {
                                  this.warnOption = this.hasLegende();
                              },
        'configureZat'      : function() {
                                  const __ZIEHANZAHL = getOptValue(this.optSet.ziehAnz, []);
                                  const __INDEX = parseInt(this.currZAT / 6);


                                  this.abrZAT = (__INDEX + 1) * 6;
    return this[valType](getValue(selection, defValue));
                                  this.rest  = 5 - (this.currZAT % 6);
}
                                  this.anzahl = __ZIEHANZAHL[__INDEX];
                              },
        'getTextMessage'    : function() {
                                  return "ZAT " + this.abrZAT + ' ' + ((this.anzahl > 1) ? "m\xFCssen " + this.anzahl : "muss einer") +
                                        " deiner Jugendspieler in das Profiteam \xFCbernommen werden, ansonsten verschwinde" + ((this.anzahl > 1) ? "n sie" : "t er") + '!';
                              },
        'createMessage'    : function() {
                                  this.label = undefined;
                                  this.when = undefined;
                                  this.text = undefined;


                                  if (this.hasHome() || this.hasLegende() || this.hasDialog()) {
// Liest die Talentklasse ("wenig", "normal", "hoch") aus der Spalte einer Zeile der Tabelle aus
                                      if (this.anzahl > 0) {
// cells: Die Zellen einer Zeile
                                          this.text = this.getTextMessage();
// colIdxStr: Spaltenindex der gesuchten Werte
// return Talent als Zahl (-1=wenig, 0=normal, +1=hoch)
function getTalentFromHTML(cells, colIdxTal) {
    const __TEXT = getStringFromHTML(cells, colIdxTal);


                                          if (this.warnMonth && (this.rest > 0)) {
    return parseInt((__TEXT === "wenig") ? -1 : (__TEXT === "hoch") ? +1 : 0, 10);
                                              this.label = "Warnung";
}
                                              this.when = "Bis zur n\xE4chsten Abrechnung am ";
                                          } else if ((this.warn || this.warnMonth) && (this.rest === 0)) {
                                              this.label = "LETZTE WARNUNG VOR DER ABRECHNUNG";
                                              this.when = "Bis zum n\xE4chsten ";
                                          }
                                      }
                                  }
                              },
        'hasMessage'        : function() {
                                  return !! this.when;
                              },
        'hasHome'          : function() {
                                  return this.warnHome;
                              },
        'hasLegende'        : function() {
                                  return this.warnLegende;
                              },
        'hasOption'        : function() {
                                  return this.warnOption;
                              },
        'hasDialog'        : function() {
                                  return this.warnDialog;
                              },
        'showMessage'      : function(anchor, tag, appendFind = true) {  // appendFind: true = append, false = insertBefore, "..." search string = insert at find position
                                  let ret = (anchor || { }).innerHTML;


                                  if (this.hasMessage()) {
// Liest die Einzelskills aus der Spalte einer Zeile der Tabelle aus
                                      if (this.hasOption()) {
// cells: Die Zellen einer Zeile
                                          const __OLDHTML = ret;
// colIdx: Liste von Spaltenindices der gesuchten Werte mit den Eintraegen
                                          const __HTML = this.getHTML(tag);
// 'Einz' (erste Spalte) und 'Zus' (Spalte hinter dem letzten Eintrag)
// return Skills als Array von Zahlen
function getSkillsFromHTML(cells, colIdx) {
    const __RESULT = [];


                                          if ((typeof appendFind) === 'string') {
    for (let i = colIdx.Einz; i < colIdx.Zus; i++) {
                                              const __INDEX = __OLDHTML.indexOf(appendFind);
        __RESULT[i - colIdx.Einz] = getIntFromHTML(cells, i);
                                              const __POS = (~ __INDEX) ? __INDEX : __OLDHTML.length;
    }


                                              ret = __OLDHTML.substring(0, __POS) + __HTML + __OLDHTML.substring(__POS);
    return __RESULT;
                                          } else if (appendFind) {
}
                                              ret = __OLDHTML + __HTML;
                                          } else {
                                              ret = __HTML + __OLDHTML;
                                          }


                                          anchor.innerHTML = ret;
// Liest aus, ob der Spieler Torwart oder Feldspieler ist
                                      }
// cells: Die Zellen einer Zeile
                                  }
// colIdxClass: Spaltenindex einer fuer TOR eingefaerbten Zelle
// return Angabe, der Spieler Torwart oder Feldspieler ist
function isGoalieFromHTML(cells, colIdxClass) {
    return (cells[colIdxClass].className === 'TOR');
}


                                  return ret;
// Liest einen String aus der Spalte einer Zeile der Tabelle aus, nachdem dieser konvertiert wurde
                              },
// cells: Die Zellen einer Zeile
        'showDialog'        : function(dlgFun) {
// colIdxStr: Spaltenindex der gesuchten Werte
                                  if (this.hasMessage()) {
// convertFun: Funktion, die den Wert konvertiert
                                      if (this.hasDialog() && (this.rest === 0)) {
// return Spalteneintrag als String ("" fuer "nicht gefunden")
                                          dlgFun(this.label, this.when + this.text);
function convertStringFromHTML(cells, colIdxStr, convertFun = sameValue) {
                                      }
    const __CELL = getValue(cells[colIdxStr], { });
                                  }
     const __TEXT = convertFun(__CELL.textContent, __CELL, colIdxStr, 0);
                              },
        'tagText'          : function(tag, text) {
                                  return ((tag !== undefined) ? this.getOpeningTag(tag) + text + this.getClosingTag(tag) : text);
                              },
        'tagParagraph'      : function(tag, text) {
                                  return this.tagText(tag, this.tagText(this.getSubTag(tag), text));
                              },
        'getSubTag'        : function(tag) {
                                  return ((tag === 'tr') ? 'td' + this.getColorTD() : ((tag === 'p') ? this.getColorTag() : undefined));
                              },
        'getSuperTag'      : function(tag) {
                                  return ((tag === 'p') ? 'div' : undefined);
                              },
        'getOpeningTag'    : function(tag) {
                                  return '<' + tag + '>';
                              },
        'getClosingTag'     : function(tag) {
                                  const __INDEX1 = (tag ? tag.indexOf(' ') : -1);
                                  const __INDEX2 = (tag ? tag.indexOf('=') : -1);
                                  const __INDEX = ((~ __INDEX1) && (~ __INDEX2)) ? Math.min(__INDEX1, __INDEX2) : Math.max(__INDEX1, __INDEX2);
                                  const __TAGNAME = ((~ __INDEX) ? tag.substring(0, __INDEX) : tag);


                                  return "</" + __TAGNAME + '>';
     if (__TEXT !== undefined) {
                              },
         __CELL.innerHTML = __TEXT;
        'getLink'          : function() {
     }
                                  return './ju.php';
                              },
        'getTopHTML'        : function(tag) {
                                  return this.tagParagraph(tag, "&nbsp;");
                              },
        'getBottomHTML'     : function(tag) {
                                  return this.tagParagraph(tag, "&nbsp;");
                              },
        'getColorTag'      : function() {
                                  return "color='red'";  // rot
                              },
        'getColorTD'        : function() {
                                  return " class='STU'";  // rot
                              },
         'getHTML'          : function(tag = 'p') {
                                  return this.tagParagraph((this.out.supertag ? this.getSuperTag(tag) : undefined), (this.out.top ? this.getTopHTML(tag) : "") +
                                        this.tagParagraph(tag, this.tagText('b', this.tagText((this.out.link ? "a href='" + this.getLink() + "'" : undefined),
                                        (this.out.label ? this.label + ": " : "") + this.when + this.text))) + (this.out.bottom ? this.getBottomHTML(tag) : ""));
                              }
     });


Object.defineProperty(WarnDrawMessage.prototype, 'innerHTML', {
    return getValue(__TEXT.toString(), "");
        get : function() {
}
                  return this.getHTML('p');
              }
    });


// Klasse WarnDrawMessageAufstieg *****************************************************************
// Liest ein Array von String-Werten aus den Spalten ab einer Zeile der Tabelle aus, nachdem diese konvertiert wurden
// cells: Die Zellen einer Zeile
// colIdxArr: Erster Spaltenindex der gesuchten Werte
// arrOrLength: Entweder ein Datenarray zum Fuellen oder die Anzahl der zu lesenden Werte
// convertFun: Funktion, die die Werte konvertiert
// return Array mit Spalteneintraegen als String ("" fuer "nicht gefunden")
function convertArrayFromHTML(cells, colIdxArr, arrOrLength = 1, convertFun = sameValue) {
    const __ARR = ((typeof arrOrSize === 'number') ? { } : arrOrLength);
    const __LENGTH = getValue(__ARR.length, arrOrLength);
    const __RET = [];


function WarnDrawMessageAufstieg(optSet, currZAT) {
    for (let index = 0, colIdx = colIdxArr; index < __LENGTH; index++, colIdx++) {
    'use strict';
        const __CELL = getValue(cells[colIdx], { });
        const __TEXT = convertFun(getValue(__ARR[index], __CELL.textContent), __CELL, colIdx, index);


    WarnDrawMessage.call(this, optSet, currZAT);
        if (__TEXT !== undefined) {
            __CELL.innerHTML = __TEXT;
        }


    this.out.top = false; // kein Vorschub vor der Zeile
        __RET.push(getValue(__TEXT, "").toString());
    }


     this.warn = (this.warn && this.warnAufstieg); // kann man ausschalten
     return __RET;
    this.startMessage(currZAT);  // 2. Aufruf (zur Korrektur)
}
}


Class.define(WarnDrawMessageAufstieg, WarnDrawMessage, {
// Konvertiert den Aufwertungstext einer Zelle auf der Jugend-Teamuebersicht
        'configureZat'      : function() {
// value: Der Inhalt dieser Zeile ("+1 SKI +1 OPT" bzw. "+2 SKI)
                                  const __ZIEHANZAUFSTIEG = getOptValue(this.optSet.ziehAnzAufstieg, 0);
// cell: Zelle, in der der Text stand (optional)
                                  const __INDEX = parseInt(this.currZAT / 6);
// return Der konvertierte String ("SKI OPT" bzw. "SKI SKI")
function convertAufwertung(value, cell = undefined) {
    if (value !== undefined) {
        value = value.replace(/\+2 (\w+)/, "$1 $1").replace(/\+1 /g, "");


                                  this.abrZAT = (__INDEX + 1) * 6;
        if (cell) {
                                  this.rest  = 5 - (this.currZAT % 6);
            if (cell.className === 'TOR') {
                                  this.anzahl = ((this.currZAT + this.__ZATMONATVORLAUF > 72 - this.__ZATWARNVORLAUF) ? __ZIEHANZAUFSTIEG : 0);
                value = convertGoalieSkill(value);
            }


                                  this.warnDialog = false;    // kein Dialog fuer Aufstiegswarnung
            cell.align = 'left';
                                  this.warnMonth = this.warn;  // nur im letzten Monat der Saison!
         }
                              },
     }
        'getTextMessage'    : function() {
                                  return "ZAT " + this.abrZAT + " ist im Falle eines Aufstiegs f\xFCr " + ((this.anzahl > 1) ? "" + this.anzahl : "einen") +
                                        " deiner Jugendspieler m\xF6glicherweise die letzte Chance, " + ((this.anzahl > 1) ? " diese noch vor ihrem" : "ihn noch vor seinem") +
                                        " Geburtstag in der n\xE4chsten Saison in das Profiteam zu \xFCbernehmen!";
                              },
        'getColorTag'       : function() {
                                  return "color='magenta'"; // magenta
                              },
         'getColorTD'        : function() {
                                  return " class='OMI'";  // magenta
                              }
     });


// Ende Hilfs-Klassen *****************************************************************
    return value;
}


// Funktionen fuer die HTML-Seite *******************************************************
// Formatiert eine Zelle um (mit einfachen Parametern)
 
// cell: Zu formatierende Zelle
// Liest eine Zahl aus der Spalte einer Zeile der Tabelle aus (z.B. Alter, Geburtsdatum)
// bold: Inhalt fett darstellen (true = ja, false = nein)
// cells: Die Zellen einer Zeile
// color: Falls angegeben, die Schriftfarbe
// colIdxInt: Spaltenindex der gesuchten Werte
// bgColor: Falls angegeben, die Hintergrundfarbe
// return Spalteneintrag als Zahl (-1 fuer "keine Zahl", undefined fuer "nicht gefunden")
// return Die formatierte Zelle
function getIntFromHTML(cells, colIdxInt) {
function formatCell(cell, bold = true, color = undefined, bgColor = undefined) {
    const __CELL = getValue(cells[colIdxInt], { });
     if (cell) {
    const __TEXT = __CELL.textContent;
         if (bold) {
 
             cell.style.fontWeight = 'bold';
     if (__TEXT !== undefined) {
        }
         try {
        if (color) {
             const __VALUE = parseInt(__TEXT, 10);
            cell.style.color = color;
 
        }
            if (! isNaN(__VALUE)) {
         if (bgColor) {
                return __VALUE;
            cell.style.backgroundColor = bgColor;
            }
         }
         } catch (ex) { }
 
         return -1;
     }
     }


     return undefined;
     return cell;
}
}


// Liest eine Dezimalzahl aus der Spalte einer Zeile der Tabelle aus
// Konvertiert die allgemeinen Skills in die eines Torwarts
// cells: Die Zellen einer Zeile
// value: Ein Text, der die Skillnamen enthaelt
// colIdxInt: Spaltenindex der gesuchten Werte
// return Der konvertierte String mit Aenderungen (z.B. "FAN" statt "KOB") oder unveraendert
// return Spalteneintrag als Dezimalzahl (undefined fuer "keine Zahl" oder "nicht gefunden")
function convertGoalieSkill(value) {
function getFloatFromHTML(cells, colIdxFloat) {
     if (value !== undefined) {
    const __CELL = getValue(cells[colIdxFloat], { });
         value = value.replace(/\w+/g, getGoalieSkill);
    const __TEXT = __CELL.textContent;
 
     if (__TEXT !== undefined) {
         try {
            return parseFloat(__TEXT);
        } catch (ex) { }
     }
     }


     return undefined;
     return value;
}
}


// Liest einen String aus der Spalte einer Zeile der Tabelle aus
// Konvertiert einen Aufwertungstext fuer einen Skillnamen in den fuer einen Torwart
// cells: Die Zellen einer Zeile
// name: Allgemeiner Skillname (abgeleitet von den Feldspielern)
// colIdxStr: Spaltenindex der gesuchten Werte
// return Der konvertierte String (z.B. "FAN" statt "KOB") oder unveraendert
// return Spalteneintrag als String ("" fuer "nicht gefunden")
function getGoalieSkill(name) {
function getStringFromHTML(cells, colIdxStr) {
     const __GOALIESKILLS = {
     const __CELL = getValue(cells[colIdxStr], { });
                              'SCH' : 'ABS',
    const __TEXT = __CELL.textContent;
                              'BAK' : 'STS',
                              'KOB' : 'FAN',
                              'ZWK' : 'STB',
                              'DEC' : 'SPL',
                              'GES' : 'REF'
                          };


     return getValue(__TEXT.toString(), "");
     return getValue(__GOALIESKILLS[name], name);
}
}


// Liest ein erstes Element aus der Spalte einer Zeile der Tabelle aus
// Liest die Aufwertungen eines Spielers aus und konvertiert je nachdem, ob der Spieler Torwart oder Feldspieler ist
// cells: Die Zellen einer Zeile
// cells: Die Zellen einer Zeile
// colIdxStr: Spaltenindex der gesuchten Werte
// colIdxAuf: Spaltenindex der gesuchten Aufwertungen
// return Spalteneintrag als Element (null fuer "nicht gefunden")
// shortForm: true = abgekuerzt, false = Originalform
function getElementFromHTML(cells, colIdxStr) {
// return Konvertierte Aufwertungen (kurze oder lange Form, aber in jedem Fall fuer Torwart konvertiert)
     const __CELL = getValue(cells[colIdxStr], { });
function getAufwertFromHTML(cells, colIdxAuf, shortForm = true) {
     const __ISGOALIE = isGoalieFromHTML(cells, colIdxAuf);


     return __CELL.firstElementChild;
     return convertStringFromHTML(cells, colIdxAuf, (shortForm ? convertAufwertung : __ISGOALIE ? convertGoalieSkill : undefined));
}
}


// Liest die Talentklasse ("wenig", "normal", "hoch") aus der Spalte einer Zeile der Tabelle aus
// Identitaetsfunktion. Konvertiert nichts, sondern liefert einfach den Wert zurueck
// cells: Die Zellen einer Zeile
// value: Der uebergebene Wert
// colIdxStr: Spaltenindex der gesuchten Werte
// return Derselbe Wert
// return Talent als Zahl (-1=wenig, 0=normal, +1=hoch)
function sameValue(value) {
function getTalentFromHTML(cells, colIdxTal) {
     return value;
    const __TEXT = getStringFromHTML(cells, colIdxTal);
 
     return parseInt((__TEXT === 'wenig') ? -1 : (__TEXT === 'hoch') ? +1 : 0, 10);
}
}


// Liest die Einzelskills aus der Spalte einer Zeile der Tabelle aus
// Liefert den ganzzeiligen Anteil einer Zahl zurueck, indem alles hinter einem Punkt abgeschnitten wird
// cells: Die Zellen einer Zeile
// value: Eine uebergebene Dezimalzahl
// colIdx: Liste von Spaltenindices der gesuchten Werte mit den Eintraegen
// return Der ganzzeilige Anteil dieser Zahl
// 'Einz' (erste Spalte) und 'Zus' (Spalte hinter dem letzten Eintrag)
function floorValue(value, dot = '.') {
// return Skills als Array von Zahlen
    if ((value === 0) || (value && isFinite(value))) {
function getSkillsFromHTML(cells, colIdx) {
        const __VALUE = value.toString();
    const __RESULT = [];
        const __INDEXDOT = (__VALUE ? __VALUE.indexOf(dot) : -1);


    for (let i = colIdx.Einz; i < colIdx.Zus; i++) {
        return Number((~ __INDEXDOT) ? __VALUE.substring(0, __INDEXDOT) : __VALUE);
         __RESULT[i - colIdx.Einz] = getIntFromHTML(cells, i);
    } else {
         return value;
     }
     }
    return __RESULT;
}
}


// Liest aus, ob der Spieler Torwart oder Feldspieler ist
// Liefert einen rechtsbuendigen Text zurueck, der links aufgefuellt wird
// cells: Die Zellen einer Zeile
// value: Ein uebergebener Wert
// colIdxClass: Spaltenindex einer fuer TOR eingefaerbten Zelle
// size: Zielbreite (clipping fuer < 0: Abschneiden, falls zu lang)
// return Angabe, der Spieler Torwart oder Feldspieler ist
// char: Zeichen zum Auffuellen
function isGoalieFromHTML(cells, colIdxClass) {
// return Ein String, der mindestens |size| lang ist (oder genau, falls size < 0, also clipping)
     return (cells[colIdxClass].className === 'TOR');
function padLeft(value, size = 4, char = ' ') {
}
     const __SIZE = Math.abs(size);
    const __CLIP = (size < 0);
    const __VALUE = (value ? value.toString() : "");
    let i = __VALUE.length;
    let str = "";
 
    while (i < __SIZE) {
        str += char;
        i += char.length;
    }
    str = ((i > __SIZE) ? str.slice(0, __SIZE - __VALUE.length - 1) : str) + __VALUE;


// Liest einen String aus der Spalte einer Zeile der Tabelle aus, nachdem dieser konvertiert wurde
    return (__CLIP ? str.slice(size) : str);
// cells: Die Zellen einer Zeile
}
// colIdxStr: Spaltenindex der gesuchten Werte
// convertFun: Funktion, die den Wert konvertiert
// return Spalteneintrag als String ("" fuer "nicht gefunden")
function convertStringFromHTML(cells, colIdxStr, convertFun = sameValue) {
    const __CELL = getValue(cells[colIdxStr], { });
    const __TEXT = convertFun(__CELL.textContent, __CELL, colIdxStr, 0);


     if (__TEXT !== undefined) {
// Liefert eine rechtsbuendigen Zahl zurueck, der links (mit Nullen) aufgefuellt wird
         __CELL.innerHTML = __TEXT;
// value: Eine uebergebene Zahl
// size: Zielbreite (Default: 2)
// char: Zeichen zum Auffuellen (Default: '0')
// forceClip: Abschneiden erzwingen, falls zu lang?
// return Eine Zahl als String, der mindestens 'size' lang ist (oder genau, falls size < 0, also clipping)
function padNumber(value, size = 2, char = '0') {
     if ((value === 0) || (value && isFinite(value))) {
         return padLeft(value, size, char);
    } else {
        return value;
     }
     }
    return getValue(__TEXT.toString(), "");
}
}


// Liest ein Array von String-Werten aus den Spalten ab einer Zeile der Tabelle aus, nachdem diese konvertiert wurden
// Hilfsfunktionen **********************************************************************
// cells: Die Zellen einer Zeile
// colIdxArr: Erster Spaltenindex der gesuchten Werte
// arrOrLength: Entweder ein Datenarray zum Fuellen oder die Anzahl der zu lesenden Werte
// convertFun: Funktion, die die Werte konvertiert
// return Array mit Spalteneintraegen als String ("" fuer "nicht gefunden")
function convertArrayFromHTML(cells, colIdxArr, arrOrLength = 1, convertFun = sameValue) {
    const __ARR = ((typeof arrOrLength === 'number') ? { } : arrOrLength);
    const __LENGTH = getValue(__ARR.length, arrOrLength);
    const __RET = [];


    for (let index = 0, colIdx = colIdxArr; index < __LENGTH; index++, colIdx++) {
// Sortiert das Positionsfeld per BubbleSort
        const __CELL = getValue(cells[colIdx], { });
function sortPositionArray(array) {
        const __TEXT = convertFun(getValue(__ARR[index], __CELL.textContent), __CELL, colIdx, index);
    const __TEMP = [];
    let transposed = true;
    // TOR soll immer die letzte Position im Feld sein, deshalb - 1
    let length = array.length - 1;


         if (__TEXT !== undefined) {
    while (transposed && (length > 1)) {
             __CELL.innerHTML = __TEXT;
         transposed = false;
        for (let i = 0; i < length - 1; i++) {
             // Vergleich Opti-Werte:
            if (array[i][1] < array[i + 1][1]) {
                // vertauschen
                __TEMP[0] = array[i][0];
                __TEMP[1] = array[i][1];
                array[i][0] = array[i + 1][0];
                array[i][1] = array[i + 1][1];
                array[i + 1][0] = __TEMP[0];
                array[i + 1][1] = __TEMP[1];
                transposed = true;
            }
         }
         }
 
         length--;
         __RET.push(getValue(__TEXT, "").toString());
     }
     }
    return __RET;
}
}


// Konvertiert den Aufwertungstext einer Zelle auf der Jugend-Teamuebersicht
// Fuegt in die uebergebene Zahl Tausender-Trennpunkte ein
// value: Der Inhalt dieser Zeile ("+1 SKI +1 OPT" bzw. "+2 SKI)
// Wandelt einen etwaig vorhandenen Dezimalpunkt in ein Komma um
// cell: Zelle, in der der Text stand (optional)
function getNumberString(numberString) {
// return Der konvertierte String ("SKI OPT" bzw. "SKI SKI")
     if (numberString.lastIndexOf(".") !== -1) {
function convertAufwertung(value, cell = undefined) {
         // Zahl enthaelt Dezimalpunkt
     if (value !== undefined) {
        const __VORKOMMA = numberString.substring(0, numberString.lastIndexOf("."));
         value = value.replace(/\+2 (\w+)/, "$1 $1").replace(/\+1 /g, "");
        const __NACHKOMMA = numberString.substring(numberString.lastIndexOf(".") + 1, numberString.length);


         if (cell) {
         return getNumberString(__VORKOMMA) + "," + __NACHKOMMA;
             if (cell.className === 'TOR') {
    } else {
                 value = convertGoalieSkill(value);
        // Kein Dezimalpunkt, fuege Tausender-Trennpunkte ein:
        // String umdrehen, nach jedem dritten Zeichen Punkt einfuegen, dann wieder umdrehen:
        const __TEMP = reverseString(numberString);
        let result = "";
 
        for (let i = 0; i < __TEMP.length; i++) {
             if ((i > 0) && (i % 3 === 0)) {
                 result += ".";
             }
             }
            result += __TEMP.substr(i, 1);
        }
        return reverseString(result);
    }
}


            cell.align = 'left';
// Dreht den uebergebenen String um
         }
function reverseString(string) {
    let result = "";
 
    for (let i = string.length - 1; i >= 0; i--) {
         result += string.substr(i, 1);
     }
     }


     return value;
     return result;
}
}


// Konvertiert die allgemeinen Skills in die eines Torwarts
// Schaut nach, ob der uebergebene Index zu einem trainierbaren Skill gehoert
// value: Ein Text, der die Skillnamen enthaelt
// Die Indizes gehen von 0 (SCH) bis 16 (EIN)
// return Der konvertierte String mit Aenderungen (z.B. "FAN" statt "KOB") oder unveraendert
function isTrainableSkill(idx) {
function convertGoalieSkill(value) {
     const __TRAINABLESKILLS = getIdxTrainableSkills();
     if (value !== undefined) {
    const __IDX = parseInt(idx, 10);
         value = value.replace(/\w+/g, getGoalieSkill);
    let result = false;
 
    for (let idxTrainable of __TRAINABLESKILLS) {
         if (__IDX === idxTrainable) {
            result = true;
            break;
        }
     }
     }


     return value;
     return result;
}
}


// Konvertiert einen Aufwertungstext fuer einen Skillnamen in den fuer einen Torwart
// Gibt alle Skill-Namen zurueck
// name: Allgemeiner Skillname (abgeleitet von den Feldspielern)
function getAllSkillNames(isGoalie = false) {
// return Der konvertierte String (z.B. "FAN" statt "KOB") oder unveraendert
     if (isGoalie) {
function getGoalieSkill(name) {
        return [ 'ABS', 'STS', 'FAN', 'STB', 'SPL', 'REF', 'FUQ', 'ERF', 'AGG', 'PAS', 'AUS', 'UEB', 'WID', 'SEL', 'DIS', 'ZUV', 'EIN' ];
     const __GOALIESKILLS = {
    } else {
                              'SCH' : 'ABS',
        return [ 'SCH', 'BAK', 'KOB', 'ZWK', 'DEC', 'GES', 'FUQ', 'ERF', 'AGG', 'PAS', 'AUS', 'UEB', 'WID', 'SEL', 'DIS', 'ZUV', 'EIN' ];
                              'BAK' : 'STS',
    }
                              'KOB' : 'FAN',
                              'ZWK' : 'STB',
                              'DEC' : 'SPL',
                              'GES' : 'REF'
                          };
 
    return getValue(__GOALIESKILLS[name], name);
}
}


// Liest die Aufwertungen eines Spielers aus und konvertiert je nachdem, ob der Spieler Torwart oder Feldspieler ist
// Gibt den Skill-Namen zu einem Index zurueck
// cells: Die Zellen einer Zeile
function getSkillName(idx, isGoalie = false) {
// colIdxAuf: Spaltenindex der gesuchten Aufwertungen
     const __ALLNAMES = getAllSkillNames(isGoalie);
// shortForm: true = abgekuerzt, false = Originalform
// return Konvertierte Aufwertungen (kurze oder lange Form, aber in jedem Fall fuer Torwart konvertiert)
function getAufwertFromHTML(cells, colIdxAuf, shortForm = true) {
     const __ISGOALIE = isGoalieFromHTML(cells, colIdxAuf);


     return convertStringFromHTML(cells, colIdxAuf, (shortForm ? convertAufwertung : __ISGOALIE ? convertGoalieSkill : undefined));
     return __ALLNAMES[idx];
}
}


// Identitaetsfunktion. Konvertiert nichts, sondern liefert einfach den Wert zurueck
// Gibt den Skill-Namen zu einem Index-Array zurueck
// value: Der uebergebene Wert
function getSkillNameArray(idxArr, isGoalie = false) {
// return Derselbe Wert
    return (idxArr ? idxArr.map(function(item) {
function sameValue(value) {
                                    return getSkillName(item, isGoalie);
    return value;
                                }) : idxArr);
}
}


// Existenzfunktion. Liefert zurueck, ob ein Wert belegt ist
// Gibt die Indizes aller Skills zurueck
// value: Der uebergebene Wert
function getIdxAllSkills() {
// return Angabe ob Wert belegt ist
     return [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ];
function existValue(value) {
     return !! value;
}
}


// Liefert den ganzzeiligen Anteil einer Zahl zurueck, indem alles hinter einem Punkt abgeschnitten wird
// Gibt die Indizes der trainierbaren Skills zurueck
// value: Eine uebergebene Dezimalzahl
function getIdxTrainableSkills() {
// return Der ganzzeilige Anteil dieser Zahl
     return [ 0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 15 ];
function floorValue(value, dot = '.') {
}
     if ((value === 0) || (value && isFinite(value))) {
        const __VALUE = value.toString();
        const __INDEXDOT = (__VALUE ? __VALUE.indexOf(dot) : -1);


        return Number((~ __INDEXDOT) ? __VALUE.substring(0, __INDEXDOT) : __VALUE);
// Gibt die Indizes der Fixskills zurueck
     } else {
function getIdxFixSkills() {
        return value;
     return [ 6, 7, 12, 13, 14, 16 ];
    }
}
}


// Liefert einen rechtsbuendigen Text zurueck, der links aufgefuellt wird
// Gibt die Indizes der Primaerskills zurueck
// value: Ein uebergebener Wert
function getIdxPriSkills(pos) {
// size: Zielbreite (clipping fuer < 0: Abschneiden, falls zu lang)
    switch (pos) {
// char: Zeichen zum Auffuellen
        case 'TOR' : return [ 2, 3, 4, 5 ];
// return Ein String, der mindestens |size| lang ist (oder genau, falls size < 0, also clipping)
        case 'ABW' : return [ 2, 3, 4, 15 ];
function padLeft(value, size = 4, char = ' ') {
        case 'DMI' : return [ 1, 4, 9, 11 ];
    const __SIZE = Math.abs(size);
        case 'MIT' : return [ 1, 3, 9, 11 ];
    const __CLIP = (size < 0);
        case 'OMI' : return [ 1, 5, 9, 11 ];
    const __VALUE = (value ? value.toString() : "");
         case 'STU' : return [ 0, 2, 3, 5 ];
    let i = __VALUE.length;
         default :    return [];
    let str = "";
 
    while (i < __SIZE) {
         str += char;
         i += char.length;
     }
     }
    str = ((i > __SIZE) ? str.slice(0, __SIZE - __VALUE.length - 1) : str) + __VALUE;
    return (__CLIP ? str.slice(size) : str);
}
}


// Liefert eine rechtsbuendigen Zahl zurueck, der links (mit Nullen) aufgefuellt wird
// Gibt die Indizes der (trainierbaren) Sekundaerskills zurueck
// value: Eine uebergebene Zahl
function getIdxSecSkills(pos) {
// size: Zielbreite (Default: 2)
    switch (pos) {
// char: Zeichen zum Auffuellen (Default: '0')
        case 'TOR' : return [ 0, 1, 8, 9, 10, 11, 15 ];
// forceClip: Abschneiden erzwingen, falls zu lang?
        case 'ABW' : return [ 0, 1, 5, 8, 9, 10, 11 ];
// return Eine Zahl als String, der mindestens 'size' lang ist (oder genau, falls size < 0, also clipping)
        case 'DMI' : return [ 0, 2, 3, 5, 8, 10, 15 ];
function padNumber(value, size = 2, char = '0') {
        case 'MIT' : return [ 0, 2, 4, 5, 8, 10, 15 ];
     if ((value === 0) || (value && isFinite(value))) {
        case 'OMI' : return [ 0, 2, 3, 4, 8, 10, 15 ];
         return padLeft(value, size, char);
        case 'STU' : return [ 1, 4, 8, 9, 10, 11, 15 ];
    } else {
        default :    return [];
         return value;
    }
}
 
// Gibt die zur Position gehoerige Farbe zurueck
function getColor(pos) {
     switch (pos) {
         case 'TOR' : return "#FFFF00";
        case 'ABW' : return "#00FF00";
        case 'DMI' : return "#3366FF";
        case 'MIT' : return "#66FFFF";
        case 'OMI' : return "#FF66FF";
        case 'STU' : return "#FF0000";
        case 'LEI' : return "#FFFFFF";
        case "" :    return "#111166";  // osBlau
         default :    return "";
     }
     }
}
}


// Hilfsfunktionen **********************************************************************
// ==================== Ende Abschnitt genereller Code zur Anzeige der Jugend ====================


// Sortiert das Positionsfeld per BubbleSort
// ==================== Abschnitt fuer interne IDs auf den Seiten ====================
function sortPositionArray(array) {
    const __TEMP = [];
    let transposed = true;
    // TOR soll immer die letzte Position im Feld sein, deshalb - 1
    let length = array.length - 1;


    while (transposed && (length > 1)) {
const __GAMETYPES = {   // "Blind FSS gesucht!"
         transposed = false;
         'unbekannt'  : -1,
         for (let i = 0; i < length - 1; i++) {
         'reserviert' :  0,
            // Vergleich Opti-Werte:
        'Frei'      : 0,
            if (array[i][1] < array[i + 1][1]) {
        'spielfrei'  :  0,
                // vertauschen
        'Friendly'  :  1,
                __TEMP[0] = array[i][0];
        'Liga'      :  2,
                __TEMP[1] = array[i][1];
        'LP'        :  3,
                array[i][0] = array[i + 1][0];
        'OSEQ'      :  4,
                array[i][1] = array[i + 1][1];
        'OSE'        :  5,
                array[i + 1][0] = __TEMP[0];
         'OSCQ'      :  6,
                array[i + 1][1] = __TEMP[1];
         'OSC'        :  7
                transposed = true;
     };
            }
         }
         length--;
     }
}


// Schaut nach, ob der uebergebene Index zu einem trainierbaren Skill gehoert
const __LIGANRN = {
// Die Indizes gehen von 0 (SCH) bis 16 (EIN)
        'unbekannt'  :  0,
function isTrainableSkill(idx) {
        '1. Liga'    :  1,
    const __TRAINABLESKILLS = getIdxTrainableSkills();
        '2. Liga A'  :  2,
    const __IDX = parseInt(idx, 10);
        '2. Liga B'  :  3,
     let result = false;
        '3. Liga A'  :  4,
        '3. Liga B'  :  5,
        '3. Liga C'  :  6,
        '3. Liga D'  :  7
     };


    for (let idxTrainable of __TRAINABLESKILLS) {
const __LANDNRN = {
         if (__IDX === idxTrainable) {
         'unbekannt'              :  0,
            result = true;
        'Albanien'              :  45,
            break;
        'Andorra'                :  95,
         }
         'Armenien'              :  83,
    }
        'Aserbaidschan'          : 104,
 
        'Belgien'                :  12,
    return result;
        'Bosnien-Herzegowina'    :  66,
}
        'Bulgarien'              :  42,
 
        'D\xE4nemark'            :  8,
// Gibt alle Skill-Namen zurueck
        'Deutschland'            :  6,
function getAllSkillNames(isGoalie = false) {
        'England'                :  1,
    if (isGoalie) {
        'Estland'                :  57,
         return [ 'ABS', 'STS', 'FAN', 'STB', 'SPL', 'REF', 'FUQ', 'ERF', 'AGG', 'PAS', 'AUS', 'UEB', 'WID', 'SEL', 'DIS', 'ZUV', 'EIN' ];
         'Far\xF6er'             :  68,
    } else {
        'Finnland'               :  40,
         return [ 'SCH', 'BAK', 'KOB', 'ZWK', 'DEC', 'GES', 'FUQ', 'ERF', 'AGG', 'PAS', 'AUS', 'UEB', 'WID', 'SEL', 'DIS', 'ZUV', 'EIN' ];
        'Frankreich'             :  32,
    }
        'Georgien'               :  49,
}
        'Griechenland'           :  30,
 
        'Irland'                 :  5,
// Gibt den Skill-Namen zu einem Index zurueck
        'Island'                 :  29,
function getSkillName(idx, isGoalie = false) {
        'Israel'                 :  23,
     const __ALLNAMES = getAllSkillNames(isGoalie);
        'Italien'               :  10,
 
        'Kasachstan'             : 105,
    return __ALLNAMES[idx];
        'Kroatien'               :  24,
}
        'Lettland'               :  97,
 
        'Liechtenstein'         :  92,
// Gibt den Skill-Namen zu einem Index-Array zurueck
        'Litauen'               :  72,
function getSkillNameArray(idxArr, isGoalie = false) {
        'Luxemburg'             :  93,
    return (idxArr ? idxArr.map(function(item) {
        'Malta'                 :  69,
                                    return getSkillName(item, isGoalie);
        'Mazedonien'             :  86,
                                }) : idxArr);
        '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 Indizes aller Skills zurueck
// Gibt die ID des Landes mit dem uebergebenen Namen zurueck.
function getIdxAllSkills() {
// land: Name des Landes
     return [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ];
// return OS2-ID des Landes, 0 fuer ungueltig
function getLandNr(land) {
     return getValue(__LANDNRN[land], __LANDNRN.unbekannt);
}
}


// Gibt die Indizes der trainierbaren Skills zurueck
// Gibt die ID der Liga mit dem uebergebenen Namen zurueck.
function getIdxTrainableSkills() {
// land: Name der Liga
     return [ 0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 15 ];
// return OS2-ID der Liga, 0 fuer ungueltig
function getLigaNr(liga) {
     return getValue(__LIGANRN[liga], __LIGANRN.unbekannt);
}
}


// Gibt die Indizes der Fixskills zurueck
// ==================== Abschnitt fuer sonstige Parameter ====================
function getIdxFixSkills() {
    return [ 6, 7, 12, 13, 14, 16 ];
}


// Gibt die Indizes der Primaerskills zurueck
const __TEAMSEARCHHAUPT = {  // Parameter zum Team "<b>Willkommen im Managerb&uuml;ro von TEAM</b><br>LIGA LAND<a href=..."
function getIdxPriSkills(pos) {
         'Zeile' : 0,
    switch (pos) {
         'Spalte' : 1,
         case 'TOR' : return [ 2, 3, 4, 5 ];
         'start' : " von ",
         case 'ABW' : return [ 2, 3, 4, 15 ];
         'middle' : "</b><br>",
         case 'DMI' : return [ 1, 4, 9, 11 ];
         'liga'   : ". Liga",
         case 'MIT' : return [ 1, 3, 9, 11 ];
         'land'   : ' ',
         case 'OMI' : return [ 1, 5, 9, 11 ];
         'end'    : "<a href="
         case 'STU' : return [ 0, 2, 3, 5 ];
     };
         default :   return [];
     }
}


// Gibt die Indizes der (trainierbaren) Sekundaerskills zurueck
const __TEAMSEARCHTEAM = {  // Parameter zum Team "<b>TEAM - LIGA <a href=...>LAND</a></b>"
function getIdxSecSkills(pos) {
         'Zeile' : 0,
    switch (pos) {
         'Spalte' : 0,
         case 'TOR' : return [ 0, 1, 8, 9, 10, 11, 15 ];
         'start' : "<b>",
         case 'ABW' : return [ 0, 1, 5, 8, 9, 10, 11 ];
         'middle' : " - ",
         case 'DMI' : return [ 0, 2, 3, 5, 8, 10, 15 ];
         'liga'   : ". Liga",
         case 'MIT' : return [ 0, 2, 4, 5, 8, 10, 15 ];
         'land'   : 'target="_blank">',
         case 'OMI' : return [ 0, 2, 3, 4, 8, 10, 15 ];
         'end'    : "</a></b>"
         case 'STU' : return [ 1, 4, 8, 9, 10, 11, 15 ];
     };
         default :   return [];
     }
}


// Gibt die zur Position gehoerige Farbe zurueck
// Ermittelt, wie das eigene Team heisst und aus welchem Land bzw. Liga es kommt (zur Unterscheidung von Erst- und Zweitteam)
function getColor(pos) {
// cell: Tabellenzelle mit den Parametern zum Team "startTEAMmiddleLIGA...landLANDend", LIGA = "#liga[ (A|B|C|D)]"
    switch (pos) {
// teamSeach: Muster fuer die Suche, die Eintraege fuer 'start', 'middle', 'liga', 'land' und 'end' enthaelt
        case 'TOR' : return "#FFFF00";
// return Im Beispiel { 'Team' : "TEAM", 'Liga' : "LIGA", 'Land' : "LAND", 'LdNr' : LAND-NUMMER, 'LgNr' : LIGA-NUMMER },
        case 'ABW' : return "#00FF00";
//        z.B. { 'Team' : "Choromonets Odessa", 'Liga' : "1. Liga", 'Land' : "Ukraine", 'LdNr' : 20, 'LgNr' : 1 }
        case 'DMI' : return "#3366FF";
function getTeamParamsFromTable(table, teamSearch = undefined) {
        case 'MIT' : return "#66FFFF";
    const __TEAMSEARCH  = getValue(teamSearch, __TEAMSEARCHHAUPT);
        case 'OMI' : return "#FF66FF";
    const __TEAMCELLROW  = getValue(__TEAMSEARCH.Zeile, 0);
        case 'STU' : return "#FF0000";
    const __TEAMCELLCOL  = getValue(__TEAMSEARCH.Spalte, 0);
        case 'LEI' : return "#FFFFFF";
    const __TEAMCELLSTR  = (table === undefined) ? "" : table.rows[__TEAMCELLROW].cells[__TEAMCELLCOL].innerHTML;
        case "" :   return "#111166"// osBlau
    const __SEARCHSTART = __TEAMSEARCH.start;
        default :   return "";
    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);


// ==================== Ende Abschnitt genereller Code zur Anzeige der Jugend ====================
    let teamParams = __TEAMCELLSTR.substring(__INDEXSTART + __SEARCHSTART.length, __INDEXEND);
    const __INDEXLIGA = teamParams.indexOf(__SEARCHLIGA);
    const __INDEXMIDDLE = teamParams.indexOf(__SEARCHMIDDLE);


// ==================== Abschnitt fuer interne IDs auf den Seiten ====================
    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);


const __GAMETYPENRN = {    // "Blind FSS gesucht!"
    if (land !== undefined) {
        'unbekannt'  : -1,
        if (land.charAt(2) === ' ') {    // Land z.B. hinter "2. Liga A " statt "1. Liga "
         'reserviert' :  0,
            land = land.substr(2);
         'Frei'      :  0,
         }
        'spielfrei'  :  0,
         if (liga !== undefined) {
         'Friendly'  :  1,
            liga = liga.substring(0, liga.length - land.length);
         'Liga'      :  2,
         }
         'LP'        :  3,
         const __INDEXLAND = land.indexOf(__SEARCHLAND);
        'OSEQ'      :  4,
         if (~ __INDEXLAND) {
         'OSE'        :  5,
            land = land.substr(__INDEXLAND + __SEARCHLAND.length);
        'OSCQ'      :  6,
         }
        'OSC'        :  7,
     }
        'Supercup'  : 10
     };


const __GAMETYPEALIASES = {
    const __TEAM = new Team(__TEAMNAME, land, liga);
        'unbekannt'  :  "unbekannt",
        'reserviert' :  undefined,
        'Frei'      :  undefined,
        'spielfrei'  :  "",
        'Friendly'  :  "FSS",
        'Liga'      :  undefined,
        'LP'        :  "Pokal",
        'OSEQ'      :  undefined,
        'OSE'        :  undefined,
        'OSCQ'      :  undefined,
        'OSC'        :  undefined,
        'Supercup'  : "Super"
    };
const __GAMETYPES = reverseMapping(__GAMETYPENRN);


const __LIGANRN = {
     return __TEAM;
        '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 __LIGATYPES = reverseMapping(__LIGANRN);


const __LANDNRN = {
// Verarbeitet die URL der Seite und ermittelt die Nummer der gewuenschten Unterseite
        'unbekannt'              :   0,
// url: Adresse der Seite
        'Albanien'              : 45,
// leafs: Liste von Filenamen mit der Default-Seitennummer (falls Query-Parameter nicht gefunden)
        'Andorra'                :  95,
// item: Query-Parameter, der die Nummer der Unterseite angibt
        'Armenien'              :  83,
// return Parameter aus der URL der Seite als Nummer
        'Aserbaidschan'          : 104,
function getPageIdFromURL(url, leafs, item = "page") {
        'Belgien'                :  12,
    const __URI = new URI(url);
        'Bosnien-Herzegowina'    :  66,
    const __LEAF = __URI.getLeaf();
        'Bulgarien'              :  42,
 
        'D\xE4nemark'            :  8,
    for (let leaf in leafs) {
        'Deutschland'            :  6,
         if (__LEAF === leaf) {
        'England'                :  1,
             const __DEFAULT = leafs[leaf];
        'Estland'                :  57,
 
        'Far\xF6er'              :  68,
             return getValue(__URI.getQueryPar(item), __DEFAULT);
        'Finnland'              :  40,
         }
         'Frankreich'            :  32,
    }
        'Georgien'              :  49,
 
        'Griechenland'          :  30,
    return -1;
        'Irland'                :  5,
}
        'Island'                :  29,
 
        'Israel'                :  23,
// Gibt die laufende Nummer des ZATs im Text einer Zelle zurueck
        'Italien'                :  10,
// cell: Tabellenzelle mit der ZAT-Nummer im Text
        'Kasachstan'             : 105,
// return ZAT-Nummer im Text
        'Kroatien'              :  24,
function getZATNrFromCell(cell) {
        'Lettland'              :  97,
    const __TEXT = ((cell === undefined) ? [] : cell.textContent.split(' '));
        'Liechtenstein'          :  92,
    let ZATNr = 0;
        'Litauen'                :  72,
 
        'Luxemburg'              :  93,
    for (let i = 1; (ZATNr === 0) && (i < __TEXT.length); i++) {
        'Malta'                  :  69,
         if (__TEXT[i - 1] === "ZAT") {
        'Mazedonien'             :  86,
             if (__TEXT[i] !== "ist") {
         'Moldawien'              :  87,
                 ZATNr = parseInt(__TEXT[i], 10);
        '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
     };
const __LAENDER = reverseMapping(__LANDNRN);


const __TLALAND = {
     return ZATNr;
        undefined : 'unbekannt',
        'ALB'    : 'Albanien',
        'AND'    : 'Andorra',
        'ARM'    : 'Armenien',
        'AZE'    : 'Aserbaidschan',
        'BEL'    : 'Belgien',
        'BIH'    : 'Bosnien-Herzegowina',
        'BUL'    : 'Bulgarien',
        'DEN'    : 'D\xE4nemark',
        'GER'    : 'Deutschland',
        'ENG'    : 'England',
        'EST'    : 'Estland',
        'FRO'    : 'Far\xF6er',
        'FIN'    : 'Finnland',
        'FRA'    : 'Frankreich',
        'GEO'    : 'Georgien',
        'GRE'    : 'Griechenland',
        'IRL'    : 'Irland',
        'ISL'    : 'Island',
        'ISR'    : 'Israel',
        'ITA'    : 'Italien',
        'KAZ'    : 'Kasachstan',
        'CRO'    : 'Kroatien',
        'LVA'    : 'Lettland',
        'LIE'    : 'Liechtenstein',
        'LTU'    : 'Litauen',
        'LUX'    : 'Luxemburg',
        'MLT'    : 'Malta',
        'MKD'    : 'Mazedonien',
        'MDA'    : 'Moldawien',
        'NED'    : 'Niederlande',
        'NIR'    : 'Nordirland',
        'NOR'    : 'Norwegen',
        'AUT'    : '\xD6sterreich',
        'POL'    : 'Polen',
        'POR'    : 'Portugal',
        'ROM'    : 'Rum\xE4nien',
        'RUS'    : 'Russland',
        'SMR'    : 'San Marino',
        'SCO'    : 'Schottland',
        'SWE'    : 'Schweden',
        'SUI'    : 'Schweiz',
        'SCG'    : 'Serbien und Montenegro',
        'SVK'    : 'Slowakei',
        'SVN'    : 'Slowenien',
        'ESP'    : 'Spanien',
        'CZE'    : 'Tschechien',
        'TUR'    : 'T\xFCrkei',
        'UKR'    : 'Ukraine',
        'HUN'    : 'Ungarn',
        'WAL'    : 'Wales',
        'BLR'    : 'Weissrussland',
        'CYP'    : 'Zypern'
    };
const __LANDTLAS = reverseMapping(__TLALAND);
 
// ==================== Abschnitt fuer Daten des Spielplans ====================
 
// Gibt die ID fuer den Namen eines Wettbewerbs zurueck
// gameType: Name des Wettbewerbs eines Spiels
// defValue: Default-Wert
// return OS2-ID fuer den Spieltyp (1 bis 7 oder 10), 0 fuer "spielfrei"/"Frei"/"reserviert", -1 fuer ungueltig
function getGameTypeID(gameType, defValue = __GAMETYPENRN.unbekannt) {
     return getValue(__GAMETYPENRN[gameType], defValue);
}
}


// Gibt den Namen eines Wettbewerbs zurueck
// ==================== Ende Abschnitt fuer sonstige Parameter ====================
// id: OS2-ID des Wettbewerbs eines Spiels (1 bis 7 oder 10), 0 fuer "spielfrei"/"Frei"/"reserviert", -1 fuer ungueltig
// defValue: Default-Wert
// return Spieltyp fuer die uebergebene OS2-ID
function getGameType(id, defValue) {
    return getValue(__GAMETYPES[id], defValue);
}


// Gibt den alternativen (Kurznamen) fuer den Namen eines Wettbewerbs zurueck
// ==================== Hauptprogramm ====================
// gameType: Name des Wettbewerbs eines Spiels
// return Normalerweise den uebergebenen Parameter, in Einzelfaellen eine Kurzversion
function getGameTypeAlias(gameType) {
    return getValue(__GAMETYPEALIASES[gameType], getValue(gameType, __GAMETYPEALIASES.unbekannt));
}


// Gibt den Namen des Landes mit dem uebergebenen Kuerzel (TLA) zurueck.
// Verarbeitet Ansicht "Haupt" (Managerbuero) zur Ermittlung des aktuellen ZATs
// tla: Kuerzel (TLA) des Landes
function procHaupt() {
// defValue: Default-Wert
     const __TEAMPARAMS = getTeamParamsFromTable(getTable(1), __TEAMSEARCHHAUPT); // Link mit Team, Liga, Land...
// return Name des Landes, 'unbekannt' fuer undefined
function getLandName(tla, defValue = __TLALAND[undefined]) {
     return getValue(__TLALAND[tla], defValue);
}


// Gibt die ID des Landes mit dem uebergebenen Namen zurueck.
    buildOptions(__OPTCONFIG, __OPTSET, {
// land: Name des Landes
                    'teamParams' : __TEAMPARAMS,
// defValue: Default-Wert
                    'hideMenu'  : true
// return OS2-ID des Landes, 0 fuer ungueltig
                });
function getLandNr(land, defValue = __LANDNRN.unbekannt) {
    return getValue(__LANDNRN[land], defValue);
}


// Gibt die ID der Liga mit dem uebergebenen Namen zurueck.
    const __ZATCELL = getProp(getProp(getRows(0), 2), 'cells', { })[0];
// land: Name der Liga
    const __NEXTZAT = getZATNrFromCell(__ZATCELL);  // "Der naechste ZAT ist ZAT xx und ..."
// defValue: Default-Wert
    const __CURRZAT = __NEXTZAT - 1;
// return OS2-ID der Liga, 0 fuer ungueltig
    const __DATAZAT = getOptValue(__OPTSET.datenZat);
function getLigaNr(liga, defValue = __LIGANRN.unbekannt) {
    return getValue(__LIGANRN[liga], defValue);
}


// Kehrt das Mapping eines Objekts um und liefert ein neues Objekt zurueck.
    // Stand der alten Daten merken...
// obj: Objekt mit key => value
    setOpt(__OPTSET.oldDatenZat, __DATAZAT, false);
// convFun: Konvertierfunktion fuer die Werte
// return Neues Objekt mit value => key (doppelte value-Werte fallen heraus!)
function reverseMapping(obj, convFun) {
    if (! obj) {
        return obj;
    }


     const __RET = { };
     if (__CURRZAT >= 0) {
        __LOG[2]("Aktueller ZAT: " + __CURRZAT);


    for (let key in obj) {
        // Neuen aktuellen ZAT speichern...
        const __VALUE = obj[key];
        setOpt(__OPTSET.aktuellerZat, __CURRZAT, false);


         __RET[__VALUE] = (convFun ? convFun(key) : key);
         if (__CURRZAT !== __DATAZAT) {
    }
            __LOG[2](__LOG.changed(__DATAZAT, __CURRZAT));


    return __RET;
            // ... und ZAT-bezogene Daten als veraltet markieren (ausser 'skills' und 'positions')
}
            __TEAMCLASS.deleteOptions({
 
                                          'skills'      : true,
// ==================== Abschnitt fuer sonstige Parameter ====================
                                          'positions'  : true,
                                          'datenZat'    : true,
                                          'oldDatenZat' : true
                                      });


// Formatiert eine Zelle um (mit einfachen Parametern)
            // Neuen Daten-ZAT speichern...
// cell: Zu formatierende Zelle
             setOpt(__OPTSET.datenZat, __CURRZAT, false);
// bold: Inhalt fett darstellen (true = ja, false = nein)
// color: Falls angegeben, die Schriftfarbe
// bgColor: Falls angegeben, die Hintergrundfarbe
// opacity: Falls angegeben, die Opazitaet
// return Die formatierte Zelle
function formatCell(cell, bold = true, color = undefined, bgColor = undefined, opacity = undefined) {
    if (cell) {
        if (bold) {
            cell.style.fontWeight = 'bold';
        }
        if (color) {
             cell.style.color = color;
        }
        if (bgColor) {
            cell.style.backgroundColor = bgColor;
        }
        if (opacity) {
        cell.style.opacity = opacity;
         }
         }
     }
     }
    return cell;
}
}


// Ermittelt die auszugewaehlenden Werte eines Selects (Combo-Box) als Array zurueck
// Verarbeitet Ansicht "Optionen" zur Ermittlung der Jugendfoerderung
// element: 'select'-Element oder dessen Name auf der HTML-Seite mit 'option'-Eintraegen der Combo-Box
function procOptionen() {
// valType: Typ-Klasse der Optionswerte ('String', 'Number', ...)
    buildOptions(__OPTCONFIG, __OPTSET, {
// valFun: Funktion zur Ermittlung des Wertes eines 'option'-Eintrags (getSelectedOptionText, getSelectedValue, ...)
                    'menuAnchor' : getTable(0, "div"),
// defValue: Default-Wert, falls nichts selektiert ist
                    'hideMenu'   : true,
// return Array mit den Options-Werten
                    'getDonation' : true,
function getSelectionArray(element, valType = 'String', valFun = getSelectedValue, defValue = undefined) {
                    'showForm'   : {
    const __SELECT = ((typeof element) === 'string' ? getValue(document.getElementsByName(element), [])[0] : element);
                                        'foerderung'   : true,
 
                                        'showForm'     : true
    return (__SELECT ? [].map.call(__SELECT.options, function(option) {
                                    }
                                                        return this[valType](getValue(valFun(option), defValue));
                });
                                                    }) : undefined);
}
}


// Ermittelt den ausgewaehlten Wert eines Selects (Combo-Box) und gibt diesen zurueck
// Verarbeitet Ansicht "Teamuebersicht"
// element: 'select'-Element oder dessen Name auf der HTML-Seite mit 'option'-Eintraegen der Combo-Box
function procTeamuebersicht() {
// valType: Typ-Klasse der Optionswerte ('String', 'Number', ...)
    const __ROWOFFSETUPPER = 1;    // Header-Zeile
// valFun: Funktion zur Ermittlung des Wertes eines 'option'-Eintrags (getSelectedOptionText, getSelectedValue, ...)
     const __ROWOFFSETLOWER = 1;     // Ziehen-Button
// defValue: Default-Wert, falls nichts selektiert ist
// return Ausgewaehlter Wert
function getSelection(element, valType = 'String', valFun = getSelectedOptionText, defValue = undefined) {
     const __SELECT = ((typeof element) === 'string' ? getValue(document.getElementsByName(element), [])[0] : element);


     return this[valType](getValue(valFun(__SELECT), defValue));
     const __COLUMNINDEX = {
}
            'Age'  : 0,
            'Geb'  : 1,
            'Flg'  : 2,
            'Land'  : 3,
            'U'    : 4,
            'Skill' : 5,
            'Tal'  : 6,
            'Akt'  : 7,
            'Auf'  : 8,
            'Zus'  : 9
        };


// Ermittelt den ausgewaehlten Wert einer Combo-Box und gibt diesen zurueck
    if (getElement('transfer') !== undefined) {
// comboBox: Alle 'option'-Eintraege der Combo-Box
        __LOG[2]("Ziehen-Seite");
// defValue: Default-Wert, falls nichts selektiert ist
    } else if (getRows(1) === undefined) {
// valType: Typ-Klasse der Optionswerte ('String', 'Number', ...)
        __LOG[2]("Diese Seite ist ohne Team nicht verf\xFCgbar!");
// return Ausgewaehlter Wert
    } else {
function getSelectionFromComboBox(comboBox, defValue = undefined, valType = 'String') {
        buildOptions(__OPTCONFIG, __OPTSET, {
     let selection;
                        'menuAnchor' : getTable(0, "div"),
                        'showForm'   : {
                                            'kennzeichenEnde'    : true,
                                            'shortAufw'          : true,
                                            'sepStyle'          : true,
                                            'sepColor'          : true,
                                            'sepWidth'          : true,
                                            'saison'            : true,
                                            'aktuellerZat'      : true,
                                            'foerderung'        : true,
                                            'team'              : true,
                                            'zeigeBalken'        : true,
                                            'absBalken'          : true,
                                            'zeigeId'            : true,
                                            'ersetzeAlter'      : true,
                                            'zeigeAlter'        : true,
                                            'zeigeQuote'        : true,
                                            'zeigePosition'      : true,
                                            'zeigeZatDone'      : true,
                                            'zeigeZatLeft'      : true,
                                            'zeigeFixSkills'    : true,
                                            'zeigeTrainiert'    : true,
                                            'zeigeAnteilPri'    : true,
                                            'zeigeAnteilSec'    : true,
                                            'zeigePrios'        : true,
                                            'zeigeSkill'        : true,
                                            'anzahlOpti'        : true,
                                            'anzahlMW'           : true,
                                            'zeigeTrainiertEnde' : true,
                                            'zeigeAnteilPriEnde' : true,
                                            'zeigeAnteilSecEnde' : true,
                                            'zeigePriosEnde'    : true,
                                            'zeigeSkillEnde'     : true,
                                            'anzahlOptiEnde'     : true,
                                            'anzahlMWEnde'      : true,
                                            'zatAges'            : true,
                                            'trainiert'          : true,
                                            'positions'          : true,
                                            'skills'            : true,
                                            'reset'              : true,
                                            'showForm'          : true
                                        },
                        'formWidth'  : 1
                    });


    for (let i = 0; i < comboBox.length; i++) {
        const __ROWS = getRows(1);
         const __ENTRY = comboBox[i];
        const __HEADERS = __ROWS[0];
         const __TITLECOLOR = getColor('LEI'); // "#FFFFFF"


         if (__ENTRY.outerHTML.match(/selected/)) {
         const __PLAYERS = init(__ROWS, __OPTSET, __COLUMNINDEX, __ROWOFFSETUPPER, __ROWOFFSETLOWER, true);
            selection = __ENTRY.textContent;
        const __COLMAN = new ColumnManager(__OPTSET, __COLUMNINDEX, {
         }
                                            'Default'            : true,
    }
                                            'ersetzeSkills'      : false,
                                            'zeigeGeb'          : false,
                                            'zeigeSkill'         : false,
                                            'zeigeTal'          : false,
                                            'zeigeAufw'          : false
                                        });


    return this[valType](getValue(selection, defValue));
        __COLMAN.addTitles(__HEADERS, __TITLECOLOR);
}


// Liefert den Text (textContent) einer selektierten Option
        for (let i = 0; i < __PLAYERS.length; i++) {
// element: 'select'-Element auf der HTML-Seite mit 'option'-Eintraegen der Combo-Box
            __COLMAN.addValues(__PLAYERS[i], __ROWS[i + __ROWOFFSETUPPER], __TITLECOLOR);
// return Wert der Selektion (textContent)
        }
function getSelectedOptionText(element) {
    const __SELECTEDOPTIONS = getValue(element, { }).selectedOptions;
    const __OPTION = getValue(__SELECTEDOPTIONS, { })[0];


    return (__OPTION ? __OPTION.textContent : undefined);
        // Format der Trennlinie zwischen den Monaten...
}
        const __BORDERSTRING = getOptValue(__OPTSET.sepStyle) + ' ' + getOptValue(__OPTSET.sepColor) + ' ' + getOptValue(__OPTSET.sepWidth);


// Liefert den 'value' einer selektierten Option
        separateGroups(__ROWS, __BORDERSTRING, __COLUMNINDEX.Age, __ROWOFFSETUPPER, __ROWOFFSETLOWER, -1, 0, floorValue);
// element: 'select'-Element auf der HTML-Seite mit 'option'-Eintraegen der Combo-Box
     }
// return Wert der Selektion ('value')
function getSelectedValue(element) {
     return getValue(element, { }).value;
}
}


// ==================== Ende Abschnitt fuer sonstige Parameter ====================
// Verarbeitet Ansicht "Spielereinzelwerte"
function procSpielereinzelwerte() {
    const __ROWOFFSETUPPER = 1;    // Header-Zeile
    const __ROWOFFSETLOWER = 0;


// ==================== Abschnitt fuer sonstige Parameter des Spielplans ====================
    const __COLUMNINDEX = {
            'Flg'  : 0,
            'Land'  : 1,
            'U'    : 2,
            'Age'  : 3,
            'Einz'  : 4,    // ab hier die Einzelskills
            'SCH'  : 4,
            'ABS'  : 4,    // TOR
            'BAK'  : 5,
            'STS'  : 5,    // TOR
            'KOB'  : 6,
            'FAN'  : 6,    // TOR
            'ZWK'  : 7,
            'STB'  : 7,    // TOR
            'DEC'  : 8,
            'SPL'  : 8,    // TOR
            'GES'  : 9,
            'REF'  : 9,    // TOR
            'FUQ'  : 10,
            'ERF'  : 11,
            'AGG'  : 12,
            'PAS'  : 13,
            'AUS'  : 14,
            'UEB'  : 15,
            'WID'  : 16,
            'SEL'  : 17,
            'DIS'  : 18,
            'ZUV'  : 19,
            'EIN'  : 20,
            'Zus'  : 21    // Zusaetze hinter den Einzelskills
        };


const __TEAMSEARCHHAUPT = {  // Parameter zum Team "<b>Willkommen im Managerb&uuml;ro von TEAM</b><br>LIGA LAND<a href=..."
     if (getRows(1) === undefined) {
        'Zeile'  : 0,
        'Spalte' : 1,
        'start'  : " von ",
        'middle' : "</b><br>",
        'liga'  : ". Liga",
        'land'  : ' ',
        'end'    : "<a href="
     };
 
const __TEAMSEARCHTEAM = {  // Parameter zum Team "<b>TEAM - LIGA <a href=...>LAND</a></b>"
        'Zeile'  : 0,
        'Spalte' : 0,
        'start'  : "<b>",
        'middle' : " - ",
        'liga'  : ". Liga",
        'land'  : 'target="_blank">',
        'end'    : "</a></b>"
    };
 
// Ermittelt, wie das eigene Team heisst und aus welchem Land bzw. Liga es kommt (zur Unterscheidung von Erst- und Zweitteam)
// cell: Tabellenzelle mit den Parametern zum Team "startTEAMmiddleLIGA...landLANDend", LIGA = "#liga[ (A|B|C|D)]"
// teamSeach: Muster fuer die Suche, die Eintraege fuer 'start', 'middle', 'liga', 'land' und 'end' enthaelt
// return Im Beispiel { 'Team' : "TEAM", 'Liga' : "LIGA", 'Land' : "LAND", 'LdNr' : LAND-NUMMER, 'LgNr' : LIGA-NUMMER },
//        z.B. { 'Team' : "Choromonets Odessa", 'Liga' : "1. Liga", 'Land' : "Ukraine", 'LdNr' : 20, 'LgNr' : 1 }
function getTeamParamsFromTable(table, teamSearch = undefined) {
    const __TEAMSEARCH  = getValue(teamSearch, __TEAMSEARCHHAUPT);
    const __TEAMCELLROW  = getValue(__TEAMSEARCH.Zeile, 0);
    const __TEAMCELLCOL  = getValue(__TEAMSEARCH.Spalte, 0);
    const __TEAMCELLSTR  = (table === undefined) ? "" : table.rows[__TEAMCELLROW].cells[__TEAMCELLCOL].innerHTML;
    const __SEARCHSTART  = __TEAMSEARCH.start;
    const __SEARCHMIDDLE = __TEAMSEARCH.middle;
    const __SEARCHLIGA  = __TEAMSEARCH.liga;
    const __SEARCHLAND  = __TEAMSEARCH.land;
    const __SEARCHEND    = __TEAMSEARCH.end;
    const __INDEXSTART  = __TEAMCELLSTR.indexOf(__SEARCHSTART);
    const __INDEXEND    = __TEAMCELLSTR.indexOf(__SEARCHEND);
 
    let teamParams = __TEAMCELLSTR.substring(__INDEXSTART + __SEARCHSTART.length, __INDEXEND);
    const __INDEXLIGA = teamParams.indexOf(__SEARCHLIGA);
    const __INDEXMIDDLE = teamParams.indexOf(__SEARCHMIDDLE);
 
    let land = ((~ __INDEXLIGA) ? teamParams.substring(__INDEXLIGA + __SEARCHLIGA.length) : undefined);
    const __TEAMNAME = ((~ __INDEXMIDDLE) ? teamParams.substring(0, __INDEXMIDDLE) : undefined);
    let liga = (((~ __INDEXLIGA) && (~ __INDEXMIDDLE)) ? teamParams.substring(__INDEXMIDDLE + __SEARCHMIDDLE.length) : undefined);
 
    if (land !== undefined) {
        if (land.charAt(2) === ' ') {    // Land z.B. hinter "2. Liga A " statt "1. Liga "
            land = land.substr(2);
        }
        if (liga !== undefined) {
            liga = liga.substring(0, liga.length - land.length);
        }
        const __INDEXLAND = land.indexOf(__SEARCHLAND);
        if (~ __INDEXLAND) {
            land = land.substr(__INDEXLAND + __SEARCHLAND.length);
        }
    }
 
    const __TEAM = new Team(__TEAMNAME, land, liga);
 
    return __TEAM;
}
 
// Verarbeitet die URL der Seite und ermittelt die Nummer der gewuenschten Unterseite
// url: Adresse der Seite
// leafs: Liste von Filenamen mit der Default-Seitennummer (falls Query-Parameter nicht gefunden)
// item: Query-Parameter, der die Nummer der Unterseite angibt
// return Parameter aus der URL der Seite als Nummer
function getPageIdFromURL(url, leafs, item = 'page') {
    const __URI = new URI(url);
    const __LEAF = __URI.getLeaf();
 
    for (let leaf in leafs) {
        if (__LEAF === leaf) {
            const __DEFAULT = leafs[leaf];
 
            return getValue(__URI.getQueryPar(item), __DEFAULT);
        }
    }
 
    return -1;
}
 
// Gibt die laufende Nummer des ZATs im Text einer Zelle zurueck
// cell: Tabellenzelle mit der ZAT-Nummer im Text
// return ZAT-Nummer im Text
function getZATNrFromCell(cell) {
    const __TEXT = ((cell === undefined) ? [] : cell.textContent.split(' '));
    let ZATNr = 0;
 
    for (let i = 1; (ZATNr === 0) && (i < __TEXT.length); i++) {
        if (__TEXT[i - 1] === "ZAT") {
            if (__TEXT[i] !== "ist") {
                ZATNr = parseInt(__TEXT[i], 10);
            }
        }
    }
 
    return ZATNr;
}
 
// ==================== Ende Abschnitt fuer sonstige Parameter des Spielplans ====================
 
// ==================== Ende Abschnitt fuer Spielplan und ZATs ====================
 
// ==================== Hauptprogramm ====================
 
// Verarbeitet Ansicht "Haupt" (Managerbuero) zur Ermittlung des aktuellen ZATs
function procHaupt() {
    const __TEAMPARAMS = getTeamParamsFromTable(getTable(1), __TEAMSEARCHHAUPT);  // Link mit Team, Liga, Land...
 
    return buildOptions(__OPTCONFIG, __OPTSET, {
                            'teamParams' : __TEAMPARAMS,
//                            'menuAnchor' : getTable(0, 'div'),
                            'hideMenu'  : true,
                            'showForm'  : {
                                              'zeigeWarnung'        : true,
                                              'zeigeWarnungMonat'    : true,
                                              'zeigeWarnungHome'    : true,
                                              'zeigeWarnungDialog'  : true,
                                              'zeigeWarnungAufstieg' : true,
                                              'zeigeWarnungLegende'  : true,
                                              'ziehAnz'              : true,
                                              'showForm'            : true
                                          }
                        }).then(async optSet => {
            const __ZATCELL = getProp(getProp(getRows(0), 2), 'cells', { })[0];
            const __NEXTZAT = getZATNrFromCell(__ZATCELL);  // "Der naechste ZAT ist ZAT xx und ..."
            const __CURRZAT = __NEXTZAT - 1;
            const __DATAZAT = getOptValue(__OPTSET.datenZat);
 
            // Stand der alten Daten merken...
            setOpt(__OPTSET.oldDatenZat, __DATAZAT, false);
 
            if (__CURRZAT >= 0) {
                __LOG[2]("Aktueller ZAT: " + __CURRZAT);
 
                // Neuen aktuellen ZAT speichern...
                setOpt(__OPTSET.aktuellerZat, __CURRZAT, false);
 
                if (__CURRZAT !== __DATAZAT) {
                    __LOG[2](__LOG.changed(__DATAZAT, __CURRZAT));
 
                    // ... und ZAT-bezogene Daten als veraltet markieren (ausser 'skills', 'positions' und 'ziehAnz')
                    await __TEAMCLASS.deleteOptions({
                                                    'skills'      : true,
                                                    'positions'  : true,
                                                    'datenZat'    : true,
                                                    'oldDatenZat' : true,
                                                    'ziehAnz'    : (__CURRZAT > __DATAZAT)  // nur loeschen, wenn < __DATAZAT
                                                }).catch(defaultCatch);
 
                    // Neuen Daten-ZAT speichern...
                    setOpt(__OPTSET.datenZat, __CURRZAT, false);
                }
            }
 
            const __MSG = new WarnDrawMessage(optSet, __CURRZAT);
            const __MSGAUFSTIEG = new WarnDrawMessageAufstieg(optSet, __CURRZAT);
            const __ANCHOR = getTable(0, 'tbody');
 
            __MSG.showMessage(__ANCHOR, 'tr', true);
            __MSG.showDialog(showAlert);
            __MSGAUFSTIEG.showMessage(__ANCHOR, 'tr', true);
        });
}
 
// Verarbeitet Ansicht "Optionen" zur Ermittlung der Jugendfoerderung
function procOptionen() {
    return buildOptions(__OPTCONFIG, __OPTSET, {
                            'menuAnchor'  : getTable(0, 'div'),
                            'hideMenu'    : true,
                            'getDonation' : true,
                            'showForm'    : {
                                                'foerderung'          : true,
                                                'zeigeWarnung'        : true,
                                                'zeigeWarnungMonat'    : true,
                                                'zeigeWarnungHome'    : true,
                                                'zeigeWarnungDialog'  : true,
                                                'zeigeWarnungAufstieg' : true,
                                                'zeigeWarnungLegende'  : true,
                                                'ziehAnz'              : true,
                                                'showForm'            : true
                                            }
        });
}
 
// Verarbeitet Ansicht "Teamuebersicht"
function procTeamuebersicht() {
    const __ROWOFFSETUPPER = 1;    // Header-Zeile
    const __ROWOFFSETLOWER = 1;    // Ziehen-Button
 
    const __COLUMNINDEX = {
            'Age'  : 0,
            'Geb'  : 1,
            'Flg'  : 2,
            'Land'  : 3,
            'U'    : 4,
            'Skill' : 5,
            'Tal'  : 6,
            'Akt'  : 7,
            'Auf'  : 8,
            'Zus'  : 9
        };
 
    if (getElement('transfer') !== undefined) {
        __LOG[2]("Ziehen-Seite");
    } else if (getRows(1) === undefined) {
         __LOG[2]("Diese Seite ist ohne Team nicht verf\xFCgbar!");
         __LOG[2]("Diese Seite ist ohne Team nicht verf\xFCgbar!");
     } else {
     } else {
         return buildOptions(__OPTCONFIG, __OPTSET, {
         buildOptions(__OPTCONFIG, __OPTSET, {
                                'menuAnchor' : getTable(0, 'div'),
                        'menuAnchor' : getTable(0, "div"),
                                'showForm'  : {
                        'hideForm'  : {
                                                  'kennzeichenEnde'      : true,
                                            'zatAges'      : true,
                                                  'shortAufw'            : true,
                                            'trainiert'     : true,
                                                  'sepStyle'            : true,
                                            'positions'     : true,
                                                  'sepColor'            : true,
                                            'skills'       : true,
                                                  'sepWidth'            : true,
                                            'shortAufw'     : true
                                                  'saison'              : true,
                                        },
                                                  'aktuellerZat'        : true,
                        'formWidth'  : 1
                                                  'foerderung'          : true,
                    });
                                                  'team'                : true,
                                                  'zeigeJahrgang'        : true,
                                                  'zeigeUxx'            : true,
                                                  'zeigeWarnung'        : true,
                                                  'zeigeWarnungMonat'    : true,
                                                  'zeigeWarnungHome'    : true,
                                                  'zeigeWarnungDialog'  : true,
                                                  'zeigeWarnungAufstieg' : true,
                                                  'zeigeWarnungLegende'  : true,
                                                  'zeigeBalken'          : true,
                                                  'absBalken'            : true,
                                                  'zeigeId'              : true,
                                                  'ersetzeAlter'        : true,
                                                  'zeigeAlter'          : true,
                                                  'zeigeQuote'          : true,
                                                  'zeigePosition'        : true,
                                                  'zeigeZatDone'        : true,
                                                  'zeigeZatLeft'        : true,
                                                  'zeigeFixSkills'      : true,
                                                  'zeigeTrainiert'      : true,
                                                  'zeigeAnteilPri'      : true,
                                                  'zeigeAnteilSec'      : true,
                                                  'zeigePrios'          : true,
                                                  'anzahlOpti'          : true,
                                                  'anzahlMW'            : true,
                                                  'zeigeTrainiertEnde'  : true,
                                                  'zeigeAnteilPriEnde'  : true,
                                                  'zeigeAnteilSecEnde'  : true,
                                                  'zeigePriosEnde'      : true,
                                                  'zeigeSkillEnde'      : true,
                                                  'anzahlOptiEnde'      : true,
                                                  'anzahlMWEnde'        : true,
                                                  'ziehAnz'              : true,
                                                  'zatAges'              : true,
                                                  'trainiert'           : true,
                                                  'positions'           : true,
                                                  'skills'               : true,
                                                  'reset'               : true,
                                                  'showForm'            : true
                                              },
                                'formWidth'  : 1
                            }).then(optSet => {
                const __ROWS = getRows(1);
                const __HEADERS = __ROWS[0];
                const __TITLECOLOR = getColor('LEI');  // "#FFFFFF"


                const __PLAYERS = init(__ROWS, __OPTSET, __COLUMNINDEX, __ROWOFFSETUPPER, __ROWOFFSETLOWER, 1);
        const __ROWS = getRows(1);
                const __COLMAN = new ColumnManager(__OPTSET, __COLUMNINDEX, {
        const __HEADERS = __ROWS[0];
                                                    'Default'            : true,
         const __TITLECOLOR = getColor('LEI'); // "#FFFFFF"
                                                    'ersetzeSkills'      : false,
                                                    'zeigeGeb'          : false,
                                                    'zeigeSkill'         : false,
                                                    'zeigeTal'          : false,
                                                    'zeigeAufw'         : false
                                                });


                __COLMAN.addTitles(__HEADERS, __TITLECOLOR);
        const __PLAYERS = init(__ROWS, __OPTSET, __COLUMNINDEX, __ROWOFFSETUPPER, __ROWOFFSETLOWER, false);
 
        const __COLMAN = new ColumnManager(__OPTSET, __COLUMNINDEX, true);
                for (let i = __ROWOFFSETUPPER, j = 0; i < __ROWS.length - __ROWOFFSETLOWER; i++) {
                    if (__ROWS[i].cells.length > 1) {
                        __COLMAN.addValues(__PLAYERS[j++], __ROWS[i], __TITLECOLOR);
                    } else {
                        __COLMAN.setGroupTitle(__ROWS[i]);
                    }
                }


                // Format der Trennlinie zwischen den Jahrgaengen...
        __COLMAN.addTitles(__HEADERS, __TITLECOLOR);
                if (! __COLMAN.gt) {
                    const __BORDERSTRING = getOptValue(__OPTSET.sepStyle) + ' ' + getOptValue(__OPTSET.sepColor) + ' ' + getOptValue(__OPTSET.sepWidth);


                    separateGroups(__ROWS, __BORDERSTRING, __COLUMNINDEX.Land, __ROWOFFSETUPPER, __ROWOFFSETLOWER, 0, 0, existValue);
        for (let i = 0; i < __PLAYERS.length; i++) {
                }
             __COLMAN.addValues(__PLAYERS[i], __ROWS[i + __ROWOFFSETUPPER], __TITLECOLOR);
 
        }
                const __CURRZAT = getOptValue(__OPTSET.datenZat);
                const __MSG = new WarnDrawMessage(__OPTSET, __CURRZAT);
                const __MSGAUFSTIEG = new WarnDrawMessageAufstieg(__OPTSET, __CURRZAT);
                const __ANCHOR = getTable(0, 'div');
                const __SEARCH = '<form method="POST">';
 
                // Kompaktere Darstellung und ohne Links...
                __MSG.out.top = false;
                __MSG.out.label = false;
                __MSG.out.link = false;
                __MSG.out.bottom = false;
                __MSGAUFSTIEG.out.label = false;
                __MSGAUFSTIEG.out.link = false;
                __MSGAUFSTIEG.out.bottom = false;
 
                __MSG.setOptionLegende();
                __MSGAUFSTIEG.setOptionLegende();
 
                __MSG.showMessage(__ANCHOR, 'p', __SEARCH);
                __MSGAUFSTIEG.showMessage(__ANCHOR, 'p', __SEARCH);
             });
    }
 
    // Promise fuer alle Faelle ohne Rueckgabewert...
    return Promise.resolve();
}
 
// Verarbeitet Ansicht "Spielereinzelwerte"
function procSpielereinzelwerte() {
    const __ROWOFFSETUPPER = 1;    // Header-Zeile
    const __ROWOFFSETLOWER = 0;
 
    const __COLUMNINDEX = {
            'Flg'  : 0,
            'Land'  : 1,
            'U'    : 2,
            'X'    : 3,
            'Age'  : 4,
            'Einz'  : 5,    // ab hier die Einzelskills
            'SCH'  : 5,
            'ABS'  : 5,    // TOR
            'BAK'  : 6,
            'STS'  : 6,    // TOR
            'KOB'  : 7,
            'FAN'  : 7,    // TOR
            'ZWK'  : 8,
            'STB'  : 8,    // TOR
            'DEC'  : 9,
            'SPL'  : 9,    // TOR
            'GES'  : 10,
            'REF'  : 10,  // TOR
            'FUQ'  : 11,
            'ERF'  : 12,
            'AGG'  : 13,
            'PAS'  : 14,
            'AUS'  : 15,
            'UEB'  : 16,
            'WID'  : 17,
            'SEL'  : 18,
            'DIS'  : 19,
            'ZUV'  : 20,
            'EIN'  : 21,
            'Zus'  : 22    // Zusaetze hinter den Einzelskills
        };
 
    if (getRows(1) === undefined) {
        __LOG[2]("Diese Seite ist ohne Team nicht verf\xFCgbar!");
    } else {
        return buildOptions(__OPTCONFIG, __OPTSET, {
                                'menuAnchor' : getTable(0, 'div'),
                                'hideForm'  : {
                                                  'zeigeWarnung'        : false,
                                                  'zeigeWarnungMonat'    : false,
                                                  'zeigeWarnungHome'    : false,
                                                  'zeigeWarnungDialog'  : false,
                                                  'zeigeWarnungAufstieg' : false,
                                                  'zeigeWarnungLegende'  : false,
                                                  'ziehAnz'              : true,
                                                  'zatAges'              : true,
                                                  'trainiert'            : true,
                                                  'positions'            : true,
                                                  'skills'              : true,
                                                  'shortAufw'            : true
                                              },
                                'formWidth'  : 1
                            }).then(optSet => {
                const __ROWS = getRows(1);
                const __HEADERS = __ROWS[0];
                const __TITLECOLOR = getColor('LEI'); // "#FFFFFF"


                const __PLAYERS = init(__ROWS, __OPTSET, __COLUMNINDEX, __ROWOFFSETUPPER, __ROWOFFSETLOWER, 2);
        // Format der Trennlinie zwischen den Monaten...
                const __COLMAN = new ColumnManager(__OPTSET, __COLUMNINDEX, true);
        const __BORDERSTRING = getOptValue(__OPTSET.sepStyle) + ' ' + getOptValue(__OPTSET.sepColor) + ' ' + getOptValue(__OPTSET.sepWidth);


                __COLMAN.addTitles(__HEADERS, __TITLECOLOR);
        separateGroups(__ROWS, __BORDERSTRING, __COLUMNINDEX.Age, __ROWOFFSETUPPER, __ROWOFFSETLOWER, -1, 0, floorValue);
 
                for (let i = __ROWOFFSETUPPER, j = 0; i < __ROWS.length - __ROWOFFSETLOWER; i++) {
                    if (__ROWS[i].cells.length > 1) {
                        __COLMAN.addValues(__PLAYERS[j++], __ROWS[i], __TITLECOLOR);
                    } else {
                        __COLMAN.setGroupTitle(__ROWS[i]);
                    }
                }
 
                // Format der Trennlinie zwischen den Jahrgaengen...
                if (! __COLMAN.gt) {
                    const __BORDERSTRING = getOptValue(__OPTSET.sepStyle) + ' ' + getOptValue(__OPTSET.sepColor) + ' ' + getOptValue(__OPTSET.sepWidth);
 
                    separateGroups(__ROWS, __BORDERSTRING, __COLUMNINDEX.Land, __ROWOFFSETUPPER, __ROWOFFSETLOWER, 0, 0, existValue);
                }
            });
     }
     }
    // Promise fuer alle Faelle ohne Rueckgabewert...
    return Promise.resolve();
}
}


// Verarbeitet Ansicht "Opt. Skill"
try {
function procOptSkill() {
     // URL-Legende:
    const __ROWOFFSETUPPER = 1;     // Header-Zeile
     // page=0: Managerbuero
     const __ROWOFFSETLOWER = 0;
     // page=1: Teamuebersicht
 
     // page=2: Spielereinzelwerte
     const __COLUMNINDEX = {
     // page=3: Optionen
            'Flg'  : 0,
            'Land'  : 1,
            'U'    : 2,
            'Age'  : 3,
            'Skill' : 4,
            'TOR'  : 5,
            'ABW'  : 6,
            'DMI'  : 7,
            'MIT'  : 8,
            'OMI'  : 9,
            'STU'  : 10,
            'Zus'  : 11     // Zusaetze hinter den OptSkills
        };
 
    if (getRows(1) === undefined) {
        __LOG[2]("Diese Seite ist ohne Team nicht verf\xFCgbar!");
    } else {
        return buildOptions(__OPTCONFIG, __OPTSET, {
                                'menuAnchor' : getTable(0, 'div'),
                                'showForm'  : {
                                                  'kennzeichenEnde'      : true,
                                                  'sepStyle'            : true,
                                                  'sepColor'            : true,
                                                  'sepWidth'            : true,
                                                  'saison'              : true,
                                                  'aktuellerZat'        : true,
                                                  'foerderung'          : true,
                                                  'team'                : true,
                                                  'zeigeJahrgang'        : true,
                                                  'zeigeUxx'            : true,
                                                  'zeigeWarnung'        : false,
                                                  'zeigeWarnungMonat'    : false,
                                                  'zeigeWarnungHome'     : false,
                                                  'zeigeWarnungDialog'  : false,
                                                  'zeigeWarnungAufstieg' : false,
                                                  'zeigeWarnungLegende'  : false,
                                                  'zeigeBalken'          : true,
                                                  'absBalken'            : true,
                                                  'zeigeId'              : true,
                                                  'ersetzeAlter'        : true,
                                                  'zeigeAlter'          : true,
                                                  'zeigeQuote'          : true,
                                                  'zeigePosition'        : true,
                                                  'zeigeZatDone'        : true,
                                                  'zeigeZatLeft'        : true,
                                                  'zeigeFixSkills'      : true,
                                                  'zeigeTrainiert'      : true,
                                                  'zeigeAnteilPri'      : true,
                                                  'zeigeAnteilSec'      : true,
                                                  'zeigePrios'          : true,
                                                  'zeigeAufw'            : true,
                                                  'zeigeGeb'            : true,
                                                  'zeigeTal'            : true,
                                                  'anzahlOpti'          : true,
                                                  'anzahlMW'            : true,
                                                  'zeigeTrainiertEnde'  : true,
                                                  'zeigeAnteilPriEnde'  : true,
                                                  'zeigeAnteilSecEnde'  : true,
                                                  'zeigePriosEnde'      : true,
                                                  'zeigeSkillEnde'      : true,
                                                  'anzahlOptiEnde'      : true,
                                                  'anzahlMWEnde'        : true,
                                                  'zatAges'              : true,
                                                  'trainiert'            : true,
                                                  'positions'            : true,
                                                  'skills'              : true,
                                                  'reset'                : true,
                                                  'showForm'            : true
                                              },
                                'formWidth'  : 1
                            }).then(optSet => {
                const __ROWS = getRows(1);
                const __HEADERS = __ROWS[0];
                const __TITLECOLOR = getColor('LEI');  // "#FFFFFF"
 
                const __PLAYERS = init(__ROWS, __OPTSET, __COLUMNINDEX, __ROWOFFSETUPPER, __ROWOFFSETLOWER, 3);
                const __COLMAN = new ColumnManager(__OPTSET, __COLUMNINDEX, {
                                                    'Default'            : true,
                                                    'ersetzeSkills'      : false,
                                                    'zeigeSkill'        : false
                                                });
 
                __COLMAN.addTitles(__HEADERS, __TITLECOLOR);


                for (let i = __ROWOFFSETUPPER, j = 0; i < __ROWS.length - __ROWOFFSETLOWER; i++) {
    // Verzweige in unterschiedliche Verarbeitungen je nach Wert von page:
                    if (__ROWS[i].cells.length > 1) {
    switch (getPageIdFromURL(window.location.href, {
                        __COLMAN.addValues(__PLAYERS[j++], __ROWS[i], __TITLECOLOR);
                                                      'haupt.php' : 0,  // Ansicht "Haupt" (Managerbuero)
                    } else {
                                                      'ju.php'    : 1  // Ansicht "Jugendteam"
                        __COLMAN.setGroupTitle(__ROWS[i]);
                                                  }, 'page')) {
                    }
        case 0  : procHaupt(); break;
                }
        case 1  : procTeamuebersicht(); break;
 
        case 2  : procSpielereinzelwerte(); break;
                // Format der Trennlinie zwischen den Jahrgaengen...
        case 3  : procOptionen(); break;
                if (! __COLMAN.gt) {
        default : break;
                    const __BORDERSTRING = getOptValue(__OPTSET.sepStyle) + ' ' + getOptValue(__OPTSET.sepColor) + ' ' + getOptValue(__OPTSET.sepWidth);
 
                    separateGroups(__ROWS, __BORDERSTRING, __COLUMNINDEX.Land, __ROWOFFSETUPPER, __ROWOFFSETLOWER, 0, 0, existValue);
                }
            });
     }
     }
 
} catch (ex) {
     // Promise fuer alle Faelle ohne Rueckgabewert...
     showAlert('[' + ex.lineNumber + "] " + __DBMOD.Name, ex.message, ex);
     return Promise.resolve();
} finally {
     __LOG[2]("SCRIPT END");
}
}
(() => {
    (async () => {
        try {
            // URL-Legende:
            // page=0: Managerbuero
            // page=1: Teamuebersicht
            // page=2: Spielereinzelwerte
            // page=3: Opt. Skill
            // page=4: Optionen
            // Verzweige in unterschiedliche Verarbeitungen je nach Wert von page:
            switch (getPageIdFromURL(window.location.href, {
                                                              'haupt.php' : 0,  // Ansicht "Haupt" (Managerbuero)
                                                              'ju.php'    : 1  // Ansicht "Jugendteam"
                                                          }, 'page')) {
                case 0  : await procHaupt().catch(defaultCatch); break;
                case 1  : await procTeamuebersicht().catch(defaultCatch); break;
                case 2  : await procSpielereinzelwerte().catch(defaultCatch); break;
                case 3  : await procOptSkill().catch(defaultCatch); break;
                case 4  : await procOptionen().catch(defaultCatch); break;
                default : break;
            }
            return 'OK';
        } catch (ex) {
            return defaultCatch(ex);
        }
    })().then(rc => {
            __LOG[1]('SCRIPT END', __DBMOD.Name, '(' + rc + ')');
        })
})();


// *** EOF ***
// *** EOF ***
</pre>
</pre>

Bitte beachte, dass alle Beiträge zu Online-Soccer-Wiki von anderen Mitwirkenden bearbeitet, geändert oder gelöscht werden können. Reiche hier keine Texte ein, falls du nicht willst, dass diese ohne Einschränkung geändert werden können.

Du bestätigst hiermit auch, dass du diese Texte selbst geschrieben hast oder diese von einer gemeinfreien Quelle kopiert hast (weitere Einzelheiten unter Online-Soccer-Wiki:Urheberrechte). ÜBERTRAGE OHNE GENEHMIGUNG KEINE URHEBERRECHTLICH GESCHÜTZTEN INHALTE!

Abbrechen Bearbeitungshilfe (wird in einem neuen Fenster geöffnet)