1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-18 17:23:37 +00:00

[PM-5189] Extracting the getAttributeBoolean method to a separate util method

This commit is contained in:
Cesar Gonzalez
2024-04-11 09:53:04 -05:00
parent 03da6d8ef2
commit 9a9a973ef0
3 changed files with 65 additions and 86 deletions

View File

@@ -12,7 +12,7 @@ import {
import { AutofillExtensionMessage } from "../content/abstractions/autofill-init"; import { AutofillExtensionMessage } from "../content/abstractions/autofill-init";
import AutofillField from "../models/autofill-field"; import AutofillField from "../models/autofill-field";
import { ElementWithOpId, FillableFormFieldElement, FormFieldElement } from "../types"; import { ElementWithOpId, FillableFormFieldElement, FormFieldElement } from "../types";
import { elementIsFillableFormField, sendExtensionMessage } from "../utils"; import { elementIsFillableFormField, getAttributeBoolean, sendExtensionMessage } from "../utils";
import { AutofillOverlayElement, RedirectFocusDirection } from "../utils/autofill-overlay.enum"; import { AutofillOverlayElement, RedirectFocusDirection } from "../utils/autofill-overlay.enum";
import { import {
@@ -708,6 +708,8 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
const formFieldElement = event.target as ElementWithOpId<FormFieldElement>; const formFieldElement = event.target as ElementWithOpId<FormFieldElement>;
const autofillFieldData = this.hiddenFormFieldElements.get(formFieldElement); const autofillFieldData = this.hiddenFormFieldElements.get(formFieldElement);
if (autofillFieldData) { if (autofillFieldData) {
autofillFieldData.readonly = getAttributeBoolean(formFieldElement, "disabled");
autofillFieldData.disabled = getAttributeBoolean(formFieldElement, "disabled");
autofillFieldData.viewable = true; autofillFieldData.viewable = true;
void this.setupAutofillOverlayListenerOnField(formFieldElement, autofillFieldData); void this.setupAutofillOverlayListenerOnField(formFieldElement, autofillFieldData);
} }

View File

@@ -1,12 +1,7 @@
import AutofillField from "../models/autofill-field"; import AutofillField from "../models/autofill-field";
import AutofillForm from "../models/autofill-form"; import AutofillForm from "../models/autofill-form";
import AutofillPageDetails from "../models/autofill-page-details"; import AutofillPageDetails from "../models/autofill-page-details";
import { import { ElementWithOpId, FillableFormFieldElement, FormFieldElement } from "../types";
ElementWithOpId,
FillableFormFieldElement,
FormFieldElement,
FormElementWithAttribute,
} from "../types";
import { import {
elementIsDescriptionDetailsElement, elementIsDescriptionDetailsElement,
elementIsDescriptionTermElement, elementIsDescriptionTermElement,
@@ -19,6 +14,8 @@ import {
nodeIsElement, nodeIsElement,
elementIsInputElement, elementIsInputElement,
elementIsTextAreaElement, elementIsTextAreaElement,
getAttributeBoolean,
getPropertyOrAttribute,
} from "../utils"; } from "../utils";
import { AutofillOverlayContentService } from "./abstractions/autofill-overlay-content.service"; import { AutofillOverlayContentService } from "./abstractions/autofill-overlay-content.service";
@@ -33,6 +30,8 @@ import { DomElementVisibilityService } from "./abstractions/dom-element-visibili
class CollectAutofillContentService implements CollectAutofillContentServiceInterface { class CollectAutofillContentService implements CollectAutofillContentServiceInterface {
private readonly domElementVisibilityService: DomElementVisibilityService; private readonly domElementVisibilityService: DomElementVisibilityService;
private readonly autofillOverlayContentService: AutofillOverlayContentService; private readonly autofillOverlayContentService: AutofillOverlayContentService;
private readonly getAttributeBoolean = getAttributeBoolean;
private readonly getPropertyOrAttribute = getPropertyOrAttribute;
private noFieldsFound = false; private noFieldsFound = false;
private domRecentlyMutated = true; private domRecentlyMutated = true;
private autofillFormElements: AutofillFormElements = new Map(); private autofillFormElements: AutofillFormElements = new Map();
@@ -467,26 +466,6 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
return autoCompleteType !== "off" ? autoCompleteType : null; return autoCompleteType !== "off" ? autoCompleteType : null;
} }
/**
* Returns a boolean representing the attribute value of an element.
* @param {ElementWithOpId<FormFieldElement>} element
* @param {string} attributeName
* @param {boolean} checkString
* @returns {boolean}
* @private
*/
private getAttributeBoolean(
element: ElementWithOpId<FormFieldElement>,
attributeName: string,
checkString = false,
): boolean {
if (checkString) {
return this.getPropertyOrAttribute(element, attributeName) === "true";
}
return Boolean(this.getPropertyOrAttribute(element, attributeName));
}
/** /**
* Returns the attribute of an element as a lowercase value. * Returns the attribute of an element as a lowercase value.
* @param {ElementWithOpId<FormFieldElement>} element * @param {ElementWithOpId<FormFieldElement>} element
@@ -798,21 +777,6 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
return this.recursivelyGetTextFromPreviousSiblings(siblingElement); return this.recursivelyGetTextFromPreviousSiblings(siblingElement);
} }
/**
* Get the value of a property or attribute from a FormFieldElement.
* @param {HTMLElement} element
* @param {string} attributeName
* @returns {string | null}
* @private
*/
private getPropertyOrAttribute(element: HTMLElement, attributeName: string): string | null {
if (attributeName in element) {
return (element as FormElementWithAttribute)[attributeName];
}
return element.getAttribute(attributeName);
}
/** /**
* Gets the value of the element. If the element is a checkbox, returns a checkmark if the * Gets the value of the element. If the element is a checkbox, returns a checkmark if the
* checkbox is checked, or an empty string if it is not checked. If the element is a hidden * checkbox is checked, or an empty string if it is not checked. If the element is a hidden

View File

@@ -1,7 +1,7 @@
import { AutofillPort } from "../enums/autofill-port.enums"; import { AutofillPort } from "../enums/autofill-port.enums";
import { FillableFormFieldElement, FormFieldElement } from "../types"; import { FillableFormFieldElement, FormElementWithAttribute, FormFieldElement } from "../types";
function generateRandomChars(length: number): string { export function generateRandomChars(length: number): string {
const chars = "abcdefghijklmnopqrstuvwxyz"; const chars = "abcdefghijklmnopqrstuvwxyz";
const randomChars = []; const randomChars = [];
const randomBytes = new Uint8Array(length); const randomBytes = new Uint8Array(length);
@@ -18,7 +18,7 @@ function generateRandomChars(length: number): string {
/** /**
* Generates a random string of characters that formatted as a custom element name. * Generates a random string of characters that formatted as a custom element name.
*/ */
function generateRandomCustomElementName(): string { export function generateRandomCustomElementName(): string {
const length = Math.floor(Math.random() * 5) + 8; // Between 8 and 12 characters const length = Math.floor(Math.random() * 5) + 8; // Between 8 and 12 characters
const numHyphens = Math.min(Math.max(Math.floor(Math.random() * 4), 1), length - 1); // At least 1, maximum of 3 hyphens const numHyphens = Math.min(Math.max(Math.floor(Math.random() * 4), 1), length - 1); // At least 1, maximum of 3 hyphens
@@ -51,7 +51,7 @@ function generateRandomCustomElementName(): string {
* @param svgString - The SVG string to build the DOM element from. * @param svgString - The SVG string to build the DOM element from.
* @param ariaHidden - Determines whether the SVG should be hidden from screen readers. * @param ariaHidden - Determines whether the SVG should be hidden from screen readers.
*/ */
function buildSvgDomElement(svgString: string, ariaHidden = true): HTMLElement { export function buildSvgDomElement(svgString: string, ariaHidden = true): HTMLElement {
const domParser = new DOMParser(); const domParser = new DOMParser();
const svgDom = domParser.parseFromString(svgString, "image/svg+xml"); const svgDom = domParser.parseFromString(svgString, "image/svg+xml");
const domElement = svgDom.documentElement; const domElement = svgDom.documentElement;
@@ -66,7 +66,7 @@ function buildSvgDomElement(svgString: string, ariaHidden = true): HTMLElement {
* @param command - The command to send. * @param command - The command to send.
* @param options - The options to send with the command. * @param options - The options to send with the command.
*/ */
async function sendExtensionMessage( export async function sendExtensionMessage(
command: string, command: string,
options: Record<string, any> = {}, options: Record<string, any> = {},
): Promise<any | void> { ): Promise<any | void> {
@@ -88,7 +88,7 @@ async function sendExtensionMessage(
* @param styles - The styles to set on the element. * @param styles - The styles to set on the element.
* @param priority - Determines whether the styles should be set as important. * @param priority - Determines whether the styles should be set as important.
*/ */
function setElementStyles( export function setElementStyles(
element: HTMLElement, element: HTMLElement,
styles: Partial<CSSStyleDeclaration>, styles: Partial<CSSStyleDeclaration>,
priority?: boolean, priority?: boolean,
@@ -111,9 +111,9 @@ function setElementStyles(
* and triggers an onDisconnect event if the extension context * and triggers an onDisconnect event if the extension context
* is invalidated. * is invalidated.
* *
* @param callback - Callback function to run when the extension disconnects * @param callback - Callback export function to run when the extension disconnects
*/ */
function setupExtensionDisconnectAction(callback: (port: chrome.runtime.Port) => void) { export function setupExtensionDisconnectAction(callback: (port: chrome.runtime.Port) => void) {
const port = chrome.runtime.connect({ name: AutofillPort.InjectedScript }); const port = chrome.runtime.connect({ name: AutofillPort.InjectedScript });
const onDisconnectCallback = (disconnectedPort: chrome.runtime.Port) => { const onDisconnectCallback = (disconnectedPort: chrome.runtime.Port) => {
callback(disconnectedPort); callback(disconnectedPort);
@@ -128,7 +128,7 @@ function setupExtensionDisconnectAction(callback: (port: chrome.runtime.Port) =>
* *
* @param windowContext - The global window context * @param windowContext - The global window context
*/ */
function setupAutofillInitDisconnectAction(windowContext: Window) { export function setupAutofillInitDisconnectAction(windowContext: Window) {
if (!windowContext.bitwardenAutofillInit) { if (!windowContext.bitwardenAutofillInit) {
return; return;
} }
@@ -146,7 +146,7 @@ function setupAutofillInitDisconnectAction(windowContext: Window) {
* *
* @param formFieldElement - The form field element to check. * @param formFieldElement - The form field element to check.
*/ */
function elementIsFillableFormField( export function elementIsFillableFormField(
formFieldElement: FormFieldElement, formFieldElement: FormFieldElement,
): formFieldElement is FillableFormFieldElement { ): formFieldElement is FillableFormFieldElement {
return !elementIsSpanElement(formFieldElement); return !elementIsSpanElement(formFieldElement);
@@ -158,7 +158,10 @@ function elementIsFillableFormField(
* @param element - The element to check. * @param element - The element to check.
* @param tagName - The tag name to check against. * @param tagName - The tag name to check against.
*/ */
function elementIsInstanceOf<T extends Element>(element: Element, tagName: string): element is T { export function elementIsInstanceOf<T extends Element>(
element: Element,
tagName: string,
): element is T {
return nodeIsElement(element) && element.tagName.toLowerCase() === tagName; return nodeIsElement(element) && element.tagName.toLowerCase() === tagName;
} }
@@ -167,7 +170,7 @@ function elementIsInstanceOf<T extends Element>(element: Element, tagName: strin
* *
* @param element - The element to check. * @param element - The element to check.
*/ */
function elementIsSpanElement(element: Element): element is HTMLSpanElement { export function elementIsSpanElement(element: Element): element is HTMLSpanElement {
return elementIsInstanceOf<HTMLSpanElement>(element, "span"); return elementIsInstanceOf<HTMLSpanElement>(element, "span");
} }
@@ -176,7 +179,7 @@ function elementIsSpanElement(element: Element): element is HTMLSpanElement {
* *
* @param element - The element to check. * @param element - The element to check.
*/ */
function elementIsInputElement(element: Element): element is HTMLInputElement { export function elementIsInputElement(element: Element): element is HTMLInputElement {
return elementIsInstanceOf<HTMLInputElement>(element, "input"); return elementIsInstanceOf<HTMLInputElement>(element, "input");
} }
@@ -185,7 +188,7 @@ function elementIsInputElement(element: Element): element is HTMLInputElement {
* *
* @param element - The element to check. * @param element - The element to check.
*/ */
function elementIsSelectElement(element: Element): element is HTMLSelectElement { export function elementIsSelectElement(element: Element): element is HTMLSelectElement {
return elementIsInstanceOf<HTMLSelectElement>(element, "select"); return elementIsInstanceOf<HTMLSelectElement>(element, "select");
} }
@@ -194,7 +197,7 @@ function elementIsSelectElement(element: Element): element is HTMLSelectElement
* *
* @param element - The element to check. * @param element - The element to check.
*/ */
function elementIsTextAreaElement(element: Element): element is HTMLTextAreaElement { export function elementIsTextAreaElement(element: Element): element is HTMLTextAreaElement {
return elementIsInstanceOf<HTMLTextAreaElement>(element, "textarea"); return elementIsInstanceOf<HTMLTextAreaElement>(element, "textarea");
} }
@@ -203,7 +206,7 @@ function elementIsTextAreaElement(element: Element): element is HTMLTextAreaElem
* *
* @param element - The element to check. * @param element - The element to check.
*/ */
function elementIsFormElement(element: Element): element is HTMLFormElement { export function elementIsFormElement(element: Element): element is HTMLFormElement {
return elementIsInstanceOf<HTMLFormElement>(element, "form"); return elementIsInstanceOf<HTMLFormElement>(element, "form");
} }
@@ -212,7 +215,7 @@ function elementIsFormElement(element: Element): element is HTMLFormElement {
* *
* @param element - The element to check. * @param element - The element to check.
*/ */
function elementIsLabelElement(element: Element): element is HTMLLabelElement { export function elementIsLabelElement(element: Element): element is HTMLLabelElement {
return elementIsInstanceOf<HTMLLabelElement>(element, "label"); return elementIsInstanceOf<HTMLLabelElement>(element, "label");
} }
@@ -221,7 +224,7 @@ function elementIsLabelElement(element: Element): element is HTMLLabelElement {
* *
* @param element - The element to check. * @param element - The element to check.
*/ */
function elementIsDescriptionDetailsElement(element: Element): element is HTMLElement { export function elementIsDescriptionDetailsElement(element: Element): element is HTMLElement {
return elementIsInstanceOf<HTMLElement>(element, "dd"); return elementIsInstanceOf<HTMLElement>(element, "dd");
} }
@@ -230,7 +233,7 @@ function elementIsDescriptionDetailsElement(element: Element): element is HTMLEl
* *
* @param element - The element to check. * @param element - The element to check.
*/ */
function elementIsDescriptionTermElement(element: Element): element is HTMLElement { export function elementIsDescriptionTermElement(element: Element): element is HTMLElement {
return elementIsInstanceOf<HTMLElement>(element, "dt"); return elementIsInstanceOf<HTMLElement>(element, "dt");
} }
@@ -239,7 +242,7 @@ function elementIsDescriptionTermElement(element: Element): element is HTMLEleme
* *
* @param node - The node to check. * @param node - The node to check.
*/ */
function nodeIsElement(node: Node): node is Element { export function nodeIsElement(node: Node): node is Element {
return node?.nodeType === Node.ELEMENT_NODE; return node?.nodeType === Node.ELEMENT_NODE;
} }
@@ -248,7 +251,7 @@ function nodeIsElement(node: Node): node is Element {
* *
* @param node - The node to check. * @param node - The node to check.
*/ */
function nodeIsInputElement(node: Node): node is HTMLInputElement { export function nodeIsInputElement(node: Node): node is HTMLInputElement {
return nodeIsElement(node) && elementIsInputElement(node); return nodeIsElement(node) && elementIsInputElement(node);
} }
@@ -257,29 +260,39 @@ function nodeIsInputElement(node: Node): node is HTMLInputElement {
* *
* @param node - The node to check. * @param node - The node to check.
*/ */
function nodeIsFormElement(node: Node): node is HTMLFormElement { export function nodeIsFormElement(node: Node): node is HTMLFormElement {
return nodeIsElement(node) && elementIsFormElement(node); return nodeIsElement(node) && elementIsFormElement(node);
} }
export { /**
generateRandomChars, * Returns a boolean representing the attribute value of an element.
generateRandomCustomElementName, *
buildSvgDomElement, * @param element
sendExtensionMessage, * @param attributeName
setElementStyles, * @param checkString
setupExtensionDisconnectAction, */
setupAutofillInitDisconnectAction, export function getAttributeBoolean(
elementIsFillableFormField, element: HTMLElement,
elementIsInstanceOf, attributeName: string,
elementIsSpanElement, checkString = false,
elementIsInputElement, ): boolean {
elementIsSelectElement, if (checkString) {
elementIsTextAreaElement, return getPropertyOrAttribute(element, attributeName) === "true";
elementIsFormElement, }
elementIsLabelElement,
elementIsDescriptionDetailsElement, return Boolean(getPropertyOrAttribute(element, attributeName));
elementIsDescriptionTermElement, }
nodeIsElement,
nodeIsInputElement, /**
nodeIsFormElement, * Get the value of a property or attribute from a FormFieldElement.
}; *
* @param element
* @param attributeName
*/
export function getPropertyOrAttribute(element: HTMLElement, attributeName: string): string | null {
if (attributeName in element) {
return (element as FormElementWithAttribute)[attributeName];
}
return element.getAttribute(attributeName);
}