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.
gristlabs_grist-core/app/client/components/ModalDialog.js

126 lines
4.5 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/* global $, document, window */
var _ = require('underscore');
var ko = require('knockout');
var BackboneEvents = require('backbone').Events;
var dom = require('../lib/dom');
var kd = require('../lib/koDom');
var Base = require('./Base');
/**
* ModalDialog constructor creates a new ModalDialog element. The dialog accepts a bunch of
* options, and the content can be overridde when calling .show(), so that a single ModalDialog
* component can be used for different purposes. It triggers a 'close' event (using
* Backbone.Events) when hidden.
*
* The DOM of the dialog is always attached to document.body.
*
* @param {Boolean} [options.fade] Include `fade` css class to fade the modal in/out.
* @param {Boolean} [options.close] Include a close icon in the corner (default true).
* @param {Boolean} [options.backdrop] Include a modal-backdrop element (default true).
* @param {Boolean} [options.keyboard] Close the modal on Escape key (default true).
* @param {Boolean} [options.show] Shows the modal when initialized (default true).
* @param {CSS String} [options.width] Optional css width to override default.
* @param {DOM|String} [options.title] The content to place in the title.
* @param {DOM|String} [options.body] The content to place in the body.
* @param {DOM|String} [options.footer] The content to place in the footer.
*/
function ModalDialog(options) {
Base.call(this, options);
options = options || {};
this.options = _.defaults(options, {
fade: false, // Controls whether the model pops or fades into view
close: true, // Determines whether the "x" dismiss icon appears in the modal
backdrop: true,
keyboard: true,
show: false,
});
// If the width option is set, the margins must be set to auto to keep the dialog centered.
this.style = options.width ?
`width: ${this.options.width}; margin-left: auto; margin-right: auto;` : '';
this.title = ko.observable(options.title || null);
this.body = ko.observable(options.body || null);
this.footer = ko.observable(options.footer || null);
this.modal = this.autoDispose(this._buildDom());
document.body.appendChild(this.modal);
$(this.modal).modal(_.pick(this.options, 'backdrop', 'keyboard', 'show'));
// On applyState event, close the modal.
this.onEvent(window, 'applyState', () => this.hide());
// If disposed, let the underlying JQuery Modal run its hiding logic, and trigger 'close' event.
this.autoDisposeCallback(this.hide);
}
Base.setBaseFor(ModalDialog);
_.extend(ModalDialog.prototype, BackboneEvents);
/**
* Shows the ModalDialog. It accepts the same `title`, `body`, and `footer` options as the
* constructor, which will replace previous content of those sections.
*/
ModalDialog.prototype.show = function(options) {
options = options || {};
// Allow options to specify new title, body, and footer content.
['title', 'body', 'footer'].forEach(function(prop) {
if (options.hasOwnProperty(prop)) {
this[prop](options[prop]);
}
}, this);
$(this.modal).modal('show');
};
/**
* Hides the ModalDialog. This triggers the `close` to be triggered using Backbone.Events.
*/
ModalDialog.prototype.hide = function() {
$(this.modal).modal('hide');
};
/**
* Internal helper to build the DOM of the dialog.
*/
ModalDialog.prototype._buildDom = function() {
var self = this;
// The .clipboard_focus class tells Clipboard.js to let this component have focus. Otherwise
// it's impossible to select text.
return dom('div.modal.clipboard_focus',
{ "role": "dialog", "tabIndex": -1 },
// Emit a 'close' Backbone.Event whenever the dialog is hidden.
dom.on('hidden.bs.modal', function() {
self.trigger('close');
}),
dom('div.modal-dialog', { style: this.style },
dom('div.modal-content',
kd.toggleClass('fade', self.options.fade),
kd.maybe(this.title, function(title) {
return dom('div.modal-header',
kd.maybe(self.options.close, function () {
return dom('button.close',
{"data-dismiss": "modal", "aria-label": "Close"},
dom('span', {"aria-hidden": true}, '×')
);
}),
dom('h4.modal-title', title)
);
}),
kd.maybe(this.body, function(body) {
return dom('div.modal-body', body);
}),
kd.maybe(this.footer, function(footer) {
return dom('div.modal-footer', footer);
})
)
)
);
};
module.exports = ModalDialog;