Add simple search modal, fix preview modal not closing on cancel
This commit is contained in:
parent
752f13f8bf
commit
2662c78080
6 changed files with 296 additions and 6 deletions
43
src/main.ts
43
src/main.ts
|
|
@ -65,13 +65,18 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
// register command to open search modal
|
// register command to open search modal
|
||||||
this.addCommand({
|
this.addCommand({
|
||||||
id: 'open-media-db-search-modal',
|
id: 'open-media-db-search-modal',
|
||||||
name: 'Add new Media DB entry',
|
name: 'Create Media DB entry',
|
||||||
|
callback: () => this.createEntryWithSearchModal(),
|
||||||
|
});
|
||||||
|
this.addCommand({
|
||||||
|
id: 'open-media-db-advanced-search-modal',
|
||||||
|
name: 'Create Media DB entry (advanced search)',
|
||||||
callback: () => this.createEntryWithAdvancedSearchModal(),
|
callback: () => this.createEntryWithAdvancedSearchModal(),
|
||||||
});
|
});
|
||||||
// register command to open id search modal
|
// register command to open id search modal
|
||||||
this.addCommand({
|
this.addCommand({
|
||||||
id: 'open-media-db-id-search-modal',
|
id: 'open-media-db-id-search-modal',
|
||||||
name: 'Add new Media DB entry by id',
|
name: 'Create Media DB entry by id',
|
||||||
callback: () => this.createEntryWithIdSearchModal(),
|
callback: () => this.createEntryWithIdSearchModal(),
|
||||||
});
|
});
|
||||||
// register command to update the open note
|
// register command to update the open note
|
||||||
|
|
@ -152,12 +157,40 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
async createEntryWithSearchModal() {
|
async createEntryWithSearchModal() {
|
||||||
|
let types: string[] = [];
|
||||||
|
let apiSearchResults: MediaTypeModel[] = await this.modalHelper.openSearchModal({}, async (searchModalData) => {
|
||||||
|
types = searchModalData.types;
|
||||||
|
const apis = this.apiManager.apis.filter(x => x.hasTypeOverlap(searchModalData.types)).map(x => x.apiName);
|
||||||
|
return await this.apiManager.query(searchModalData.query, apis);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!apiSearchResults) {
|
||||||
|
// TODO: add new notice saying no results found?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter the results
|
||||||
|
apiSearchResults = apiSearchResults.filter(x => types.contains(x.type));
|
||||||
|
|
||||||
|
let selectResults: MediaTypeModel[];
|
||||||
|
let proceed: boolean;
|
||||||
|
|
||||||
|
while (!proceed) {
|
||||||
|
selectResults = await this.modalHelper.openSelectModal({elements: apiSearchResults}, async (selectModalData) => {
|
||||||
|
return await this.queryDetails(selectModalData.selected);
|
||||||
|
});
|
||||||
|
if (!selectResults) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
proceed = await this.modalHelper.openPreviewModal({elements: selectResults}, async (previewModalData) => {
|
||||||
|
return previewModalData.confirmed;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.createMediaDbNotes(selectResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: further refactor: extract it into own method, pass the action (api query) as lambda as well as an options object
|
|
||||||
*/
|
|
||||||
async createEntryWithAdvancedSearchModal() {
|
async createEntryWithAdvancedSearchModal() {
|
||||||
let apiSearchResults: MediaTypeModel[] = await this.modalHelper.openAdvancedSearchModal({}, async (advancedSearchModalData) => {
|
let apiSearchResults: MediaTypeModel[] = await this.modalHelper.openAdvancedSearchModal({}, async (advancedSearchModalData) => {
|
||||||
return await this.apiManager.query(advancedSearchModalData.query, advancedSearchModalData.apis);
|
return await this.apiManager.query(advancedSearchModalData.query, advancedSearchModalData.apis);
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ export class MediaDbPreviewModal extends Modal {
|
||||||
const bottomSettingRow = new Setting(contentEl);
|
const bottomSettingRow = new Setting(contentEl);
|
||||||
bottomSettingRow.addButton(btn => {
|
bottomSettingRow.addButton(btn => {
|
||||||
btn.setButtonText('Cancel');
|
btn.setButtonText('Cancel');
|
||||||
btn.onClick(() => this.closeCallback());
|
btn.onClick(() => this.close());
|
||||||
btn.buttonEl.addClass('media-db-plugin-button');
|
btn.buttonEl.addClass('media-db-plugin-button');
|
||||||
this.cancelButton = btn;
|
this.cancelButton = btn;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
140
src/modals/MediaDbSearchModal.ts
Normal file
140
src/modals/MediaDbSearchModal.ts
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
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,
|
||||||
|
SEARCH_MODAL_DEFAULT_OPTIONS,
|
||||||
|
SearchModalData,
|
||||||
|
SearchModalOptions,
|
||||||
|
} from '../utils/ModalHelper';
|
||||||
|
import {MEDIA_TYPES} from '../utils/MediaTypeManager';
|
||||||
|
import {unCamelCase} from '../utils/Utils';
|
||||||
|
|
||||||
|
export class MediaDbSearchModal extends Modal {
|
||||||
|
plugin: MediaDbPlugin;
|
||||||
|
|
||||||
|
query: string;
|
||||||
|
isBusy: boolean;
|
||||||
|
title: string;
|
||||||
|
selectedTypes: { name: string, selected: boolean }[];
|
||||||
|
|
||||||
|
searchBtn: ButtonComponent;
|
||||||
|
|
||||||
|
submitCallback?: (res: SearchModalData) => void;
|
||||||
|
closeCallback?: (err?: Error) => void;
|
||||||
|
|
||||||
|
|
||||||
|
constructor(plugin: MediaDbPlugin, searchModalOptions: SearchModalOptions) {
|
||||||
|
searchModalOptions = Object.assign({}, SEARCH_MODAL_DEFAULT_OPTIONS, searchModalOptions);
|
||||||
|
super(plugin.app);
|
||||||
|
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.selectedTypes = [];
|
||||||
|
this.title = searchModalOptions.modalTitle;
|
||||||
|
this.query = searchModalOptions.prefilledSearchString;
|
||||||
|
|
||||||
|
for (const mediaType of MEDIA_TYPES) {
|
||||||
|
this.selectedTypes.push({name: mediaType, selected: searchModalOptions.preselectedTypes.contains(mediaType)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setSubmitCallback(submitCallback: (res: SearchModalData) => void): void {
|
||||||
|
this.submitCallback = submitCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCloseCallback(closeCallback: (err?: Error) => void): void {
|
||||||
|
this.closeCallback = closeCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
keyPressCallback(event: KeyboardEvent) {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
this.search();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async search(): Promise<MediaTypeModel[]> {
|
||||||
|
if (!this.query || this.query.length < 3) {
|
||||||
|
new Notice('MDB | Query too short');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const types: string[] = this.selectedTypes.filter(x => x.selected).map(x => x.name);
|
||||||
|
|
||||||
|
if (types.length === 0) {
|
||||||
|
new Notice('MDB | No Type selected');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.isBusy) {
|
||||||
|
this.isBusy = true;
|
||||||
|
this.searchBtn.setDisabled(false);
|
||||||
|
this.searchBtn.setButtonText('Searching...');
|
||||||
|
|
||||||
|
this.submitCallback({query: this.query, types: types});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onOpen() {
|
||||||
|
const {contentEl} = this;
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
contentEl.appendChild(searchComponent.inputEl);
|
||||||
|
searchComponent.inputEl.focus();
|
||||||
|
|
||||||
|
contentEl.createDiv({cls: 'media-db-plugin-spacer'});
|
||||||
|
contentEl.createEl('h3', {text: 'APIs to search'});
|
||||||
|
|
||||||
|
for (const mediaType of MEDIA_TYPES) {
|
||||||
|
const apiToggleListElementWrapper = contentEl.createEl('div', {cls: 'media-db-plugin-list-wrapper'});
|
||||||
|
|
||||||
|
const apiToggleTextWrapper = apiToggleListElementWrapper.createEl('div', {cls: 'media-db-plugin-list-text-wrapper'});
|
||||||
|
apiToggleTextWrapper.createEl('span', {text: unCamelCase(mediaType), cls: 'media-db-plugin-list-text'});
|
||||||
|
|
||||||
|
const apiToggleComponentWrapper = apiToggleListElementWrapper.createEl('div', {cls: 'media-db-plugin-list-toggle'});
|
||||||
|
|
||||||
|
const apiToggleComponent = new ToggleComponent(apiToggleComponentWrapper);
|
||||||
|
apiToggleComponent.setTooltip(unCamelCase(mediaType));
|
||||||
|
apiToggleComponent.setValue(this.selectedTypes.find(x => x.name === mediaType).selected);
|
||||||
|
apiToggleComponent.onChange((value) => {
|
||||||
|
this.selectedTypes.find(x => x.name === mediaType).selected = value;
|
||||||
|
});
|
||||||
|
apiToggleComponentWrapper.appendChild(apiToggleComponent.toggleEl);
|
||||||
|
}
|
||||||
|
|
||||||
|
contentEl.createDiv({cls: 'media-db-plugin-spacer'});
|
||||||
|
|
||||||
|
new Setting(contentEl)
|
||||||
|
.addButton(btn => {
|
||||||
|
btn.setButtonText('Cancel');
|
||||||
|
btn.onClick(() => this.close());
|
||||||
|
btn.buttonEl.addClass('media-db-plugin-button');
|
||||||
|
})
|
||||||
|
.addButton(btn => {
|
||||||
|
btn.setButtonText('Ok');
|
||||||
|
btn.setCta();
|
||||||
|
btn.onClick(() => {
|
||||||
|
this.search();
|
||||||
|
});
|
||||||
|
btn.buttonEl.addClass('media-db-plugin-button');
|
||||||
|
this.searchBtn = btn;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onClose() {
|
||||||
|
this.closeCallback();
|
||||||
|
const {contentEl} = this;
|
||||||
|
contentEl.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -62,6 +62,7 @@ export class MediaDbSearchResultModal extends SelectModal<MediaTypeModel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
onClose() {
|
onClose() {
|
||||||
|
|
||||||
this.closeCallback();
|
this.closeCallback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import {Notice} from 'obsidian';
|
||||||
import MediaDbPlugin from '../main';
|
import MediaDbPlugin from '../main';
|
||||||
import {MediaDbPreviewModal} from 'src/modals/MediaDbPreviewModal';
|
import {MediaDbPreviewModal} from 'src/modals/MediaDbPreviewModal';
|
||||||
import {CreateNoteOptions} from './Utils';
|
import {CreateNoteOptions} from './Utils';
|
||||||
|
import {MediaDbSearchModal} from '../modals/MediaDbSearchModal';
|
||||||
|
|
||||||
|
|
||||||
export enum ModalResultCode {
|
export enum ModalResultCode {
|
||||||
|
|
@ -15,6 +16,17 @@ export enum ModalResultCode {
|
||||||
ERROR,
|
ERROR,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object containing the data {@link ModalHelper.createSearchModal} returns.
|
||||||
|
* On {@link ModalResultCode.SUCCESS} this contains {@link SearchModalData}.
|
||||||
|
* On {@link ModalResultCode.ERROR} this contains a reference to that error.
|
||||||
|
*/
|
||||||
|
export interface SearchModalResult {
|
||||||
|
code: ModalResultCode.SUCCESS | ModalResultCode.CLOSE | ModalResultCode.ERROR,
|
||||||
|
data?: SearchModalData,
|
||||||
|
error?: Error,
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object containing the data {@link ModalHelper.createAdvancedSearchModal} returns.
|
* Object containing the data {@link ModalHelper.createAdvancedSearchModal} returns.
|
||||||
* On {@link ModalResultCode.SUCCESS} this contains {@link AdvancedSearchModalData}.
|
* On {@link ModalResultCode.SUCCESS} this contains {@link AdvancedSearchModalData}.
|
||||||
|
|
@ -59,6 +71,16 @@ export interface PreviewModalResult {
|
||||||
error?: Error,
|
error?: Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data the search modal returns.
|
||||||
|
* - query: the query string
|
||||||
|
* - types: the selected APIs
|
||||||
|
*/
|
||||||
|
export interface SearchModalData {
|
||||||
|
query: string,
|
||||||
|
types: string[],
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data the advanced search modal returns.
|
* The data the advanced search modal returns.
|
||||||
* - query: the query string
|
* - query: the query string
|
||||||
|
|
@ -95,6 +117,18 @@ export interface PreviewModalData {
|
||||||
confirmed: boolean,
|
confirmed: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options for the search modal.
|
||||||
|
* - modalTitle: the title of the modal
|
||||||
|
* - preselectedTypes: a list of preselected Types
|
||||||
|
* - prefilledSearchString: prefilled query
|
||||||
|
*/
|
||||||
|
export interface SearchModalOptions {
|
||||||
|
modalTitle?: string,
|
||||||
|
preselectedTypes?: string[],
|
||||||
|
prefilledSearchString?: string,
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options for the advanced search modal.
|
* Options for the advanced search modal.
|
||||||
* - modalTitle: the title of the modal
|
* - modalTitle: the title of the modal
|
||||||
|
|
@ -144,6 +178,12 @@ export interface PreviewModalOptions {
|
||||||
createNoteOptions?: CreateNoteOptions,
|
createNoteOptions?: CreateNoteOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const SEARCH_MODAL_DEFAULT_OPTIONS: SearchModalOptions = {
|
||||||
|
modalTitle: 'Media DB Search',
|
||||||
|
preselectedTypes: [],
|
||||||
|
prefilledSearchString: '',
|
||||||
|
};
|
||||||
|
|
||||||
export const ADVANCED_SEARCH_MODAL_DEFAULT_OPTIONS: AdvancedSearchModalOptions = {
|
export const ADVANCED_SEARCH_MODAL_DEFAULT_OPTIONS: AdvancedSearchModalOptions = {
|
||||||
modalTitle: 'Media DB Advanced Search',
|
modalTitle: 'Media DB Advanced Search',
|
||||||
preselectedAPIs: [],
|
preselectedAPIs: [],
|
||||||
|
|
@ -180,6 +220,68 @@ export class ModalHelper {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an {@link MediaDbSearchModal}, 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 searchModalOptions the options for the modal, see {@link SEARCH_MODAL_DEFAULT_OPTIONS}
|
||||||
|
* @returns the user input or nothing and a reference to the modal.
|
||||||
|
*/
|
||||||
|
async createSearchModal(searchModalOptions: SearchModalOptions): Promise<{ searchModalResult: SearchModalResult, searchModal: MediaDbSearchModal }> {
|
||||||
|
const modal = new MediaDbSearchModal(this.plugin, searchModalOptions);
|
||||||
|
const res: SearchModalResult = 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 {searchModalResult: res, searchModal: modal};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens an {@link MediaDbSearchModal} and awaits its result,
|
||||||
|
* then executes the `submitCallback` returning the callbacks result and closing the modal.
|
||||||
|
*
|
||||||
|
* @param searchModalOptions the options for the modal, see {@link 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 openSearchModal(searchModalOptions: SearchModalOptions, submitCallback: (searchModalData: SearchModalData) => Promise<MediaTypeModel[]>): Promise<MediaTypeModel[]> {
|
||||||
|
const {searchModalResult, searchModal} = await this.createSearchModal(searchModalOptions);
|
||||||
|
console.debug(`MDB | searchModal closed with code ${searchModalResult.code}`)
|
||||||
|
|
||||||
|
if (searchModalResult.code === ModalResultCode.ERROR) {
|
||||||
|
// there was an error in the modal itself
|
||||||
|
console.warn(searchModalResult.error);
|
||||||
|
new Notice(searchModalResult.error.toString());
|
||||||
|
searchModal.close();
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchModalResult.code === ModalResultCode.CLOSE) {
|
||||||
|
// modal is already being closed
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let callbackRes: MediaTypeModel[];
|
||||||
|
callbackRes = await submitCallback(searchModalResult.data);
|
||||||
|
searchModal.close();
|
||||||
|
return callbackRes;
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(e);
|
||||||
|
new Notice(e.toString());
|
||||||
|
searchModal.close();
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an {@link MediaDbAdvancedSearchModal}, then sets callbacks and awaits them,
|
* Creates an {@link MediaDbAdvancedSearchModal}, then sets callbacks and awaits them,
|
||||||
* returning either the user input once submitted or nothing once closed.
|
* returning either the user input once submitted or nothing once closed.
|
||||||
|
|
@ -214,6 +316,7 @@ export class ModalHelper {
|
||||||
*/
|
*/
|
||||||
async openAdvancedSearchModal(advancedSearchModalOptions: AdvancedSearchModalOptions, submitCallback: (advancedSearchModalData: AdvancedSearchModalData) => Promise<MediaTypeModel[]>): Promise<MediaTypeModel[]> {
|
async openAdvancedSearchModal(advancedSearchModalOptions: AdvancedSearchModalOptions, submitCallback: (advancedSearchModalData: AdvancedSearchModalData) => Promise<MediaTypeModel[]>): Promise<MediaTypeModel[]> {
|
||||||
const {advancedSearchModalResult, advancedSearchModal} = await this.createAdvancedSearchModal(advancedSearchModalOptions);
|
const {advancedSearchModalResult, advancedSearchModal} = await this.createAdvancedSearchModal(advancedSearchModalOptions);
|
||||||
|
console.debug(`MDB | advencedSearchModal closed with code ${advancedSearchModalResult.code}`)
|
||||||
|
|
||||||
if (advancedSearchModalResult.code === ModalResultCode.ERROR) {
|
if (advancedSearchModalResult.code === ModalResultCode.ERROR) {
|
||||||
// there was an error in the modal itself
|
// there was an error in the modal itself
|
||||||
|
|
@ -275,6 +378,7 @@ export class ModalHelper {
|
||||||
*/
|
*/
|
||||||
async openIdSearchModal(idSearchModalOptions: IdSearchModalOptions, submitCallback: (idSearchModalData: IdSearchModalData) => Promise<MediaTypeModel>): Promise<MediaTypeModel> {
|
async openIdSearchModal(idSearchModalOptions: IdSearchModalOptions, submitCallback: (idSearchModalData: IdSearchModalData) => Promise<MediaTypeModel>): Promise<MediaTypeModel> {
|
||||||
const {idSearchModalResult, idSearchModal} = await this.createIdSearchModal(idSearchModalOptions);
|
const {idSearchModalResult, idSearchModal} = await this.createIdSearchModal(idSearchModalOptions);
|
||||||
|
console.debug(`MDB | idSearchModal closed with code ${idSearchModalResult.code}`)
|
||||||
|
|
||||||
if (idSearchModalResult.code === ModalResultCode.ERROR) {
|
if (idSearchModalResult.code === ModalResultCode.ERROR) {
|
||||||
// there was an error in the modal itself
|
// there was an error in the modal itself
|
||||||
|
|
@ -337,6 +441,7 @@ export class ModalHelper {
|
||||||
*/
|
*/
|
||||||
async openSelectModal(selectModalOptions: SelectModalOptions, submitCallback: (selectModalData: SelectModalData) => Promise<MediaTypeModel[]>): Promise<MediaTypeModel[]> {
|
async openSelectModal(selectModalOptions: SelectModalOptions, submitCallback: (selectModalData: SelectModalData) => Promise<MediaTypeModel[]>): Promise<MediaTypeModel[]> {
|
||||||
const {selectModalResult, selectModal} = await this.createSelectModal(selectModalOptions);
|
const {selectModalResult, selectModal} = await this.createSelectModal(selectModalOptions);
|
||||||
|
console.debug(`MDB | selectModal closed with code ${selectModalResult.code}`)
|
||||||
|
|
||||||
if (selectModalResult.code === ModalResultCode.ERROR) {
|
if (selectModalResult.code === ModalResultCode.ERROR) {
|
||||||
// there was an error in the modal itself
|
// there was an error in the modal itself
|
||||||
|
|
@ -388,6 +493,7 @@ export class ModalHelper {
|
||||||
|
|
||||||
async openPreviewModal(previewModalOptions: PreviewModalOptions, submitCallback: (previewModalData: PreviewModalData) => Promise<boolean>): Promise<boolean> {
|
async openPreviewModal(previewModalOptions: PreviewModalOptions, submitCallback: (previewModalData: PreviewModalData) => Promise<boolean>): Promise<boolean> {
|
||||||
const {previewModalResult, previewModal} = await this.createPreviewModal(previewModalOptions);
|
const {previewModalResult, previewModal} = await this.createPreviewModal(previewModalOptions);
|
||||||
|
console.debug(`MDB | previewModal closed with code ${previewModalResult.code}`)
|
||||||
|
|
||||||
if (previewModalResult.code === ModalResultCode.ERROR) {
|
if (previewModalResult.code === ModalResultCode.ERROR) {
|
||||||
// there was an error in the modal itself
|
// there was an error in the modal itself
|
||||||
|
|
|
||||||
|
|
@ -219,3 +219,13 @@ export function migrateObject<T extends object>(object: T, oldData: any, default
|
||||||
object[key] = oldData.hasOwnProperty(key) ? oldData[key] : defaultData[key];
|
object[key] = oldData.hasOwnProperty(key) ? oldData[key] : defaultData[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function unCamelCase(str: string): string {
|
||||||
|
return str
|
||||||
|
// insert a space between lower & upper
|
||||||
|
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
||||||
|
// space before last upper in a sequence followed by lower
|
||||||
|
.replace(/\b([A-Z]+)([A-Z])([a-z])/, '$1 $2$3')
|
||||||
|
// uppercase the first character
|
||||||
|
.replace(/^./, function(str){ return str.toUpperCase(); });
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue