[ADD] doc: new documentation, with training tutorials, and new scaffolding
[odoo/odoo.git] / doc / _themes / odoodoc / static / bootstrap / js / modal.js
1 /* ========================================================================
2  * Bootstrap: modal.js v3.2.0
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
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.$backdrop      =
21     this.isShown        = null
22     this.scrollbarWidth = 0
23
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
33   Modal.VERSION  = '3.2.0'
34
35   Modal.DEFAULTS = {
36     backdrop: true,
37     keyboard: true,
38     show: true
39   }
40
41   Modal.prototype.toggle = function (_relatedTarget) {
42     return this.isShown ? this.hide() : this.show(_relatedTarget)
43   }
44
45   Modal.prototype.show = function (_relatedTarget) {
46     var that = this
47     var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
48
49     this.$element.trigger(e)
50
51     if (this.isShown || e.isDefaultPrevented()) return
52
53     this.isShown = true
54
55     this.checkScrollbar()
56     this.$body.addClass('modal-open')
57
58     this.setScrollbar()
59     this.escape()
60
61     this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
62
63     this.backdrop(function () {
64       var transition = $.support.transition && that.$element.hasClass('fade')
65
66       if (!that.$element.parent().length) {
67         that.$element.appendTo(that.$body) // don't move modals dom position
68       }
69
70       that.$element
71         .show()
72         .scrollTop(0)
73
74       if (transition) {
75         that.$element[0].offsetWidth // force reflow
76       }
77
78       that.$element
79         .addClass('in')
80         .attr('aria-hidden', false)
81
82       that.enforceFocus()
83
84       var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
85
86       transition ?
87         that.$element.find('.modal-dialog') // wait for modal to slide in
88           .one('bsTransitionEnd', function () {
89             that.$element.trigger('focus').trigger(e)
90           })
91           .emulateTransitionEnd(300) :
92         that.$element.trigger('focus').trigger(e)
93     })
94   }
95
96   Modal.prototype.hide = function (e) {
97     if (e) e.preventDefault()
98
99     e = $.Event('hide.bs.modal')
100
101     this.$element.trigger(e)
102
103     if (!this.isShown || e.isDefaultPrevented()) return
104
105     this.isShown = false
106
107     this.$body.removeClass('modal-open')
108
109     this.resetScrollbar()
110     this.escape()
111
112     $(document).off('focusin.bs.modal')
113
114     this.$element
115       .removeClass('in')
116       .attr('aria-hidden', true)
117       .off('click.dismiss.bs.modal')
118
119     $.support.transition && this.$element.hasClass('fade') ?
120       this.$element
121         .one('bsTransitionEnd', $.proxy(this.hideModal, this))
122         .emulateTransitionEnd(300) :
123       this.hideModal()
124   }
125
126   Modal.prototype.enforceFocus = function () {
127     $(document)
128       .off('focusin.bs.modal') // guard against infinite focus loop
129       .on('focusin.bs.modal', $.proxy(function (e) {
130         if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
131           this.$element.trigger('focus')
132         }
133       }, this))
134   }
135
136   Modal.prototype.escape = function () {
137     if (this.isShown && this.options.keyboard) {
138       this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) {
139         e.which == 27 && this.hide()
140       }, this))
141     } else if (!this.isShown) {
142       this.$element.off('keyup.dismiss.bs.modal')
143     }
144   }
145
146   Modal.prototype.hideModal = function () {
147     var that = this
148     this.$element.hide()
149     this.backdrop(function () {
150       that.$element.trigger('hidden.bs.modal')
151     })
152   }
153
154   Modal.prototype.removeBackdrop = function () {
155     this.$backdrop && this.$backdrop.remove()
156     this.$backdrop = null
157   }
158
159   Modal.prototype.backdrop = function (callback) {
160     var that = this
161     var animate = this.$element.hasClass('fade') ? 'fade' : ''
162
163     if (this.isShown && this.options.backdrop) {
164       var doAnimate = $.support.transition && animate
165
166       this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
167         .appendTo(this.$body)
168
169       this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
170         if (e.target !== e.currentTarget) return
171         this.options.backdrop == 'static'
172           ? this.$element[0].focus.call(this.$element[0])
173           : this.hide.call(this)
174       }, this))
175
176       if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
177
178       this.$backdrop.addClass('in')
179
180       if (!callback) return
181
182       doAnimate ?
183         this.$backdrop
184           .one('bsTransitionEnd', callback)
185           .emulateTransitionEnd(150) :
186         callback()
187
188     } else if (!this.isShown && this.$backdrop) {
189       this.$backdrop.removeClass('in')
190
191       var callbackRemove = function () {
192         that.removeBackdrop()
193         callback && callback()
194       }
195       $.support.transition && this.$element.hasClass('fade') ?
196         this.$backdrop
197           .one('bsTransitionEnd', callbackRemove)
198           .emulateTransitionEnd(150) :
199         callbackRemove()
200
201     } else if (callback) {
202       callback()
203     }
204   }
205
206   Modal.prototype.checkScrollbar = function () {
207     if (document.body.clientWidth >= window.innerWidth) return
208     this.scrollbarWidth = this.scrollbarWidth || this.measureScrollbar()
209   }
210
211   Modal.prototype.setScrollbar = function () {
212     var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
213     if (this.scrollbarWidth) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
214   }
215
216   Modal.prototype.resetScrollbar = function () {
217     this.$body.css('padding-right', '')
218   }
219
220   Modal.prototype.measureScrollbar = function () { // thx walsh
221     var scrollDiv = document.createElement('div')
222     scrollDiv.className = 'modal-scrollbar-measure'
223     this.$body.append(scrollDiv)
224     var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
225     this.$body[0].removeChild(scrollDiv)
226     return scrollbarWidth
227   }
228
229
230   // MODAL PLUGIN DEFINITION
231   // =======================
232
233   function Plugin(option, _relatedTarget) {
234     return this.each(function () {
235       var $this   = $(this)
236       var data    = $this.data('bs.modal')
237       var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
238
239       if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
240       if (typeof option == 'string') data[option](_relatedTarget)
241       else if (options.show) data.show(_relatedTarget)
242     })
243   }
244
245   var old = $.fn.modal
246
247   $.fn.modal             = Plugin
248   $.fn.modal.Constructor = Modal
249
250
251   // MODAL NO CONFLICT
252   // =================
253
254   $.fn.modal.noConflict = function () {
255     $.fn.modal = old
256     return this
257   }
258
259
260   // MODAL DATA-API
261   // ==============
262
263   $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
264     var $this   = $(this)
265     var href    = $this.attr('href')
266     var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
267     var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
268
269     if ($this.is('a')) e.preventDefault()
270
271     $target.one('show.bs.modal', function (showEvent) {
272       if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
273       $target.one('hidden.bs.modal', function () {
274         $this.is(':visible') && $this.trigger('focus')
275       })
276     })
277     Plugin.call($target, option, this)
278   })
279
280 }(jQuery);