mirror of
https://github.com/bitwarden/browser.git
synced 2024-12-21 16:18:28 +01:00
Add new context menu item: Copy Custom Field Name (#2045)
* Add "Copy custom field name" context menu item * Title case context menu string * Improve Copy Custom Field Name logic * Move CopyClickedElement to runtime.background * Update dependencies * Add comments, refactor logic, add failure messages * Fix typo and linting * Fix typos * Move null check inside function
This commit is contained in:
parent
ca03703f9d
commit
0bd22dcddc
@ -88,6 +88,9 @@
|
||||
"generatePasswordCopied": {
|
||||
"message": "Generate Password (copied)"
|
||||
},
|
||||
"copyElementIdentifier": {
|
||||
"message": "Copy Custom Field Name"
|
||||
},
|
||||
"noMatchingLogins": {
|
||||
"message": "No matching logins."
|
||||
},
|
||||
|
@ -29,6 +29,8 @@ export default class ContextMenusBackground {
|
||||
this.contextMenus.onClicked.addListener(async (info: any, tab: any) => {
|
||||
if (info.menuItemId === 'generate-password') {
|
||||
await this.generatePasswordToClipboard();
|
||||
} else if (info.menuItemId === 'copy-identifier') {
|
||||
await this.getClickedElement();
|
||||
} else if (info.parentMenuItemId === 'autofill' ||
|
||||
info.parentMenuItemId === 'copy-username' ||
|
||||
info.parentMenuItemId === 'copy-password' ||
|
||||
@ -45,6 +47,15 @@ export default class ContextMenusBackground {
|
||||
this.passwordGenerationService.addHistory(password);
|
||||
}
|
||||
|
||||
private async getClickedElement() {
|
||||
const tab = await BrowserApi.getTabFromCurrentWindow();
|
||||
if (tab == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
BrowserApi.tabSendMessageData(tab, 'getClickedElement');
|
||||
}
|
||||
|
||||
private async cipherAction(info: any) {
|
||||
const id = info.menuItemId.split('_')[1];
|
||||
if (id === 'noop') {
|
||||
|
@ -512,6 +512,14 @@ export default class MainBackground {
|
||||
title: this.i18nService.t('generatePasswordCopied'),
|
||||
});
|
||||
|
||||
await this.contextMenusCreate({
|
||||
type: 'normal',
|
||||
id: 'copy-identifier',
|
||||
parentId: 'root',
|
||||
contexts: ['all'],
|
||||
title: this.i18nService.t('copyElementIdentifier'),
|
||||
});
|
||||
|
||||
this.buildingContextMenu = false;
|
||||
}
|
||||
|
||||
|
@ -195,6 +195,8 @@ export default class RuntimeBackground {
|
||||
type: 'info',
|
||||
});
|
||||
break;
|
||||
case 'getClickedElementResponse':
|
||||
this.platformUtilsService.copyToClipboard(msg.identifier, { window: window });
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
45
src/content/contextMenuHandler.ts
Normal file
45
src/content/contextMenuHandler.ts
Normal file
@ -0,0 +1,45 @@
|
||||
const inputTags = ['input', 'textarea', 'select'];
|
||||
const attributes = ['id', 'name', 'label-aria', 'placeholder'];
|
||||
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.'
|
||||
}
|
||||
|
||||
if (!inputTags.includes(clickedEl.nodeName.toLowerCase())) {
|
||||
return 'Invalid element type.';
|
||||
}
|
||||
|
||||
for (const attr of attributes) {
|
||||
const attributeValue = clickedEl.getAttribute(attr);
|
||||
const selector = '[' + attr + '="' + attributeValue + '"]';
|
||||
if (!isNullOrEmpty(attributeValue) && document.querySelectorAll(selector)?.length === 1) {
|
||||
return attributeValue;
|
||||
}
|
||||
}
|
||||
return 'No unique identifier found.';
|
||||
}
|
||||
|
||||
function isNullOrEmpty(s: string) {
|
||||
return s == null || s === '';
|
||||
}
|
||||
|
||||
// We only have access to the element that's been clicked when the context menu is first opened.
|
||||
// Remember it for use later.
|
||||
document.addEventListener('contextmenu', event => {
|
||||
clickedEl = event.target as HTMLElement;
|
||||
});
|
||||
|
||||
// Runs when the 'Copy Custom Field Name' context menu item is actually clicked.
|
||||
chrome.runtime.onMessage.addListener(event => {
|
||||
if (event.command === 'getClickedElement') {
|
||||
const identifier = getClickedElementIdentifier();
|
||||
chrome.runtime.sendMessage({
|
||||
command: 'getClickedElementResponse',
|
||||
sender: 'contextMenuHandler',
|
||||
identifier: identifier,
|
||||
});
|
||||
}
|
||||
});
|
@ -20,7 +20,8 @@
|
||||
"js": [
|
||||
"content/autofill.js",
|
||||
"content/autofiller.js",
|
||||
"content/notificationBar.js"
|
||||
"content/notificationBar.js",
|
||||
"content/contextMenuHandler.js"
|
||||
],
|
||||
"matches": [
|
||||
"http://*/*",
|
||||
|
@ -130,6 +130,7 @@ const config = {
|
||||
'content/autofill': './src/content/autofill.js',
|
||||
'content/autofiller': './src/content/autofiller.ts',
|
||||
'content/notificationBar': './src/content/notificationBar.ts',
|
||||
'content/contextMenuHandler': './src/content/contextMenuHandler.ts',
|
||||
'content/shortcuts': './src/content/shortcuts.ts',
|
||||
'content/message_handler': './src/content/message_handler.ts',
|
||||
'notification/bar': './src/notification/bar.js',
|
||||
|
Loading…
Reference in New Issue
Block a user