assets/javascripts/bootstrap/modal.js
changeset 114 af15590802a4
equal deleted inserted replaced
113:d4ec02c51c91 114:af15590802a4
       
     1 /* ========================================================================
       
     2  * Bootstrap: modal.js v3.3.5
       
     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  * ======================================================================== */
       
     8 
       
     9 
       
    10 +function ($) {
       
    11   'use strict';
       
    12 
       
    13   // MODAL CLASS DEFINITION
       
    14   // ======================
       
    15 
       
    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')
       
    21     this.$backdrop           = null
       
    22     this.isShown             = null
       
    23     this.originalBodyPad     = null
       
    24     this.scrollbarWidth      = 0
       
    25     this.ignoreBackdropClick = false
       
    26 
       
    27     if (this.options.remote) {
       
    28       this.$element
       
    29         .find('.modal-content')
       
    30         .load(this.options.remote, $.proxy(function () {
       
    31           this.$element.trigger('loaded.bs.modal')
       
    32         }, this))
       
    33     }
       
    34   }
       
    35 
       
    36   Modal.VERSION  = '3.3.5'
       
    37 
       
    38   Modal.TRANSITION_DURATION = 300
       
    39   Modal.BACKDROP_TRANSITION_DURATION = 150
       
    40 
       
    41   Modal.DEFAULTS = {
       
    42     backdrop: true,
       
    43     keyboard: true,
       
    44     show: true
       
    45   }
       
    46 
       
    47   Modal.prototype.toggle = function (_relatedTarget) {
       
    48     return this.isShown ? this.hide() : this.show(_relatedTarget)
       
    49   }
       
    50 
       
    51   Modal.prototype.show = function (_relatedTarget) {
       
    52     var that = this
       
    53     var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
       
    54 
       
    55     this.$element.trigger(e)
       
    56 
       
    57     if (this.isShown || e.isDefaultPrevented()) return
       
    58 
       
    59     this.isShown = true
       
    60 
       
    61     this.checkScrollbar()
       
    62     this.setScrollbar()
       
    63     this.$body.addClass('modal-open')
       
    64 
       
    65     this.escape()
       
    66     this.resize()
       
    67 
       
    68     this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
       
    69 
       
    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
       
    73       })
       
    74     })
       
    75 
       
    76     this.backdrop(function () {
       
    77       var transition = $.support.transition && that.$element.hasClass('fade')
       
    78 
       
    79       if (!that.$element.parent().length) {
       
    80         that.$element.appendTo(that.$body) // don't move modals dom position
       
    81       }
       
    82 
       
    83       that.$element
       
    84         .show()
       
    85         .scrollTop(0)
       
    86 
       
    87       that.adjustDialog()
       
    88 
       
    89       if (transition) {
       
    90         that.$element[0].offsetWidth // force reflow
       
    91       }
       
    92 
       
    93       that.$element.addClass('in')
       
    94 
       
    95       that.enforceFocus()
       
    96 
       
    97       var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
       
    98 
       
    99       transition ?
       
   100         that.$dialog // wait for modal to slide in
       
   101           .one('bsTransitionEnd', function () {
       
   102             that.$element.trigger('focus').trigger(e)
       
   103           })
       
   104           .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
       
   105         that.$element.trigger('focus').trigger(e)
       
   106     })
       
   107   }
       
   108 
       
   109   Modal.prototype.hide = function (e) {
       
   110     if (e) e.preventDefault()
       
   111 
       
   112     e = $.Event('hide.bs.modal')
       
   113 
       
   114     this.$element.trigger(e)
       
   115 
       
   116     if (!this.isShown || e.isDefaultPrevented()) return
       
   117 
       
   118     this.isShown = false
       
   119 
       
   120     this.escape()
       
   121     this.resize()
       
   122 
       
   123     $(document).off('focusin.bs.modal')
       
   124 
       
   125     this.$element
       
   126       .removeClass('in')
       
   127       .off('click.dismiss.bs.modal')
       
   128       .off('mouseup.dismiss.bs.modal')
       
   129 
       
   130     this.$dialog.off('mousedown.dismiss.bs.modal')
       
   131 
       
   132     $.support.transition && this.$element.hasClass('fade') ?
       
   133       this.$element
       
   134         .one('bsTransitionEnd', $.proxy(this.hideModal, this))
       
   135         .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
       
   136       this.hideModal()
       
   137   }
       
   138 
       
   139   Modal.prototype.enforceFocus = function () {
       
   140     $(document)
       
   141       .off('focusin.bs.modal') // guard against infinite focus loop
       
   142       .on('focusin.bs.modal', $.proxy(function (e) {
       
   143         if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
       
   144           this.$element.trigger('focus')
       
   145         }
       
   146       }, this))
       
   147   }
       
   148 
       
   149   Modal.prototype.escape = function () {
       
   150     if (this.isShown && this.options.keyboard) {
       
   151       this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
       
   152         e.which == 27 && this.hide()
       
   153       }, this))
       
   154     } else if (!this.isShown) {
       
   155       this.$element.off('keydown.dismiss.bs.modal')
       
   156     }
       
   157   }
       
   158 
       
   159   Modal.prototype.resize = function () {
       
   160     if (this.isShown) {
       
   161       $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
       
   162     } else {
       
   163       $(window).off('resize.bs.modal')
       
   164     }
       
   165   }
       
   166 
       
   167   Modal.prototype.hideModal = function () {
       
   168     var that = this
       
   169     this.$element.hide()
       
   170     this.backdrop(function () {
       
   171       that.$body.removeClass('modal-open')
       
   172       that.resetAdjustments()
       
   173       that.resetScrollbar()
       
   174       that.$element.trigger('hidden.bs.modal')
       
   175     })
       
   176   }
       
   177 
       
   178   Modal.prototype.removeBackdrop = function () {
       
   179     this.$backdrop && this.$backdrop.remove()
       
   180     this.$backdrop = null
       
   181   }
       
   182 
       
   183   Modal.prototype.backdrop = function (callback) {
       
   184     var that = this
       
   185     var animate = this.$element.hasClass('fade') ? 'fade' : ''
       
   186 
       
   187     if (this.isShown && this.options.backdrop) {
       
   188       var doAnimate = $.support.transition && animate
       
   189 
       
   190       this.$backdrop = $(document.createElement('div'))
       
   191         .addClass('modal-backdrop ' + animate)
       
   192         .appendTo(this.$body)
       
   193 
       
   194       this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
       
   195         if (this.ignoreBackdropClick) {
       
   196           this.ignoreBackdropClick = false
       
   197           return
       
   198         }
       
   199         if (e.target !== e.currentTarget) return
       
   200         this.options.backdrop == 'static'
       
   201           ? this.$element[0].focus()
       
   202           : this.hide()
       
   203       }, this))
       
   204 
       
   205       if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
       
   206 
       
   207       this.$backdrop.addClass('in')
       
   208 
       
   209       if (!callback) return
       
   210 
       
   211       doAnimate ?
       
   212         this.$backdrop
       
   213           .one('bsTransitionEnd', callback)
       
   214           .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
       
   215         callback()
       
   216 
       
   217     } else if (!this.isShown && this.$backdrop) {
       
   218       this.$backdrop.removeClass('in')
       
   219 
       
   220       var callbackRemove = function () {
       
   221         that.removeBackdrop()
       
   222         callback && callback()
       
   223       }
       
   224       $.support.transition && this.$element.hasClass('fade') ?
       
   225         this.$backdrop
       
   226           .one('bsTransitionEnd', callbackRemove)
       
   227           .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
       
   228         callbackRemove()
       
   229 
       
   230     } else if (callback) {
       
   231       callback()
       
   232     }
       
   233   }
       
   234 
       
   235   // these following methods are used to handle overflowing modals
       
   236 
       
   237   Modal.prototype.handleUpdate = function () {
       
   238     this.adjustDialog()
       
   239   }
       
   240 
       
   241   Modal.prototype.adjustDialog = function () {
       
   242     var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
       
   243 
       
   244     this.$element.css({
       
   245       paddingLeft:  !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
       
   246       paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
       
   247     })
       
   248   }
       
   249 
       
   250   Modal.prototype.resetAdjustments = function () {
       
   251     this.$element.css({
       
   252       paddingLeft: '',
       
   253       paddingRight: ''
       
   254     })
       
   255   }
       
   256 
       
   257   Modal.prototype.checkScrollbar = function () {
       
   258     var fullWindowWidth = window.innerWidth
       
   259     if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
       
   260       var documentElementRect = document.documentElement.getBoundingClientRect()
       
   261       fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
       
   262     }
       
   263     this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
       
   264     this.scrollbarWidth = this.measureScrollbar()
       
   265   }
       
   266 
       
   267   Modal.prototype.setScrollbar = function () {
       
   268     var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
       
   269     this.originalBodyPad = document.body.style.paddingRight || ''
       
   270     if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
       
   271   }
       
   272 
       
   273   Modal.prototype.resetScrollbar = function () {
       
   274     this.$body.css('padding-right', this.originalBodyPad)
       
   275   }
       
   276 
       
   277   Modal.prototype.measureScrollbar = function () { // thx walsh
       
   278     var scrollDiv = document.createElement('div')
       
   279     scrollDiv.className = 'modal-scrollbar-measure'
       
   280     this.$body.append(scrollDiv)
       
   281     var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
       
   282     this.$body[0].removeChild(scrollDiv)
       
   283     return scrollbarWidth
       
   284   }
       
   285 
       
   286 
       
   287   // MODAL PLUGIN DEFINITION
       
   288   // =======================
       
   289 
       
   290   function Plugin(option, _relatedTarget) {
       
   291     return this.each(function () {
       
   292       var $this   = $(this)
       
   293       var data    = $this.data('bs.modal')
       
   294       var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
       
   295 
       
   296       if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
       
   297       if (typeof option == 'string') data[option](_relatedTarget)
       
   298       else if (options.show) data.show(_relatedTarget)
       
   299     })
       
   300   }
       
   301 
       
   302   var old = $.fn.modal
       
   303 
       
   304   $.fn.modal             = Plugin
       
   305   $.fn.modal.Constructor = Modal
       
   306 
       
   307 
       
   308   // MODAL NO CONFLICT
       
   309   // =================
       
   310 
       
   311   $.fn.modal.noConflict = function () {
       
   312     $.fn.modal = old
       
   313     return this
       
   314   }
       
   315 
       
   316 
       
   317   // MODAL DATA-API
       
   318   // ==============
       
   319 
       
   320   $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
       
   321     var $this   = $(this)
       
   322     var href    = $this.attr('href')
       
   323     var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
       
   324     var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
       
   325 
       
   326     if ($this.is('a')) e.preventDefault()
       
   327 
       
   328     $target.one('show.bs.modal', function (showEvent) {
       
   329       if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
       
   330       $target.one('hidden.bs.modal', function () {
       
   331         $this.is(':visible') && $this.trigger('focus')
       
   332       })
       
   333     })
       
   334     Plugin.call($target, option, this)
       
   335   })
       
   336 
       
   337 }(jQuery);