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