@brandocms/jupiter 5.0.0-beta.12 → 5.0.0-beta.14
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/README.md +7 -0
- package/package.json +1 -1
- package/src/modules/Application/index.js +52 -40
- package/src/modules/Dataloader/index.js +136 -59
- package/src/modules/DoubleHeader/index.js +14 -0
- package/src/modules/FeatureTests/index.js +2 -1
- package/src/modules/FixedHeader/index.js +13 -0
- package/src/modules/Lazyload/index.js +115 -49
- package/src/modules/Links/index.js +1 -1
- package/src/modules/Looper/index.js +453 -247
- package/src/modules/Moonwalk/index.js +195 -165
- package/src/modules/StickyHeader/index.js +13 -0
- package/src/utils/rafCallback.js +4 -5
- package/types/modules/Application/index.d.ts +7 -8
- package/types/modules/Dataloader/index.d.ts +48 -2
- package/types/modules/FeatureTests/index.d.ts +1 -1
- package/types/modules/FixedHeader/index.d.ts +58 -0
- package/types/modules/Lazyload/index.d.ts +32 -13
- package/types/modules/Moonwalk/index.d.ts +93 -18
|
@@ -14,12 +14,11 @@ import * as Events from '../../events'
|
|
|
14
14
|
* @typedef {Object} LazyloadOptions
|
|
15
15
|
* @property {IntersectionObserverConfig} [revealIntersectionObserverConfig] - Configuration for the reveal intersection observer
|
|
16
16
|
* @property {IntersectionObserverConfig} [loadIntersectionObserverConfig] - Configuration for the load intersection observer
|
|
17
|
-
* @property {IntersectionObserverConfig} [intersectionObserverConfig] - Configuration for general intersection observers
|
|
18
17
|
* @property {boolean} [useNativeLazyloadIfAvailable=true] - Whether to use native lazyloading if available
|
|
19
|
-
* @property {string} [mode='default'] - Lazyload mode
|
|
20
18
|
* @property {number} [minSize=40] - Minimum size for auto sizing
|
|
21
19
|
* @property {boolean} [updateSizes=true] - Whether to update sizes attribute
|
|
22
20
|
* @property {boolean} [registerCallback=true] - Whether to register a callback for APPLICATION_REVEALED event
|
|
21
|
+
* @property {HTMLElement|null} [target=null] - Container element to scope lazyloading to. Defaults to document.body
|
|
23
22
|
*/
|
|
24
23
|
|
|
25
24
|
/** @type {LazyloadOptions} */
|
|
@@ -33,7 +32,6 @@ const DEFAULT_OPTIONS = {
|
|
|
33
32
|
threshold: 0.0,
|
|
34
33
|
},
|
|
35
34
|
useNativeLazyloadIfAvailable: true,
|
|
36
|
-
mode: 'default',
|
|
37
35
|
minSize: 40,
|
|
38
36
|
updateSizes: true,
|
|
39
37
|
registerCallback: true,
|
|
@@ -145,9 +143,6 @@ export default class Lazyload {
|
|
|
145
143
|
initialize() {
|
|
146
144
|
// initialize ResizeObserver for images with data-sizes="auto"
|
|
147
145
|
this.initializeResizeObserver()
|
|
148
|
-
// look for lazyload sections. if we find, add an observer that triggers
|
|
149
|
-
// lazyload for all images within.
|
|
150
|
-
this.initializeSections()
|
|
151
146
|
|
|
152
147
|
// if we have native lazyload, use it.
|
|
153
148
|
if ('loading' in HTMLImageElement.prototype && this.opts.useNativeLazyloadIfAvailable) {
|
|
@@ -180,10 +175,14 @@ export default class Lazyload {
|
|
|
180
175
|
|
|
181
176
|
this.initObserver(this.loadObserver)
|
|
182
177
|
|
|
178
|
+
// look for lazyload sections. if we find, add an observer that triggers
|
|
179
|
+
// lazyload for all images within.
|
|
180
|
+
this.initializeSections()
|
|
181
|
+
|
|
183
182
|
// Deprecate data-ll-image sometime
|
|
184
183
|
this.imageObserver = new IntersectionObserver(
|
|
185
184
|
this.lazyloadImages.bind(this),
|
|
186
|
-
this.opts.
|
|
185
|
+
this.opts.loadIntersectionObserverConfig
|
|
187
186
|
)
|
|
188
187
|
|
|
189
188
|
this.lazyImages = this.target.querySelectorAll('[data-ll-image]')
|
|
@@ -204,6 +203,13 @@ export default class Lazyload {
|
|
|
204
203
|
})
|
|
205
204
|
}
|
|
206
205
|
|
|
206
|
+
/**
|
|
207
|
+
* Force load all lazyload elements within a container, bypassing intersection observers.
|
|
208
|
+
* Used by modules like Looper when dynamically adding content that needs immediate loading.
|
|
209
|
+
* @param {HTMLElement} [$container=document.body] - Container to search for lazyload elements
|
|
210
|
+
* @param {Object} [options]
|
|
211
|
+
* @param {boolean} [options.reveal=true] - Whether to also reveal (set data-ll-loaded) after loading
|
|
212
|
+
*/
|
|
207
213
|
forceLoad($container = document.body, { reveal = true } = {}) {
|
|
208
214
|
const images = Dom.all($container, '[data-ll-image]')
|
|
209
215
|
images.forEach(img => this.swapImage(img))
|
|
@@ -215,6 +221,29 @@ export default class Lazyload {
|
|
|
215
221
|
this.revealPicture(picture)
|
|
216
222
|
}
|
|
217
223
|
})
|
|
224
|
+
|
|
225
|
+
// Set sizes on dynamically added images with data-sizes="auto"
|
|
226
|
+
// and register them with the ResizeObserver for future updates
|
|
227
|
+
if (this.opts.updateSizes && this.sizeObserver) {
|
|
228
|
+
const autoSizesImages = Dom.all($container, '[data-sizes="auto"]')
|
|
229
|
+
autoSizesImages.forEach(img => {
|
|
230
|
+
let width = Math.round(img.offsetWidth)
|
|
231
|
+
if (width < this.opts.minSize) {
|
|
232
|
+
width = this.opts.minSize
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const sizes = `${width}px`
|
|
236
|
+
img.setAttribute('sizes', sizes)
|
|
237
|
+
|
|
238
|
+
if (img.parentNode) {
|
|
239
|
+
Dom.all(img.parentNode, 'source').forEach(source => {
|
|
240
|
+
source.setAttribute('sizes', sizes)
|
|
241
|
+
})
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
this.sizeObserver.observe(img)
|
|
245
|
+
})
|
|
246
|
+
}
|
|
218
247
|
}
|
|
219
248
|
|
|
220
249
|
initializeResizeObserver() {
|
|
@@ -276,7 +305,7 @@ export default class Lazyload {
|
|
|
276
305
|
if (currentSizes !== newSizes) {
|
|
277
306
|
img.setAttribute('sizes', newSizes)
|
|
278
307
|
if (img.parentNode) {
|
|
279
|
-
|
|
308
|
+
Dom.all(img.parentNode, 'source').forEach(source => {
|
|
280
309
|
if (source.getAttribute('sizes') !== newSizes) {
|
|
281
310
|
source.setAttribute('sizes', newSizes)
|
|
282
311
|
}
|
|
@@ -290,37 +319,35 @@ export default class Lazyload {
|
|
|
290
319
|
}
|
|
291
320
|
|
|
292
321
|
initializeSections() {
|
|
293
|
-
const sections =
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
sections.forEach(section => {
|
|
314
|
-
const children = section.querySelectorAll('picture')
|
|
315
|
-
const obs = sectionObserver(section, children)
|
|
316
|
-
obs.observe(section)
|
|
317
|
-
})
|
|
322
|
+
const sections = this.target.querySelectorAll('[data-lazyload-section]')
|
|
323
|
+
|
|
324
|
+
const sectionObserver = (section, children) => {
|
|
325
|
+
const imagesInSection = Dom.all(section, 'img')
|
|
326
|
+
return new IntersectionObserver((entries, self) => {
|
|
327
|
+
entries.forEach(entry => {
|
|
328
|
+
if (entry.isIntersecting || entry.intersectionRatio > 0) {
|
|
329
|
+
imagesAreLoaded(imagesInSection, true).then(() => {
|
|
330
|
+
dispatchElementEvent(section, Events.SECTION_LAZYLOADED)
|
|
331
|
+
})
|
|
332
|
+
children.forEach(picture => {
|
|
333
|
+
this.loadPicture(picture)
|
|
334
|
+
this.loadObserver.unobserve(picture)
|
|
335
|
+
})
|
|
336
|
+
self.unobserve(section)
|
|
337
|
+
}
|
|
338
|
+
})
|
|
339
|
+
}, this.opts.loadIntersectionObserverConfig)
|
|
318
340
|
}
|
|
341
|
+
|
|
342
|
+
sections.forEach(section => {
|
|
343
|
+
const children = section.querySelectorAll('picture')
|
|
344
|
+
const obs = sectionObserver(section, children)
|
|
345
|
+
obs.observe(section)
|
|
346
|
+
})
|
|
319
347
|
}
|
|
320
348
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
elements.forEach(item => {
|
|
349
|
+
handleLoadEntries(entries) {
|
|
350
|
+
entries.forEach(item => {
|
|
324
351
|
if (item.isIntersecting || item.intersectionRatio > 0) {
|
|
325
352
|
const picture = item.target
|
|
326
353
|
this.loadPicture(picture)
|
|
@@ -329,9 +356,8 @@ export default class Lazyload {
|
|
|
329
356
|
})
|
|
330
357
|
}
|
|
331
358
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
elements.forEach(item => {
|
|
359
|
+
handleRevealEntries(entries) {
|
|
360
|
+
entries.forEach(item => {
|
|
335
361
|
if (item.isIntersecting || item.intersectionRatio > 0) {
|
|
336
362
|
const picture = item.target
|
|
337
363
|
const ready = item.target.hasAttribute('data-ll-srcset-ready')
|
|
@@ -380,7 +406,7 @@ export default class Lazyload {
|
|
|
380
406
|
picture.setAttribute('data-ll-srcset-ready', '')
|
|
381
407
|
}
|
|
382
408
|
|
|
383
|
-
img.addEventListener('load', onload,
|
|
409
|
+
img.addEventListener('load', onload, { once: true })
|
|
384
410
|
img.setAttribute('data-ll-loading', '')
|
|
385
411
|
|
|
386
412
|
if (img.dataset.src) {
|
|
@@ -391,12 +417,6 @@ export default class Lazyload {
|
|
|
391
417
|
img.setAttribute('srcset', img.dataset.srcset)
|
|
392
418
|
}
|
|
393
419
|
|
|
394
|
-
if (this.app.featureTests.results.ie11) {
|
|
395
|
-
if (window.picturefill) {
|
|
396
|
-
window.picturefill({ reevaluate: true })
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
|
|
400
420
|
// safari sometimes caches, so force load
|
|
401
421
|
if (img.complete) {
|
|
402
422
|
onload()
|
|
@@ -405,7 +425,10 @@ export default class Lazyload {
|
|
|
405
425
|
dispatchElementEvent(img, Events.IMAGE_LAZYLOADED)
|
|
406
426
|
}
|
|
407
427
|
|
|
408
|
-
|
|
428
|
+
/**
|
|
429
|
+
* Reveal a picture element by setting `data-ll-loaded` on its img child.
|
|
430
|
+
* @param {HTMLElement} picture - The picture element to reveal
|
|
431
|
+
*/
|
|
409
432
|
revealPicture(picture) {
|
|
410
433
|
const img = picture.querySelector('img')
|
|
411
434
|
if (img.hasAttribute('data-ll-loaded')) {
|
|
@@ -415,8 +438,33 @@ export default class Lazyload {
|
|
|
415
438
|
dispatchElementEvent(img, Events.IMAGE_REVEALED)
|
|
416
439
|
}
|
|
417
440
|
|
|
418
|
-
|
|
419
|
-
|
|
441
|
+
/**
|
|
442
|
+
* Swap source attributes on a picture element for the native lazyload path.
|
|
443
|
+
* Copies data-srcset to srcset on all sources and the img element.
|
|
444
|
+
* @param {HTMLElement} picture - The picture element to swap
|
|
445
|
+
*/
|
|
446
|
+
swapPicture(picture) {
|
|
447
|
+
const sources = picture.querySelectorAll('source')
|
|
448
|
+
sources.forEach(source => {
|
|
449
|
+
if (source.hasAttribute('data-srcset')) {
|
|
450
|
+
source.setAttribute('srcset', source.dataset.srcset)
|
|
451
|
+
}
|
|
452
|
+
})
|
|
453
|
+
|
|
454
|
+
const img = picture.querySelector('img')
|
|
455
|
+
if (img) {
|
|
456
|
+
if (img.dataset.src) {
|
|
457
|
+
img.setAttribute('src', img.dataset.src)
|
|
458
|
+
}
|
|
459
|
+
if (img.dataset.srcset) {
|
|
460
|
+
img.setAttribute('srcset', img.dataset.srcset)
|
|
461
|
+
}
|
|
462
|
+
img.setAttribute('data-ll-loaded', '')
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
lazyloadImages(entries) {
|
|
467
|
+
entries.forEach(item => {
|
|
420
468
|
if (item.isIntersecting || item.intersectionRatio > 0) {
|
|
421
469
|
const image = item.target
|
|
422
470
|
this.swapImage(image)
|
|
@@ -429,4 +477,22 @@ export default class Lazyload {
|
|
|
429
477
|
image.src = image.dataset.src
|
|
430
478
|
image.setAttribute('data-ll-loaded', '')
|
|
431
479
|
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Destroy the Lazyload instance, disconnecting all observers and freeing resources.
|
|
483
|
+
*/
|
|
484
|
+
destroy() {
|
|
485
|
+
this.srcsetReadyObserver?.disconnect()
|
|
486
|
+
this.loadObserver?.disconnect()
|
|
487
|
+
this.revealObserver?.disconnect()
|
|
488
|
+
this.imageObserver?.disconnect()
|
|
489
|
+
this.sizeObserver?.disconnect()
|
|
490
|
+
|
|
491
|
+
if (this.rafId) {
|
|
492
|
+
cancelAnimationFrame(this.rafId)
|
|
493
|
+
this.rafId = null
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
this.resizePending.clear()
|
|
497
|
+
}
|
|
432
498
|
}
|
|
@@ -29,7 +29,7 @@ const DEFAULT_OPTIONS = {
|
|
|
29
29
|
if (links.opts.scrollOffsetNav) {
|
|
30
30
|
const header = document.querySelector('header[data-nav]')
|
|
31
31
|
const headerHeight = header ? header.clientHeight : 0
|
|
32
|
-
target = { y: target, offsetY: headerHeight }
|
|
32
|
+
target = { y: target, offsetY: -headerHeight }
|
|
33
33
|
}
|
|
34
34
|
links.app.scrollTo(target, links.opts.scrollDuration, links.opts.triggerEvents)
|
|
35
35
|
},
|