1/* ============================================================= 2 * bootstrap-scrollspy.js v2.3.1 3 * http://twitter.github.com/bootstrap/javascript.html#scrollspy 4 * ============================================================= 5 * Copyright 2012 Twitter, Inc. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * ============================================================== */ 19 20 21!function ($) { 22 23 "use strict"; // jshint ;_; 24 25 26 /* SCROLLSPY CLASS DEFINITION 27 * ========================== */ 28 29 function ScrollSpy(element, options) { 30 var process = $.proxy(this.process, this) 31 , $element = $(element).is('body') ? $(window) : $(element) 32 , href 33 this.options = $.extend({}, $.fn.scrollspy.defaults, options) 34 this.$scrollElement = $element.on('scroll.scroll-spy.data-api', process) 35 this.selector = (this.options.target 36 || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 37 || '') + ' .nav li > a' 38 this.$body = $('body') 39 this.refresh() 40 this.process() 41 } 42 43 ScrollSpy.prototype = { 44 45 constructor: ScrollSpy 46 47 , refresh: function () { 48 var self = this 49 , $targets 50 51 this.offsets = $([]) 52 this.targets = $([]) 53 54 $targets = this.$body 55 .find(this.selector) 56 .map(function () { 57 var $el = $(this) 58 , href = $el.data('target') || $el.attr('href') 59 , $href = /^#\w/.test(href) && $(href) 60 return ( $href 61 && $href.length 62 && [[ $href.position().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]] ) || null 63 }) 64 .sort(function (a, b) { return a[0] - b[0] }) 65 .each(function () { 66 self.offsets.push(this[0]) 67 self.targets.push(this[1]) 68 }) 69 } 70 71 , process: function () { 72 var scrollTop = this.$scrollElement.scrollTop() + this.options.offset 73 , scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight 74 , maxScroll = scrollHeight - this.$scrollElement.height() 75 , offsets = this.offsets 76 , targets = this.targets 77 , activeTarget = this.activeTarget 78 , i 79 80 if (scrollTop >= maxScroll) { 81 return activeTarget != (i = targets.last()[0]) 82 && this.activate ( i ) 83 } 84 85 for (i = offsets.length; i--;) { 86 activeTarget != targets[i] 87 && scrollTop >= offsets[i] 88 && (!offsets[i + 1] || scrollTop <= offsets[i + 1]) 89 && this.activate( targets[i] ) 90 } 91 } 92 93 , activate: function (target) { 94 var active 95 , selector 96 97 this.activeTarget = target 98 99 $(this.selector) 100 .parent('.active') 101 .removeClass('active') 102 103 selector = this.selector 104 + '[data-target="' + target + '"],' 105 + this.selector + '[href="' + target + '"]' 106 107 active = $(selector) 108 .parent('li') 109 .addClass('active') 110 111 if (active.parent('.dropdown-menu').length) { 112 active = active.closest('li.dropdown').addClass('active') 113 } 114 115 active.trigger('activate') 116 } 117 118 } 119 120 121 /* SCROLLSPY PLUGIN DEFINITION 122 * =========================== */ 123 124 var old = $.fn.scrollspy 125 126 $.fn.scrollspy = function (option) { 127 return this.each(function () { 128 var $this = $(this) 129 , data = $this.data('scrollspy') 130 , options = typeof option == 'object' && option 131 if (!data) $this.data('scrollspy', (data = new ScrollSpy(this, options))) 132 if (typeof option == 'string') data[option]() 133 }) 134 } 135 136 $.fn.scrollspy.Constructor = ScrollSpy 137 138 $.fn.scrollspy.defaults = { 139 offset: 10 140 } 141 142 143 /* SCROLLSPY NO CONFLICT 144 * ===================== */ 145 146 $.fn.scrollspy.noConflict = function () { 147 $.fn.scrollspy = old 148 return this 149 } 150 151 152 /* SCROLLSPY DATA-API 153 * ================== */ 154 155 $(window).on('load', function () { 156 $('[data-spy="scroll"]').each(function () { 157 var $spy = $(this) 158 $spy.scrollspy($spy.data()) 159 }) 160 }) 161 162}(window.jQuery);