|
1 | 1 | /* ======================================================================== |
2 | | - * Bootstrap: affix.js v3.2.0 |
3 | | - * http://getbootstrap.com/javascript/#affix |
| 2 | + * Bootstrap: affix.js v3.4.1 |
| 3 | + * https://getbootstrap.com/docs/3.4/javascript/#affix |
4 | 4 | * ======================================================================== |
5 | | - * Copyright 2011-2014 Twitter, Inc. |
| 5 | + * Copyright 2011-2019 Twitter, Inc. |
6 | 6 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) |
7 | 7 | * ======================================================================== */ |
8 | 8 |
|
|
16 | 16 | var Affix = function (element, options) { |
17 | 17 | this.options = $.extend({}, Affix.DEFAULTS, options) |
18 | 18 |
|
19 | | - this.$target = $(this.options.target) |
| 19 | + var target = this.options.target === Affix.DEFAULTS.target ? $(this.options.target) : $(document).find(this.options.target) |
| 20 | + |
| 21 | + this.$target = target |
20 | 22 | .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) |
21 | 23 | .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) |
22 | 24 |
|
23 | 25 | this.$element = $(element) |
24 | | - this.affixed = |
25 | | - this.unpin = |
| 26 | + this.affixed = null |
| 27 | + this.unpin = null |
26 | 28 | this.pinnedOffset = null |
27 | 29 |
|
28 | 30 | this.checkPosition() |
29 | 31 | } |
30 | 32 |
|
31 | | - Affix.VERSION = '3.2.0' |
| 33 | + Affix.VERSION = '3.4.1' |
32 | 34 |
|
33 | 35 | Affix.RESET = 'affix affix-top affix-bottom' |
34 | 36 |
|
|
37 | 39 | target: window |
38 | 40 | } |
39 | 41 |
|
| 42 | + Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) { |
| 43 | + var scrollTop = this.$target.scrollTop() |
| 44 | + var position = this.$element.offset() |
| 45 | + var targetHeight = this.$target.height() |
| 46 | + |
| 47 | + if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false |
| 48 | + |
| 49 | + if (this.affixed == 'bottom') { |
| 50 | + if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom' |
| 51 | + return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom' |
| 52 | + } |
| 53 | + |
| 54 | + var initializing = this.affixed == null |
| 55 | + var colliderTop = initializing ? scrollTop : position.top |
| 56 | + var colliderHeight = initializing ? targetHeight : height |
| 57 | + |
| 58 | + if (offsetTop != null && scrollTop <= offsetTop) return 'top' |
| 59 | + if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom' |
| 60 | + |
| 61 | + return false |
| 62 | + } |
| 63 | + |
40 | 64 | Affix.prototype.getPinnedOffset = function () { |
41 | 65 | if (this.pinnedOffset) return this.pinnedOffset |
42 | 66 | this.$element.removeClass(Affix.RESET).addClass('affix') |
|
52 | 76 | Affix.prototype.checkPosition = function () { |
53 | 77 | if (!this.$element.is(':visible')) return |
54 | 78 |
|
55 | | - var scrollHeight = $(document).height() |
56 | | - var scrollTop = this.$target.scrollTop() |
57 | | - var position = this.$element.offset() |
| 79 | + var height = this.$element.height() |
58 | 80 | var offset = this.options.offset |
59 | 81 | var offsetTop = offset.top |
60 | 82 | var offsetBottom = offset.bottom |
| 83 | + var scrollHeight = Math.max($(document).height(), $(document.body).height()) |
61 | 84 |
|
62 | 85 | if (typeof offset != 'object') offsetBottom = offsetTop = offset |
63 | 86 | if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element) |
64 | 87 | if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element) |
65 | 88 |
|
66 | | - var affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? false : |
67 | | - offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' : |
68 | | - offsetTop != null && (scrollTop <= offsetTop) ? 'top' : false |
| 89 | + var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom) |
69 | 90 |
|
70 | | - if (this.affixed === affix) return |
71 | | - if (this.unpin != null) this.$element.css('top', '') |
| 91 | + if (this.affixed != affix) { |
| 92 | + if (this.unpin != null) this.$element.css('top', '') |
72 | 93 |
|
73 | | - var affixType = 'affix' + (affix ? '-' + affix : '') |
74 | | - var e = $.Event(affixType + '.bs.affix') |
| 94 | + var affixType = 'affix' + (affix ? '-' + affix : '') |
| 95 | + var e = $.Event(affixType + '.bs.affix') |
75 | 96 |
|
76 | | - this.$element.trigger(e) |
| 97 | + this.$element.trigger(e) |
77 | 98 |
|
78 | | - if (e.isDefaultPrevented()) return |
| 99 | + if (e.isDefaultPrevented()) return |
79 | 100 |
|
80 | | - this.affixed = affix |
81 | | - this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null |
| 101 | + this.affixed = affix |
| 102 | + this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null |
82 | 103 |
|
83 | | - this.$element |
84 | | - .removeClass(Affix.RESET) |
85 | | - .addClass(affixType) |
86 | | - .trigger($.Event(affixType.replace('affix', 'affixed'))) |
| 104 | + this.$element |
| 105 | + .removeClass(Affix.RESET) |
| 106 | + .addClass(affixType) |
| 107 | + .trigger(affixType.replace('affix', 'affixed') + '.bs.affix') |
| 108 | + } |
87 | 109 |
|
88 | 110 | if (affix == 'bottom') { |
89 | 111 | this.$element.offset({ |
90 | | - top: scrollHeight - this.$element.height() - offsetBottom |
| 112 | + top: scrollHeight - height - offsetBottom |
91 | 113 | }) |
92 | 114 | } |
93 | 115 | } |
|
132 | 154 |
|
133 | 155 | data.offset = data.offset || {} |
134 | 156 |
|
135 | | - if (data.offsetBottom) data.offset.bottom = data.offsetBottom |
136 | | - if (data.offsetTop) data.offset.top = data.offsetTop |
| 157 | + if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom |
| 158 | + if (data.offsetTop != null) data.offset.top = data.offsetTop |
137 | 159 |
|
138 | 160 | Plugin.call($spy, data) |
139 | 161 | }) |
|
0 commit comments