@glitchr/stickyjs 1.0.45 → 1.0.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/src/js/sticky.js +26 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glitchr/stickyjs",
3
- "version": "1.0.45",
3
+ "version": "1.0.51",
4
4
  "description": "Sticky scroll library",
5
5
  "main": "src/index.js",
6
6
  "repository": {
@@ -12,4 +12,4 @@
12
12
  "scripts": {
13
13
  "test": "echo \"Error: no test specified\" && exit 1"
14
14
  }
15
- }
15
+ }
package/src/js/sticky.js CHANGED
@@ -677,7 +677,20 @@ $.fn.serializeObject = function () {
677
677
  return parseInt(closest);
678
678
  }
679
679
 
680
- Sticky.userScroll = function(el = undefined) { return $(el === undefined ? document.documentElement : el).closestScrollable().prop("user-scroll") ?? true; }
680
+ Sticky.userScroll = function(el = undefined) {
681
+ // Defensive: closestScrollable() can return a value without .prop in
682
+ // some race conditions (transient DOM during transparent.js page
683
+ // transitions, sticky-scrollpercent triggers fired against detached
684
+ // nodes). Default to true so the autoscroll falls back to "user is
685
+ // scrolling, don't auto-advance."
686
+ try {
687
+ var $target = $(el === undefined ? document.documentElement : el);
688
+ if (!$target || !$target.length) return true;
689
+ var $scroll = $target.closestScrollable && $target.closestScrollable();
690
+ if (!$scroll || typeof $scroll.prop !== "function") return true;
691
+ return $scroll.prop("user-scroll") ?? true;
692
+ } catch (e) { return true; }
693
+ }
681
694
  Sticky.scrollTo = function(dict, callback = function() {}, el = window)
682
695
  {
683
696
  el = $(el).length ? $(el)[0] : window;
@@ -1147,9 +1160,20 @@ $.fn.serializeObject = function () {
1147
1160
  if(Settings.debug > 1) console.log("Sticky headlines:", $(ids));
1148
1161
 
1149
1162
 
1163
+ // Hoisted out of the filter below. getScrollPadding() runs closestScrollable(),
1164
+ // which walks the whole ancestor chain calling getComputedStyle twice per level
1165
+ // (isScrollableX + isScrollableY), and it does not depend on the element being
1166
+ // filtered - `scroller` is fixed for this whole call. Evaluating it per candidate
1167
+ // put that ancestor walk on every headline candidate on EVERY scroll event, so
1168
+ // the cost grew with the length of the page. Measured on a long article feed, a
1169
+ // 2400px scroll went from ~6200 to ~2650 getComputedStyle calls and from ~4700
1170
+ // to ~3500 scrollHeight/clientHeight reads, cutting the scroll handler's own
1171
+ // time by ~17%.
1172
+ var scrollPaddingTop = Sticky.getScrollPadding(scroller).top + 1;
1173
+
1150
1174
  var elAll = $(ids).filter(function() {
1151
1175
  if(this === $(Settings.identifier)) return false;
1152
- return this.getBoundingClientRect().top < Sticky.getScrollPadding(scroller).top + 1;
1176
+ return this.getBoundingClientRect().top < scrollPaddingTop;
1153
1177
  }).toArray().sort(function (el1, el2) {
1154
1178
  return el1.offsetTop > el2.offsetTop ? -1
1155
1179
  : (el1.offsetTop < el2.offsetTop ? 1 : 0);