diff options
Diffstat (limited to 'toolkit/components/satchel/FormScenarios.sys.mjs')
-rw-r--r-- | toolkit/components/satchel/FormScenarios.sys.mjs | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/toolkit/components/satchel/FormScenarios.sys.mjs b/toolkit/components/satchel/FormScenarios.sys.mjs new file mode 100644 index 0000000000..505b5443ec --- /dev/null +++ b/toolkit/components/satchel/FormScenarios.sys.mjs @@ -0,0 +1,87 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { FormLikeFactory } from "resource://gre/modules/FormLikeFactory.sys.mjs"; +import { SignUpFormRuleset } from "resource://gre/modules/SignUpFormRuleset.sys.mjs"; +import { FirefoxRelayUtils } from "resource://gre/modules/FirefoxRelayUtils.sys.mjs"; +import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs"; + +export class FormScenarios { + /** + * Caches the scores when running the SignUpFormRuleset against a form + */ + static #cachedSignUpFormScore = new WeakMap(); + + /** + * Detect usage scenarios of the form. + * + * @param {object} options named options + * @param {HTMLInputElement} [options.input] where current focus is + * @param {FormLike} [options.form] + * + * @returns {Array<string>} detected scenario names + */ + static detect({ input, form }) { + const scenarios = {}; + + if (!FormScenarios.signupDetectionEnabled) { + return scenarios; + } + + // Running simple heuristics first, because running the SignUpFormRuleset is expensive + if ( + input && + // At the moment Relay integration is the only interested party in "sign up form", + // so we optimize a bit by checking if it's enabled or not. + FirefoxRelayUtils.isRelayInterestedField(input) + ) { + form ??= FormLikeFactory.findRootForField(input); + + scenarios.signUpForm = FormScenarios.#isProbablyASignUpForm(form); + } + + return scenarios; + } + + /** + * Determine if the form is a sign-up form. + * This is done by running the rules of the Fathom SignUpFormRuleset against the form and calucating a score between 0 and 1. + * It's considered a sign-up form, if the score is higher than the confidence threshold (default=0.75) + * + * @param {HTMLFormElement} formElement + * @returns {boolean} returns true if the calculcated score is higher than the confidenceThreshold + */ + static #isProbablyASignUpForm(formElement) { + let score = FormScenarios.#cachedSignUpFormScore.get(formElement); + if (!score) { + TelemetryStopwatch.start("PWMGR_SIGNUP_FORM_DETECTION_MS"); + try { + const { rules, type } = SignUpFormRuleset; + const results = rules.against(formElement); + score = results.get(formElement).scoreFor(type); + TelemetryStopwatch.finish("PWMGR_SIGNUP_FORM_DETECTION_MS"); + } finally { + if (TelemetryStopwatch.running("PWMGR_SIGNUP_FORM_DETECTION_MS")) { + TelemetryStopwatch.cancel("PWMGR_SIGNUP_FORM_DETECTION_MS"); + } + } + FormScenarios.#cachedSignUpFormScore.set(formElement, score); + } + + const threshold = FormScenarios.signupDetectionConfidenceThreshold; + return score > threshold; + } +} +XPCOMUtils.defineLazyPreferenceGetter( + FormScenarios, + "signupDetectionConfidenceThreshold", + "signon.signupDetection.confidenceThreshold", + "0.75" +); +XPCOMUtils.defineLazyPreferenceGetter( + FormScenarios, + "signupDetectionEnabled", + "signon.signupDetection.enabled", + true +); |