1 /* ========================================================================
2 * Bootstrap: modal.js v3.3.7
3 * http://getbootstrap.com/javascript/#modals
4 * ========================================================================
5 * Copyright 2011-2016 Twitter, Inc.
6 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
7 * ======================================================================== */
13 // MODAL CLASS DEFINITION
14 // ======================
16 var Modal = function (element, options) {
17 this.options = options
18 this.$body = $(document.body)
19 this.$element = $(element)
20 this.$dialog = this.$element.find('.modal-dialog')
23 this.originalBodyPad = null
24 this.scrollbarWidth = 0
25 this.ignoreBackdropClick = false
27 if (this.options.remote) {
29 .find('.modal-content')
30 .load(this.options.remote, $.proxy(function () {
31 this.$element.trigger('loaded.bs.modal')
36 Modal.VERSION = '3.3.7'
38 Modal.TRANSITION_DURATION = 300
39 Modal.BACKDROP_TRANSITION_DURATION = 150
47 Modal.prototype.toggle = function (_relatedTarget) {
48 return this.isShown ? this.hide() : this.show(_relatedTarget)
51 Modal.prototype.show = function (_relatedTarget) {
53 var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
55 this.$element.trigger(e)
57 if (this.isShown || e.isDefaultPrevented()) return
63 this.$body.addClass('modal-open')
68 this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
70 this.$dialog.on('mousedown.dismiss.bs.modal', function () {
71 that.$element.one('mouseup.dismiss.bs.modal', function (e) {
72 if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
76 this.backdrop(function () {
77 var transition = $.support.transition && that.$element.hasClass('fade')
79 if (!that.$element.parent().length) {
80 that.$element.appendTo(that.$body) // don't move modals dom position
90 that.$element[0].offsetWidth // force reflow
93 that.$element.addClass('in')
97 var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
100 that.$dialog // wait for modal to slide in
101 .one('bsTransitionEnd', function () {
102 that.$element.trigger('focus').trigger(e)
104 .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
105 that.$element.trigger('focus').trigger(e)
109 Modal.prototype.hide = function (e) {
110 if (e) e.preventDefault()
112 e = $.Event('hide.bs.modal')
114 this.$element.trigger(e)
116 if (!this.isShown || e.isDefaultPrevented()) return
123 $(document).off('focusin.bs.modal')
127 .off('click.dismiss.bs.modal')
128 .off('mouseup.dismiss.bs.modal')
130 this.$dialog.off('mousedown.dismiss.bs.modal')
132 $.support.transition && this.$element.hasClass('fade') ?
134 .one('bsTransitionEnd', $.proxy(this.hideModal, this))
135 .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
139 Modal.prototype.enforceFocus = function () {
141 .off('focusin.bs.modal') // guard against infinite focus loop
142 .on('focusin.bs.modal', $.proxy(function (e) {
143 if (document !== e.target &&
144 this.$element[0] !== e.target &&
145 !this.$element.has(e.target).length) {
146 this.$element.trigger('focus')
151 Modal.prototype.escape = function () {
152 if (this.isShown && this.options.keyboard) {
153 this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
154 e.which == 27 && this.hide()
156 } else if (!this.isShown) {
157 this.$element.off('keydown.dismiss.bs.modal')
161 Modal.prototype.resize = function () {
163 $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
165 $(window).off('resize.bs.modal')
169 Modal.prototype.hideModal = function () {
172 this.backdrop(function () {
173 that.$body.removeClass('modal-open')
174 that.resetAdjustments()
175 that.resetScrollbar()
176 that.$element.trigger('hidden.bs.modal')
180 Modal.prototype.removeBackdrop = function () {
181 this.$backdrop && this.$backdrop.remove()
182 this.$backdrop = null
185 Modal.prototype.backdrop = function (callback) {
187 var animate = this.$element.hasClass('fade') ? 'fade' : ''
189 if (this.isShown && this.options.backdrop) {
190 var doAnimate = $.support.transition && animate
192 this.$backdrop = $(document.createElement('div'))
193 .addClass('modal-backdrop ' + animate)
194 .appendTo(this.$body)
196 this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
197 if (this.ignoreBackdropClick) {
198 this.ignoreBackdropClick = false
201 if (e.target !== e.currentTarget) return
202 this.options.backdrop == 'static'
203 ? this.$element[0].focus()
207 if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
209 this.$backdrop.addClass('in')
211 if (!callback) return
215 .one('bsTransitionEnd', callback)
216 .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
219 } else if (!this.isShown && this.$backdrop) {
220 this.$backdrop.removeClass('in')
222 var callbackRemove = function () {
223 that.removeBackdrop()
224 callback && callback()
226 $.support.transition && this.$element.hasClass('fade') ?
228 .one('bsTransitionEnd', callbackRemove)
229 .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
232 } else if (callback) {
237 // these following methods are used to handle overflowing modals
239 Modal.prototype.handleUpdate = function () {
243 Modal.prototype.adjustDialog = function () {
244 var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
247 paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
248 paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
252 Modal.prototype.resetAdjustments = function () {
259 Modal.prototype.checkScrollbar = function () {
260 var fullWindowWidth = window.innerWidth
261 if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
262 var documentElementRect = document.documentElement.getBoundingClientRect()
263 fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
265 this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
266 this.scrollbarWidth = this.measureScrollbar()
269 Modal.prototype.setScrollbar = function () {
270 var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
271 this.originalBodyPad = document.body.style.paddingRight || ''
272 if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
275 Modal.prototype.resetScrollbar = function () {
276 this.$body.css('padding-right', this.originalBodyPad)
279 Modal.prototype.measureScrollbar = function () { // thx walsh
280 var scrollDiv = document.createElement('div')
281 scrollDiv.className = 'modal-scrollbar-measure'
282 this.$body.append(scrollDiv)
283 var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
284 this.$body[0].removeChild(scrollDiv)
285 return scrollbarWidth
289 // MODAL PLUGIN DEFINITION
290 // =======================
292 function Plugin(option, _relatedTarget) {
293 return this.each(function () {
295 var data = $this.data('bs.modal')
296 var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
298 if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
299 if (typeof option == 'string') data[option](_relatedTarget)
300 else if (options.show) data.show(_relatedTarget)
307 $.fn.modal.Constructor = Modal
313 $.fn.modal.noConflict = function () {
322 $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
324 var href = $this.attr('href')
325 var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
326 var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
328 if ($this.is('a')) e.preventDefault()
330 $target.one('show.bs.modal', function (showEvent) {
331 if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
332 $target.one('hidden.bs.modal', function () {
333 $this.is(':visible') && $this.trigger('focus')
336 Plugin.call($target, option, this)