@brandocms/jupiter 3.46.4 → 3.48.0
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 +9 -9
- package/src/events/index.js +1 -0
- package/src/index.js +7 -7
- package/src/modules/Application/index.js +119 -80
- package/src/modules/Breakpoints/index.js +14 -17
- package/src/modules/Cookies/index.js +86 -43
- package/src/modules/CoverOverlay/index.js +6 -3
- package/src/modules/Dataloader/index.js +173 -7
- package/src/modules/Dom/index.js +26 -26
- package/src/modules/Dropdown/index.js +14 -14
- package/src/modules/EqualHeightElements/index.js +70 -0
- package/src/modules/EqualHeightImages/index.js +95 -0
- package/src/modules/FeatureTests/index.js +22 -15
- package/src/modules/FixedHeader/index.js +79 -75
- package/src/modules/Fontloader/index.js +5 -3
- package/src/modules/FooterReveal/index.js +1 -1
- package/src/modules/HeroSlider/index.js +33 -23
- package/src/modules/HeroVideo/index.js +15 -13
- package/src/modules/Lazyload/index.js +119 -65
- package/src/modules/Lightbox/index.js +40 -43
- package/src/modules/Links/index.js +8 -7
- package/src/modules/Marquee/index.js +47 -37
- package/src/modules/MobileMenu/index.js +112 -65
- package/src/modules/Moonwalk/index.js +256 -203
- package/src/modules/Parallax/index.js +24 -14
- package/src/modules/Popup/index.js +24 -21
- package/src/modules/ScrollSpy/index.js +5 -5
- package/src/modules/StackedBoxes/index.js +5 -5
- package/src/modules/StickyHeader/index.js +73 -70
- package/src/modules/Toggler/index.js +2 -2
- package/src/modules/Typography/index.js +13 -10
- package/src/utils/dispatchElementEvent.js +2 -2
- package/src/utils/imageIsLoaded.js +1 -1
- package/src/utils/imagesAreLoaded.js +3 -3
- package/src/utils/loadScript.js +9 -8
- package/src/utils/rafCallback.js +12 -10
- package/src/utils/zoom.js +11 -8
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
export default class Fontloader {
|
|
2
|
-
constructor
|
|
2
|
+
constructor(app) {
|
|
3
3
|
this.app = app
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
loadFonts
|
|
6
|
+
loadFonts() {
|
|
7
7
|
return new Promise(resolve => {
|
|
8
8
|
if (!window.FontFace) {
|
|
9
|
-
setTimeout(() => {
|
|
9
|
+
setTimeout(() => {
|
|
10
|
+
resolve()
|
|
11
|
+
}, 800)
|
|
10
12
|
} else {
|
|
11
13
|
document.fonts.ready.then(() => {
|
|
12
14
|
resolve()
|
|
@@ -52,7 +52,9 @@ const DEFAULT_OPTIONS = {
|
|
|
52
52
|
gsap.to(hs.el, {
|
|
53
53
|
duration: 0.25,
|
|
54
54
|
opacity: 1,
|
|
55
|
-
onComplete: () => {
|
|
55
|
+
onComplete: () => {
|
|
56
|
+
callback()
|
|
57
|
+
}
|
|
56
58
|
})
|
|
57
59
|
} else {
|
|
58
60
|
gsap.to(hs.el, {
|
|
@@ -64,7 +66,7 @@ const DEFAULT_OPTIONS = {
|
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
export default class HeroSlider {
|
|
67
|
-
constructor
|
|
69
|
+
constructor(app, opts = {}) {
|
|
68
70
|
this.app = app
|
|
69
71
|
this.opts = _defaultsDeep(opts, DEFAULT_OPTIONS)
|
|
70
72
|
|
|
@@ -81,7 +83,7 @@ export default class HeroSlider {
|
|
|
81
83
|
this.initialize()
|
|
82
84
|
}
|
|
83
85
|
|
|
84
|
-
initialize
|
|
86
|
+
initialize() {
|
|
85
87
|
this._addResizeHandler()
|
|
86
88
|
// style the container
|
|
87
89
|
gsap.set(this.el, {
|
|
@@ -132,9 +134,9 @@ export default class HeroSlider {
|
|
|
132
134
|
|
|
133
135
|
this.opts.onInitialize(this)
|
|
134
136
|
|
|
135
|
-
const callback =
|
|
137
|
+
const callback = this.slides.length > 1 ? this.next.bind(this) : () => {}
|
|
136
138
|
|
|
137
|
-
|
|
139
|
+
this.app.registerCallback(Events.APPLICATION_REVEALED, () => {
|
|
138
140
|
/* Wait for the first image to load, then fade in container element */
|
|
139
141
|
const firstImg = this.slides[this._currentSlideIdx].querySelector('img')
|
|
140
142
|
|
|
@@ -149,7 +151,7 @@ export default class HeroSlider {
|
|
|
149
151
|
/**
|
|
150
152
|
* Calculate which slide is next, and call the slide function
|
|
151
153
|
*/
|
|
152
|
-
next
|
|
154
|
+
next() {
|
|
153
155
|
if (prefersReducedMotion() && this.app.opts.respectReducedMotion) {
|
|
154
156
|
return
|
|
155
157
|
}
|
|
@@ -163,7 +165,7 @@ export default class HeroSlider {
|
|
|
163
165
|
this._previousSlide = this.slides[this._currentSlideIdx]
|
|
164
166
|
this._currentSlideIdx += 1
|
|
165
167
|
if (this._currentSlideIdx === this.slideCount) {
|
|
166
|
-
[this._nextSlide] = this.slides
|
|
168
|
+
;[this._nextSlide] = this.slides
|
|
167
169
|
} else {
|
|
168
170
|
this._nextSlide = this.slides[this._currentSlideIdx + 1]
|
|
169
171
|
}
|
|
@@ -177,7 +179,7 @@ export default class HeroSlider {
|
|
|
177
179
|
/**
|
|
178
180
|
* Switches between slides
|
|
179
181
|
*/
|
|
180
|
-
slide
|
|
182
|
+
slide(type) {
|
|
181
183
|
const timeline = gsap.timeline()
|
|
182
184
|
|
|
183
185
|
switch (type) {
|
|
@@ -205,12 +207,16 @@ export default class HeroSlider {
|
|
|
205
207
|
.set(this._previousSlide, {
|
|
206
208
|
opacity: 0
|
|
207
209
|
})
|
|
208
|
-
.call(
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
210
|
+
.call(
|
|
211
|
+
() => {
|
|
212
|
+
this._nextSlide.style.zIndex = this.opts.zIndex.visible
|
|
213
|
+
this._currentSlide.style.zIndex = this.opts.zIndex.regular
|
|
214
|
+
this._previousSlide.style.zIndex = this.opts.zIndex.regular
|
|
215
|
+
this.next()
|
|
216
|
+
},
|
|
217
|
+
null,
|
|
218
|
+
this
|
|
219
|
+
)
|
|
214
220
|
|
|
215
221
|
break
|
|
216
222
|
|
|
@@ -221,13 +227,17 @@ export default class HeroSlider {
|
|
|
221
227
|
scale: 1.0,
|
|
222
228
|
width: '100%'
|
|
223
229
|
})
|
|
224
|
-
.fromTo(
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
230
|
+
.fromTo(
|
|
231
|
+
this._previousSlide,
|
|
232
|
+
{
|
|
233
|
+
duration: this.opts.interval,
|
|
234
|
+
overflow: 'hidden'
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
duration: this.opts.interval,
|
|
238
|
+
scale: this.opts.transition.scale
|
|
239
|
+
}
|
|
240
|
+
)
|
|
231
241
|
.to(this._previousSlide, {
|
|
232
242
|
duration: this.opts.transition.duration,
|
|
233
243
|
width: 0,
|
|
@@ -261,7 +271,7 @@ export default class HeroSlider {
|
|
|
261
271
|
/**
|
|
262
272
|
* Add a window resize handler that resizes slide widths
|
|
263
273
|
*/
|
|
264
|
-
_addResizeHandler
|
|
274
|
+
_addResizeHandler() {
|
|
265
275
|
this.observer = new IntersectionObserver(entries => {
|
|
266
276
|
const [{ isIntersecting }] = entries
|
|
267
277
|
if (isIntersecting) {
|
|
@@ -275,7 +285,7 @@ export default class HeroSlider {
|
|
|
275
285
|
this.observer.observe(this.el)
|
|
276
286
|
}
|
|
277
287
|
|
|
278
|
-
_resizeSlides
|
|
288
|
+
_resizeSlides() {
|
|
279
289
|
gsap.to(this.images, {
|
|
280
290
|
duration: 0.15,
|
|
281
291
|
width: document.body.clientWidth,
|
|
@@ -62,7 +62,7 @@ const DEFAULT_OPTIONS = {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
export default class HeroVideo {
|
|
65
|
-
constructor
|
|
65
|
+
constructor(app, opts = {}) {
|
|
66
66
|
this.app = app
|
|
67
67
|
this.booting = true
|
|
68
68
|
this.playing = false
|
|
@@ -83,7 +83,7 @@ export default class HeroVideo {
|
|
|
83
83
|
this.initialize()
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
initialize
|
|
86
|
+
initialize() {
|
|
87
87
|
this._addResizeHandler()
|
|
88
88
|
// style the container
|
|
89
89
|
gsap.set(this.el, {
|
|
@@ -163,21 +163,23 @@ export default class HeroVideo {
|
|
|
163
163
|
})
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
setSrc
|
|
166
|
+
setSrc() {
|
|
167
167
|
const dataSrc = this.video.getAttribute('data-src')
|
|
168
168
|
if (!dataSrc) {
|
|
169
169
|
return
|
|
170
170
|
}
|
|
171
171
|
const dataObj = JSON.parse(dataSrc)
|
|
172
|
-
if (
|
|
173
|
-
|
|
172
|
+
if (
|
|
173
|
+
this.app.breakpoints.mediaQueries.iphone.matches ||
|
|
174
|
+
this.app.breakpoints.mediaQueries.mobile.matches
|
|
175
|
+
) {
|
|
174
176
|
this.video.setAttribute('src', dataObj.phone)
|
|
175
177
|
} else {
|
|
176
178
|
this.video.setAttribute('src', dataObj.desktop)
|
|
177
179
|
}
|
|
178
180
|
}
|
|
179
181
|
|
|
180
|
-
addEvents
|
|
182
|
+
addEvents() {
|
|
181
183
|
this.video.addEventListener('canplay', () => {
|
|
182
184
|
if (!this.playing) {
|
|
183
185
|
if (!prefersReducedMotion()) {
|
|
@@ -209,7 +211,7 @@ export default class HeroVideo {
|
|
|
209
211
|
}
|
|
210
212
|
}
|
|
211
213
|
|
|
212
|
-
play
|
|
214
|
+
play() {
|
|
213
215
|
if (this.cover) {
|
|
214
216
|
this.opts.onFadeOutCover(this)
|
|
215
217
|
}
|
|
@@ -217,20 +219,20 @@ export default class HeroVideo {
|
|
|
217
219
|
this.playing = true
|
|
218
220
|
}
|
|
219
221
|
|
|
220
|
-
pause
|
|
222
|
+
pause() {
|
|
221
223
|
this.video.pause()
|
|
222
224
|
this.playing = false
|
|
223
225
|
}
|
|
224
226
|
|
|
225
|
-
fadeIn
|
|
227
|
+
fadeIn() {
|
|
226
228
|
this.opts.onFadeIn(this)
|
|
227
229
|
}
|
|
228
230
|
|
|
229
|
-
fadeInCover
|
|
231
|
+
fadeInCover() {
|
|
230
232
|
this.opts.onFadeInCover(this)
|
|
231
233
|
}
|
|
232
234
|
|
|
233
|
-
addObserver
|
|
235
|
+
addObserver() {
|
|
234
236
|
const observer = new IntersectionObserver(entries => {
|
|
235
237
|
const [{ isIntersecting }] = entries
|
|
236
238
|
if (isIntersecting) {
|
|
@@ -252,7 +254,7 @@ export default class HeroVideo {
|
|
|
252
254
|
/**
|
|
253
255
|
* Add a window resize handler that resizes video width
|
|
254
256
|
*/
|
|
255
|
-
_addResizeHandler
|
|
257
|
+
_addResizeHandler() {
|
|
256
258
|
this.observer = new IntersectionObserver(entries => {
|
|
257
259
|
const [{ isIntersecting }] = entries
|
|
258
260
|
if (isIntersecting) {
|
|
@@ -266,7 +268,7 @@ export default class HeroVideo {
|
|
|
266
268
|
this.observer.observe(this.el)
|
|
267
269
|
}
|
|
268
270
|
|
|
269
|
-
_resize
|
|
271
|
+
_resize() {
|
|
270
272
|
gsap.to(this.video, {
|
|
271
273
|
duration: 0.15,
|
|
272
274
|
width: document.body.clientWidth,
|
|
@@ -1,29 +1,43 @@
|
|
|
1
1
|
import _defaultsDeep from 'lodash.defaultsdeep'
|
|
2
|
-
import { IMAGE_LAZYLOADED, SECTION_LAZYLOADED } from '../../events'
|
|
3
2
|
import dispatchElementEvent from '../../utils/dispatchElementEvent'
|
|
4
3
|
import imagesAreLoaded from '../../utils/imagesAreLoaded'
|
|
5
4
|
import Dom from '../Dom'
|
|
6
5
|
import * as Events from '../../events'
|
|
7
6
|
|
|
8
7
|
const DEFAULT_OPTIONS = {
|
|
9
|
-
|
|
10
|
-
rootMargin: '
|
|
8
|
+
revealIntersectionObserverConfig: {
|
|
9
|
+
rootMargin: '0px 100px 0px 100px',
|
|
10
|
+
threshold: 0.0
|
|
11
|
+
},
|
|
12
|
+
loadIntersectionObserverConfig: {
|
|
13
|
+
rootMargin: '850px 500px 850px 500px',
|
|
11
14
|
threshold: 0.0
|
|
12
15
|
},
|
|
13
16
|
useNativeLazyloadIfAvailable: true,
|
|
14
17
|
mode: 'default',
|
|
15
18
|
minSize: 40,
|
|
16
|
-
updateSizes: true
|
|
19
|
+
updateSizes: true,
|
|
20
|
+
registerCallback: true
|
|
17
21
|
}
|
|
18
22
|
|
|
19
23
|
export default class Lazyload {
|
|
20
|
-
constructor
|
|
24
|
+
constructor(app, opts = {}) {
|
|
21
25
|
this.app = app
|
|
22
26
|
this.opts = _defaultsDeep(opts, DEFAULT_OPTIONS)
|
|
23
27
|
this.initialize()
|
|
28
|
+
|
|
29
|
+
if (this.opts.registerCallback) {
|
|
30
|
+
this.app.registerCallback(Events.APPLICATION_REVEALED, () => {
|
|
31
|
+
this.watch()
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
watch() {
|
|
37
|
+
this.initObserver(this.revealObserver, false)
|
|
24
38
|
}
|
|
25
39
|
|
|
26
|
-
initialize
|
|
40
|
+
initialize() {
|
|
27
41
|
// initialize all images that have data-sizes="auto" and set sizes="<actual width>px"
|
|
28
42
|
this.initializeAutoSizes()
|
|
29
43
|
// look for lazyload sections. if we find, add an observer that triggers
|
|
@@ -40,43 +54,57 @@ export default class Lazyload {
|
|
|
40
54
|
|
|
41
55
|
const lazyPictures = document.querySelectorAll('[data-ll-srcset]')
|
|
42
56
|
lazyPictures.forEach(picture => {
|
|
43
|
-
picture.querySelectorAll('img').forEach(img =>
|
|
44
|
-
img.setAttribute('loading', 'lazy')
|
|
45
|
-
})
|
|
57
|
+
picture.querySelectorAll('img').forEach(img => img.setAttribute('loading', 'lazy'))
|
|
46
58
|
this.swapPicture(picture)
|
|
47
59
|
})
|
|
48
|
-
} else {
|
|
49
|
-
this.imgObserver = new IntersectionObserver(
|
|
50
|
-
this.lazyloadImages.bind(this),
|
|
51
|
-
this.opts.intersectionObserverConfig
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
this.lazyImages = document.querySelectorAll('[data-ll-image]')
|
|
55
|
-
this.lazyImages.forEach((img, idx) => {
|
|
56
|
-
img.setAttribute('data-ll-blurred', '')
|
|
57
|
-
img.setAttribute('data-ll-idx', idx)
|
|
58
|
-
img.style.setProperty('--ll-idx', idx)
|
|
59
|
-
this.imgObserver.observe(img)
|
|
60
|
-
})
|
|
61
60
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
this.lazyPictures = document.querySelectorAll('[data-ll-srcset]')
|
|
65
|
+
|
|
66
|
+
this.loadObserver = new IntersectionObserver(
|
|
67
|
+
this.handleLoadEntries.bind(this),
|
|
68
|
+
this.opts.loadIntersectionObserverConfig
|
|
69
|
+
)
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
this.
|
|
71
|
+
this.revealObserver = new IntersectionObserver(
|
|
72
|
+
this.handleRevealEntries.bind(this),
|
|
73
|
+
this.opts.revealIntersectionObserverConfig
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
this.lazyPictures = document.querySelectorAll('[data-ll-srcset]')
|
|
77
|
+
this.initObserver(this.loadObserver)
|
|
78
|
+
|
|
79
|
+
// Deprecate data-ll-image sometime
|
|
80
|
+
this.imageObserver = new IntersectionObserver(
|
|
81
|
+
this.lazyloadImages.bind(this),
|
|
82
|
+
this.opts.intersectionObserverConfig
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
this.lazyImages = document.querySelectorAll('[data-ll-image]')
|
|
86
|
+
this.lazyImages.forEach((img, idx) => {
|
|
87
|
+
img.setAttribute('data-ll-blurred', '')
|
|
88
|
+
img.setAttribute('data-ll-idx', idx)
|
|
89
|
+
img.style.setProperty('--ll-idx', idx)
|
|
90
|
+
this.imageObserver.observe(img)
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
initObserver(observer, setAttrs = true) {
|
|
95
|
+
this.lazyPictures.forEach((picture, idx) => {
|
|
96
|
+
if (setAttrs) {
|
|
69
97
|
picture.querySelectorAll('img:not([data-ll-loaded])').forEach(img => {
|
|
70
98
|
img.setAttribute('data-ll-blurred', '')
|
|
71
99
|
img.setAttribute('data-ll-idx', idx)
|
|
72
100
|
img.style.setProperty('--ll-idx', idx)
|
|
73
101
|
})
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
102
|
+
}
|
|
103
|
+
observer.observe(picture)
|
|
104
|
+
})
|
|
77
105
|
}
|
|
78
106
|
|
|
79
|
-
initializeAutoSizes
|
|
107
|
+
initializeAutoSizes() {
|
|
80
108
|
if (this.opts.updateSizes) {
|
|
81
109
|
this.$autoSizesImages = Dom.all('[data-sizes="auto"]')
|
|
82
110
|
this.autoSizes()
|
|
@@ -87,17 +115,19 @@ export default class Lazyload {
|
|
|
87
115
|
/**
|
|
88
116
|
* Set sizes attribute for all imgs with `data-sizes="auto"` and source within the <picture>
|
|
89
117
|
*/
|
|
90
|
-
autoSizes
|
|
118
|
+
autoSizes() {
|
|
91
119
|
Array.from(this.$autoSizesImages).forEach(img => {
|
|
92
120
|
const width = this.getWidth(img)
|
|
93
121
|
img.setAttribute('sizes', `${width}px`)
|
|
94
122
|
if (img.parentNode) {
|
|
95
|
-
Array.from(Dom.all(img.parentNode, 'source')).forEach(source =>
|
|
123
|
+
Array.from(Dom.all(img.parentNode, 'source')).forEach(source =>
|
|
124
|
+
source.setAttribute('sizes', `${width}px`)
|
|
125
|
+
)
|
|
96
126
|
}
|
|
97
127
|
})
|
|
98
128
|
}
|
|
99
129
|
|
|
100
|
-
getWidth
|
|
130
|
+
getWidth(img) {
|
|
101
131
|
let width = img.offsetWidth
|
|
102
132
|
let parent = img.parentNode
|
|
103
133
|
|
|
@@ -109,7 +139,7 @@ export default class Lazyload {
|
|
|
109
139
|
return width
|
|
110
140
|
}
|
|
111
141
|
|
|
112
|
-
initializeSections
|
|
142
|
+
initializeSections() {
|
|
113
143
|
const sections = document.querySelectorAll('[data-lazyload-section]')
|
|
114
144
|
if (sections) {
|
|
115
145
|
const sectionObserver = (section, children) => {
|
|
@@ -118,17 +148,16 @@ export default class Lazyload {
|
|
|
118
148
|
entries.forEach(entry => {
|
|
119
149
|
if (entry.isIntersecting || entry.intersectionRatio > 0) {
|
|
120
150
|
imagesAreLoaded(imagesInSection, true).then(() => {
|
|
121
|
-
dispatchElementEvent(section, SECTION_LAZYLOADED)
|
|
151
|
+
dispatchElementEvent(section, Events.SECTION_LAZYLOADED)
|
|
122
152
|
})
|
|
123
153
|
children.forEach(picture => {
|
|
124
|
-
this.
|
|
125
|
-
this.
|
|
154
|
+
this.loadPicture(picture)
|
|
155
|
+
this.loadObserver.unobserve(picture)
|
|
126
156
|
})
|
|
127
157
|
self.unobserve(section)
|
|
128
158
|
}
|
|
129
159
|
})
|
|
130
|
-
},
|
|
131
|
-
this.opts.intersectionObserverConfig)
|
|
160
|
+
}, this.opts.intersectionObserverConfig)
|
|
132
161
|
}
|
|
133
162
|
|
|
134
163
|
sections.forEach(section => {
|
|
@@ -139,44 +168,41 @@ export default class Lazyload {
|
|
|
139
168
|
}
|
|
140
169
|
}
|
|
141
170
|
|
|
142
|
-
|
|
171
|
+
// we load the picture a ways before it enters the viewport
|
|
172
|
+
handleLoadEntries(elements) {
|
|
143
173
|
elements.forEach(item => {
|
|
144
174
|
if (item.isIntersecting || item.intersectionRatio > 0) {
|
|
145
|
-
const
|
|
146
|
-
this.
|
|
147
|
-
this.
|
|
175
|
+
const picture = item.target
|
|
176
|
+
this.loadPicture(picture)
|
|
177
|
+
this.loadObserver.unobserve(item.target)
|
|
148
178
|
}
|
|
149
179
|
})
|
|
150
180
|
}
|
|
151
181
|
|
|
152
|
-
|
|
182
|
+
// we reveal the picture when it enters the viewport
|
|
183
|
+
handleRevealEntries(elements) {
|
|
153
184
|
elements.forEach(item => {
|
|
154
185
|
if (item.isIntersecting || item.intersectionRatio > 0) {
|
|
155
186
|
const picture = item.target
|
|
156
|
-
this.
|
|
157
|
-
this.
|
|
187
|
+
this.revealPicture(picture)
|
|
188
|
+
this.revealObserver.unobserve(item.target)
|
|
158
189
|
}
|
|
159
190
|
})
|
|
160
191
|
}
|
|
161
192
|
|
|
162
|
-
|
|
163
|
-
image.src = image.dataset.src
|
|
164
|
-
image.setAttribute('data-ll-loaded', '')
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
swapPicture (picture) {
|
|
193
|
+
loadPicture(picture) {
|
|
168
194
|
// gather all the source elements in picture
|
|
169
195
|
const sources = picture.querySelectorAll('source')
|
|
170
196
|
let loadedSomething = false
|
|
171
197
|
|
|
172
198
|
for (let s = 0; s < sources.length; s += 1) {
|
|
173
199
|
const source = sources[s]
|
|
174
|
-
if (!source.hasAttribute('data-ll-
|
|
200
|
+
if (!source.hasAttribute('data-ll-ready')) {
|
|
175
201
|
loadedSomething = true
|
|
176
202
|
}
|
|
177
203
|
if (source.hasAttribute('data-srcset')) {
|
|
178
204
|
source.setAttribute('srcset', source.dataset.srcset)
|
|
179
|
-
source.setAttribute('data-ll-
|
|
205
|
+
source.setAttribute('data-ll-ready', '')
|
|
180
206
|
}
|
|
181
207
|
}
|
|
182
208
|
|
|
@@ -187,24 +213,25 @@ export default class Lazyload {
|
|
|
187
213
|
const img = picture.querySelector('img')
|
|
188
214
|
|
|
189
215
|
const onload = () => {
|
|
190
|
-
if (!img.getAttribute('data-ll-
|
|
191
|
-
// set sizes attribute on load again,
|
|
192
|
-
// since firefox sometimes is a bit slow to
|
|
216
|
+
if (!img.getAttribute('data-ll-ready') && this.app.browser === 'firefox') {
|
|
217
|
+
// set sizes attribute on load again,
|
|
218
|
+
// since firefox sometimes is a bit slow to
|
|
193
219
|
// get the actual image width
|
|
194
220
|
const width = this.getWidth(img)
|
|
195
221
|
|
|
196
222
|
img.setAttribute('sizes', `${width}px`)
|
|
197
223
|
if (img.parentNode) {
|
|
198
|
-
Array.from(Dom.all(img.parentNode, 'source'))
|
|
199
|
-
|
|
224
|
+
Array.from(Dom.all(img.parentNode, 'source')).forEach(source =>
|
|
225
|
+
source.setAttribute('sizes', `${width}px`)
|
|
226
|
+
)
|
|
200
227
|
}
|
|
201
228
|
}
|
|
202
229
|
|
|
203
230
|
img.removeAttribute('data-ll-placeholder')
|
|
204
231
|
img.removeAttribute('data-ll-blurred')
|
|
205
232
|
img.removeAttribute('data-ll-loading')
|
|
206
|
-
img.setAttribute('data-ll-
|
|
207
|
-
picture.setAttribute('data-ll-srcset-
|
|
233
|
+
img.setAttribute('data-ll-ready', '')
|
|
234
|
+
picture.setAttribute('data-ll-srcset-ready', '')
|
|
208
235
|
}
|
|
209
236
|
|
|
210
237
|
img.addEventListener('load', onload, false)
|
|
@@ -225,8 +252,35 @@ export default class Lazyload {
|
|
|
225
252
|
}
|
|
226
253
|
|
|
227
254
|
// safari sometimes caches, so force load
|
|
228
|
-
if (img.complete) {
|
|
255
|
+
if (img.complete) {
|
|
256
|
+
onload()
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
dispatchElementEvent(img, Events.IMAGE_LAZYLOADED)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/* reveal by just setting `data-ll-loaded` */
|
|
263
|
+
revealPicture(picture) {
|
|
264
|
+
const img = picture.querySelector('img')
|
|
265
|
+
if (img.hasAttribute('data-ll-loaded')) {
|
|
266
|
+
return
|
|
267
|
+
}
|
|
268
|
+
img.setAttribute('data-ll-loaded', '')
|
|
269
|
+
dispatchElementEvent(img, Events.IMAGE_REVEALED)
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
lazyloadImages(elements) {
|
|
273
|
+
elements.forEach(item => {
|
|
274
|
+
if (item.isIntersecting || item.intersectionRatio > 0) {
|
|
275
|
+
const image = item.target
|
|
276
|
+
this.swapImage(image)
|
|
277
|
+
this.imageObserver.unobserve(image)
|
|
278
|
+
}
|
|
279
|
+
})
|
|
280
|
+
}
|
|
229
281
|
|
|
230
|
-
|
|
282
|
+
swapImage(image) {
|
|
283
|
+
image.src = image.dataset.src
|
|
284
|
+
image.setAttribute('data-ll-loaded', '')
|
|
231
285
|
}
|
|
232
286
|
}
|