Some more modal changes (look at those doc comments :o)

How did this work the first time i tested it???
This commit is contained in:
mProjectsCode 2022-10-08 22:04:03 +02:00
parent db4a6c98a3
commit a3905daf5b
8 changed files with 374 additions and 160 deletions

View file

@ -5,16 +5,135 @@ import {MediaDbSearchResultModal} from '../modals/MediaDbSearchResultModal';
import {Notice} from 'obsidian';
import MediaDbPlugin from '../main';
interface AdvancedSearchOptions {
export enum ModalResultCode {
SUCCESS,
SKIP,
CLOSE,
ERROR,
}
/**
* Object containing the data {@link ModalHelper.createAdvancedSearchModal} returns.
* On {@link ModalResultCode.SUCCESS} this contains {@link AdvancedSearchModalData}.
* On {@link ModalResultCode.ERROR} this contains a reference to that error.
*/
export interface AdvancedSearchModalResult {
code: ModalResultCode.SUCCESS | ModalResultCode.CLOSE | ModalResultCode.ERROR,
data?: AdvancedSearchModalData,
error?: Error,
}
/**
* Object containing the data {@link ModalHelper.createIdSearchModal} returns.
* On {@link ModalResultCode.SUCCESS} this contains {@link IdSearchModalData}.
* On {@link ModalResultCode.ERROR} this contains a reference to that error.
*/
export interface IdSearchModalResult {
code: ModalResultCode.SUCCESS | ModalResultCode.CLOSE | ModalResultCode.ERROR,
data?: IdSearchModalData,
error?: Error,
}
/**
* Object containing the data {@link ModalHelper.createSelectModal} returns.
* On {@link ModalResultCode.SUCCESS} this contains {@link SelectModalData}.
* On {@link ModalResultCode.ERROR} this contains a reference to that error.
*/
export interface SelectModalResult {
code: ModalResultCode.SUCCESS | ModalResultCode.CLOSE | ModalResultCode.SKIP | ModalResultCode.ERROR,
data?: SelectModalData,
error?: Error,
}
/**
* The data the advanced search modal returns.
* query: the query string
* apis: the selected APIs
*/
export interface AdvancedSearchModalData {
query: string,
apis: string[],
}
interface IdSearchOptions {
/**
* The data the id search modal returns.
* query: the query string
* apis: the selected APIs
*/
export interface IdSearchModalData {
query: string,
api: string,
}
/**
* The data the select modal returns.
* selected: the selected items
*/
export interface SelectModalData {
selected: MediaTypeModel[],
}
/**
* Options for the advanced search modal.
* modalTitle: the title of the modal
* preselectedAPIs: a list of preselected APIs
* prefilledSearchString: prefilled query
*/
export interface AdvancedSearchModalOptions {
modalTitle?: string,
preselectedAPIs?: string[],
prefilledSearchString?: string,
}
/**
* Options for the id search modal.
* modalTitle: the title of the modal
* preselectedAPIs: a list of preselected APIs
* prefilledSearchString: prefilled query
*/
export interface IdSearchModalOptions {
modalTitle?: string,
preselectedAPI?: string,
prefilledSearchString?: string,
}
/**
* Options for the select modal.
* modalTitle: the title of the modal
* elements: the elements the user can select from
* multiSelect: whether to allow multiselect
* skipButton: whether to add a skip button to the modal
*/
export interface SelectModalOptions {
modalTitle?: string,
elements?: MediaTypeModel[],
multiSelect?: boolean,
skipButton?: boolean,
}
export const ADVANCED_SEARCH_MODAL_DEFAULT_OPTIONS: AdvancedSearchModalOptions = {
modalTitle: 'Media DB Advanced Search',
preselectedAPIs: [],
prefilledSearchString: '',
};
export const ID_SEARCH_MODAL_DEFAULT_OPTIONS: IdSearchModalOptions = {
modalTitle: 'Media DB Id Search',
preselectedAPI: '',
prefilledSearchString: '',
};
export const SELECT_MODAL_OPTIONS_DEFAULT: SelectModalOptions = {
modalTitle: 'Media DB Search Results',
elements: [],
multiSelect: true,
skipButton: false,
};
/**
* A class providing multiple usefull functions for dealing with the plugins modals.
*/
export class ModalHelper {
plugin: MediaDbPlugin;
@ -23,105 +142,185 @@ export class ModalHelper {
this.plugin = plugin;
}
async createAdvancedSearchModal(): Promise<{ advancedSearchOptions: AdvancedSearchOptions, advancedSearchModal: MediaDbAdvancedSearchModal }> {
const modal = new MediaDbAdvancedSearchModal(this.plugin);
const res: { query: string, apis: string[] } = await new Promise((resolve, reject) => {
modal.setSubmitCallback(res => resolve(res));
/**
* Creates an {@link MediaDbAdvancedSearchModal}, then sets callbacks and awaits them,
* returning either the user input once submitted or nothing once closed.
* The modal needs ot be manually closed by calling `close()` on the modal reference.
*
* @param advancedSearchModalOptions the options for the modal, see {@link ADVANCED_SEARCH_MODAL_DEFAULT_OPTIONS}
* @returns the user input or nothing and a reference to the modal.
*/
async createAdvancedSearchModal(advancedSearchModalOptions: AdvancedSearchModalOptions): Promise<{ advancedSearchModalResult: AdvancedSearchModalResult, advancedSearchModal: MediaDbAdvancedSearchModal }> {
const modal = new MediaDbAdvancedSearchModal(this.plugin, advancedSearchModalOptions);
const res: AdvancedSearchModalResult = await new Promise((resolve, reject) => {
modal.setSubmitCallback(res => resolve({code: ModalResultCode.SUCCESS, data: res}));
modal.setCloseCallback(err => {
if (err) {
reject(err);
resolve({code: ModalResultCode.ERROR, error: err});
}
resolve(undefined);
resolve({code: ModalResultCode.CLOSE});
});
modal.open();
});
return {advancedSearchOptions: res, advancedSearchModal: modal};
return {advancedSearchModalResult: res, advancedSearchModal: modal};
}
async openAdvancedSearchModal<T>(submitCallback: (advancedSearchOptions: AdvancedSearchOptions) => Promise<T>): Promise<T> {
const {advancedSearchOptions, advancedSearchModal} = await this.createAdvancedSearchModal();
if (!advancedSearchOptions) {
advancedSearchModal.close();
return;
}
/**
* Opens an {@link MediaDbAdvancedSearchModal} and awaits its result,
* then executes the `submitCallback` returning the callbacks result and closing the modal.
*
* @param advancedSearchModalOptions the options for the modal, see {@link ADVANCED_SEARCH_MODAL_DEFAULT_OPTIONS}
* @param submitCallback the callback that gets executed after the modal has been submitted, but after it has been closed
* @returns the user input or nothing and a reference to the modal.
*/
async openAdvancedSearchModal(advancedSearchModalOptions: AdvancedSearchModalOptions, submitCallback: (advancedSearchModalData: AdvancedSearchModalData) => Promise<MediaTypeModel[]>): Promise<MediaTypeModel[]> {
const {advancedSearchModalResult, advancedSearchModal} = await this.createAdvancedSearchModal(advancedSearchModalOptions);
try {
let callbackRes: T;
callbackRes = await submitCallback(advancedSearchOptions);
advancedSearchModal.close();
return callbackRes;
} catch (e) {
console.warn(e);
new Notice(e.toString());
if (advancedSearchModalResult.code === ModalResultCode.ERROR) {
// there was an error in the modal itself
console.warn(advancedSearchModalResult.error);
new Notice(advancedSearchModalResult.error.toString());
advancedSearchModal.close();
return undefined;
}
}
async createIdSearchModal(): Promise<{ idSearchOptions: { query: string, api: string }, idSearchModal: MediaDbIdSearchModal }> {
const modal = new MediaDbIdSearchModal(this.plugin);
const res: { query: string, api: string } = await new Promise((resolve, reject) => {
modal.setSubmitCallback(res => resolve(res));
modal.setCloseCallback(err => {
if (err) {
reject(err);
}
resolve(undefined);
});
modal.open();
});
return {idSearchOptions: res, idSearchModal: modal};
}
async openIdSearchModal<T>(submitCallback: (idSearchOptions: IdSearchOptions) => Promise<T>): Promise<T> {
const {idSearchOptions, idSearchModal} = await this.createIdSearchModal();
if (!idSearchOptions) {
idSearchModal.close();
return;
}
try {
let callbackRes: T;
callbackRes = await submitCallback(idSearchOptions);
idSearchModal.close();
return callbackRes;
} catch (e) {
console.warn(e);
new Notice(e.toString());
idSearchModal.close();
if (advancedSearchModalResult.code === ModalResultCode.CLOSE) {
// modal is already being closed
return undefined;
}
}
async createSelectModal(resultsToDisplay: MediaTypeModel[], skipButton: boolean = false, allowMultiSelect: boolean = true): Promise<{ selectRes: MediaTypeModel[], selectModal: MediaDbSearchResultModal }> {
const modal = new MediaDbSearchResultModal(this.plugin, resultsToDisplay, skipButton, allowMultiSelect);
const res: MediaTypeModel[] = await new Promise((resolve, reject) => {
modal.setSubmitCallback(res => resolve(res));
modal.setSkipCallback(() => resolve([]));
modal.setCloseCallback(err => {
if (err) {
reject(err);
}
resolve(undefined);
});
modal.open();
});
return {selectRes: res, selectModal: modal};
}
async openSelectModal(mediaModels: MediaTypeModel[], submitCallback: (selectedMediaTypeModels: MediaTypeModel[]) => Promise<MediaTypeModel[]>): Promise<MediaTypeModel[]> {
const {selectRes, selectModal} = await this.createSelectModal(mediaModels, false);
if (!selectRes) {
selectModal.close();
return;
}
try {
let callbackRes: MediaTypeModel[];
callbackRes = await submitCallback(selectRes);
callbackRes = await submitCallback(advancedSearchModalResult.data);
advancedSearchModal.close();
return callbackRes;
} catch (e) {
console.warn(e);
new Notice(e.toString());
advancedSearchModal.close();
return undefined;
}
}
/**
* Creates an {@link MediaDbIdSearchModal}, then sets callbacks and awaits them,
* returning either the user input once submitted or nothing once closed.
* The modal needs ot be manually closed by calling `close()` on the modal reference.
*
* @param idSearchModalOptions the options for the modal, see {@link ID_SEARCH_MODAL_DEFAULT_OPTIONS}
* @returns the user input or nothing and a reference to the modal.
*/
async createIdSearchModal(idSearchModalOptions: IdSearchModalOptions): Promise<{ idSearchModalResult: IdSearchModalResult, idSearchModal: MediaDbIdSearchModal }> {
const modal = new MediaDbIdSearchModal(this.plugin, idSearchModalOptions);
const res: IdSearchModalResult = await new Promise((resolve, reject) => {
modal.setSubmitCallback(res => resolve({code: ModalResultCode.SUCCESS, data: res}));
modal.setCloseCallback(err => {
if (err) {
resolve({code: ModalResultCode.ERROR, error: err});
}
resolve({code: ModalResultCode.CLOSE});
});
modal.open();
});
return {idSearchModalResult: res, idSearchModal: modal};
}
/**
* Opens an {@link MediaDbIdSearchModal} and awaits its result,
* then executes the `submitCallback` returning the callbacks result and closing the modal.
*
* @param idSearchModalOptions the options for the modal, see {@link ID_SEARCH_MODAL_DEFAULT_OPTIONS}
* @param submitCallback the callback that gets executed after the modal has been submitted, but after it has been closed
* @returns the user input or nothing and a reference to the modal.
*/
async openIdSearchModal(idSearchModalOptions: IdSearchModalOptions, submitCallback: (idSearchModalData: IdSearchModalData) => Promise<MediaTypeModel>): Promise<MediaTypeModel> {
const {idSearchModalResult, idSearchModal} = await this.createIdSearchModal(idSearchModalOptions);
if (idSearchModalResult.code === ModalResultCode.ERROR) {
// there was an error in the modal itself
console.warn(idSearchModalResult.error);
new Notice(idSearchModalResult.error.toString());
idSearchModal.close();
return undefined;
}
if (idSearchModalResult.code === ModalResultCode.CLOSE) {
// modal is already being closed
return undefined;
}
try {
let callbackRes: MediaTypeModel;
callbackRes = await submitCallback(idSearchModalResult.data);
idSearchModal.close();
return callbackRes;
} catch (e) {
console.warn(e);
new Notice(e.toString());
idSearchModal.close();
return undefined;
}
}
/**
* Creates an {@link MediaDbSearchResultModal}, then sets callbacks and awaits them,
* returning either the user input once submitted or nothing once closed.
* The modal needs ot be manually closed by calling `close()` on the modal reference.
*
* @param selectModalOptions the options for the modal, see {@link SELECT_MODAL_OPTIONS_DEFAULT}
* @returns the user input or nothing and a reference to the modal.
*/
async createSelectModal(selectModalOptions: SelectModalOptions): Promise<{ selectModalResult: SelectModalResult, selectModal: MediaDbSearchResultModal }> {
const modal = new MediaDbSearchResultModal(this.plugin, selectModalOptions);
const res: SelectModalResult = await new Promise((resolve, reject) => {
modal.setSubmitCallback(res => resolve({code: ModalResultCode.SUCCESS, data: res}));
modal.setSkipCallback(() => resolve({code: ModalResultCode.SKIP}));
modal.setCloseCallback(err => {
if (err) {
resolve({code: ModalResultCode.ERROR, error: err});
}
resolve({code: ModalResultCode.CLOSE});
});
modal.open();
});
return {selectModalResult: res, selectModal: modal};
}
/**
* Opens an {@link MediaDbSearchResultModal} and awaits its result,
* then executes the `submitCallback` returning the callbacks result and closing the modal.
*
* @param selectModalOptions the options for the modal, see {@link SELECT_MODAL_OPTIONS_DEFAULT}
* @param submitCallback the callback that gets executed after the modal has been submitted, but after it has been closed
* @returns the user input or nothing and a reference to the modal.
*/
async openSelectModal(selectModalOptions: SelectModalOptions, submitCallback: (selectModalData: SelectModalData) => Promise<MediaTypeModel[]>): Promise<MediaTypeModel[]> {
const {selectModalResult, selectModal} = await this.createSelectModal(selectModalOptions);
if (selectModalResult.code === ModalResultCode.ERROR) {
// there was an error in the modal itself
console.warn(selectModalResult.error);
new Notice(selectModalResult.error.toString());
selectModal.close();
return undefined;
}
if (selectModalResult.code === ModalResultCode.CLOSE) {
// modal is already being closed
return undefined;
}
if (selectModalResult.code === ModalResultCode.SKIP) {
// selection was skipped
return undefined;
}
try {
let callbackRes: MediaTypeModel[];
callbackRes = await submitCallback(selectModalResult.data);
selectModal.close();
return callbackRes;
} catch (e) {