| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import * as Common from '../../core/common/common.js'; |
| import * as i18n from '../../core/i18n/i18n.js'; |
| import type * as Protocol from '../../generated/protocol.js'; |
| import * as SourceFrame from '../../ui/legacy/components/source_frame/source_frame.js'; |
| import * as UI from '../../ui/legacy/legacy.js'; |
| |
| import * as ApplicationComponents from './components/components.js'; |
| import {KeyValueStorageItemsView, type View as ViewFunction} from './KeyValueStorageItemsView.js'; |
| import {SharedStorageForOrigin} from './SharedStorageModel.js'; |
| |
| const UIStrings = { |
| /** |
| * @description Text in SharedStorage Items View of the Application panel |
| */ |
| sharedStorage: 'Shared storage', |
| /** |
| * @description Text for announcing that the "Shared Storage Items" table was cleared, that is, all |
| * entries were deleted. |
| */ |
| sharedStorageItemsCleared: 'Shared Storage items cleared', |
| /** |
| * @description Text for announcing that the filtered "Shared Storage Items" table was cleared, that is, |
| * all filtered entries were deleted. |
| */ |
| sharedStorageFilteredItemsCleared: 'Shared Storage filtered items cleared', |
| /** |
| * @description Text for announcing a Shared Storage key/value item has been deleted |
| */ |
| sharedStorageItemDeleted: 'The storage item was deleted.', |
| /** |
| * @description Text for announcing a Shared Storage key/value item has been edited |
| */ |
| sharedStorageItemEdited: 'The storage item was edited.', |
| /** |
| * @description Text for announcing a Shared Storage key/value item edit request has been canceled |
| */ |
| sharedStorageItemEditCanceled: 'The storage item edit was canceled.', |
| } as const; |
| const str_ = i18n.i18n.registerUIStrings('panels/application/SharedStorageItemsView.ts', UIStrings); |
| const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_); |
| |
| interface WrappedEntry { |
| key: string; |
| value: string; |
| } |
| |
| export namespace SharedStorageItemsDispatcher { |
| export const enum Events { |
| FILTERED_ITEMS_CLEARED = 'FilteredItemsCleared', |
| ITEM_DELETED = 'ItemDeleted', |
| ITEM_EDITED = 'ItemEdited', |
| ITEMS_CLEARED = 'ItemsCleared', |
| ITEMS_REFRESHED = 'ItemsRefreshed', |
| } |
| |
| export interface ItemDeletedEvent { |
| key: string; |
| } |
| |
| export interface ItemEditedEvent { |
| columnIdentifier: string; |
| oldText: string|null; |
| newText: string; |
| } |
| |
| export interface EventTypes { |
| [Events.FILTERED_ITEMS_CLEARED]: void; |
| [Events.ITEM_DELETED]: ItemDeletedEvent; |
| [Events.ITEM_EDITED]: void; |
| [Events.ITEMS_CLEARED]: void; |
| [Events.ITEMS_REFRESHED]: void; |
| } |
| } |
| |
| export class SharedStorageItemsView extends KeyValueStorageItemsView { |
| #sharedStorage: SharedStorageForOrigin; |
| readonly sharedStorageItemsDispatcher: Common.ObjectWrapper.ObjectWrapper<SharedStorageItemsDispatcher.EventTypes>; |
| |
| constructor(sharedStorage: SharedStorageForOrigin, view?: ViewFunction) { |
| super( |
| i18nString(UIStrings.sharedStorage), 'shared-storage-items-view', /* editable=*/ true, view, |
| new ApplicationComponents.SharedStorageMetadataView.SharedStorageMetadataView( |
| sharedStorage, sharedStorage.securityOrigin)); |
| |
| this.#sharedStorage = sharedStorage; |
| this.performUpdate(); |
| |
| this.#sharedStorage.addEventListener( |
| SharedStorageForOrigin.Events.SHARED_STORAGE_CHANGED, this.#sharedStorageChanged, this); |
| |
| this.sharedStorageItemsDispatcher = |
| new Common.ObjectWrapper.ObjectWrapper<SharedStorageItemsDispatcher.EventTypes>(); |
| } |
| |
| // Use `createView()` instead of the constructor to create a view, so that entries can be awaited asynchronously. |
| static async createView(sharedStorage: SharedStorageForOrigin, viewFunction?: ViewFunction): |
| Promise<SharedStorageItemsView> { |
| const view = new SharedStorageItemsView(sharedStorage, viewFunction); |
| await view.updateEntriesOnly(); |
| return view; |
| } |
| |
| async updateEntriesOnly(): Promise<void> { |
| const entries = await this.#sharedStorage.getEntries(); |
| if (entries) { |
| this.#showSharedStorageItems(entries); |
| } |
| } |
| |
| async #sharedStorageChanged(): Promise<void> { |
| await this.refreshItems(); |
| } |
| |
| override async refreshItems(): Promise<void> { |
| await this.metadataView?.render(); |
| await this.updateEntriesOnly(); |
| this.sharedStorageItemsDispatcher.dispatchEventToListeners(SharedStorageItemsDispatcher.Events.ITEMS_REFRESHED); |
| } |
| |
| override async deleteAllItems(): Promise<void> { |
| if (!this.toolbar?.hasFilter()) { |
| await this.#sharedStorage.clear(); |
| await this.refreshItems(); |
| this.sharedStorageItemsDispatcher.dispatchEventToListeners(SharedStorageItemsDispatcher.Events.ITEMS_CLEARED); |
| UI.ARIAUtils.LiveAnnouncer.alert(i18nString(UIStrings.sharedStorageItemsCleared)); |
| return; |
| } |
| |
| await Promise.all(this.keys().map(key => this.#sharedStorage.deleteEntry(key))); |
| |
| await this.refreshItems(); |
| this.sharedStorageItemsDispatcher.dispatchEventToListeners( |
| SharedStorageItemsDispatcher.Events.FILTERED_ITEMS_CLEARED); |
| UI.ARIAUtils.LiveAnnouncer.alert(i18nString(UIStrings.sharedStorageFilteredItemsCleared)); |
| } |
| |
| protected override isEditAllowed(columnIdentifier: string, _oldText: string, newText: string): boolean { |
| if (columnIdentifier === 'key' && newText === '') { |
| // The Shared Storage backend does not currently allow '' as a key, so we only set a new entry with a new key if its new key is nonempty. |
| void this.refreshItems().then(() => { |
| UI.ARIAUtils.LiveAnnouncer.alert(i18nString(UIStrings.sharedStorageItemEditCanceled)); |
| }); |
| return false; |
| } |
| return true; |
| } |
| |
| protected async setItem(key: string, value: string): Promise<void> { |
| await this.#sharedStorage.setEntry(key, value, false); |
| |
| await this.refreshItems(); |
| this.sharedStorageItemsDispatcher.dispatchEventToListeners(SharedStorageItemsDispatcher.Events.ITEM_EDITED); |
| UI.ARIAUtils.LiveAnnouncer.alert(i18nString(UIStrings.sharedStorageItemEdited)); |
| } |
| |
| #showSharedStorageItems(items: Protocol.Storage.SharedStorageEntry[]): void { |
| if (this.toolbar) { |
| const filteredList = items.filter(item => this.toolbar?.filterRegex?.test(`${item.key} ${item.value}`) ?? true); |
| this.showItems(filteredList); |
| } |
| } |
| |
| protected async removeItem(key: string): Promise<void> { |
| await this.#sharedStorage.deleteEntry(key); |
| await this.refreshItems(); |
| this.sharedStorageItemsDispatcher.dispatchEventToListeners( |
| SharedStorageItemsDispatcher.Events.ITEM_DELETED, {key} as SharedStorageItemsDispatcher.ItemDeletedEvent); |
| UI.ARIAUtils.LiveAnnouncer.alert(i18nString(UIStrings.sharedStorageItemDeleted)); |
| } |
| |
| protected async createPreview(key: string, value: string): Promise<UI.Widget.Widget|null> { |
| const wrappedEntry = key && {key, value: value || ''} as WrappedEntry; |
| return SourceFrame.JSONView.JSONView.createViewSync(wrappedEntry); |
| } |
| } |