├── .gitignore ├── LICENSE ├── _config.yml ├── demo ├── blank-ajax-response.html └── bootstrap-modal-demo.html ├── dist └── bootstrap-modal-wrapper-factory.min.js ├── gulpfile.js ├── js └── bootstrap-modal-wrapper-factory.js ├── nbproject ├── project.properties └── project.xml ├── package-lock.json ├── package.json └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | # OS or Editor folders 2 | .DS_Store 3 | .idea 4 | npm-debug.log 5 | # Folders to ignore 6 | node_modules 7 | /nbproject/private/ 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 JavaTMP (http://www.javatmp.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /demo/blank-ajax-response.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. Ut wisis enim ad minim veniam, quis nostrud exerci tution ullam corper suscipit lobortis nisi ut aliquip ex ea commodo consequat. Duis te feugi facilisi. Duis autem dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit au gue duis dolore te feugat nulla facilisi.

5 |

Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. Ut wisis enim ad minim veniam, quis nostrud exerci tution ullam corper suscipit lobortis nisi ut aliquip ex ea commodo consequat. Duis te feugi facilisi. Duis autem dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit au gue duis dolore te feugat nulla facilisi.

6 |

Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. Ut wisis enim ad minim veniam, quis nostrud exerci tution ullam corper suscipit lobortis nisi ut aliquip ex ea commodo consequat. Duis te feugi facilisi. Duis autem dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit au gue duis dolore te feugat nulla facilisi.

7 |

Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. Ut wisis enim ad minim veniam, quis nostrud exerci tution ullam corper suscipit lobortis nisi ut aliquip ex ea commodo consequat. Duis te feugi facilisi. Duis autem dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit au gue duis dolore te feugat nulla facilisi.

8 |

Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. Ut wisis enim ad minim veniam, quis nostrud exerci tution ullam corper suscipit lobortis nisi ut aliquip ex ea commodo consequat. Duis te feugi facilisi. Duis autem dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit au gue duis dolore te feugat nulla facilisi.

9 |

Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. Ut wisis enim ad minim veniam, quis nostrud exerci tution ullam corper suscipit lobortis nisi ut aliquip ex ea commodo consequat. Duis te feugi facilisi. Duis autem dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit au gue duis dolore te feugat nulla facilisi.

10 |
11 |
12 | 66 |
-------------------------------------------------------------------------------- /demo/bootstrap-modal-demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Bootstrap Modal Wrapper Plugin Demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |

Bootstrap Modal Wrapper Plugin Demo

16 |

Predefined Modal Types

17 | 20 | 23 | 26 |

Using Generic Modal Factory's createModal method

27 | 30 | 33 | 36 | 39 | 42 | 45 | 48 | 51 | 54 | 55 |

Update Contents on the fly

56 | 59 | 62 | 65 | 68 |

Bootstrap Ajax Content Modal

69 | 72 | 75 | 78 | 81 | 84 | 85 |

Original Bootstrap events

86 | 89 |

Centered Bootstrap Modals

90 | 93 |
94 |
95 |
96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 138 | 708 | 709 | 710 | -------------------------------------------------------------------------------- /dist/bootstrap-modal-wrapper-factory.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * bootstrap-modal-wrapper (http://javatmp.com) 3 | * Bootstrap modal wrapper plugin creates dynamic and nested stacked dialog instances 4 | * 5 | * @version 2.0.2 6 | * @link https://github.com/JavaTMP/bootstrap-modal-wrapper 7 | * @copyright 2018 JavaTMP 8 | * @license MIT 9 | */ 10 | !function(o,t){"use strict";"undefined"!=typeof module&&module.exports?module.exports=t(require("jquery"),require("bootstrap")):"function"==typeof define&&define.amd?define("bootstrap-modal-wrapper-factory",["jquery","bootstrap"],function(o){return t(o)}):o.BootstrapModalWrapperFactory=t(o.jQuery)}(this,function(e){"use strict";var i={starterZIndex:1e4};function o(o){this.options=e.extend({},i,o),this.defaults=i,this.globalModals=[],this.registerGlobalEventsHandler()}o.prototype.createModal=function(o){var t=new l(this,o);return this.globalModals.push(t),t.init(),t},o.prototype.createAjaxModal=function(o){var a=e.extend(!0,{},{sendId:!0,idParameter:"ajaxModalId",updateSizeAfterDataFetchTo:"modal-lg",ajaxContainerReadyEventName:"ajax-container-ready",ajax:{type:"GET",dataType:"html",url:null,data:{},success:function(o,t,i){n.updateSize(a.updateSizeAfterDataFetchTo),n.updateMessage(o),setTimeout(function(){e("#"+n.options.id).trigger(a.ajaxContainerReadyEventName,[n])},0)}}},o),n=this.createModal(a);return n.options.sendId&&(n.options.ajax.data[n.options.idParameter]=n.options.id),n.originalModal.removeClass("fade"),n.originalModal.find(".modal-dialog").css({transition:"all .3s"}),n.originalModal.one("shown.bs.modal",function(o){e.ajax(n.options.ajax)}),n.show(),n};var a="",n="";var s=function(o){return o+"-"+Math.floor(1e8*Math.random()+1)+"-"+(new Date).getTime()+"-"+function(){var o,t,i="";for(o=0;o<32;o++)t=16*Math.random()|0,8!==o&&12!==o&&16!==o&&20!==o||(i+="-"),i+=(12===o?4:16===o?3&t|8:t).toString(16);return i}()};function l(o,t){this.factory=o,this.options=e.extend(!0,{},{id:s("b-m-w"),title:null,message:null,closable:!1,closeByBackdrop:!0,closeByKeyboard:!0,size:null,onDestroy:null,buttons:[],headerClass:null,localData:{},centered:!1,modalDialogScrollable:!0,modalTitleContainer:"",modalButtonContainer:"",modalFooterContainer:""},t),this.originalModal=null,this.isDestroy=!1,this.isOpen=!1}return l.prototype.generateTemplate=function(){this.originalModal=e(""),this.originalModal.attr("id",this.options.id);var o=this.originalModal.find(".modal-dialog");if(!this.options.size||"modal-sm"!==this.options.size&&"modal-lg"!==this.options.size&&"modal-xl"!==this.options.size||o.addClass(this.options.size),!0===this.options.centered&&o.addClass("modal-dialog-centered"),!0===this.options.modalDialogScrollable&&o.addClass("modal-dialog-scrollable"),(this.options.title||this.options.closable)&&this.originalModal.find(".modal-content").append(a),this.options.title&&this.originalModal.find(".modal-header").append(this.options.modalTitleContainer).find(".modal-title").append(this.options.title),this.options.closable&&this.originalModal.find(".modal-header").append(n),this.options.headerClass&&this.originalModal.find(".modal-header").addClass(this.options.headerClass),this.options.message&&(this.originalModal.find(".modal-content").append(""),this.originalModal.find(".modal-body").html("").append(this.options.message)),this.options.buttons&&0 (http://javatmp.com)', 18 | ' * <%= pkg.description %>', 19 | ' *', 20 | ' * @version <%= pkg.version %>', 21 | ' * @link <%= pkg.homepage %>', 22 | ' * @copyright 2018 JavaTMP', 23 | ' * @license <%= pkg.license %>', 24 | ' */', 25 | ''].join('\n'); 26 | 27 | gulp.task('clean', function (cb) { 28 | return del.sync(['./dist'], cb()); 29 | }); 30 | 31 | gulp.task('dist', gulp.series("clean", function (cb) { 32 | return gulp.src('./js/bootstrap-modal-wrapper-factory.js') 33 | .pipe(eslint({ 34 | "env": {"browser": true, "node": true, "jquery": true}, 35 | "rules": { 36 | "semi": 2, 37 | "eqeqeq": 1, 38 | "quotes": 0, 39 | "no-trailing-spaces": 1, 40 | "eol-last": 1, 41 | "no-unused-vars": 0, 42 | "no-underscore-dangle": 0, 43 | "no-alert": 1, 44 | "no-lone-blocks": 1 45 | }, 46 | "globals": ["jQuery", "$"] 47 | })) 48 | .pipe(eslint.format()) 49 | .pipe(uglify({output: {comments: /^!/}})) 50 | .pipe(header(banner, {pkg: pkg})) 51 | .pipe(rename({suffix: '.min'})) 52 | .pipe(gulp.dest('./dist/')) 53 | .on('end', function () { 54 | cb(); 55 | }); 56 | })); 57 | 58 | gulp.task('default', gulp.series("dist", function (cb) { 59 | // place code for your default task here 60 | cb(); 61 | })); 62 | -------------------------------------------------------------------------------- /js/bootstrap-modal-wrapper-factory.js: -------------------------------------------------------------------------------- 1 | (function (root, factory) { 2 | "use strict"; 3 | // CommonJS module is defined 4 | if (typeof module !== "undefined" && module.exports) { 5 | module.exports = factory(require("jquery"), require("bootstrap")); 6 | } 7 | // AMD module is defined 8 | else if (typeof define === "function" && define.amd) { 9 | define("bootstrap-modal-wrapper-factory", ["jquery", "bootstrap"], function ($) { 10 | return factory($); 11 | }); 12 | } else { 13 | // planted over the root! 14 | root.BootstrapModalWrapperFactory = factory(root.jQuery); 15 | } 16 | 17 | }(this, function ($) { 18 | "use strict"; 19 | 20 | var defaults = { 21 | starterZIndex: 10000 22 | }; 23 | 24 | // The actual plugin constructor 25 | function ModalWrapperFactory(options) { 26 | this.options = $.extend({}, defaults, options); 27 | this.defaults = defaults; 28 | this.globalModals = []; 29 | this.registerGlobalEventsHandler(); 30 | } 31 | 32 | ModalWrapperFactory.prototype.createModal = function (options) { 33 | var newModalWrapper = new ModalWrapper(this, options); 34 | this.globalModals.push(newModalWrapper); 35 | newModalWrapper.init(); 36 | return newModalWrapper; 37 | }; 38 | 39 | ModalWrapperFactory.prototype.createAjaxModal = function (options) { 40 | var $this = this; 41 | var settings = $.extend(true, {}, { 42 | sendId: true, 43 | idParameter: "ajaxModalId", 44 | updateSizeAfterDataFetchTo: "modal-lg", 45 | ajaxContainerReadyEventName: "ajax-container-ready", 46 | ajax: { 47 | type: "GET", 48 | dataType: "html", 49 | url: null, 50 | data: {}, 51 | success: function (response, textStatus, jqXHR) { 52 | ajaxModalContainer.updateSize(settings.updateSizeAfterDataFetchTo); 53 | ajaxModalContainer.updateMessage(response); 54 | setTimeout(function () { 55 | $("#" + ajaxModalContainer.options.id).trigger(settings.ajaxContainerReadyEventName, [ajaxModalContainer]); 56 | }, 0); 57 | } 58 | } 59 | }, options); 60 | var ajaxModalContainer = $this.createModal(settings); 61 | if (ajaxModalContainer.options.sendId) { 62 | ajaxModalContainer.options.ajax.data[ajaxModalContainer.options.idParameter] = ajaxModalContainer.options.id; 63 | } 64 | 65 | ajaxModalContainer.originalModal.removeClass("fade"); 66 | ajaxModalContainer.originalModal.find(".modal-dialog").css({transition: 'all .3s'}); 67 | // make sure the dialog is shown before calling AJAX request 68 | ajaxModalContainer.originalModal.one('shown.bs.modal', function (e) { 69 | $.ajax(ajaxModalContainer.options.ajax); 70 | }); 71 | ajaxModalContainer.show(); 72 | 73 | return ajaxModalContainer; 74 | }; 75 | 76 | var modalTemplateContainer = 77 | ""; 83 | var modalHeaderContainer = ""; 84 | var modalHeaderClosableContainer = 85 | ""; 88 | var modalBodyContainer = ""; 89 | 90 | function uuid() { 91 | var uuid = "", i, random; 92 | for (i = 0; i < 32; i++) { 93 | random = Math.random() * 16 | 0; 94 | if (i === 8 || i === 12 || i === 16 || i === 20) { 95 | uuid += "-"; 96 | } 97 | uuid += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random)).toString(16); 98 | } 99 | return uuid; 100 | } 101 | var getUniqueID = function (prefix) { 102 | return prefix + "-" + Math.floor((Math.random() * 100000000) + 1) + "-" + new Date().getTime() + "-" + uuid(); 103 | }; 104 | function ModalWrapper(factory, options) { 105 | this.factory = factory; 106 | this.options = $.extend(true, {}, { 107 | id: getUniqueID("b-m-w"), 108 | title: null, 109 | message: null, 110 | closable: false, 111 | closeByBackdrop: true, 112 | closeByKeyboard: true, 113 | size: null, 114 | onDestroy: null, 115 | buttons: [], 116 | headerClass: null, 117 | localData: {}, 118 | centered: false, 119 | modalDialogScrollable: true, 120 | modalTitleContainer: "", 121 | modalButtonContainer: "", 122 | modalFooterContainer: "" 123 | }, options); 124 | 125 | // $.extend(true, this.options.localData, options.localData); 126 | 127 | this.originalModal = null; 128 | this.isDestroy = false; 129 | this.isOpen = false; 130 | } 131 | 132 | ModalWrapper.prototype.generateTemplate = function () { 133 | 134 | this.originalModal = $(modalTemplateContainer); 135 | 136 | this.originalModal.attr("id", this.options.id); 137 | var $dialog = this.originalModal.find(".modal-dialog"); 138 | if (this.options.size && (this.options.size === "modal-sm" || this.options.size === "modal-lg" || this.options.size === "modal-xl")) { 139 | $dialog.addClass(this.options.size); 140 | } 141 | if (this.options.centered === true) { 142 | $dialog.addClass('modal-dialog-centered'); 143 | } 144 | if (this.options.modalDialogScrollable === true) { 145 | $dialog.addClass('modal-dialog-scrollable'); 146 | } 147 | 148 | if (this.options.title || this.options.closable) { 149 | this.originalModal.find(".modal-content").append(modalHeaderContainer); 150 | } 151 | if (this.options.title) { 152 | this.originalModal.find(".modal-header").append(this.options.modalTitleContainer).find(".modal-title").append(this.options.title); 153 | } 154 | if (this.options.closable) { 155 | this.originalModal.find(".modal-header").append(modalHeaderClosableContainer); 156 | } 157 | 158 | if (this.options.headerClass) { 159 | this.originalModal.find(".modal-header").addClass(this.options.headerClass); 160 | } 161 | 162 | if (this.options.message) { 163 | this.originalModal.find(".modal-content").append(modalBodyContainer); 164 | this.originalModal.find(".modal-body").html('').append(this.options.message); 165 | } 166 | if (this.options.buttons && this.options.buttons.length > 0) { 167 | this.originalModal.find(".modal-content").append(this.options.modalFooterContainer); 168 | for (var i = 0; i < this.options.buttons.length; i++) { 169 | var buttonData = this.options.buttons[i]; 170 | this.addButton(buttonData, false); 171 | } 172 | } 173 | }; 174 | ModalWrapper.prototype.init = function () { 175 | this.generateTemplate(); 176 | var $this = this; 177 | this.originalModal.on("show.bs.modal", function (event) { 178 | // YOU SHOULD STOP PROPAGATION because we register too for global modals. 179 | event.stopPropagation(); 180 | var zIndex = $this.factory.defaults.starterZIndex + (10 * $(".modal.show").length); 181 | $(this).css("z-index", zIndex); 182 | setTimeout(function () { 183 | $(".modal-backdrop").not(".modal-stack").first().css("z-index", zIndex - 1).addClass("modal-stack"); 184 | }, 0); 185 | }).on("shown.bs.modal", function (event) { 186 | $this.isOpen = true; 187 | }).on("hide.bs.modal", function (event) { 188 | if ($this.options.onDestroy && (typeof $this.options.onDestroy === "function")) { 189 | if (!$this.options.onDestroy.call($this, $this)) { 190 | event.preventDefault(); 191 | } 192 | } 193 | }).on("hidden.bs.modal", function (event) { 194 | // YOU SHOULD STOP PROPAGATION because we register too for global modals. 195 | event.stopPropagation(); 196 | $this.destroy(); 197 | $(".modal.show").length && $("body").addClass("modal-open"); 198 | }); 199 | }; 200 | ModalWrapper.prototype.destroy = function () { 201 | var $this = this; 202 | this.originalModal.modal("hide").promise().done(function () { 203 | $this.isOpen = false; 204 | $("#" + $this.options.id).off("show.bs.modal"); 205 | $("#" + $this.options.id).off("hidden.bs.modal"); 206 | $("#" + $this.options.id).modal("dispose"); 207 | for (var i = 0; i < $this.options.buttons.length; i++) { 208 | var button = $this.options.buttons[i]; 209 | button.buttonObject.off(); 210 | } 211 | 212 | $this.isDestroy = true; 213 | var i = $this.factory.globalModals.length; 214 | while (i--) { 215 | if ($this.factory.globalModals[i].options.id === $this.options.id) { 216 | $this.factory.globalModals.splice(i, 1); 217 | break; 218 | } 219 | } 220 | $("#" + $this.options.id).find(".modal-dialog").off(); 221 | $("#" + $this.options.id).off(); 222 | $("#" + $this.options.id).remove(); 223 | }); 224 | }; 225 | 226 | ModalWrapper.prototype.show = function () { 227 | var currentOptions = { 228 | show: true, 229 | backdrop: this.options.closeByBackdrop ? true : "static", 230 | keyboard: this.options.closeByKeyboard, 231 | focus: true 232 | }; 233 | this.originalModal.modal(currentOptions); 234 | return this; 235 | }; 236 | ModalWrapper.prototype.hide = function () { 237 | this.originalModal.modal("hide"); 238 | }; 239 | 240 | ModalWrapper.prototype.updateTitle = function (newTitle) { 241 | this.options.title = newTitle; 242 | var titleElement = this.originalModal.find(".modal-title"); 243 | if (titleElement.length === 0) { 244 | var headerElement = this.originalModal.find(".modal-header"); 245 | if (headerElement.length === 0) { 246 | this.originalModal.find(".modal-content").prepend(modalHeaderContainer); 247 | headerElement = this.originalModal.find(".modal-header"); 248 | } 249 | headerElement.prepend(this.options.modalTitleContainer); 250 | titleElement = this.originalModal.find(".modal-title"); 251 | } 252 | titleElement.html(newTitle); 253 | this.originalModal.modal("handleUpdate"); 254 | return this; 255 | }; 256 | ModalWrapper.prototype.updateClosable = function (newClosable) { 257 | if (this.options.closable !== newClosable) { 258 | this.options.closable = newClosable; 259 | // if closable is true , we should show the x button on top right. 260 | // else we should remove button and check if title exist or not if exist 261 | // then we do nothing but if not exist we remove header to. 262 | if (this.options.closable === true) { 263 | var headerElement = this.originalModal.find(".modal-header"); 264 | if (headerElement.length === 0) { 265 | this.originalModal.find(".modal-content").prepend(modalHeaderContainer); 266 | headerElement = this.originalModal.find(".modal-header"); 267 | } 268 | headerElement.append(modalHeaderClosableContainer); 269 | } else if (this.options.closable === false) { 270 | var closableElement = this.originalModal.find(".modal-header").find("button.close"); 271 | closableElement.off(); 272 | closableElement.remove(); 273 | var modalTitleElement = this.originalModal.find(".modal-header").find(".modal-title"); 274 | if (modalTitleElement.length === 0) { 275 | this.originalModal.find(".modal-header").remove(); 276 | } 277 | 278 | } 279 | this.originalModal.modal("handleUpdate"); 280 | } 281 | return this; 282 | }; 283 | ModalWrapper.prototype.updateClosableByBackdrop = function (newClosableByBackdropValue) { 284 | if (this.options.closeByBackdrop !== newClosableByBackdropValue) { 285 | this.options.closeByBackdrop = newClosableByBackdropValue; 286 | $("#" + this.options.id).data('bs.modal')._config.backdrop = this.options.closeByBackdrop ? true : "static"; 287 | this.originalModal.modal("handleUpdate"); 288 | } 289 | return this; 290 | }; 291 | ModalWrapper.prototype.removeHeader = function () { 292 | var headerElement = this.originalModal.find(".modal-header"); 293 | if (headerElement.length > 0) { 294 | var closeButton = headerElement.find("button.close"); 295 | if (closeButton.length > 0) { 296 | closeButton.off(); 297 | closeButton.remove(); 298 | this.options.closable = false; 299 | } 300 | headerElement.remove(); 301 | this.options.title = null; 302 | } 303 | this.originalModal.modal("handleUpdate"); 304 | return this; 305 | }; 306 | ModalWrapper.prototype.updateMessage = function (newMessage) { 307 | this.options.message = newMessage; 308 | var bodyElement = this.originalModal.find(".modal-body"); 309 | bodyElement.html("").html(newMessage); 310 | this.originalModal.modal("handleUpdate"); 311 | return this; 312 | }; 313 | ModalWrapper.prototype.updateSize = function (newSize) { 314 | if (this.options.size !== newSize) { 315 | this.options.size = newSize; 316 | if (!this.options.size || (typeof this.options.size === "undefined") || this.options.size === null) { 317 | this.originalModal.find(".modal-dialog").removeClass("modal-xl modal-lg modal-sm"); 318 | } else if (this.options.size === "modal-sm" || this.options.size === "modal-lg" || this.options.size === "modal-xl") { 319 | this.originalModal.find(".modal-dialog").removeClass("modal-xl modal-lg modal-sm"); 320 | this.originalModal.find(".modal-dialog").addClass(this.options.size); 321 | } 322 | this.originalModal.modal("handleUpdate"); 323 | } 324 | return this; 325 | }; 326 | ModalWrapper.prototype.updateModalDialogScrollable = function (modalDialogScrollable) { 327 | if (this.options.modalDialogScrollable !== modalDialogScrollable) { 328 | this.options.modalDialogScrollable = modalDialogScrollable; 329 | var modalDialog = this.originalModal.find(".modal-dialog"); 330 | if (this.options.modalDialogScrollable === true) { 331 | modalDialog.addClass("modal-dialog-scrollable"); 332 | } else if (this.options.modalDialogScrollable === false) { 333 | modalDialog.removeClass("modal-dialog-scrollable"); 334 | } 335 | this.originalModal.modal("handleUpdate"); 336 | } 337 | return this; 338 | }; 339 | ModalWrapper.prototype.disableButtons = function () { 340 | var footerElement = this.originalModal.find(".modal-footer"); 341 | footerElement.find('button').prop('disabled', true); 342 | }; 343 | ModalWrapper.prototype.enableButtons = function () { 344 | var footerElement = this.originalModal.find(".modal-footer"); 345 | footerElement.find('button').prop('disabled', false); 346 | }; 347 | ModalWrapper.prototype.addButton = function (buttonData, updateOptions) { 348 | var modalWrapperInstance = this; 349 | var footerElement = this.originalModal.find(".modal-footer"); 350 | if (footerElement.length === 0) { 351 | this.originalModal.find(".modal-content").append(this.options.modalFooterContainer); 352 | footerElement = this.originalModal.find(".modal-footer"); 353 | } 354 | buttonData.id = buttonData.id ? buttonData.id : getUniqueID("modal-button"); 355 | var buttonHtml = buttonData.template ? buttonData.template : modalWrapperInstance.options.modalButtonContainer; 356 | var button = $(buttonHtml); 357 | button.attr("id", buttonData.id); 358 | button.addClass(buttonData.cssClass ? buttonData.cssClass : ""); 359 | button.append(buttonData.label); 360 | buttonData.buttonObject = button; 361 | button.on("click", {modalWrapper: modalWrapperInstance, button: button, buttonData: buttonData}, function (event) { 362 | var modalWrapper = event.data.modalWrapper; 363 | var button = event.data.button; 364 | var buttonData = event.data.buttonData; 365 | if (buttonData.action && (typeof buttonData.action === "function")) { 366 | return buttonData.action.call(modalWrapper, button, buttonData, event); 367 | } 368 | }); 369 | if (updateOptions !== false) { 370 | this.options.buttons.push(buttonData); 371 | } 372 | 373 | return button.appendTo(footerElement); 374 | }; 375 | 376 | ModalWrapper.prototype.setOnDestroy = function (onDestroyFunc) { 377 | // if (onDestroyFunc && (typeof onDestroyFunc === "function")) { 378 | // this.options.onDestroy = onDestroyFunc; 379 | // } 380 | this.options.onDestroy = onDestroyFunc; 381 | }; 382 | ModalWrapper.prototype.removeButton = function (buttonId) { 383 | // var modalWrapperInstance = this; 384 | // check if the button id exist 385 | var requestedButton = null; 386 | var i = this.options.buttons.length; 387 | while (i--) { 388 | if (this.options.buttons[i].id === buttonId) { 389 | var requestedButton = this.options.buttons[i]; 390 | requestedButton.buttonObject.off(); 391 | requestedButton.buttonObject.remove(); 392 | this.options.buttons.splice(i, 1); 393 | } 394 | } 395 | return this; 396 | }; 397 | 398 | ModalWrapperFactory.prototype.showMessage = function (options) { 399 | var showOptions = null; 400 | if (typeof options === "object" && options.constructor === {}.constructor) { 401 | showOptions = $.extend(true, defaults, options); 402 | } else { 403 | showOptions = $.extend(true, defaults, {message: options}); 404 | } 405 | 406 | return this.createModal(showOptions).show(); 407 | }; 408 | ModalWrapperFactory.prototype.alert = function (options) { 409 | var defaults = { 410 | title: "Alert", 411 | message: "", 412 | closable: true, 413 | closeByBackdrop: true, 414 | closeByKeyboard: true, 415 | buttons: [ 416 | { 417 | label: "OK", 418 | cssClass: "btn btn-primary", 419 | action: function (button, buttonData, originalEvent) { 420 | this.hide(); 421 | } 422 | } 423 | ] 424 | }; 425 | var alertOptions = null; 426 | if (typeof options === "object" && options.constructor === {}.constructor) { 427 | alertOptions = $.extend(true, defaults, options); 428 | } else { 429 | alertOptions = $.extend(true, defaults, {message: options}); 430 | } 431 | return this.createModal(alertOptions).show(); 432 | }; 433 | ModalWrapperFactory.prototype.confirm = function (options) { 434 | var defaults = { 435 | title: "Confirm", 436 | message: "Are You Sure ?", 437 | closable: false, 438 | closeByBackdrop: false, 439 | closeByKeyboard: false, 440 | buttons: [ 441 | { 442 | label: "No", 443 | cssClass: "btn btn-secondary", 444 | action: function (button, buttonData, originalEvent) { 445 | this.hide(); 446 | if (options.onConfirmCancel && (typeof options.onConfirmCancel === "function")) { 447 | options.onConfirmCancel(); 448 | } 449 | } 450 | }, 451 | { 452 | label: "Yes", 453 | cssClass: "btn btn-primary", 454 | action: function (button, buttonData, originalEvent) { 455 | this.hide(); 456 | if (options.onConfirmAccept && (typeof options.onConfirmAccept === "function")) { 457 | options.onConfirmAccept(); 458 | } 459 | } 460 | } 461 | ] 462 | }; 463 | var confirmOptions = $.extend({}, defaults, options); 464 | return this.createModal(confirmOptions).show(); 465 | }; 466 | 467 | ModalWrapperFactory.prototype.registerGlobalEventsHandler = function () { 468 | // some bootstrap plugins like summernote have problem when run inside a bootstrap modals 469 | // as native bootstrap modal does support nested modal so we should handle the z-index of those plugins' modals 470 | // too in the same way we handle the modal wrapper instaces 471 | var $this = this; 472 | $(document).on("show.bs.modal", '.modal', function (event) { 473 | var zIndex = $this.options.starterZIndex + (10 * $(".modal.show").length); 474 | $(this).css("z-index", zIndex); 475 | setTimeout(function () { 476 | $(".modal-backdrop").not(".modal-stack").first().css("z-index", zIndex - 1).addClass("modal-stack"); 477 | }, 0); 478 | }).on("hidden.bs.modal", '.modal', function (event) { 479 | $(".modal.show").length && $("body").addClass("modal-open"); 480 | }).on('inserted.bs.tooltip', function (event) { 481 | var zIndex = $this.options.starterZIndex + (10 * $(".modal.show").length); 482 | var tooltipId = $(event.target).attr("aria-describedby"); 483 | $("#" + tooltipId).css("z-index", zIndex); 484 | }).on('inserted.bs.popover', function (event) { 485 | var zIndex = $this.options.starterZIndex + (10 * $(".modal.show").length); 486 | var popoverId = $(event.target).attr("aria-describedby"); 487 | $("#" + popoverId).css("z-index", zIndex); 488 | }); 489 | 490 | }; 491 | 492 | return new ModalWrapperFactory(); 493 | })); 494 | -------------------------------------------------------------------------------- /nbproject/project.properties: -------------------------------------------------------------------------------- 1 | auxiliary.org-netbeans-modules-javascript-nodejs.run_2e_enabled=false 2 | browser.autorefresh.Chrome=true 3 | browser.highlightselection.Chrome=true 4 | browser.run=true 5 | file.reference.bootstrap-modal-wrapper-public_html=public_html 6 | file.reference.bootstrap-modal-wrapper-test=test 7 | file.reference.NetBeansProjects-bootstrap-modal-wrapper=. 8 | files.encoding=UTF-8 9 | site.root.folder=${file.reference.NetBeansProjects-bootstrap-modal-wrapper} 10 | start.file=demo/bootstrap-modal-demo.html 11 | web.context.root=/bootstrap-modal-wrapper 12 | -------------------------------------------------------------------------------- /nbproject/project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.netbeans.modules.web.clientproject 4 | 5 | 6 | bootstrap-modal-wrapper 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap-modal-wrapper", 3 | "version": "2.0.2", 4 | "description": "Bootstrap modal wrapper plugin creates dynamic and nested stacked dialog instances", 5 | "keywords": [ 6 | "bootstrap", 7 | "modal", 8 | "dialog", 9 | "bootstrap modal", 10 | "bootstrap dialog" 11 | ], 12 | "author": "javatmp", 13 | "license": "MIT", 14 | "bugs": { 15 | "url": "https://github.com/JavaTMP/bootstrap-modal-wrapper/issues" 16 | }, 17 | "homepage": "https://github.com/JavaTMP/bootstrap-modal-wrapper", 18 | "devDependencies": { 19 | "del": "^5.0.0", 20 | "gulp": "^4.0.2", 21 | "gulp-eslint": "^6.0.0", 22 | "gulp-header": "^2.0.7", 23 | "gulp-rename": "^1.4.0", 24 | "gulp-uglify": "^3.0.1" 25 | }, 26 | "dependencies": { 27 | "bootstrap": "^4.2.1", 28 | "jquery": "^3.4.1", 29 | "popper.js": "^1.14.6" 30 | }, 31 | "scripts": {}, 32 | "repository": { 33 | "type": "git", 34 | "url": "https://github.com/JavaTMP/bootstrap-modal-wrapper.git" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Bootstrap Modal Wrapper 2 | Bootstrap modal wrapper factory for creating dynamic and nested stacked dialog instances. 3 | 4 | [![](https://data.jsdelivr.com/v1/package/npm/bootstrap-modal-wrapper/badge)](https://www.jsdelivr.com/package/npm/bootstrap-modal-wrapper) 5 | 6 | ## Installation Using NPM 7 | ``` 8 | npm install bootstrap-modal-wrapper 9 | ``` 10 | 11 | ## Building from The source 12 | Make sure node.js and git client are locally installed on your machine and then run the following commands: 13 | ``` 14 | cd bootstrap-modal-wrapper 15 | npm install 16 | gulp 17 | ``` 18 | ## Demo And Examples 19 | Online demo of all below examples can be found in the following JavaTMP demo pages: 20 | - [Bootstrap Modal Online Demo](http://java.javatmp.com/#/pages/static/plugins/bootstrap-modal-wrapper). 21 | 22 | ### BOOTSTRAP MESSAGE MODAL 23 | The simplest scenario of modal wrapper is to show a simple message when use press a button: 24 | ```html 25 | 28 | 35 | ``` 36 | 37 | ### BOOTSTRAP ALERT MODAL 38 | The simple scenario of modal wrapper is to show a simple alert when use press a button: 39 | ```html 40 | 43 | 50 | ``` 51 | 52 | ### BOOTSTRAP CONFIRMATION MODAL 53 | JavaTMP Bootstrap modal wrapper factory provides a confirmation dialog too with ability to run different code. 54 | See the following example: 55 | ```html 56 | 59 | 75 | ``` 76 | ### JAVATMP BOOTSTRAP MODAL WRAPPER `CREATEMODAL` METHOD 77 | The JavaTMP Bootstrap Modal wrapper object provides a general method `createModal` which creates modals dynamically. 78 | the implementation of `BootstrapModalWrapperFactory.alert` and `BootstrapModalWrapperFactory.confirm` methods use `createModal` 79 | to provide desired behaviors. 80 | The following examples show you how to use `createModal` method in action: 81 | #### Create simple Bootstrap Modal wrapper instance dynamically 82 | ```JS 83 | var onlyBody = BootstrapModalWrapperFactory.createModal({ 84 | message: "Simple Message body", 85 | closable: false, 86 | closeByBackdrop: true 87 | }); 88 | onlyBody.show(); 89 | ``` 90 | #### Create a simple bootstrap modal wrapper with body and title only: 91 | ```JS 92 | var modalWrapper = BootstrapModalWrapperFactory.createModal({ 93 | message: "Simple Message body", 94 | title: "Header Title", 95 | closable: true, 96 | closeByBackdrop: true 97 | }); 98 | modalWrapper.show(); 99 | ``` 100 | #### Create a simple bootstrap modal wrapper with a button to close and destroy it 101 | ```JS 102 | var modalWrapper = BootstrapModalWrapperFactory.createModal({ 103 | message: "Simple Message body", 104 | title: "Header Title", 105 | closable: false, 106 | closeByBackdrop: false, 107 | buttons: [ 108 | { 109 | label: "Close Me", 110 | cssClass: "btn btn-primary", 111 | action: function (button, buttonData, originalEvent) { 112 | return this.hide(); 113 | } 114 | } 115 | ] 116 | }); 117 | modalWrapper.show(); 118 | ``` 119 | #### Create nested bootstrap modal wrapper instances dynamically: 120 | ```JS 121 | var modalWrapper = BootstrapModalWrapperFactory.createModal({ 122 | message: "Simple Message body", 123 | title: "Header Title", 124 | closable: false, 125 | closeByBackdrop: false, 126 | buttons: [ 127 | { 128 | label: "Close", 129 | cssClass: "btn btn-secondary", 130 | action: function (button, buttonData, originalEvent) { 131 | return this.hide(); 132 | } 133 | }, 134 | { 135 | label: "Create alert", 136 | cssClass: "btn btn-primary", 137 | action: function (button, buttonData, originalEvent) { 138 | BootstrapModalWrapperFactory.alert("Alert Modal Created"); 139 | } 140 | } 141 | ] 142 | }).show(); 143 | ``` 144 | #### Update title and body of bootstrap modal wrapper dynamically after showing: 145 | ```JS 146 | BootstrapModalWrapperFactory.createModal({ 147 | message: "Simple Message body", 148 | title: "Header Title", 149 | closable: false, 150 | closeByBackdrop: false, 151 | buttons: [ 152 | { 153 | label: "Close", 154 | cssClass: "btn btn-secondary", 155 | action: function (button, buttonData, originalEvent) { 156 | return this.hide(); 157 | } 158 | }, 159 | { 160 | label: "Update Title & Message", 161 | cssClass: "btn btn-primary", 162 | action: function (button, buttonData, originalEvent) { 163 | this.updateTitle("New Title"); 164 | this.updateMessage("Updated message content"); 165 | } 166 | } 167 | ] 168 | }).show(); 169 | ``` 170 | #### Update the size of shown bootstrap modal dynamically: 171 | ```JS 172 | BootstrapModalWrapperFactory.createModal({ 173 | message: "Simple Message body", 174 | title: "Header Title", 175 | closable: false, 176 | closeByBackdrop: false, 177 | buttons: [ 178 | { 179 | label: "Close", 180 | cssClass: "btn btn-secondary", 181 | action: function (button, buttonData, originalEvent) { 182 | return this.hide(); 183 | } 184 | }, 185 | { 186 | label: "Make Me Large", 187 | cssClass: "btn btn-primary", 188 | action: function (button, buttonData, originalEvent) { 189 | this.originalModal.find(".modal-dialog").css({transition: 'all 0.4s'}); 190 | this.updateSize("modal-lg"); 191 | } 192 | }, 193 | { 194 | label: "Make Me Small", 195 | cssClass: "btn btn-primary", 196 | action: function (button, buttonData, originalEvent) { 197 | this.originalModal.find(".modal-dialog").css({transition: 'all 0.4s'}); 198 | this.updateSize("modal-sm"); 199 | } 200 | }, 201 | { 202 | label: "Make Me Default", 203 | cssClass: "btn btn-primary", 204 | action: function (button, buttonData, originalEvent) { 205 | this.originalModal.find(".modal-dialog").css({transition: 'all 0.4s'}); 206 | this.updateSize(null); 207 | } 208 | } 209 | ] 210 | }).show(); 211 | ``` 212 | #### Create Bootstrap Modal wrapper buttons dynamically and remove them: 213 | ```JS 214 | var buttonsCount = 0; 215 | BootstrapModalWrapperFactory.createModal({ 216 | message: "Simple Message body", 217 | title: "Header Title", 218 | closable: false, 219 | closeByBackdrop: false, 220 | buttons: [ 221 | { 222 | label: "Close", 223 | cssClass: "btn btn-secondary", 224 | action: function (button, buttonData, originalEvent) { 225 | return this.hide(); 226 | } 227 | }, 228 | { 229 | label: "Add Button", 230 | cssClass: "btn btn-primary", 231 | action: function (button, buttonData, originalEvent) { 232 | this.addButton({ 233 | id: "id-" + (++buttonsCount), 234 | label: "New " + buttonsCount, 235 | cssClass: "btn btn-secondary", 236 | action: function (button, buttonData, originalEvent) { 237 | BootstrapModalWrapperFactory.showMessage("nothing only to show attached event to button id [" + buttonData.id + "]"); 238 | return true; 239 | } 240 | }); 241 | } 242 | }, 243 | { 244 | label: "Delete Button", 245 | cssClass: "btn btn-primary", 246 | action: function (button, buttonData, originalEvent) { 247 | this.removeButton("id-" + (buttonsCount--)); 248 | } 249 | } 250 | ] 251 | }).show(); 252 | ``` 253 | #### Simulate Updating Bootstrap Modal wrapper instace dynamically with AJAX response content: 254 | ```JS 255 | var m = BootstrapModalWrapperFactory.createModal({ 256 | message: '
', 257 | closable: false, 258 | closeByBackdrop: false 259 | }); 260 | m.originalModal.find(".modal-dialog").css({transition: 'all 0.5s'}); 261 | m.show(); 262 | setTimeout(function () { 263 | m.updateSize("modal-lg"); 264 | m.updateTitle("Message Received"); 265 | m.updateMessage("Message Content"); 266 | m.addButton({ 267 | label: "Close", 268 | cssClass: "btn btn-secondary", 269 | action: function (button, buttonData, originalEvent) { 270 | return this.hide(); 271 | } 272 | }); 273 | }, 3000); 274 | ``` 275 | #### Advanced AJAX Bootstrap Modal Wrapper Contents 276 | You can simply adapt and use the bootstrap modal wrapper to provide a dynamic Bootstrap modal with remote AJAX contents 277 | using `createAjaxModal` method, For example: 278 | ```JS 279 | BootstrapModalWrapperFactory.createAjaxModal({ 280 | message: '
Loading
', 281 | closable: true, 282 | title: "AJAX Content", 283 | closeByBackdrop: false, 284 | localData: {}, 285 | ajax: { // all jquery.ajax parameters are supported. 286 | url: "", 287 | data: {} 288 | }, 289 | ajaxContainerReadyEventName: "event-name-triggered-once-ajax-content-updated" 290 | }); 291 | ``` 292 | 293 | And the following are the response HTML code from the above URL: 294 | ```HTML 295 |
296 |
297 |
298 |

Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat. Ut wisis enim ad minim veniam, quis nostrud exerci tution ullam corper suscipit lobortis nisi ut aliquip ex ea commodo consequat. Duis te feugi facilisi. Duis autem dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit au gue duis dolore te feugat nulla facilisi.

299 |
300 |
301 | 354 |
355 | ``` 356 | 357 | ## Copyright and License 358 | Bootstrap-modal-wrapper is copyrighted by [JavaTMP](http://www.javatmp.com) and 359 | licensed under [MIT license](https://github.com/JavaTMP/bootstrap-modal-wrapper/blob/master/LICENSE). 360 | --------------------------------------------------------------------------------