From f796c6fd044817466bface5e6c30a0896beac455 Mon Sep 17 00:00:00 2001 From: iw0 Date: Wed, 1 May 2024 14:53:27 +0200 Subject: [PATCH] choose your own adventure --- content_script.js | 72 +++++++++++++++++++++++++++++----------------- options/index.html | 10 +++++-- options/script.js | 6 ++-- 3 files changed, 55 insertions(+), 33 deletions(-) diff --git a/content_script.js b/content_script.js index b31cca7..2b10f28 100644 --- a/content_script.js +++ b/content_script.js @@ -1,6 +1,9 @@ "use strict"; // Put all the javascript code here, that you want to execute after page load. +/** + * @typedef ("delay"|"nodep"|"abort"|"") DisruptionType + */ /** * * @typedef {Object} Stage @@ -11,9 +14,14 @@ */ /** * @type Stage + * @todo this can now also contain a dict */ let currentStage; const settings = browser.storage.sync; +/** + * @type ("delay"|"nodep"|"abort"|"") + */ +let disruption = ""; /** * @@ -44,22 +52,6 @@ const pressKey = (...keys) => { d(new KeyboardEvent('keyup', { bubbles: true, key: k })); }) } -/** @param {Node} node */ -function executeStage(node) { - if (node.nodeType === 1) { - if (currentStage === undefined) { - currentStage = stages.shift(); - } - if (currentStage.match(node)) { - console.log(currentStage.name, "matched: ", node); - console.log(currentStage.name, currentStage.execute(node) ? "executed" : "execution failed"); - nextStage(); - } else { - console.log(currentStage.name, "did not match: ", mutation); - } - } -} - let stages; const personalDataConfigKeys = [ "addr__appellation", "addr__title", "addr__firstName", "addr__surName", @@ -88,6 +80,19 @@ function processMutations(mutationList, observer) { if (currentStage === undefined) { currentStage = stages.shift(); } + if (!("name" in currentStage)){ + // stages always have a `name`, so this must be the disruption type split + if (disruption in currentStage){ + stages.unshift(...currentStage[disruption]); + currentStage = stages.shift(); + } else if (disruption == "") { + // no default action - skip to personal data stuff + currentStage = stages.shift(); + //TODO sniff action and provide field jumps instead + } else { + console.log("this Stage is invalid, aborting", currentStage); + } + } for (const mutation of mutationList) { if ('expects' in currentStage) { if (currentStage.expects == 'mutation') { @@ -116,7 +121,6 @@ function processMutations(mutationList, observer) { } } -let clickThroughForms; let hasConfiguredBankDetails, hasConfiguredPersonalData; let observer = new MutationObserver(processMutations); function nextStage() { @@ -129,9 +133,9 @@ function nextStage() { } const addObserver = () => { settings.get( - ['autocontinue', 'enable'].concat(personalDataConfigKeys, bankDetailConfigKeys) + ['enable', 'defaultAction'].concat(personalDataConfigKeys, bankDetailConfigKeys) ).then(userSettings => { - clickThroughForms = !!userSettings.autocontinue; + disruption = userSettings.defaultAction || ""; hasConfiguredPersonalData = Object.keys(userSettings).filter(k => personalDataConfigKeys.includes(k)).length > 0; hasConfiguredBankDetails = Object.keys(userSettings).filter(k => bankDetailConfigKeys.includes(k)).length > 0; if (!!userSettings.enable) { @@ -231,9 +235,21 @@ const clickContinue = { } +//TODO construction zone +const sniffDisruption = { + name: "sniffDisruption", + match: node => { + //delay -> .verspaetungs-auswahl.fahrgastrechte-page__section.test-current-section + //nodep -> .fahrplan...., .antrags-typ-auswahl:children("input[name=radioAntragsTyp]"):id(#antragstyp-nicht-angetreten):has-siblings(.db-web-radio-button-container__radio-button-icon--checked) + //abort -> .fahrplan...., ...#antragstyp-abgebrochen, An welchem Bahnhof? -> .fahrgastrechte-page__section:has-child(.fahrgastrechte-editable.fahrgastrechte-bahnhof.abbruchbahnhof) + // Weitere Kosten? (.kosten-abfrage.f-p__s.t-c-s:has_child(.db-web-radio-button-container.kosten-abfrage__radio)) + }, + execute: () => true +} + const iWasDelayed = { name: "iWasDelayed", - match: node => node.classList.contains("antrags-typ-auswahl") && clickThroughForms, + match: node => node.classList.contains("antrags-typ-auswahl"), execute: node => { const delay = $$(node, 'input#antragstyp-verspaetung'); if (delay instanceof HTMLInputElement) { @@ -246,19 +262,21 @@ const iWasDelayed = { const moreThan60Minutes = { name: "moreThan60Minutes", - match: node => node.classList.contains("verspaetungs-auswahl") && clickThroughForms, - execute: node => node.querySelector('#verspaetungstyp-mehr-als-stunde').dispatchEvent(new Event('change')) + match: node => node.classList.contains("verspaetungs-auswahl"), + execute: node => { + return node.querySelector('#verspaetungstyp-mehr-als-stunde').dispatchEvent(new Event('change')); + } } const continueToForm = { name: "continueToForm", - match: node => node.classList.contains("verspaetung-bestaetigung") && clickThroughForms, + match: node => node.classList.contains("verspaetung-bestaetigung"), execute: node => $$(node, 'button.fahrgastrechte-continue-button').dispatchEvent(_clickEv()) } const focusDepartureInput = { name: "focusDepartureInput", - match: node => node.classList.contains("fahrplan") && clickThroughForms, + match: node => node.classList.contains("fahrplan"), execute: node => { const depInput = $$(node, '.fahrplan__start .fahrplan__haltestelle input'); const obs = new IntersectionObserver((entries, intObserver) => { @@ -274,7 +292,7 @@ const focusDepartureInput = { const jumpToTimeInput = { name: "jumpToTimeInput", - match: node => node.classList.contains("ankunft-zeit") && clickThroughForms, + match: node => node.classList.contains("ankunft-zeit"), execute: node => { $$(node, '#fahrgastrechte-ankunft-uhrzeit--db-web-text-input').focus(); return true; @@ -426,8 +444,8 @@ const enterPaymentDetails = { } const defaultStages = [ startClaim, fillData, clickContinue, - iWasDelayed, moreThan60Minutes, continueToForm, - focusDepartureInput, jumpToTimeInput, + {"delay": [iWasDelayed, moreThan60Minutes, continueToForm, + focusDepartureInput, jumpToTimeInput], "nodep": [], "abort": []}, activateAppellationDropdown, enterAppellationAndActivateTitleDropdown, enterTitleAndActivateCountryDropdown, enterCountry, enterTextPersonalData, /* continueToPayout, */ enterPaymentDetails diff --git a/options/index.html b/options/index.html index 33e2c4f..cf0bb7d 100644 --- a/options/index.html +++ b/options/index.html @@ -16,9 +16,13 @@ diff --git a/options/script.js b/options/script.js index 67224e1..afacfae 100644 --- a/options/script.js +++ b/options/script.js @@ -75,8 +75,8 @@ async function saveOptions(ev) { putError("Please enter a birthday."); return; } - let autoContinue = this.querySelector('#autocontinue').checked; let enable = this.querySelector('#enable').checked; + let defaultAction = this.querySelector('#default_action').value; let title = this.querySelector('#title').value; let title_addl = this.querySelector('#title_addl').value; let firstName = this.querySelector('#firstname').value; @@ -95,8 +95,8 @@ async function saveOptions(ev) { let options = { bcnum: bcNum, bday: bDay, - autocontinue: autoContinue, enable: enable, + defaultAction: defaultAction, addr__appellation: title, addr__title: title_addl, addr__firstName: firstName, @@ -131,7 +131,7 @@ async function restoreOptions() { document.querySelector('#enable').checked = settings.enable || true; document.querySelector("#bcnum").value = settings.bcnum || ""; document.querySelector("#birthday").value = settings.bday || ""; - document.querySelector("#autocontinue").checked = settings.autocontinue || false; + document.querySelector("#default_action").value = settings.defaultAction || ""; document.querySelector('#title').value = settings.addr__appellation || ""; document.querySelector('#title_addl').value = settings.addr__title || ""; document.querySelector('#firstname').value = settings.addr__firstName || "";