@brandocms/jupiter 3.54.1 → 3.54.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brandocms/jupiter",
3
- "version": "3.54.1",
3
+ "version": "3.54.2",
4
4
  "description": "Frontend helpers.",
5
5
  "author": "Univers/Twined",
6
6
  "license": "UNLICENSED",
@@ -12,10 +12,10 @@ import Dom from '../Dom'
12
12
 
13
13
  gsap.registerPlugin(ScrollToPlugin)
14
14
  gsap.defaults({
15
- ease: 'sine.out'
15
+ ease: 'sine.out',
16
16
  })
17
17
 
18
- window.onpageshow = event => {
18
+ window.onpageshow = (event) => {
19
19
  if (event.persisted) {
20
20
  const f = document.querySelector('#fader')
21
21
  if (f) {
@@ -46,7 +46,7 @@ window.onpageshow = event => {
46
46
  const DEFAULT_OPTIONS = {
47
47
  respectReducedMotion: true,
48
48
  featureTests: {
49
- touch: true
49
+ touch: true,
50
50
  },
51
51
 
52
52
  focusableSelectors: [
@@ -55,7 +55,7 @@ const DEFAULT_OPTIONS = {
55
55
  'select',
56
56
  'button',
57
57
  'textarea',
58
- 'iframe' // , 'video'?
58
+ 'iframe', // , 'video'?
59
59
  ],
60
60
 
61
61
  bindScroll: true,
@@ -79,10 +79,10 @@ const DEFAULT_OPTIONS = {
79
79
  gsap.set(fader, { display: 'none' })
80
80
  document.body.classList.remove('unloaded')
81
81
  callback()
82
- }
82
+ },
83
83
  })
84
- }
85
- }
84
+ },
85
+ },
86
86
  }
87
87
 
88
88
  export default class Application {
@@ -101,16 +101,17 @@ export default class Application {
101
101
  initialOuterHeight: 0,
102
102
  initialInnerWidth: 0,
103
103
  initialOuterWidth: 0,
104
- zoom: 1
104
+ zoom: 1,
105
105
  }
106
106
 
107
107
  this.position = {
108
108
  top: 0,
109
- left: 0
109
+ left: 0,
110
110
  }
111
111
 
112
112
  this.state = {
113
- revealed: false
113
+ revealed: false,
114
+ forcedScroll: false,
114
115
  }
115
116
 
116
117
  this.opts = _defaultsDeep(opts, DEFAULT_OPTIONS)
@@ -144,33 +145,48 @@ export default class Application {
144
145
  gsap.globalTimeline.timeScale(200)
145
146
  document.documentElement.classList.add('prefers-reduced-motion')
146
147
  }
147
- window.addEventListener(Events.BREAKPOINT_CHANGE, this.onBreakpointChanged.bind(this))
148
+ window.addEventListener(
149
+ Events.BREAKPOINT_CHANGE,
150
+ this.onBreakpointChanged.bind(this)
151
+ )
148
152
 
149
- this.beforeInitializedEvent = new window.CustomEvent(Events.APPLICATION_PRELUDIUM, this)
150
- this.initializedEvent = new window.CustomEvent(Events.APPLICATION_INITIALIZED, this)
153
+ this.beforeInitializedEvent = new window.CustomEvent(
154
+ Events.APPLICATION_PRELUDIUM,
155
+ this
156
+ )
157
+ this.initializedEvent = new window.CustomEvent(
158
+ Events.APPLICATION_INITIALIZED,
159
+ this
160
+ )
151
161
  this.readyEvent = new window.CustomEvent(Events.APPLICATION_READY, this)
152
- this.revealedEvent = new window.CustomEvent(Events.APPLICATION_REVEALED, this)
162
+ this.revealedEvent = new window.CustomEvent(
163
+ Events.APPLICATION_REVEALED,
164
+ this
165
+ )
153
166
 
154
167
  /**
155
168
  * Grab common events and defer
156
169
  */
157
- document.addEventListener('visibilitychange', this.onVisibilityChange.bind(this))
170
+ document.addEventListener(
171
+ 'visibilitychange',
172
+ this.onVisibilityChange.bind(this)
173
+ )
158
174
  window.addEventListener('orientationchange', this.onResize.bind(this), {
159
175
  capture: false,
160
- passive: true
176
+ passive: true,
161
177
  })
162
178
 
163
179
  if (opts.bindScroll) {
164
180
  window.addEventListener('scroll', rafCallback(this.onScroll.bind(this)), {
165
181
  capture: false,
166
- passive: true
182
+ passive: true,
167
183
  })
168
184
  }
169
185
 
170
186
  if (opts.bindResize) {
171
187
  window.addEventListener('resize', rafCallback(this.onResize.bind(this)), {
172
188
  capture: false,
173
- passive: true
189
+ passive: true,
174
190
  })
175
191
  }
176
192
  }
@@ -208,7 +224,10 @@ export default class Application {
208
224
  break
209
225
 
210
226
  case 'safari':
211
- this._zoomSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
227
+ this._zoomSVG = document.createElementNS(
228
+ 'http://www.w3.org/2000/svg',
229
+ 'svg'
230
+ )
212
231
  this._zoomSVG.setAttribute('xmlns', 'http://www.w3.org/2000/svg')
213
232
  this._zoomSVG.setAttribute('version', '1.1')
214
233
  gsap.set(this._zoomSVG, { display: 'none' })
@@ -252,13 +271,17 @@ export default class Application {
252
271
  default:
253
272
  if ([1, -1].indexOf(dprDelta) === -1) {
254
273
  if (dimsChanged) {
255
- this.size.zoom = 1 + (zoom.calculate(this.browser) - this._initialZoom)
274
+ this.size.zoom =
275
+ 1 + (zoom.calculate(this.browser) - this._initialZoom)
256
276
  if (this.size.zoom === 0) {
257
277
  this.size.zoom = 1
258
278
  }
259
279
  }
260
280
  } else {
261
- this._initialZoom = Math.min(Math.max(this._initialZoom - dprDelta, 1), 2)
281
+ this._initialZoom = Math.min(
282
+ Math.max(this._initialZoom - dprDelta, 1),
283
+ 2
284
+ )
262
285
  }
263
286
  }
264
287
 
@@ -289,7 +312,7 @@ export default class Application {
289
312
  if (!Object.prototype.hasOwnProperty.call(this.callbacks, type)) {
290
313
  return
291
314
  }
292
- this.callbacks[type].forEach(cb => cb(this))
315
+ this.callbacks[type].forEach((cb) => cb(this))
293
316
  }
294
317
 
295
318
  /**
@@ -325,7 +348,9 @@ export default class Application {
325
348
  window.dispatchEvent(ev)
326
349
  this.SCROLL_LOCKED = true
327
350
  gsap.set(document.body, { overflow: 'hidden' })
328
- gsap.set(this._scrollPaddedElements, { paddingRight: currentScrollbarWidth })
351
+ gsap.set(this._scrollPaddedElements, {
352
+ paddingRight: currentScrollbarWidth,
353
+ })
329
354
  document.addEventListener('touchmove', this.scrollVoid, false)
330
355
  }
331
356
 
@@ -350,7 +375,10 @@ export default class Application {
350
375
  */
351
376
  scrollTo(target, time = 0.8, emitEvents = true, ease = 'sine.inOut') {
352
377
  let scrollToData
353
- const forcedScrollEventStart = new window.CustomEvent(Events.APPLICATION_FORCED_SCROLL_START)
378
+ const forcedScrollEventStart = new window.CustomEvent(
379
+ Events.APPLICATION_FORCED_SCROLL_START
380
+ )
381
+ this.state.forcedScroll = true
354
382
  if (emitEvents) {
355
383
  window.dispatchEvent(forcedScrollEventStart)
356
384
  }
@@ -365,12 +393,15 @@ export default class Application {
365
393
  duration: time,
366
394
  scrollTo: scrollToData,
367
395
  onComplete: () => {
368
- const forcedScrollEventEnd = new window.CustomEvent(Events.APPLICATION_FORCED_SCROLL_END)
396
+ const forcedScrollEventEnd = new window.CustomEvent(
397
+ Events.APPLICATION_FORCED_SCROLL_END
398
+ )
369
399
  if (emitEvents) {
370
400
  window.dispatchEvent(forcedScrollEventEnd)
401
+ requestAnimationFrame(() => (this.state.forcedScroll = false))
371
402
  }
372
403
  },
373
- ease
404
+ ease,
374
405
  })
375
406
  }
376
407
 
@@ -516,10 +547,22 @@ export default class Application {
516
547
  this.size.initialOuterWidth = window.outerWidth
517
548
  this.size.scrollHeight = document.body.scrollHeight
518
549
 
519
- root.style.setProperty('--vp-initial-inner-h', `${this.size.initialInnerHeight}px`)
520
- root.style.setProperty('--vp-initial-outer-h', `${this.size.initialOuterHeight}px`)
521
- root.style.setProperty('--vp-initial-inner-w', `${this.size.initialInnerWidth}px`)
522
- root.style.setProperty('--vp-initial-outer-w', `${this.size.initialOuterWidth}px`)
550
+ root.style.setProperty(
551
+ '--vp-initial-inner-h',
552
+ `${this.size.initialInnerHeight}px`
553
+ )
554
+ root.style.setProperty(
555
+ '--vp-initial-outer-h',
556
+ `${this.size.initialOuterHeight}px`
557
+ )
558
+ root.style.setProperty(
559
+ '--vp-initial-inner-w',
560
+ `${this.size.initialInnerWidth}px`
561
+ )
562
+ root.style.setProperty(
563
+ '--vp-initial-outer-w',
564
+ `${this.size.initialOuterWidth}px`
565
+ )
523
566
  root.style.setProperty('--ec-zoom', `${this.size.zoom}`)
524
567
  root.style.setProperty('--scroll-h', `${this.size.scrollHeight}px`)
525
568
 
@@ -551,7 +594,9 @@ export default class Application {
551
594
  */
552
595
  setvh100() {
553
596
  const root = document.querySelector(':root')
554
- const height = this.featureTests.results.ios ? screen.height : window.innerHeight
597
+ const height = this.featureTests.results.ios
598
+ ? screen.height
599
+ : window.innerHeight
555
600
  root.style.setProperty('--vp-100vh', `${height}px`)
556
601
  root.style.setProperty('--vp-1vh', `${height * 0.01}px`)
557
602
  }
@@ -603,7 +648,7 @@ export default class Application {
603
648
  this.setFontBaseVw()
604
649
 
605
650
  const evt = new CustomEvent(Events.APPLICATION_RESIZE, {
606
- detail: { widthChanged, heightChanged }
651
+ detail: { widthChanged, heightChanged },
607
652
  })
608
653
  window.dispatchEvent(evt)
609
654
  }
@@ -672,9 +717,13 @@ export default class Application {
672
717
 
673
718
  const span = userAgent.querySelector('span')
674
719
  const windowWidth =
675
- window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
720
+ window.innerWidth ||
721
+ document.documentElement.clientWidth ||
722
+ document.body.clientWidth
676
723
  const windowHeight =
677
- window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
724
+ window.innerHeight ||
725
+ document.documentElement.clientHeight ||
726
+ document.body.clientHeight
678
727
 
679
728
  span.addEventListener('click', () => {
680
729
  const copyText = userAgent.querySelector('b')
@@ -724,7 +773,7 @@ ${JSON.stringify(this.featureTests.results, undefined, 2)}
724
773
  gsap.set(breakpoint, { width: 'auto', display: 'block' })
725
774
  tl.from(breakpoint, { duration: 0.7, width: 0 }).to(breakpoint, {
726
775
  duration: 0.3,
727
- autoAlpha: 1
776
+ autoAlpha: 1,
728
777
  })
729
778
  break
730
779
 
@@ -733,7 +782,7 @@ ${JSON.stringify(this.featureTests.results, undefined, 2)}
733
782
  gsap.set(userAgent, { width: 'auto', display: 'block' })
734
783
  tl.from(userAgent, { duration: 0.7, width: 0 }).to(userAgent, {
735
784
  duration: 0.3,
736
- autoAlpha: 1
785
+ autoAlpha: 1,
737
786
  })
738
787
  break
739
788
 
@@ -746,7 +795,7 @@ ${JSON.stringify(this.featureTests.results, undefined, 2)}
746
795
  * CTRL-G to show grid overlay
747
796
  */
748
797
  setupGridoverlay() {
749
- const gridKeyPressed = e => {
798
+ const gridKeyPressed = (e) => {
750
799
  if (e.keyCode === 71 && e.ctrlKey) {
751
800
  const guides = Dom.find('.dbg-grid')
752
801
  const cols = Dom.all(guides, 'b')
@@ -764,7 +813,7 @@ ${JSON.stringify(this.featureTests.results, undefined, 2)}
764
813
  ease: 'sine.inOut',
765
814
  onComplete: () => {
766
815
  guides.classList.toggle('visible')
767
- }
816
+ },
768
817
  })
769
818
  } else {
770
819
  gsap.set(cols, { width: 0 })
@@ -773,7 +822,7 @@ ${JSON.stringify(this.featureTests.results, undefined, 2)}
773
822
  duration: 0.35,
774
823
  width: '100%',
775
824
  stagger: 0.02,
776
- ease: 'sine.inOut'
825
+ ease: 'sine.inOut',
777
826
  })
778
827
  }
779
828
  }
@@ -42,7 +42,7 @@ const DEFAULT_OPTIONS = {
42
42
  page: 0,
43
43
  loaderParam: {},
44
44
  filter: '',
45
- onFetch: dataloader => {
45
+ onFetch: (dataloader) => {
46
46
  /**
47
47
  * Called after fetch complete. Do your DOM manipulation here
48
48
  *
@@ -53,7 +53,7 @@ const DEFAULT_OPTIONS = {
53
53
  * new EqualHeightImages(dataloader.app, {}, dataloader.$canvasEl)
54
54
  * mw.ready()
55
55
  */
56
- }
56
+ },
57
57
  }
58
58
 
59
59
  export default class Dataloader {
@@ -71,12 +71,12 @@ export default class Dataloader {
71
71
  }
72
72
 
73
73
  static replaceInnerHTML(el, url) {
74
- return new Promise(resolve => {
74
+ return new Promise((resolve) => {
75
75
  fetch(url)
76
- .then(res => {
76
+ .then((res) => {
77
77
  return res.text()
78
78
  })
79
- .then(html => {
79
+ .then((html) => {
80
80
  el.innerHTML = html
81
81
  return resolve(el)
82
82
  })
@@ -101,7 +101,7 @@ export default class Dataloader {
101
101
  this.baseURL = this.$el.dataset.loader
102
102
  this.$paramEls = Dom.all(this.$el, '[data-loader-param]')
103
103
 
104
- this.$paramEls.forEach($paramEl => {
104
+ this.$paramEls.forEach(($paramEl) => {
105
105
  $paramEl.addEventListener('click', this.onParam.bind(this))
106
106
  })
107
107
 
@@ -119,7 +119,10 @@ export default class Dataloader {
119
119
  }
120
120
 
121
121
  if (this.$filterInput) {
122
- this.$filterInput.addEventListener('input', this.debounce(this.onFilterInput.bind(this)))
122
+ this.$filterInput.addEventListener(
123
+ 'input',
124
+ this.debounce(this.onFilterInput.bind(this))
125
+ )
123
126
  }
124
127
  }
125
128
 
@@ -156,14 +159,15 @@ export default class Dataloader {
156
159
  // if already selected, clear it
157
160
  const key = e.currentTarget.dataset.loaderParamKey || 'defaultParam'
158
161
  if (multiVals) {
159
- this.opts.loaderParam[key] = this.opts.loaderParam[key].filter(val => {
160
- return val !== e.currentTarget.dataset.loaderParam
161
- })
162
+ this.opts.loaderParam[key] = this.opts.loaderParam[key].filter(
163
+ (val) => {
164
+ return val !== e.currentTarget.dataset.loaderParam
165
+ }
166
+ )
162
167
  } else {
163
168
  delete this.opts.loaderParam[key]
164
169
  }
165
170
  e.currentTarget.removeAttribute('data-loader-param-selected')
166
- console.log(this.opts.loaderParam[key])
167
171
  } else {
168
172
  if (multiVals) {
169
173
  const key = e.currentTarget.dataset.loaderParamKey || 'defaultParam'
@@ -174,7 +178,7 @@ export default class Dataloader {
174
178
  e.currentTarget.setAttribute('data-loader-param-selected', '')
175
179
  } else {
176
180
  const paramKey = e.currentTarget.dataset.loaderParamKey
177
- this.$paramEls.forEach($paramEl => {
181
+ this.$paramEls.forEach(($paramEl) => {
178
182
  if (paramKey) {
179
183
  if ($paramEl.dataset.loaderParamKey === paramKey) {
180
184
  $paramEl.removeAttribute('data-loader-param-selected')
@@ -201,12 +205,12 @@ export default class Dataloader {
201
205
  `${this.baseURL}/${defaultParam ? defaultParam + '/' : ''}${this.opts.page}?` +
202
206
  new URLSearchParams({ filter, ...otherParams })
203
207
  )
204
- .then(res => {
208
+ .then((res) => {
205
209
  this.status = res.headers.get('jpt-dataloader') || 'available'
206
210
  this.updateButton()
207
211
  return res.text()
208
212
  })
209
- .then(html => {
213
+ .then((html) => {
210
214
  if (addEntries) {
211
215
  this.$canvasEl.innerHTML += html
212
216
  } else {
@@ -29,16 +29,16 @@ import * as Events from '../../events'
29
29
  import Dom from '../Dom'
30
30
 
31
31
  const DEFAULT_EVENTS = {
32
- onPin: h => {
32
+ onPin: (h) => {
33
33
  gsap.to(h.el, {
34
34
  duration: 0.35,
35
35
  yPercent: '0',
36
36
  ease: 'sine.out',
37
- autoRound: true
37
+ autoRound: true,
38
38
  })
39
39
  },
40
40
 
41
- onUnpin: h => {
41
+ onUnpin: (h) => {
42
42
  h._hiding = true
43
43
  gsap.to(h.el, {
44
44
  duration: 0.25,
@@ -47,50 +47,50 @@ const DEFAULT_EVENTS = {
47
47
  autoRound: true,
48
48
  onComplete: () => {
49
49
  h._hiding = false
50
- }
50
+ },
51
51
  })
52
52
  },
53
53
 
54
- onAltBg: h => {
54
+ onAltBg: (h) => {
55
55
  if (h.opts.altBgColor) {
56
56
  gsap.to(h.el, {
57
57
  duration: 0.2,
58
- backgroundColor: h.opts.altBgColor
58
+ backgroundColor: h.opts.altBgColor,
59
59
  })
60
60
  }
61
61
  },
62
62
 
63
- onNotAltBg: h => {
63
+ onNotAltBg: (h) => {
64
64
  if (h.opts.regBgColor) {
65
65
  gsap.to(h.el, {
66
66
  duration: 0.4,
67
- backgroundColor: h.opts.regBgColor
67
+ backgroundColor: h.opts.regBgColor,
68
68
  })
69
69
  }
70
70
  },
71
71
 
72
72
  // eslint-disable-next-line no-unused-vars
73
- onSmall: h => {},
73
+ onSmall: (h) => {},
74
74
  // eslint-disable-next-line no-unused-vars
75
- onNotSmall: h => {},
75
+ onNotSmall: (h) => {},
76
76
  // eslint-disable-next-line no-unused-vars
77
- onTop: h => {},
77
+ onTop: (h) => {},
78
78
  // eslint-disable-next-line no-unused-vars
79
- onNotTop: h => {},
79
+ onNotTop: (h) => {},
80
80
  // eslint-disable-next-line no-unused-vars
81
- onBottom: h => {},
81
+ onBottom: (h) => {},
82
82
  // eslint-disable-next-line no-unused-vars
83
- onNotBottom: h => {},
83
+ onNotBottom: (h) => {},
84
84
  // eslint-disable-next-line no-unused-vars
85
- onMobileMenuOpen: h => {},
85
+ onMobileMenuOpen: (h) => {},
86
86
  // eslint-disable-next-line no-unused-vars
87
- onMobileMenuClose: h => {},
87
+ onMobileMenuClose: (h) => {},
88
88
  // eslint-disable-next-line no-unused-vars
89
- onIntersect: h => {},
90
- onOutline: h => {
89
+ onIntersect: (h) => {},
90
+ onOutline: (h) => {
91
91
  h.preventUnpin = true
92
92
  h.pin()
93
- }
93
+ },
94
94
  }
95
95
 
96
96
  const DEFAULT_OPTIONS = {
@@ -98,18 +98,19 @@ const DEFAULT_OPTIONS = {
98
98
  on: Events.APPLICATION_REVEALED,
99
99
  unpinOnForcedScrollStart: true,
100
100
  pinOnForcedScrollEnd: true,
101
+ ignoreForcedScroll: false,
101
102
  rafScroll: true,
102
103
 
103
104
  default: {
104
105
  unPinOnResize: true,
105
106
  canvas: window,
106
107
  intersects: null,
107
- beforeEnter: h => {
108
+ beforeEnter: (h) => {
108
109
  const timeline = gsap.timeline()
109
110
  timeline.set(h.el, { yPercent: -100 }).set(h.lis, { opacity: 0 })
110
111
  },
111
112
 
112
- enter: h => {
113
+ enter: (h) => {
113
114
  const timeline = gsap.timeline()
114
115
  timeline
115
116
  .to(h.el, {
@@ -117,7 +118,7 @@ const DEFAULT_OPTIONS = {
117
118
  yPercent: 0,
118
119
  delay: h.opts.enterDelay,
119
120
  ease: 'power3.out',
120
- autoRound: true
121
+ autoRound: true,
121
122
  })
122
123
  .staggerTo(h.lis, 0.8, { opacity: 1, ease: 'sine.in' }, 0.1, '-=1')
123
124
  },
@@ -129,8 +130,8 @@ const DEFAULT_OPTIONS = {
129
130
  offsetBg: 200, // how far down before changing backgroundcolor
130
131
  regBgColor: null,
131
132
  altBgColor: null,
132
- ...DEFAULT_EVENTS
133
- }
133
+ ...DEFAULT_EVENTS,
134
+ },
134
135
  }
135
136
 
136
137
  export default class FixedHeader {
@@ -223,7 +224,11 @@ export default class FixedHeader {
223
224
  }
224
225
 
225
226
  if (this.mainOpts.pinOnForcedScrollEnd) {
226
- window.addEventListener(Events.APPLICATION_FORCED_SCROLL_END, this.pin.bind(this), false)
227
+ window.addEventListener(
228
+ Events.APPLICATION_FORCED_SCROLL_END,
229
+ this.pin.bind(this),
230
+ false
231
+ )
227
232
  }
228
233
 
229
234
  this.app.registerCallback(Events.APPLICATION_REVEALED, () => {
@@ -234,11 +239,14 @@ export default class FixedHeader {
234
239
 
235
240
  window.addEventListener(SCROLL_EVENT, this.redraw.bind(this), {
236
241
  capture: false,
237
- passive: true
242
+ passive: true,
238
243
  })
239
244
  })
240
245
 
241
- this.app.registerCallback(Events.APPLICATION_READY, this.unpinIfScrolled.bind(this))
246
+ this.app.registerCallback(
247
+ Events.APPLICATION_READY,
248
+ this.unpinIfScrolled.bind(this)
249
+ )
242
250
 
243
251
  this.preflight()
244
252
 
@@ -248,7 +256,11 @@ export default class FixedHeader {
248
256
 
249
257
  // DON'T unpin on iOS since this will unpin when bottom menu bar appears on scrolling upwards!
250
258
  if (this.opts.unPinOnResize && !this.app.featureTests.results.ios) {
251
- window.addEventListener(Events.APPLICATION_RESIZE, this.setResizeTimer.bind(this), false)
259
+ window.addEventListener(
260
+ Events.APPLICATION_RESIZE,
261
+ this.setResizeTimer.bind(this),
262
+ false
263
+ )
252
264
  }
253
265
 
254
266
  this.opts.beforeEnter(this)
@@ -367,7 +379,10 @@ export default class FixedHeader {
367
379
  }
368
380
 
369
381
  checkBot(force) {
370
- if (this.currentScrollY + this.getViewportHeight() >= this.getScrollerHeight()) {
382
+ if (
383
+ this.currentScrollY + this.getViewportHeight() >=
384
+ this.getScrollerHeight()
385
+ ) {
371
386
  if (force) {
372
387
  this.bottom()
373
388
  } else if (!this._bottom) {
@@ -411,7 +426,10 @@ export default class FixedHeader {
411
426
 
412
427
  /* content-visibility: auto may CHANGE the scrollheight of the document
413
428
  as we roll down/up. Try to avoid false positives here */
414
- if (this.currentScrollHeight !== this.lastKnownScrollHeight && !this._firstLoad) {
429
+ if (
430
+ this.currentScrollHeight !== this.lastKnownScrollHeight &&
431
+ !this._firstLoad
432
+ ) {
415
433
  this.lastKnownScrollY = this.currentScrollY
416
434
  this.lastKnownScrollHeight = this.currentScrollHeight
417
435
  return
@@ -421,7 +439,12 @@ export default class FixedHeader {
421
439
  this.checkBg(false)
422
440
  this.checkTop(false)
423
441
  this.checkBot(false)
424
- this.checkPin(false, toleranceExceeded)
442
+
443
+ if (this.mainOpts.ignoreForcedScroll && this.app.state.forcedScroll) {
444
+ // ignore forced scroll
445
+ } else {
446
+ this.checkPin(false, toleranceExceeded)
447
+ }
425
448
 
426
449
  this.lastKnownScrollY = this.currentScrollY
427
450
  this.lastKnownScrollHeight = this.currentScrollHeight
@@ -526,7 +549,8 @@ export default class FixedHeader {
526
549
  isOutOfBounds() {
527
550
  const pastTop = this.currentScrollY < 0
528
551
  const pastBottom =
529
- this.currentScrollY + this.getScrollerPhysicalHeight() > this.getScrollerHeight()
552
+ this.currentScrollY + this.getScrollerPhysicalHeight() >
553
+ this.getScrollerHeight()
530
554
 
531
555
  return pastTop || pastBottom
532
556
  }
@@ -559,7 +583,9 @@ export default class FixedHeader {
559
583
 
560
584
  getViewportHeight() {
561
585
  return (
562
- window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
586
+ window.innerHeight ||
587
+ document.documentElement.clientHeight ||
588
+ document.body.clientHeight
563
589
  )
564
590
  }
565
591
 
@@ -578,11 +604,18 @@ export default class FixedHeader {
578
604
  if (this.opts.canvas.scrollTop !== undefined) {
579
605
  return this.opts.canvas.scrollTop
580
606
  }
581
- return (document.documentElement || document.body.parentNode || document.body).scrollTop
607
+ return (
608
+ document.documentElement ||
609
+ document.body.parentNode ||
610
+ document.body
611
+ ).scrollTop
582
612
  }
583
613
 
584
614
  toleranceExceeded() {
585
- return Math.abs(this.currentScrollY - this.lastKnownScrollY) >= this.opts.tolerance
615
+ return (
616
+ Math.abs(this.currentScrollY - this.lastKnownScrollY) >=
617
+ this.opts.tolerance
618
+ )
586
619
  }
587
620
 
588
621
  _getOptionsForSection(section, opts) {
@@ -601,8 +634,14 @@ export default class FixedHeader {
601
634
  }
602
635
 
603
636
  _bindMobileMenuListeners() {
604
- window.addEventListener('APPLICATION:MOBILE_MENU:OPEN', this._onMobileMenuOpen.bind(this))
605
- window.addEventListener('APPLICATION:MOBILE_MENU:CLOSED', this._onMobileMenuClose.bind(this))
637
+ window.addEventListener(
638
+ 'APPLICATION:MOBILE_MENU:OPEN',
639
+ this._onMobileMenuOpen.bind(this)
640
+ )
641
+ window.addEventListener(
642
+ 'APPLICATION:MOBILE_MENU:CLOSED',
643
+ this._onMobileMenuClose.bind(this)
644
+ )
606
645
  }
607
646
 
608
647
  _onMobileMenuOpen() {
@@ -7,17 +7,17 @@ import * as Events from '../../events'
7
7
  const DEFAULT_OPTIONS = {
8
8
  revealIntersectionObserverConfig: {
9
9
  rootMargin: '0px 100px 0px 100px',
10
- threshold: 0.0
10
+ threshold: 0.0,
11
11
  },
12
12
  loadIntersectionObserverConfig: {
13
13
  rootMargin: '850px 500px 850px 500px',
14
- threshold: 0.0
14
+ threshold: 0.0,
15
15
  },
16
16
  useNativeLazyloadIfAvailable: true,
17
17
  mode: 'default',
18
18
  minSize: 40,
19
19
  updateSizes: true,
20
- registerCallback: true
20
+ registerCallback: true,
21
21
  }
22
22
 
23
23
  export default class Lazyload {
@@ -49,16 +49,21 @@ export default class Lazyload {
49
49
  this.initializeSections()
50
50
 
51
51
  // if we have native lazyload, use it.
52
- if ('loading' in HTMLImageElement.prototype && this.opts.useNativeLazyloadIfAvailable) {
52
+ if (
53
+ 'loading' in HTMLImageElement.prototype &&
54
+ this.opts.useNativeLazyloadIfAvailable
55
+ ) {
53
56
  const lazyImages = document.querySelectorAll('[data-ll-image]')
54
- lazyImages.forEach(img => {
57
+ lazyImages.forEach((img) => {
55
58
  img.setAttribute('loading', 'lazy')
56
59
  this.swapImage(img)
57
60
  })
58
61
 
59
62
  const lazyPictures = document.querySelectorAll('[data-ll-srcset]')
60
- lazyPictures.forEach(picture => {
61
- picture.querySelectorAll('img').forEach(img => img.setAttribute('loading', 'lazy'))
63
+ lazyPictures.forEach((picture) => {
64
+ picture
65
+ .querySelectorAll('img')
66
+ .forEach((img) => img.setAttribute('loading', 'lazy'))
62
67
  this.swapPicture(picture)
63
68
  })
64
69
 
@@ -98,7 +103,7 @@ export default class Lazyload {
98
103
  this.lazyPictures.forEach((picture, idx) => {
99
104
  if (setAttrs) {
100
105
  picture.setAttribute('data-ll-srcset-initialized', '')
101
- picture.querySelectorAll('img:not([data-ll-loaded])').forEach(img => {
106
+ picture.querySelectorAll('img:not([data-ll-loaded])').forEach((img) => {
102
107
  img.setAttribute('data-ll-blurred', '')
103
108
  img.setAttribute('data-ll-idx', idx)
104
109
  img.style.setProperty('--ll-idx', idx)
@@ -108,6 +113,14 @@ export default class Lazyload {
108
113
  })
109
114
  }
110
115
 
116
+ forceLoad($container = document.body) {
117
+ const images = Dom.all($container, '[data-ll-image]')
118
+ images.forEach((img) => this.swapImage(img))
119
+
120
+ const pictures = Dom.all($container, '[data-ll-srcset]')
121
+ pictures.forEach((picture) => this.revealPicture(picture))
122
+ }
123
+
111
124
  initializeAutoSizes() {
112
125
  if (this.opts.updateSizes) {
113
126
  this.$autoSizesImages = Dom.all('[data-sizes="auto"]')
@@ -120,11 +133,11 @@ export default class Lazyload {
120
133
  * Set sizes attribute for all imgs with `data-sizes="auto"` and source within the <picture>
121
134
  */
122
135
  autoSizes() {
123
- Array.from(this.$autoSizesImages).forEach(img => {
136
+ Array.from(this.$autoSizesImages).forEach((img) => {
124
137
  const width = this.getWidth(img)
125
138
  img.setAttribute('sizes', `${width}px`)
126
139
  if (img.parentNode) {
127
- Array.from(Dom.all(img.parentNode, 'source')).forEach(source =>
140
+ Array.from(Dom.all(img.parentNode, 'source')).forEach((source) =>
128
141
  source.setAttribute('sizes', `${width}px`)
129
142
  )
130
143
  }
@@ -149,12 +162,12 @@ export default class Lazyload {
149
162
  const sectionObserver = (section, children) => {
150
163
  const imagesInSection = Dom.all(section, 'img')
151
164
  return new IntersectionObserver((entries, self) => {
152
- entries.forEach(entry => {
165
+ entries.forEach((entry) => {
153
166
  if (entry.isIntersecting || entry.intersectionRatio > 0) {
154
167
  imagesAreLoaded(imagesInSection, true).then(() => {
155
168
  dispatchElementEvent(section, Events.SECTION_LAZYLOADED)
156
169
  })
157
- children.forEach(picture => {
170
+ children.forEach((picture) => {
158
171
  this.loadPicture(picture)
159
172
  this.loadObserver.unobserve(picture)
160
173
  })
@@ -164,7 +177,7 @@ export default class Lazyload {
164
177
  }, this.opts.intersectionObserverConfig)
165
178
  }
166
179
 
167
- sections.forEach(section => {
180
+ sections.forEach((section) => {
168
181
  const children = section.querySelectorAll('picture')
169
182
  const obs = sectionObserver(section, children)
170
183
  obs.observe(section)
@@ -174,7 +187,7 @@ export default class Lazyload {
174
187
 
175
188
  // we load the picture a ways before it enters the viewport
176
189
  handleLoadEntries(elements) {
177
- elements.forEach(item => {
190
+ elements.forEach((item) => {
178
191
  if (item.isIntersecting || item.intersectionRatio > 0) {
179
192
  const picture = item.target
180
193
  this.loadPicture(picture)
@@ -185,16 +198,19 @@ export default class Lazyload {
185
198
 
186
199
  // we reveal the picture when it enters the viewport
187
200
  handleRevealEntries(elements) {
188
- const srcsetReadyObserver = new MutationObserver(mutations => {
189
- mutations.forEach(record => {
190
- if (record.type === 'attributes' && record.attributeName === 'data-ll-srcset-ready') {
201
+ const srcsetReadyObserver = new MutationObserver((mutations) => {
202
+ mutations.forEach((record) => {
203
+ if (
204
+ record.type === 'attributes' &&
205
+ record.attributeName === 'data-ll-srcset-ready'
206
+ ) {
191
207
  this.revealPicture(record.target)
192
208
  this.revealObserver.unobserve(record.target)
193
209
  }
194
210
  })
195
211
  })
196
212
 
197
- elements.forEach(item => {
213
+ elements.forEach((item) => {
198
214
  if (item.isIntersecting || item.intersectionRatio > 0) {
199
215
  const picture = item.target
200
216
  const ready = item.target.hasAttribute('data-ll-srcset-ready')
@@ -233,7 +249,10 @@ export default class Lazyload {
233
249
  const img = picture.querySelector('img')
234
250
 
235
251
  const onload = () => {
236
- if (!img.getAttribute('data-ll-ready') && this.app.browser === 'firefox') {
252
+ if (
253
+ !img.getAttribute('data-ll-ready') &&
254
+ this.app.browser === 'firefox'
255
+ ) {
237
256
  // set sizes attribute on load again,
238
257
  // since firefox sometimes is a bit slow to
239
258
  // get the actual image width
@@ -241,7 +260,7 @@ export default class Lazyload {
241
260
 
242
261
  img.setAttribute('sizes', `${width}px`)
243
262
  if (img.parentNode) {
244
- Array.from(Dom.all(img.parentNode, 'source')).forEach(source =>
263
+ Array.from(Dom.all(img.parentNode, 'source')).forEach((source) =>
245
264
  source.setAttribute('sizes', `${width}px`)
246
265
  )
247
266
  }
@@ -290,7 +309,7 @@ export default class Lazyload {
290
309
  }
291
310
 
292
311
  lazyloadImages(elements) {
293
- elements.forEach(item => {
312
+ elements.forEach((item) => {
294
313
  if (item.isIntersecting || item.intersectionRatio > 0) {
295
314
  const image = item.target
296
315
  this.swapImage(image)
@@ -7,13 +7,24 @@ gsap.registerPlugin(ScrollToPlugin)
7
7
  const DEFAULT_OPTIONS = {
8
8
  triggerEvents: true,
9
9
  scrollDuration: 0.8,
10
+ scrollOffsetNav: false,
10
11
  mobileMenuDelay: 800,
11
12
  openExternalInWindow: true,
12
- linkQuery: 'a:not([href^="#"]):not([target="_blank"]):not([data-lightbox]):not(.noanim)',
13
+ linkQuery:
14
+ 'a:not([href^="#"]):not([target="_blank"]):not([data-lightbox]):not(.noanim)',
13
15
  anchorQuery: 'a[href^="#"]:not(.noanim)',
14
16
 
15
17
  onAnchor: (target, links) => {
16
- links.app.scrollTo(target, links.opts.scrollDuration, links.opts.triggerEvents)
18
+ if (links.opts.scrollOffsetNav) {
19
+ const header = document.querySelector('header[data-nav]')
20
+ const headerHeight = header ? header.clientHeight : 0
21
+ target = { y: target, offsetY: headerHeight }
22
+ }
23
+ links.app.scrollTo(
24
+ target,
25
+ links.opts.scrollDuration,
26
+ links.opts.triggerEvents
27
+ )
17
28
  },
18
29
 
19
30
  onTransition: (href, app) => {
@@ -27,7 +38,7 @@ const DEFAULT_OPTIONS = {
27
38
  gsap.to(main, {
28
39
  duration: 0.8,
29
40
  y: 25,
30
- ease: 'power3.out'
41
+ ease: 'power3.out',
31
42
  })
32
43
 
33
44
  if (header) {
@@ -43,13 +54,13 @@ const DEFAULT_OPTIONS = {
43
54
  opacity: 1,
44
55
  onComplete: () => {
45
56
  window.location = href
46
- }
57
+ },
47
58
  })
48
59
  } else {
49
60
  gsap.to(main, {
50
61
  duration: 0.8,
51
62
  y: 25,
52
- ease: 'power3.out'
63
+ ease: 'power3.out',
53
64
  })
54
65
 
55
66
  if (header) {
@@ -65,10 +76,10 @@ const DEFAULT_OPTIONS = {
65
76
  opacity: 0,
66
77
  onComplete: () => {
67
78
  window.location = href
68
- }
79
+ },
69
80
  })
70
81
  }
71
- }
82
+ },
72
83
  }
73
84
 
74
85
  export default class Links {
@@ -87,7 +98,7 @@ export default class Links {
87
98
  bindHeroLink() {
88
99
  const el = document.querySelector('[data-link-to-content]')
89
100
  if (el) {
90
- el.addEventListener('click', e => {
101
+ el.addEventListener('click', (e) => {
91
102
  const dataTarget = document.querySelector('main')
92
103
  e.preventDefault()
93
104
  if (dataTarget) {
@@ -99,8 +110,8 @@ export default class Links {
99
110
 
100
111
  bindAnchors(anchors) {
101
112
  let wait = false
102
- Array.from(anchors).forEach(anchor => {
103
- anchor.addEventListener('click', e => {
113
+ Array.from(anchors).forEach((anchor) => {
114
+ anchor.addEventListener('click', (e) => {
104
115
  e.preventDefault()
105
116
  const href = anchor.getAttribute('href')
106
117
  if (href === '#') {
@@ -124,11 +135,22 @@ export default class Links {
124
135
  history.pushState({}, '', href)
125
136
  }
126
137
 
127
- if (this.app.header && dataTarget.id !== 'top') {
128
- setTimeout(() => {
129
- this.app.header.unpin()
130
- }, 800)
138
+ if (!this.app.header) {
139
+ return
131
140
  }
141
+ if (dataTarget.id === 'top') {
142
+ return
143
+ }
144
+ if (this.app.header.mainOpts.ignoreForcedScroll) {
145
+ return
146
+ }
147
+ if (this.app.header.mainOpts.pinOnForcedScrollEnd) {
148
+ return
149
+ }
150
+
151
+ setTimeout(() => {
152
+ this.app.header.unpin()
153
+ }, 800)
132
154
  }
133
155
  }
134
156
 
@@ -142,19 +164,38 @@ export default class Links {
142
164
  }
143
165
 
144
166
  bindLinks(links) {
145
- Array.from(links).forEach(link => {
167
+ const loadingContainer = document.querySelector('.loading-container')
168
+
169
+ Array.from(links).forEach((link) => {
146
170
  const href = link.getAttribute('href')
147
- if (!href) {
148
- return
171
+ if (!href || href === '#' || href.startsWith('javascript:')) {
172
+ return // Skip empty, anchor, or JS-based links
173
+ }
174
+
175
+ // Determine the normalized hostname of the current document.
176
+ const normalizedCurrentHost = this.normalizeHostname(
177
+ document.location.hostname
178
+ )
179
+
180
+ // For absolute URLs, use the URL constructor.
181
+ let linkHostname
182
+ try {
183
+ linkHostname = new URL(href, document.location.href).hostname
184
+ } catch (error) {
185
+ // If URL construction fails, assume it's not internal.
186
+ console.warn(`Failed to parse URL for href "${href}":`, error) // Log errors for debugging
187
+ linkHostname = ''
149
188
  }
150
- const internalLink = href.indexOf(document.location.hostname) > -1 || href.startsWith('/')
189
+ const normalizedLinkHost = this.normalizeHostname(linkHostname)
190
+
191
+ // Check if the link is internal by comparing the normalized hostnames.
192
+ const internalLink = normalizedLinkHost === normalizedCurrentHost
193
+
151
194
  if (this.opts.openExternalInWindow && !internalLink) {
152
195
  link.setAttribute('target', '_blank')
153
196
  }
154
197
 
155
- link.addEventListener('click', e => {
156
- const loadingContainer = document.querySelector('.loading-container')
157
-
198
+ link.addEventListener('click', (e) => {
158
199
  if (e.shiftKey || e.metaKey || e.ctrlKey) {
159
200
  return
160
201
  }
@@ -170,4 +211,8 @@ export default class Links {
170
211
  })
171
212
  })
172
213
  }
214
+
215
+ normalizeHostname(hostname) {
216
+ return hostname.replace(/^www\./, '')
217
+ }
173
218
  }