modal.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. /* ========================================================================
  2. * Bootstrap: modal.js v3.3.1
  3. * http://getbootstrap.com/javascript/#modals
  4. * ========================================================================
  5. * Copyright 2011-2014 Twitter, Inc.
  6. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
  7. * ======================================================================== */
  8. /*
  9. modified by Felix Jan-2014
  10. - change $body to $container
  11. - add this.$container = $(options.container || document.body)
  12. */
  13. +function ($) {
  14. 'use strict';
  15. // MODAL CLASS DEFINITION
  16. // ======================
  17. var Modal = function (element, options) {
  18. this.options = options
  19. this.$container = $(options.container || document.body)
  20. this.$element = $(element)
  21. this.$backdrop =
  22. this.isShown = null
  23. this.scrollbarWidth = 0
  24. if (this.options.remote) {
  25. this.$element
  26. .find('.modal-content')
  27. .load(this.options.remote, $.proxy(function () {
  28. this.$element.trigger('loaded.bs.modal')
  29. }, this))
  30. }
  31. }
  32. Modal.VERSION = '3.3.1'
  33. Modal.TRANSITION_DURATION = 300
  34. Modal.BACKDROP_TRANSITION_DURATION = 150
  35. Modal.DEFAULTS = {
  36. backdrop: true,
  37. keyboard: true,
  38. show: true
  39. }
  40. Modal.prototype.toggle = function (_relatedTarget) {
  41. return this.isShown ? this.hide() : this.show(_relatedTarget)
  42. }
  43. Modal.prototype.show = function (_relatedTarget) {
  44. var that = this
  45. var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
  46. this.$element.trigger(e)
  47. if (this.isShown || e.isDefaultPrevented()) return
  48. this.isShown = true
  49. this.checkScrollbar()
  50. this.setScrollbar()
  51. this.$container.addClass('modal-open')
  52. this.escape()
  53. this.resize()
  54. this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
  55. this.backdrop(function () {
  56. var transition = $.support.transition && that.$element.hasClass('fade')
  57. if (!that.$element.parent().length) {
  58. that.$element.appendTo(that.$container) // don't move modals dom position
  59. }
  60. that.$element
  61. .show()
  62. .scrollTop(0)
  63. if (that.options.backdrop) that.adjustBackdrop()
  64. that.adjustDialog()
  65. if (transition) {
  66. that.$element[0].offsetWidth // force reflow
  67. }
  68. that.$element
  69. .addClass('in')
  70. .attr('aria-hidden', false)
  71. that.enforceFocus()
  72. var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
  73. transition ?
  74. that.$element.find('.modal-dialog') // wait for modal to slide in
  75. .one('bsTransitionEnd', function () {
  76. that.$element.trigger('focus').trigger(e)
  77. })
  78. .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
  79. that.$element.trigger('focus').trigger(e)
  80. })
  81. }
  82. Modal.prototype.hide = function (e) {
  83. if (e) e.preventDefault()
  84. e = $.Event('hide.bs.modal')
  85. this.$element.trigger(e)
  86. if (!this.isShown || e.isDefaultPrevented()) return
  87. this.isShown = false
  88. this.escape()
  89. this.resize()
  90. $(document).off('focusin.bs.modal')
  91. this.$element
  92. .removeClass('in')
  93. .attr('aria-hidden', true)
  94. .off('click.dismiss.bs.modal')
  95. $.support.transition && this.$element.hasClass('fade') ?
  96. this.$element
  97. .one('bsTransitionEnd', $.proxy(this.hideModal, this))
  98. .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
  99. this.hideModal()
  100. }
  101. Modal.prototype.enforceFocus = function () {
  102. $(document)
  103. .off('focusin.bs.modal') // guard against infinite focus loop
  104. .on('focusin.bs.modal', $.proxy(function (e) {
  105. if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
  106. this.$element.trigger('focus')
  107. }
  108. }, this))
  109. }
  110. Modal.prototype.escape = function () {
  111. if (this.isShown && this.options.keyboard) {
  112. this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
  113. e.which == 27 && this.hide()
  114. }, this))
  115. } else if (!this.isShown) {
  116. this.$element.off('keydown.dismiss.bs.modal')
  117. }
  118. }
  119. Modal.prototype.resize = function () {
  120. if (this.isShown) {
  121. $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
  122. } else {
  123. $(window).off('resize.bs.modal')
  124. }
  125. }
  126. Modal.prototype.hideModal = function () {
  127. var that = this
  128. this.$element.hide()
  129. this.backdrop(function () {
  130. that.$container.removeClass('modal-open')
  131. that.resetAdjustments()
  132. that.resetScrollbar()
  133. that.$element.trigger('hidden.bs.modal')
  134. })
  135. }
  136. Modal.prototype.removeBackdrop = function () {
  137. this.$backdrop && this.$backdrop.remove()
  138. this.$backdrop = null
  139. }
  140. Modal.prototype.backdrop = function (callback) {
  141. var that = this
  142. var animate = this.$element.hasClass('fade') ? 'fade' : ''
  143. if (this.isShown && this.options.backdrop) {
  144. var doAnimate = $.support.transition && animate
  145. this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
  146. .prependTo(this.$element)
  147. .on('click.dismiss.bs.modal', $.proxy(function (e) {
  148. if (e.target !== e.currentTarget) return
  149. this.options.backdrop == 'static'
  150. ? this.$element[0].focus.call(this.$element[0])
  151. : this.hide.call(this)
  152. }, this))
  153. if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
  154. this.$backdrop.addClass('in')
  155. if (!callback) return
  156. doAnimate ?
  157. this.$backdrop
  158. .one('bsTransitionEnd', callback)
  159. .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
  160. callback()
  161. } else if (!this.isShown && this.$backdrop) {
  162. this.$backdrop.removeClass('in')
  163. var callbackRemove = function () {
  164. that.removeBackdrop()
  165. callback && callback()
  166. }
  167. $.support.transition && this.$element.hasClass('fade') ?
  168. this.$backdrop
  169. .one('bsTransitionEnd', callbackRemove)
  170. .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
  171. callbackRemove()
  172. } else if (callback) {
  173. callback()
  174. }
  175. }
  176. // these following methods are used to handle overflowing modals
  177. Modal.prototype.handleUpdate = function () {
  178. if (this.options.backdrop) this.adjustBackdrop()
  179. this.adjustDialog()
  180. }
  181. Modal.prototype.adjustBackdrop = function () {
  182. this.$backdrop
  183. .css('height', 0)
  184. .css('height', this.$element[0].scrollHeight)
  185. }
  186. Modal.prototype.adjustDialog = function () {
  187. var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
  188. this.$element.css({
  189. paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
  190. paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
  191. })
  192. }
  193. Modal.prototype.resetAdjustments = function () {
  194. this.$element.css({
  195. paddingLeft: '',
  196. paddingRight: ''
  197. })
  198. }
  199. Modal.prototype.checkScrollbar = function () {
  200. this.bodyIsOverflowing = document.body.scrollHeight > document.documentElement.clientHeight
  201. this.scrollbarWidth = this.measureScrollbar()
  202. }
  203. Modal.prototype.setScrollbar = function () {
  204. var bodyPad = parseInt((this.$container.css('padding-right') || 0), 10)
  205. if (this.bodyIsOverflowing) this.$container.css('padding-right', bodyPad + this.scrollbarWidth)
  206. }
  207. Modal.prototype.resetScrollbar = function () {
  208. this.$container.css('padding-right', '')
  209. }
  210. Modal.prototype.measureScrollbar = function () { // thx walsh
  211. var scrollDiv = document.createElement('div')
  212. scrollDiv.className = 'modal-scrollbar-measure'
  213. this.$container.append(scrollDiv)
  214. var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
  215. this.$container[0].removeChild(scrollDiv)
  216. return scrollbarWidth
  217. }
  218. // MODAL PLUGIN DEFINITION
  219. // =======================
  220. function Plugin(option, _relatedTarget) {
  221. return this.each(function () {
  222. var $this = $(this)
  223. var data = $this.data('bs.modal')
  224. var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
  225. if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
  226. if (typeof option == 'string') data[option](_relatedTarget)
  227. else if (options.show) data.show(_relatedTarget)
  228. })
  229. }
  230. var old = $.fn.modal
  231. $.fn.modal = Plugin
  232. $.fn.modal.Constructor = Modal
  233. // MODAL NO CONFLICT
  234. // =================
  235. $.fn.modal.noConflict = function () {
  236. $.fn.modal = old
  237. return this
  238. }
  239. // MODAL DATA-API
  240. // ==============
  241. $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
  242. var $this = $(this)
  243. var href = $this.attr('href')
  244. var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
  245. var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
  246. if ($this.is('a')) e.preventDefault()
  247. $target.one('show.bs.modal', function (showEvent) {
  248. if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
  249. $target.one('hidden.bs.modal', function () {
  250. $this.is(':visible') && $this.trigger('focus')
  251. })
  252. })
  253. Plugin.call($target, option, this)
  254. })
  255. }(jQuery);