├── .eslintignore ├── .eslintrc ├── .gitignore ├── .npmignore ├── README.md ├── bower.json ├── changelog.txt ├── composer.json ├── dist ├── css │ ├── bootstrap-dialog.css │ └── bootstrap-dialog.min.css ├── js │ ├── bootstrap-dialog.js │ └── bootstrap-dialog.min.js └── less │ └── bootstrap-dialog.less ├── examples ├── images │ └── pig.ico ├── index.html ├── play │ ├── append-to-div.html │ ├── button-event.html │ ├── custom-dialog-id.html │ ├── only-one-dialog.html │ ├── reopen-dialog.html │ ├── spinning-icon.html │ └── tabindex.html └── remote.html ├── gulpfile.js ├── package.json └── src ├── css └── bootstrap-dialog.css ├── js └── bootstrap-dialog.js └── less └── bootstrap-dialog.less /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/** 2 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true 4 | }, 5 | 6 | "rules": { 7 | "brace-style": [2, "1tbs"], 8 | "default-case": 2, 9 | "func-style": [2, "declaration"], 10 | "guard-for-in": 2, 11 | "no-floating-decimal": 2, 12 | "no-nested-ternary": 2, 13 | "radix": 2, 14 | "space-unary-word-ops": 2, 15 | "space-after-keywords": [2, "always"], 16 | "valid-jsdoc": [2, { 17 | "prefer": { 18 | "return": "returns" 19 | } 20 | }], 21 | "quotes": [1, "single", "allow-avoiding-escaped-quotes"], 22 | "wrap-iife": 2 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | nbproject 2 | node_modules 3 | bower_components 4 | /vendor/ 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nakupanda/bootstrap3-dialog/a491a98c97921114883ad44e5715fe28396dbaea/.npmignore -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | bootstrap-dialog 2 | ================ 3 | 4 | [![Latest release](https://img.shields.io/github/release/nakupanda/bootstrap3-dialog.svg)](https://github.com/nakupanda/bootstrap3-dialog/releases/latest) 5 | 6 | Make use of Bootstrap Modal more monkey-friendly. 7 | 8 | See live examples here: http://nakupanda.github.io/bootstrap3-dialog/ 9 | 10 | Please note that this project is for Bootstrap 3. 11 | 12 | Thanks for [akinoniku](https://github.com/akinoniku)'s suggestions on dialog appearance. 13 | 14 | ================ 15 | 16 | ## Ask a question 17 | 18 | It's recommended to provide online examples when asking questions or reporting bugs. 19 | Fork this all-ready jsfiddle and start writing your example: 20 | http://jsfiddle.net/o5k0eaws/1/ 21 | 22 | ================ 23 | 24 | ## Use Guidances from contributors 25 | 26 | How to use bootstrap-dialog as Rails 4 confirm - @[Genkilabs](https://github.com/Genkilabs) 27 | 28 | How to use in ReactJS - @[sonhan](https://github.com/sonhan) 29 | 30 | ================ 31 | ## Reference to CDN 32 | 33 | ``` 34 | https://cdnjs.cloudflare.com/ajax/libs/bootstrap3-dialog/1.34.7/css/bootstrap-dialog.min.css 35 | https://cdnjs.cloudflare.com/ajax/libs/bootstrap3-dialog/1.34.7/js/bootstrap-dialog.min.js 36 | ``` 37 | ================ 38 | 39 | ## Install using Bower 40 | 41 | ``` 42 | bower install bootstrap-dialog 43 | ``` 44 | 45 | Or 46 | 47 | ``` 48 | bower install bootstrap3-dialog 49 | ``` 50 | 51 | ================ 52 | 53 | ## Install using npm 54 | 55 | ``` 56 | npm install --save bootstrap3-dialog 57 | ``` 58 | 59 | ================ 60 | 61 | ## Build instructions: 62 | 63 | Prepare: 64 | 65 | ``` 66 | npm install 67 | ``` 68 | 69 | Build: 70 | 71 | ``` 72 | gulp dist 73 | ``` 74 | 75 | ================ 76 | 77 | Licensed under The MIT License. 78 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap3-dialog", 3 | "description": "Make use of Bootstrap Modal more monkey-friendly. http://nakupanda.github.io/bootstrap3-dialog/", 4 | "version": "1.35.4", 5 | "keywords": [ 6 | "css", 7 | "js", 8 | "less", 9 | "mobile-first", 10 | "responsive", 11 | "front-end", 12 | "framework", 13 | "web" 14 | ], 15 | "homepage": "http://nakupanda.github.io/bootstrap3-dialog/", 16 | "main": [ 17 | "dist/less/bootstrap-dialog.less", 18 | "dist/css/bootstrap-dialog.min.css", 19 | "dist/js/bootstrap-dialog.min.js" 20 | ], 21 | "license": "MIT", 22 | "ignore": [ 23 | "source", 24 | "spec", 25 | ".bowerrc", 26 | ".gitignore", 27 | ".jshintignore", 28 | ".jshintrc", 29 | "bower.json", 30 | "gruntfile.js", 31 | "package.json", 32 | "README.md" 33 | ], 34 | "dependencies": { 35 | "bootstrap": ">= 3.1.0", 36 | "jquery": ">= 1.9.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /changelog.txt: -------------------------------------------------------------------------------- 1 | LASTEST NOT RELEASED 2 | ------------------------------ 3 | * Merged #347 * 4 | 5 | V1.35.4 6 | ------------------------------ 7 | * Refs #300 * 8 | * Refs #308 * 9 | * Refs #232 * 10 | * Refs #334 * 11 | * Refs #331 * 12 | 13 | V1.35.3 14 | ------------------------------ 15 | * Refs #144 * 16 | * Refs #284 * 17 | * Refs #231 * 18 | * Refs #271 * 19 | * Refs #294 * 20 | 21 | V1.35.2 22 | ------------------------------ 23 | * Refs #251 Close icon on the top right is configurable * 24 | * Refs #249 * 25 | * Refs #256 * 26 | 27 | V1.35.1 28 | ------------------------------ 29 | * Refs #243 * 30 | 31 | V1.35.0 32 | ------------------------------ 33 | * Refs #224 * 34 | * Refs #208 * 35 | * Refs #233 * 36 | * Refs #247 * 37 | * Refs #248 * 38 | 39 | V1.34.9 40 | ------------------------------ 41 | * Fixed #221 * 42 | 43 | V1.34.8 44 | ------------------------------ 45 | * Set 'realized' status to false when closing a 'autodestroy' dialog. * 46 | * Merged #136 * 47 | * Refs #210 * 48 | * Merged #219 * 49 | 50 | V1.34.7 51 | ------------------------------ 52 | * Refs #176 * 53 | * Refs #109, Add methods getDialog(), setDialog() and addDialog() to BootstrapDialog. * 54 | * Refs #201 * 55 | * Refs #200 * 56 | 57 | V1.34.6 58 | ------------------------------ 59 | * Refs #159 * 60 | * Refs #160* 61 | * Refs #179, removed local assets for example page, and used files hosted on CDN instead. * 62 | 63 | V1.34.5 64 | ------------------------------ 65 | * Merged #137, Add missing less and remove stray css file in src folder * 66 | * Tabindex is a customizable option now. * 67 | * Refs #142 * 68 | * Refs #145 * 69 | 70 | V1.34.4 71 | ------------------------------ 72 | * Updated required Bootstrap version. * 73 | 74 | V1.34.3 75 | ------------------------------ 76 | * Fixed #125, a bug that dialog footer won't be shown if it was hidden by a no button realization. * 77 | * Refs #126. Adding a data 'button' to the created button. Passing original event object to button callback action(dialog, event). * 78 | * Support Bootstrap v3.3.4 79 | 80 | V1.34.2 81 | ------------------------------ 82 | * FIXED #102 * 83 | * FIXED #121 * 84 | * Implemented modal-sm, REFS #105 * 85 | * More controls on confirm dialog, REFS #105 * 86 | * Added I18N example * 87 | 88 | V1.34.1 89 | ------------------------------ 90 | * Added more compatible methods to make BootstrapDialog works better with older version of Bootstrap Modal. * 91 | 92 | V1.34.0 93 | ------------------------------ 94 | * FIXED #84 * 95 | * Support Bootstrap Modal v3.3.0 * 96 | 97 | V1.33.5 98 | ------------------------------ 99 | * PULL REQUEST: #72 * 100 | * PULL REQUEST: #83 * 101 | * Fixed a bug that after dragging the dialog to another place, the original place prevents closing the dialog by clicking on backdrop. * 102 | 103 | V1.33.4 104 | ------------------------------ 105 | * RE-FIXED #56 * 106 | 107 | V1.33.3 108 | ------------------------------ 109 | * FIXED #62 * 110 | * IMPLEMENTED #67 * 111 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cross-solution/bootstrap3-dialog", 3 | "description": "Make use of Bootstrap Modal more monkey-friendly.", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Nakupanda", 8 | "email": "javanoob@hotmail.com" 9 | } 10 | ], 11 | "require": { 12 | "components/jquery": "*", 13 | "twbs/bootstrap": "3.*" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /dist/css/bootstrap-dialog.css: -------------------------------------------------------------------------------- 1 | .bootstrap-dialog { 2 | /* dialog types */ 3 | /** 4 | * Icon animation 5 | * Copied from font-awesome: http://fontawesome.io/ 6 | **/ 7 | /** End of icon animation **/ 8 | } 9 | .bootstrap-dialog .modal-header { 10 | border-top-left-radius: 4px; 11 | border-top-right-radius: 4px; 12 | } 13 | .bootstrap-dialog .bootstrap-dialog-title { 14 | color: #fff; 15 | display: inline-block; 16 | font-size: 16px; 17 | } 18 | .bootstrap-dialog .bootstrap-dialog-message { 19 | font-size: 14px; 20 | } 21 | .bootstrap-dialog .bootstrap-dialog-button-icon { 22 | margin-right: 3px; 23 | } 24 | .bootstrap-dialog .bootstrap-dialog-close-button { 25 | font-size: 20px; 26 | float: right; 27 | opacity: 0.9; 28 | filter: alpha(opacity=90); 29 | } 30 | .bootstrap-dialog .bootstrap-dialog-close-button:hover { 31 | cursor: pointer; 32 | opacity: 1; 33 | filter: alpha(opacity=100); 34 | } 35 | .bootstrap-dialog.type-default .modal-header { 36 | background-color: #ffffff; 37 | } 38 | .bootstrap-dialog.type-default .bootstrap-dialog-title { 39 | color: #333; 40 | } 41 | .bootstrap-dialog.type-info .modal-header { 42 | background-color: #5bc0de; 43 | } 44 | .bootstrap-dialog.type-primary .modal-header { 45 | background-color: #337ab7; 46 | } 47 | .bootstrap-dialog.type-success .modal-header { 48 | background-color: #5cb85c; 49 | } 50 | .bootstrap-dialog.type-warning .modal-header { 51 | background-color: #f0ad4e; 52 | } 53 | .bootstrap-dialog.type-danger .modal-header { 54 | background-color: #d9534f; 55 | } 56 | .bootstrap-dialog.size-large .bootstrap-dialog-title { 57 | font-size: 24px; 58 | } 59 | .bootstrap-dialog.size-large .bootstrap-dialog-close-button { 60 | font-size: 30px; 61 | } 62 | .bootstrap-dialog.size-large .bootstrap-dialog-message { 63 | font-size: 18px; 64 | } 65 | .bootstrap-dialog .icon-spin { 66 | display: inline-block; 67 | -moz-animation: spin 2s infinite linear; 68 | -o-animation: spin 2s infinite linear; 69 | -webkit-animation: spin 2s infinite linear; 70 | animation: spin 2s infinite linear; 71 | } 72 | @-moz-keyframes spin { 73 | 0% { 74 | -moz-transform: rotate(0deg); 75 | } 76 | 100% { 77 | -moz-transform: rotate(359deg); 78 | } 79 | } 80 | @-webkit-keyframes spin { 81 | 0% { 82 | -webkit-transform: rotate(0deg); 83 | } 84 | 100% { 85 | -webkit-transform: rotate(359deg); 86 | } 87 | } 88 | @-o-keyframes spin { 89 | 0% { 90 | -o-transform: rotate(0deg); 91 | } 92 | 100% { 93 | -o-transform: rotate(359deg); 94 | } 95 | } 96 | @-ms-keyframes spin { 97 | 0% { 98 | -ms-transform: rotate(0deg); 99 | } 100 | 100% { 101 | -ms-transform: rotate(359deg); 102 | } 103 | } 104 | @keyframes spin { 105 | 0% { 106 | transform: rotate(0deg); 107 | } 108 | 100% { 109 | transform: rotate(359deg); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /dist/css/bootstrap-dialog.min.css: -------------------------------------------------------------------------------- 1 | .bootstrap-dialog .modal-header{border-top-left-radius:4px;border-top-right-radius:4px}.bootstrap-dialog .bootstrap-dialog-title{color:#fff;display:inline-block;font-size:16px}.bootstrap-dialog .bootstrap-dialog-message{font-size:14px}.bootstrap-dialog .bootstrap-dialog-button-icon{margin-right:3px}.bootstrap-dialog .bootstrap-dialog-close-button{font-size:20px;float:right;opacity:.9;filter:alpha(opacity=90)}.bootstrap-dialog .bootstrap-dialog-close-button:hover{cursor:pointer;opacity:1;filter:alpha(opacity=100)}.bootstrap-dialog.type-default .modal-header{background-color:#fff}.bootstrap-dialog.type-default .bootstrap-dialog-title{color:#333}.bootstrap-dialog.type-info .modal-header{background-color:#5bc0de}.bootstrap-dialog.type-primary .modal-header{background-color:#337ab7}.bootstrap-dialog.type-success .modal-header{background-color:#5cb85c}.bootstrap-dialog.type-warning .modal-header{background-color:#f0ad4e}.bootstrap-dialog.type-danger .modal-header{background-color:#d9534f}.bootstrap-dialog.size-large .bootstrap-dialog-title{font-size:24px}.bootstrap-dialog.size-large .bootstrap-dialog-close-button{font-size:30px}.bootstrap-dialog.size-large .bootstrap-dialog-message{font-size:18px}.bootstrap-dialog .icon-spin{display:inline-block;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)}100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg)}100%{-ms-transform:rotate(359deg)}}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}} -------------------------------------------------------------------------------- /dist/js/bootstrap-dialog.js: -------------------------------------------------------------------------------- 1 | /* global define */ 2 | 3 | /* ================================================ 4 | * Make use of Bootstrap's modal more monkey-friendly. 5 | * 6 | * For Bootstrap 3. 7 | * 8 | * javanoob@hotmail.com 9 | * 10 | * https://github.com/nakupanda/bootstrap3-dialog 11 | * 12 | * Licensed under The MIT License. 13 | * ================================================ */ 14 | (function (root, factory) { 15 | 16 | "use strict"; 17 | 18 | // CommonJS module is defined 19 | if (typeof module !== 'undefined' && module.exports) { 20 | module.exports = factory(require('jquery'), require('bootstrap')); 21 | } 22 | // AMD module is defined 23 | else if (typeof define === "function" && define.amd) { 24 | define("bootstrap-dialog", ["jquery", "bootstrap"], function ($) { 25 | return factory($); 26 | }); 27 | } else { 28 | // planted over the root! 29 | root.BootstrapDialog = factory(root.jQuery); 30 | } 31 | 32 | }(this, function ($) { 33 | 34 | "use strict"; 35 | 36 | /* ================================================ 37 | * Definition of BootstrapDialogModal. 38 | * Extend Bootstrap Modal and override some functions. 39 | * BootstrapDialogModal === Modified Modal. 40 | * ================================================ */ 41 | var Modal = $.fn.modal.Constructor; 42 | var BootstrapDialogModal = function (element, options) { 43 | Modal.call(this, element, options); 44 | }; 45 | BootstrapDialogModal.getModalVersion = function () { 46 | var version = null; 47 | if (typeof $.fn.modal.Constructor.VERSION === 'undefined') { 48 | version = 'v3.1'; 49 | } else if (/3\.2\.\d+/.test($.fn.modal.Constructor.VERSION)) { 50 | version = 'v3.2'; 51 | } else if (/3\.3\.[1,2]/.test($.fn.modal.Constructor.VERSION)) { 52 | version = 'v3.3'; // v3.3.1, v3.3.2 53 | } else { 54 | version = 'v3.3.4'; 55 | } 56 | 57 | return version; 58 | }; 59 | BootstrapDialogModal.ORIGINAL_BODY_PADDING = parseInt(($('body').css('padding-right') || 0), 10); 60 | BootstrapDialogModal.METHODS_TO_OVERRIDE = {}; 61 | BootstrapDialogModal.METHODS_TO_OVERRIDE['v3.1'] = {}; 62 | BootstrapDialogModal.METHODS_TO_OVERRIDE['v3.2'] = { 63 | hide: function (e) { 64 | if (e) { 65 | e.preventDefault(); 66 | } 67 | e = $.Event('hide.bs.modal'); 68 | 69 | this.$element.trigger(e); 70 | 71 | if (!this.isShown || e.isDefaultPrevented()) { 72 | return; 73 | } 74 | 75 | this.isShown = false; 76 | 77 | // Remove css class 'modal-open' when the last opened dialog is closing. 78 | var openedDialogs = this.getGlobalOpenedDialogs(); 79 | if (openedDialogs.length === 0) { 80 | this.$body.removeClass('modal-open'); 81 | } 82 | 83 | this.resetScrollbar(); 84 | this.escape(); 85 | 86 | $(document).off('focusin.bs.modal'); 87 | 88 | this.$element 89 | .removeClass('in') 90 | .attr('aria-hidden', true) 91 | .off('click.dismiss.bs.modal'); 92 | 93 | $.support.transition && this.$element.hasClass('fade') ? 94 | this.$element 95 | .one('bsTransitionEnd', $.proxy(this.hideModal, this)) 96 | .emulateTransitionEnd(300) : 97 | this.hideModal(); 98 | } 99 | }; 100 | BootstrapDialogModal.METHODS_TO_OVERRIDE['v3.3'] = { 101 | /** 102 | * Overrided. 103 | * 104 | * @returns {undefined} 105 | */ 106 | setScrollbar: function () { 107 | var bodyPad = BootstrapDialogModal.ORIGINAL_BODY_PADDING; 108 | if (this.bodyIsOverflowing) { 109 | this.$body.css('padding-right', bodyPad + this.scrollbarWidth); 110 | } 111 | }, 112 | /** 113 | * Overrided. 114 | * 115 | * @returns {undefined} 116 | */ 117 | resetScrollbar: function () { 118 | var openedDialogs = this.getGlobalOpenedDialogs(); 119 | if (openedDialogs.length === 0) { 120 | this.$body.css('padding-right', BootstrapDialogModal.ORIGINAL_BODY_PADDING); 121 | } 122 | }, 123 | /** 124 | * Overrided. 125 | * 126 | * @returns {undefined} 127 | */ 128 | hideModal: function () { 129 | this.$element.hide(); 130 | this.backdrop($.proxy(function () { 131 | var openedDialogs = this.getGlobalOpenedDialogs(); 132 | if (openedDialogs.length === 0) { 133 | this.$body.removeClass('modal-open'); 134 | } 135 | this.resetAdjustments(); 136 | this.resetScrollbar(); 137 | this.$element.trigger('hidden.bs.modal'); 138 | }, this)); 139 | } 140 | }; 141 | BootstrapDialogModal.METHODS_TO_OVERRIDE['v3.3.4'] = $.extend({}, BootstrapDialogModal.METHODS_TO_OVERRIDE['v3.3']); 142 | BootstrapDialogModal.prototype = { 143 | constructor: BootstrapDialogModal, 144 | /** 145 | * New function, to get the dialogs that opened by BootstrapDialog. 146 | * 147 | * @returns {undefined} 148 | */ 149 | getGlobalOpenedDialogs: function () { 150 | var openedDialogs = []; 151 | $.each(BootstrapDialog.dialogs, function (id, dialogInstance) { 152 | if (dialogInstance.isRealized() && dialogInstance.isOpened()) { 153 | openedDialogs.push(dialogInstance); 154 | } 155 | }); 156 | 157 | return openedDialogs; 158 | } 159 | }; 160 | 161 | // Add compatible methods. 162 | BootstrapDialogModal.prototype = $.extend(BootstrapDialogModal.prototype, Modal.prototype, BootstrapDialogModal.METHODS_TO_OVERRIDE[BootstrapDialogModal.getModalVersion()]); 163 | 164 | /* ================================================ 165 | * Definition of BootstrapDialog. 166 | * ================================================ */ 167 | var BootstrapDialog = function (options) { 168 | this.defaultOptions = $.extend(true, { 169 | id: BootstrapDialog.newGuid(), 170 | buttons: [], 171 | data: {}, 172 | onshow: null, 173 | onshown: null, 174 | onhide: null, 175 | onhidden: null 176 | }, BootstrapDialog.defaultOptions); 177 | this.indexedButtons = {}; 178 | this.registeredButtonHotkeys = {}; 179 | this.draggableData = { 180 | isMouseDown: false, 181 | mouseOffset: {} 182 | }; 183 | this.realized = false; 184 | this.opened = false; 185 | this.initOptions(options); 186 | this.holdThisInstance(); 187 | }; 188 | 189 | BootstrapDialog.BootstrapDialogModal = BootstrapDialogModal; 190 | 191 | /** 192 | * Some constants. 193 | */ 194 | BootstrapDialog.NAMESPACE = 'bootstrap-dialog'; 195 | BootstrapDialog.TYPE_DEFAULT = 'type-default'; 196 | BootstrapDialog.TYPE_INFO = 'type-info'; 197 | BootstrapDialog.TYPE_PRIMARY = 'type-primary'; 198 | BootstrapDialog.TYPE_SUCCESS = 'type-success'; 199 | BootstrapDialog.TYPE_WARNING = 'type-warning'; 200 | BootstrapDialog.TYPE_DANGER = 'type-danger'; 201 | BootstrapDialog.DEFAULT_TEXTS = {}; 202 | BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_DEFAULT] = 'Information'; 203 | BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_INFO] = 'Information'; 204 | BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_PRIMARY] = 'Information'; 205 | BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_SUCCESS] = 'Success'; 206 | BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_WARNING] = 'Warning'; 207 | BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_DANGER] = 'Danger'; 208 | BootstrapDialog.DEFAULT_TEXTS['OK'] = 'OK'; 209 | BootstrapDialog.DEFAULT_TEXTS['CANCEL'] = 'Cancel'; 210 | BootstrapDialog.DEFAULT_TEXTS['CONFIRM'] = 'Confirmation'; 211 | BootstrapDialog.SIZE_NORMAL = 'size-normal'; 212 | BootstrapDialog.SIZE_SMALL = 'size-small'; 213 | BootstrapDialog.SIZE_WIDE = 'size-wide'; // size-wide is equal to modal-lg 214 | BootstrapDialog.SIZE_LARGE = 'size-large'; 215 | BootstrapDialog.BUTTON_SIZES = {}; 216 | BootstrapDialog.BUTTON_SIZES[BootstrapDialog.SIZE_NORMAL] = ''; 217 | BootstrapDialog.BUTTON_SIZES[BootstrapDialog.SIZE_SMALL] = ''; 218 | BootstrapDialog.BUTTON_SIZES[BootstrapDialog.SIZE_WIDE] = ''; 219 | BootstrapDialog.BUTTON_SIZES[BootstrapDialog.SIZE_LARGE] = 'btn-lg'; 220 | BootstrapDialog.ICON_SPINNER = 'glyphicon glyphicon-asterisk'; 221 | BootstrapDialog.BUTTONS_ORDER_CANCEL_OK = 'btns-order-cancel-ok'; 222 | BootstrapDialog.BUTTONS_ORDER_OK_CANCEL = 'btns-order-ok-cancel'; 223 | 224 | /** 225 | * Default options. 226 | */ 227 | BootstrapDialog.defaultOptions = { 228 | type: BootstrapDialog.TYPE_PRIMARY, 229 | size: BootstrapDialog.SIZE_NORMAL, 230 | cssClass: '', 231 | title: null, 232 | message: null, 233 | nl2br: true, 234 | closable: true, 235 | closeByBackdrop: true, 236 | closeByKeyboard: true, 237 | closeIcon: '×', 238 | spinicon: BootstrapDialog.ICON_SPINNER, 239 | autodestroy: true, 240 | draggable: false, 241 | animate: true, 242 | description: '', 243 | tabindex: -1, 244 | btnsOrder: BootstrapDialog.BUTTONS_ORDER_CANCEL_OK 245 | }; 246 | 247 | /** 248 | * Config default options. 249 | */ 250 | BootstrapDialog.configDefaultOptions = function (options) { 251 | BootstrapDialog.defaultOptions = $.extend(true, BootstrapDialog.defaultOptions, options); 252 | }; 253 | 254 | /** 255 | * Open / Close all created dialogs all at once. 256 | */ 257 | BootstrapDialog.dialogs = {}; 258 | BootstrapDialog.openAll = function () { 259 | $.each(BootstrapDialog.dialogs, function (id, dialogInstance) { 260 | dialogInstance.open(); 261 | }); 262 | }; 263 | BootstrapDialog.closeAll = function () { 264 | $.each(BootstrapDialog.dialogs, function (id, dialogInstance) { 265 | dialogInstance.close(); 266 | }); 267 | }; 268 | 269 | /** 270 | * Get dialog instance by given id. 271 | * 272 | * @returns dialog instance 273 | */ 274 | BootstrapDialog.getDialog = function (id) { 275 | var dialog = null; 276 | if (typeof BootstrapDialog.dialogs[id] !== 'undefined') { 277 | dialog = BootstrapDialog.dialogs[id]; 278 | } 279 | 280 | return dialog; 281 | }; 282 | 283 | /** 284 | * Set a dialog. 285 | * 286 | * @returns the dialog that has just been set. 287 | */ 288 | BootstrapDialog.setDialog = function (dialog) { 289 | BootstrapDialog.dialogs[dialog.getId()] = dialog; 290 | 291 | return dialog; 292 | }; 293 | 294 | /** 295 | * Alias of BootstrapDialog.setDialog(dialog) 296 | * 297 | * @param {type} dialog 298 | * @returns {unresolved} 299 | */ 300 | BootstrapDialog.addDialog = function (dialog) { 301 | return BootstrapDialog.setDialog(dialog); 302 | }; 303 | 304 | /** 305 | * Move focus to next visible dialog. 306 | */ 307 | BootstrapDialog.moveFocus = function () { 308 | var lastDialogInstance = null; 309 | $.each(BootstrapDialog.dialogs, function (id, dialogInstance) { 310 | if (dialogInstance.isRealized() && dialogInstance.isOpened()) { 311 | lastDialogInstance = dialogInstance; 312 | } 313 | }); 314 | if (lastDialogInstance !== null) { 315 | lastDialogInstance.getModal().focus(); 316 | } 317 | }; 318 | 319 | BootstrapDialog.METHODS_TO_OVERRIDE = {}; 320 | BootstrapDialog.METHODS_TO_OVERRIDE['v3.1'] = { 321 | handleModalBackdropEvent: function () { 322 | this.getModal().on('click', {dialog: this}, function (event) { 323 | event.target === this && event.data.dialog.isClosable() && event.data.dialog.canCloseByBackdrop() && event.data.dialog.close(); 324 | }); 325 | 326 | return this; 327 | }, 328 | /** 329 | * To make multiple opened dialogs look better. 330 | * 331 | * Will be removed in later version, after Bootstrap Modal >= 3.3.0, updating z-index is unnecessary. 332 | */ 333 | updateZIndex: function () { 334 | if (this.isOpened()) { 335 | var zIndexBackdrop = 1040; 336 | var zIndexModal = 1050; 337 | var dialogCount = 0; 338 | $.each(BootstrapDialog.dialogs, function (dialogId, dialogInstance) { 339 | if (dialogInstance.isRealized() && dialogInstance.isOpened()) { 340 | dialogCount++; 341 | } 342 | }); 343 | var $modal = this.getModal(); 344 | var $backdrop = $modal.data('bs.modal').$backdrop; 345 | $modal.css('z-index', zIndexModal + (dialogCount - 1) * 20); 346 | $backdrop.css('z-index', zIndexBackdrop + (dialogCount - 1) * 20); 347 | } 348 | 349 | return this; 350 | }, 351 | open: function () { 352 | !this.isRealized() && this.realize(); 353 | this.getModal().modal('show'); 354 | this.updateZIndex(); 355 | 356 | return this; 357 | } 358 | }; 359 | BootstrapDialog.METHODS_TO_OVERRIDE['v3.2'] = { 360 | handleModalBackdropEvent: BootstrapDialog.METHODS_TO_OVERRIDE['v3.1']['handleModalBackdropEvent'], 361 | updateZIndex: BootstrapDialog.METHODS_TO_OVERRIDE['v3.1']['updateZIndex'], 362 | open: BootstrapDialog.METHODS_TO_OVERRIDE['v3.1']['open'] 363 | }; 364 | BootstrapDialog.METHODS_TO_OVERRIDE['v3.3'] = {}; 365 | BootstrapDialog.METHODS_TO_OVERRIDE['v3.3.4'] = $.extend({}, BootstrapDialog.METHODS_TO_OVERRIDE['v3.1']); 366 | BootstrapDialog.prototype = { 367 | constructor: BootstrapDialog, 368 | initOptions: function (options) { 369 | this.options = $.extend(true, this.defaultOptions, options); 370 | 371 | return this; 372 | }, 373 | holdThisInstance: function () { 374 | BootstrapDialog.addDialog(this); 375 | 376 | return this; 377 | }, 378 | initModalStuff: function () { 379 | this.setModal(this.createModal()) 380 | .setModalDialog(this.createModalDialog()) 381 | .setModalContent(this.createModalContent()) 382 | .setModalHeader(this.createModalHeader()) 383 | .setModalBody(this.createModalBody()) 384 | .setModalFooter(this.createModalFooter()); 385 | 386 | this.getModal().append(this.getModalDialog()); 387 | this.getModalDialog().append(this.getModalContent()); 388 | this.getModalContent() 389 | .append(this.getModalHeader()) 390 | .append(this.getModalBody()) 391 | .append(this.getModalFooter()); 392 | 393 | return this; 394 | }, 395 | createModal: function () { 396 | var $modal = $(''); 397 | $modal.prop('id', this.getId()); 398 | $modal.attr('aria-labelledby', this.getId() + '_title'); 399 | 400 | return $modal; 401 | }, 402 | getModal: function () { 403 | return this.$modal; 404 | }, 405 | setModal: function ($modal) { 406 | this.$modal = $modal; 407 | 408 | return this; 409 | }, 410 | createModalDialog: function () { 411 | return $(''); 412 | }, 413 | getModalDialog: function () { 414 | return this.$modalDialog; 415 | }, 416 | setModalDialog: function ($modalDialog) { 417 | this.$modalDialog = $modalDialog; 418 | 419 | return this; 420 | }, 421 | createModalContent: function () { 422 | return $(''); 423 | }, 424 | getModalContent: function () { 425 | return this.$modalContent; 426 | }, 427 | setModalContent: function ($modalContent) { 428 | this.$modalContent = $modalContent; 429 | 430 | return this; 431 | }, 432 | createModalHeader: function () { 433 | return $(''); 434 | }, 435 | getModalHeader: function () { 436 | return this.$modalHeader; 437 | }, 438 | setModalHeader: function ($modalHeader) { 439 | this.$modalHeader = $modalHeader; 440 | 441 | return this; 442 | }, 443 | createModalBody: function () { 444 | return $(''); 445 | }, 446 | getModalBody: function () { 447 | return this.$modalBody; 448 | }, 449 | setModalBody: function ($modalBody) { 450 | this.$modalBody = $modalBody; 451 | 452 | return this; 453 | }, 454 | createModalFooter: function () { 455 | return $(''); 456 | }, 457 | getModalFooter: function () { 458 | return this.$modalFooter; 459 | }, 460 | setModalFooter: function ($modalFooter) { 461 | this.$modalFooter = $modalFooter; 462 | 463 | return this; 464 | }, 465 | createDynamicContent: function (rawContent) { 466 | var content = null; 467 | if (typeof rawContent === 'function') { 468 | content = rawContent.call(rawContent, this); 469 | } else { 470 | content = rawContent; 471 | } 472 | if (typeof content === 'string') { 473 | content = this.formatStringContent(content); 474 | } 475 | 476 | return content; 477 | }, 478 | formatStringContent: function (content) { 479 | if (this.options.nl2br) { 480 | return content.replace(/\r\n/g, '
').replace(/[\r\n]/g, '
'); 481 | } 482 | 483 | return content; 484 | }, 485 | setData: function (key, value) { 486 | this.options.data[key] = value; 487 | 488 | return this; 489 | }, 490 | getData: function (key) { 491 | return this.options.data[key]; 492 | }, 493 | setId: function (id) { 494 | this.options.id = id; 495 | 496 | return this; 497 | }, 498 | getId: function () { 499 | return this.options.id; 500 | }, 501 | getType: function () { 502 | return this.options.type; 503 | }, 504 | setType: function (type) { 505 | this.options.type = type; 506 | this.updateType(); 507 | 508 | return this; 509 | }, 510 | updateType: function () { 511 | if (this.isRealized()) { 512 | var types = [BootstrapDialog.TYPE_DEFAULT, 513 | BootstrapDialog.TYPE_INFO, 514 | BootstrapDialog.TYPE_PRIMARY, 515 | BootstrapDialog.TYPE_SUCCESS, 516 | BootstrapDialog.TYPE_WARNING, 517 | BootstrapDialog.TYPE_DANGER]; 518 | 519 | this.getModal().removeClass(types.join(' ')).addClass(this.getType()); 520 | } 521 | 522 | return this; 523 | }, 524 | getSize: function () { 525 | return this.options.size; 526 | }, 527 | setSize: function (size) { 528 | this.options.size = size; 529 | this.updateSize(); 530 | 531 | return this; 532 | }, 533 | updateSize: function () { 534 | if (this.isRealized()) { 535 | var dialog = this; 536 | 537 | // Dialog size 538 | this.getModal().removeClass(BootstrapDialog.SIZE_NORMAL) 539 | .removeClass(BootstrapDialog.SIZE_SMALL) 540 | .removeClass(BootstrapDialog.SIZE_WIDE) 541 | .removeClass(BootstrapDialog.SIZE_LARGE); 542 | this.getModal().addClass(this.getSize()); 543 | 544 | // Smaller dialog. 545 | this.getModalDialog().removeClass('modal-sm'); 546 | if (this.getSize() === BootstrapDialog.SIZE_SMALL) { 547 | this.getModalDialog().addClass('modal-sm'); 548 | } 549 | 550 | // Wider dialog. 551 | this.getModalDialog().removeClass('modal-lg'); 552 | if (this.getSize() === BootstrapDialog.SIZE_WIDE) { 553 | this.getModalDialog().addClass('modal-lg'); 554 | } 555 | 556 | // Button size 557 | $.each(this.options.buttons, function (index, button) { 558 | var $button = dialog.getButton(button.id); 559 | var buttonSizes = ['btn-lg', 'btn-sm', 'btn-xs']; 560 | var sizeClassSpecified = false; 561 | if (typeof button['cssClass'] === 'string') { 562 | var btnClasses = button['cssClass'].split(' '); 563 | $.each(btnClasses, function (index, btnClass) { 564 | if ($.inArray(btnClass, buttonSizes) !== -1) { 565 | sizeClassSpecified = true; 566 | } 567 | }); 568 | } 569 | if (!sizeClassSpecified) { 570 | $button.removeClass(buttonSizes.join(' ')); 571 | $button.addClass(dialog.getButtonSize()); 572 | } 573 | }); 574 | } 575 | 576 | return this; 577 | }, 578 | getCssClass: function () { 579 | return this.options.cssClass; 580 | }, 581 | setCssClass: function (cssClass) { 582 | this.options.cssClass = cssClass; 583 | 584 | return this; 585 | }, 586 | getTitle: function () { 587 | return this.options.title; 588 | }, 589 | setTitle: function (title) { 590 | this.options.title = title; 591 | this.updateTitle(); 592 | 593 | return this; 594 | }, 595 | updateTitle: function () { 596 | if (this.isRealized()) { 597 | var title = this.getTitle() !== null ? this.createDynamicContent(this.getTitle()) : this.getDefaultText(); 598 | this.getModalHeader().find('.' + this.getNamespace('title')).html('').append(title).prop('id', this.getId() + '_title'); 599 | } 600 | 601 | return this; 602 | }, 603 | getMessage: function () { 604 | return this.options.message; 605 | }, 606 | setMessage: function (message) { 607 | this.options.message = message; 608 | this.updateMessage(); 609 | 610 | return this; 611 | }, 612 | updateMessage: function () { 613 | if (this.isRealized()) { 614 | var message = this.createDynamicContent(this.getMessage()); 615 | this.getModalBody().find('.' + this.getNamespace('message')).html('').append(message); 616 | } 617 | 618 | return this; 619 | }, 620 | isClosable: function () { 621 | return this.options.closable; 622 | }, 623 | setClosable: function (closable) { 624 | this.options.closable = closable; 625 | this.updateClosable(); 626 | 627 | return this; 628 | }, 629 | setCloseByBackdrop: function (closeByBackdrop) { 630 | this.options.closeByBackdrop = closeByBackdrop; 631 | 632 | return this; 633 | }, 634 | canCloseByBackdrop: function () { 635 | return this.options.closeByBackdrop; 636 | }, 637 | setCloseByKeyboard: function (closeByKeyboard) { 638 | this.options.closeByKeyboard = closeByKeyboard; 639 | 640 | return this; 641 | }, 642 | canCloseByKeyboard: function () { 643 | return this.options.closeByKeyboard; 644 | }, 645 | isAnimate: function () { 646 | return this.options.animate; 647 | }, 648 | setAnimate: function (animate) { 649 | this.options.animate = animate; 650 | 651 | return this; 652 | }, 653 | updateAnimate: function () { 654 | if (this.isRealized()) { 655 | this.getModal().toggleClass('fade', this.isAnimate()); 656 | } 657 | 658 | return this; 659 | }, 660 | getSpinicon: function () { 661 | return this.options.spinicon; 662 | }, 663 | setSpinicon: function (spinicon) { 664 | this.options.spinicon = spinicon; 665 | 666 | return this; 667 | }, 668 | addButton: function (button) { 669 | this.options.buttons.push(button); 670 | 671 | return this; 672 | }, 673 | addButtons: function (buttons) { 674 | var that = this; 675 | $.each(buttons, function (index, button) { 676 | that.addButton(button); 677 | }); 678 | 679 | return this; 680 | }, 681 | getButtons: function () { 682 | return this.options.buttons; 683 | }, 684 | setButtons: function (buttons) { 685 | this.options.buttons = buttons; 686 | this.updateButtons(); 687 | 688 | return this; 689 | }, 690 | /** 691 | * If there is id provided for a button option, it will be in dialog.indexedButtons list. 692 | * 693 | * In that case you can use dialog.getButton(id) to find the button. 694 | * 695 | * @param {type} id 696 | * @returns {undefined} 697 | */ 698 | getButton: function (id) { 699 | if (typeof this.indexedButtons[id] !== 'undefined') { 700 | return this.indexedButtons[id]; 701 | } 702 | 703 | return null; 704 | }, 705 | getButtonSize: function () { 706 | if (typeof BootstrapDialog.BUTTON_SIZES[this.getSize()] !== 'undefined') { 707 | return BootstrapDialog.BUTTON_SIZES[this.getSize()]; 708 | } 709 | 710 | return ''; 711 | }, 712 | updateButtons: function () { 713 | if (this.isRealized()) { 714 | if (this.getButtons().length === 0) { 715 | this.getModalFooter().hide(); 716 | } else { 717 | this.getModalFooter().show().find('.' + this.getNamespace('footer')).html('').append(this.createFooterButtons()); 718 | } 719 | } 720 | 721 | return this; 722 | }, 723 | isAutodestroy: function () { 724 | return this.options.autodestroy; 725 | }, 726 | setAutodestroy: function (autodestroy) { 727 | this.options.autodestroy = autodestroy; 728 | }, 729 | getDescription: function () { 730 | return this.options.description; 731 | }, 732 | setDescription: function (description) { 733 | this.options.description = description; 734 | 735 | return this; 736 | }, 737 | setTabindex: function (tabindex) { 738 | this.options.tabindex = tabindex; 739 | 740 | return this; 741 | }, 742 | getTabindex: function () { 743 | return this.options.tabindex; 744 | }, 745 | updateTabindex: function () { 746 | if (this.isRealized()) { 747 | this.getModal().attr('tabindex', this.getTabindex()); 748 | } 749 | 750 | return this; 751 | }, 752 | getDefaultText: function () { 753 | return BootstrapDialog.DEFAULT_TEXTS[this.getType()]; 754 | }, 755 | getNamespace: function (name) { 756 | return BootstrapDialog.NAMESPACE + '-' + name; 757 | }, 758 | createHeaderContent: function () { 759 | var $container = $('
'); 760 | $container.addClass(this.getNamespace('header')); 761 | 762 | // title 763 | $container.append(this.createTitleContent()); 764 | 765 | // Close button 766 | $container.prepend(this.createCloseButton()); 767 | 768 | return $container; 769 | }, 770 | createTitleContent: function () { 771 | var $title = $('
'); 772 | $title.addClass(this.getNamespace('title')); 773 | 774 | return $title; 775 | }, 776 | createCloseButton: function () { 777 | var $container = $('
'); 778 | $container.addClass(this.getNamespace('close-button')); 779 | var $icon = $(''); 780 | $icon.append(this.options.closeIcon); 781 | $container.append($icon); 782 | $container.on('click', {dialog: this}, function (event) { 783 | event.data.dialog.close(); 784 | }); 785 | 786 | return $container; 787 | }, 788 | createBodyContent: function () { 789 | var $container = $('
'); 790 | $container.addClass(this.getNamespace('body')); 791 | 792 | // Message 793 | $container.append(this.createMessageContent()); 794 | 795 | return $container; 796 | }, 797 | createMessageContent: function () { 798 | var $message = $('
'); 799 | $message.addClass(this.getNamespace('message')); 800 | 801 | return $message; 802 | }, 803 | createFooterContent: function () { 804 | var $container = $('
'); 805 | $container.addClass(this.getNamespace('footer')); 806 | 807 | return $container; 808 | }, 809 | createFooterButtons: function () { 810 | var that = this; 811 | var $container = $('
'); 812 | $container.addClass(this.getNamespace('footer-buttons')); 813 | this.indexedButtons = {}; 814 | $.each(this.options.buttons, function (index, button) { 815 | if (!button.id) { 816 | button.id = BootstrapDialog.newGuid(); 817 | } 818 | var $button = that.createButton(button); 819 | that.indexedButtons[button.id] = $button; 820 | $container.append($button); 821 | }); 822 | 823 | return $container; 824 | }, 825 | createButton: function (button) { 826 | var $button = $(''); 827 | $button.prop('id', button.id); 828 | $button.data('button', button); 829 | 830 | // Icon 831 | if (typeof button.icon !== 'undefined' && $.trim(button.icon) !== '') { 832 | $button.append(this.createButtonIcon(button.icon)); 833 | } 834 | 835 | // Label 836 | if (typeof button.label !== 'undefined') { 837 | $button.append(button.label); 838 | } 839 | 840 | // title 841 | if (typeof button.title !== 'undefined') { 842 | $button.attr('title', button.title); 843 | } 844 | 845 | // Css class 846 | if (typeof button.cssClass !== 'undefined' && $.trim(button.cssClass) !== '') { 847 | $button.addClass(button.cssClass); 848 | } else { 849 | $button.addClass('btn-default'); 850 | } 851 | 852 | // Data attributes 853 | if (typeof button.data === 'object' && button.data.constructor === {}.constructor) { 854 | $.each(button.data, function (key, value) { 855 | $button.attr('data-' + key, value); 856 | }); 857 | } 858 | 859 | // Hotkey 860 | if (typeof button.hotkey !== 'undefined') { 861 | this.registeredButtonHotkeys[button.hotkey] = $button; 862 | } 863 | 864 | // Button on click 865 | $button.on('click', {dialog: this, $button: $button, button: button}, function (event) { 866 | var dialog = event.data.dialog; 867 | var $button = event.data.$button; 868 | var button = $button.data('button'); 869 | if (button.autospin) { 870 | $button.toggleSpin(true); 871 | } 872 | if (typeof button.action === 'function') { 873 | return button.action.call($button, dialog, event); 874 | } 875 | }); 876 | 877 | // Dynamically add extra functions to $button 878 | this.enhanceButton($button); 879 | 880 | //Initialize enabled or not 881 | if (typeof button.enabled !== 'undefined') { 882 | $button.toggleEnable(button.enabled); 883 | } 884 | 885 | return $button; 886 | }, 887 | /** 888 | * Dynamically add extra functions to $button 889 | * 890 | * Using '$this' to reference 'this' is just for better readability. 891 | * 892 | * @param {type} $button 893 | * @returns {_L13.BootstrapDialog.prototype} 894 | */ 895 | enhanceButton: function ($button) { 896 | $button.dialog = this; 897 | 898 | // Enable / Disable 899 | $button.toggleEnable = function (enable) { 900 | var $this = this; 901 | if (typeof enable !== 'undefined') { 902 | $this.prop("disabled", !enable).toggleClass('disabled', !enable); 903 | } else { 904 | $this.prop("disabled", !$this.prop("disabled")); 905 | } 906 | 907 | return $this; 908 | }; 909 | $button.enable = function () { 910 | var $this = this; 911 | $this.toggleEnable(true); 912 | 913 | return $this; 914 | }; 915 | $button.disable = function () { 916 | var $this = this; 917 | $this.toggleEnable(false); 918 | 919 | return $this; 920 | }; 921 | 922 | // Icon spinning, helpful for indicating ajax loading status. 923 | $button.toggleSpin = function (spin) { 924 | var $this = this; 925 | var dialog = $this.dialog; 926 | var $icon = $this.find('.' + dialog.getNamespace('button-icon')); 927 | if (typeof spin === 'undefined') { 928 | spin = !($button.find('.icon-spin').length > 0); 929 | } 930 | if (spin) { 931 | $icon.hide(); 932 | $button.prepend(dialog.createButtonIcon(dialog.getSpinicon()).addClass('icon-spin')); 933 | } else { 934 | $icon.show(); 935 | $button.find('.icon-spin').remove(); 936 | } 937 | 938 | return $this; 939 | }; 940 | $button.spin = function () { 941 | var $this = this; 942 | $this.toggleSpin(true); 943 | 944 | return $this; 945 | }; 946 | $button.stopSpin = function () { 947 | var $this = this; 948 | $this.toggleSpin(false); 949 | 950 | return $this; 951 | }; 952 | 953 | return this; 954 | }, 955 | createButtonIcon: function (icon) { 956 | var $icon = $(''); 957 | $icon.addClass(this.getNamespace('button-icon')).addClass(icon); 958 | 959 | return $icon; 960 | }, 961 | /** 962 | * Invoke this only after the dialog is realized. 963 | * 964 | * @param {type} enable 965 | * @returns {undefined} 966 | */ 967 | enableButtons: function (enable) { 968 | $.each(this.indexedButtons, function (id, $button) { 969 | $button.toggleEnable(enable); 970 | }); 971 | 972 | return this; 973 | }, 974 | /** 975 | * Invoke this only after the dialog is realized. 976 | * 977 | * @returns {undefined} 978 | */ 979 | updateClosable: function () { 980 | if (this.isRealized()) { 981 | // Close button 982 | this.getModalHeader().find('.' + this.getNamespace('close-button')).toggle(this.isClosable()); 983 | } 984 | 985 | return this; 986 | }, 987 | /** 988 | * Set handler for modal event 'show.bs.modal'. 989 | * This is a setter! 990 | */ 991 | onShow: function (onshow) { 992 | this.options.onshow = onshow; 993 | 994 | return this; 995 | }, 996 | /** 997 | * Set handler for modal event 'shown.bs.modal'. 998 | * This is a setter! 999 | */ 1000 | onShown: function (onshown) { 1001 | this.options.onshown = onshown; 1002 | 1003 | return this; 1004 | }, 1005 | /** 1006 | * Set handler for modal event 'hide.bs.modal'. 1007 | * This is a setter! 1008 | */ 1009 | onHide: function (onhide) { 1010 | this.options.onhide = onhide; 1011 | 1012 | return this; 1013 | }, 1014 | /** 1015 | * Set handler for modal event 'hidden.bs.modal'. 1016 | * This is a setter! 1017 | */ 1018 | onHidden: function (onhidden) { 1019 | this.options.onhidden = onhidden; 1020 | 1021 | return this; 1022 | }, 1023 | isRealized: function () { 1024 | return this.realized; 1025 | }, 1026 | setRealized: function (realized) { 1027 | this.realized = realized; 1028 | 1029 | return this; 1030 | }, 1031 | isOpened: function () { 1032 | return this.opened; 1033 | }, 1034 | setOpened: function (opened) { 1035 | this.opened = opened; 1036 | 1037 | return this; 1038 | }, 1039 | handleModalEvents: function () { 1040 | this.getModal().on('show.bs.modal', {dialog: this}, function (event) { 1041 | var dialog = event.data.dialog; 1042 | dialog.setOpened(true); 1043 | if (dialog.isModalEvent(event) && typeof dialog.options.onshow === 'function') { 1044 | var openIt = dialog.options.onshow(dialog); 1045 | if (openIt === false) { 1046 | dialog.setOpened(false); 1047 | } 1048 | 1049 | return openIt; 1050 | } 1051 | }); 1052 | this.getModal().on('shown.bs.modal', {dialog: this}, function (event) { 1053 | var dialog = event.data.dialog; 1054 | dialog.isModalEvent(event) && typeof dialog.options.onshown === 'function' && dialog.options.onshown(dialog); 1055 | }); 1056 | this.getModal().on('hide.bs.modal', {dialog: this}, function (event) { 1057 | var dialog = event.data.dialog; 1058 | dialog.setOpened(false); 1059 | if (dialog.isModalEvent(event) && typeof dialog.options.onhide === 'function') { 1060 | var hideIt = dialog.options.onhide(dialog); 1061 | if (hideIt === false) { 1062 | dialog.setOpened(true); 1063 | } 1064 | 1065 | return hideIt; 1066 | } 1067 | }); 1068 | this.getModal().on('hidden.bs.modal', {dialog: this}, function (event) { 1069 | var dialog = event.data.dialog; 1070 | dialog.isModalEvent(event) && typeof dialog.options.onhidden === 'function' && dialog.options.onhidden(dialog); 1071 | if (dialog.isAutodestroy()) { 1072 | dialog.setRealized(false); 1073 | delete BootstrapDialog.dialogs[dialog.getId()]; 1074 | $(this).remove(); 1075 | } 1076 | BootstrapDialog.moveFocus(); 1077 | if ($('.modal').hasClass('in')) { 1078 | $('body').addClass('modal-open'); 1079 | } 1080 | }); 1081 | 1082 | // Backdrop, I did't find a way to change bs3 backdrop option after the dialog is popped up, so here's a new wheel. 1083 | this.handleModalBackdropEvent(); 1084 | 1085 | // ESC key support 1086 | this.getModal().on('keyup', {dialog: this}, function (event) { 1087 | event.which === 27 && event.data.dialog.isClosable() && event.data.dialog.canCloseByKeyboard() && event.data.dialog.close(); 1088 | }); 1089 | 1090 | // Button hotkey 1091 | this.getModal().on('keyup', {dialog: this}, function (event) { 1092 | var dialog = event.data.dialog; 1093 | if (typeof dialog.registeredButtonHotkeys[event.which] !== 'undefined') { 1094 | var $button = $(dialog.registeredButtonHotkeys[event.which]); 1095 | !$button.prop('disabled') && !$button.is(':focus') && $button.focus().trigger('click'); 1096 | } 1097 | }); 1098 | 1099 | return this; 1100 | }, 1101 | handleModalBackdropEvent: function () { 1102 | this.getModal().on('click', {dialog: this}, function (event) { 1103 | $(event.target).hasClass('modal-backdrop') && event.data.dialog.isClosable() && event.data.dialog.canCloseByBackdrop() && event.data.dialog.close(); 1104 | }); 1105 | 1106 | return this; 1107 | }, 1108 | isModalEvent: function (event) { 1109 | return typeof event.namespace !== 'undefined' && event.namespace === 'bs.modal'; 1110 | }, 1111 | makeModalDraggable: function () { 1112 | if (this.options.draggable) { 1113 | this.getModalHeader().addClass(this.getNamespace('draggable')).on('mousedown', {dialog: this}, function (event) { 1114 | var dialog = event.data.dialog; 1115 | dialog.draggableData.isMouseDown = true; 1116 | var dialogOffset = dialog.getModalDialog().offset(); 1117 | dialog.draggableData.mouseOffset = { 1118 | top: event.clientY - dialogOffset.top, 1119 | left: event.clientX - dialogOffset.left 1120 | }; 1121 | }); 1122 | this.getModal().on('mouseup mouseleave', {dialog: this}, function (event) { 1123 | event.data.dialog.draggableData.isMouseDown = false; 1124 | }); 1125 | $('body').on('mousemove', {dialog: this}, function (event) { 1126 | var dialog = event.data.dialog; 1127 | if (!dialog.draggableData.isMouseDown) { 1128 | return; 1129 | } 1130 | dialog.getModalDialog().offset({ 1131 | top: event.clientY - dialog.draggableData.mouseOffset.top, 1132 | left: event.clientX - dialog.draggableData.mouseOffset.left 1133 | }); 1134 | }); 1135 | } 1136 | 1137 | return this; 1138 | }, 1139 | realize: function () { 1140 | this.initModalStuff(); 1141 | this.getModal().addClass(BootstrapDialog.NAMESPACE) 1142 | .addClass(this.getCssClass()); 1143 | this.updateSize(); 1144 | if (this.getDescription()) { 1145 | this.getModal().attr('aria-describedby', this.getDescription()); 1146 | } 1147 | this.getModalFooter().append(this.createFooterContent()); 1148 | this.getModalHeader().append(this.createHeaderContent()); 1149 | this.getModalBody().append(this.createBodyContent()); 1150 | this.getModal().data('bs.modal', new BootstrapDialogModal(this.getModal(), { 1151 | backdrop: 'static', 1152 | keyboard: false, 1153 | show: false 1154 | })); 1155 | this.makeModalDraggable(); 1156 | this.handleModalEvents(); 1157 | this.setRealized(true); 1158 | this.updateButtons(); 1159 | this.updateType(); 1160 | this.updateTitle(); 1161 | this.updateMessage(); 1162 | this.updateClosable(); 1163 | this.updateAnimate(); 1164 | this.updateSize(); 1165 | this.updateTabindex(); 1166 | 1167 | return this; 1168 | }, 1169 | open: function () { 1170 | !this.isRealized() && this.realize(); 1171 | this.getModal().modal('show'); 1172 | 1173 | return this; 1174 | }, 1175 | close: function () { 1176 | !this.isRealized() && this.realize(); 1177 | this.getModal().modal('hide'); 1178 | 1179 | return this; 1180 | } 1181 | }; 1182 | 1183 | // Add compatible methods. 1184 | BootstrapDialog.prototype = $.extend(BootstrapDialog.prototype, BootstrapDialog.METHODS_TO_OVERRIDE[BootstrapDialogModal.getModalVersion()]); 1185 | 1186 | /** 1187 | * RFC4122 version 4 compliant unique id creator. 1188 | * 1189 | * Added by https://github.com/tufanbarisyildirim/ 1190 | * 1191 | * @returns {String} 1192 | */ 1193 | BootstrapDialog.newGuid = function () { 1194 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { 1195 | var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8); 1196 | return v.toString(16); 1197 | }); 1198 | }; 1199 | 1200 | /* ================================================ 1201 | * For lazy people 1202 | * ================================================ */ 1203 | 1204 | /** 1205 | * Shortcut function: show 1206 | * 1207 | * @param {type} options 1208 | * @returns the created dialog instance 1209 | */ 1210 | BootstrapDialog.show = function (options) { 1211 | return new BootstrapDialog(options).open(); 1212 | }; 1213 | 1214 | /** 1215 | * Alert window 1216 | * 1217 | * @returns the created dialog instance 1218 | */ 1219 | BootstrapDialog.alert = function () { 1220 | var alertOptions = {}; 1221 | var defaultAlertOptions = { 1222 | type: BootstrapDialog.TYPE_PRIMARY, 1223 | title: null, 1224 | message: null, 1225 | closable: false, 1226 | draggable: false, 1227 | buttonLabel: BootstrapDialog.DEFAULT_TEXTS.OK, 1228 | buttonHotkey: null, 1229 | callback: null 1230 | }; 1231 | 1232 | if (typeof arguments[0] === 'object' && arguments[0].constructor === {}.constructor) { 1233 | alertOptions = $.extend(true, defaultAlertOptions, arguments[0]); 1234 | } else { 1235 | alertOptions = $.extend(true, defaultAlertOptions, { 1236 | message: arguments[0], 1237 | callback: typeof arguments[1] !== 'undefined' ? arguments[1] : null 1238 | }); 1239 | } 1240 | 1241 | var dialog = new BootstrapDialog(alertOptions); 1242 | dialog.setData('callback', alertOptions.callback); 1243 | dialog.addButton({ 1244 | label: alertOptions.buttonLabel, 1245 | hotkey: alertOptions.buttonHotkey, 1246 | action: function (dialog) { 1247 | if (typeof dialog.getData('callback') === 'function' && dialog.getData('callback').call(this, true) === false) { 1248 | return false; 1249 | } 1250 | dialog.setData('btnClicked', true); 1251 | 1252 | return dialog.close(); 1253 | } 1254 | }); 1255 | if (typeof dialog.options.onhide === 'function') { 1256 | dialog.onHide(function (dialog) { 1257 | var hideIt = true; 1258 | if (!dialog.getData('btnClicked') && dialog.isClosable() && typeof dialog.getData('callback') === 'function') { 1259 | hideIt = dialog.getData('callback')(false); 1260 | } 1261 | if (hideIt === false) { 1262 | return false; 1263 | } 1264 | hideIt = this.onhide(dialog); 1265 | 1266 | return hideIt; 1267 | }.bind({ 1268 | onhide: dialog.options.onhide 1269 | })); 1270 | } else { 1271 | dialog.onHide(function (dialog) { 1272 | var hideIt = true; 1273 | if (!dialog.getData('btnClicked') && dialog.isClosable() && typeof dialog.getData('callback') === 'function') { 1274 | hideIt = dialog.getData('callback')(false); 1275 | } 1276 | 1277 | return hideIt; 1278 | }); 1279 | } 1280 | 1281 | return dialog.open(); 1282 | }; 1283 | 1284 | /** 1285 | * Confirm window 1286 | * 1287 | * @returns the created dialog instance 1288 | */ 1289 | BootstrapDialog.confirm = function () { 1290 | var confirmOptions = {}; 1291 | var defaultConfirmOptions = { 1292 | type: BootstrapDialog.TYPE_PRIMARY, 1293 | title: null, 1294 | message: null, 1295 | closable: false, 1296 | draggable: false, 1297 | btnCancelLabel: BootstrapDialog.DEFAULT_TEXTS.CANCEL, 1298 | btnCancelClass: null, 1299 | btnCancelHotkey: null, 1300 | btnOKLabel: BootstrapDialog.DEFAULT_TEXTS.OK, 1301 | btnOKClass: null, 1302 | btnOKHotkey: null, 1303 | btnsOrder: BootstrapDialog.defaultOptions.btnsOrder, 1304 | callback: null 1305 | }; 1306 | if (typeof arguments[0] === 'object' && arguments[0].constructor === {}.constructor) { 1307 | confirmOptions = $.extend(true, defaultConfirmOptions, arguments[0]); 1308 | } else { 1309 | confirmOptions = $.extend(true, defaultConfirmOptions, { 1310 | message: arguments[0], 1311 | callback: typeof arguments[1] !== 'undefined' ? arguments[1] : null 1312 | }); 1313 | } 1314 | if (confirmOptions.btnOKClass === null) { 1315 | confirmOptions.btnOKClass = ['btn', confirmOptions.type.split('-')[1]].join('-'); 1316 | } 1317 | 1318 | var dialog = new BootstrapDialog(confirmOptions); 1319 | dialog.setData('callback', confirmOptions.callback); 1320 | 1321 | var buttons = [{ 1322 | label: confirmOptions.btnCancelLabel, 1323 | cssClass: confirmOptions.btnCancelClass, 1324 | hotkey: confirmOptions.btnCancelHotkey, 1325 | action: function (dialog) { 1326 | if (typeof dialog.getData('callback') === 'function' && dialog.getData('callback').call(this, false) === false) { 1327 | return false; 1328 | } 1329 | 1330 | return dialog.close(); 1331 | } 1332 | }, { 1333 | label: confirmOptions.btnOKLabel, 1334 | cssClass: confirmOptions.btnOKClass, 1335 | hotkey: confirmOptions.btnOKHotkey, 1336 | action: function (dialog) { 1337 | if (typeof dialog.getData('callback') === 'function' && dialog.getData('callback').call(this, true) === false) { 1338 | return false; 1339 | } 1340 | 1341 | return dialog.close(); 1342 | } 1343 | }]; 1344 | if (confirmOptions.btnsOrder === BootstrapDialog.BUTTONS_ORDER_OK_CANCEL) { 1345 | buttons.reverse(); 1346 | } 1347 | dialog.addButtons(buttons); 1348 | 1349 | return dialog.open(); 1350 | 1351 | }; 1352 | 1353 | /** 1354 | * Warning window 1355 | * 1356 | * @param {type} message 1357 | * @returns the created dialog instance 1358 | */ 1359 | BootstrapDialog.warning = function (message, callback) { 1360 | return new BootstrapDialog({ 1361 | type: BootstrapDialog.TYPE_WARNING, 1362 | message: message 1363 | }).open(); 1364 | }; 1365 | 1366 | /** 1367 | * Danger window 1368 | * 1369 | * @param {type} message 1370 | * @returns the created dialog instance 1371 | */ 1372 | BootstrapDialog.danger = function (message, callback) { 1373 | return new BootstrapDialog({ 1374 | type: BootstrapDialog.TYPE_DANGER, 1375 | message: message 1376 | }).open(); 1377 | }; 1378 | 1379 | /** 1380 | * Success window 1381 | * 1382 | * @param {type} message 1383 | * @returns the created dialog instance 1384 | */ 1385 | BootstrapDialog.success = function (message, callback) { 1386 | return new BootstrapDialog({ 1387 | type: BootstrapDialog.TYPE_SUCCESS, 1388 | message: message 1389 | }).open(); 1390 | }; 1391 | 1392 | return BootstrapDialog; 1393 | 1394 | })); 1395 | -------------------------------------------------------------------------------- /dist/js/bootstrap-dialog.min.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"use strict";"undefined"!=typeof module&&module.exports?module.exports=e(require("jquery"),require("bootstrap")):"function"==typeof define&&define.amd?define("bootstrap-dialog",["jquery","bootstrap"],function(t){return e(t)}):t.BootstrapDialog=e(t.jQuery)}(this,function(t){"use strict";var e=t.fn.modal.Constructor,n=function(t,n){e.call(this,t,n)};n.getModalVersion=function(){return void 0===t.fn.modal.Constructor.VERSION?"v3.1":/3\.2\.\d+/.test(t.fn.modal.Constructor.VERSION)?"v3.2":/3\.3\.[1,2]/.test(t.fn.modal.Constructor.VERSION)?"v3.3":"v3.3.4"},n.ORIGINAL_BODY_PADDING=parseInt(t("body").css("padding-right")||0,10),(n.METHODS_TO_OVERRIDE={})["v3.1"]={},n.METHODS_TO_OVERRIDE["v3.2"]={hide:function(e){e&&e.preventDefault(),e=t.Event("hide.bs.modal"),this.$element.trigger(e),this.isShown&&!e.isDefaultPrevented()&&(this.isShown=!1,0===this.getGlobalOpenedDialogs().length&&this.$body.removeClass("modal-open"),this.resetScrollbar(),this.escape(),t(document).off("focusin.bs.modal"),this.$element.removeClass("in").attr("aria-hidden",!0).off("click.dismiss.bs.modal"),t.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",t.proxy(this.hideModal,this)).emulateTransitionEnd(300):this.hideModal())}},n.METHODS_TO_OVERRIDE["v3.3"]={setScrollbar:function(){var t=n.ORIGINAL_BODY_PADDING;this.bodyIsOverflowing&&this.$body.css("padding-right",t+this.scrollbarWidth)},resetScrollbar:function(){0===this.getGlobalOpenedDialogs().length&&this.$body.css("padding-right",n.ORIGINAL_BODY_PADDING)},hideModal:function(){this.$element.hide(),this.backdrop(t.proxy(function(){0===this.getGlobalOpenedDialogs().length&&this.$body.removeClass("modal-open"),this.resetAdjustments(),this.resetScrollbar(),this.$element.trigger("hidden.bs.modal")},this))}},n.METHODS_TO_OVERRIDE["v3.3.4"]=t.extend({},n.METHODS_TO_OVERRIDE["v3.3"]),n.prototype={constructor:n,getGlobalOpenedDialogs:function(){var e=[];return t.each(o.dialogs,function(t,n){n.isRealized()&&n.isOpened()&&e.push(n)}),e}},n.prototype=t.extend(n.prototype,e.prototype,n.METHODS_TO_OVERRIDE[n.getModalVersion()]);var o=function(e){this.defaultOptions=t.extend(!0,{id:o.newGuid(),buttons:[],data:{},onshow:null,onshown:null,onhide:null,onhidden:null},o.defaultOptions),this.indexedButtons={},this.registeredButtonHotkeys={},this.draggableData={isMouseDown:!1,mouseOffset:{}},this.realized=!1,this.opened=!1,this.initOptions(e),this.holdThisInstance()};return o.BootstrapDialogModal=n,o.NAMESPACE="bootstrap-dialog",o.TYPE_DEFAULT="type-default",o.TYPE_INFO="type-info",o.TYPE_PRIMARY="type-primary",o.TYPE_SUCCESS="type-success",o.TYPE_WARNING="type-warning",o.TYPE_DANGER="type-danger",o.DEFAULT_TEXTS={},o.DEFAULT_TEXTS[o.TYPE_DEFAULT]="Information",o.DEFAULT_TEXTS[o.TYPE_INFO]="Information",o.DEFAULT_TEXTS[o.TYPE_PRIMARY]="Information",o.DEFAULT_TEXTS[o.TYPE_SUCCESS]="Success",o.DEFAULT_TEXTS[o.TYPE_WARNING]="Warning",o.DEFAULT_TEXTS[o.TYPE_DANGER]="Danger",o.DEFAULT_TEXTS.OK="OK",o.DEFAULT_TEXTS.CANCEL="Cancel",o.DEFAULT_TEXTS.CONFIRM="Confirmation",o.SIZE_NORMAL="size-normal",o.SIZE_SMALL="size-small",o.SIZE_WIDE="size-wide",o.SIZE_LARGE="size-large",o.BUTTON_SIZES={},o.BUTTON_SIZES[o.SIZE_NORMAL]="",o.BUTTON_SIZES[o.SIZE_SMALL]="",o.BUTTON_SIZES[o.SIZE_WIDE]="",o.BUTTON_SIZES[o.SIZE_LARGE]="btn-lg",o.ICON_SPINNER="glyphicon glyphicon-asterisk",o.BUTTONS_ORDER_CANCEL_OK="btns-order-cancel-ok",o.BUTTONS_ORDER_OK_CANCEL="btns-order-ok-cancel",o.defaultOptions={type:o.TYPE_PRIMARY,size:o.SIZE_NORMAL,cssClass:"",title:null,message:null,nl2br:!0,closable:!0,closeByBackdrop:!0,closeByKeyboard:!0,closeIcon:"×",spinicon:o.ICON_SPINNER,autodestroy:!0,draggable:!1,animate:!0,description:"",tabindex:-1,btnsOrder:o.BUTTONS_ORDER_CANCEL_OK},o.configDefaultOptions=function(e){o.defaultOptions=t.extend(!0,o.defaultOptions,e)},o.dialogs={},o.openAll=function(){t.each(o.dialogs,function(t,e){e.open()})},o.closeAll=function(){t.each(o.dialogs,function(t,e){e.close()})},o.getDialog=function(t){var e=null;return void 0!==o.dialogs[t]&&(e=o.dialogs[t]),e},o.setDialog=function(t){return o.dialogs[t.getId()]=t,t},o.addDialog=function(t){return o.setDialog(t)},o.moveFocus=function(){var e=null;t.each(o.dialogs,function(t,n){n.isRealized()&&n.isOpened()&&(e=n)}),null!==e&&e.getModal().focus()},o.METHODS_TO_OVERRIDE={},o.METHODS_TO_OVERRIDE["v3.1"]={handleModalBackdropEvent:function(){return this.getModal().on("click",{dialog:this},function(t){t.target===this&&t.data.dialog.isClosable()&&t.data.dialog.canCloseByBackdrop()&&t.data.dialog.close()}),this},updateZIndex:function(){if(this.isOpened()){var e=0;t.each(o.dialogs,function(t,n){n.isRealized()&&n.isOpened()&&e++});var n=this.getModal(),i=n.data("bs.modal").$backdrop;n.css("z-index",1050+20*(e-1)),i.css("z-index",1040+20*(e-1))}return this},open:function(){return!this.isRealized()&&this.realize(),this.getModal().modal("show"),this.updateZIndex(),this}},o.METHODS_TO_OVERRIDE["v3.2"]={handleModalBackdropEvent:o.METHODS_TO_OVERRIDE["v3.1"].handleModalBackdropEvent,updateZIndex:o.METHODS_TO_OVERRIDE["v3.1"].updateZIndex,open:o.METHODS_TO_OVERRIDE["v3.1"].open},o.METHODS_TO_OVERRIDE["v3.3"]={},o.METHODS_TO_OVERRIDE["v3.3.4"]=t.extend({},o.METHODS_TO_OVERRIDE["v3.1"]),o.prototype={constructor:o,initOptions:function(e){return this.options=t.extend(!0,this.defaultOptions,e),this},holdThisInstance:function(){return o.addDialog(this),this},initModalStuff:function(){return this.setModal(this.createModal()).setModalDialog(this.createModalDialog()).setModalContent(this.createModalContent()).setModalHeader(this.createModalHeader()).setModalBody(this.createModalBody()).setModalFooter(this.createModalFooter()),this.getModal().append(this.getModalDialog()),this.getModalDialog().append(this.getModalContent()),this.getModalContent().append(this.getModalHeader()).append(this.getModalBody()).append(this.getModalFooter()),this},createModal:function(){var e=t('');return e.prop("id",this.getId()),e.attr("aria-labelledby",this.getId()+"_title"),e},getModal:function(){return this.$modal},setModal:function(t){return this.$modal=t,this},createModalDialog:function(){return t('')},getModalDialog:function(){return this.$modalDialog},setModalDialog:function(t){return this.$modalDialog=t,this},createModalContent:function(){return t('')},getModalContent:function(){return this.$modalContent},setModalContent:function(t){return this.$modalContent=t,this},createModalHeader:function(){return t('')},getModalHeader:function(){return this.$modalHeader},setModalHeader:function(t){return this.$modalHeader=t,this},createModalBody:function(){return t('')},getModalBody:function(){return this.$modalBody},setModalBody:function(t){return this.$modalBody=t,this},createModalFooter:function(){return t('')},getModalFooter:function(){return this.$modalFooter},setModalFooter:function(t){return this.$modalFooter=t,this},createDynamicContent:function(t){var e=null;return"string"==typeof(e="function"==typeof t?t.call(t,this):t)&&(e=this.formatStringContent(e)),e},formatStringContent:function(t){return this.options.nl2br?t.replace(/\r\n/g,"
").replace(/[\r\n]/g,"
"):t},setData:function(t,e){return this.options.data[t]=e,this},getData:function(t){return this.options.data[t]},setId:function(t){return this.options.id=t,this},getId:function(){return this.options.id},getType:function(){return this.options.type},setType:function(t){return this.options.type=t,this.updateType(),this},updateType:function(){if(this.isRealized()){var t=[o.TYPE_DEFAULT,o.TYPE_INFO,o.TYPE_PRIMARY,o.TYPE_SUCCESS,o.TYPE_WARNING,o.TYPE_DANGER];this.getModal().removeClass(t.join(" ")).addClass(this.getType())}return this},getSize:function(){return this.options.size},setSize:function(t){return this.options.size=t,this.updateSize(),this},updateSize:function(){if(this.isRealized()){var e=this;this.getModal().removeClass(o.SIZE_NORMAL).removeClass(o.SIZE_SMALL).removeClass(o.SIZE_WIDE).removeClass(o.SIZE_LARGE),this.getModal().addClass(this.getSize()),this.getModalDialog().removeClass("modal-sm"),this.getSize()===o.SIZE_SMALL&&this.getModalDialog().addClass("modal-sm"),this.getModalDialog().removeClass("modal-lg"),this.getSize()===o.SIZE_WIDE&&this.getModalDialog().addClass("modal-lg"),t.each(this.options.buttons,function(n,o){var i=e.getButton(o.id),s=["btn-lg","btn-sm","btn-xs"],a=!1;if("string"==typeof o.cssClass){var d=o.cssClass.split(" ");t.each(d,function(e,n){-1!==t.inArray(n,s)&&(a=!0)})}a||(i.removeClass(s.join(" ")),i.addClass(e.getButtonSize()))})}return this},getCssClass:function(){return this.options.cssClass},setCssClass:function(t){return this.options.cssClass=t,this},getTitle:function(){return this.options.title},setTitle:function(t){return this.options.title=t,this.updateTitle(),this},updateTitle:function(){if(this.isRealized()){var t=null!==this.getTitle()?this.createDynamicContent(this.getTitle()):this.getDefaultText();this.getModalHeader().find("."+this.getNamespace("title")).html("").append(t).prop("id",this.getId()+"_title")}return this},getMessage:function(){return this.options.message},setMessage:function(t){return this.options.message=t,this.updateMessage(),this},updateMessage:function(){if(this.isRealized()){var t=this.createDynamicContent(this.getMessage());this.getModalBody().find("."+this.getNamespace("message")).html("").append(t)}return this},isClosable:function(){return this.options.closable},setClosable:function(t){return this.options.closable=t,this.updateClosable(),this},setCloseByBackdrop:function(t){return this.options.closeByBackdrop=t,this},canCloseByBackdrop:function(){return this.options.closeByBackdrop},setCloseByKeyboard:function(t){return this.options.closeByKeyboard=t,this},canCloseByKeyboard:function(){return this.options.closeByKeyboard},isAnimate:function(){return this.options.animate},setAnimate:function(t){return this.options.animate=t,this},updateAnimate:function(){return this.isRealized()&&this.getModal().toggleClass("fade",this.isAnimate()),this},getSpinicon:function(){return this.options.spinicon},setSpinicon:function(t){return this.options.spinicon=t,this},addButton:function(t){return this.options.buttons.push(t),this},addButtons:function(e){var n=this;return t.each(e,function(t,e){n.addButton(e)}),this},getButtons:function(){return this.options.buttons},setButtons:function(t){return this.options.buttons=t,this.updateButtons(),this},getButton:function(t){return void 0!==this.indexedButtons[t]?this.indexedButtons[t]:null},getButtonSize:function(){return void 0!==o.BUTTON_SIZES[this.getSize()]?o.BUTTON_SIZES[this.getSize()]:""},updateButtons:function(){return this.isRealized()&&(0===this.getButtons().length?this.getModalFooter().hide():this.getModalFooter().show().find("."+this.getNamespace("footer")).html("").append(this.createFooterButtons())),this},isAutodestroy:function(){return this.options.autodestroy},setAutodestroy:function(t){this.options.autodestroy=t},getDescription:function(){return this.options.description},setDescription:function(t){return this.options.description=t,this},setTabindex:function(t){return this.options.tabindex=t,this},getTabindex:function(){return this.options.tabindex},updateTabindex:function(){return this.isRealized()&&this.getModal().attr("tabindex",this.getTabindex()),this},getDefaultText:function(){return o.DEFAULT_TEXTS[this.getType()]},getNamespace:function(t){return o.NAMESPACE+"-"+t},createHeaderContent:function(){var e=t("
");return e.addClass(this.getNamespace("header")),e.append(this.createTitleContent()),e.prepend(this.createCloseButton()),e},createTitleContent:function(){var e=t("
");return e.addClass(this.getNamespace("title")),e},createCloseButton:function(){var e=t("
");e.addClass(this.getNamespace("close-button"));var n=t('');return n.append(this.options.closeIcon),e.append(n),e.on("click",{dialog:this},function(t){t.data.dialog.close()}),e},createBodyContent:function(){var e=t("
");return e.addClass(this.getNamespace("body")),e.append(this.createMessageContent()),e},createMessageContent:function(){var e=t("
");return e.addClass(this.getNamespace("message")),e},createFooterContent:function(){var e=t("
");return e.addClass(this.getNamespace("footer")),e},createFooterButtons:function(){var e=this,n=t("
");return n.addClass(this.getNamespace("footer-buttons")),this.indexedButtons={},t.each(this.options.buttons,function(t,i){i.id||(i.id=o.newGuid());var s=e.createButton(i);e.indexedButtons[i.id]=s,n.append(s)}),n},createButton:function(e){var n=t('');return n.prop("id",e.id),n.data("button",e),void 0!==e.icon&&""!==t.trim(e.icon)&&n.append(this.createButtonIcon(e.icon)),void 0!==e.label&&n.append(e.label),void 0!==e.title&&n.attr("title",e.title),void 0!==e.cssClass&&""!==t.trim(e.cssClass)?n.addClass(e.cssClass):n.addClass("btn-default"),"object"==typeof e.data&&e.data.constructor==={}.constructor&&t.each(e.data,function(t,e){n.attr("data-"+t,e)}),void 0!==e.hotkey&&(this.registeredButtonHotkeys[e.hotkey]=n),n.on("click",{dialog:this,$button:n,button:e},function(t){var e=t.data.dialog,n=t.data.$button,o=n.data("button");if(o.autospin&&n.toggleSpin(!0),"function"==typeof o.action)return o.action.call(n,e,t)}),this.enhanceButton(n),void 0!==e.enabled&&n.toggleEnable(e.enabled),n},enhanceButton:function(t){return t.dialog=this,t.toggleEnable=function(t){var e=this;return void 0!==t?e.prop("disabled",!t).toggleClass("disabled",!t):e.prop("disabled",!e.prop("disabled")),e},t.enable=function(){var t=this;return t.toggleEnable(!0),t},t.disable=function(){var t=this;return t.toggleEnable(!1),t},t.toggleSpin=function(e){var n=this,o=n.dialog,i=n.find("."+o.getNamespace("button-icon"));return void 0===e&&(e=!(t.find(".icon-spin").length>0)),e?(i.hide(),t.prepend(o.createButtonIcon(o.getSpinicon()).addClass("icon-spin"))):(i.show(),t.find(".icon-spin").remove()),n},t.spin=function(){var t=this;return t.toggleSpin(!0),t},t.stopSpin=function(){var t=this;return t.toggleSpin(!1),t},this},createButtonIcon:function(e){var n=t("");return n.addClass(this.getNamespace("button-icon")).addClass(e),n},enableButtons:function(e){return t.each(this.indexedButtons,function(t,n){n.toggleEnable(e)}),this},updateClosable:function(){return this.isRealized()&&this.getModalHeader().find("."+this.getNamespace("close-button")).toggle(this.isClosable()),this},onShow:function(t){return this.options.onshow=t,this},onShown:function(t){return this.options.onshown=t,this},onHide:function(t){return this.options.onhide=t,this},onHidden:function(t){return this.options.onhidden=t,this},isRealized:function(){return this.realized},setRealized:function(t){return this.realized=t,this},isOpened:function(){return this.opened},setOpened:function(t){return this.opened=t,this},handleModalEvents:function(){return this.getModal().on("show.bs.modal",{dialog:this},function(t){var e=t.data.dialog;if(e.setOpened(!0),e.isModalEvent(t)&&"function"==typeof e.options.onshow){var n=e.options.onshow(e);return!1===n&&e.setOpened(!1),n}}),this.getModal().on("shown.bs.modal",{dialog:this},function(t){var e=t.data.dialog;e.isModalEvent(t)&&"function"==typeof e.options.onshown&&e.options.onshown(e)}),this.getModal().on("hide.bs.modal",{dialog:this},function(t){var e=t.data.dialog;if(e.setOpened(!1),e.isModalEvent(t)&&"function"==typeof e.options.onhide){var n=e.options.onhide(e);return!1===n&&e.setOpened(!0),n}}),this.getModal().on("hidden.bs.modal",{dialog:this},function(e){var n=e.data.dialog;n.isModalEvent(e)&&"function"==typeof n.options.onhidden&&n.options.onhidden(n),n.isAutodestroy()&&(n.setRealized(!1),delete o.dialogs[n.getId()],t(this).remove()),o.moveFocus(),t(".modal").hasClass("in")&&t("body").addClass("modal-open")}),this.handleModalBackdropEvent(),this.getModal().on("keyup",{dialog:this},function(t){27===t.which&&t.data.dialog.isClosable()&&t.data.dialog.canCloseByKeyboard()&&t.data.dialog.close()}),this.getModal().on("keyup",{dialog:this},function(e){var n=e.data.dialog;if(void 0!==n.registeredButtonHotkeys[e.which]){var o=t(n.registeredButtonHotkeys[e.which]);!o.prop("disabled")&&!o.is(":focus")&&o.focus().trigger("click")}}),this},handleModalBackdropEvent:function(){return this.getModal().on("click",{dialog:this},function(e){t(e.target).hasClass("modal-backdrop")&&e.data.dialog.isClosable()&&e.data.dialog.canCloseByBackdrop()&&e.data.dialog.close()}),this},isModalEvent:function(t){return void 0!==t.namespace&&"bs.modal"===t.namespace},makeModalDraggable:function(){return this.options.draggable&&(this.getModalHeader().addClass(this.getNamespace("draggable")).on("mousedown",{dialog:this},function(t){var e=t.data.dialog;e.draggableData.isMouseDown=!0;var n=e.getModalDialog().offset();e.draggableData.mouseOffset={top:t.clientY-n.top,left:t.clientX-n.left}}),this.getModal().on("mouseup mouseleave",{dialog:this},function(t){t.data.dialog.draggableData.isMouseDown=!1}),t("body").on("mousemove",{dialog:this},function(t){var e=t.data.dialog;e.draggableData.isMouseDown&&e.getModalDialog().offset({top:t.clientY-e.draggableData.mouseOffset.top,left:t.clientX-e.draggableData.mouseOffset.left})})),this},realize:function(){return this.initModalStuff(),this.getModal().addClass(o.NAMESPACE).addClass(this.getCssClass()),this.updateSize(),this.getDescription()&&this.getModal().attr("aria-describedby",this.getDescription()),this.getModalFooter().append(this.createFooterContent()),this.getModalHeader().append(this.createHeaderContent()),this.getModalBody().append(this.createBodyContent()),this.getModal().data("bs.modal",new n(this.getModal(),{backdrop:"static",keyboard:!1,show:!1})),this.makeModalDraggable(),this.handleModalEvents(),this.setRealized(!0),this.updateButtons(),this.updateType(),this.updateTitle(),this.updateMessage(),this.updateClosable(),this.updateAnimate(),this.updateSize(),this.updateTabindex(),this},open:function(){return!this.isRealized()&&this.realize(),this.getModal().modal("show"),this},close:function(){return!this.isRealized()&&this.realize(),this.getModal().modal("hide"),this}},o.prototype=t.extend(o.prototype,o.METHODS_TO_OVERRIDE[n.getModalVersion()]),o.newGuid=function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(t){var e=16*Math.random()|0;return("x"===t?e:3&e|8).toString(16)})},o.show=function(t){return new o(t).open()},o.alert=function(){var e={},n={type:o.TYPE_PRIMARY,title:null,message:null,closable:!1,draggable:!1,buttonLabel:o.DEFAULT_TEXTS.OK,buttonHotkey:null,callback:null};e="object"==typeof arguments[0]&&arguments[0].constructor==={}.constructor?t.extend(!0,n,arguments[0]):t.extend(!0,n,{message:arguments[0],callback:void 0!==arguments[1]?arguments[1]:null});var i=new o(e);return i.setData("callback",e.callback),i.addButton({label:e.buttonLabel,hotkey:e.buttonHotkey,action:function(t){return("function"!=typeof t.getData("callback")||!1!==t.getData("callback").call(this,!0))&&(t.setData("btnClicked",!0),t.close())}}),"function"==typeof i.options.onhide?i.onHide(function(t){var e=!0;return!t.getData("btnClicked")&&t.isClosable()&&"function"==typeof t.getData("callback")&&(e=t.getData("callback")(!1)),!1!==e&&(e=this.onhide(t))}.bind({onhide:i.options.onhide})):i.onHide(function(t){var e=!0;return!t.getData("btnClicked")&&t.isClosable()&&"function"==typeof t.getData("callback")&&(e=t.getData("callback")(!1)),e}),i.open()},o.confirm=function(){var e={},n={type:o.TYPE_PRIMARY,title:null,message:null,closable:!1,draggable:!1,btnCancelLabel:o.DEFAULT_TEXTS.CANCEL,btnCancelClass:null,btnCancelHotkey:null,btnOKLabel:o.DEFAULT_TEXTS.OK,btnOKClass:null,btnOKHotkey:null,btnsOrder:o.defaultOptions.btnsOrder,callback:null};null===(e="object"==typeof arguments[0]&&arguments[0].constructor==={}.constructor?t.extend(!0,n,arguments[0]):t.extend(!0,n,{message:arguments[0],callback:void 0!==arguments[1]?arguments[1]:null})).btnOKClass&&(e.btnOKClass=["btn",e.type.split("-")[1]].join("-"));var i=new o(e);i.setData("callback",e.callback);var s=[{label:e.btnCancelLabel,cssClass:e.btnCancelClass,hotkey:e.btnCancelHotkey,action:function(t){return("function"!=typeof t.getData("callback")||!1!==t.getData("callback").call(this,!1))&&t.close()}},{label:e.btnOKLabel,cssClass:e.btnOKClass,hotkey:e.btnOKHotkey,action:function(t){return("function"!=typeof t.getData("callback")||!1!==t.getData("callback").call(this,!0))&&t.close()}}];return e.btnsOrder===o.BUTTONS_ORDER_OK_CANCEL&&s.reverse(),i.addButtons(s),i.open()},o.warning=function(t,e){return new o({type:o.TYPE_WARNING,message:t}).open()},o.danger=function(t,e){return new o({type:o.TYPE_DANGER,message:t}).open()},o.success=function(t,e){return new o({type:o.TYPE_SUCCESS,message:t}).open()},o}); -------------------------------------------------------------------------------- /examples/images/pig.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nakupanda/bootstrap3-dialog/a491a98c97921114883ad44e5715fe28396dbaea/examples/images/pig.ico -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | BootstrapDialog examples 12 | 17 | 18 | 19 |
20 |

Make use of Bootstrap's modal more monkey-friendly.

21 |
22 |

23 | Monkeys love the Modal Dialog from Bootstrap, but they're getting angry because they have to write this stuff: 24 |

25 |
<div class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Modal title</h4>
</div>
<div class="modal-body">
<p>One fine body…</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal --> 26 |
27 |

28 | What they want is more like this: 29 |

30 |
31 | BootstrapDialog.alert('I want banana!'); 32 |
33 |

34 |

35 | Like it? See Available Options or try more Examples below. 36 |

37 | 38 | 39 | 40 |

Examples

41 |
42 | 43 |

Simplest

44 |

Provide only the message to show, and keep all other things default.

45 |
46 | 51 |
52 | 53 |

Dialog Title

54 |
55 | 61 |
62 | 63 | 64 |

Manipulating Dialog Title

65 |
66 | 83 |
84 | 85 |

Manipulating Dialog Message

86 |
87 | 104 |
105 | 106 | 107 |

Loading remote page (1)

108 |

109 | There are some workarounds for loading remote page into BootstrapDialog as message, one of those workarounds is as below.
110 | Check out the remote.html. 111 |

112 |
113 | 118 |
119 | 120 |

Loading remote page (2)

121 |

122 | Another solution of loading remote page into BootstrapDialog.
123 | This one is more flexible and customizable, but it's also a bit more complicated to use. 124 |

125 |
126 | 140 |
141 | 142 |

Buttons

143 |
144 | 174 |
175 | 176 |

Manipulating Buttons

177 |

178 | Buttons that created by BootstrapDialog have some extra functions available:
179 | $button.toggleEnable(true|false);
180 | $button.enable(); // Equals to $button.toggleEnable(true);
181 | $button.disable(); // Equals to $button.toggleEnable(false);
182 | $button.toggleSpin(true|false);
183 | $button.spin(); // Equals to $button.toggleSpin(true);
184 | $button.stopSpin(); // Equals to $button.toggleSpin(false);
185 |

186 |
187 | 213 |
214 | 215 | 216 |

Button Hotkey

217 |

218 | Try to press the keys that have been associated with buttons below.
219 | The last button is disabled so nothing is going to happen when pressing its hotkey.
220 | Please note that if there are some components that require keyboard operations in your dialog, conflicts may occur, you can try next example. 221 |

222 |
223 | 252 |
253 | 254 |

Keys Conflicts

255 |

Try to avoid doing similar in your code.

256 |
257 | 271 |
272 | 273 | 274 |

Opening multiple dialogs

275 |

A good looking stacked dialogs. Please also note the second and the third dialog are draggable.

276 |
277 | 302 |
303 | 304 |

Creating dialog instances

305 |

BootstrapDialog.show(...) is just a shortcut method, if you need dialog instances, use 'new'.

306 |
307 | 329 |
330 |

In fact BootstrapDialog.show(...) will also return the created dialog instance.

331 |
332 | 338 |
339 | 340 |

Open / Close multiple dialogs

341 |

This example demonstrates opening and closing a batch of dialogs at one time.
Dialog that created by BootstrapDialog will be in a container BootstrapDialog.dialogs before it's closed and destroyed, iterate BootstrapDialog.dialogs to find all dialogs that havn't been destroyed.

342 |
343 | 368 |
369 | 370 |

Button with identifier

371 |
372 | 387 |
388 | 389 |

Message types

390 |
391 | 410 |
411 | 412 | 413 |

Changing dialog type

414 |
415 | 440 |
441 | 442 |

Larger dialog

443 |

444 | By default, the dialog size is 'size-normal' or BootstrapDialog.SIZE_NORMAL, but you can have a larger dialog by setting option 'size' to 'size-large' or BootstrapDialog.SIZE_LARGE. 445 |

446 |
447 | 471 |
472 | 473 | 474 |

More dialog sizes

475 |

476 | Please note that specifying BootstrapDialog.SIZE_WIDE is equal to using css class 'modal-lg' on Bootstrap Modal. 477 |

478 |
479 | 510 |
511 | 512 |

Rich message

513 |

BootstrapDialog supports displaying rich content, so you can even use a video clip as your message in the dialog.

514 |
515 | 536 |
537 | 538 |

Dialog closable / unclosable

539 |

540 | If option 'closable' is set to false, the default closing behaviors will be disabled, but you can still close the dialog by using dialog.close(). 541 |

542 |
543 | 567 |
568 | 569 | 570 |

More controls on closing a dialog.

571 |

572 | By default, when option 'closable' is set to true, dialog can be closed by these ways: clicking outside the dialog, pressing ESC key, clicking the close icon on the right of dialog header.
573 | If you want your dialog closes only when the close icon in dialog header was clicked, try setting both of the options 'closeByBackdrop' and 'closeByKeyboard' to false. 574 |

575 |
576 | 591 |
592 | 593 | 594 |

Disabling Animation

595 |

596 | Setting option 'animate' to false to disable animation for the opening dialog.
597 | If you want to disable animation globally, try to do this:
598 | BootstrapDialog.configDefaultOptions({ 599 | animate: false 600 | }); 601 |

602 |
603 | 615 |
616 | 617 |

Auto spinning icon

618 |

619 | Lazy guys must love this. 620 |

621 |
622 | 646 |
647 | 648 | 649 |

Dialog Draggable

650 |

651 | When option 'draggable' is set to true, your dialog can be moved by dragging on its header.
652 | If you would like to change the cursor shape of hovering on dialog header, you can try the following css lines:
653 |

654 | .bootstrap-dialog .modal-header.bootstrap-dialog-draggable { 655 | cursor: move; 656 | } 657 |
658 |

659 |
660 | 667 |
668 | 669 |

Manipulating your dialog

670 |
671 | 692 |
693 | 694 |

Adding additional css classes to your dialog

695 |

This is useful for applying effects to specific dialogs.
696 | For example if you would like to give your 'login-dialog' a smaller size, you can do this way:

697 |
698 | 705 |
706 |
707 | 721 |
722 | 723 |

Adding a description to your dialog (for accessibility)

724 |

This adds an 'aria-describedby' attribute to your dialog, which provides a description of the dialog for screen readers.

725 |
726 | 733 |
734 | 735 |

Data binding

736 |
737 | 759 |
760 | 761 |

Dialog events

762 |

763 | Please note that if you're going to use setters to configure event handlers, use dialog.onShow(function) and dialog.onHide(function). 764 |

765 |
766 | 783 |
784 | 785 | 786 |

Stop closing your dialog.

787 |

788 | Option 'onhide' gives you an opportunity to stop closing the dialog according to some conditions, making your 'onhide' callback returns false to stop closing the dialog.
789 | In the following example, the dialog closes only when your most favorite fruit is 'banana' (Case insensitive). 790 |

791 |
792 | 810 |
811 | 812 |

More shortcut methods

813 |
814 |

Alert

815 |
816 | 819 |
820 | 821 |

Alert with callback

822 |
823 | 828 |
829 | 830 | 831 |

Customizing dialog type, title, and more.

832 |

All options shown below are optional.

833 |
834 | 848 |
849 | 850 |

Confirm

851 |
852 | 855 |
856 | 857 |

Confirm with callback

858 |
859 | 868 |
869 | 870 | 871 |

Just like what we have done in alert, we can control confirm dialog more.

872 |
873 | 893 |
894 | 895 | 896 |

I18N

897 |

To provide local messages for you needed, reset those messages below before using BootstrapDialog.

898 |
899 | 910 |
911 | 912 | 913 | 914 |

Available options

915 |
916 |

917 | Please note that all options described below are optional, but you will have a weird dialog if you don't even give it a message to display. 918 |
919 | Most options can be set via init options or property setters. 920 |

921 | 922 | 923 | 924 | 927 | 930 | 933 | 934 | 935 | 936 | 937 | 938 | 946 | 949 | 950 | 951 | 952 | 957 | 960 | 961 | 962 | 963 | 966 | 969 | 970 | 971 | 972 | 975 | 978 | 979 | 980 | 981 | 984 | 987 | 988 | 989 | 990 | 993 | 1022 | 1023 | 1024 | 1025 | 1028 | 1036 | 1037 | 1038 | 1039 | 1043 | 1046 | 1047 | 1048 | 1049 | 1052 | 1055 | 1056 | 1057 | 1058 | 1061 | 1064 | 1065 | 1066 | 1067 | 1070 | 1073 | 1074 | 1075 | 1076 | 1079 | 1082 | 1083 | 1084 | 1085 | 1088 | 1091 | 1092 | 1093 | 1094 | 1097 | 1100 | 1101 | 1102 | 1103 | 1106 | 1109 | 1110 | 1111 | 1112 | 1115 | 1118 | 1119 | 1120 | 1121 |
925 | Option 926 | 928 | Possible values 929 | 931 | Description 932 |
type 939 | BootstrapDialog.TYPE_DEFAULT or 'type-default'
940 | BootstrapDialog.TYPE_INFO or 'type-info'
941 | BootstrapDialog.TYPE_PRIMARY or 'type-primary' (default)
942 | BootstrapDialog.TYPE_SUCCESS or 'type-success'
943 | BootstrapDialog.TYPE_WARNING or 'type-warning'
944 | BootstrapDialog.TYPE_DANGER or 'type-danger' 945 |
947 | Give your dialog a specific look, color scheme can be seen on Bootstrap's Button. 948 |
size 953 | BootstrapDialog.SIZE_NORMAL or 'size-normal' (default)
954 | BootstrapDialog.SIZE_WIDE or 'size-wide'
955 | BootstrapDialog.SIZE_LARGE or 'size-large'
956 |
958 | - 959 |
cssClass 964 | - 965 | 967 | Additional css classes that will be added to your dialog. 968 |
title 973 | String or Object(html) 974 | 976 | - 977 |
message 982 | String or Object(html) 983 | 985 | - 986 |
buttons 991 | array 992 | 994 | Examples: 995 |
996 | BootstrapDialog.show({ 997 | title: 'Say-hello dialog', 998 | message: 'Hello world!', 999 | buttons: [{ 1000 | id: 'btn-ok', 1001 | icon: 'glyphicon glyphicon-check', 1002 | label: 'OK', 1003 | cssClass: 'btn-primary', 1004 | data: { 1005 | js: 'btn-confirm', 1006 | 'user-id': '3' 1007 | }, 1008 | autospin: false, 1009 | action: function(dialogRef){ 1010 | dialogRef.close(); 1011 | } 1012 | }] 1013 | }); 1014 |
1015 | id: optional, if id is set, you can use dialogInstance.getButton(id) to get the button later.
1016 | icon: optional, if set, the specified icon will be added to the button.
1017 | cssClass: optional, additional css class to be added to the button.
1018 | data: optional, object containing data attributes to be added to the button.
1019 | autospin: optional, if it's true, after clicked the button a spinning icon appears.
1020 | action: optional, if provided, the callback will be invoked after the button is clicked, and the dialog instance will be passed to the callback function. 1021 |
closable 1026 | true | false 1027 | 1029 | When set to true, you can close the dialog by:
1030 |
    1031 |
  • Clicking the close icon in dialog header.
  • 1032 |
  • Clicking outside the dialog.
  • 1033 |
  • ESC key.
  • 1034 |
1035 |
spinicon 1040 | Icon class name, for example 'glyphicon glyphicon-check'.
1041 | Default value is 'glyphicon glyphicon-asterisk'. 1042 |
1044 | Specify what icon to be used as the spinning icon when button's 'autospin' is set to true. 1045 |
data 1050 | Key-value object. For example {'id' : '100'} 1051 | 1053 | Data to be bound to the dialog. 1054 |
onshow 1059 | function 1060 | 1062 | If provided, it will be invoked when the dialog is popping up.
1063 |
onshown 1068 | function 1069 | 1071 | If provided, it will be invoked when the dialog is popped up.
1072 |
onhide 1077 | function 1078 | 1080 | If provided, it will be invoked when the dialog is popping down.
1081 |
onhidden 1086 | function 1087 | 1089 | If provided, it will be invoked when the dialog is popped down.
1090 |
autodestroy 1095 | true (default) | false 1096 | 1098 | When it's true, all modal stuff will be removed from the DOM tree after the dialog is popped down, set it to false if you need your dialog (same instance) pups up and down again and again. 1099 |
description 1104 | String 1105 | 1107 | If provided, 'aria-describedby' attribute will be added to the dialog with the description string as its value. This can improve accessibility, as the description can be read by screen readers. 1108 |
nl2br 1113 | true | false 1114 | 1116 | Automatically convert line breaking character to <br /> if it's set to true, everything keeps original if it's false. 1117 |
1122 | 1123 | 1124 | 1125 |

Available methods

1126 |
1127 | 1128 | 1129 | 1130 | 1133 | 1136 | 1137 | 1138 | 1139 | 1140 | 1141 | 1142 | 1143 | 1144 | 1145 | 1146 | 1147 | 1148 | 1149 | 1150 | 1151 | 1152 | 1153 | 1154 | 1155 | 1156 | 1157 | 1158 | 1159 | 1160 | 1161 | 1162 | 1163 | 1164 | 1165 | 1166 | 1167 | 1168 | 1169 | 1170 | 1171 | 1172 | 1173 | 1174 | 1175 | 1176 | 1177 | 1178 | 1179 | 1180 | 1181 | 1182 | 1183 | 1184 | 1185 | 1186 | 1187 | 1188 | 1189 | 1190 | 1191 | 1192 |
1131 | Method 1132 | 1134 | Description 1135 |
open()Open the dialog. Usage: dialogInstance.open()
close()Close the dialog. Usage: dialogInstance.close()
getModal()Return the raw modal, equivalent to $('<div class='modal fade'...></div>')
getModalDialog()Return the raw modal dialog.
getModalContent()Return the raw modal content.
getModalHeader()Return the raw modal header.
getModalBody()Return the raw modal body.
getModalFooter()Return the raw modal footer.
getData(key)Get data entry according to the given key, returns null if no data entry found.
setData(key, value)Bind data entry to dialog instance, value can be any types that javascript supports.
enableButtons(boolean)Disable all buttons in dialog footer when it's false, enable all when it's true.
setClosable(boolean)When set to true (default), dialog can be closed by clicking close icon in dialog header, or by clicking outside the dialog, or, ESC key is pressed.
realize()Calling dialog.open() will automatically get this method called first, but if you want to do something on your dialog before it's shown, you can manually call dialog.realize() before calling dialog.open().
1193 | 1194 |
1195 | 1196 |
1197 | 1198 | 1221 | 1222 | 1223 | -------------------------------------------------------------------------------- /examples/play/append-to-div.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Append modal to div 11 | 12 | 13 | 14 | 15 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /examples/play/button-event.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Button Event 11 | 12 | 13 | 14 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /examples/play/custom-dialog-id.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Dialog ID 11 | 12 | 13 | 14 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /examples/play/only-one-dialog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Only one dialog 12 | 13 | 24 | 25 | 26 |
27 | 28 |
29 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /examples/play/reopen-dialog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Reopen Dialog 11 | 12 | 13 | 14 | 15 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /examples/play/spinning-icon.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Spinning Icon 12 | 13 | 14 | 15 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /examples/play/tabindex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Tabindex 12 | 13 | 14 | 15 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /examples/remote.html: -------------------------------------------------------------------------------- 1 | Hello, this is a message from remote.html! -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | // Gulpfile.js 2 | 3 | "use strict"; 4 | 5 | var gulp = require("gulp"), 6 | eslint = require("gulp-eslint"), 7 | less = require("gulp-less"), 8 | minifyCSS = require("gulp-minify-css"), 9 | path = require("path"), 10 | notify = require("gulp-notify"), 11 | clean = require("gulp-clean"), 12 | rename = require("gulp-rename"), 13 | concat = require("gulp-concat"), 14 | uglify = require("gulp-uglify"); 15 | 16 | var less_src = [ 17 | "node_modules/bootstrap/less/variables.less", 18 | "node_modules/bootstrap/less/mixins/*.less", 19 | "src/less/bootstrap-dialog.less" 20 | ]; 21 | 22 | gulp.task("less", function() { 23 | gulp.src(less_src) 24 | .pipe(concat("bootstrap-dialog.less")) 25 | .pipe(gulp.dest("dist/less")) 26 | .pipe(less()) 27 | .pipe(gulp.dest("dist/css")) 28 | .pipe(gulp.dest("src/css")) 29 | .pipe(rename("bootstrap-dialog.min.css")) 30 | .pipe(minifyCSS()) 31 | .pipe(gulp.dest("dist/css")); 32 | }); 33 | 34 | gulp.task("lint", function() { 35 | gulp.src(["src/js/bootstrap-dialog.js"]) 36 | .pipe(eslint()) 37 | .pipe(eslint.format()); 38 | }); 39 | 40 | gulp.task("dist", ["clean", "less"], function() { 41 | gulp.src(["src/js/bootstrap-dialog.js"]) 42 | .pipe(gulp.dest("dist/js")) 43 | .pipe(rename("bootstrap-dialog.min.js")) 44 | .pipe(uglify()) 45 | .pipe(gulp.dest("dist/js")) 46 | .pipe(notify({ 47 | message: "Build task completed." 48 | })); 49 | }); 50 | 51 | gulp.task("clean", function() { 52 | return gulp.src(["dist/"], { 53 | read: false 54 | }) 55 | .pipe(clean()); 56 | }); 57 | 58 | gulp.task("default", ["clean"], function() { 59 | gulp.start("dist"); 60 | }); 61 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap3-dialog", 3 | "version": "1.35.4", 4 | "description": "Make use of Bootstrap Modal more monkey-friendly.", 5 | "directories": { 6 | "example": "examples" 7 | }, 8 | "main": "dist/js/bootstrap-dialog.js", 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/nakupanda/bootstrap3-dialog.git" 15 | }, 16 | "keywords": [ 17 | "bootstrap", 18 | "dialog" 19 | ], 20 | "author": "nakupanda", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/nakupanda/bootstrap3-dialog/issues" 24 | }, 25 | "homepage": "http://nakupanda.github.io/bootstrap3-dialog", 26 | "devDependencies": { 27 | "bootstrap": ">=3.1.0", 28 | "eslint": ">=0.6.2", 29 | "gulp": ">=3.8.1", 30 | "gulp-clean": ">=0.3.0", 31 | "gulp-concat": "^2.5.2", 32 | "gulp-eslint": ">=0.1.7", 33 | "gulp-less": ">=1.2.3", 34 | "gulp-minify-css": "^0.3.4", 35 | "gulp-notify": ">=1.3.1", 36 | "gulp-rename": ">=1.2.0", 37 | "gulp-streamify": "0.0.5", 38 | "gulp-uglify": ">=0.3.0", 39 | "vinyl-source-stream": "^0.1.1" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/css/bootstrap-dialog.css: -------------------------------------------------------------------------------- 1 | .bootstrap-dialog { 2 | /* dialog types */ 3 | /** 4 | * Icon animation 5 | * Copied from font-awesome: http://fontawesome.io/ 6 | **/ 7 | /** End of icon animation **/ 8 | } 9 | .bootstrap-dialog .modal-header { 10 | border-top-left-radius: 4px; 11 | border-top-right-radius: 4px; 12 | } 13 | .bootstrap-dialog .bootstrap-dialog-title { 14 | color: #fff; 15 | display: inline-block; 16 | font-size: 16px; 17 | } 18 | .bootstrap-dialog .bootstrap-dialog-message { 19 | font-size: 14px; 20 | } 21 | .bootstrap-dialog .bootstrap-dialog-button-icon { 22 | margin-right: 3px; 23 | } 24 | .bootstrap-dialog .bootstrap-dialog-close-button { 25 | font-size: 20px; 26 | float: right; 27 | opacity: 0.9; 28 | filter: alpha(opacity=90); 29 | } 30 | .bootstrap-dialog .bootstrap-dialog-close-button:hover { 31 | cursor: pointer; 32 | opacity: 1; 33 | filter: alpha(opacity=100); 34 | } 35 | .bootstrap-dialog.type-default .modal-header { 36 | background-color: #ffffff; 37 | } 38 | .bootstrap-dialog.type-default .bootstrap-dialog-title { 39 | color: #333; 40 | } 41 | .bootstrap-dialog.type-info .modal-header { 42 | background-color: #5bc0de; 43 | } 44 | .bootstrap-dialog.type-primary .modal-header { 45 | background-color: #337ab7; 46 | } 47 | .bootstrap-dialog.type-success .modal-header { 48 | background-color: #5cb85c; 49 | } 50 | .bootstrap-dialog.type-warning .modal-header { 51 | background-color: #f0ad4e; 52 | } 53 | .bootstrap-dialog.type-danger .modal-header { 54 | background-color: #d9534f; 55 | } 56 | .bootstrap-dialog.size-large .bootstrap-dialog-title { 57 | font-size: 24px; 58 | } 59 | .bootstrap-dialog.size-large .bootstrap-dialog-close-button { 60 | font-size: 30px; 61 | } 62 | .bootstrap-dialog.size-large .bootstrap-dialog-message { 63 | font-size: 18px; 64 | } 65 | .bootstrap-dialog .icon-spin { 66 | display: inline-block; 67 | -moz-animation: spin 2s infinite linear; 68 | -o-animation: spin 2s infinite linear; 69 | -webkit-animation: spin 2s infinite linear; 70 | animation: spin 2s infinite linear; 71 | } 72 | @-moz-keyframes spin { 73 | 0% { 74 | -moz-transform: rotate(0deg); 75 | } 76 | 100% { 77 | -moz-transform: rotate(359deg); 78 | } 79 | } 80 | @-webkit-keyframes spin { 81 | 0% { 82 | -webkit-transform: rotate(0deg); 83 | } 84 | 100% { 85 | -webkit-transform: rotate(359deg); 86 | } 87 | } 88 | @-o-keyframes spin { 89 | 0% { 90 | -o-transform: rotate(0deg); 91 | } 92 | 100% { 93 | -o-transform: rotate(359deg); 94 | } 95 | } 96 | @-ms-keyframes spin { 97 | 0% { 98 | -ms-transform: rotate(0deg); 99 | } 100 | 100% { 101 | -ms-transform: rotate(359deg); 102 | } 103 | } 104 | @keyframes spin { 105 | 0% { 106 | transform: rotate(0deg); 107 | } 108 | 100% { 109 | transform: rotate(359deg); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/js/bootstrap-dialog.js: -------------------------------------------------------------------------------- 1 | /* global define */ 2 | 3 | /* ================================================ 4 | * Make use of Bootstrap's modal more monkey-friendly. 5 | * 6 | * For Bootstrap 3. 7 | * 8 | * javanoob@hotmail.com 9 | * 10 | * https://github.com/nakupanda/bootstrap3-dialog 11 | * 12 | * Licensed under The MIT License. 13 | * ================================================ */ 14 | (function (root, factory) { 15 | 16 | "use strict"; 17 | 18 | // CommonJS module is defined 19 | if (typeof module !== 'undefined' && module.exports) { 20 | module.exports = factory(require('jquery'), require('bootstrap')); 21 | } 22 | // AMD module is defined 23 | else if (typeof define === "function" && define.amd) { 24 | define("bootstrap-dialog", ["jquery", "bootstrap"], function ($) { 25 | return factory($); 26 | }); 27 | } else { 28 | // planted over the root! 29 | root.BootstrapDialog = factory(root.jQuery); 30 | } 31 | 32 | }(this, function ($) { 33 | 34 | "use strict"; 35 | 36 | /* ================================================ 37 | * Definition of BootstrapDialogModal. 38 | * Extend Bootstrap Modal and override some functions. 39 | * BootstrapDialogModal === Modified Modal. 40 | * ================================================ */ 41 | var Modal = $.fn.modal.Constructor; 42 | var BootstrapDialogModal = function (element, options) { 43 | Modal.call(this, element, options); 44 | }; 45 | BootstrapDialogModal.getModalVersion = function () { 46 | var version = null; 47 | if (typeof $.fn.modal.Constructor.VERSION === 'undefined') { 48 | version = 'v3.1'; 49 | } else if (/3\.2\.\d+/.test($.fn.modal.Constructor.VERSION)) { 50 | version = 'v3.2'; 51 | } else if (/3\.3\.[1,2]/.test($.fn.modal.Constructor.VERSION)) { 52 | version = 'v3.3'; // v3.3.1, v3.3.2 53 | } else { 54 | version = 'v3.3.4'; 55 | } 56 | 57 | return version; 58 | }; 59 | BootstrapDialogModal.ORIGINAL_BODY_PADDING = parseInt(($('body').css('padding-right') || 0), 10); 60 | BootstrapDialogModal.METHODS_TO_OVERRIDE = {}; 61 | BootstrapDialogModal.METHODS_TO_OVERRIDE['v3.1'] = {}; 62 | BootstrapDialogModal.METHODS_TO_OVERRIDE['v3.2'] = { 63 | hide: function (e) { 64 | if (e) { 65 | e.preventDefault(); 66 | } 67 | e = $.Event('hide.bs.modal'); 68 | 69 | this.$element.trigger(e); 70 | 71 | if (!this.isShown || e.isDefaultPrevented()) { 72 | return; 73 | } 74 | 75 | this.isShown = false; 76 | 77 | // Remove css class 'modal-open' when the last opened dialog is closing. 78 | var openedDialogs = this.getGlobalOpenedDialogs(); 79 | if (openedDialogs.length === 0) { 80 | this.$body.removeClass('modal-open'); 81 | } 82 | 83 | this.resetScrollbar(); 84 | this.escape(); 85 | 86 | $(document).off('focusin.bs.modal'); 87 | 88 | this.$element 89 | .removeClass('in') 90 | .attr('aria-hidden', true) 91 | .off('click.dismiss.bs.modal'); 92 | 93 | $.support.transition && this.$element.hasClass('fade') ? 94 | this.$element 95 | .one('bsTransitionEnd', $.proxy(this.hideModal, this)) 96 | .emulateTransitionEnd(300) : 97 | this.hideModal(); 98 | } 99 | }; 100 | BootstrapDialogModal.METHODS_TO_OVERRIDE['v3.3'] = { 101 | /** 102 | * Overrided. 103 | * 104 | * @returns {undefined} 105 | */ 106 | setScrollbar: function () { 107 | var bodyPad = BootstrapDialogModal.ORIGINAL_BODY_PADDING; 108 | if (this.bodyIsOverflowing) { 109 | this.$body.css('padding-right', bodyPad + this.scrollbarWidth); 110 | } 111 | }, 112 | /** 113 | * Overrided. 114 | * 115 | * @returns {undefined} 116 | */ 117 | resetScrollbar: function () { 118 | var openedDialogs = this.getGlobalOpenedDialogs(); 119 | if (openedDialogs.length === 0) { 120 | this.$body.css('padding-right', BootstrapDialogModal.ORIGINAL_BODY_PADDING); 121 | } 122 | }, 123 | /** 124 | * Overrided. 125 | * 126 | * @returns {undefined} 127 | */ 128 | hideModal: function () { 129 | this.$element.hide(); 130 | this.backdrop($.proxy(function () { 131 | var openedDialogs = this.getGlobalOpenedDialogs(); 132 | if (openedDialogs.length === 0) { 133 | this.$body.removeClass('modal-open'); 134 | } 135 | this.resetAdjustments(); 136 | this.resetScrollbar(); 137 | this.$element.trigger('hidden.bs.modal'); 138 | }, this)); 139 | } 140 | }; 141 | BootstrapDialogModal.METHODS_TO_OVERRIDE['v3.3.4'] = $.extend({}, BootstrapDialogModal.METHODS_TO_OVERRIDE['v3.3']); 142 | BootstrapDialogModal.prototype = { 143 | constructor: BootstrapDialogModal, 144 | /** 145 | * New function, to get the dialogs that opened by BootstrapDialog. 146 | * 147 | * @returns {undefined} 148 | */ 149 | getGlobalOpenedDialogs: function () { 150 | var openedDialogs = []; 151 | $.each(BootstrapDialog.dialogs, function (id, dialogInstance) { 152 | if (dialogInstance.isRealized() && dialogInstance.isOpened()) { 153 | openedDialogs.push(dialogInstance); 154 | } 155 | }); 156 | 157 | return openedDialogs; 158 | } 159 | }; 160 | 161 | // Add compatible methods. 162 | BootstrapDialogModal.prototype = $.extend(BootstrapDialogModal.prototype, Modal.prototype, BootstrapDialogModal.METHODS_TO_OVERRIDE[BootstrapDialogModal.getModalVersion()]); 163 | 164 | /* ================================================ 165 | * Definition of BootstrapDialog. 166 | * ================================================ */ 167 | var BootstrapDialog = function (options) { 168 | this.defaultOptions = $.extend(true, { 169 | id: BootstrapDialog.newGuid(), 170 | buttons: [], 171 | data: {}, 172 | onshow: null, 173 | onshown: null, 174 | onhide: null, 175 | onhidden: null 176 | }, BootstrapDialog.defaultOptions); 177 | this.indexedButtons = {}; 178 | this.registeredButtonHotkeys = {}; 179 | this.draggableData = { 180 | isMouseDown: false, 181 | mouseOffset: {} 182 | }; 183 | this.realized = false; 184 | this.opened = false; 185 | this.initOptions(options); 186 | this.holdThisInstance(); 187 | }; 188 | 189 | BootstrapDialog.BootstrapDialogModal = BootstrapDialogModal; 190 | 191 | /** 192 | * Some constants. 193 | */ 194 | BootstrapDialog.NAMESPACE = 'bootstrap-dialog'; 195 | BootstrapDialog.TYPE_DEFAULT = 'type-default'; 196 | BootstrapDialog.TYPE_INFO = 'type-info'; 197 | BootstrapDialog.TYPE_PRIMARY = 'type-primary'; 198 | BootstrapDialog.TYPE_SUCCESS = 'type-success'; 199 | BootstrapDialog.TYPE_WARNING = 'type-warning'; 200 | BootstrapDialog.TYPE_DANGER = 'type-danger'; 201 | BootstrapDialog.DEFAULT_TEXTS = {}; 202 | BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_DEFAULT] = 'Information'; 203 | BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_INFO] = 'Information'; 204 | BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_PRIMARY] = 'Information'; 205 | BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_SUCCESS] = 'Success'; 206 | BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_WARNING] = 'Warning'; 207 | BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_DANGER] = 'Danger'; 208 | BootstrapDialog.DEFAULT_TEXTS['OK'] = 'OK'; 209 | BootstrapDialog.DEFAULT_TEXTS['CANCEL'] = 'Cancel'; 210 | BootstrapDialog.DEFAULT_TEXTS['CONFIRM'] = 'Confirmation'; 211 | BootstrapDialog.SIZE_NORMAL = 'size-normal'; 212 | BootstrapDialog.SIZE_SMALL = 'size-small'; 213 | BootstrapDialog.SIZE_WIDE = 'size-wide'; // size-wide is equal to modal-lg 214 | BootstrapDialog.SIZE_LARGE = 'size-large'; 215 | BootstrapDialog.BUTTON_SIZES = {}; 216 | BootstrapDialog.BUTTON_SIZES[BootstrapDialog.SIZE_NORMAL] = ''; 217 | BootstrapDialog.BUTTON_SIZES[BootstrapDialog.SIZE_SMALL] = ''; 218 | BootstrapDialog.BUTTON_SIZES[BootstrapDialog.SIZE_WIDE] = ''; 219 | BootstrapDialog.BUTTON_SIZES[BootstrapDialog.SIZE_LARGE] = 'btn-lg'; 220 | BootstrapDialog.ICON_SPINNER = 'glyphicon glyphicon-asterisk'; 221 | BootstrapDialog.BUTTONS_ORDER_CANCEL_OK = 'btns-order-cancel-ok'; 222 | BootstrapDialog.BUTTONS_ORDER_OK_CANCEL = 'btns-order-ok-cancel'; 223 | 224 | /** 225 | * Default options. 226 | */ 227 | BootstrapDialog.defaultOptions = { 228 | type: BootstrapDialog.TYPE_PRIMARY, 229 | size: BootstrapDialog.SIZE_NORMAL, 230 | cssClass: '', 231 | title: null, 232 | message: null, 233 | nl2br: true, 234 | closable: true, 235 | closeByBackdrop: true, 236 | closeByKeyboard: true, 237 | closeIcon: '×', 238 | spinicon: BootstrapDialog.ICON_SPINNER, 239 | autodestroy: true, 240 | draggable: false, 241 | animate: true, 242 | description: '', 243 | tabindex: -1, 244 | btnsOrder: BootstrapDialog.BUTTONS_ORDER_CANCEL_OK 245 | }; 246 | 247 | /** 248 | * Config default options. 249 | */ 250 | BootstrapDialog.configDefaultOptions = function (options) { 251 | BootstrapDialog.defaultOptions = $.extend(true, BootstrapDialog.defaultOptions, options); 252 | }; 253 | 254 | /** 255 | * Open / Close all created dialogs all at once. 256 | */ 257 | BootstrapDialog.dialogs = {}; 258 | BootstrapDialog.openAll = function () { 259 | $.each(BootstrapDialog.dialogs, function (id, dialogInstance) { 260 | dialogInstance.open(); 261 | }); 262 | }; 263 | BootstrapDialog.closeAll = function () { 264 | $.each(BootstrapDialog.dialogs, function (id, dialogInstance) { 265 | dialogInstance.close(); 266 | }); 267 | }; 268 | 269 | /** 270 | * Get dialog instance by given id. 271 | * 272 | * @returns dialog instance 273 | */ 274 | BootstrapDialog.getDialog = function (id) { 275 | var dialog = null; 276 | if (typeof BootstrapDialog.dialogs[id] !== 'undefined') { 277 | dialog = BootstrapDialog.dialogs[id]; 278 | } 279 | 280 | return dialog; 281 | }; 282 | 283 | /** 284 | * Set a dialog. 285 | * 286 | * @returns the dialog that has just been set. 287 | */ 288 | BootstrapDialog.setDialog = function (dialog) { 289 | BootstrapDialog.dialogs[dialog.getId()] = dialog; 290 | 291 | return dialog; 292 | }; 293 | 294 | /** 295 | * Alias of BootstrapDialog.setDialog(dialog) 296 | * 297 | * @param {type} dialog 298 | * @returns {unresolved} 299 | */ 300 | BootstrapDialog.addDialog = function (dialog) { 301 | return BootstrapDialog.setDialog(dialog); 302 | }; 303 | 304 | /** 305 | * Move focus to next visible dialog. 306 | */ 307 | BootstrapDialog.moveFocus = function () { 308 | var lastDialogInstance = null; 309 | $.each(BootstrapDialog.dialogs, function (id, dialogInstance) { 310 | if (dialogInstance.isRealized() && dialogInstance.isOpened()) { 311 | lastDialogInstance = dialogInstance; 312 | } 313 | }); 314 | if (lastDialogInstance !== null) { 315 | lastDialogInstance.getModal().focus(); 316 | } 317 | }; 318 | 319 | BootstrapDialog.METHODS_TO_OVERRIDE = {}; 320 | BootstrapDialog.METHODS_TO_OVERRIDE['v3.1'] = { 321 | handleModalBackdropEvent: function () { 322 | this.getModal().on('click', {dialog: this}, function (event) { 323 | event.target === this && event.data.dialog.isClosable() && event.data.dialog.canCloseByBackdrop() && event.data.dialog.close(); 324 | }); 325 | 326 | return this; 327 | }, 328 | /** 329 | * To make multiple opened dialogs look better. 330 | * 331 | * Will be removed in later version, after Bootstrap Modal >= 3.3.0, updating z-index is unnecessary. 332 | */ 333 | updateZIndex: function () { 334 | if (this.isOpened()) { 335 | var zIndexBackdrop = 1040; 336 | var zIndexModal = 1050; 337 | var dialogCount = 0; 338 | $.each(BootstrapDialog.dialogs, function (dialogId, dialogInstance) { 339 | if (dialogInstance.isRealized() && dialogInstance.isOpened()) { 340 | dialogCount++; 341 | } 342 | }); 343 | var $modal = this.getModal(); 344 | var $backdrop = $modal.data('bs.modal').$backdrop; 345 | $modal.css('z-index', zIndexModal + (dialogCount - 1) * 20); 346 | $backdrop.css('z-index', zIndexBackdrop + (dialogCount - 1) * 20); 347 | } 348 | 349 | return this; 350 | }, 351 | open: function () { 352 | !this.isRealized() && this.realize(); 353 | this.getModal().modal('show'); 354 | this.updateZIndex(); 355 | 356 | return this; 357 | } 358 | }; 359 | BootstrapDialog.METHODS_TO_OVERRIDE['v3.2'] = { 360 | handleModalBackdropEvent: BootstrapDialog.METHODS_TO_OVERRIDE['v3.1']['handleModalBackdropEvent'], 361 | updateZIndex: BootstrapDialog.METHODS_TO_OVERRIDE['v3.1']['updateZIndex'], 362 | open: BootstrapDialog.METHODS_TO_OVERRIDE['v3.1']['open'] 363 | }; 364 | BootstrapDialog.METHODS_TO_OVERRIDE['v3.3'] = {}; 365 | BootstrapDialog.METHODS_TO_OVERRIDE['v3.3.4'] = $.extend({}, BootstrapDialog.METHODS_TO_OVERRIDE['v3.1']); 366 | BootstrapDialog.prototype = { 367 | constructor: BootstrapDialog, 368 | initOptions: function (options) { 369 | this.options = $.extend(true, this.defaultOptions, options); 370 | 371 | return this; 372 | }, 373 | holdThisInstance: function () { 374 | BootstrapDialog.addDialog(this); 375 | 376 | return this; 377 | }, 378 | initModalStuff: function () { 379 | this.setModal(this.createModal()) 380 | .setModalDialog(this.createModalDialog()) 381 | .setModalContent(this.createModalContent()) 382 | .setModalHeader(this.createModalHeader()) 383 | .setModalBody(this.createModalBody()) 384 | .setModalFooter(this.createModalFooter()); 385 | 386 | this.getModal().append(this.getModalDialog()); 387 | this.getModalDialog().append(this.getModalContent()); 388 | this.getModalContent() 389 | .append(this.getModalHeader()) 390 | .append(this.getModalBody()) 391 | .append(this.getModalFooter()); 392 | 393 | return this; 394 | }, 395 | createModal: function () { 396 | var $modal = $(''); 397 | $modal.prop('id', this.getId()); 398 | $modal.attr('aria-labelledby', this.getId() + '_title'); 399 | 400 | return $modal; 401 | }, 402 | getModal: function () { 403 | return this.$modal; 404 | }, 405 | setModal: function ($modal) { 406 | this.$modal = $modal; 407 | 408 | return this; 409 | }, 410 | createModalDialog: function () { 411 | return $(''); 412 | }, 413 | getModalDialog: function () { 414 | return this.$modalDialog; 415 | }, 416 | setModalDialog: function ($modalDialog) { 417 | this.$modalDialog = $modalDialog; 418 | 419 | return this; 420 | }, 421 | createModalContent: function () { 422 | return $(''); 423 | }, 424 | getModalContent: function () { 425 | return this.$modalContent; 426 | }, 427 | setModalContent: function ($modalContent) { 428 | this.$modalContent = $modalContent; 429 | 430 | return this; 431 | }, 432 | createModalHeader: function () { 433 | return $(''); 434 | }, 435 | getModalHeader: function () { 436 | return this.$modalHeader; 437 | }, 438 | setModalHeader: function ($modalHeader) { 439 | this.$modalHeader = $modalHeader; 440 | 441 | return this; 442 | }, 443 | createModalBody: function () { 444 | return $(''); 445 | }, 446 | getModalBody: function () { 447 | return this.$modalBody; 448 | }, 449 | setModalBody: function ($modalBody) { 450 | this.$modalBody = $modalBody; 451 | 452 | return this; 453 | }, 454 | createModalFooter: function () { 455 | return $(''); 456 | }, 457 | getModalFooter: function () { 458 | return this.$modalFooter; 459 | }, 460 | setModalFooter: function ($modalFooter) { 461 | this.$modalFooter = $modalFooter; 462 | 463 | return this; 464 | }, 465 | createDynamicContent: function (rawContent) { 466 | var content = null; 467 | if (typeof rawContent === 'function') { 468 | content = rawContent.call(rawContent, this); 469 | } else { 470 | content = rawContent; 471 | } 472 | if (typeof content === 'string') { 473 | content = this.formatStringContent(content); 474 | } 475 | 476 | return content; 477 | }, 478 | formatStringContent: function (content) { 479 | if (this.options.nl2br) { 480 | return content.replace(/\r\n/g, '
').replace(/[\r\n]/g, '
'); 481 | } 482 | 483 | return content; 484 | }, 485 | setData: function (key, value) { 486 | this.options.data[key] = value; 487 | 488 | return this; 489 | }, 490 | getData: function (key) { 491 | return this.options.data[key]; 492 | }, 493 | setId: function (id) { 494 | this.options.id = id; 495 | 496 | return this; 497 | }, 498 | getId: function () { 499 | return this.options.id; 500 | }, 501 | getType: function () { 502 | return this.options.type; 503 | }, 504 | setType: function (type) { 505 | this.options.type = type; 506 | this.updateType(); 507 | 508 | return this; 509 | }, 510 | updateType: function () { 511 | if (this.isRealized()) { 512 | var types = [BootstrapDialog.TYPE_DEFAULT, 513 | BootstrapDialog.TYPE_INFO, 514 | BootstrapDialog.TYPE_PRIMARY, 515 | BootstrapDialog.TYPE_SUCCESS, 516 | BootstrapDialog.TYPE_WARNING, 517 | BootstrapDialog.TYPE_DANGER]; 518 | 519 | this.getModal().removeClass(types.join(' ')).addClass(this.getType()); 520 | } 521 | 522 | return this; 523 | }, 524 | getSize: function () { 525 | return this.options.size; 526 | }, 527 | setSize: function (size) { 528 | this.options.size = size; 529 | this.updateSize(); 530 | 531 | return this; 532 | }, 533 | updateSize: function () { 534 | if (this.isRealized()) { 535 | var dialog = this; 536 | 537 | // Dialog size 538 | this.getModal().removeClass(BootstrapDialog.SIZE_NORMAL) 539 | .removeClass(BootstrapDialog.SIZE_SMALL) 540 | .removeClass(BootstrapDialog.SIZE_WIDE) 541 | .removeClass(BootstrapDialog.SIZE_LARGE); 542 | this.getModal().addClass(this.getSize()); 543 | 544 | // Smaller dialog. 545 | this.getModalDialog().removeClass('modal-sm'); 546 | if (this.getSize() === BootstrapDialog.SIZE_SMALL) { 547 | this.getModalDialog().addClass('modal-sm'); 548 | } 549 | 550 | // Wider dialog. 551 | this.getModalDialog().removeClass('modal-lg'); 552 | if (this.getSize() === BootstrapDialog.SIZE_WIDE) { 553 | this.getModalDialog().addClass('modal-lg'); 554 | } 555 | 556 | // Button size 557 | $.each(this.options.buttons, function (index, button) { 558 | var $button = dialog.getButton(button.id); 559 | var buttonSizes = ['btn-lg', 'btn-sm', 'btn-xs']; 560 | var sizeClassSpecified = false; 561 | if (typeof button['cssClass'] === 'string') { 562 | var btnClasses = button['cssClass'].split(' '); 563 | $.each(btnClasses, function (index, btnClass) { 564 | if ($.inArray(btnClass, buttonSizes) !== -1) { 565 | sizeClassSpecified = true; 566 | } 567 | }); 568 | } 569 | if (!sizeClassSpecified) { 570 | $button.removeClass(buttonSizes.join(' ')); 571 | $button.addClass(dialog.getButtonSize()); 572 | } 573 | }); 574 | } 575 | 576 | return this; 577 | }, 578 | getCssClass: function () { 579 | return this.options.cssClass; 580 | }, 581 | setCssClass: function (cssClass) { 582 | this.options.cssClass = cssClass; 583 | 584 | return this; 585 | }, 586 | getTitle: function () { 587 | return this.options.title; 588 | }, 589 | setTitle: function (title) { 590 | this.options.title = title; 591 | this.updateTitle(); 592 | 593 | return this; 594 | }, 595 | updateTitle: function () { 596 | if (this.isRealized()) { 597 | var title = this.getTitle() !== null ? this.createDynamicContent(this.getTitle()) : this.getDefaultText(); 598 | this.getModalHeader().find('.' + this.getNamespace('title')).html('').append(title).prop('id', this.getId() + '_title'); 599 | } 600 | 601 | return this; 602 | }, 603 | getMessage: function () { 604 | return this.options.message; 605 | }, 606 | setMessage: function (message) { 607 | this.options.message = message; 608 | this.updateMessage(); 609 | 610 | return this; 611 | }, 612 | updateMessage: function () { 613 | if (this.isRealized()) { 614 | var message = this.createDynamicContent(this.getMessage()); 615 | this.getModalBody().find('.' + this.getNamespace('message')).html('').append(message); 616 | } 617 | 618 | return this; 619 | }, 620 | isClosable: function () { 621 | return this.options.closable; 622 | }, 623 | setClosable: function (closable) { 624 | this.options.closable = closable; 625 | this.updateClosable(); 626 | 627 | return this; 628 | }, 629 | setCloseByBackdrop: function (closeByBackdrop) { 630 | this.options.closeByBackdrop = closeByBackdrop; 631 | 632 | return this; 633 | }, 634 | canCloseByBackdrop: function () { 635 | return this.options.closeByBackdrop; 636 | }, 637 | setCloseByKeyboard: function (closeByKeyboard) { 638 | this.options.closeByKeyboard = closeByKeyboard; 639 | 640 | return this; 641 | }, 642 | canCloseByKeyboard: function () { 643 | return this.options.closeByKeyboard; 644 | }, 645 | isAnimate: function () { 646 | return this.options.animate; 647 | }, 648 | setAnimate: function (animate) { 649 | this.options.animate = animate; 650 | 651 | return this; 652 | }, 653 | updateAnimate: function () { 654 | if (this.isRealized()) { 655 | this.getModal().toggleClass('fade', this.isAnimate()); 656 | } 657 | 658 | return this; 659 | }, 660 | getSpinicon: function () { 661 | return this.options.spinicon; 662 | }, 663 | setSpinicon: function (spinicon) { 664 | this.options.spinicon = spinicon; 665 | 666 | return this; 667 | }, 668 | addButton: function (button) { 669 | this.options.buttons.push(button); 670 | 671 | return this; 672 | }, 673 | addButtons: function (buttons) { 674 | var that = this; 675 | $.each(buttons, function (index, button) { 676 | that.addButton(button); 677 | }); 678 | 679 | return this; 680 | }, 681 | getButtons: function () { 682 | return this.options.buttons; 683 | }, 684 | setButtons: function (buttons) { 685 | this.options.buttons = buttons; 686 | this.updateButtons(); 687 | 688 | return this; 689 | }, 690 | /** 691 | * If there is id provided for a button option, it will be in dialog.indexedButtons list. 692 | * 693 | * In that case you can use dialog.getButton(id) to find the button. 694 | * 695 | * @param {type} id 696 | * @returns {undefined} 697 | */ 698 | getButton: function (id) { 699 | if (typeof this.indexedButtons[id] !== 'undefined') { 700 | return this.indexedButtons[id]; 701 | } 702 | 703 | return null; 704 | }, 705 | getButtonSize: function () { 706 | if (typeof BootstrapDialog.BUTTON_SIZES[this.getSize()] !== 'undefined') { 707 | return BootstrapDialog.BUTTON_SIZES[this.getSize()]; 708 | } 709 | 710 | return ''; 711 | }, 712 | updateButtons: function () { 713 | if (this.isRealized()) { 714 | if (this.getButtons().length === 0) { 715 | this.getModalFooter().hide(); 716 | } else { 717 | this.getModalFooter().show().find('.' + this.getNamespace('footer')).html('').append(this.createFooterButtons()); 718 | } 719 | } 720 | 721 | return this; 722 | }, 723 | isAutodestroy: function () { 724 | return this.options.autodestroy; 725 | }, 726 | setAutodestroy: function (autodestroy) { 727 | this.options.autodestroy = autodestroy; 728 | }, 729 | getDescription: function () { 730 | return this.options.description; 731 | }, 732 | setDescription: function (description) { 733 | this.options.description = description; 734 | 735 | return this; 736 | }, 737 | setTabindex: function (tabindex) { 738 | this.options.tabindex = tabindex; 739 | 740 | return this; 741 | }, 742 | getTabindex: function () { 743 | return this.options.tabindex; 744 | }, 745 | updateTabindex: function () { 746 | if (this.isRealized()) { 747 | this.getModal().attr('tabindex', this.getTabindex()); 748 | } 749 | 750 | return this; 751 | }, 752 | getDefaultText: function () { 753 | return BootstrapDialog.DEFAULT_TEXTS[this.getType()]; 754 | }, 755 | getNamespace: function (name) { 756 | return BootstrapDialog.NAMESPACE + '-' + name; 757 | }, 758 | createHeaderContent: function () { 759 | var $container = $('
'); 760 | $container.addClass(this.getNamespace('header')); 761 | 762 | // title 763 | $container.append(this.createTitleContent()); 764 | 765 | // Close button 766 | $container.prepend(this.createCloseButton()); 767 | 768 | return $container; 769 | }, 770 | createTitleContent: function () { 771 | var $title = $('
'); 772 | $title.addClass(this.getNamespace('title')); 773 | 774 | return $title; 775 | }, 776 | createCloseButton: function () { 777 | var $container = $('
'); 778 | $container.addClass(this.getNamespace('close-button')); 779 | var $icon = $(''); 780 | $icon.append(this.options.closeIcon); 781 | $container.append($icon); 782 | $container.on('click', {dialog: this}, function (event) { 783 | event.data.dialog.close(); 784 | }); 785 | 786 | return $container; 787 | }, 788 | createBodyContent: function () { 789 | var $container = $('
'); 790 | $container.addClass(this.getNamespace('body')); 791 | 792 | // Message 793 | $container.append(this.createMessageContent()); 794 | 795 | return $container; 796 | }, 797 | createMessageContent: function () { 798 | var $message = $('
'); 799 | $message.addClass(this.getNamespace('message')); 800 | 801 | return $message; 802 | }, 803 | createFooterContent: function () { 804 | var $container = $('
'); 805 | $container.addClass(this.getNamespace('footer')); 806 | 807 | return $container; 808 | }, 809 | createFooterButtons: function () { 810 | var that = this; 811 | var $container = $('
'); 812 | $container.addClass(this.getNamespace('footer-buttons')); 813 | this.indexedButtons = {}; 814 | $.each(this.options.buttons, function (index, button) { 815 | if (!button.id) { 816 | button.id = BootstrapDialog.newGuid(); 817 | } 818 | var $button = that.createButton(button); 819 | that.indexedButtons[button.id] = $button; 820 | $container.append($button); 821 | }); 822 | 823 | return $container; 824 | }, 825 | createButton: function (button) { 826 | var $button = $(''); 827 | $button.prop('id', button.id); 828 | $button.data('button', button); 829 | 830 | // Icon 831 | if (typeof button.icon !== 'undefined' && $.trim(button.icon) !== '') { 832 | $button.append(this.createButtonIcon(button.icon)); 833 | } 834 | 835 | // Label 836 | if (typeof button.label !== 'undefined') { 837 | $button.append(button.label); 838 | } 839 | 840 | // title 841 | if (typeof button.title !== 'undefined') { 842 | $button.attr('title', button.title); 843 | } 844 | 845 | // Css class 846 | if (typeof button.cssClass !== 'undefined' && $.trim(button.cssClass) !== '') { 847 | $button.addClass(button.cssClass); 848 | } else { 849 | $button.addClass('btn-default'); 850 | } 851 | 852 | // Data attributes 853 | if (typeof button.data === 'object' && button.data.constructor === {}.constructor) { 854 | $.each(button.data, function (key, value) { 855 | $button.attr('data-' + key, value); 856 | }); 857 | } 858 | 859 | // Hotkey 860 | if (typeof button.hotkey !== 'undefined') { 861 | this.registeredButtonHotkeys[button.hotkey] = $button; 862 | } 863 | 864 | // Button on click 865 | $button.on('click', {dialog: this, $button: $button, button: button}, function (event) { 866 | var dialog = event.data.dialog; 867 | var $button = event.data.$button; 868 | var button = $button.data('button'); 869 | if (button.autospin) { 870 | $button.toggleSpin(true); 871 | } 872 | if (typeof button.action === 'function') { 873 | return button.action.call($button, dialog, event); 874 | } 875 | }); 876 | 877 | // Dynamically add extra functions to $button 878 | this.enhanceButton($button); 879 | 880 | //Initialize enabled or not 881 | if (typeof button.enabled !== 'undefined') { 882 | $button.toggleEnable(button.enabled); 883 | } 884 | 885 | return $button; 886 | }, 887 | /** 888 | * Dynamically add extra functions to $button 889 | * 890 | * Using '$this' to reference 'this' is just for better readability. 891 | * 892 | * @param {type} $button 893 | * @returns {_L13.BootstrapDialog.prototype} 894 | */ 895 | enhanceButton: function ($button) { 896 | $button.dialog = this; 897 | 898 | // Enable / Disable 899 | $button.toggleEnable = function (enable) { 900 | var $this = this; 901 | if (typeof enable !== 'undefined') { 902 | $this.prop("disabled", !enable).toggleClass('disabled', !enable); 903 | } else { 904 | $this.prop("disabled", !$this.prop("disabled")); 905 | } 906 | 907 | return $this; 908 | }; 909 | $button.enable = function () { 910 | var $this = this; 911 | $this.toggleEnable(true); 912 | 913 | return $this; 914 | }; 915 | $button.disable = function () { 916 | var $this = this; 917 | $this.toggleEnable(false); 918 | 919 | return $this; 920 | }; 921 | 922 | // Icon spinning, helpful for indicating ajax loading status. 923 | $button.toggleSpin = function (spin) { 924 | var $this = this; 925 | var dialog = $this.dialog; 926 | var $icon = $this.find('.' + dialog.getNamespace('button-icon')); 927 | if (typeof spin === 'undefined') { 928 | spin = !($button.find('.icon-spin').length > 0); 929 | } 930 | if (spin) { 931 | $icon.hide(); 932 | $button.prepend(dialog.createButtonIcon(dialog.getSpinicon()).addClass('icon-spin')); 933 | } else { 934 | $icon.show(); 935 | $button.find('.icon-spin').remove(); 936 | } 937 | 938 | return $this; 939 | }; 940 | $button.spin = function () { 941 | var $this = this; 942 | $this.toggleSpin(true); 943 | 944 | return $this; 945 | }; 946 | $button.stopSpin = function () { 947 | var $this = this; 948 | $this.toggleSpin(false); 949 | 950 | return $this; 951 | }; 952 | 953 | return this; 954 | }, 955 | createButtonIcon: function (icon) { 956 | var $icon = $(''); 957 | $icon.addClass(this.getNamespace('button-icon')).addClass(icon); 958 | 959 | return $icon; 960 | }, 961 | /** 962 | * Invoke this only after the dialog is realized. 963 | * 964 | * @param {type} enable 965 | * @returns {undefined} 966 | */ 967 | enableButtons: function (enable) { 968 | $.each(this.indexedButtons, function (id, $button) { 969 | $button.toggleEnable(enable); 970 | }); 971 | 972 | return this; 973 | }, 974 | /** 975 | * Invoke this only after the dialog is realized. 976 | * 977 | * @returns {undefined} 978 | */ 979 | updateClosable: function () { 980 | if (this.isRealized()) { 981 | // Close button 982 | this.getModalHeader().find('.' + this.getNamespace('close-button')).toggle(this.isClosable()); 983 | } 984 | 985 | return this; 986 | }, 987 | /** 988 | * Set handler for modal event 'show.bs.modal'. 989 | * This is a setter! 990 | */ 991 | onShow: function (onshow) { 992 | this.options.onshow = onshow; 993 | 994 | return this; 995 | }, 996 | /** 997 | * Set handler for modal event 'shown.bs.modal'. 998 | * This is a setter! 999 | */ 1000 | onShown: function (onshown) { 1001 | this.options.onshown = onshown; 1002 | 1003 | return this; 1004 | }, 1005 | /** 1006 | * Set handler for modal event 'hide.bs.modal'. 1007 | * This is a setter! 1008 | */ 1009 | onHide: function (onhide) { 1010 | this.options.onhide = onhide; 1011 | 1012 | return this; 1013 | }, 1014 | /** 1015 | * Set handler for modal event 'hidden.bs.modal'. 1016 | * This is a setter! 1017 | */ 1018 | onHidden: function (onhidden) { 1019 | this.options.onhidden = onhidden; 1020 | 1021 | return this; 1022 | }, 1023 | isRealized: function () { 1024 | return this.realized; 1025 | }, 1026 | setRealized: function (realized) { 1027 | this.realized = realized; 1028 | 1029 | return this; 1030 | }, 1031 | isOpened: function () { 1032 | return this.opened; 1033 | }, 1034 | setOpened: function (opened) { 1035 | this.opened = opened; 1036 | 1037 | return this; 1038 | }, 1039 | handleModalEvents: function () { 1040 | this.getModal().on('show.bs.modal', {dialog: this}, function (event) { 1041 | var dialog = event.data.dialog; 1042 | dialog.setOpened(true); 1043 | if (dialog.isModalEvent(event) && typeof dialog.options.onshow === 'function') { 1044 | var openIt = dialog.options.onshow(dialog); 1045 | if (openIt === false) { 1046 | dialog.setOpened(false); 1047 | } 1048 | 1049 | return openIt; 1050 | } 1051 | }); 1052 | this.getModal().on('shown.bs.modal', {dialog: this}, function (event) { 1053 | var dialog = event.data.dialog; 1054 | dialog.isModalEvent(event) && typeof dialog.options.onshown === 'function' && dialog.options.onshown(dialog); 1055 | }); 1056 | this.getModal().on('hide.bs.modal', {dialog: this}, function (event) { 1057 | var dialog = event.data.dialog; 1058 | dialog.setOpened(false); 1059 | if (dialog.isModalEvent(event) && typeof dialog.options.onhide === 'function') { 1060 | var hideIt = dialog.options.onhide(dialog); 1061 | if (hideIt === false) { 1062 | dialog.setOpened(true); 1063 | } 1064 | 1065 | return hideIt; 1066 | } 1067 | }); 1068 | this.getModal().on('hidden.bs.modal', {dialog: this}, function (event) { 1069 | var dialog = event.data.dialog; 1070 | dialog.isModalEvent(event) && typeof dialog.options.onhidden === 'function' && dialog.options.onhidden(dialog); 1071 | if (dialog.isAutodestroy()) { 1072 | dialog.setRealized(false); 1073 | delete BootstrapDialog.dialogs[dialog.getId()]; 1074 | $(this).remove(); 1075 | } 1076 | BootstrapDialog.moveFocus(); 1077 | if ($('.modal').hasClass('in')) { 1078 | $('body').addClass('modal-open'); 1079 | } 1080 | }); 1081 | 1082 | // Backdrop, I did't find a way to change bs3 backdrop option after the dialog is popped up, so here's a new wheel. 1083 | this.handleModalBackdropEvent(); 1084 | 1085 | // ESC key support 1086 | this.getModal().on('keyup', {dialog: this}, function (event) { 1087 | event.which === 27 && event.data.dialog.isClosable() && event.data.dialog.canCloseByKeyboard() && event.data.dialog.close(); 1088 | }); 1089 | 1090 | // Button hotkey 1091 | this.getModal().on('keyup', {dialog: this}, function (event) { 1092 | var dialog = event.data.dialog; 1093 | if (typeof dialog.registeredButtonHotkeys[event.which] !== 'undefined') { 1094 | var $button = $(dialog.registeredButtonHotkeys[event.which]); 1095 | !$button.prop('disabled') && !$button.is(':focus') && $button.focus().trigger('click'); 1096 | } 1097 | }); 1098 | 1099 | return this; 1100 | }, 1101 | handleModalBackdropEvent: function () { 1102 | this.getModal().on('click', {dialog: this}, function (event) { 1103 | $(event.target).hasClass('modal-backdrop') && event.data.dialog.isClosable() && event.data.dialog.canCloseByBackdrop() && event.data.dialog.close(); 1104 | }); 1105 | 1106 | return this; 1107 | }, 1108 | isModalEvent: function (event) { 1109 | return typeof event.namespace !== 'undefined' && event.namespace === 'bs.modal'; 1110 | }, 1111 | makeModalDraggable: function () { 1112 | if (this.options.draggable) { 1113 | this.getModalHeader().addClass(this.getNamespace('draggable')).on('mousedown', {dialog: this}, function (event) { 1114 | var dialog = event.data.dialog; 1115 | dialog.draggableData.isMouseDown = true; 1116 | var dialogOffset = dialog.getModalDialog().offset(); 1117 | dialog.draggableData.mouseOffset = { 1118 | top: event.clientY - dialogOffset.top, 1119 | left: event.clientX - dialogOffset.left 1120 | }; 1121 | }); 1122 | this.getModal().on('mouseup mouseleave', {dialog: this}, function (event) { 1123 | event.data.dialog.draggableData.isMouseDown = false; 1124 | }); 1125 | $('body').on('mousemove', {dialog: this}, function (event) { 1126 | var dialog = event.data.dialog; 1127 | if (!dialog.draggableData.isMouseDown) { 1128 | return; 1129 | } 1130 | dialog.getModalDialog().offset({ 1131 | top: event.clientY - dialog.draggableData.mouseOffset.top, 1132 | left: event.clientX - dialog.draggableData.mouseOffset.left 1133 | }); 1134 | }); 1135 | } 1136 | 1137 | return this; 1138 | }, 1139 | realize: function () { 1140 | this.initModalStuff(); 1141 | this.getModal().addClass(BootstrapDialog.NAMESPACE) 1142 | .addClass(this.getCssClass()); 1143 | this.updateSize(); 1144 | if (this.getDescription()) { 1145 | this.getModal().attr('aria-describedby', this.getDescription()); 1146 | } 1147 | this.getModalFooter().append(this.createFooterContent()); 1148 | this.getModalHeader().append(this.createHeaderContent()); 1149 | this.getModalBody().append(this.createBodyContent()); 1150 | this.getModal().data('bs.modal', new BootstrapDialogModal(this.getModal(), { 1151 | backdrop: 'static', 1152 | keyboard: false, 1153 | show: false 1154 | })); 1155 | this.makeModalDraggable(); 1156 | this.handleModalEvents(); 1157 | this.setRealized(true); 1158 | this.updateButtons(); 1159 | this.updateType(); 1160 | this.updateTitle(); 1161 | this.updateMessage(); 1162 | this.updateClosable(); 1163 | this.updateAnimate(); 1164 | this.updateSize(); 1165 | this.updateTabindex(); 1166 | 1167 | return this; 1168 | }, 1169 | open: function () { 1170 | !this.isRealized() && this.realize(); 1171 | this.getModal().modal('show'); 1172 | 1173 | return this; 1174 | }, 1175 | close: function () { 1176 | !this.isRealized() && this.realize(); 1177 | this.getModal().modal('hide'); 1178 | 1179 | return this; 1180 | } 1181 | }; 1182 | 1183 | // Add compatible methods. 1184 | BootstrapDialog.prototype = $.extend(BootstrapDialog.prototype, BootstrapDialog.METHODS_TO_OVERRIDE[BootstrapDialogModal.getModalVersion()]); 1185 | 1186 | /** 1187 | * RFC4122 version 4 compliant unique id creator. 1188 | * 1189 | * Added by https://github.com/tufanbarisyildirim/ 1190 | * 1191 | * @returns {String} 1192 | */ 1193 | BootstrapDialog.newGuid = function () { 1194 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { 1195 | var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8); 1196 | return v.toString(16); 1197 | }); 1198 | }; 1199 | 1200 | /* ================================================ 1201 | * For lazy people 1202 | * ================================================ */ 1203 | 1204 | /** 1205 | * Shortcut function: show 1206 | * 1207 | * @param {type} options 1208 | * @returns the created dialog instance 1209 | */ 1210 | BootstrapDialog.show = function (options) { 1211 | return new BootstrapDialog(options).open(); 1212 | }; 1213 | 1214 | /** 1215 | * Alert window 1216 | * 1217 | * @returns the created dialog instance 1218 | */ 1219 | BootstrapDialog.alert = function () { 1220 | var alertOptions = {}; 1221 | var defaultAlertOptions = { 1222 | type: BootstrapDialog.TYPE_PRIMARY, 1223 | title: null, 1224 | message: null, 1225 | closable: false, 1226 | draggable: false, 1227 | buttonLabel: BootstrapDialog.DEFAULT_TEXTS.OK, 1228 | buttonHotkey: null, 1229 | callback: null 1230 | }; 1231 | 1232 | if (typeof arguments[0] === 'object' && arguments[0].constructor === {}.constructor) { 1233 | alertOptions = $.extend(true, defaultAlertOptions, arguments[0]); 1234 | } else { 1235 | alertOptions = $.extend(true, defaultAlertOptions, { 1236 | message: arguments[0], 1237 | callback: typeof arguments[1] !== 'undefined' ? arguments[1] : null 1238 | }); 1239 | } 1240 | 1241 | var dialog = new BootstrapDialog(alertOptions); 1242 | dialog.setData('callback', alertOptions.callback); 1243 | dialog.addButton({ 1244 | label: alertOptions.buttonLabel, 1245 | hotkey: alertOptions.buttonHotkey, 1246 | action: function (dialog) { 1247 | if (typeof dialog.getData('callback') === 'function' && dialog.getData('callback').call(this, true) === false) { 1248 | return false; 1249 | } 1250 | dialog.setData('btnClicked', true); 1251 | 1252 | return dialog.close(); 1253 | } 1254 | }); 1255 | if (typeof dialog.options.onhide === 'function') { 1256 | dialog.onHide(function (dialog) { 1257 | var hideIt = true; 1258 | if (!dialog.getData('btnClicked') && dialog.isClosable() && typeof dialog.getData('callback') === 'function') { 1259 | hideIt = dialog.getData('callback')(false); 1260 | } 1261 | if (hideIt === false) { 1262 | return false; 1263 | } 1264 | hideIt = this.onhide(dialog); 1265 | 1266 | return hideIt; 1267 | }.bind({ 1268 | onhide: dialog.options.onhide 1269 | })); 1270 | } else { 1271 | dialog.onHide(function (dialog) { 1272 | var hideIt = true; 1273 | if (!dialog.getData('btnClicked') && dialog.isClosable() && typeof dialog.getData('callback') === 'function') { 1274 | hideIt = dialog.getData('callback')(false); 1275 | } 1276 | 1277 | return hideIt; 1278 | }); 1279 | } 1280 | 1281 | return dialog.open(); 1282 | }; 1283 | 1284 | /** 1285 | * Confirm window 1286 | * 1287 | * @returns the created dialog instance 1288 | */ 1289 | BootstrapDialog.confirm = function () { 1290 | var confirmOptions = {}; 1291 | var defaultConfirmOptions = { 1292 | type: BootstrapDialog.TYPE_PRIMARY, 1293 | title: null, 1294 | message: null, 1295 | closable: false, 1296 | draggable: false, 1297 | btnCancelLabel: BootstrapDialog.DEFAULT_TEXTS.CANCEL, 1298 | btnCancelClass: null, 1299 | btnCancelHotkey: null, 1300 | btnOKLabel: BootstrapDialog.DEFAULT_TEXTS.OK, 1301 | btnOKClass: null, 1302 | btnOKHotkey: null, 1303 | btnsOrder: BootstrapDialog.defaultOptions.btnsOrder, 1304 | callback: null 1305 | }; 1306 | if (typeof arguments[0] === 'object' && arguments[0].constructor === {}.constructor) { 1307 | confirmOptions = $.extend(true, defaultConfirmOptions, arguments[0]); 1308 | } else { 1309 | confirmOptions = $.extend(true, defaultConfirmOptions, { 1310 | message: arguments[0], 1311 | callback: typeof arguments[1] !== 'undefined' ? arguments[1] : null 1312 | }); 1313 | } 1314 | if (confirmOptions.btnOKClass === null) { 1315 | confirmOptions.btnOKClass = ['btn', confirmOptions.type.split('-')[1]].join('-'); 1316 | } 1317 | 1318 | var dialog = new BootstrapDialog(confirmOptions); 1319 | dialog.setData('callback', confirmOptions.callback); 1320 | 1321 | var buttons = [{ 1322 | label: confirmOptions.btnCancelLabel, 1323 | cssClass: confirmOptions.btnCancelClass, 1324 | hotkey: confirmOptions.btnCancelHotkey, 1325 | action: function (dialog) { 1326 | if (typeof dialog.getData('callback') === 'function' && dialog.getData('callback').call(this, false) === false) { 1327 | return false; 1328 | } 1329 | 1330 | return dialog.close(); 1331 | } 1332 | }, { 1333 | label: confirmOptions.btnOKLabel, 1334 | cssClass: confirmOptions.btnOKClass, 1335 | hotkey: confirmOptions.btnOKHotkey, 1336 | action: function (dialog) { 1337 | if (typeof dialog.getData('callback') === 'function' && dialog.getData('callback').call(this, true) === false) { 1338 | return false; 1339 | } 1340 | 1341 | return dialog.close(); 1342 | } 1343 | }]; 1344 | if (confirmOptions.btnsOrder === BootstrapDialog.BUTTONS_ORDER_OK_CANCEL) { 1345 | buttons.reverse(); 1346 | } 1347 | dialog.addButtons(buttons); 1348 | 1349 | return dialog.open(); 1350 | 1351 | }; 1352 | 1353 | /** 1354 | * Warning window 1355 | * 1356 | * @param {type} message 1357 | * @returns the created dialog instance 1358 | */ 1359 | BootstrapDialog.warning = function (message, callback) { 1360 | return new BootstrapDialog({ 1361 | type: BootstrapDialog.TYPE_WARNING, 1362 | message: message 1363 | }).open(); 1364 | }; 1365 | 1366 | /** 1367 | * Danger window 1368 | * 1369 | * @param {type} message 1370 | * @returns the created dialog instance 1371 | */ 1372 | BootstrapDialog.danger = function (message, callback) { 1373 | return new BootstrapDialog({ 1374 | type: BootstrapDialog.TYPE_DANGER, 1375 | message: message 1376 | }).open(); 1377 | }; 1378 | 1379 | /** 1380 | * Success window 1381 | * 1382 | * @param {type} message 1383 | * @returns the created dialog instance 1384 | */ 1385 | BootstrapDialog.success = function (message, callback) { 1386 | return new BootstrapDialog({ 1387 | type: BootstrapDialog.TYPE_SUCCESS, 1388 | message: message 1389 | }).open(); 1390 | }; 1391 | 1392 | return BootstrapDialog; 1393 | 1394 | })); 1395 | -------------------------------------------------------------------------------- /src/less/bootstrap-dialog.less: -------------------------------------------------------------------------------- 1 | .bootstrap-dialog { 2 | 3 | .modal-header { 4 | border-top-left-radius: 4px; 5 | border-top-right-radius: 4px; 6 | } 7 | .bootstrap-dialog-title { 8 | color: #fff; 9 | display: inline-block; 10 | font-size: 16px; 11 | } 12 | .bootstrap-dialog-message { 13 | font-size: 14px; 14 | } 15 | .bootstrap-dialog-button-icon { 16 | margin-right: 3px; 17 | } 18 | .bootstrap-dialog-close-button { 19 | font-size: 20px; 20 | float: right; 21 | .opacity(0.9); 22 | &:hover { 23 | cursor: pointer; 24 | .opacity(1.0); 25 | } 26 | } 27 | 28 | /* dialog types */ 29 | &.type-default { 30 | .modal-header { 31 | background-color: @modal-content-bg; 32 | } 33 | .bootstrap-dialog-title { 34 | color: #333; 35 | } 36 | } 37 | 38 | &.type-info { 39 | .modal-header { 40 | background-color: @brand-info; 41 | } 42 | } 43 | 44 | &.type-primary { 45 | .modal-header { 46 | background-color: @brand-primary; 47 | } 48 | } 49 | 50 | &.type-success { 51 | .modal-header { 52 | background-color: @brand-success; 53 | } 54 | } 55 | 56 | &.type-warning { 57 | .modal-header { 58 | background-color: @brand-warning; 59 | } 60 | } 61 | 62 | &.type-danger { 63 | .modal-header { 64 | background-color: @brand-danger; 65 | } 66 | } 67 | 68 | &.size-large { 69 | .bootstrap-dialog-title { 70 | font-size: 24px; 71 | } 72 | .bootstrap-dialog-close-button { 73 | font-size: 30px; 74 | } 75 | .bootstrap-dialog-message { 76 | font-size: 18px; 77 | } 78 | } 79 | 80 | /** 81 | * Icon animation 82 | * Copied from font-awesome: http://fontawesome.io/ 83 | **/ 84 | .icon-spin { 85 | display: inline-block; 86 | -moz-animation: spin 2s infinite linear; 87 | -o-animation: spin 2s infinite linear; 88 | -webkit-animation: spin 2s infinite linear; 89 | animation: spin 2s infinite linear; 90 | } 91 | @-moz-keyframes spin { 92 | 0% { 93 | -moz-transform: rotate(0deg); 94 | } 95 | 100% { 96 | -moz-transform: rotate(359deg); 97 | } 98 | } 99 | @-webkit-keyframes spin { 100 | 0% { 101 | -webkit-transform: rotate(0deg); 102 | } 103 | 100% { 104 | -webkit-transform: rotate(359deg); 105 | } 106 | } 107 | @-o-keyframes spin { 108 | 0% { 109 | -o-transform: rotate(0deg); 110 | } 111 | 100% { 112 | -o-transform: rotate(359deg); 113 | } 114 | } 115 | @-ms-keyframes spin { 116 | 0% { 117 | -ms-transform: rotate(0deg); 118 | } 119 | 100% { 120 | -ms-transform: rotate(359deg); 121 | } 122 | } 123 | @keyframes spin { 124 | 0% { 125 | transform: rotate(0deg); 126 | } 127 | 100% { 128 | transform: rotate(359deg); 129 | } 130 | } 131 | /** End of icon animation **/ 132 | } 133 | --------------------------------------------------------------------------------