1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-18 09:13:33 +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 AutofillField from "../models/autofill-field";
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 {
@@ -708,6 +708,8 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
const formFieldElement = event.target as ElementWithOpId<FormFieldElement>;
const autofillFieldData = this.hiddenFormFieldElements.get(formFieldElement);
if (autofillFieldData) {
autofillFieldData.readonly = getAttributeBoolean(formFieldElement, "disabled");
autofillFieldData.disabled = getAttributeBoolean(formFieldElement, "disabled");
autofillFieldData.viewable = true;
void this.setupAutofillOverlayListenerOnField(formFieldElement, autofillFieldData);
}

View File

@@ -1,12 +1,7 @@
import AutofillField from "../models/autofill-field";
import AutofillForm from "../models/autofill-form";
import AutofillPageDetails from "../models/autofill-page-details";
import {
ElementWithOpId,
FillableFormFieldElement,
FormFieldElement,
FormElementWithAttribute,
} from "../types";
import { ElementWithOpId, FillableFormFieldElement, FormFieldElement } from "../types";
import {
elementIsDescriptionDetailsElement,
elementIsDescriptionTermElement,
@@ -19,6 +14,8 @@ import {
nodeIsElement,
elementIsInputElement,
elementIsTextAreaElement,
getAttributeBoolean,
getPropertyOrAttribute,
} from "../utils";
import { AutofillOverlayContentService } from "./abstractions/autofill-overlay-content.service";
@@ -33,6 +30,8 @@ import { DomElementVisibilityService } from "./abstractions/dom-element-visibili
class CollectAutofillContentService implements CollectAutofillContentServiceInterface {
private readonly domElementVisibilityService: DomElementVisibilityService;
private readonly autofillOverlayContentService: AutofillOverlayContentService;
private readonly getAttributeBoolean = getAttributeBoolean;
private readonly getPropertyOrAttribute = getPropertyOrAttribute;
private noFieldsFound = false;
private domRecentlyMutated = true;
private autofillFormElements: AutofillFormElements = new Map();
@@ -467,26 +466,6 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
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.
* @param {ElementWithOpId<FormFieldElement>} element
@@ -798,21 +777,6 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
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
* 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 { 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 randomChars = [];
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.
*/
function generateRandomCustomElementName(): string {
export function generateRandomCustomElementName(): string {
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
@@ -51,7 +51,7 @@ function generateRandomCustomElementName(): string {
* @param svgString - The SVG string to build the DOM element from.
* @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 svgDom = domParser.parseFromString(svgString, "image/svg+xml");
const domElement = svgDom.documentElement;
@@ -66,7 +66,7 @@ function buildSvgDomElement(svgString: string, ariaHidden = true): HTMLElement {
* @param command - The command to send.
* @param options - The options to send with the command.
*/
async function sendExtensionMessage(
export async function sendExtensionMessage(
command: string,
options: Record<string, any> = {},
): Promise<any | void> {
@@ -88,7 +88,7 @@ async function sendExtensionMessage(
* @param styles - The styles to set on the element.
* @param priority - Determines whether the styles should be set as important.
*/
function setElementStyles(
export function setElementStyles(
element: HTMLElement,
styles: Partial<CSSStyleDeclaration>,
priority?: boolean,
@@ -111,9 +111,9 @@ function setElementStyles(
* and triggers an onDisconnect event if the extension context
* 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 onDisconnectCallback = (disconnectedPort: chrome.runtime.Port) => {
callback(disconnectedPort);
@@ -128,7 +128,7 @@ function setupExtensionDisconnectAction(callback: (port: chrome.runtime.Port) =>
*
* @param windowContext - The global window context
*/
function setupAutofillInitDisconnectAction(windowContext: Window) {
export function setupAutofillInitDisconnectAction(windowContext: Window) {
if (!windowContext.bitwardenAutofillInit) {
return;
}
@@ -146,7 +146,7 @@ function setupAutofillInitDisconnectAction(windowContext: Window) {
*
* @param formFieldElement - The form field element to check.
*/
function elementIsFillableFormField(
export function elementIsFillableFormField(
formFieldElement: FormFieldElement,
): formFieldElement is FillableFormFieldElement {
return !elementIsSpanElement(formFieldElement);
@@ -158,7 +158,10 @@ function elementIsFillableFormField(
* @param element - The element to check.
* @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;
}
@@ -167,7 +170,7 @@ function elementIsInstanceOf<T extends Element>(element: Element, tagName: strin
*
* @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");
}
@@ -176,7 +179,7 @@ function elementIsSpanElement(element: Element): element is HTMLSpanElement {
*
* @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");
}
@@ -185,7 +188,7 @@ function elementIsInputElement(element: Element): element is HTMLInputElement {
*
* @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");
}
@@ -194,7 +197,7 @@ function elementIsSelectElement(element: Element): element is HTMLSelectElement
*
* @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");
}
@@ -203,7 +206,7 @@ function elementIsTextAreaElement(element: Element): element is HTMLTextAreaElem
*
* @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");
}
@@ -212,7 +215,7 @@ function elementIsFormElement(element: Element): element is HTMLFormElement {
*
* @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");
}
@@ -221,7 +224,7 @@ function elementIsLabelElement(element: Element): element is HTMLLabelElement {
*
* @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");
}
@@ -230,7 +233,7 @@ function elementIsDescriptionDetailsElement(element: Element): element is HTMLEl
*
* @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");
}
@@ -239,7 +242,7 @@ function elementIsDescriptionTermElement(element: Element): element is HTMLEleme
*
* @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;
}
@@ -248,7 +251,7 @@ function nodeIsElement(node: Node): node is Element {
*
* @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);
}
@@ -257,29 +260,39 @@ function nodeIsInputElement(node: Node): node is HTMLInputElement {
*
* @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);
}
export {
generateRandomChars,
generateRandomCustomElementName,
buildSvgDomElement,
sendExtensionMessage,
setElementStyles,
setupExtensionDisconnectAction,
setupAutofillInitDisconnectAction,
elementIsFillableFormField,
elementIsInstanceOf,
elementIsSpanElement,
elementIsInputElement,
elementIsSelectElement,
elementIsTextAreaElement,
elementIsFormElement,
elementIsLabelElement,
elementIsDescriptionDetailsElement,
elementIsDescriptionTermElement,
nodeIsElement,
nodeIsInputElement,
nodeIsFormElement,
};
/**
* Returns a boolean representing the attribute value of an element.
*
* @param element
* @param attributeName
* @param checkString
*/
export function getAttributeBoolean(
element: HTMLElement,
attributeName: string,
checkString = false,
): boolean {
if (checkString) {
return getPropertyOrAttribute(element, attributeName) === "true";
}
return Boolean(getPropertyOrAttribute(element, attributeName));
}
/**
* 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);
}