This commit is contained in:
Yuri Kuznetsov
2022-06-18 19:14:09 +03:00
parent b69d55d114
commit cb43e60ae9
3 changed files with 269 additions and 19 deletions

View File

@@ -55,22 +55,24 @@ define('ui', [], function () {
*/
/**
* A button or a dropdown action item.
* A button or dropdown action item.
*
* @typedef {Object} module:ui.Dialog~Button
*
* @property {boolean} [hidden] Is hidden.
* @property {string} name A name.
* @property {boolean} [pullLeft=false] To put the button to the other side.
* @property {string} [html] HTML.
* @property {string} [text] A title.
* @property {boolean} [disabled=false] Disabled.
* @property {boolean} [hidden=false] Hidden.
* @property {'default'|'danger'|'success'|'warning'} [style='default'] A style.
* @property {Function} [onClick] An on-click callback.
* @property {function():void} [onClick] An on-click callback.
*/
/**
* @class
* @name Espo.Ui.Dialog
*
* @param {module:ui.Dialog~Params} options Options.
*/
let Dialog = function (options) {

View File

@@ -31,12 +31,14 @@ define('view', [], function () {
/**
* A base view.
*
* @see {@link https://docs.espocrm.com/development/view/}
*
* @class
* @name Class
* @extends Bull.View
* @memberOf module:view
*/
return Bull.View.extend(/** @lends module:view.Class.prototype */{
return Bull.View.extend(/** @lends module:view.Class# */{
/**
* @callback module:view.Class~actionHandlerCallback

View File

@@ -28,52 +28,199 @@
define('views/modal', ['view'], function (Dep) {
return Dep.extend({
/**
* A base modal view. Can be extended or used directly.
*
* Options:
* - `headerHtml`
* - `headerText`
* - `$header`
* - `backdrop`
* - `buttonList`
* - `dropdownItemList`
*
* @see {@link https://docs.espocrm.com/development/modal/}
*
* @class
* @name Class
* @extends module:view.Class
* @memberOf module:views/modal
*/
return Dep.extend(/** @lends module:views/modal.Class# */{
/**
* A button or dropdown action item.
*
* @typedef {Object} module:views/modal.Class~Button
*
* @property {string} name A name.
* @property {string} [label] A label. To be translated
* (with a scope defined in the `scope` class property).
* @property {string} [text] A text (not translated).
* @property {string} [html] HTML.
* @property {boolean} [pullLeft=false] To put the button to the other side.
* @property {'default'|'danger'|'success'|'warning'} [style='default'] A style.
* @property {boolean} [hidden=false] Is hidden.
* @property {boolean} [disabled=false] Disabled.
* @property {function():void} [onClick] Called on click. If not defined, then
* the `action<Name>` class method will be called.
*/
/**
* A CSS name.
*
* @protected
*/
cssName: 'modal-dialog',
/**
* A class-name. Use `'dialog dialog-record'` for modals containing a record form.
*
* @protected
*/
className: 'dialog',
/**
* @protected
* @deprecated Use `headerHtml`
*/
header: false,
/**
* A header HTML.
*
* @protected
* @type {string}
*/
headerHtml: null,
/**
* A dialog instance.
*
* @protected
* @type {Espo.Ui.Dialog}
*/
dialog: null,
/**
* A container selector.
*
* @protected
* @type {string}
*/
containerSelector: null,
/**
* A scope name. Used when translating button labels.
*
* @protected
* @type {string|null}
*/
scope: null,
/**
* A backdrop.
*
* @protected
* @type {'static'|boolean}
*/
backdrop: 'static',
/**
* Buttons.
*
* @protected
* @type {module:views/modal.Class~Button[]}
*/
buttonList: [],
/**
* Dropdown action items.
*
* @protected
* @type {module:views/modal.Class~Button[]}
*/
dropdownItemList: [],
// @todo Remove it as deprecated.
/**
* @deprecated Use `buttonList`.
* @protected
* @todo Remove.
*/
buttons: [],
width: false,
/**
* A width.
*
* @protected
* @type {number|null}
*/
width: null,
/**
* Not used.
*
* @deprecated
*/
fitHeight: false,
/**
* To disable fitting to a window height.
*
* @protected
* @type {boolean}
*/
noFullHeight: false,
/**
* Disable the ability to close by pressing the `Esc` key.
*
* @protected
* @type {boolean}
*/
escapeDisabled: false,
/**
* Is draggable.
*
* @protected
* @type {boolean}
*/
isDraggable: false,
/**
* Is collapsable.
*
* @protected
* @type {boolean}
*/
isCollapsable: false,
/**
* Is collapsed. Do not change value. Only for reading.
*
* @protected
* @type {boolean}
*/
isCollapsed: false,
/**
* @inheritDoc
*/
events: {
/** @this module:views/modal.Class */
'click .action': function (e) {
Espo.Utils.handleAction(this, e);
},
/** @this module:views/modal.Class */
'click [data-action="collapseModal"]': function () {
this.collapse();
},
},
/**
* @inheritDoc
*/
init: function () {
var id = this.cssName + '-container-' + Math.floor((Math.random() * 10000) + 1).toString();
var containerSelector = this.containerSelector = '#' + id;
@@ -86,8 +233,6 @@ define('views/modal', ['view'], function (Dep) {
this.headerHtml = Handlebars.Utils.escapeExpression(this.options.headerText);
}
this.options = this.options || {};
this.backdrop = this.options.backdrop || this.backdrop;
this.setSelector(this.containerSelector);
@@ -173,11 +318,17 @@ define('views/modal', ['view'], function (Dep) {
});
},
/**
* Get a button list for a dialog.
*
* @private
* @return {module:ui.Dialog~Button[]}
*/
getDialogButtonList: function () {
var buttonListExt = [];
// TODO remove it as deprecated
this.buttons.forEach((item) => {
this.buttons.forEach(item => {
var o = Espo.Utils.clone(item);
if (!('text' in o) && ('label' in o)) {
@@ -187,8 +338,7 @@ define('views/modal', ['view'], function (Dep) {
buttonListExt.push(o);
});
this.buttonList.forEach((item) => {
this.buttonList.forEach(item => {
var o = {};
if (typeof item === 'string') {
@@ -219,6 +369,12 @@ define('views/modal', ['view'], function (Dep) {
return buttonListExt;
},
/**
* Get a dropdown item list for a dialog.
*
* @private
* @return {module:ui.Dialog~Button[]}
*/
getDialogDropdownItemList: function () {
var dropdownItemListExt = [];
@@ -253,6 +409,9 @@ define('views/modal', ['view'], function (Dep) {
return dropdownItemListExt;
},
/**
* @private
*/
updateDialog: function () {
if (!this.dialog) {
return;
@@ -262,6 +421,9 @@ define('views/modal', ['view'], function (Dep) {
this.dialog.dropdownItemList = this.getDialogDropdownItemList();
},
/**
* @private
*/
onDialogClose: function () {
if (!this.isBeingRendered() && !this.isCollapsed) {
this.trigger('close');
@@ -269,20 +431,34 @@ define('views/modal', ['view'], function (Dep) {
}
},
/**
* A `cancel` action.
*/
actionCancel: function () {
this.trigger('cancel');
this.dialog.close();
},
/**
* A `close` action.
*/
actionClose: function () {
this.trigger('cancel');
this.dialog.close();
},
/**
* Close a dialog.
*/
close: function () {
this.dialog.close();
},
/**
* Disable a button.
*
* @param {string} name A button name.
*/
disableButton: function (name) {
this.buttonList.forEach((d) => {
if (d.name !== name) {
@@ -301,6 +477,11 @@ define('views/modal', ['view'], function (Dep) {
.attr('disabled', 'disabled');
},
/**
* Enable a button.
*
* @param {string} name A button name.
*/
enableButton: function (name) {
this.buttonList.forEach((d) => {
if (d.name !== name) {
@@ -319,6 +500,14 @@ define('views/modal', ['view'], function (Dep) {
.removeAttr('disabled');
},
/**
* Add a button.
*
* @param {module:ui.Dialog~Button} o Button definitions.
* @param {boolean|string} [position=false] True prepends, false appends. If a string,
* then will be added after a button with a corresponding name.
* @param {boolean} [doNotReRender=false] Do not re-render.
*/
addButton: function (o, position, doNotReRender) {
var index = -1;
@@ -359,6 +548,13 @@ define('views/modal', ['view'], function (Dep) {
}
},
/**
* Add a dropdown item.
*
* @param {module:ui.Dialog~Button} o Button definitions.
* @param {boolean} [toBeginning=false] To prepend.
* @param {boolean} [doNotReRender=false] Do not re-render.
*/
addDropdownItem: function (o, toBeginning, doNotReRender) {
var method = toBeginning ? 'unshift' : 'push';
@@ -387,6 +583,9 @@ define('views/modal', ['view'], function (Dep) {
}
},
/**
* @private
*/
reRenderFooter: function () {
if (!this.dialog) {
return;
@@ -401,6 +600,12 @@ define('views/modal', ['view'], function (Dep) {
this.dialog.initButtonEvents();
},
/**
* Remove a button or a dropdown action item.
*
* @param {string} name A name.
* @param {boolean} [doNotReRender=false] Do not re-render.
*/
removeButton: function (name, doNotReRender) {
var index = -1;
@@ -431,6 +636,12 @@ define('views/modal', ['view'], function (Dep) {
}
},
/**
* @deprecated Use `showActionItem`.
*
* @protected
* @param {string} name
*/
showButton: function (name) {
this.buttonList.forEach((d) => {
if (d.name !== name) {
@@ -447,6 +658,12 @@ define('views/modal', ['view'], function (Dep) {
this.$el.find('footer button[data-name="'+name+'"]').removeClass('hidden');
},
/**
* @deprecated Use `hideActionItem`.
*
* @protected
* @param {string} name
*/
hideButton: function (name) {
this.buttonList.forEach((d) => {
if (d.name !== name) {
@@ -463,8 +680,13 @@ define('views/modal', ['view'], function (Dep) {
this.$el.find('footer button[data-name="'+name+'"]').addClass('hidden');
},
/**
* Show an action item (button or dropdown item).
*
* @param {string} name A name.
*/
showActionItem: function (name) {
this.buttonList.forEach((d) => {
this.buttonList.forEach(d => {
if (d.name !== name) {
return;
}
@@ -472,7 +694,7 @@ define('views/modal', ['view'], function (Dep) {
d.hidden = false;
});
this.dropdownItemList.forEach((d) => {
this.dropdownItemList.forEach(d => {
if (d.name !== name) {
return;
}
@@ -492,15 +714,20 @@ define('views/modal', ['view'], function (Dep) {
}
},
/**
* Hide an action item (button or dropdown item).
*
* @param {string} name A name.
*/
hideActionItem: function (name) {
this.buttonList.forEach((d) => {
this.buttonList.forEach(d => {
if (d.name !== name) {
return;
}
d.hidden = true;
});
this.dropdownItemList.forEach((d) => {
this.dropdownItemList.forEach(d => {
if (d.name !== name) {
return;
}
@@ -520,6 +747,10 @@ define('views/modal', ['view'], function (Dep) {
}
},
/**
* @private
* @return {boolean}
*/
isDropdownItemListEmpty: function () {
if (this.dropdownItemList.length === 0) {
return true;
@@ -536,15 +767,20 @@ define('views/modal', ['view'], function (Dep) {
return isEmpty;
},
/**
* @private
* @param {number} [step=0]
*/
adjustHeaderFontSize: function (step) {
step = step || 0;
if (!step) this.fontSizePercentage = 100;
if (!step) {
this.fontSizePercentage = 100;
}
var $titleText = this.$el.find('.modal-title > .modal-title-text');
var containerWidth = $titleText.parent().width();
var textWidth = 0;
$titleText.children().each((i, el) => {
@@ -567,12 +803,16 @@ define('views/modal', ['view'], function (Dep) {
var fontSizePercentage = this.fontSizePercentage -= 4;
this.$el.find('.modal-title .font-size-flexible').css('font-size', this.fontSizePercentage + '%');
this.$el.find('.modal-title .font-size-flexible')
.css('font-size', this.fontSizePercentage + '%');
this.adjustHeaderFontSize(step + 1);
}
},
/**
* Collapse.
*/
collapse: function () {
this.beforeCollapse().then(data => {
if (!this.getParentView()) {
@@ -629,6 +869,12 @@ define('views/modal', ['view'], function (Dep) {
});
},
/**
* Called before collapse. Can be extended to execute some logic, e.g. save form data.
*
* @protected
* @return {Promise}
*/
beforeCollapse: function () {
return new Promise(resolve => resolve());
},