Previously, when a cache was invalidated and every tab/iframe issued a getStyles request, we previous needlessly accessed IndexedDB for each of these requests. It happened because 1) the global cachedStyles was created only at the end of the async DB-reading, 2) and each style record is retrieved asynchronously so the single threaded JS engine interleaved all these operations. It could easily span a few seconds when many tabs are open and you have like 100 styles.
Now, in getStyles: all requests issued while cachedStyles is being populated are queued and invoked at the end.
Now, in filterStyles: all requests are cached using the request's options combined in a string as a key. It also helps on each navigation because we monitor page loading process at different stages: before, when committed, history traversal, requesting applicable styles by a content script. Icon badge update also may issue a copy of the just issued request by one of the navigation listeners.
Now, the caches are invalidated smartly: style add/update/delete/toggle only purges filtering cache, and modifies style cache in-place without re-reading the entire IndexedDB.
Now, code:false mode for manage page that only needs style meta. It reduces the transferred message size 10-100 times thus reducing the overhead caused by to internal JSON-fication in the extensions API.
Also fast&direct getStylesSafe for own pages; code cosmetics
* hotkey to open Manage styles
* hotkey to enable/disable all styles
No default hotkeys are provided, to customize go to "Keyboard shortcuts" on the Extensions page
(1) Add UI controls for `keyMap`, `tabSize`, `indentWithTabs`, and
`lineWrapping`; `indentUnit` tracks `tabSize`.
(2) Dispatch `change` events from `loadPrefs` to initialize CM options
from the controls' event listener.
(3) Move stock options from the `CM.fromTextArea` call into `CM.defaults`.
Add `CM.setOption` method, analogous to the instance method, which updates
`CM.defaults` and sets the option in all instances; add `CM.getOption`
which simply returns `CM.defaults[option]`.
(4) Move the new editor functions into `CM.commands` and replace the
functions with commands.
Styles are listed before actions by default. Actions are listed before
styles if `popup.stylesFirst` is false. A control for the option is shown
in "Manage" if `popup.stylesFirstUI` is true.
Two independent filters. One allows only styles that are enabled, the
other allows only styles that were written locally (that is, styles
without an update URL).
(1) An element's `change` listener can be used to initialize what it's
controlling. `loadPrefs` sends a `change` event to the element
after setting the element `value` but before adding its own `change`
listener. Add the element's listener before calling `loadPrefs` to receive
the synthetic event.
(2) `prefs.setPref` only broadcasts a notification if the value returned
by `getPref` changes.
(3) A user preference with the same (typed) value as the default is
evicted from `localStorage`. (Firefox does this.)