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:
parent
db4a6c98a3
commit
a3905daf5b
8 changed files with 374 additions and 160 deletions
|
|
@ -4,7 +4,6 @@ import MediaDbPlugin from '../../main';
|
|||
import {BoardGameModel} from 'src/models/BoardGameModel';
|
||||
import {debugLog} from '../../utils/Utils';
|
||||
import {requestUrl} from 'obsidian';
|
||||
import {MediaType} from '../../utils/MediaType';
|
||||
|
||||
export class BoardGameGeekAPI extends APIModel {
|
||||
plugin: MediaDbPlugin;
|
||||
|
|
|
|||
90
src/main.ts
90
src/main.ts
|
|
@ -2,9 +2,8 @@ import {MarkdownView, Notice, parseYaml, Plugin, stringifyYaml, TFile, TFolder}
|
|||
import {getDefaultSettings, MediaDbPluginSettings, MediaDbSettingTab} from './settings/Settings';
|
||||
import {APIManager} from './api/APIManager';
|
||||
import {MediaTypeModel} from './models/MediaTypeModel';
|
||||
import {dateTimeToString, markdownTable, replaceIllegalFileNameCharactersInString, UserCancelError, UserSkipError} from './utils/Utils';
|
||||
import {dateTimeToString, markdownTable, replaceIllegalFileNameCharactersInString} from './utils/Utils';
|
||||
import {OMDbAPI} from './api/apis/OMDbAPI';
|
||||
import {MediaDbSearchResultModal} from './modals/MediaDbSearchResultModal';
|
||||
import {MALAPI} from './api/apis/MALAPI';
|
||||
import {WikipediaAPI} from './api/apis/WikipediaAPI';
|
||||
import {MusicBrainzAPI} from './api/apis/MusicBrainzAPI';
|
||||
|
|
@ -15,7 +14,7 @@ import {PropertyMapper} from './settings/PropertyMapper';
|
|||
import {YAMLConverter} from './utils/YAMLConverter';
|
||||
import {MediaDbFolderImportModal} from './modals/MediaDbFolderImportModal';
|
||||
import {PropertyMapping, PropertyMappingModel} from './settings/PropertyMapping';
|
||||
import {ModalHelper} from './utils/ModalHelper';
|
||||
import {ModalHelper, ModalResultCode} from './utils/ModalHelper';
|
||||
|
||||
export default class MediaDbPlugin extends Plugin {
|
||||
settings: MediaDbPluginSettings;
|
||||
|
|
@ -126,23 +125,23 @@ export default class MediaDbPlugin extends Plugin {
|
|||
*/
|
||||
async createLinkWithSearchModal() {
|
||||
|
||||
let apiSearchResults: MediaTypeModel[] = await this.modalHelper.openAdvancedSearchModal(async (advancedSearchOptions) => {
|
||||
return await this.apiManager.query(advancedSearchOptions.query, advancedSearchOptions.apis);
|
||||
let apiSearchResults: MediaTypeModel[] = await this.modalHelper.openAdvancedSearchModal({}, async (advancedSearchModalData) => {
|
||||
return await this.apiManager.query(advancedSearchModalData.query, advancedSearchModalData.apis);
|
||||
});
|
||||
|
||||
if (!apiSearchResults) {
|
||||
return;
|
||||
}
|
||||
|
||||
const selectResults: MediaTypeModel[] = await this.modalHelper.openSelectModal(apiSearchResults, async (selectedMediaTypeModels) => {
|
||||
return await this.queryDetails(selectedMediaTypeModels);
|
||||
const selectResults: MediaTypeModel[] = await this.modalHelper.openSelectModal({elements: apiSearchResults, multiSelect: false}, async (selectModalData) => {
|
||||
return await this.queryDetails(selectModalData.selected);
|
||||
});
|
||||
|
||||
if (!selectResults || selectResults.length < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const link = `[${selectResults[0].title}](${selectResults[0].url})`
|
||||
const link = `[${selectResults[0].title}](${selectResults[0].url})`;
|
||||
|
||||
const view = this.app.workspace.getActiveViewOfType(MarkdownView);
|
||||
|
||||
|
|
@ -160,16 +159,16 @@ export default class MediaDbPlugin extends Plugin {
|
|||
* TODO: further refactor: extract it into own method, pass the action (api query) as lambda as well as an options object
|
||||
*/
|
||||
async createEntryWithAdvancedSearchModal() {
|
||||
const apiSearchResults: MediaTypeModel[] = await this.modalHelper.openAdvancedSearchModal(async (advancedSearchOptions) => {
|
||||
return await this.apiManager.query(advancedSearchOptions.query, advancedSearchOptions.apis);
|
||||
let apiSearchResults: MediaTypeModel[] = await this.modalHelper.openAdvancedSearchModal({}, async (advancedSearchModalData) => {
|
||||
return await this.apiManager.query(advancedSearchModalData.query, advancedSearchModalData.apis);
|
||||
});
|
||||
|
||||
if (!apiSearchResults) {
|
||||
return;
|
||||
}
|
||||
|
||||
const selectResults: MediaTypeModel[] = await this.modalHelper.openSelectModal(apiSearchResults, async (selectedMediaTypeModels) => {
|
||||
return await this.queryDetails(selectedMediaTypeModels);
|
||||
const selectResults: MediaTypeModel[] = await this.modalHelper.openSelectModal({elements: apiSearchResults}, async (selectModalData) => {
|
||||
return await this.queryDetails(selectModalData.selected);
|
||||
});
|
||||
|
||||
if (!selectResults) {
|
||||
|
|
@ -180,9 +179,9 @@ export default class MediaDbPlugin extends Plugin {
|
|||
}
|
||||
|
||||
async createEntryWithIdSearchModal() {
|
||||
const idSearchResult: MediaTypeModel = await this.modalHelper.openIdSearchModal(async (idSearchOptions) => {
|
||||
return await this.apiManager.queryDetailedInfoById(idSearchOptions.query, idSearchOptions.api);
|
||||
})
|
||||
const idSearchResult: MediaTypeModel = await this.modalHelper.openIdSearchModal({}, async (idSearchModalData) => {
|
||||
return await this.apiManager.queryDetailedInfoById(idSearchModalData.query, idSearchModalData.api);
|
||||
});
|
||||
|
||||
if (!idSearchResult) {
|
||||
return;
|
||||
|
|
@ -210,7 +209,7 @@ export default class MediaDbPlugin extends Plugin {
|
|||
return detailModels;
|
||||
}
|
||||
|
||||
async createMediaDbNoteFromModel(mediaTypeModel: MediaTypeModel, options: {attachTemplate?: boolean, attachFile?: TFile, openNote?: boolean}): Promise<void> {
|
||||
async createMediaDbNoteFromModel(mediaTypeModel: MediaTypeModel, options: { attachTemplate?: boolean, attachFile?: TFile, openNote?: boolean }): Promise<void> {
|
||||
try {
|
||||
console.debug('MDB | creating new note');
|
||||
|
||||
|
|
@ -223,12 +222,15 @@ export default class MediaDbPlugin extends Plugin {
|
|||
}
|
||||
}
|
||||
|
||||
private async generateMediaDbNoteContents(mediaTypeModel: MediaTypeModel, options: {attachTemplate?: boolean, attachFile?: TFile}) {
|
||||
private async generateMediaDbNoteContents(mediaTypeModel: MediaTypeModel, options: { attachTemplate?: boolean, attachFile?: TFile }) {
|
||||
let fileMetadata = this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject());
|
||||
let fileContent = '';
|
||||
|
||||
({fileMetadata, fileContent} = await this.attachFile(fileMetadata, fileContent, options.attachFile));
|
||||
({fileMetadata, fileContent} = await this.attachTemplate(fileMetadata, fileContent, options.attachTemplate ? await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app) : ''));
|
||||
({
|
||||
fileMetadata,
|
||||
fileContent,
|
||||
} = await this.attachTemplate(fileMetadata, fileContent, options.attachTemplate ? await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app) : ''));
|
||||
|
||||
fileContent = `---\n${this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(fileMetadata) : stringifyYaml(fileMetadata)}---\n` + fileContent;
|
||||
return fileContent;
|
||||
|
|
@ -417,46 +419,36 @@ export default class MediaDbPlugin extends Plugin {
|
|||
continue;
|
||||
}
|
||||
|
||||
let selectedResults: MediaTypeModel[] = [];
|
||||
const modal = new MediaDbSearchResultModal(this, results, true);
|
||||
try {
|
||||
selectedResults = await new Promise((resolve, reject) => {
|
||||
modal.title = `Results for \'${title}\'`;
|
||||
modal.setSubmitCallback(res => resolve(res));
|
||||
modal.setSkipCallback(() => reject(new UserCancelError('user skipped')));
|
||||
modal.setCloseCallback(err => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
reject(new UserCancelError('user canceled'));
|
||||
});
|
||||
let {selectModalResult, selectModal} = await this.modalHelper.createSelectModal({elements: results, skipButton: true, modalTitle: `Results for \'${title}\'`});
|
||||
|
||||
modal.open();
|
||||
});
|
||||
} catch (e) {
|
||||
modal.close();
|
||||
if (e instanceof UserCancelError) {
|
||||
erroredFiles.push({filePath: file.path, error: e.message});
|
||||
canceled = true;
|
||||
continue;
|
||||
} else if (e instanceof UserSkipError) {
|
||||
erroredFiles.push({filePath: file.path, error: e.message});
|
||||
continue;
|
||||
} else {
|
||||
erroredFiles.push({filePath: file.path, error: e.message});
|
||||
continue;
|
||||
}
|
||||
if (selectModalResult.code === ModalResultCode.ERROR) {
|
||||
erroredFiles.push({filePath: file.path, error: selectModalResult.error.message});
|
||||
selectModal.close();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (selectedResults.length === 0) {
|
||||
if (selectModalResult.code === ModalResultCode.CLOSE) {
|
||||
erroredFiles.push({filePath: file.path, error: 'user canceled'});
|
||||
selectModal.close();
|
||||
canceled = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (selectModalResult.code === ModalResultCode.SKIP) {
|
||||
erroredFiles.push({filePath: file.path, error: 'user skipped'});
|
||||
selectModal.close();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (selectModalResult.data.selected.length === 0) {
|
||||
erroredFiles.push({filePath: file.path, error: `no search results selected`});
|
||||
continue;
|
||||
}
|
||||
|
||||
const detailedResults = await this.queryDetails(selectedResults);
|
||||
const detailedResults = await this.queryDetails(selectModalResult.data.selected);
|
||||
await this.createMediaDbNotes(detailedResults, appendContent ? file : null);
|
||||
|
||||
modal.close();
|
||||
selectModal.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,26 +1,37 @@
|
|||
import {ButtonComponent, Modal, Notice, Setting, TextComponent, ToggleComponent} from 'obsidian';
|
||||
import {MediaTypeModel} from '../models/MediaTypeModel';
|
||||
import MediaDbPlugin from '../main';
|
||||
import {ADVANCED_SEARCH_MODAL_DEFAULT_OPTIONS, AdvancedSearchModalData, AdvancedSearchModalOptions} from '../utils/ModalHelper';
|
||||
|
||||
export class MediaDbAdvancedSearchModal extends Modal {
|
||||
plugin: MediaDbPlugin;
|
||||
|
||||
query: string;
|
||||
isBusy: boolean;
|
||||
plugin: MediaDbPlugin;
|
||||
searchBtn: ButtonComponent;
|
||||
title: string;
|
||||
selectedApis: { name: string, selected: boolean }[];
|
||||
submitCallback?: (res: { query: string, apis: string[] }) => void;
|
||||
|
||||
searchBtn: ButtonComponent;
|
||||
|
||||
submitCallback?: (res: AdvancedSearchModalData) => void;
|
||||
closeCallback?: (err?: Error) => void;
|
||||
|
||||
constructor(plugin: MediaDbPlugin) {
|
||||
|
||||
constructor(plugin: MediaDbPlugin, advancedSearchModalOptions: AdvancedSearchModalOptions) {
|
||||
advancedSearchModalOptions = Object.assign({}, ADVANCED_SEARCH_MODAL_DEFAULT_OPTIONS, advancedSearchModalOptions);
|
||||
super(plugin.app);
|
||||
|
||||
this.plugin = plugin;
|
||||
this.selectedApis = [];
|
||||
this.title = advancedSearchModalOptions.modalTitle;
|
||||
this.query = advancedSearchModalOptions.prefilledSearchString;
|
||||
|
||||
for (const api of this.plugin.apiManager.apis) {
|
||||
this.selectedApis.push({name: api.apiName, selected: false});
|
||||
this.selectedApis.push({name: api.apiName, selected: advancedSearchModalOptions.preselectedAPIs.contains(api.apiName)});
|
||||
}
|
||||
}
|
||||
|
||||
setSubmitCallback(submitCallback: (res: { query: string, apis: string[] }) => void): void {
|
||||
setSubmitCallback(submitCallback: (res: AdvancedSearchModalData) => void): void {
|
||||
this.submitCallback = submitCallback;
|
||||
}
|
||||
|
||||
|
|
@ -59,12 +70,13 @@ export class MediaDbAdvancedSearchModal extends Modal {
|
|||
onOpen() {
|
||||
const {contentEl} = this;
|
||||
|
||||
contentEl.createEl('h2', {text: 'Search media db'});
|
||||
contentEl.createEl('h2', {text: this.title});
|
||||
|
||||
const placeholder = 'Search by title';
|
||||
const searchComponent = new TextComponent(contentEl);
|
||||
searchComponent.inputEl.style.width = '100%';
|
||||
searchComponent.setPlaceholder(placeholder);
|
||||
searchComponent.setValue(this.query);
|
||||
searchComponent.onChange(value => (this.query = value));
|
||||
searchComponent.inputEl.addEventListener('keydown', this.keyPressCallback.bind(this));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,23 +1,32 @@
|
|||
import {ButtonComponent, DropdownComponent, Modal, Notice, Setting, TextComponent} from 'obsidian';
|
||||
import {MediaTypeModel} from '../models/MediaTypeModel';
|
||||
import MediaDbPlugin from '../main';
|
||||
import {ID_SEARCH_MODAL_DEFAULT_OPTIONS, IdSearchModalData, IdSearchModalOptions} from '../utils/ModalHelper';
|
||||
|
||||
export class MediaDbIdSearchModal extends Modal {
|
||||
plugin: MediaDbPlugin;
|
||||
|
||||
query: string;
|
||||
isBusy: boolean;
|
||||
plugin: MediaDbPlugin;
|
||||
searchBtn: ButtonComponent;
|
||||
title: string;
|
||||
selectedApi: string;
|
||||
submitCallback?: (res: { query: string, api: string }, err?: Error) => void;
|
||||
|
||||
searchBtn: ButtonComponent;
|
||||
|
||||
submitCallback?: (res: IdSearchModalData, err?: Error) => void;
|
||||
closeCallback?: (err?: Error) => void;
|
||||
|
||||
constructor(plugin: MediaDbPlugin) {
|
||||
|
||||
constructor(plugin: MediaDbPlugin, idSearchModalOptions: IdSearchModalOptions) {
|
||||
idSearchModalOptions = Object.assign({}, ID_SEARCH_MODAL_DEFAULT_OPTIONS, idSearchModalOptions);
|
||||
super(plugin.app);
|
||||
|
||||
this.plugin = plugin;
|
||||
this.selectedApi = plugin.apiManager.apis[0].apiName;
|
||||
this.title = idSearchModalOptions.modalTitle;
|
||||
this.selectedApi = idSearchModalOptions.preselectedAPI || plugin.apiManager.apis[0].apiName;
|
||||
}
|
||||
|
||||
setSubmitCallback(submitCallback: (res: { query: string, api: string }, err?: Error) => void): void {
|
||||
setSubmitCallback(submitCallback: (res: IdSearchModalData, err?: Error) => void): void {
|
||||
this.submitCallback = submitCallback;
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +63,7 @@ export class MediaDbIdSearchModal extends Modal {
|
|||
onOpen() {
|
||||
const {contentEl} = this;
|
||||
|
||||
contentEl.createEl('h2', {text: 'Search media db by id'});
|
||||
contentEl.createEl('h2', {text: this.title});
|
||||
|
||||
const placeholder = 'Search by id';
|
||||
const searchComponent = new TextComponent(contentEl);
|
||||
|
|
|
|||
|
|
@ -1,31 +1,34 @@
|
|||
import {MediaTypeModel} from '../models/MediaTypeModel';
|
||||
import MediaDbPlugin from '../main';
|
||||
import {SelectModal} from './SelectModal';
|
||||
import {SELECT_MODAL_OPTIONS_DEFAULT, SelectModalData, SelectModalOptions} from '../utils/ModalHelper';
|
||||
|
||||
export class MediaDbSearchResultModal extends SelectModal<MediaTypeModel> {
|
||||
plugin: MediaDbPlugin;
|
||||
heading: string;
|
||||
|
||||
busy: boolean;
|
||||
submitCallback: (res: MediaTypeModel[]) => void;
|
||||
sendCallback: boolean;
|
||||
|
||||
submitCallback: (res: SelectModalData) => void;
|
||||
closeCallback: (err?: Error) => void;
|
||||
skipCallback: () => void;
|
||||
|
||||
sendCallback: boolean;
|
||||
|
||||
constructor(plugin: MediaDbPlugin, elements: MediaTypeModel[], skipButton: boolean, allowMultiSelect: boolean = true) {
|
||||
super(plugin.app, elements, allowMultiSelect);
|
||||
constructor(plugin: MediaDbPlugin, selectModalOptions: SelectModalOptions) {
|
||||
selectModalOptions = Object.assign({}, SELECT_MODAL_OPTIONS_DEFAULT, selectModalOptions);
|
||||
super(plugin.app, selectModalOptions.elements, selectModalOptions.multiSelect);
|
||||
this.plugin = plugin;
|
||||
|
||||
this.title = 'Search Results';
|
||||
this.title = selectModalOptions.modalTitle;
|
||||
this.description = 'Select one or multiple search results.';
|
||||
this.addSkipButton = skipButton;
|
||||
this.addSkipButton = selectModalOptions.skipButton;
|
||||
|
||||
this.busy = false;
|
||||
|
||||
this.sendCallback = false;
|
||||
}
|
||||
|
||||
setSubmitCallback(submitCallback: (res: MediaTypeModel[]) => void): void {
|
||||
setSubmitCallback(submitCallback: (res: SelectModalData) => void): void {
|
||||
this.submitCallback = submitCallback;
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +52,7 @@ export class MediaDbSearchResultModal extends SelectModal<MediaTypeModel> {
|
|||
if (!this.busy) {
|
||||
this.busy = true;
|
||||
this.submitButton.setButtonText('Creating entry...');
|
||||
this.submitCallback(this.selectModalElements.filter(x => x.isActive()).map(x => x.value));
|
||||
this.submitCallback({selected: this.selectModalElements.filter(x => x.isActive()).map(x => x.value)});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,16 +46,16 @@
|
|||
<div class="media-db-plugin-property-mapping-to">
|
||||
<input type="text" spellcheck="false" bind:value="{property.newProperty}">
|
||||
</div>
|
||||
{ /if }
|
||||
{ /if }
|
||||
{ /if }
|
||||
{ /if }
|
||||
</div>
|
||||
{ /each }
|
||||
{ /each }
|
||||
</div>
|
||||
{ #if !validationResult?.res }
|
||||
<div class="media-db-plugin-property-mapping-validation">
|
||||
{validationResult?.err?.message}
|
||||
</div>
|
||||
{ /if }
|
||||
{ /if }
|
||||
<button
|
||||
class="media-db-plugin-property-mappings-save-button {validationResult?.res ? 'mod-cta' : 'mod-muted'}"
|
||||
on:click={() => { if(model.validate().res) save(model) }}>Save
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
<div class="setting-item" style="display: flex; gap: 10px; flex-direction: column; align-items: stretch;">
|
||||
{ #each models as model }
|
||||
<PropertyMappingModelComponent model={model} save={save}></PropertyMappingModelComponent>
|
||||
{ /each }
|
||||
{ /each }
|
||||
|
||||
<!--
|
||||
<pre>{JSON.stringify(models, null, 4)}</pre>
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue