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