
index.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>bootstrap 4模态窗口增强插件 </title>
<link rel="stylesheet" href="http://cdn.bootstrapmb.com/bootstrap/4.3.1/css/bootstrap.min.css">
<link href="./src/css/simple-bs-dialog.css" rel="stylesheet" type="text/css" />
<script src="http://cdn.bootstrapmb.com/jquery/jquery-3.3.1.min.js"></script>
<script src="http://cdn.bootstrapmb.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/google/code-prettify@master/loader/run_prettify.js"></script>
<script src="./src/js/simple-bs-dialog.js"></script>
<style>
.login-dialog .modal-header {
color: #0480be;
}
</style>
</head>
<body>
<div class="container">
<h2>Make use of Bootstrap's 4 Modal in a more friendly way.</h2>
<hr />
<h3>Full example</h3>
<p>Full functionality of SimpleBsDialog.</p>
<div class="source-code runnable">
<!--
SimpleBsDialog.show({
width: '900px',
autoWidth: false,
height: '30%',
autoHeight: true,
title: 'Simple Bootstrap 4 Dialog (v' + SimpleBsDialog.version + ')',
closable: true,
spinner: true,
spinnerIcon: '<span class="spinner-border text-primary" role="status"></span>',
closeByBackdrop: true,
closeByKeyboard: true,
html: '',
cssClass: 'login-dialog',
buttons: [{
id: 'btn-ok',
label: 'OK',
cssClass: 'btn-primary',
action: function(dialogRef) {
console.log('OK button pressed!');
dialogRef.close();
},
}, {
id: 'btn-cancel',
label: 'Cancel',
cssClass: 'btn-warning',
action: function(dialogRef) {
console.log('Cancel button pressed!');
dialogRef.close();
},
},
],
onShow: function(dialogRef) {
console.log('onShow');
dialogRef.getButtons().prop('disabled', true);
},
onShown: function(dialogRef) {
console.log('onShown');
setTimeout(function() {
dialogRef.set({
'spinner': false,
}).getModalBody().html('Your content goes here...');
dialogRef.getButtons().prop('disabled', false);
}, 1000);
},
onHide: function(dialogRef) {
console.log('onHide');
},
onHidden: function(dialogRef) {
console.log('onHidden');
},
});
-->
</div>
<!-- Available options -->
<br />
<a name="available-options"></a>
<h2>Available options</h2>
<hr />
<p>
Please note that all options described below are <strong>optional</strong>, but you will have a weird dialog if you don't even give it a title to display.
<br />
Most options can be set via init options or property setters.
</p>
<table class="table table-bordered">
<thead>
<tr>
<th>
Option
</th>
<th>
Type
</th>
<th>
Default value
</th>
<th>
Description
</th>
</tr>
</thead>
<tbody>
<tr>
<td>width</td>
<td>
String or Integer
</td>
<td>
500
</td>
<td>
The dialog's width in pixels or percent. Examples:
<div class="source-code runnable">
SimpleBsDialog.show({
width: '900px',
});
</div>
<hr />
<div class="source-code runnable">
SimpleBsDialog.show({
width: '70%',
});
</div>
<hr />
<div class="source-code runnable">
SimpleBsDialog.show({
width: '600',
});
</div>
</td>
</tr>
<tr>
<td>autoWidth</td>
<td>
Boolean
</td>
<td>
false
</td>
<td>
Enables resizing the dialog when the document is resized. It applies only when the 'width' value is set in percent.
<div class="source-code runnable">
SimpleBsDialog.show({
width: '80%',
autoWidth: true,
});
</div>
</td>
</tr>
<tr>
<td>height</td>
<td>
String or Integer
</td>
<td>
280
</td>
<td>
The dialog's height in pixels or percent. Examples:
<div class="source-code runnable">
SimpleBsDialog.show({
height: '300px',
});
</div>
<hr />
<div class="source-code runnable">
SimpleBsDialog.show({
height: '60%',
});
</div>
</td>
</tr>
<tr>
<td>autoHeight</td>
<td>
Boolean
</td>
<td>
false
</td>
<td>
Enables resizing the dialog when the document is resized. It applies only when the 'height' value is set in percent.
<div class="source-code runnable">
SimpleBsDialog.show({
height: '60%',
autoHeight: true,
});
</div>
</td>
</tr>
<tr>
<td>title</td>
<td>
String
</td>
<td></td>
<td>
The dialog's title.
</td>
</tr>
<tr>
<td>closable</td>
<td>
Boolean
</td>
<td>
true
</td>
<td>
Show|hide the close button at the top right corner.
</td>
</tr>
<tr>
<td>spinner</td>
<td>
Boolean
</td>
<td>
false
</td>
<td>
Show|hide the spinner icon.
</td>
</tr>
<tr>
<td>spinnerIcon</td>
<td>
String
</td>
<td>
<div class="source-code"><span class="spinner-border" role="status"></span></div>
</td>
<td>
Set the spinner's icon.
</td>
</tr>
<tr>
<td>closeByBackdrop</td>
<td>
Boolean
</td>
<td>
true
</td>
<td>
When it's true, you can close it by clicking outside the dialog.
</td>
</tr>
<tr>
<td>closeByKeyboard</td>
<td>
Boolean
</td>
<td>
true
</td>
<td>
When it's true, you can close it by pressing the ESC key.
</td>
</tr>
<tr>
<td>html</td>
<td>
String
</td>
<td></td>
<td>
The dialog's content.
</td>
</tr>
<tr>
<td>cssClass</td>
<td>
String
</td>
<td></td>
<td>
Additional css classes that will be added to your dialog.
</td>
</tr>
<tr>
<td>buttons</td>
<td>
Array
</td>
<td></td>
<td>
Example:
<div class="source-code runnable">
SimpleBsDialog.show({
buttons: [{
id: 'btn-ok',
label: 'OK',
cssClass: 'btn-primary',
action: function(dialogRef) {
dialogRef.close();
},
},
],
});
</div>
<strong>id</strong>: optional, otherwise a random id will be generated.<br />
<strong>label</strong>: optional, the button's title.<br />
<strong>cssClass</strong>: optional, additional css class to be added to the button.<br />
<strong>action</strong>: optional, if provided, the callback will be invoked after the button is clicked, and the dialog instance will be passed to the callback function.<br />
</td>
</tr>
<tr>
<td>onShow</td>
<td>
function
</td>
<td></td>
<td>
If provided, it will be invoked when the dialog is popping up.
</td>
</tr>
<tr>
<td>onShown</td>
<td>
function
</td>
<td></td>
<td>
If provided, it will be invoked when the dialog is popped up.
</td>
</tr>
<tr>
<td>onHide</td>
<td>
function
</td>
<td></td>
<td>
If provided, it will be invoked when the dialog is popping down.
</td>
</tr>
<tr>
<td>onHidden</td>
<td>
function
</td>
<td></td>
<td>
If provided, it will be invoked when the dialog is popped down.
</td>
</tr>
</tbody>
</table>
<!-- Available methods -->
<br />
<a name="available-methods"></a>
<h2>Available methods</h2>
<hr />
<table class="table table-bordered">
<thead>
<tr>
<th>
Method
</th>
<th>
Description
</th>
</tr>
</thead>
<tbody>
<tr>
<td>open()</td>
<td>Opens the dialog. Usage: dialogInstance.open().</td>
</tr>
<tr>
<td>close()</td>
<td>Closes the dialog. Usage: dialogInstance.close().</td>
</tr>
<tr>
<td>get(option)</td>
<td>
Getter for options. You can get the following options:<br />
<strong>width, autoWidth, height, autoHeight, title, closable, spinner, spinnerIcon</strong>
</td>
</tr>
<tr>
<td>set(option, value)</td>
<td>
Setter for a given option. You can set the following options:<br />
<strong>width, autoWidth, height, autoHeight, title, closable, spinner, spinnerIcon</strong>
</td>
</tr>
<tr>
<td>set(options)</td>
<td>
Setter for many options. You can set the following options:<br />
<strong>width, autoWidth, height, autoHeight, title, closable, spinner, spinnerIcon</strong>
</td>
</tr>
<tr>
<td>getModalBody()</td>
<td>Returns the raw modal body.</td>
</tr>
<tr>
<td>getButton(id)</td>
<td>Returns a button by id as a jQuery object.</td>
</tr>
<tr>
<td>getButtons()</td>
<td>Returns all available buttons as jQuery objects.</td>
</tr>
<tr>
<td>SimpleBsDialog.show(options)</td>
<td>Creates a new dialog with options, opens it and returns the dialog object.</td>
</tr>
<tr>
<td>SimpleBsDialog.version</td>
<td>Returns the current SimpleBsDialog's version.</td>
</tr>
</tbody>
</table>
<hr />
</div>
<script type="text/javascript">
$(function () {
$('.source-code').each(function (index) {
var $section = $(this);
var code = $(this).html().replace('<!--', '').replace('-->', '');
// Code preview
var $codePreview = $('<pre class="prettyprint lang-javascript"></pre>');
$codePreview.text(code);
$section.html($codePreview);
// Run code
if ($section.hasClass('runnable')) {
var $button = $('<button class="btn btn-primary">Run the code</button>');
$button.on('click', { code: code }, function (event) {
eval(event.data.code);
});
$button.insertAfter($section);
$('<div class="clearfix" style="margin-bottom: 10px;"></div>').insertAfter($button);
}
});
});
</script>
</body>
</html>
simple-bs-dialog.css
.simple-bs-dialog .modal-dialog,
.simple-bs-dialog .modal-content {
min-height: 200px;
}
.simple-bs-dialog .modal-body {
min-height: 80px;
}
.simple-bs-dialog .modal-spinner {
background: white;
z-index: 1;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
simple-bs-dialog.js
(function(w, $) {
'use strict';
// register the main object
w.SimpleBsDialog = function(options) {
this.options = $.extend({}, {
id: newGuid(),
width: 500,
autoWidth: false,
height: 280,
autoHeight: false,
title: '',
closable: true,
spinner: false,
spinnerIcon: '<span class="spinner-border" role="status"></span>',
closeByBackdrop: true,
closeByKeyboard: true,
html: '',
cssClass: '',
buttons: [],
onShow: function(dialogRef){},
onShown: function(dialogRef){},
onHide: function(dialogRef){},
onHidden: function(dialogRef){},
}, options);
};
// private methods
function newGuid()
{
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = (c == 'x' ? r : r & 0x03 | 0x08);
return v.toString(16);
});
}
function setWidth(e, init)
{
var width = 0;
// parse width
if (e.data.options.width.toString().indexOf('px') >= 0) {
width = parseInt(e.data.options.width.toString().substring(0, e.data.options.width.toString().indexOf('px')));
} else if (e.data.options.width.toString().indexOf('%') >= 0) {
width = parseInt((parseInt(e.data.options.width.toString().substring(0, e.data.options.width.toString().indexOf('%'))) / 100) * $(window).outerWidth(true), 10);
} else {
width = parseInt(e.data.options.width);
}
// set left
$('#' + e.data.options.id).find('.modal-dialog').css({'margin-left': parseInt(($(window).outerWidth(true) - width) / 2, 10) + 'px'});
// set width
if (init === true || (e.data.options.autoWidth === true && e.data.options.width.toString().indexOf('%') >= 0)) {
$('#' + e.data.options.id).find('.modal-content').css({'width': width + 'px'}).find('.modal-body').css({'min-width': (width - 120) + 'px'});
}
}
function setHeight(e, init)
{
var height = 0;
// parse height
if (e.data.options.height.toString().indexOf('px') >= 0) {
height = parseInt(e.data.options.height.toString().substring(0, e.data.options.height.toString().indexOf('px')));
} else if (e.data.options.height.toString().indexOf('%') >= 0) {
height = parseInt((parseInt(e.data.options.height.toString().substring(0, e.data.options.height.toString().indexOf('%'))) / 100) * ($(window).outerHeight(true) - parseInt($('#' + e.data.options.id).find('.modal-dialog').css('margin-top'), 10)), 10);
} else {
height = parseInt(e.data.options.height);
}
// set height
if (init === true || (e.data.options.autoHeight === true && e.data.options.height.toString().indexOf('%') >= 0)) {
$('#' + e.data.options.id).find('.modal-content').css({'min-height': height + 'px'}).find('.modal-body').css({'min-height': (height - 120) + 'px'});
}
}
function setSize(e)
{
setWidth(e, false);
setHeight(e, false);
}
function validOptions()
{
return [
'width',
'autoWidth',
'height',
'autoHeight',
'title',
'closable',
'spinner',
'spinnerIcon',
];
}
function parseCssClass(cssClass)
{
var cssClasses = cssClass.split(' ');
if (cssClasses.length == 0) {
return '';
}
return ' ' + cssClasses.join(' ');
}
// public methods
SimpleBsDialog.prototype.open = function()
{
// store this
var dialog = this;
// bootstrap dialog
$('body').append('<div class="simple-bs-dialog modal fade' + parseCssClass(dialog.options.cssClass) + '" id="' + dialog.options.id + '" tabindex="-1"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">' + dialog.options.title + '</h5><button type="button" class="close' + (dialog.options.closable ? '' : ' d-none') + '" data-dismiss="modal">×</button></div><div class="modal-html"><div class="modal-body">' + dialog.options.html + '</div><div class="modal-spinner' + (dialog.options.spinner ? '' : ' d-none') + '">' + dialog.options.spinnerIcon + '</div></div>' + (dialog.options.buttons.length > 0 ? '<div class="modal-footer"></div>' : '') + '</div></div></div>');
// add buttons
$.each(dialog.options.buttons, function(index, options) {
var opts = $.extend({}, {
id: newGuid(),
label: '',
cssClass: '',
action: function(dialogRef){},
}, options);
var button = $('<button type="button" class="btn btn-default' + (opts.cssClass.length > 0 ? ' ' : '') + opts.cssClass + '" id="' + opts.id + '">' + opts.label + '</button>');
button.on('click', function(e) {
opts.action(dialog);
});
$('#' + dialog.options.id).find('.modal-footer').append(button);
});
// destroy dom element
$('#' + dialog.options.id).on('show.bs.modal', function() {
// initial width
setWidth({
data: dialog,
}, true);
// initial height
setHeight({
data: dialog,
}, true);
// set dialog's auto size
$(window).on('resize', dialog, setSize);
// onShow event
dialog.options.onShow(dialog);
}).on('shown.bs.modal', function() {
// onShown event
dialog.options.onShown(dialog);
}).on('hide.bs.modal', function(e) {
// onHide event
dialog.options.onHide(dialog);
}).on('hidden.bs.modal', function(e) {
// cancel dialog's auto size
$(window).off('resize', setSize);
// remove dialog's div
$('#' + dialog.options.id).remove();
// onHidden event
dialog.options.onHidden(dialog);
}).modal({
'backdrop': dialog.options.closeByBackdrop,
'keyboard': dialog.options.closeByKeyboard,
});
// return main object
return this;
}
SimpleBsDialog.prototype.close = function()
{
$('#' + this.options.id).modal('hide');
// return main object
return this;
}
SimpleBsDialog.prototype.get = function(option)
{
if (validOptions().indexOf(option) > -1) {
return this.options[option];
}
}
SimpleBsDialog.prototype.set = function(options, value)
{
if (!$.isPlainObject(options) && validOptions().indexOf(options) > -1) {
var option = options;
options = {};
options[option] = value;
}
if ($.isPlainObject(options)) {
// store this
var dialog = this;
$.each(options, function(option, value) {
switch (option) {
case 'width': {
// new width
dialog.options.width = value;
// init new size
setWidth({
data: dialog,
}, true);
break;
}
case 'autoWidth': {
// new autoWidth
dialog.options.autoWidth = value;
// init new size
setWidth({
data: dialog,
}, true);
break;
}
case 'height': {
// new height
dialog.options.height = value;
// init new size
setHeight({
data: dialog,
}, true);
break;
}
case 'autoHeight': {
// new autoHeight
dialog.options.autoHeight = value;
// init new size
setHeight({
data: dialog,
}, true);
break;
}
case 'title': {
// update dialog's title
$('#' + dialog.options.id).find('.modal-title').html(dialog.options.title = value);
break;
}
case 'closable': {
// update dialog's closable
if (dialog.options.closable = value) {
$('#' + dialog.options.id).find('.modal-header button.close').removeClass('d-none');
} else {
$('#' + dialog.options.id).find('.modal-header button.close').addClass('d-none');
}
break;
}
case 'spinner': {
// update dialog's spinner
if (dialog.options.spinner = value) {
$('#' + dialog.options.id).find('.modal-spinner').removeClass('d-none');
} else {
$('#' + dialog.options.id).find('.modal-spinner').addClass('d-none');
}
break;
}
case 'spinnerIcon': {
// update dialog's spinnerIcon
$('#' + dialog.options.id).find('.modal-spinner').html(dialog.options.spinnerIcon = value);
break;
}
}
});
}
// return main object
return this;
}
SimpleBsDialog.prototype.getModalBody = function()
{
// get modal body
return $('#' + this.options.id).find('.modal-body');
}
SimpleBsDialog.prototype.getButton = function(id)
{
// get button's object
return $('#' + this.options.id).find('.modal-footer button#' + id);
}
SimpleBsDialog.prototype.getButtons = function()
{
// get all the buttons' object
return $('#' + this.options.id).find('.modal-footer button');
}
// for lazy people
SimpleBsDialog.show = function(options)
{
return (new SimpleBsDialog(options)).open();
}
// current version
SimpleBsDialog.version = '1.0.1';
}(window, jQuery));
参考:http://www.bootstrapmb.com/item/6561/preview