The communications platform that puts data protection first.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
Rocket.Chat/app/ui-utils/client/lib/modal.js

285 lines
6.5 KiB

import { Meteor } from 'meteor/meteor';
import { Blaze } from 'meteor/blaze';
import { Template } from 'meteor/templating';
import { t, getUserPreference, handleError } from '../../../utils';
import './modal.html';
let modalStack = [];
const createModal = (config = {}, fn, onCancel) => {
config.confirmButtonText = config.confirmButtonText || (config.type === 'error' ? t('Ok') : t('Send'));
config.cancelButtonText = config.cancelButtonText || t('Cancel');
config.closeOnConfirm = config.closeOnConfirm == null ? true : config.closeOnConfirm;
config.showConfirmButton = config.showConfirmButton == null ? true : config.showConfirmButton;
config.showFooter = config.showConfirmButton === true || config.showCancelButton === true;
config.confirmOnEnter = config.confirmOnEnter == null ? true : config.confirmOnEnter;
config.closeOnEscape = config.closeOnEscape == null ? true : config.closeOnEscape;
if (config.type === 'input') {
config.input = true;
config.type = false;
if (!config.inputType) {
config.inputType = 'text';
}
}
let renderedModal;
let timer;
const instance = {
...config,
render: () => {
if (renderedModal) {
renderedModal.firstNode().style.display = '';
return;
}
renderedModal = Blaze.renderWithData(Template.rc_modal, instance, document.body);
if (config.timer) {
timer = setTimeout(() => {
instance.close();
}, config.timer);
}
},
hide: () => {
if (renderedModal) {
renderedModal.firstNode().style.display = 'none';
}
if (timer) {
clearTimeout(timer);
timer = undefined;
}
},
destroy: () => {
if (renderedModal) {
Blaze.remove(renderedModal);
renderedModal = undefined;
}
if (timer) {
clearTimeout(timer);
timer = undefined;
}
},
close: () => {
if (onCancel) {
onCancel.call(instance);
}
instance.destroy();
modalStack = modalStack.filter((modal) => modal !== instance);
if (modalStack.length) {
modalStack[modalStack.length - 1].render();
}
},
confirm: (value) => {
config.closeOnConfirm && instance.close();
if (fn) {
fn.call(instance, value);
return;
}
instance.close();
},
cancel: () => {
instance.close();
},
showInputError: (text) => {
const errorEl = document.querySelector('.rc-modal__content-error');
errorEl.innerHTML = text;
errorEl.style.display = 'block';
},
};
return instance;
};
export const modal = {
open: (config = {}, fn, onCancel) => {
modalStack.forEach((instance) => {
instance.destroy();
});
modalStack = [];
const instance = createModal(config, fn, onCancel);
if (config.dontAskAgain) {
const dontAskAgainList = getUserPreference(Meteor.userId(), 'dontAskAgainList');
if (dontAskAgainList && dontAskAgainList.some((dontAsk) => dontAsk.action === config.dontAskAgain.action)) {
instance.confirm(true);
return;
}
}
instance.render();
modalStack.push(instance);
},
push: (config = {}, fn, onCancel) => {
const instance = createModal(config, fn, onCancel);
modalStack.forEach((instance) => {
instance.hide();
});
instance.render();
modalStack.push(instance);
return instance;
},
cancel: () => {
if (modalStack.length) {
modalStack[modalStack.length - 1].cancel();
}
},
close: () => {
if (modalStack.length) {
modalStack[modalStack.length - 1].close();
}
},
confirm: (value) => {
if (modalStack.length) {
modalStack[modalStack.length - 1].confirm(value);
}
},
showInputError: (text) => {
if (modalStack.length) {
modalStack[modalStack.length - 1].showInputError(text);
}
},
onKeyDown: (event) => {
if (!modalStack.length) {
return;
}
const instance = modalStack[modalStack.length - 1];
if (event.key === 'Escape') {
event.preventDefault();
event.stopPropagation();
instance.close();
}
if (instance && instance.confirmOnEnter && event.key === 'Enter') {
event.preventDefault();
event.stopPropagation();
if (instance.input) {
return instance.confirm($('.js-modal-input').val());
}
instance.confirm(true);
}
},
};
Template.rc_modal.helpers({
showFooter() {
const { showCancelButton, showConfirmButton } = this;
return showCancelButton || showConfirmButton;
},
hasAction() {
return !!this.action;
},
type() {
return this.type && `rc-modal__content-icon rc-modal__content-icon--modal-${ this.type }`;
},
modalIcon() {
switch (this.type) {
case 'success':
return 'checkmark-circled';
case 'error':
return 'circle-cross';
case 'info':
return 'info-circled';
default:
return `modal-${ this.type }`;
}
},
});
Template.rc_modal.onRendered(function() {
this.oldFocus = document.activeElement;
if (this.data.onRendered) {
this.data.onRendered();
}
if (this.data.input) {
$('.js-modal-input', this.firstNode).focus();
} else if (this.data.showConfirmButton && this.data.confirmOnEnter) {
$('.js-confirm', this.firstNode).focus();
}
this.data.closeOnEscape && document.addEventListener('keydown', modal.onKeyDown);
});
Template.rc_modal.onDestroyed(function() {
this.oldFocus && this.oldFocus.focus();
document.removeEventListener('keydown', modal.onKeyDown);
});
Template.rc_modal.events({
'click .js-action'(event, instance) {
!this.action || this.action.call(instance.data.data, event, instance);
event.stopPropagation();
this.close();
},
'click .js-input-action'(e, instance) {
!this.inputAction || this.inputAction.call(instance.data.data, e, instance);
e.stopPropagation();
},
'click .js-close'(e) {
e.preventDefault();
e.stopPropagation();
this.cancel();
},
'click .js-confirm'(event, instance) {
event.stopPropagation();
const { dontAskAgain } = instance.data;
if (dontAskAgain && document.getElementById('dont-ask-me-again').checked) {
const dontAskAgainObject = {
action: dontAskAgain.action,
label: dontAskAgain.label,
};
let dontAskAgainList = getUserPreference(Meteor.userId(), 'dontAskAgainList');
if (dontAskAgainList) {
dontAskAgainList.push(dontAskAgainObject);
} else {
dontAskAgainList = [dontAskAgainObject];
}
Meteor.call('saveUserPreferences', { dontAskAgainList }, function(error) {
if (error) {
return handleError(error);
}
});
}
if (instance.data.input) {
this.confirm(document.getElementsByClassName('js-modal-input')[0].value);
return;
}
this.confirm(true);
},
'click .rc-modal-wrapper'(event, instance) {
if (instance.data.allowOutsideClick === false) {
return false;
}
if (event.currentTarget === event.target) {
event.stopPropagation();
this.close();
}
},
});