# Updating Web Extension When User Alters Preferences

**URL:** <https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453>\
**Category:** Development\
**Created:** [December 20, 2018, 10:16pm UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453 "2018-12-20T22:16:25Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![msaroff](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/msaroff/32/20303_2.png) [@msaroff](https://discourse.mozilla.org/u/msaroff)\
**Post date:** [December 20, 2018, 10:16pm UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453/1 "2018-12-20T22:16:25Z")

</div>

I’ve got my app up to what I would call a “twitchy alpha”, and I am looking at dealing with a minor annoyance.

A user can edit or create custom tags for a context menu, but they do not show up on that context menu until the extension is reloaded (currently doing this though the whole `about:debugging` thing).

Obviously, once it gets released on AMO, I could just tell the users that the modifications to custom tags require a restart, but that is a bit of a PITA.

Is there a function that can be called to regenerate the custom tags when the user hits save on new/modified tags?

---

<div class="post-metadata">

**Author:** ![jscher2000](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/jscher2000/32/28202_2.png) [@jscher2000](https://discourse.mozilla.org/u/jscher2000)\
**Post date:** [December 20, 2018, 11:14pm UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453/2 "2018-12-20T23:14:45Z")

</div>

Do you mean, update individual context menu items so you don’t have to rebuild the entire (rather large) menu structure?

There is the following, but you need to know the id of the menu entry. Perhaps you can capture that as the user is changing it?

> **[menus.update() - Mozilla | MDN](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/menus/update)**
>
> Updates a previously created menu item.

---

<div class="post-metadata">

**Author:** ![msaroff](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/msaroff/32/20303_2.png) [@msaroff](https://discourse.mozilla.org/u/msaroff)\
**Post date:** [December 23, 2018, 2:07am UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453/3 "2018-12-23T02:07:49Z")

</div>

Actually, I’m looking to update all the menus associated with my app.

All the ids for this app start with the same string, but if someone adds a custom menu, or activates or deactivates a menu, I want it updated.

---

<div class="post-metadata">

**Author:** ![juraj.masiar](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/juraj.masiar/32/30587_2.png) [@juraj.masiar](https://discourse.mozilla.org/u/juraj.masiar)\
**Post date:** [December 23, 2018, 8:17pm UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453/4 "2018-12-23T20:17:20Z")

</div>

Well I suppose there is one easy way - create function that builds all context menu items and when user changes something, just remove all menus and recreate them again using your function.

> **[menus.removeAll() - Mozilla | MDN](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/menus/removeAll)**
>
> Removes all menu items added by the extension.

---

<div class="post-metadata">

**Author:** ![msaroff](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/msaroff/32/20303_2.png) [@msaroff](https://discourse.mozilla.org/u/msaroff)\
**Post date:** [December 27, 2018, 6:27pm UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453/5 "2018-12-27T18:27:11Z")

</div>

Good to know.

Does it make sense to pull the menu creation code out of my context menu script, and make it a library that I would load when the extension is first loaded (contextmenu.js) when the user changes the active menus (options.js) and when the user changes the custom menus (custom\_tags.js), or should I just copy and paste into all three scripts?

---

<div class="post-metadata">

**Author:** ![juraj.masiar](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/juraj.masiar/32/30587_2.png) [@juraj.masiar](https://discourse.mozilla.org/u/juraj.masiar)\
**Post date:** [December 27, 2018, 6:53pm UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453/6 "2018-12-27T18:53:21Z")

</div>

The DRY principle is clear on this 🙂 :

> **[Don't repeat yourself](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)**
>
> In software engineering, don't repeat yourself (DRY) is a principle of software development aimed at reducing repetition of software patterns, replacing it with abstractions or using data normalization to avoid redundancy.
> The DRY principle is stated as "Every piece of knowledge must have a single, unambiguous, authoritative representation within a system". The principle has been formulated by Andy Hunt and Dave Thomas in their book The Pragmatic Programmer. They apply it quite broadly to includ...

I would implement it in the background script and then control it by sending messages to your background script.  
You can have it in the separate file - your background script can load multiple scripts just like any other page.

---

<div class="post-metadata">

**Author:** ![msaroff](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/msaroff/32/20303_2.png) [@msaroff](https://discourse.mozilla.org/u/msaroff)\
**Post date:** [December 28, 2018, 3:20pm UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453/7 "2018-12-28T15:20:06Z")

</div>

The thing is that the script to delete and regenerate the menus will run three times:

- At startup. (Runs in the background script `./context_menu.js` now)
- When changing the active menus on the `./settings/options.html` page.
- When editing custom tags on the `./settings/custom+tags.html` page. (I keep them separate because I prefer the interface that way)

My `./context_menu.js` already generates the menu upon extension loading and reloading.

So, could I simply put a `menus.removeAll()` before the menu generation code of my `./context_menu.js` file, and then call it when the save button is pushed on the other pages? (Message passing reruns `./context_menu.js`)

---

<div class="post-metadata">

**Author:** ![juraj.masiar](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/juraj.masiar/32/30587_2.png) [@juraj.masiar](https://discourse.mozilla.org/u/juraj.masiar)\
**Post date:** [December 28, 2018, 3:54pm UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453/8 "2018-12-28T15:54:00Z")

</div>

It’s hard to say, but could be good enough.

But you could decouple it completely by using existing events.  
For example, when user clicks save button, you store the config to the browser storage, right?  
I would just register `browser.storage.onChanged.addListener` listener in your context menu builder module and let it rebuild it. That way, you don’t care who and where changed it, it will rebuild when saved settings changes.

---

<div class="post-metadata">

**Author:** ![msaroff](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/msaroff/32/20303_2.png) [@msaroff](https://discourse.mozilla.org/u/msaroff)\
**Post date:** [December 28, 2018, 3:56pm UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453/9 "2018-12-28T15:56:59Z")

</div>

Woah. That is a lot simpler.

Thanks,

---

<div class="post-metadata">

**Author:** ![msaroff](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/msaroff/32/20303_2.png) [@msaroff](https://discourse.mozilla.org/u/msaroff)\
**Post date:** [January 7, 2019, 9:47pm UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453/10 "2019-01-07T21:47:39Z")

</div>

OK, I’ve got it working, but I have a question

This works like a dream:

```auto
window.addEventListener("storage", generateMenu, false);

```

but this marginally simpler syntax doesn’t:

```auto
browser.storage.onChanged.addListener(generateMenu);

```

My reading of the docs is that both should work.

What am I missing?

---

<div class="post-metadata">

**Author:** ![juraj.masiar](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/juraj.masiar/32/30587_2.png) [@juraj.masiar](https://discourse.mozilla.org/u/juraj.masiar)\
**Post date:** [January 7, 2019, 10:01pm UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453/11 "2019-01-07T22:01:52Z")

</div>

What exactly doesn’t work? The `generateMenu` is not being called? Also note that the parameter send to that function will be a object with changes.

I’m using the `browser.storage.onChanged.addListener` all over my apps and it works well, for example:

```javascript
browser.storage.onChanged.addListener(changes => {
    if (changes.options) {
      reloadOptions();
    }
}

```

---

<div class="post-metadata">

**Author:** ![msaroff](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/msaroff/32/20303_2.png) [@msaroff](https://discourse.mozilla.org/u/msaroff)\
**Post date:** [January 7, 2019, 11:41pm UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453/12 "2019-01-07T23:41:47Z")

</div>

The former invoked the function, and the latter did nothing, but this probably has something to do with my profound lack of knowledge in JavaScript.

For example, I know that the `=>` used in your code above, is some sort of Java idiom, and I have actually used it in some (open source licensed) code that I’ve borrowed, but I do not quite know what it does.

The two snippets above were what I tried, and the former worked, and the latter did not.

---

<div class="post-metadata">

**Author:** ![freaktechnik](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/freaktechnik/32/37766_2.png) [@freaktechnik](https://discourse.mozilla.org/u/freaktechnik)\
**Post date:** [January 8, 2019, 8:08am UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453/13 "2019-01-08T08:08:45Z")

</div>

These event listeners are for two completely different storages. The first one is for `window.localStorage` and `window.sessionStorage` and the second one is for `browser.storage.local`, `browser.storage.managed` and `browser.storage.sync`.

> [@msaroff](#):
>
> For example, I know that the `=>` used in your code above, is some sort of Java idiom, and I have actually used it in some (open source licensed) code that I’ve borrowed, but I do not quite know what it does.

It’s just function syntax with some special rules: [Arrow function expressions - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)

---

<div class="post-metadata">

**Author:** ![juraj.masiar](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/juraj.masiar/32/30587_2.png) [@juraj.masiar](https://discourse.mozilla.org/u/juraj.masiar)\
**Post date:** [January 8, 2019, 8:09am UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453/14 "2019-01-08T08:09:13Z")

</div>

The arrow is a lambda function. You should use them, they are very handy 🙂.  
It’s the same as if you wrote:

```javascript
function (changes) {
  ...
}

```

---

<div class="post-metadata">

**Author:** ![juraj.masiar](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/juraj.masiar/32/30587_2.png) [@juraj.masiar](https://discourse.mozilla.org/u/juraj.masiar)\
**Post date:** [January 8, 2019, 12:08pm UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453/15 "2019-01-08T12:08:59Z")

</div>

Regarding the storages - for your add-on data you may want to use `browser.storage.local` and not `window.localStorage`.

The `window.localStorage` is synchronous and it may get cleared:

> Although this API is similar to [`Window.localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) it is recommended that you don’t use `Window.localStorage` in extension code. Firefox will clear data stored by extensions using the localStorage API in various scenarios where users clear their browsing history and data for privacy reasons, while data saved using the storage.local API will be correctly persisted in these scenarios.

> **[storage.local - Mozilla | MDN](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage/local)**
>
> Represents the local storage area. Items in local storage are local to the machine the extension is installed on.

---

<div class="post-metadata">

**Author:** ![msaroff](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/msaroff/32/20303_2.png) [@msaroff](https://discourse.mozilla.org/u/msaroff)\
**Post date:** [January 9, 2019, 4:49pm UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453/16 "2019-01-09T16:49:16Z")

</div>

OK, I just tried out something with the code, and

`window.addEventListener("storage", generateMenu, false);`

works, and

`browser.addEventListener("storage", generateMenu, false);`

does not until I manually reaload the extension through the about:debugging page.

In the options page, saving the updated data looks like this:

```auto
function saveMenus () {
console.log(JSON.stringify(activeMenus));
    for (i = 0; i < Object.keys(activeMenus).length; i++) {
        let crntMenu = Object.keys(activeMenus)[i]; //steps through object names
        let crntCheck = crntMenu+"CHK"; //steps through check box names
        let checkVal = document.getElementById(crntCheck).checked; //gives boolean value of check box
activeMenus[crntMenu] = checkVal; //gotta use this notation because I am using a variable for the name.
}
    localStorage.setItem('activeMenus',JSON.stringify(activeMenus)); //store default in local menu
console.log("Menu Settings Saved");
}

```

It appears the listener picks up when listening to the window, but not for the browser.

---

<div class="post-metadata">

**Author:** ![freaktechnik](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/freaktechnik/32/37766_2.png) [@freaktechnik](https://discourse.mozilla.org/u/freaktechnik)\
**Post date:** [January 9, 2019, 4:50pm UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453/17 "2019-01-09T16:50:27Z")

</div>

> [@msaroff](#):
>
> browser.addEventListener(“storage”, generateMenu, false);

That seems like a thing that should never work. browser only has the webextension APIs, So the `browser.storage.*` APIs. No DOM API like `localStorage` or `addEventListener`

Important: `localStorage` and `browser.storage.local` are two _very_ different things.

---

<div class="post-metadata">

**Author:** ![msaroff](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/msaroff/32/20303_2.png) [@msaroff](https://discourse.mozilla.org/u/msaroff)\
**Post date:** [January 9, 2019, 5:54pm UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453/18 "2019-01-09T17:54:04Z")

</div>

So, I’m trying to square the circle on the statement earlier in this discussion that `window.localStorage` should not be used, and that browser.storage.\* will not work.

Or am I reading this wrong?

---

<div class="post-metadata">

**Author:** ![freaktechnik](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/freaktechnik/32/37766_2.png) [@freaktechnik](https://discourse.mozilla.org/u/freaktechnik)\
**Post date:** [January 9, 2019, 5:56pm UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453/19 "2019-01-09T17:56:31Z")

</div>

Let me break this down:

[`window.localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage):

- avoid usage in extensions, since data in it can be deleted by privacy features
- changes trigger `window.addEventListener("storage", listener)`

[`browser.storage.local`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage/local):

- use in extensions
- changes trigger `browser.storage.onChanged`

The “doesn’t work” was that the event listener you were using does not fire for that storage type.

---

<div class="post-metadata">

**Author:** ![msaroff](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/msaroff/32/20303_2.png) [@msaroff](https://discourse.mozilla.org/u/msaroff)\
**Post date:** [January 9, 2019, 6:09pm UTC](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453/20 "2019-01-09T18:09:16Z")

</div>

So, when I am saving to local storage with `localStorage.setItem();` is this being set in [`window.localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) , or to the more permanent [`browser.storage.local`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage/local)?

It appears that you are saying to me that to save locally stored data, I should probably use  
`browser.localStorage.setItem();` as opposed to `localStorage.setItem();` , and user `browser.localStorage.getItem();` as well, correct?

If so, what is the proper listener for this data?

[Next page](https://discourse.mozilla.org/t/updating-web-extension-when-user-alters-preferences/34453.md?page=2)
