Fix Copy Custom Field Name on pages with iframes (#2091)
* Improve error messages * Send getClickedElement msg to specific frameId * Add support for finding input element from label * Use i18n for error messages * Fix unrelated linting
This commit is contained in:
parent
bbcbcf2b40
commit
cffd4b3515
|
@ -1807,5 +1807,11 @@
|
|||
},
|
||||
"personalVaultExportPolicyInEffect": {
|
||||
"message": "One or more organization policies prevents you from exporting your personal vault."
|
||||
},
|
||||
"copyCustomFieldNameInvalidElement": {
|
||||
"message": "Unable to identify a valid form element. Try inspecting the HTML instead."
|
||||
},
|
||||
"copyCustomFieldNameNotUnique": {
|
||||
"message": "No unique identifier found."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ export default class ContextMenusBackground {
|
|||
if (info.menuItemId === 'generate-password') {
|
||||
await this.generatePasswordToClipboard();
|
||||
} else if (info.menuItemId === 'copy-identifier') {
|
||||
await this.getClickedElement();
|
||||
await this.getClickedElement(info.frameId);
|
||||
} else if (info.parentMenuItemId === 'autofill' ||
|
||||
info.parentMenuItemId === 'copy-username' ||
|
||||
info.parentMenuItemId === 'copy-password' ||
|
||||
|
@ -47,13 +47,13 @@ export default class ContextMenusBackground {
|
|||
this.passwordGenerationService.addHistory(password);
|
||||
}
|
||||
|
||||
private async getClickedElement() {
|
||||
private async getClickedElement(frameId: number) {
|
||||
const tab = await BrowserApi.getTabFromCurrentWindow();
|
||||
if (tab == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
BrowserApi.tabSendMessageData(tab, 'getClickedElement');
|
||||
BrowserApi.tabSendMessage(tab, { command: 'getClickedElement' }, { frameId: frameId });
|
||||
}
|
||||
|
||||
private async cipherAction(info: any) {
|
||||
|
|
|
@ -1,25 +1,49 @@
|
|||
const inputTags = ['input', 'textarea', 'select'];
|
||||
const labelTags = ['label', 'span'];
|
||||
const attributes = ['id', 'name', 'label-aria', 'placeholder'];
|
||||
const invalidElement = chrome.i18n.getMessage('copyCustomFieldNameInvalidElement');
|
||||
const noUniqueIdentifier = chrome.i18n.getMessage('copyCustomFieldNameNotUnique');
|
||||
|
||||
let clickedEl: HTMLElement = null;
|
||||
|
||||
// Find the best attribute to be used as the Name for an element in a custom field.
|
||||
function getClickedElementIdentifier() {
|
||||
if (clickedEl == null) {
|
||||
return 'Unable to identify clicked element.';
|
||||
return invalidElement;
|
||||
}
|
||||
|
||||
if (!inputTags.includes(clickedEl.nodeName.toLowerCase())) {
|
||||
return 'Invalid element type.';
|
||||
const tagName = clickedEl.nodeName.toLowerCase();
|
||||
let inputEl = null;
|
||||
|
||||
// Try to identify the input element (which may not be the clicked element)
|
||||
if (inputTags.includes(tagName)) {
|
||||
inputEl = clickedEl;
|
||||
} else if (labelTags.includes(tagName)) {
|
||||
let inputName = null;
|
||||
if (tagName === 'label') {
|
||||
inputName = clickedEl.getAttribute('for');
|
||||
} else {
|
||||
inputName = clickedEl.closest('label')?.getAttribute('for');
|
||||
}
|
||||
|
||||
if (inputName != null) {
|
||||
inputEl = document.querySelector('input[name=' + inputName + '], select[name=' + inputName +
|
||||
'], textarea[name=' + inputName + ']');
|
||||
}
|
||||
}
|
||||
|
||||
if (inputEl == null) {
|
||||
return invalidElement;
|
||||
}
|
||||
|
||||
for (const attr of attributes) {
|
||||
const attributeValue = clickedEl.getAttribute(attr);
|
||||
const attributeValue = inputEl.getAttribute(attr);
|
||||
const selector = '[' + attr + '="' + attributeValue + '"]';
|
||||
if (!isNullOrEmpty(attributeValue) && document.querySelectorAll(selector)?.length === 1) {
|
||||
return attributeValue;
|
||||
}
|
||||
}
|
||||
return 'No unique identifier found.';
|
||||
return noUniqueIdentifier;
|
||||
}
|
||||
|
||||
function isNullOrEmpty(s: string) {
|
||||
|
|
|
@ -62,6 +62,7 @@ import { StateService } from 'jslib-common/services/state.service';
|
|||
|
||||
import { PopupSearchService } from './popup-search.service';
|
||||
import { PopupUtilsService } from './popup-utils.service';
|
||||
|
||||
import { ThemeType } from 'jslib-common/enums/themeType';
|
||||
|
||||
function getBgService<T>(service: string) {
|
||||
|
|
|
@ -3,6 +3,7 @@ import {
|
|||
OnInit,
|
||||
} from '@angular/core';
|
||||
|
||||
import { ThemeType } from 'jslib-common/enums/themeType';
|
||||
import { UriMatchType } from 'jslib-common/enums/uriMatchType';
|
||||
|
||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||
|
@ -12,7 +13,6 @@ import { StorageService } from 'jslib-common/abstractions/storage.service';
|
|||
import { TotpService } from 'jslib-common/abstractions/totp.service';
|
||||
|
||||
import { ConstantsService } from 'jslib-common/services/constants.service';
|
||||
import { ThemeType } from 'jslib-common/enums/themeType';
|
||||
|
||||
@Component({
|
||||
selector: 'app-options',
|
||||
|
|
Loading…
Reference in New Issue