I have a color selection in an extension popup window, and I have the following code to save to localStorage upon windows close.
The window closes upon clicking “OK”, or “Cancel”:
window.addEventListener("unload", function(event) { //when the window is closed
localStorage.setItem("pickColor", "meep"); // save selected color to localStorage
let sending = browser.runtime.sendMessage({
message: "color set done"
});
console.log("message sent");
});
The message is sent, and the console.log fires, but saving to localStorage does not work, I get null rather than my test value "meep", which indicates that the value is not being saved to localStorage.
I am using localStorage rather than browser.storage.local since this is used for only for the duration of the click.
The simple answer is that you can’t really do this reliably. The only reliable way is to save the color continuously. Or to have an explicit save button.
I do have a save button, which also chooses the window.
I need the listener for the message, which serves to make the menu wait for user input, but I can save the value off of the user button click, as opposed to the listener.
Would using beforeunload be possible? In some instances, I was able to capture certain data elements with that event that unload did not capture. Perhaps, it will provide more time for the storage to complete.
Yes, popups get the localStorage of the extension context, content scripts get the one of the page context. That’s one of the reasons why storage.local is useful.
There is async function as mentioned before, however you can not use it in this case. What you can do is have the bg page read localStorage for your content script and send messages. Or send this info via messaging to start with?
This sounds a bit wrong. If you want to communicate with some other part of your add-on and not storing a value, then just use messaging.
You can send direct message to your content script (running in a tab) or to all your content scripts - and you are already doing it in your first example:
let sending = browser.runtime.sendMessage({
Note that the “sending” here is a Promise that will resolve once the receiver receives it - it can even be an actual value - response from a content script if it returns a promise from the message handler.
Also this is a nice place to “const” instead of “let” .
Using storage API for this can also cause a number of other issues, for example Firefox (or Chrome?) won’t fire an event when you store the same value as the one that is already there (because it compares it and sees that it’s the same so it won’t fire).
You can use simple switch to handle messages, for example:
browser.runtime.onMessage.addListener(data => { // main communication point with background script
switch (data.type) {
case 'newColor': colorPicked(data.color); break;
case 'getColor': return Promise.resolve(getColorSync());
case 'getRemoteColor': return getColorAsync();
}
});
Just keep it simple, no logic there, just call your functions and return Promise if you need to send a response.
Yes, but the logic should not be in the listener, it should only call the appropriate function / module. If you keep it simple (one case, one line), it’s very easy to read and extend. You can have this listener in every part of your add-on - popup, content script, background script and even options page.