converse.js
Version:
Browser based XMPP chat client
211 lines (195 loc) • 6.65 kB
JavaScript
import './alert.js';
import Confirm from './confirm.js';
import { Model } from '@converse/skeletor';
import { api } from '@converse/headless';
let modals = [];
let modals_map = {};
let toasts_map = {};
const modal_api = {
/**
* API namespace for methods relating to modals
* @namespace _converse.api.modal
* @memberOf _converse.api
*/
modal: {
/**
* Shows a modal of type `ModalClass` to the user.
* Will create a new instance of that class if an existing one isn't
* found.
* @param {string|any} name
* @param {Object} [properties] - Optional properties that will be set on a newly created modal instance.
* @param {Event} [ev] - The DOM event that causes the modal to be shown.
*/
show(name, properties, ev) {
let modal;
if (typeof name === 'string') {
modal = this.get(name) ?? this.create(name, properties);
Object.assign(modal, properties);
} else {
// Legacy...
const ModalClass = name;
const id = ModalClass.id ?? properties.id;
modal = this.get(id) ?? this.create(ModalClass, properties);
}
modal.show(ev);
return modal;
},
/**
* Return a modal with the passed-in identifier, if it exists.
* @param {String} id
*/
get(id) {
return modals_map[id] ?? modals.filter((m) => m.id == id).pop();
},
/**
* Create a modal of the passed-in type.
* @param {String} name
* @param {Object} [properties] - Optional properties that will be
* set on the modal instance.
*/
create(name, properties) {
const ModalClass = customElements.get(name);
const modal = (modals_map[name] = new ModalClass(properties));
return modal;
},
/**
* Remove a particular modal
* @param {String} name
*/
remove(name) {
let modal;
if (typeof name === 'string') {
modal = modals_map[name];
delete modals_map[name];
} else {
// Legacy...
modal = name;
modals = modals.filter((m) => m !== modal);
}
modal?.remove();
},
/**
* Remove all modals
*/
removeAll() {
modals.forEach((m) => m.remove());
modals = [];
modals_map = {};
},
},
/**
* Show a confirm modal to the user.
* @method _converse.api.confirm
* @param {String} title - The header text for the confirmation dialog
* @param {(Array<String>|String)} messages - The text to show to the user
* @param {Array<import('./types').Field>} fields - An object representing a field presented to the user.
* @returns {Promise<Array|false>} A promise which resolves with an array of
* filled in fields or `false` if the confirm dialog was closed or canceled.
*/
async confirm(title, messages = [], fields = []) {
if (typeof messages === 'string') {
messages = [messages];
}
const state = new Model({ title, messages, fields, 'type': 'confirm' });
const confirm = new Confirm({ state });
confirm.show();
let result;
try {
result = await confirm.confirmation;
} catch (e) {
result = false;
}
confirm.remove();
return result;
},
/**
* Show a prompt modal to the user.
* @method _converse.api.prompt
* @param { String } title - The header text for the prompt
* @param { (Array<String>|String) } messages - The prompt text to show to the user
* @param { String } placeholder - The placeholder text for the prompt input
* @returns { Promise<String|false> } A promise which resolves with the text provided by the
* user or `false` if the user canceled the prompt.
*/
async prompt(title, messages = [], placeholder = '') {
if (typeof messages === 'string') {
messages = [messages];
}
const state = new Model({
title,
messages,
fields: [
{
'name': 'reason',
'placeholder': placeholder,
},
],
type: 'prompt',
});
const prompt = new Confirm({ state });
prompt.show();
let result;
try {
result = (await prompt.confirmation).pop()?.value;
} catch (e) {
result = false;
}
prompt.remove();
return result;
},
/**
* Show an alert modal to the user.
* @method _converse.api.alert
* @param { ('info'|'warn'|'error') } type - The type of alert.
* @param { String } title - The header text for the alert.
* @param { (Array<String>|String) } messages - The alert text to show to the user.
*/
alert(type, title, messages) {
if (typeof messages === 'string') {
messages = [messages];
}
let level;
if (type === 'error') {
level = 'alert-danger';
} else if (type === 'info') {
level = 'alert-info';
} else if (type === 'warn') {
level = 'alert-warning';
}
const state = new Model({ title, messages, level, 'type': 'alert' });
modal_api.modal.show('converse-alert-modal', { state });
},
/**
* API namespace for methods relating to toast messages
* @namespace _converse.api.toast
* @memberOf _converse.api
*/
toast: {
/**
* @param {string} name
* @param {import('./types').ToastProperties} [properties] - Optional properties that will be set on a newly created toast instance.
*/
show(name, properties) {
toasts_map[name] = properties;
api.trigger('showToast', properties);
},
/**
* @param {String} [name]
*/
get(name) {
if (name) {
return toasts_map[name];
} else {
return Object.keys(toasts_map).map((name) => ({ name, ...toasts_map[name] }));
}
},
/**
* @param {String} [name]
*/
remove(name) {
delete toasts_map[name];
api.trigger('hideToast');
},
},
};
export default modal_api;