From f906728bf8bf45bb24a42231af5e805499597cd3 Mon Sep 17 00:00:00 2001 From: Dima Gerasimov Date: Tue, 27 Dec 2022 23:26:10 +0000 Subject: [PATCH] user browser polyfill with Promise for options access --- extension/.flowconfig | 1 + extension/package.json | 1 + extension/src/js/background.js | 5 ++- extension/src/js/browser_types.js | 25 +++++++++++ extension/src/js/options.js | 32 ++++++-------- extension/src/js/options_page.js | 69 ++++++++++++++++--------------- extension/src/js/popup.js | 14 ++++--- extension/src/manifest.json | 5 ++- extension/src/options.html | 1 + extension/src/popup.html | 1 + extension/webpack.config.js | 1 + 11 files changed, 93 insertions(+), 62 deletions(-) create mode 100644 extension/src/js/browser_types.js diff --git a/extension/.flowconfig b/extension/.flowconfig index 5aaad51..4995da2 100644 --- a/extension/.flowconfig +++ b/extension/.flowconfig @@ -5,6 +5,7 @@ [libs] node_modules/flow-interfaces-chrome/interfaces/ +src/js/browser_types.js [lints] diff --git a/extension/package.json b/extension/package.json index 7ada904..7f35e4a 100644 --- a/extension/package.json +++ b/extension/package.json @@ -46,6 +46,7 @@ "style-loader": "^3.3.1", "web-ext": "^7.4.0", "web-ext-submit": "^7.4.0", + "webextension-polyfill": "^0.10.0", "webpack": "^5.75.0", "webpack-cli": "^5.0.1", "webpack-dev-server": "^4.11.1", diff --git a/extension/src/js/background.js b/extension/src/js/background.js index f9f0551..ed3c726 100644 --- a/extension/src/js/background.js +++ b/extension/src/js/background.js @@ -1,8 +1,9 @@ /* @flow */ // TODO do I really need to annotate all files with @flow?? + import {COMMAND_CAPTURE_SIMPLE, METHOD_CAPTURE_WITH_EXTRAS, showNotification} from './common' -import {get_options} from './options' +import {getOptions} from './options' import type {Options} from './options' @@ -87,7 +88,7 @@ function capture(comment: ?string = null, tag_str: ?string = null) { // TODO await properly and handle errors const has_scripting = 'scripting' in chrome - get_options(opts => { + getOptions().then(opts => { if (has_scripting) { // $FlowFixMe chrome.scripting.executeScript({ diff --git a/extension/src/js/browser_types.js b/extension/src/js/browser_types.js new file mode 100644 index 0000000..472e1c5 --- /dev/null +++ b/extension/src/js/browser_types.js @@ -0,0 +1,25 @@ +/* @flow */ + +/* + * Based on https://github.com/Shraymonks/flow-interfaces-chrome + * not sure if browser polyfill has flow types?? + * https://github.com/mozilla/webextension-polyfill/issues/421 + */ + + +type browser$StorageArea = { + get: (keys: string | Array | Object | null) => Promise, + set: (items: Object) => Promise, +} + + +type browser$storage = { + local: browser$StorageArea, + managed: browser$StorageArea, + sync: browser$StorageArea, +} + + +declare var browser: { + storage: browser$storage, +} diff --git a/extension/src/js/options.js b/extension/src/js/options.js index 39341f2..caa8b02 100644 --- a/extension/src/js/options.js +++ b/extension/src/js/options.js @@ -6,31 +6,23 @@ export type Options = { notification: boolean; } -function default_options(): Options { + +function defaultOptions(): Options { return { endpoint: "http://localhost:12212/capture", default_tags: "grasp", notification: true, - }; -} - -export function get_options(cb: (Options) => void) { - chrome.storage.local.get(null, res => { - res = {...default_options(), ...res}; - cb(res); - }); -} - -export function set_options(opts: Options, cb: () => void) { - console.log('Saving %s', JSON.stringify(opts)); - chrome.storage.local.set(opts, cb); + } } - -export function getOptions(): Promise { - return new Promise((resolve) => { - // TODO FIXME reject? - get_options(resolve); - }); +export async function getOptions(): Promise { + const res = await browser.storage.local.get(null) + return {...defaultOptions(), ...res} +} + + +export async function setOptions(opts: Options): Promise { + console.log('Saving %o', opts) + await browser.storage.local.set(opts) } diff --git a/extension/src/js/options_page.js b/extension/src/js/options_page.js index 8938ac6..89782ed 100644 --- a/extension/src/js/options_page.js +++ b/extension/src/js/options_page.js @@ -1,15 +1,15 @@ /* @flow */ -import {get_options, set_options} from './options'; -import {ensurePermissions, hasPermissions} from './permissions'; +import {getOptions, setOptions} from './options' +import {ensurePermissions, hasPermissions} from './permissions' + const ENDPOINT_ID = 'endpoint_id'; const HAS_PERMISSION_ID = 'has_permission_id'; const NOTIFICATION_ID = 'notification_id'; const DEFAULT_TAGS_ID = 'default_tags_id'; -// TODO specify capture path here? - const SAVE_ID = 'save_id'; + function getEndpoint(): HTMLInputElement { return ((document.getElementById(ENDPOINT_ID): any): HTMLInputElement); } @@ -31,47 +31,50 @@ function getHasPermission(): HTMLElement { return ((document.getElementById(HAS_PERMISSION_ID): any): HTMLElement); } + // ugh. needs a better name.. -function refreshPermissionValidation(endpoint: string) { - hasPermissions(endpoint).then(has => { - const pstyle = getHasPermission().style; - if (has) { - console.debug('Got permisssions, nothing to worry about.'); - pstyle.display = 'none'; - return; - } - console.debug('Whoops, no permissions to access %s', endpoint); - // TODO maybe just show button? but then it would need to be reactive.. - pstyle.display = 'block'; - }); +async function refreshPermissionValidation(endpoint: string) { + const has = await hasPermissions(endpoint) + const pstyle = getHasPermission().style + if (has) { + console.debug('Got permisssions, nothing to worry about.') + pstyle.display = 'none' + return + } + console.debug('Whoops, no permissions to access %s', endpoint) + // TODO maybe just show button? but then it would need to be reactive.. + pstyle.display = 'block' } -function restoreOptions() { - getSaveButton().addEventListener('click', saveOptions); - get_options(opts => { - const ep = opts.endpoint; - getEndpoint().value = ep; - getDefaultTags().value = opts.default_tags; - getEnableNotification().checked = opts.notification; - refreshPermissionValidation(ep); - }); + +async function restoreOptions() { + getSaveButton().addEventListener('click', saveOptions) + + const opts = await getOptions() + getEndpoint().value = opts.endpoint + getDefaultTags().value = opts.default_tags + getEnableNotification().checked = opts.notification + await refreshPermissionValidation(opts.endpoint) } -function saveOptions() { + +async function saveOptions() { // TODO could also check for permissions and display message? - const endpoint = getEndpoint().value; - ensurePermissions(endpoint).finally(() => { - refreshPermissionValidation(endpoint); - }); + const endpoint = getEndpoint().value + await ensurePermissions(endpoint) + refreshPermissionValidation(endpoint) const opts = { endpoint: endpoint, default_tags: getDefaultTags().value, notification: getEnableNotification().checked, - }; - set_options(opts, () => { alert('Saved!'); }); + } + await setOptions(opts) + + // hmm seems that regular alert() doesn't work in chrome anymore + chrome.extension.getBackgroundPage().alert('Saved!') } -document.addEventListener('DOMContentLoaded', restoreOptions); +document.addEventListener('DOMContentLoaded', restoreOptions) diff --git a/extension/src/js/popup.js b/extension/src/js/popup.js index 52bc48c..615c0ee 100644 --- a/extension/src/js/popup.js +++ b/extension/src/js/popup.js @@ -1,7 +1,8 @@ /* @flow */ -import {METHOD_CAPTURE_WITH_EXTRAS} from './common'; -import {get_options} from './options'; + +import {METHOD_CAPTURE_WITH_EXTRAS} from './common' +import {getOptions} from './options' // TODO template it in html too? const BUTTON_ID = 'button_id'; @@ -73,14 +74,15 @@ function getUiState(): State { } -function restoreState(state: ?State) { +async function restoreState(state: ?State) { window.justSubmitted = false if (state == null) { // comment just relies on default - get_options(opts => {getTags().value = opts.default_tags;}); + const opts = await getOptions() + getTags().value = opts.default_tags } else { - getComment().value = state.comment; - getTags().value = state.tag_str; + getComment().value = state.comment + getTags().value = state.tag_str } } diff --git a/extension/src/manifest.json b/extension/src/manifest.json index 66df0da..22c3921 100644 --- a/extension/src/manifest.json +++ b/extension/src/manifest.json @@ -2,7 +2,10 @@ "name": "", "version": "", "background": { - "scripts": ["background.js"], + "scripts": [ + "browser-polyfill.js", + "background.js" + ], "persistent": false }, "options_ui": { diff --git a/extension/src/options.html b/extension/src/options.html index d669a1a..3c28a6e 100644 --- a/extension/src/options.html +++ b/extension/src/options.html @@ -2,6 +2,7 @@ +