PluginProbe
WPBot – AI ChatBot for Live Support, Lead Generation, AI Services / 4.2.4
WPBot – AI ChatBot for Live Support, Lead Generation, AI Services v4.2.4
8.7.5 8.7.4 8.7.3 8.7.2 8.7.1 8.7.0 8.6.9 8.6.8 8.6.7 8.6.6 8.6.5 8.6.4 8.6.2 8.6.1 8.6.0 8.5.9 8.5.8 8.5.7 8.5.6 8.5.5 8.5.4 8.5.3 8.5.2 8.5.0 8.4.9 All 531 releases
chatbot / js / bootstrap.js

bootstrap.js in WPBot – AI ChatBot for Live Support, Lead Generation, AI Services 4.2.4, at js/bootstrap.js

2,378 lines 70.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /*!
2 * Bootstrap v3.3.7 (http://getbootstrap.com)
3 * Copyright 2011-2016 Twitter, Inc.
4 * Licensed under the MIT license
5 */
6
7 if (typeof jQuery === 'undefined') {
8 throw new Error('Bootstrap\'s JavaScript requires jQuery')
9 }
10
11 +function ($) {
12 'use strict';
13 var version = $.fn.jquery.split(' ')[0].split('.')
14 if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 3)) {
15 throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4')
16 }
17 }(jQuery);
18
19 /* ========================================================================
20 * Bootstrap: transition.js v3.3.7
21 * http://getbootstrap.com/javascript/#transitions
22 * ========================================================================
23 * Copyright 2011-2016 Twitter, Inc.
24 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
25 * ======================================================================== */
26
27
28 +function ($) {
29 'use strict';
30
31 // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
32 // ============================================================
33
34 function transitionEnd() {
35 var el = document.createElement('bootstrap')
36
37 var transEndEventNames = {
38 WebkitTransition : 'webkitTransitionEnd',
39 MozTransition : 'transitionend',
40 OTransition : 'oTransitionEnd otransitionend',
41 transition : 'transitionend'
42 }
43
44 for (var name in transEndEventNames) {
45 if (el.style[name] !== undefined) {
46 return { end: transEndEventNames[name] }
47 }
48 }
49
50 return false // explicit for ie8 ( ._.)
51 }
52
53 // http://blog.alexmaccaw.com/css-transitions
54 $.fn.emulateTransitionEnd = function (duration) {
55 var called = false
56 var $el = this
57 $(this).one('bsTransitionEnd', function () { called = true })
58 var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
59 setTimeout(callback, duration)
60 return this
61 }
62
63 $(function () {
64 $.support.transition = transitionEnd()
65
66 if (!$.support.transition) return
67
68 $.event.special.bsTransitionEnd = {
69 bindType: $.support.transition.end,
70 delegateType: $.support.transition.end,
71 handle: function (e) {
72 if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
73 }
74 }
75 })
76
77 }(jQuery);
78
79 /* ========================================================================
80 * Bootstrap: alert.js v3.3.7
81 * http://getbootstrap.com/javascript/#alerts
82 * ========================================================================
83 * Copyright 2011-2016 Twitter, Inc.
84 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
85 * ======================================================================== */
86
87
88 +function ($) {
89 'use strict';
90
91 // ALERT CLASS DEFINITION
92 // ======================
93
94 var dismiss = '[data-dismiss="alert"]'
95 var Alert = function (el) {
96 $(el).on('click', dismiss, this.close)
97 }
98
99 Alert.VERSION = '3.3.7'
100
101 Alert.TRANSITION_DURATION = 150
102
103 Alert.prototype.close = function (e) {
104 var $this = $(this)
105 var selector = $this.attr('data-target')
106
107 if (!selector) {
108 selector = $this.attr('href')
109 selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
110 }
111
112 var $parent = $(selector === '#' ? [] : selector)
113
114 if (e) e.preventDefault()
115
116 if (!$parent.length) {
117 $parent = $this.closest('.alert')
118 }
119
120 $parent.trigger(e = $.Event('close.bs.alert'))
121
122 if (e.isDefaultPrevented()) return
123
124 $parent.removeClass('in')
125
126 function removeElement() {
127 // detach from parent, fire event then clean up data
128 $parent.detach().trigger('closed.bs.alert').remove()
129 }
130
131 $.support.transition && $parent.hasClass('fade') ?
132 $parent
133 .one('bsTransitionEnd', removeElement)
134 .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
135 removeElement()
136 }
137
138
139 // ALERT PLUGIN DEFINITION
140 // =======================
141
142 function Plugin(option) {
143 return this.each(function () {
144 var $this = $(this)
145 var data = $this.data('bs.alert')
146
147 if (!data) $this.data('bs.alert', (data = new Alert(this)))
148 if (typeof option == 'string') data[option].call($this)
149 })
150 }
151
152 var old = $.fn.alert
153
154 $.fn.alert = Plugin
155 $.fn.alert.Constructor = Alert
156
157
158 // ALERT NO CONFLICT
159 // =================
160
161 $.fn.alert.noConflict = function () {
162 $.fn.alert = old
163 return this
164 }
165
166
167 // ALERT DATA-API
168 // ==============
169
170 $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
171
172 }(jQuery);
173
174 /* ========================================================================
175 * Bootstrap: button.js v3.3.7
176 * http://getbootstrap.com/javascript/#buttons
177 * ========================================================================
178 * Copyright 2011-2016 Twitter, Inc.
179 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
180 * ======================================================================== */
181
182
183 +function ($) {
184 'use strict';
185
186 // BUTTON PUBLIC CLASS DEFINITION
187 // ==============================
188
189 var Button = function (element, options) {
190 this.$element = $(element)
191 this.options = $.extend({}, Button.DEFAULTS, options)
192 this.isLoading = false
193 }
194
195 Button.VERSION = '3.3.7'
196
197 Button.DEFAULTS = {
198 loadingText: 'loading...'
199 }
200
201 Button.prototype.setState = function (state) {
202 var d = 'disabled'
203 var $el = this.$element
204 var val = $el.is('input') ? 'val' : 'html'
205 var data = $el.data()
206
207 state += 'Text'
208
209 if (data.resetText == null) $el.data('resetText', $el[val]())
210
211 // push to event loop to allow forms to submit
212 setTimeout($.proxy(function () {
213 $el[val](data[state] == null ? this.options[state] : data[state])
214
215 if (state == 'loadingText') {
216 this.isLoading = true
217 $el.addClass(d).attr(d, d).prop(d, true)
218 } else if (this.isLoading) {
219 this.isLoading = false
220 $el.removeClass(d).removeAttr(d).prop(d, false)
221 }
222 }, this), 0)
223 }
224
225 Button.prototype.toggle = function () {
226 var changed = true
227 var $parent = this.$element.closest('[data-toggle="buttons"]')
228
229 if ($parent.length) {
230 var $input = this.$element.find('input')
231 if ($input.prop('type') == 'radio') {
232 if ($input.prop('checked')) changed = false
233 $parent.find('.active').removeClass('active')
234 this.$element.addClass('active')
235 } else if ($input.prop('type') == 'checkbox') {
236 if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false
237 this.$element.toggleClass('active')
238 }
239 $input.prop('checked', this.$element.hasClass('active'))
240 if (changed) $input.trigger('change')
241 } else {
242 this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
243 this.$element.toggleClass('active')
244 }
245 }
246
247
248 // BUTTON PLUGIN DEFINITION
249 // ========================
250
251 function Plugin(option) {
252 return this.each(function () {
253 var $this = $(this)
254 var data = $this.data('bs.button')
255 var options = typeof option == 'object' && option
256
257 if (!data) $this.data('bs.button', (data = new Button(this, options)))
258
259 if (option == 'toggle') data.toggle()
260 else if (option) data.setState(option)
261 })
262 }
263
264 var old = $.fn.button
265
266 $.fn.button = Plugin
267 $.fn.button.Constructor = Button
268
269
270 // BUTTON NO CONFLICT
271 // ==================
272
273 $.fn.button.noConflict = function () {
274 $.fn.button = old
275 return this
276 }
277
278
279 // BUTTON DATA-API
280 // ===============
281
282 $(document)
283 .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
284 var $btn = $(e.target).closest('.btn')
285 Plugin.call($btn, 'toggle')
286 if (!($(e.target).is('input[type="radio"], input[type="checkbox"]'))) {
287 // Prevent double click on radios, and the double selections (so cancellation) on checkboxes
288 e.preventDefault()
289 // The target component still receive the focus
290 if ($btn.is('input,button')) $btn.trigger('focus')
291 else $btn.find('input:visible,button:visible').first().trigger('focus')
292 }
293 })
294 .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
295 $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
296 })
297
298 }(jQuery);
299
300 /* ========================================================================
301 * Bootstrap: carousel.js v3.3.7
302 * http://getbootstrap.com/javascript/#carousel
303 * ========================================================================
304 * Copyright 2011-2016 Twitter, Inc.
305 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
306 * ======================================================================== */
307
308
309 +function ($) {
310 'use strict';
311
312 // CAROUSEL CLASS DEFINITION
313 // =========================
314
315 var Carousel = function (element, options) {
316 this.$element = $(element)
317 this.$indicators = this.$element.find('.carousel-indicators')
318 this.options = options
319 this.paused = null
320 this.sliding = null
321 this.interval = null
322 this.$active = null
323 this.$items = null
324
325 this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
326
327 this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
328 .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
329 .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
330 }
331
332 Carousel.VERSION = '3.3.7'
333
334 Carousel.TRANSITION_DURATION = 600
335
336 Carousel.DEFAULTS = {
337 interval: 5000,
338 pause: 'hover',
339 wrap: true,
340 keyboard: true
341 }
342
343 Carousel.prototype.keydown = function (e) {
344 if (/input|textarea/i.test(e.target.tagName)) return
345 switch (e.which) {
346 case 37: this.prev(); break
347 case 39: this.next(); break
348 default: return
349 }
350
351 e.preventDefault()
352 }
353
354 Carousel.prototype.cycle = function (e) {
355 e || (this.paused = false)
356
357 this.interval && clearInterval(this.interval)
358
359 this.options.interval
360 && !this.paused
361 && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
362
363 return this
364 }
365
366 Carousel.prototype.getItemIndex = function (item) {
367 this.$items = item.parent().children('.item')
368 return this.$items.index(item || this.$active)
369 }
370
371 Carousel.prototype.getItemForDirection = function (direction, active) {
372 var activeIndex = this.getItemIndex(active)
373 var willWrap = (direction == 'prev' && activeIndex === 0)
374 || (direction == 'next' && activeIndex == (this.$items.length - 1))
375 if (willWrap && !this.options.wrap) return active
376 var delta = direction == 'prev' ? -1 : 1
377 var itemIndex = (activeIndex + delta) % this.$items.length
378 return this.$items.eq(itemIndex)
379 }
380
381 Carousel.prototype.to = function (pos) {
382 var that = this
383 var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
384
385 if (pos > (this.$items.length - 1) || pos < 0) return
386
387 if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
388 if (activeIndex == pos) return this.pause().cycle()
389
390 return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
391 }
392
393 Carousel.prototype.pause = function (e) {
394 e || (this.paused = true)
395
396 if (this.$element.find('.next, .prev').length && $.support.transition) {
397 this.$element.trigger($.support.transition.end)
398 this.cycle(true)
399 }
400
401 this.interval = clearInterval(this.interval)
402
403 return this
404 }
405
406 Carousel.prototype.next = function () {
407 if (this.sliding) return
408 return this.slide('next')
409 }
410
411 Carousel.prototype.prev = function () {
412 if (this.sliding) return
413 return this.slide('prev')
414 }
415
416 Carousel.prototype.slide = function (type, next) {
417 var $active = this.$element.find('.item.active')
418 var $next = next || this.getItemForDirection(type, $active)
419 var isCycling = this.interval
420 var direction = type == 'next' ? 'left' : 'right'
421 var that = this
422
423 if ($next.hasClass('active')) return (this.sliding = false)
424
425 var relatedTarget = $next[0]
426 var slideEvent = $.Event('slide.bs.carousel', {
427 relatedTarget: relatedTarget,
428 direction: direction
429 })
430 this.$element.trigger(slideEvent)
431 if (slideEvent.isDefaultPrevented()) return
432
433 this.sliding = true
434
435 isCycling && this.pause()
436
437 if (this.$indicators.length) {
438 this.$indicators.find('.active').removeClass('active')
439 var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
440 $nextIndicator && $nextIndicator.addClass('active')
441 }
442
443 var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
444 if ($.support.transition && this.$element.hasClass('slide')) {
445 $next.addClass(type)
446 $next[0].offsetWidth // force reflow
447 $active.addClass(direction)
448 $next.addClass(direction)
449 $active
450 .one('bsTransitionEnd', function () {
451 $next.removeClass([type, direction].join(' ')).addClass('active')
452 $active.removeClass(['active', direction].join(' '))
453 that.sliding = false
454 setTimeout(function () {
455 that.$element.trigger(slidEvent)
456 }, 0)
457 })
458 .emulateTransitionEnd(Carousel.TRANSITION_DURATION)
459 } else {
460 $active.removeClass('active')
461 $next.addClass('active')
462 this.sliding = false
463 this.$element.trigger(slidEvent)
464 }
465
466 isCycling && this.cycle()
467
468 return this
469 }
470
471
472 // CAROUSEL PLUGIN DEFINITION
473 // ==========================
474
475 function Plugin(option) {
476 return this.each(function () {
477 var $this = $(this)
478 var data = $this.data('bs.carousel')
479 var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
480 var action = typeof option == 'string' ? option : options.slide
481
482 if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
483 if (typeof option == 'number') data.to(option)
484 else if (action) data[action]()
485 else if (options.interval) data.pause().cycle()
486 })
487 }
488
489 var old = $.fn.carousel
490
491 $.fn.carousel = Plugin
492 $.fn.carousel.Constructor = Carousel
493
494
495 // CAROUSEL NO CONFLICT
496 // ====================
497
498 $.fn.carousel.noConflict = function () {
499 $.fn.carousel = old
500 return this
501 }
502
503
504 // CAROUSEL DATA-API
505 // =================
506
507 var clickHandler = function (e) {
508 var href
509 var $this = $(this)
510 var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
511 if (!$target.hasClass('carousel')) return
512 var options = $.extend({}, $target.data(), $this.data())
513 var slideIndex = $this.attr('data-slide-to')
514 if (slideIndex) options.interval = false
515
516 Plugin.call($target, options)
517
518 if (slideIndex) {
519 $target.data('bs.carousel').to(slideIndex)
520 }
521
522 e.preventDefault()
523 }
524
525 $(document)
526 .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
527 .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)
528
529 $(window).on('load', function () {
530 $('[data-ride="carousel"]').each(function () {
531 var $carousel = $(this)
532 Plugin.call($carousel, $carousel.data())
533 })
534 })
535
536 }(jQuery);
537
538 /* ========================================================================
539 * Bootstrap: collapse.js v3.3.7
540 * http://getbootstrap.com/javascript/#collapse
541 * ========================================================================
542 * Copyright 2011-2016 Twitter, Inc.
543 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
544 * ======================================================================== */
545
546 /* jshint latedef: false */
547
548 +function ($) {
549 'use strict';
550
551 // COLLAPSE PUBLIC CLASS DEFINITION
552 // ================================
553
554 var Collapse = function (element, options) {
555 this.$element = $(element)
556 this.options = $.extend({}, Collapse.DEFAULTS, options)
557 this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
558 '[data-toggle="collapse"][data-target="#' + element.id + '"]')
559 this.transitioning = null
560
561 if (this.options.parent) {
562 this.$parent = this.getParent()
563 } else {
564 this.addAriaAndCollapsedClass(this.$element, this.$trigger)
565 }
566
567 if (this.options.toggle) this.toggle()
568 }
569
570 Collapse.VERSION = '3.3.7'
571
572 Collapse.TRANSITION_DURATION = 350
573
574 Collapse.DEFAULTS = {
575 toggle: true
576 }
577
578 Collapse.prototype.dimension = function () {
579 var hasWidth = this.$element.hasClass('width')
580 return hasWidth ? 'width' : 'height'
581 }
582
583 Collapse.prototype.show = function () {
584 if (this.transitioning || this.$element.hasClass('in')) return
585
586 var activesData
587 var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')
588
589 if (actives && actives.length) {
590 activesData = actives.data('bs.collapse')
591 if (activesData && activesData.transitioning) return
592 }
593
594 var startEvent = $.Event('show.bs.collapse')
595 this.$element.trigger(startEvent)
596 if (startEvent.isDefaultPrevented()) return
597
598 if (actives && actives.length) {
599 Plugin.call(actives, 'hide')
600 activesData || actives.data('bs.collapse', null)
601 }
602
603 var dimension = this.dimension()
604
605 this.$element
606 .removeClass('collapse')
607 .addClass('collapsing')[dimension](0)
608 .attr('aria-expanded', true)
609
610 this.$trigger
611 .removeClass('collapsed')
612 .attr('aria-expanded', true)
613
614 this.transitioning = 1
615
616 var complete = function () {
617 this.$element
618 .removeClass('collapsing')
619 .addClass('collapse in')[dimension]('')
620 this.transitioning = 0
621 this.$element
622 .trigger('shown.bs.collapse')
623 }
624
625 if (!$.support.transition) return complete.call(this)
626
627 var scrollSize = $.camelCase(['scroll', dimension].join('-'))
628
629 this.$element
630 .one('bsTransitionEnd', $.proxy(complete, this))
631 .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
632 }
633
634 Collapse.prototype.hide = function () {
635 if (this.transitioning || !this.$element.hasClass('in')) return
636
637 var startEvent = $.Event('hide.bs.collapse')
638 this.$element.trigger(startEvent)
639 if (startEvent.isDefaultPrevented()) return
640
641 var dimension = this.dimension()
642
643 this.$element[dimension](this.$element[dimension]())[0].offsetHeight
644
645 this.$element
646 .addClass('collapsing')
647 .removeClass('collapse in')
648 .attr('aria-expanded', false)
649
650 this.$trigger
651 .addClass('collapsed')
652 .attr('aria-expanded', false)
653
654 this.transitioning = 1
655
656 var complete = function () {
657 this.transitioning = 0
658 this.$element
659 .removeClass('collapsing')
660 .addClass('collapse')
661 .trigger('hidden.bs.collapse')
662 }
663
664 if (!$.support.transition) return complete.call(this)
665
666 this.$element
667 [dimension](0)
668 .one('bsTransitionEnd', $.proxy(complete, this))
669 .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
670 }
671
672 Collapse.prototype.toggle = function () {
673 this[this.$element.hasClass('in') ? 'hide' : 'show']()
674 }
675
676 Collapse.prototype.getParent = function () {
677 return $(this.options.parent)
678 .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
679 .each($.proxy(function (i, element) {
680 var $element = $(element)
681 this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
682 }, this))
683 .end()
684 }
685
686 Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
687 var isOpen = $element.hasClass('in')
688
689 $element.attr('aria-expanded', isOpen)
690 $trigger
691 .toggleClass('collapsed', !isOpen)
692 .attr('aria-expanded', isOpen)
693 }
694
695 function getTargetFromTrigger($trigger) {
696 var href
697 var target = $trigger.attr('data-target')
698 || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
699
700 return $(target)
701 }
702
703
704 // COLLAPSE PLUGIN DEFINITION
705 // ==========================
706
707 function Plugin(option) {
708 return this.each(function () {
709 var $this = $(this)
710 var data = $this.data('bs.collapse')
711 var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
712
713 if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
714 if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
715 if (typeof option == 'string') data[option]()
716 })
717 }
718
719 var old = $.fn.collapse
720
721 $.fn.collapse = Plugin
722 $.fn.collapse.Constructor = Collapse
723
724
725 // COLLAPSE NO CONFLICT
726 // ====================
727
728 $.fn.collapse.noConflict = function () {
729 $.fn.collapse = old
730 return this
731 }
732
733
734 // COLLAPSE DATA-API
735 // =================
736
737 $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
738 var $this = $(this)
739
740 if (!$this.attr('data-target')) e.preventDefault()
741
742 var $target = getTargetFromTrigger($this)
743 var data = $target.data('bs.collapse')
744 var option = data ? 'toggle' : $this.data()
745
746 Plugin.call($target, option)
747 })
748
749 }(jQuery);
750
751 /* ========================================================================
752 * Bootstrap: dropdown.js v3.3.7
753 * http://getbootstrap.com/javascript/#dropdowns
754 * ========================================================================
755 * Copyright 2011-2016 Twitter, Inc.
756 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
757 * ======================================================================== */
758
759
760 +function ($) {
761 'use strict';
762
763 // DROPDOWN CLASS DEFINITION
764 // =========================
765
766 var backdrop = '.dropdown-backdrop'
767 var toggle = '[data-toggle="dropdown"]'
768 var Dropdown = function (element) {
769 $(element).on('click.bs.dropdown', this.toggle)
770 }
771
772 Dropdown.VERSION = '3.3.7'
773
774 function getParent($this) {
775 var selector = $this.attr('data-target')
776
777 if (!selector) {
778 selector = $this.attr('href')
779 selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
780 }
781
782 var $parent = selector && $(selector)
783
784 return $parent && $parent.length ? $parent : $this.parent()
785 }
786
787 function clearMenus(e) {
788 if (e && e.which === 3) return
789 $(backdrop).remove()
790 $(toggle).each(function () {
791 var $this = $(this)
792 var $parent = getParent($this)
793 var relatedTarget = { relatedTarget: this }
794
795 if (!$parent.hasClass('open')) return
796
797 if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return
798
799 $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
800
801 if (e.isDefaultPrevented()) return
802
803 $this.attr('aria-expanded', 'false')
804 $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget))
805 })
806 }
807
808 Dropdown.prototype.toggle = function (e) {
809 var $this = $(this)
810
811 if ($this.is('.disabled, :disabled')) return
812
813 var $parent = getParent($this)
814 var isActive = $parent.hasClass('open')
815
816 clearMenus()
817
818 if (!isActive) {
819 if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
820 // if mobile we use a backdrop because click events don't delegate
821 $(document.createElement('div'))
822 .addClass('dropdown-backdrop')
823 .insertAfter($(this))
824 .on('click', clearMenus)
825 }
826
827 var relatedTarget = { relatedTarget: this }
828 $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
829
830 if (e.isDefaultPrevented()) return
831
832 $this
833 .trigger('focus')
834 .attr('aria-expanded', 'true')
835
836 $parent
837 .toggleClass('open')
838 .trigger($.Event('shown.bs.dropdown', relatedTarget))
839 }
840
841 return false
842 }
843
844 Dropdown.prototype.keydown = function (e) {
845 if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
846
847 var $this = $(this)
848
849 e.preventDefault()
850 e.stopPropagation()
851
852 if ($this.is('.disabled, :disabled')) return
853
854 var $parent = getParent($this)
855 var isActive = $parent.hasClass('open')
856
857 if (!isActive && e.which != 27 || isActive && e.which == 27) {
858 if (e.which == 27) $parent.find(toggle).trigger('focus')
859 return $this.trigger('click')
860 }
861
862 var desc = ' li:not(.disabled):visible a'
863 var $items = $parent.find('.dropdown-menu' + desc)
864
865 if (!$items.length) return
866
867 var index = $items.index(e.target)
868
869 if (e.which == 38 && index > 0) index-- // up
870 if (e.which == 40 && index < $items.length - 1) index++ // down
871 if (!~index) index = 0
872
873 $items.eq(index).trigger('focus')
874 }
875
876
877 // DROPDOWN PLUGIN DEFINITION
878 // ==========================
879
880 function Plugin(option) {
881 return this.each(function () {
882 var $this = $(this)
883 var data = $this.data('bs.dropdown')
884
885 if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
886 if (typeof option == 'string') data[option].call($this)
887 })
888 }
889
890 var old = $.fn.dropdown
891
892 $.fn.dropdown = Plugin
893 $.fn.dropdown.Constructor = Dropdown
894
895
896 // DROPDOWN NO CONFLICT
897 // ====================
898
899 $.fn.dropdown.noConflict = function () {
900 $.fn.dropdown = old
901 return this
902 }
903
904
905 // APPLY TO STANDARD DROPDOWN ELEMENTS
906 // ===================================
907
908 $(document)
909 .on('click.bs.dropdown.data-api', clearMenus)
910 .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
911 .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
912 .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
913 .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
914
915 }(jQuery);
916
917 /* ========================================================================
918 * Bootstrap: modal.js v3.3.7
919 * http://getbootstrap.com/javascript/#modals
920 * ========================================================================
921 * Copyright 2011-2016 Twitter, Inc.
922 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
923 * ======================================================================== */
924
925
926 +function ($) {
927 'use strict';
928
929 // MODAL CLASS DEFINITION
930 // ======================
931
932 var Modal = function (element, options) {
933 this.options = options
934 this.$body = $(document.body)
935 this.$element = $(element)
936 this.$dialog = this.$element.find('.modal-dialog')
937 this.$backdrop = null
938 this.isShown = null
939 this.originalBodyPad = null
940 this.scrollbarWidth = 0
941 this.ignoreBackdropClick = false
942
943 if (this.options.remote) {
944 this.$element
945 .find('.modal-content')
946 .load(this.options.remote, $.proxy(function () {
947 this.$element.trigger('loaded.bs.modal')
948 }, this))
949 }
950 }
951
952 Modal.VERSION = '3.3.7'
953
954 Modal.TRANSITION_DURATION = 300
955 Modal.BACKDROP_TRANSITION_DURATION = 150
956
957 Modal.DEFAULTS = {
958 backdrop: true,
959 keyboard: true,
960 show: true
961 }
962
963 Modal.prototype.toggle = function (_relatedTarget) {
964 return this.isShown ? this.hide() : this.show(_relatedTarget)
965 }
966
967 Modal.prototype.show = function (_relatedTarget) {
968 var that = this
969 var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
970
971 this.$element.trigger(e)
972
973 if (this.isShown || e.isDefaultPrevented()) return
974
975 this.isShown = true
976
977 this.checkScrollbar()
978 this.setScrollbar()
979 this.$body.addClass('modal-open')
980
981 this.escape()
982 this.resize()
983
984 this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
985
986 this.$dialog.on('mousedown.dismiss.bs.modal', function () {
987 that.$element.one('mouseup.dismiss.bs.modal', function (e) {
988 if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
989 })
990 })
991
992 this.backdrop(function () {
993 var transition = $.support.transition && that.$element.hasClass('fade')
994
995 if (!that.$element.parent().length) {
996 that.$element.appendTo(that.$body) // don't move modals dom position
997 }
998
999 that.$element
1000 .show()
1001 .scrollTop(0)
1002
1003 that.adjustDialog()
1004
1005 if (transition) {
1006 that.$element[0].offsetWidth // force reflow
1007 }
1008
1009 that.$element.addClass('in')
1010
1011 that.enforceFocus()
1012
1013 var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
1014
1015 transition ?
1016 that.$dialog // wait for modal to slide in
1017 .one('bsTransitionEnd', function () {
1018 that.$element.trigger('focus').trigger(e)
1019 })
1020 .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
1021 that.$element.trigger('focus').trigger(e)
1022 })
1023 }
1024
1025 Modal.prototype.hide = function (e) {
1026 if (e) e.preventDefault()
1027
1028 e = $.Event('hide.bs.modal')
1029
1030 this.$element.trigger(e)
1031
1032 if (!this.isShown || e.isDefaultPrevented()) return
1033
1034 this.isShown = false
1035
1036 this.escape()
1037 this.resize()
1038
1039 $(document).off('focusin.bs.modal')
1040
1041 this.$element
1042 .removeClass('in')
1043 .off('click.dismiss.bs.modal')
1044 .off('mouseup.dismiss.bs.modal')
1045
1046 this.$dialog.off('mousedown.dismiss.bs.modal')
1047
1048 $.support.transition && this.$element.hasClass('fade') ?
1049 this.$element
1050 .one('bsTransitionEnd', $.proxy(this.hideModal, this))
1051 .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
1052 this.hideModal()
1053 }
1054
1055 Modal.prototype.enforceFocus = function () {
1056 $(document)
1057 .off('focusin.bs.modal') // guard against infinite focus loop
1058 .on('focusin.bs.modal', $.proxy(function (e) {
1059 if (document !== e.target &&
1060 this.$element[0] !== e.target &&
1061 !this.$element.has(e.target).length) {
1062 this.$element.trigger('focus')
1063 }
1064 }, this))
1065 }
1066
1067 Modal.prototype.escape = function () {
1068 if (this.isShown && this.options.keyboard) {
1069 this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
1070 e.which == 27 && this.hide()
1071 }, this))
1072 } else if (!this.isShown) {
1073 this.$element.off('keydown.dismiss.bs.modal')
1074 }
1075 }
1076
1077 Modal.prototype.resize = function () {
1078 if (this.isShown) {
1079 $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
1080 } else {
1081 $(window).off('resize.bs.modal')
1082 }
1083 }
1084
1085 Modal.prototype.hideModal = function () {
1086 var that = this
1087 this.$element.hide()
1088 this.backdrop(function () {
1089 that.$body.removeClass('modal-open')
1090 that.resetAdjustments()
1091 that.resetScrollbar()
1092 that.$element.trigger('hidden.bs.modal')
1093 })
1094 }
1095
1096 Modal.prototype.removeBackdrop = function () {
1097 this.$backdrop && this.$backdrop.remove()
1098 this.$backdrop = null
1099 }
1100
1101 Modal.prototype.backdrop = function (callback) {
1102 var that = this
1103 var animate = this.$element.hasClass('fade') ? 'fade' : ''
1104
1105 if (this.isShown && this.options.backdrop) {
1106 var doAnimate = $.support.transition && animate
1107
1108 this.$backdrop = $(document.createElement('div'))
1109 .addClass('modal-backdrop ' + animate)
1110 .appendTo(this.$body)
1111
1112 this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
1113 if (this.ignoreBackdropClick) {
1114 this.ignoreBackdropClick = false
1115 return
1116 }
1117 if (e.target !== e.currentTarget) return
1118 this.options.backdrop == 'static'
1119 ? this.$element[0].focus()
1120 : this.hide()
1121 }, this))
1122
1123 if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
1124
1125 this.$backdrop.addClass('in')
1126
1127 if (!callback) return
1128
1129 doAnimate ?
1130 this.$backdrop
1131 .one('bsTransitionEnd', callback)
1132 .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
1133 callback()
1134
1135 } else if (!this.isShown && this.$backdrop) {
1136 this.$backdrop.removeClass('in')
1137
1138 var callbackRemove = function () {
1139 that.removeBackdrop()
1140 callback && callback()
1141 }
1142 $.support.transition && this.$element.hasClass('fade') ?
1143 this.$backdrop
1144 .one('bsTransitionEnd', callbackRemove)
1145 .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
1146 callbackRemove()
1147
1148 } else if (callback) {
1149 callback()
1150 }
1151 }
1152
1153 // these following methods are used to handle overflowing modals
1154
1155 Modal.prototype.handleUpdate = function () {
1156 this.adjustDialog()
1157 }
1158
1159 Modal.prototype.adjustDialog = function () {
1160 var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
1161
1162 this.$element.css({
1163 paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
1164 paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
1165 })
1166 }
1167
1168 Modal.prototype.resetAdjustments = function () {
1169 this.$element.css({
1170 paddingLeft: '',
1171 paddingRight: ''
1172 })
1173 }
1174
1175 Modal.prototype.checkScrollbar = function () {
1176 var fullWindowWidth = window.innerWidth
1177 if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
1178 var documentElementRect = document.documentElement.getBoundingClientRect()
1179 fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
1180 }
1181 this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
1182 this.scrollbarWidth = this.measureScrollbar()
1183 }
1184
1185 Modal.prototype.setScrollbar = function () {
1186 var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
1187 this.originalBodyPad = document.body.style.paddingRight || ''
1188 if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
1189 }
1190
1191 Modal.prototype.resetScrollbar = function () {
1192 this.$body.css('padding-right', this.originalBodyPad)
1193 }
1194
1195 Modal.prototype.measureScrollbar = function () { // thx walsh
1196 var scrollDiv = document.createElement('div')
1197 scrollDiv.className = 'modal-scrollbar-measure'
1198 this.$body.append(scrollDiv)
1199 var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
1200 this.$body[0].removeChild(scrollDiv)
1201 return scrollbarWidth
1202 }
1203
1204
1205 // MODAL PLUGIN DEFINITION
1206 // =======================
1207
1208 function Plugin(option, _relatedTarget) {
1209 return this.each(function () {
1210 var $this = $(this)
1211 var data = $this.data('bs.modal')
1212 var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
1213
1214 if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
1215 if (typeof option == 'string') data[option](_relatedTarget)
1216 else if (options.show) data.show(_relatedTarget)
1217 })
1218 }
1219
1220 var old = $.fn.modal
1221
1222 $.fn.modal = Plugin
1223 $.fn.modal.Constructor = Modal
1224
1225
1226 // MODAL NO CONFLICT
1227 // =================
1228
1229 $.fn.modal.noConflict = function () {
1230 $.fn.modal = old
1231 return this
1232 }
1233
1234
1235 // MODAL DATA-API
1236 // ==============
1237
1238 $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
1239 var $this = $(this)
1240 var href = $this.attr('href')
1241 var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
1242 var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
1243
1244 if ($this.is('a')) e.preventDefault()
1245
1246 $target.one('show.bs.modal', function (showEvent) {
1247 if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
1248 $target.one('hidden.bs.modal', function () {
1249 $this.is(':visible') && $this.trigger('focus')
1250 })
1251 })
1252 Plugin.call($target, option, this)
1253 })
1254
1255 }(jQuery);
1256
1257 /* ========================================================================
1258 * Bootstrap: tooltip.js v3.3.7
1259 * http://getbootstrap.com/javascript/#tooltip
1260 * Inspired by the original jQuery.tipsy by Jason Frame
1261 * ========================================================================
1262 * Copyright 2011-2016 Twitter, Inc.
1263 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1264 * ======================================================================== */
1265
1266
1267 +function ($) {
1268 'use strict';
1269
1270 // TOOLTIP PUBLIC CLASS DEFINITION
1271 // ===============================
1272
1273 var Tooltip = function (element, options) {
1274 this.type = null
1275 this.options = null
1276 this.enabled = null
1277 this.timeout = null
1278 this.hoverState = null
1279 this.$element = null
1280 this.inState = null
1281
1282 this.init('tooltip', element, options)
1283 }
1284
1285 Tooltip.VERSION = '3.3.7'
1286
1287 Tooltip.TRANSITION_DURATION = 150
1288
1289 Tooltip.DEFAULTS = {
1290 animation: true,
1291 placement: 'top',
1292 selector: false,
1293 template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
1294 trigger: 'hover focus',
1295 title: '',
1296 delay: 0,
1297 html: false,
1298 container: false,
1299 viewport: {
1300 selector: 'body',
1301 padding: 0
1302 }
1303 }
1304
1305 Tooltip.prototype.init = function (type, element, options) {
1306 this.enabled = true
1307 this.type = type
1308 this.$element = $(element)
1309 this.options = this.getOptions(options)
1310 this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
1311 this.inState = { click: false, hover: false, focus: false }
1312
1313 if (this.$element[0] instanceof document.constructor && !this.options.selector) {
1314 throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
1315 }
1316
1317 var triggers = this.options.trigger.split(' ')
1318
1319 for (var i = triggers.length; i--;) {
1320 var trigger = triggers[i]
1321
1322 if (trigger == 'click') {
1323 this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
1324 } else if (trigger != 'manual') {
1325 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
1326 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
1327
1328 this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
1329 this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
1330 }
1331 }
1332
1333 this.options.selector ?
1334 (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
1335 this.fixTitle()
1336 }
1337
1338 Tooltip.prototype.getDefaults = function () {
1339 return Tooltip.DEFAULTS
1340 }
1341
1342 Tooltip.prototype.getOptions = function (options) {
1343 options = $.extend({}, this.getDefaults(), this.$element.data(), options)
1344
1345 if (options.delay && typeof options.delay == 'number') {
1346 options.delay = {
1347 show: options.delay,
1348 hide: options.delay
1349 }
1350 }
1351
1352 return options
1353 }
1354
1355 Tooltip.prototype.getDelegateOptions = function () {
1356 var options = {}
1357 var defaults = this.getDefaults()
1358
1359 this._options && $.each(this._options, function (key, value) {
1360 if (defaults[key] != value) options[key] = value
1361 })
1362
1363 return options
1364 }
1365
1366 Tooltip.prototype.enter = function (obj) {
1367 var self = obj instanceof this.constructor ?
1368 obj : $(obj.currentTarget).data('bs.' + this.type)
1369
1370 if (!self) {
1371 self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
1372 $(obj.currentTarget).data('bs.' + this.type, self)
1373 }
1374
1375 if (obj instanceof $.Event) {
1376 self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
1377 }
1378
1379 if (self.tip().hasClass('in') || self.hoverState == 'in') {
1380 self.hoverState = 'in'
1381 return
1382 }
1383
1384 clearTimeout(self.timeout)
1385
1386 self.hoverState = 'in'
1387
1388 if (!self.options.delay || !self.options.delay.show) return self.show()
1389
1390 self.timeout = setTimeout(function () {
1391 if (self.hoverState == 'in') self.show()
1392 }, self.options.delay.show)
1393 }
1394
1395 Tooltip.prototype.isInStateTrue = function () {
1396 for (var key in this.inState) {
1397 if (this.inState[key]) return true
1398 }
1399
1400 return false
1401 }
1402
1403 Tooltip.prototype.leave = function (obj) {
1404 var self = obj instanceof this.constructor ?
1405 obj : $(obj.currentTarget).data('bs.' + this.type)
1406
1407 if (!self) {
1408 self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
1409 $(obj.currentTarget).data('bs.' + this.type, self)
1410 }
1411
1412 if (obj instanceof $.Event) {
1413 self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
1414 }
1415
1416 if (self.isInStateTrue()) return
1417
1418 clearTimeout(self.timeout)
1419
1420 self.hoverState = 'out'
1421
1422 if (!self.options.delay || !self.options.delay.hide) return self.hide()
1423
1424 self.timeout = setTimeout(function () {
1425 if (self.hoverState == 'out') self.hide()
1426 }, self.options.delay.hide)
1427 }
1428
1429 Tooltip.prototype.show = function () {
1430 var e = $.Event('show.bs.' + this.type)
1431
1432 if (this.hasContent() && this.enabled) {
1433 this.$element.trigger(e)
1434
1435 var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
1436 if (e.isDefaultPrevented() || !inDom) return
1437 var that = this
1438
1439 var $tip = this.tip()
1440
1441 var tipId = this.getUID(this.type)
1442
1443 this.setContent()
1444 $tip.attr('id', tipId)
1445 this.$element.attr('aria-describedby', tipId)
1446
1447 if (this.options.animation) $tip.addClass('fade')
1448
1449 var placement = typeof this.options.placement == 'function' ?
1450 this.options.placement.call(this, $tip[0], this.$element[0]) :
1451 this.options.placement
1452
1453 var autoToken = /\s?auto?\s?/i
1454 var autoPlace = autoToken.test(placement)
1455 if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
1456
1457 $tip
1458 .detach()
1459 .css({ top: 0, left: 0, display: 'block' })
1460 .addClass(placement)
1461 .data('bs.' + this.type, this)
1462
1463 this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
1464 this.$element.trigger('inserted.bs.' + this.type)
1465
1466 var pos = this.getPosition()
1467 var actualWidth = $tip[0].offsetWidth
1468 var actualHeight = $tip[0].offsetHeight
1469
1470 if (autoPlace) {
1471 var orgPlacement = placement
1472 var viewportDim = this.getPosition(this.$viewport)
1473
1474 placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top' :
1475 placement == 'top' && pos.top - actualHeight < viewportDim.top ? 'bottom' :
1476 placement == 'right' && pos.right + actualWidth > viewportDim.width ? 'left' :
1477 placement == 'left' && pos.left - actualWidth < viewportDim.left ? 'right' :
1478 placement
1479
1480 $tip
1481 .removeClass(orgPlacement)
1482 .addClass(placement)
1483 }
1484
1485 var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
1486
1487 this.applyPlacement(calculatedOffset, placement)
1488
1489 var complete = function () {
1490 var prevHoverState = that.hoverState
1491 that.$element.trigger('shown.bs.' + that.type)
1492 that.hoverState = null
1493
1494 if (prevHoverState == 'out') that.leave(that)
1495 }
1496
1497 $.support.transition && this.$tip.hasClass('fade') ?
1498 $tip
1499 .one('bsTransitionEnd', complete)
1500 .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
1501 complete()
1502 }
1503 }
1504
1505 Tooltip.prototype.applyPlacement = function (offset, placement) {
1506 var $tip = this.tip()
1507 var width = $tip[0].offsetWidth
1508 var height = $tip[0].offsetHeight
1509
1510 // manually read margins because getBoundingClientRect includes difference
1511 var marginTop = parseInt($tip.css('margin-top'), 10)
1512 var marginLeft = parseInt($tip.css('margin-left'), 10)
1513
1514 // we must check for NaN for ie 8/9
1515 if (isNaN(marginTop)) marginTop = 0
1516 if (isNaN(marginLeft)) marginLeft = 0
1517
1518 offset.top += marginTop
1519 offset.left += marginLeft
1520
1521 // $.fn.offset doesn't round pixel values
1522 // so we use setOffset directly with our own function B-0
1523 $.offset.setOffset($tip[0], $.extend({
1524 using: function (props) {
1525 $tip.css({
1526 top: Math.round(props.top),
1527 left: Math.round(props.left)
1528 })
1529 }
1530 }, offset), 0)
1531
1532 $tip.addClass('in')
1533
1534 // check to see if placing tip in new offset caused the tip to resize itself
1535 var actualWidth = $tip[0].offsetWidth
1536 var actualHeight = $tip[0].offsetHeight
1537
1538 if (placement == 'top' && actualHeight != height) {
1539 offset.top = offset.top + height - actualHeight
1540 }
1541
1542 var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
1543
1544 if (delta.left) offset.left += delta.left
1545 else offset.top += delta.top
1546
1547 var isVertical = /top|bottom/.test(placement)
1548 var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
1549 var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
1550
1551 $tip.offset(offset)
1552 this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
1553 }
1554
1555 Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
1556 this.arrow()
1557 .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
1558 .css(isVertical ? 'top' : 'left', '')
1559 }
1560
1561 Tooltip.prototype.setContent = function () {
1562 var $tip = this.tip()
1563 var title = this.getTitle()
1564
1565 $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
1566 $tip.removeClass('fade in top bottom left right')
1567 }
1568
1569 Tooltip.prototype.hide = function (callback) {
1570 var that = this
1571 var $tip = $(this.$tip)
1572 var e = $.Event('hide.bs.' + this.type)
1573
1574 function complete() {
1575 if (that.hoverState != 'in') $tip.detach()
1576 if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary.
1577 that.$element
1578 .removeAttr('aria-describedby')
1579 .trigger('hidden.bs.' + that.type)
1580 }
1581 callback && callback()
1582 }
1583
1584 this.$element.trigger(e)
1585
1586 if (e.isDefaultPrevented()) return
1587
1588 $tip.removeClass('in')
1589
1590 $.support.transition && $tip.hasClass('fade') ?
1591 $tip
1592 .one('bsTransitionEnd', complete)
1593 .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
1594 complete()
1595
1596 this.hoverState = null
1597
1598 return this
1599 }
1600
1601 Tooltip.prototype.fixTitle = function () {
1602 var $e = this.$element
1603 if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {
1604 $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
1605 }
1606 }
1607
1608 Tooltip.prototype.hasContent = function () {
1609 return this.getTitle()
1610 }
1611
1612 Tooltip.prototype.getPosition = function ($element) {
1613 $element = $element || this.$element
1614
1615 var el = $element[0]
1616 var isBody = el.tagName == 'BODY'
1617
1618 var elRect = el.getBoundingClientRect()
1619 if (elRect.width == null) {
1620 // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
1621 elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
1622 }
1623 var isSvg = window.SVGElement && el instanceof window.SVGElement
1624 // Avoid using $.offset() on SVGs since it gives incorrect results in jQuery 3.
1625 // See https://github.com/twbs/bootstrap/issues/20280
1626 var elOffset = isBody ? { top: 0, left: 0 } : (isSvg ? null : $element.offset())
1627 var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
1628 var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
1629
1630 return $.extend({}, elRect, scroll, outerDims, elOffset)
1631 }
1632
1633 Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
1634 return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
1635 placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
1636 placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
1637 /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
1638
1639 }
1640
1641 Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
1642 var delta = { top: 0, left: 0 }
1643 if (!this.$viewport) return delta
1644
1645 var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
1646 var viewportDimensions = this.getPosition(this.$viewport)
1647
1648 if (/right|left/.test(placement)) {
1649 var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll
1650 var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
1651 if (topEdgeOffset < viewportDimensions.top) { // top overflow
1652 delta.top = viewportDimensions.top - topEdgeOffset
1653 } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
1654 delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
1655 }
1656 } else {
1657 var leftEdgeOffset = pos.left - viewportPadding
1658 var rightEdgeOffset = pos.left + viewportPadding + actualWidth
1659 if (leftEdgeOffset < viewportDimensions.left) { // left overflow
1660 delta.left = viewportDimensions.left - leftEdgeOffset
1661 } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow
1662 delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
1663 }
1664 }
1665
1666 return delta
1667 }
1668
1669 Tooltip.prototype.getTitle = function () {
1670 var title
1671 var $e = this.$element
1672 var o = this.options
1673
1674 title = $e.attr('data-original-title')
1675 || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
1676
1677 return title
1678 }
1679
1680 Tooltip.prototype.getUID = function (prefix) {
1681 do prefix += ~~(Math.random() * 1000000)
1682 while (document.getElementById(prefix))
1683 return prefix
1684 }
1685
1686 Tooltip.prototype.tip = function () {
1687 if (!this.$tip) {
1688 this.$tip = $(this.options.template)
1689 if (this.$tip.length != 1) {
1690 throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
1691 }
1692 }
1693 return this.$tip
1694 }
1695
1696 Tooltip.prototype.arrow = function () {
1697 return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
1698 }
1699
1700 Tooltip.prototype.enable = function () {
1701 this.enabled = true
1702 }
1703
1704 Tooltip.prototype.disable = function () {
1705 this.enabled = false
1706 }
1707
1708 Tooltip.prototype.toggleEnabled = function () {
1709 this.enabled = !this.enabled
1710 }
1711
1712 Tooltip.prototype.toggle = function (e) {
1713 var self = this
1714 if (e) {
1715 self = $(e.currentTarget).data('bs.' + this.type)
1716 if (!self) {
1717 self = new this.constructor(e.currentTarget, this.getDelegateOptions())
1718 $(e.currentTarget).data('bs.' + this.type, self)
1719 }
1720 }
1721
1722 if (e) {
1723 self.inState.click = !self.inState.click
1724 if (self.isInStateTrue()) self.enter(self)
1725 else self.leave(self)
1726 } else {
1727 self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
1728 }
1729 }
1730
1731 Tooltip.prototype.destroy = function () {
1732 var that = this
1733 clearTimeout(this.timeout)
1734 this.hide(function () {
1735 that.$element.off('.' + that.type).removeData('bs.' + that.type)
1736 if (that.$tip) {
1737 that.$tip.detach()
1738 }
1739 that.$tip = null
1740 that.$arrow = null
1741 that.$viewport = null
1742 that.$element = null
1743 })
1744 }
1745
1746
1747 // TOOLTIP PLUGIN DEFINITION
1748 // =========================
1749
1750 function Plugin(option) {
1751 return this.each(function () {
1752 var $this = $(this)
1753 var data = $this.data('bs.tooltip')
1754 var options = typeof option == 'object' && option
1755
1756 if (!data && /destroy|hide/.test(option)) return
1757 if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
1758 if (typeof option == 'string') data[option]()
1759 })
1760 }
1761
1762 var old = $.fn.tooltip
1763
1764 $.fn.tooltip = Plugin
1765 $.fn.tooltip.Constructor = Tooltip
1766
1767
1768 // TOOLTIP NO CONFLICT
1769 // ===================
1770
1771 $.fn.tooltip.noConflict = function () {
1772 $.fn.tooltip = old
1773 return this
1774 }
1775
1776 }(jQuery);
1777
1778 /* ========================================================================
1779 * Bootstrap: popover.js v3.3.7
1780 * http://getbootstrap.com/javascript/#popovers
1781 * ========================================================================
1782 * Copyright 2011-2016 Twitter, Inc.
1783 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1784 * ======================================================================== */
1785
1786
1787 +function ($) {
1788 'use strict';
1789
1790 // POPOVER PUBLIC CLASS DEFINITION
1791 // ===============================
1792
1793 var Popover = function (element, options) {
1794 this.init('popover', element, options)
1795 }
1796
1797 if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
1798
1799 Popover.VERSION = '3.3.7'
1800
1801 Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
1802 placement: 'right',
1803 trigger: 'click',
1804 content: '',
1805 template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
1806 })
1807
1808
1809 // NOTE: POPOVER EXTENDS tooltip.js
1810 // ================================
1811
1812 Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
1813
1814 Popover.prototype.constructor = Popover
1815
1816 Popover.prototype.getDefaults = function () {
1817 return Popover.DEFAULTS
1818 }
1819
1820 Popover.prototype.setContent = function () {
1821 var $tip = this.tip()
1822 var title = this.getTitle()
1823 var content = this.getContent()
1824
1825 $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
1826 $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events
1827 this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
1828 ](content)
1829
1830 $tip.removeClass('fade top bottom left right in')
1831
1832 // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
1833 // this manually by checking the contents.
1834 if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
1835 }
1836
1837 Popover.prototype.hasContent = function () {
1838 return this.getTitle() || this.getContent()
1839 }
1840
1841 Popover.prototype.getContent = function () {
1842 var $e = this.$element
1843 var o = this.options
1844
1845 return $e.attr('data-content')
1846 || (typeof o.content == 'function' ?
1847 o.content.call($e[0]) :
1848 o.content)
1849 }
1850
1851 Popover.prototype.arrow = function () {
1852 return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
1853 }
1854
1855
1856 // POPOVER PLUGIN DEFINITION
1857 // =========================
1858
1859 function Plugin(option) {
1860 return this.each(function () {
1861 var $this = $(this)
1862 var data = $this.data('bs.popover')
1863 var options = typeof option == 'object' && option
1864
1865 if (!data && /destroy|hide/.test(option)) return
1866 if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
1867 if (typeof option == 'string') data[option]()
1868 })
1869 }
1870
1871 var old = $.fn.popover
1872
1873 $.fn.popover = Plugin
1874 $.fn.popover.Constructor = Popover
1875
1876
1877 // POPOVER NO CONFLICT
1878 // ===================
1879
1880 $.fn.popover.noConflict = function () {
1881 $.fn.popover = old
1882 return this
1883 }
1884
1885 }(jQuery);
1886
1887 /* ========================================================================
1888 * Bootstrap: scrollspy.js v3.3.7
1889 * http://getbootstrap.com/javascript/#scrollspy
1890 * ========================================================================
1891 * Copyright 2011-2016 Twitter, Inc.
1892 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1893 * ======================================================================== */
1894
1895
1896 +function ($) {
1897 'use strict';
1898
1899 // SCROLLSPY CLASS DEFINITION
1900 // ==========================
1901
1902 function ScrollSpy(element, options) {
1903 this.$body = $(document.body)
1904 this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
1905 this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
1906 this.selector = (this.options.target || '') + ' .nav li > a'
1907 this.offsets = []
1908 this.targets = []
1909 this.activeTarget = null
1910 this.scrollHeight = 0
1911
1912 this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
1913 this.refresh()
1914 this.process()
1915 }
1916
1917 ScrollSpy.VERSION = '3.3.7'
1918
1919 ScrollSpy.DEFAULTS = {
1920 offset: 10
1921 }
1922
1923 ScrollSpy.prototype.getScrollHeight = function () {
1924 return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
1925 }
1926
1927 ScrollSpy.prototype.refresh = function () {
1928 var that = this
1929 var offsetMethod = 'offset'
1930 var offsetBase = 0
1931
1932 this.offsets = []
1933 this.targets = []
1934 this.scrollHeight = this.getScrollHeight()
1935
1936 if (!$.isWindow(this.$scrollElement[0])) {
1937 offsetMethod = 'position'
1938 offsetBase = this.$scrollElement.scrollTop()
1939 }
1940
1941 this.$body
1942 .find(this.selector)
1943 .map(function () {
1944 var $el = $(this)
1945 var href = $el.data('target') || $el.attr('href')
1946 var $href = /^#./.test(href) && $(href)
1947
1948 return ($href
1949 && $href.length
1950 && $href.is(':visible')
1951 && [[$href[offsetMethod]().top + offsetBase, href]]) || null
1952 })
1953 .sort(function (a, b) { return a[0] - b[0] })
1954 .each(function () {
1955 that.offsets.push(this[0])
1956 that.targets.push(this[1])
1957 })
1958 }
1959
1960 ScrollSpy.prototype.process = function () {
1961 var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
1962 var scrollHeight = this.getScrollHeight()
1963 var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height()
1964 var offsets = this.offsets
1965 var targets = this.targets
1966 var activeTarget = this.activeTarget
1967 var i
1968
1969 if (this.scrollHeight != scrollHeight) {
1970 this.refresh()
1971 }
1972
1973 if (scrollTop >= maxScroll) {
1974 return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
1975 }
1976
1977 if (activeTarget && scrollTop < offsets[0]) {
1978 this.activeTarget = null
1979 return this.clear()
1980 }
1981
1982 for (i = offsets.length; i--;) {
1983 activeTarget != targets[i]
1984 && scrollTop >= offsets[i]
1985 && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
1986 && this.activate(targets[i])
1987 }
1988 }
1989
1990 ScrollSpy.prototype.activate = function (target) {
1991 this.activeTarget = target
1992
1993 this.clear()
1994
1995 var selector = this.selector +
1996 '[data-target="' + target + '"],' +
1997 this.selector + '[href="' + target + '"]'
1998
1999 var active = $(selector)
2000 .parents('li')
2001 .addClass('active')
2002
2003 if (active.parent('.dropdown-menu').length) {
2004 active = active
2005 .closest('li.dropdown')
2006 .addClass('active')
2007 }
2008
2009 active.trigger('activate.bs.scrollspy')
2010 }
2011
2012 ScrollSpy.prototype.clear = function () {
2013 $(this.selector)
2014 .parentsUntil(this.options.target, '.active')
2015 .removeClass('active')
2016 }
2017
2018
2019 // SCROLLSPY PLUGIN DEFINITION
2020 // ===========================
2021
2022 function Plugin(option) {
2023 return this.each(function () {
2024 var $this = $(this)
2025 var data = $this.data('bs.scrollspy')
2026 var options = typeof option == 'object' && option
2027
2028 if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
2029 if (typeof option == 'string') data[option]()
2030 })
2031 }
2032
2033 var old = $.fn.scrollspy
2034
2035 $.fn.scrollspy = Plugin
2036 $.fn.scrollspy.Constructor = ScrollSpy
2037
2038
2039 // SCROLLSPY NO CONFLICT
2040 // =====================
2041
2042 $.fn.scrollspy.noConflict = function () {
2043 $.fn.scrollspy = old
2044 return this
2045 }
2046
2047
2048 // SCROLLSPY DATA-API
2049 // ==================
2050
2051 $(window).on('load.bs.scrollspy.data-api', function () {
2052 $('[data-spy="scroll"]').each(function () {
2053 var $spy = $(this)
2054 Plugin.call($spy, $spy.data())
2055 })
2056 })
2057
2058 }(jQuery);
2059
2060 /* ========================================================================
2061 * Bootstrap: tab.js v3.3.7
2062 * http://getbootstrap.com/javascript/#tabs
2063 * ========================================================================
2064 * Copyright 2011-2016 Twitter, Inc.
2065 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
2066 * ======================================================================== */
2067
2068
2069 +function ($) {
2070 'use strict';
2071
2072 // TAB CLASS DEFINITION
2073 // ====================
2074
2075 var Tab = function (element) {
2076 // jscs:disable requireDollarBeforejQueryAssignment
2077 this.element = $(element)
2078 // jscs:enable requireDollarBeforejQueryAssignment
2079 }
2080
2081 Tab.VERSION = '3.3.7'
2082
2083 Tab.TRANSITION_DURATION = 150
2084
2085 Tab.prototype.show = function () {
2086 var $this = this.element
2087 var $ul = $this.closest('ul:not(.dropdown-menu)')
2088 var selector = $this.data('target')
2089
2090 if (!selector) {
2091 selector = $this.attr('href')
2092 selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
2093 }
2094
2095 if ($this.parent('li').hasClass('active')) return
2096
2097 var $previous = $ul.find('.active:last a')
2098 var hideEvent = $.Event('hide.bs.tab', {
2099 relatedTarget: $this[0]
2100 })
2101 var showEvent = $.Event('show.bs.tab', {
2102 relatedTarget: $previous[0]
2103 })
2104
2105 $previous.trigger(hideEvent)
2106 $this.trigger(showEvent)
2107
2108 if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
2109
2110 var $target = $(selector)
2111
2112 this.activate($this.closest('li'), $ul)
2113 this.activate($target, $target.parent(), function () {
2114 $previous.trigger({
2115 type: 'hidden.bs.tab',
2116 relatedTarget: $this[0]
2117 })
2118 $this.trigger({
2119 type: 'shown.bs.tab',
2120 relatedTarget: $previous[0]
2121 })
2122 })
2123 }
2124
2125 Tab.prototype.activate = function (element, container, callback) {
2126 var $active = container.find('> .active')
2127 var transition = callback
2128 && $.support.transition
2129 && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)
2130
2131 function next() {
2132 $active
2133 .removeClass('active')
2134 .find('> .dropdown-menu > .active')
2135 .removeClass('active')
2136 .end()
2137 .find('[data-toggle="tab"]')
2138 .attr('aria-expanded', false)
2139
2140 element
2141 .addClass('active')
2142 .find('[data-toggle="tab"]')
2143 .attr('aria-expanded', true)
2144
2145 if (transition) {
2146 element[0].offsetWidth // reflow for transition
2147 element.addClass('in')
2148 } else {
2149 element.removeClass('fade')
2150 }
2151
2152 if (element.parent('.dropdown-menu').length) {
2153 element
2154 .closest('li.dropdown')
2155 .addClass('active')
2156 .end()
2157 .find('[data-toggle="tab"]')
2158 .attr('aria-expanded', true)
2159 }
2160
2161 callback && callback()
2162 }
2163
2164 $active.length && transition ?
2165 $active
2166 .one('bsTransitionEnd', next)
2167 .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
2168 next()
2169
2170 $active.removeClass('in')
2171 }
2172
2173
2174 // TAB PLUGIN DEFINITION
2175 // =====================
2176
2177 function Plugin(option) {
2178 return this.each(function () {
2179 var $this = $(this)
2180 var data = $this.data('bs.tab')
2181
2182 if (!data) $this.data('bs.tab', (data = new Tab(this)))
2183 if (typeof option == 'string') data[option]()
2184 })
2185 }
2186
2187 var old = $.fn.tab
2188
2189 $.fn.tab = Plugin
2190 $.fn.tab.Constructor = Tab
2191
2192
2193 // TAB NO CONFLICT
2194 // ===============
2195
2196 $.fn.tab.noConflict = function () {
2197 $.fn.tab = old
2198 return this
2199 }
2200
2201
2202 // TAB DATA-API
2203 // ============
2204
2205 var clickHandler = function (e) {
2206 e.preventDefault()
2207 Plugin.call($(this), 'show')
2208 }
2209
2210 $(document)
2211 .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
2212 .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
2213
2214 }(jQuery);
2215
2216 /* ========================================================================
2217 * Bootstrap: affix.js v3.3.7
2218 * http://getbootstrap.com/javascript/#affix
2219 * ========================================================================
2220 * Copyright 2011-2016 Twitter, Inc.
2221 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
2222 * ======================================================================== */
2223
2224
2225 +function ($) {
2226 'use strict';
2227
2228 // AFFIX CLASS DEFINITION
2229 // ======================
2230
2231 var Affix = function (element, options) {
2232 this.options = $.extend({}, Affix.DEFAULTS, options)
2233
2234 this.$target = $(this.options.target)
2235 .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
2236 .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
2237
2238 this.$element = $(element)
2239 this.affixed = null
2240 this.unpin = null
2241 this.pinnedOffset = null
2242
2243 this.checkPosition()
2244 }
2245
2246 Affix.VERSION = '3.3.7'
2247
2248 Affix.RESET = 'affix affix-top affix-bottom'
2249
2250 Affix.DEFAULTS = {
2251 offset: 0,
2252 target: window
2253 }
2254
2255 Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
2256 var scrollTop = this.$target.scrollTop()
2257 var position = this.$element.offset()
2258 var targetHeight = this.$target.height()
2259
2260 if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
2261
2262 if (this.affixed == 'bottom') {
2263 if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
2264 return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
2265 }
2266
2267 var initializing = this.affixed == null
2268 var colliderTop = initializing ? scrollTop : position.top
2269 var colliderHeight = initializing ? targetHeight : height
2270
2271 if (offsetTop != null && scrollTop <= offsetTop) return 'top'
2272 if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
2273
2274 return false
2275 }
2276
2277 Affix.prototype.getPinnedOffset = function () {
2278 if (this.pinnedOffset) return this.pinnedOffset
2279 this.$element.removeClass(Affix.RESET).addClass('affix')
2280 var scrollTop = this.$target.scrollTop()
2281 var position = this.$element.offset()
2282 return (this.pinnedOffset = position.top - scrollTop)
2283 }
2284
2285 Affix.prototype.checkPositionWithEventLoop = function () {
2286 setTimeout($.proxy(this.checkPosition, this), 1)
2287 }
2288
2289 Affix.prototype.checkPosition = function () {
2290 if (!this.$element.is(':visible')) return
2291
2292 var height = this.$element.height()
2293 var offset = this.options.offset
2294 var offsetTop = offset.top
2295 var offsetBottom = offset.bottom
2296 var scrollHeight = Math.max($(document).height(), $(document.body).height())
2297
2298 if (typeof offset != 'object') offsetBottom = offsetTop = offset
2299 if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)
2300 if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
2301
2302 var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
2303
2304 if (this.affixed != affix) {
2305 if (this.unpin != null) this.$element.css('top', '')
2306
2307 var affixType = 'affix' + (affix ? '-' + affix : '')
2308 var e = $.Event(affixType + '.bs.affix')
2309
2310 this.$element.trigger(e)
2311
2312 if (e.isDefaultPrevented()) return
2313
2314 this.affixed = affix
2315 this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
2316
2317 this.$element
2318 .removeClass(Affix.RESET)
2319 .addClass(affixType)
2320 .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
2321 }
2322
2323 if (affix == 'bottom') {
2324 this.$element.offset({
2325 top: scrollHeight - height - offsetBottom
2326 })
2327 }
2328 }
2329
2330
2331 // AFFIX PLUGIN DEFINITION
2332 // =======================
2333
2334 function Plugin(option) {
2335 return this.each(function () {
2336 var $this = $(this)
2337 var data = $this.data('bs.affix')
2338 var options = typeof option == 'object' && option
2339
2340 if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
2341 if (typeof option == 'string') data[option]()
2342 })
2343 }
2344
2345 var old = $.fn.affix
2346
2347 $.fn.affix = Plugin
2348 $.fn.affix.Constructor = Affix
2349
2350
2351 // AFFIX NO CONFLICT
2352 // =================
2353
2354 $.fn.affix.noConflict = function () {
2355 $.fn.affix = old
2356 return this
2357 }
2358
2359
2360 // AFFIX DATA-API
2361 // ==============
2362
2363 $(window).on('load', function () {
2364 $('[data-spy="affix"]').each(function () {
2365 var $spy = $(this)
2366 var data = $spy.data()
2367
2368 data.offset = data.offset || {}
2369
2370 if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
2371 if (data.offsetTop != null) data.offset.top = data.offsetTop
2372
2373 Plugin.call($spy, data)
2374 })
2375 })
2376
2377 }(jQuery);
2378