-
Notifications
You must be signed in to change notification settings - Fork 54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create right-click menu #284
base: master
Are you sure you want to change the base?
Changes from 1 commit
0d52930
8874b79
646c7e5
3a7f61d
025c98e
fcc3d39
7aaf9c4
48a3d35
434affd
f880d43
f9b23ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,6 +41,8 @@ chrome.browserAction.setBadgeBackgroundColor({ | |
chrome.tabs.onUpdated.addListener((tabId, info) => { | ||
// unregister any auth listeners for this tab | ||
if (info.status === "complete") { | ||
createContextMenu(); | ||
|
||
if (authListeners[tabId]) { | ||
chrome.webRequest.onAuthRequired.removeListener(authListeners[tabId]); | ||
delete authListeners[tabId]; | ||
|
@@ -51,6 +53,10 @@ chrome.tabs.onUpdated.addListener((tabId, info) => { | |
updateMatchingPasswordsCount(tabId); | ||
}); | ||
|
||
chrome.tabs.onActivated.addListener(() => { | ||
createContextMenu(); | ||
}); | ||
|
||
// handle incoming messages | ||
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) { | ||
receiveMessage(message, sender, sendResponse); | ||
|
@@ -1156,3 +1162,61 @@ function onExtensionInstalled(details) { | |
}); | ||
} | ||
} | ||
|
||
/** | ||
* Create a context menu, also called right-click menu | ||
* | ||
* @since 3.8.0 | ||
* | ||
* @return void | ||
*/ | ||
async function createContextMenu() { | ||
await chrome.contextMenus.removeAll(); | ||
|
||
const menuEntryProps = { | ||
contexts: ["all"], | ||
type: "normal", | ||
}; | ||
const menuEntryId = "menuEntry"; | ||
|
||
const settings = await getFullSettings(); | ||
const response = await hostAction(settings, "list"); | ||
|
||
if (response.status != "ok") { | ||
throw new Error(JSON.stringify(response)); | ||
} | ||
const files = helpers.ignoreFiles(response.data.files, settings); | ||
const logins = helpers.prepareLogins(files, settings); | ||
const loginsForThisHost = helpers.filterSortLogins(logins, "", true); | ||
maximbaz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const numberOfLoginsForThisHost = loginsForThisHost.length; | ||
const singularOrPlural = numberOfLoginsForThisHost === 1 ? 'entry' : 'entries' | ||
|
||
await chrome.contextMenus.create({ | ||
...menuEntryProps, | ||
title: `Browserpass - ${numberOfLoginsForThisHost} ${singularOrPlural}`, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Although it's cool to be able to have a dynamic title, honestly I don't see how it is useful - except to indicate that there are 0 entries, in which case I think it's better to not take up space in context menu at all... I'd just prefer a static minimalistic "Browserpass" title... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can live with that :) In combination with the not showing if 0 matches, the presence of the menu entry now indicates that there is at least one match There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool :) Would that be too much to ask to rerecord the gif? Not important as you'll change UI in the next PR anyway but if it's super quick for you... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
id: menuEntryId, | ||
}); | ||
|
||
for (let i = 0; i < numberOfLoginsForThisHost; i++) { | ||
await chrome.contextMenus.create({ | ||
...menuEntryProps, | ||
parentId: menuEntryId, | ||
id: "login" + i, | ||
title: loginsForThisHost[i].login, | ||
onclick: () => clickMenuEntry(settings, loginsForThisHost[i]), | ||
}); | ||
} | ||
} | ||
|
||
/** | ||
* Handle the click of a context menu item | ||
* | ||
* @since 3.8.0 | ||
* | ||
* @param object settings Full settings object | ||
* @param array login Filtered and sorted list of logins | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe this comment is not true, it's not a list of logins right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, you're right. Btw that reminds me of an idea that I had: what would you think about porting the project to TypeScript, then part of the documentation would become unnecessary and wouldn't need to be manually maintained + it would maybe be a bit easier to understand input/output parameters quickly. Let me know what you think about that, I'd be interested to look into it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'd prefer not to do that at this point. It's a discussion for another time perhaps, but in the more immediate term I'd rather get the current backlog of stuff cleared and ready for release. |
||
* @return void | ||
*/ | ||
async function clickMenuEntry(settings, login) { | ||
await handleMessage(settings, { action: "fill", login }, () => {}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The last parameter to |
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While testing I managed to get some errors in the console when I was opening a new tab, which is because of concurrent attempts to recreate context menu. Here's what happens:
createContextMenu
isasync
, so by calling it here we don't really block browser, there's no way of knowing when the function completes. In the beginning ofcreateContextMenu
we first remove the context menu and then try to recreate it. At the same time,chrome.tabs.onActivated
will get called, in turn callingcreateContextMenu
in parallel. The previous run has just created the parent menu, this run removes it, and then the previous run tries to create children to a now gone parent, and crashes.Of course one way to reduce the chances of a crash is to move
chrome.contextMenus.removeAll()
from the beginning of the function to as much later as possible - but this will not entirely eliminate the problem, but rather just reduce its chances.Another problem is that here you actually call
createContextMenu
only oncomplete
event - I understand why you did it, but it presents a problem on slow websites. I open github.com and my context menu is filled with entries. I then go in this tab to some very slow website, which loads a ton of images, and socomplete
event will only fire in say 5 seconds. During the first 5 seconds if I right click, I will still see entries for github.I propose to repeat what
updateMatchingPasswordsCount
function does:complete
isRefreshing
variable to prevent concurrent runschrome.tabs.onActivated
below, because badge seems to not need it...Let me know if it makes sense and if you have any questions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the thorough review, I can reproduce but haven't figured out how to solve it completely yet. I'll keep you posted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I figured it out 🎉. I call
createContextMenu
now on every status, but I needchrome.tabs.onActivated
to "kill" callbacks that are being called from an "old" tab.It's a bit hard to formulate, so here's an example: I'm in
tab A
with a slow page, I switch totab B
beforetab A
finished loading, whentab A
finally finished loading I don't want it to mess up the context menu.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fkneist Would simply including the origin in the callback be sufficient? That way you can just discard any calls that have a different origin than the currently active one.