1/* =========================================================== 2 * bootstrap-modalmanager.js v2.2.5 3 * =========================================================== 4 * Copyright 2012 Jordan Schroter. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * ========================================================== */ 18 19!function ($) { 20 21 "use strict"; // jshint ;_; 22 23 /* MODAL MANAGER CLASS DEFINITION 24 * ====================== */ 25 26 var ModalManager = function (element, options) { 27 this.init(element, options); 28 }; 29 30 ModalManager.prototype = { 31 32 constructor: ModalManager, 33 34 init: function (element, options) { 35 this.$element = $(element); 36 this.options = $.extend({}, $.fn.modalmanager.defaults, this.$element.data(), typeof options == 'object' && options); 37 this.stack = []; 38 this.backdropCount = 0; 39 40 if (this.options.resize) { 41 var resizeTimeout, 42 that = this; 43 44 $(window).on('resize.modal', function(){ 45 resizeTimeout && clearTimeout(resizeTimeout); 46 resizeTimeout = setTimeout(function(){ 47 for (var i = 0; i < that.stack.length; i++){ 48 that.stack[i].isShown && that.stack[i].layout(); 49 } 50 }, 10); 51 }); 52 } 53 }, 54 55 createModal: function (element, options) { 56 $(element).modal($.extend({ manager: this }, options)); 57 }, 58 59 appendModal: function (modal) { 60 this.stack.push(modal); 61 62 var that = this; 63 64 modal.$element.on('show.modalmanager', targetIsSelf(function (e) { 65 66 var showModal = function(){ 67 modal.isShown = true; 68 69 var transition = $.support.transition && modal.$element.hasClass('fade'); 70 71 that.$element 72 .toggleClass('modal-open', that.hasOpenModal()) 73 .toggleClass('page-overflow', $(window).height() < that.$element.height()); 74 75 modal.$parent = modal.$element.parent(); 76 77 modal.$container = that.createContainer(modal); 78 79 modal.$element.appendTo(modal.$container); 80 81 that.backdrop(modal, function () { 82 modal.$element.show(); 83 84 if (transition) { 85 //modal.$element[0].style.display = 'run-in'; 86 modal.$element[0].offsetWidth; 87 //modal.$element.one($.support.transition.end, function () { modal.$element[0].style.display = 'block' }); 88 } 89 90 modal.layout(); 91 92 modal.$element 93 .addClass('in') 94 .attr('aria-hidden', false); 95 96 var complete = function () { 97 that.setFocus(); 98 modal.$element.trigger('shown'); 99 }; 100 101 transition ? 102 modal.$element.one($.support.transition.end, complete) : 103 complete(); 104 }); 105 }; 106 107 modal.options.replace ? 108 that.replace(showModal) : 109 showModal(); 110 })); 111 112 modal.$element.on('hidden.modalmanager', targetIsSelf(function (e) { 113 that.backdrop(modal); 114 // handle the case when a modal may have been removed from the dom before this callback executes 115 if (!modal.$element.parent().length) { 116 that.destroyModal(modal); 117 } else if (modal.$backdrop){ 118 var transition = $.support.transition && modal.$element.hasClass('fade'); 119 120 // trigger a relayout due to firebox's buggy transition end event 121 if (transition) { modal.$element[0].offsetWidth; } 122 $.support.transition && modal.$element.hasClass('fade') ? 123 modal.$backdrop.one($.support.transition.end, function () { modal.destroy(); }) : 124 modal.destroy(); 125 } else { 126 modal.destroy(); 127 } 128 129 })); 130 131 modal.$element.on('destroyed.modalmanager', targetIsSelf(function (e) { 132 that.destroyModal(modal); 133 })); 134 }, 135 136 getOpenModals: function () { 137 var openModals = []; 138 for (var i = 0; i < this.stack.length; i++){ 139 if (this.stack[i].isShown) openModals.push(this.stack[i]); 140 } 141 142 return openModals; 143 }, 144 145 hasOpenModal: function () { 146 return this.getOpenModals().length > 0; 147 }, 148 149 setFocus: function () { 150 var topModal; 151 152 for (var i = 0; i < this.stack.length; i++){ 153 if (this.stack[i].isShown) topModal = this.stack[i]; 154 } 155 156 if (!topModal) return; 157 158 topModal.focus(); 159 }, 160 161 destroyModal: function (modal) { 162 modal.$element.off('.modalmanager'); 163 if (modal.$backdrop) this.removeBackdrop(modal); 164 this.stack.splice(this.getIndexOfModal(modal), 1); 165 166 var hasOpenModal = this.hasOpenModal(); 167 168 this.$element.toggleClass('modal-open', hasOpenModal); 169 170 if (!hasOpenModal){ 171 this.$element.removeClass('page-overflow'); 172 } 173 174 this.removeContainer(modal); 175 176 this.setFocus(); 177 }, 178 179 getModalAt: function (index) { 180 return this.stack[index]; 181 }, 182 183 getIndexOfModal: function (modal) { 184 for (var i = 0; i < this.stack.length; i++){ 185 if (modal === this.stack[i]) return i; 186 } 187 }, 188 189 replace: function (callback) { 190 var topModal; 191 192 for (var i = 0; i < this.stack.length; i++){ 193 if (this.stack[i].isShown) topModal = this.stack[i]; 194 } 195 196 if (topModal) { 197 this.$backdropHandle = topModal.$backdrop; 198 topModal.$backdrop = null; 199 200 callback && topModal.$element.one('hidden', 201 targetIsSelf( $.proxy(callback, this) )); 202 203 topModal.hide(); 204 } else if (callback) { 205 callback(); 206 } 207 }, 208 209 removeBackdrop: function (modal) { 210 modal.$backdrop.remove(); 211 modal.$backdrop = null; 212 }, 213 214 createBackdrop: function (animate, tmpl) { 215 var $backdrop; 216 217 if (!this.$backdropHandle) { 218 $backdrop = $(tmpl) 219 .addClass(animate) 220 .appendTo(this.$element); 221 } else { 222 $backdrop = this.$backdropHandle; 223 $backdrop.off('.modalmanager'); 224 this.$backdropHandle = null; 225 this.isLoading && this.removeSpinner(); 226 } 227 228 return $backdrop; 229 }, 230 231 removeContainer: function (modal) { 232 modal.$container.remove(); 233 modal.$container = null; 234 }, 235 236 createContainer: function (modal) { 237 var $container; 238
239 $container = $('<div class="modal-scrollable">') 240 .css('z-index', getzIndex('modal', this.getOpenModals().length)) 241 .appendTo(this.$element); 242 243 if (modal && modal.options.backdrop != 'static') { 244 $container.on('click.modal', targetIsSelf(function (e) { 245 modal.hide(); 246 })); 247 } else if (modal) { 248 $container.on('click.modal', targetIsSelf(function (e) { 249 modal.attention(); 250 })); 251 } 252 253 return $container; 254 255 }, 256 257 backdrop: function (modal, callback) { 258 var animate = modal.$element.hasClass('fade') ? 'fade' : '', 259 showBackdrop = modal.options.backdrop && 260 this.backdropCount < this.options.backdropLimit; 261 262 if (modal.isShown && showBackdrop) { 263 var doAnimate = $.support.transition && animate && !this.$backdropHandle; 264 265 modal.$backdrop = this.createBackdrop(animate, modal.options.backdropTemplate); 266 267 modal.$backdrop.css('z-index', getzIndex( 'backdrop', this.getOpenModals().length )); 268 269 if (doAnimate) modal.$backdrop[0].offsetWidth; // force reflow 270 271 modal.$backdrop.addClass('in'); 272 273 this.backdropCount += 1; 274 275 doAnimate ? 276 modal.$backdrop.one($.support.transition.end, callback) : 277 callback(); 278 279 } else if (!modal.isShown && modal.$backdrop) { 280 modal.$backdrop.removeClass('in'); 281 282 this.backdropCount -= 1; 283 284 var that = this; 285 286 $.support.transition && modal.$element.hasClass('fade')? 287 modal.$backdrop.one($.support.transition.end, function () { that.removeBackdrop(modal) }) : 288 that.removeBackdrop(modal); 289 290 } else if (callback) { 291 callback(); 292 } 293 }, 294 295 removeSpinner: function(){ 296 this.$spinner && this.$spinner.remove(); 297 this.$spinner = null; 298 this.isLoading = false; 299 }, 300 301 removeLoading: function () { 302 this.$backdropHandle && this.$backdropHandle.remove(); 303 this.$backdropHandle = null; 304 this.removeSpinner(); 305 }, 306 307 loading: function (callback) { 308 callback = callback || function () { }; 309 310 this.$element 311 .toggleClass('modal-open', !this.isLoading || this.hasOpenModal()) 312 .toggleClass('page-overflow', $(window).height() < this.$element.height()); 313 314 if (!this.isLoading) { 315 316 this.$backdropHandle = this.createBackdrop('fade', this.options.backdropTemplate); 317 318 this.$backdropHandle[0].offsetWidth; // force reflow 319 320 var openModals = this.getOpenModals(); 321 322 this.$backdropHandle 323 .css('z-index', getzIndex('backdrop', openModals.length + 1)) 324 .addClass('in'); 325 326 var $spinner = $(this.options.spinner) 327 .css('z-index', getzIndex('modal', openModals.length + 1)) 328 .appendTo(this.$element) 329 .addClass('in'); 330 331 this.$spinner = $(this.createContainer()) 332 .append($spinner) 333 .on('click.modalmanager', $.proxy(this.loading, this)); 334 335 this.isLoading = true; 336 337 $.support.transition ? 338 this.$backdropHandle.one($.support.transition.end, callback) : 339 callback(); 340 341 } else if (this.isLoading && this.$backdropHandle) { 342 this.$backdropHandle.removeClass('in'); 343 344 var that = this; 345 $.support.transition ? 346 this.$backdropHandle.one($.support.transition.end, function () { that.removeLoading() }) : 347 that.removeLoading(); 348 349 } else if (callback) { 350 callback(this.isLoading); 351 } 352 } 353 }; 354 355 /* PRIVATE METHODS 356 * ======================= */ 357 358 // computes and caches the zindexes 359 var getzIndex = (function () { 360 var zIndexFactor, 361 baseIndex = {}; 362 363 return function (type, pos) { 364 365 if (typeof zIndexFactor === 'undefined'){ 366 var $baseModal = $('<div class="modal hide" />').appendTo('body'), 367 $baseBackdrop = $('<div class="modal-backdrop hide" />').appendTo('body'); 368 369 baseIndex['modal'] = +$baseModal.css('z-index'); 370 baseIndex['backdrop'] = +$baseBackdrop.css('z-index'); 371 zIndexFactor = baseIndex['modal'] - baseIndex['backdrop']; 372 373 $baseModal.remove(); 374 $baseBackdrop.remove(); 375 $baseBackdrop = $baseModal = null; 376 } 377 378 return baseIndex[type] + (zIndexFactor * pos); 379 380 } 381 }()); 382 383 // make sure the event target is the modal itself in order to prevent 384 // other components such as tabsfrom triggering the modal manager. 385 // if Boostsrap namespaced events, this would not be needed. 386 function targetIsSelf(callback){ 387 return function (e) { 388 if (e && this === e.target){ 389 return callback.apply(this, arguments); 390 } 391 } 392 } 393 394 395 /* MODAL MANAGER PLUGIN DEFINITION 396 * ======================= */ 397 398 $.fn.modalmanager = function (option, args) { 399 return this.each(function () { 400 var $this = $(this), 401 data = $this.data('modalmanager'); 402 403 if (!data) $this.data('modalmanager', (data = new ModalManager(this, option))); 404 if (typeof option === 'string') data[option].apply(data, [].concat(args)) 405 }) 406 }; 407 408 $.fn.modalmanager.defaults = { 409 backdropLimit: 999, 410 resize: true, 411 spinner: '<div class="loading-spinner fade" style="width: 200px; margin-left: -100px;"><div class="progress progress-striped active"><div class="bar" style="width: 100%;"></div></div></div>', 412 backdropTemplate: '<div class="modal-backdrop" />' 413 }; 414 415 $.fn.modalmanager.Constructor = ModalManager 416 417 // ModalManager handles the modal-open class so we need 418 // to remove conflicting bootstrap 3 event handlers 419 $(function () { 420 $(document).off('show.bs.modal').off('hidden.bs.modal'); 421 }); 422 423}(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.