"use strict"; // Put all the javascript code here, that you want to execute after page load. let currentStage; function executeStage(node) { if (node.nodeType === 1) { if (currentStage === undefined) { currentStage = stages.shift(); } if (currentStage.match(node)) { console.log(currentStage.name, "matched"); console.log(currentStage.name, currentStage.execute(node) ? "executed" : "execution failed"); if (stages.length > 0) { currentStage = stages.shift(); } else { observer.disconnect(); } } else { console.log(currentStage.name, "did not match: ", node); } } } let stages; const personalDataConfigKeys = ["addr__appellation", "addr__firstName", "addr__surName", "addr__email", "addr__street", "addr__postcode", "addr__placename"]; const bankDetailConfigKeys = ["pymt__iban", "pymt__bic"]; function processMutations(mutationList, observer) { for (const mutation of mutationList) { if (mutation.type === "childList") { mutation.addedNodes.forEach(executeStage); } } } let clickThroughForms; let hasConfiguredBankDetails, hasConfiguredPersonalData; let observer = new MutationObserver(processMutations); const addObserver = () => { browser.storage.sync.get(['autocontinue', 'enable'].concat(personalDataConfigKeys, bankDetailConfigKeys)).then(v => { clickThroughForms = !!v.autocontinue; hasConfiguredPersonalData = Object.keys(v).filter(k => personalDataConfigKeys.includes(k)).length > 0; hasConfiguredBankDetails = Object.keys(v).filter(k => bankDetailConfigKeys.includes(k)).length > 0; if (!!v.enable) { observer.observe(document.body, { childList: true, subtree: true }) } }) }; addObserver(); function fillTextInput(parentNode, selector, value) { const node = parentNode.querySelector(selector); node.value = value; node.dispatchEvent(new Event("input", { bubbles: true })); } const startClaim = { name: "startClaim", match: node => node.classList.contains("antrag-starten"), execute: node => { const startenButton = node.querySelector('button.test-antrag-starten-button'); if (startenButton instanceof HTMLButtonElement) { startenButton.dispatchEvent(new Event('click', { bubbles: true })); return true; } return false; } } function fillBcnum(bcNumberInput) { browser.storage.sync.get('bcnum').then(v => { let bcNum = v.bcnum || null; if (bcNum !== null && bcNum !== "") { bcNumberInput.value = bcNum; bcNumberInput.dispatchEvent(new Event('input', { bubbles: true })); return true; } }) return false; } function fillBday(birthdayInput) { browser.storage.sync.get('bday').then(v => { const bDay = v.bday || null; if (bDay !== null && bDay !== "") { birthdayInput.value = bDay; birthdayInput.dispatchEvent(new Event('input', { bubbles: true })); return true; } }) return false; } const fillData = { name: "fillData", match: node => node.classList.contains("fahrgastrechte-bahn-card-auswahl"), execute: node => { let bcNumField, bdayField; node.querySelectorAll('input').forEach(e => { if (e.name === "fahrgastrechte-bahn-card-nummer") { bcNumField = e; } else if (e.name === "fahrgastrechte-bahn-card-auswahl-geburts-datum") { bdayField = e; } }) fillBcnum(bcNumField); fillBday(bdayField); return true; } } const clickContinue = { name: "clickContinue", match: () => true, execute: e => { const continueButton = document.querySelector('.fahrgastrechte-bahn-card-auswahl button.fahrgastrechte-continue-button'); if (continueButton instanceof Element) { continueButton.dispatchEvent(new Event('click')); return true; } return false; } } const iWasDelayed = { name: "iWasDelayed", match: node => node.classList.contains("antrags-typ-auswahl") && clickThroughForms, execute: node => { const delay = node.querySelector('input#antragstyp-verspaetung'); if (delay instanceof HTMLInputElement) { delay.dispatchEvent(new Event('change')); return true; } return false; } } const moreThan60Minutes = { name: "moreThan60Minutes", match: node => node.classList.contains("verspaetungs-auswahl") && clickThroughForms, execute: node => node.querySelector('#verspaetungstyp-mehr-als-stunde').dispatchEvent(new Event('change')) } const continueToForm = { name: "continueToForm", match: node => node.classList.contains("verspaetung-bestaetigung") && clickThroughForms, execute: node => node.querySelector('button.fahrgastrechte-continue-button').dispatchEvent(new Event('click', { bubbles: true })) } const enterPersonalData = { name: "enterPersonalData", match: node => node.classList.contains("persoenlicheangaben") && hasConfiguredPersonalData, execute: node => { browser.storage.sync.get(personalDataConfigKeys).then(foundKeys => { console.log("storage returned", foundKeys); //TODO the dropdowns are crazy // if (foundKeys.keys().contains("addr__appellation")){ // let dropDownSelectList = node.querySelector('.test-name-anrede ul.db-web-select-list'); // } const configKey_Selector = { "addr__firstName": ".test-name-vorname input", "addr__surName": ".test-name-nachname input", "addr__email": ".persoenlicheangaben__email input", "addr__street": ".test-adresse-strasse input", "addr__postcode": ".test-adresse-plz input", "addr__placename": ".test-adresse-ort input" } for (const [k, v] of Object.entries(foundKeys)) { if (Object.keys(configKey_Selector).includes(k)) { //TODO WIP this only works on some fields console.log("filling", configKey_Selector, "with", v); fillTextInput(node, configKey_Selector[k], v); } else { console.log("no selector found for config key", k); } } const continueBtn = document.querySelector(".fahrgastrechte-editable__buttons button.fahrgastrechte-continue-button"); if (continueBtn.querySelector("span span.db-web-button__label").textContent == "OK, weiter" && clickThroughForms) { continueBtn.dispatchEvent(new Event("click", { bubbles: true })); } return true; }) }, } const enterPaymentDetails = { name: "enterPaymentDetails", match: node => node.classList.contains("entschaedigung") && hasConfiguredBankDetails, execute: node => { node.querySelector('#ueberweisung').dispatchEvent(new Event('change')); browser.storage.sync.get(bankDetailConfigKeys).then(results => { console.log(results); for (const [k, v] of Object.entries(results)) { switch (k) { case "pymt__iban": fillTextInput(node, '.test-entschaedigung-iban input', v); break; case "pymt__bic": fillTextInput(node, '.test-entschaedigung-bic input', v); break; } } }) true }, } const defaultStages = [ startClaim, fillData, clickContinue, iWasDelayed, moreThan60Minutes, continueToForm, enterPersonalData, enterPaymentDetails ]; stages = defaultStages;