1 /* ========================================================================
2 * Bootstrap: modal.js v3.3.4
3 * http://getbootstrap.com/javascript/#modals
4 * ========================================================================
5 * Copyright 2011-2015 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.4'
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
95 .attr('aria-hidden', false)
99 var e
= $.Event('shown.bs.modal', { relatedTarget
: _relatedTarget
})
102 that
.$dialog
// wait for modal to slide in
103 .one('bsTransitionEnd', function () {
104 that
.$element
.trigger('focus').trigger(e
)
106 .emulateTransitionEnd(Modal
.TRANSITION_DURATION
) :
107 that
.$element
.trigger('focus').trigger(e
)
111 Modal
.prototype.hide = function (e
) {
112 if (e
) e
.preventDefault()
114 e
= $.Event('hide.bs.modal')
116 this.$element
.trigger(e
)
118 if (!this.isShown
|| e
.isDefaultPrevented()) return
125 $(document
).off('focusin.bs.modal')
129 .attr('aria-hidden', true)
130 .off('click.dismiss.bs.modal')
131 .off('mouseup.dismiss.bs.modal')
133 this.$dialog
.off('mousedown.dismiss.bs.modal')
135 $.support
.transition
&& this.$element
.hasClass('fade') ?
137 .one('bsTransitionEnd', $.proxy(this.hideModal
, this))
138 .emulateTransitionEnd(Modal
.TRANSITION_DURATION
) :
142 Modal
.prototype.enforceFocus = function () {
144 .off('focusin.bs.modal') // guard against infinite focus loop
145 .on('focusin.bs.modal', $.proxy(function (e
) {
146 if (this.$element
[0] !== e
.target
&& !this.$element
.has(e
.target
).length
) {
147 this.$element
.trigger('focus')
152 Modal
.prototype.escape = function () {
153 if (this.isShown
&& this.options
.keyboard
) {
154 this.$element
.on('keydown.dismiss.bs.modal', $.proxy(function (e
) {
155 e
.which
== 27 && this.hide()
157 } else if (!this.isShown
) {
158 this.$element
.off('keydown.dismiss.bs.modal')
162 Modal
.prototype.resize = function () {
164 $(window
).on('resize.bs.modal', $.proxy(this.handleUpdate
, this))
166 $(window
).off('resize.bs.modal')
170 Modal
.prototype.hideModal = function () {
173 this.backdrop(function () {
174 that
.$body
.removeClass('modal-open')
175 that
.resetAdjustments()
176 that
.resetScrollbar()
177 that
.$element
.trigger('hidden.bs.modal')
181 Modal
.prototype.removeBackdrop = function () {
182 this.$backdrop
&& this.$backdrop
.remove()
183 this.$backdrop
= null
186 Modal
.prototype.backdrop = function (callback
) {
188 var animate
= this.$element
.hasClass('fade') ? 'fade' : ''
190 if (this.isShown
&& this.options
.backdrop
) {
191 var doAnimate
= $.support
.transition
&& animate
193 this.$backdrop
= $('<div class="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)