diff --git a/src/services/utils/dialog.ts b/src/services/utils/dialog.ts index a77cdd52..a745cb4e 100644 --- a/src/services/utils/dialog.ts +++ b/src/services/utils/dialog.ts @@ -1,4 +1,8 @@ import { translate as t, translatePlural as n } from '@nextcloud/l10n'; +import { FilePickerType, getFilePickerBuilder } from '@nextcloud/dialogs'; +import { showError } from '@nextcloud/dialogs'; +import { bus } from './event-bus'; +import { fragment } from './fragment'; // https://github.com/nextcloud/server/blob/4b7ec0a0c18d4e2007565dc28ee214814940161e/core/src/OC/dialogs.js const oc_dialogs = (OC).dialogs; @@ -20,6 +24,12 @@ type ConfirmOptions = { modal?: boolean; }; +// Register fragment navigation +bus.on('memories:fragment:pop:dialog', () => { + const selectors = ['button.oc-dialog-close', '[role="dialog"]:last-of-type button.modal-container__close'].join(', '); + (document.querySelector(selectors) as HTMLElement)?.click?.(); +}); + export function confirmDestructive(options: ConfirmOptions): Promise { const opts: ConfirmOptions = Object.assign( { @@ -55,7 +65,10 @@ export function confirmDestructive(options: ConfirmOptions): Promise { // Watch changes to body observer.observe(document.body, { childList: true }); - return new Promise((resolve) => oc_dialogs.confirmDestructive(opts.message, opts.title, opts, resolve)); + return fragment.wrap( + new Promise((resolve) => oc_dialogs.confirmDestructive(opts.message, opts.title, opts, resolve)), + fragment.types.dialog, + ); } type PromptOptions = { @@ -84,6 +97,50 @@ export async function prompt(opts: PromptOptions): Promise { }); } +/** + * Choose a folder using the NC file picker + * + * @param title Title of the file picker + * @param initial Initial path + * @param type Type of the file picker + * + * @returns The path of the chosen folder + */ +export async function chooseNcFolder( + title: string, + initial: string = '/', + type: FilePickerType = FilePickerType.Choose, +) { + const picker = getFilePickerBuilder(title) + .setMultiSelect(false) + .setModal(true) + .setType(type) + .addMimeTypeFilter('httpd/unix-directory') + .allowDirectories() + .startAt(initial) + .build(); + + // Choose a folder + const promise = fragment.wrap(picker.pick(), fragment.types.dialog); + let folder = (await promise) || '/'; + + // Remove double slashes + folder = folder.replace(/\/+/g, '/'); + + // Look for any trailing or leading whitespace + if (folder.trim() !== folder) { + showError( + t( + 'memories', + 'The folder name "{folder}" has a leading or trailing whitespace. This may lead to errors and should be corrected.', + { folder }, + ), + ); + } + + return folder; +} + /** Bespoke confirmation dialogs for re-use */ export const dialogs = { moveToTrash: (count: number) => diff --git a/src/services/utils/fragment.ts b/src/services/utils/fragment.ts index c87f573a..33a7c766 100644 --- a/src/services/utils/fragment.ts +++ b/src/services/utils/fragment.ts @@ -8,6 +8,7 @@ enum FragmentType { sidebar = 'i', editor = 'e', settings = 'ss', + dialog = 'd', } /** Names of fragments */ @@ -160,6 +161,18 @@ export const fragment = { else await this.pop(type); }, + /** + * Wrap a promise as a route fragment. + */ + async wrap(promise: Promise, type: FragmentType, ...args: string[]): Promise { + await this.push(type, ...args); + try { + return await promise; + } finally { + await this.pop(type); + } + }, + get viewer() { return this.get(FragmentType.viewer); }, diff --git a/src/services/utils/helpers.ts b/src/services/utils/helpers.ts index 49fd8164..4b29a99f 100644 --- a/src/services/utils/helpers.ts +++ b/src/services/utils/helpers.ts @@ -1,7 +1,4 @@ -import { FilePickerType, getFilePickerBuilder } from '@nextcloud/dialogs'; import { getCurrentUser } from '@nextcloud/auth'; -import { showError } from '@nextcloud/dialogs'; -import { translate as t } from '@nextcloud/l10n'; import { API } from '../API'; import { constants as c } from './const'; @@ -190,49 +187,6 @@ export function setupLivePhotoHooks(video: HTMLVideoElement) { }; } -/** - * Choose a folder using the NC file picker - * - * @param title Title of the file picker - * @param initial Initial path - * @param type Type of the file picker - * - * @returns The path of the chosen folder - */ -export async function chooseNcFolder( - title: string, - initial: string = '/', - type: FilePickerType = FilePickerType.Choose, -) { - const picker = getFilePickerBuilder(title) - .setMultiSelect(false) - .setModal(true) - .setType(type) - .addMimeTypeFilter('httpd/unix-directory') - .allowDirectories() - .startAt(initial) - .build(); - - // Choose a folder - let folder = (await picker.pick()) || '/'; - - // Remove double slashes - folder = folder.replace(/\/+/g, '/'); - - // Look for any trailing or leading whitespace - if (folder.trim() !== folder) { - showError( - t( - 'memories', - 'The folder name "{folder}" has a leading or trailing whitespace. This may lead to errors and should be corrected.', - { folder }, - ), - ); - } - - return folder; -} - /** * Check if the provided Axios Error is a network error. */