From b09c4cb0841e927a4fb82c262d9a81630d5685a7 Mon Sep 17 00:00:00 2001 From: Parkreiner Date: Tue, 25 Jun 2024 21:35:53 +0000 Subject: [PATCH] fix: speed up code for filling in form --- windows-rdp/devolutions-patch.js | 99 +++++++++----------------------- 1 file changed, 28 insertions(+), 71 deletions(-) diff --git a/windows-rdp/devolutions-patch.js b/windows-rdp/devolutions-patch.js index c9e25da..86198a8 100644 --- a/windows-rdp/devolutions-patch.js +++ b/windows-rdp/devolutions-patch.js @@ -74,9 +74,9 @@ const formFieldEntries = { }; /** - * Handles typing in the values for the input form, dispatching each character - * as an event. This function assumes that all characters in the input will be - * UTF-8. + * Handles typing in the values for the input form. All values are written + * immediately, even though that would be physically impossible with a real + * keyboard. * * Note: this code will never break, but you might get warnings in the console * from Angular about unexpected value changes. Angular patches over a lot of @@ -94,75 +94,32 @@ const formFieldEntries = { * @returns {Promise} */ function setInputValue(inputField, inputText) { - const continueEventName = "coder-patch--continue"; - - const keyboardInputPromise = /** @type {Promise} */ ( - new Promise((resolve, reject) => { - if (inputText === "") { - resolve(); - return; - } - - // -1 indicates a "pre-write" for clearing out the input before trying to - // write new text to it - let i = -1; - - // requestAnimationFrame is not capable of giving back values of 0 for its - // task IDs. Good default value to ensure that we don't need if statements - // when trying to cancel anything - let currentAnimationId = 0; - - // Super easy to pool the same event objects, because the events don't - // have any custom, context-specific values on them, and they're - // restricted to this one callback. - const continueEvent = new CustomEvent(continueEventName); - const inputEvent = new Event("input", { - bubbles: true, - cancelable: true, - }); - - /** @returns {void} */ - const handleNextCharIndex = () => { - if (i === inputText.length) { - resolve(); - return; - } - - const currentChar = inputText[i]; - if (i !== -1 && currentChar === undefined) { - throw new Error("Went out of bounds"); - } - - try { - inputField.addEventListener( - continueEventName, - () => { - i++; - currentAnimationId = - window.requestAnimationFrame(handleNextCharIndex); - }, - { once: true }, - ); - - if (i === -1) { - inputField.value = ""; - } else { - inputField.value = inputField.value + currentChar; - } - - inputField.dispatchEvent(inputEvent); - inputField.dispatchEvent(continueEvent); - } catch (err) { - cancelAnimationFrame(currentAnimationId); - reject(err); - } - }; - - currentAnimationId = window.requestAnimationFrame(handleNextCharIndex); - }) - ); + return new Promise((resolve, reject) => { + // Adding timeout for input event, even though we'll be dispatching it + // immediately, just in the off chance that something in the Angular app + // intercepts it or stops it from propagating properly + const timeoutId = window.setTimeout(() => { + reject(new Error("Input event did not get processed correctly in time.")); + }, 3_000); + + const handleSuccessfulDispatch = () => { + resolve(); + window.clearTimeout(timeoutId); + inputField.removeEventListener("input", handleSuccessfulDispatch); + }; + + inputField.addEventListener("input", handleSuccessfulDispatch); + + // Code assumes that Angular will have an event handler in place to handle + // the new event + const inputEvent = new Event("input", { + bubbles: true, + cancelable: true, + }); - return keyboardInputPromise; + inputField.value = inputText; + inputField.dispatchEvent(inputEvent); + }); } /**