@brandocms/jupiter 3.55.0 → 4.0.0-beta.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/README.md +509 -54
- package/package.json +30 -18
- package/src/index.js +15 -10
- package/src/modules/Application/index.js +236 -158
- package/src/modules/Breakpoints/index.js +116 -36
- package/src/modules/Cookies/index.js +95 -64
- package/src/modules/CoverOverlay/index.js +21 -14
- package/src/modules/Dataloader/index.js +71 -24
- package/src/modules/Dataloader/url-sync.js +238 -0
- package/src/modules/Dom/index.js +24 -0
- package/src/modules/DoubleHeader/index.js +571 -0
- package/src/modules/Dropdown/index.js +108 -73
- package/src/modules/EqualHeightElements/index.js +8 -8
- package/src/modules/EqualHeightImages/index.js +15 -7
- package/src/modules/FixedHeader/index.js +116 -30
- package/src/modules/FooterReveal/index.js +5 -5
- package/src/modules/HeroSlider/index.js +231 -106
- package/src/modules/HeroVideo/index.js +72 -44
- package/src/modules/Lazyload/index.js +128 -80
- package/src/modules/Lightbox/index.js +101 -80
- package/src/modules/Links/index.js +77 -51
- package/src/modules/Looper/index.js +1737 -0
- package/src/modules/Marquee/index.js +106 -37
- package/src/modules/MobileMenu/index.js +105 -130
- package/src/modules/Moonwalk/index.js +479 -153
- package/src/modules/Parallax/index.js +280 -57
- package/src/modules/Popover/index.js +187 -17
- package/src/modules/Popup/index.js +172 -53
- package/src/modules/ScrollSpy/index.js +21 -0
- package/src/modules/StackedBoxes/index.js +8 -6
- package/src/modules/StickyHeader/index.js +394 -164
- package/src/modules/Toggler/index.js +207 -11
- package/src/modules/Typography/index.js +33 -20
- package/src/utils/motion-helpers.js +330 -0
- package/types/README.md +159 -0
- package/types/events/index.d.ts +20 -0
- package/types/index.d.ts +6 -0
- package/types/modules/Application/index.d.ts +168 -0
- package/types/modules/Breakpoints/index.d.ts +40 -0
- package/types/modules/Cookies/index.d.ts +81 -0
- package/types/modules/CoverOverlay/index.d.ts +6 -0
- package/types/modules/Dataloader/index.d.ts +38 -0
- package/types/modules/Dataloader/url-sync.d.ts +36 -0
- package/types/modules/Dom/index.d.ts +47 -0
- package/types/modules/DoubleHeader/index.d.ts +63 -0
- package/types/modules/Dropdown/index.d.ts +15 -0
- package/types/modules/EqualHeightElements/index.d.ts +8 -0
- package/types/modules/EqualHeightImages/index.d.ts +11 -0
- package/types/modules/FeatureTests/index.d.ts +27 -0
- package/types/modules/FixedHeader/index.d.ts +219 -0
- package/types/modules/Fontloader/index.d.ts +5 -0
- package/types/modules/FooterReveal/index.d.ts +5 -0
- package/types/modules/HeroSlider/index.d.ts +28 -0
- package/types/modules/HeroVideo/index.d.ts +83 -0
- package/types/modules/Lazyload/index.d.ts +80 -0
- package/types/modules/Lightbox/index.d.ts +123 -0
- package/types/modules/Links/index.d.ts +55 -0
- package/types/modules/Looper/index.d.ts +127 -0
- package/types/modules/Marquee/index.d.ts +23 -0
- package/types/modules/MobileMenu/index.d.ts +63 -0
- package/types/modules/Moonwalk/index.d.ts +322 -0
- package/types/modules/Parallax/index.d.ts +71 -0
- package/types/modules/Popover/index.d.ts +29 -0
- package/types/modules/Popup/index.d.ts +76 -0
- package/types/modules/ScrollSpy/index.d.ts +29 -0
- package/types/modules/StackedBoxes/index.d.ts +9 -0
- package/types/modules/StickyHeader/index.d.ts +220 -0
- package/types/modules/Toggler/index.d.ts +48 -0
- package/types/modules/Typography/index.d.ts +77 -0
- package/types/utils/dispatchElementEvent.d.ts +1 -0
- package/types/utils/imageIsLoaded.d.ts +1 -0
- package/types/utils/imagesAreLoaded.d.ts +1 -0
- package/types/utils/loadScript.d.ts +2 -0
- package/types/utils/prefersReducedMotion.d.ts +4 -0
- package/types/utils/rafCallback.d.ts +2 -0
- package/types/utils/zoom.d.ts +4 -0
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import _defaultsDeep from 'lodash.defaultsdeep'
|
|
2
2
|
import * as Events from '../../events'
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {Object} BreakpointsOptions
|
|
6
|
+
* @property {boolean} [runListenerOnInit=false] - Whether to run listener on initialization
|
|
7
|
+
* @property {string[]} [breakpoints=['xs', 'sm', 'md', 'lg']] - Breakpoint names
|
|
8
|
+
* @property {Object.<string, Function>} [listeners={}] - Listener functions for breakpoints
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** @type {BreakpointsOptions} */
|
|
4
12
|
const DEFAULT_OPTIONS = {
|
|
5
13
|
runListenerOnInit: false,
|
|
6
14
|
breakpoints: ['xs', 'sm', 'md', 'lg'],
|
|
@@ -13,14 +21,24 @@ const DEFAULT_OPTIONS = {
|
|
|
13
21
|
// // NOT XS ANYMORE
|
|
14
22
|
// }
|
|
15
23
|
// }
|
|
16
|
-
}
|
|
24
|
+
},
|
|
17
25
|
}
|
|
18
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Breakpoints module for responsive design
|
|
29
|
+
*/
|
|
19
30
|
export default class Breakpoints {
|
|
31
|
+
/**
|
|
32
|
+
* Create a new Breakpoints instance
|
|
33
|
+
* @param {Object} app - Application instance
|
|
34
|
+
* @param {BreakpointsOptions} [opts={}] - Breakpoints options
|
|
35
|
+
*/
|
|
20
36
|
constructor(app, opts = {}) {
|
|
21
37
|
this.app = app
|
|
22
38
|
this.mediaQueries = {}
|
|
23
39
|
this.opts = _defaultsDeep(opts, DEFAULT_OPTIONS)
|
|
40
|
+
this.currentBreakpoint = null
|
|
41
|
+
this.initialized = false
|
|
24
42
|
window.addEventListener(Events.APPLICATION_PRELUDIUM, () => {
|
|
25
43
|
this.initialize(false)
|
|
26
44
|
})
|
|
@@ -30,63 +48,125 @@ export default class Breakpoints {
|
|
|
30
48
|
}
|
|
31
49
|
|
|
32
50
|
initialize(reveal = false) {
|
|
33
|
-
|
|
34
|
-
this.
|
|
35
|
-
|
|
51
|
+
if (!reveal) {
|
|
52
|
+
this.opts.breakpoints.forEach((size) => {
|
|
53
|
+
this.mediaQueries[size] = this._getVal(`--breakpoint-${size}`)
|
|
54
|
+
})
|
|
36
55
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
|
|
56
|
+
const keys = Object.keys(this.mediaQueries)
|
|
57
|
+
keys.forEach((key) => {
|
|
58
|
+
let query = ''
|
|
59
|
+
const next = keys[(keys.indexOf(key) + 1) % keys.length]
|
|
60
|
+
if (
|
|
61
|
+
key === this.opts.breakpoints[0] &&
|
|
62
|
+
this.mediaQueries[key] === '0'
|
|
63
|
+
) {
|
|
64
|
+
query = `(min-width: 0px) and (max-width: ${parseInt(this.mediaQueries[next]) - 1}px)`
|
|
65
|
+
} else if (next === this.opts.breakpoints[0]) {
|
|
66
|
+
// max size
|
|
67
|
+
query = `(min-width: ${this.mediaQueries[key]})`
|
|
68
|
+
} else {
|
|
69
|
+
query = `(min-width: ${this.mediaQueries[key]}) and (max-width: ${
|
|
70
|
+
parseInt(this.mediaQueries[next]) - 1
|
|
71
|
+
}px)`
|
|
72
|
+
}
|
|
51
73
|
|
|
52
|
-
|
|
53
|
-
this.mediaQueries[key].addListener(this.defaultListener.bind(this))
|
|
74
|
+
this.mediaQueries[key] = window.matchMedia(query)
|
|
54
75
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
76
|
+
// Replace the direct listener with a combined one that handles both core and custom behavior
|
|
77
|
+
const combinedListener = (e) => {
|
|
78
|
+
if (e.matches) {
|
|
79
|
+
// Get the current breakpoint
|
|
80
|
+
const oldBreakpoint = this.currentBreakpoint
|
|
81
|
+
this.setCurrentBreakpoint()
|
|
59
82
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
83
|
+
// Only dispatch event if breakpoint actually changed
|
|
84
|
+
if (oldBreakpoint !== this.currentBreakpoint) {
|
|
85
|
+
const evt = new CustomEvent(Events.BREAKPOINT_CHANGE, {
|
|
86
|
+
detail: {
|
|
87
|
+
leaveBreakpoint: oldBreakpoint,
|
|
88
|
+
enterBreakpoint: this.currentBreakpoint,
|
|
89
|
+
},
|
|
90
|
+
})
|
|
91
|
+
window.dispatchEvent(evt)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Run any custom listener if one exists for this breakpoint
|
|
96
|
+
if (Object.prototype.hasOwnProperty.call(this.opts.listeners, key)) {
|
|
97
|
+
this.opts.listeners[key](e)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
this.mediaQueries[key].addListener(combinedListener)
|
|
102
|
+
})
|
|
65
103
|
}
|
|
66
104
|
|
|
105
|
+
// Set the current breakpoint first
|
|
67
106
|
this.setCurrentBreakpoint()
|
|
107
|
+
|
|
108
|
+
// Only fire events and run listeners for initialization if needed
|
|
109
|
+
if (reveal && this.opts.runListenerOnInit && !this.initialized) {
|
|
110
|
+
this.initialized = true
|
|
111
|
+
const result = this.getCurrentBreakpoint()
|
|
112
|
+
|
|
113
|
+
if (result && result.key && result.mq) {
|
|
114
|
+
// Create a fake event object that mimics MediaQueryListEvent
|
|
115
|
+
const fakeEvent = {
|
|
116
|
+
matches: result.mq.matches,
|
|
117
|
+
media: result.mq.media,
|
|
118
|
+
target: result.mq,
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Fire the BREAKPOINT_CHANGE event only once during initialization
|
|
122
|
+
const evt = new CustomEvent(Events.BREAKPOINT_CHANGE)
|
|
123
|
+
window.dispatchEvent(evt)
|
|
124
|
+
|
|
125
|
+
// Run any custom listener if one exists for this breakpoint
|
|
126
|
+
if (
|
|
127
|
+
Object.prototype.hasOwnProperty.call(this.opts.listeners, result.key)
|
|
128
|
+
) {
|
|
129
|
+
this.opts.listeners[result.key](fakeEvent)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
68
133
|
}
|
|
69
134
|
|
|
70
135
|
getCurrentBreakpoint() {
|
|
71
|
-
|
|
136
|
+
// First check if mediaQueries is populated
|
|
137
|
+
if (!Object.keys(this.mediaQueries).length) {
|
|
138
|
+
return null
|
|
139
|
+
}
|
|
72
140
|
|
|
73
|
-
|
|
141
|
+
const key = Object.keys(this.mediaQueries).find((q) => {
|
|
142
|
+
return this.mediaQueries[q] && this.mediaQueries[q].matches
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
// Only return if we found a matching breakpoint
|
|
146
|
+
if (key && this.mediaQueries[key]) {
|
|
147
|
+
return { key, mq: this.mediaQueries[key] }
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return null
|
|
74
151
|
}
|
|
75
152
|
|
|
76
153
|
defaultListener(e) {
|
|
77
154
|
if (e.matches) {
|
|
78
155
|
this.setCurrentBreakpoint()
|
|
79
156
|
}
|
|
80
|
-
const evt = new CustomEvent(Events.BREAKPOINT_CHANGE)
|
|
81
|
-
window.dispatchEvent(evt)
|
|
82
157
|
}
|
|
83
158
|
|
|
84
159
|
setCurrentBreakpoint() {
|
|
85
|
-
const
|
|
86
|
-
|
|
160
|
+
const result = this.getCurrentBreakpoint()
|
|
161
|
+
if (result && result.key) {
|
|
162
|
+
this.currentBreakpoint = result.key
|
|
163
|
+
this.app.breakpoint = result.key
|
|
164
|
+
}
|
|
87
165
|
}
|
|
88
166
|
|
|
89
167
|
_getVal(key) {
|
|
90
|
-
return getComputedStyle(document.documentElement)
|
|
168
|
+
return getComputedStyle(document.documentElement)
|
|
169
|
+
.getPropertyValue(key)
|
|
170
|
+
.trim()
|
|
91
171
|
}
|
|
92
172
|
}
|
|
@@ -1,46 +1,64 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { animate } from 'motion'
|
|
2
2
|
import _defaultsDeep from 'lodash.defaultsdeep'
|
|
3
3
|
import * as Events from '../../events'
|
|
4
|
-
|
|
4
|
+
import { set } from '../../utils/motion-helpers'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {Object} CookiesOptions
|
|
8
|
+
* @property {Function} [onAccept] - Called when cookies are accepted
|
|
9
|
+
* @property {Function} [onRefuse] - Called when cookies are refused
|
|
10
|
+
* @property {Function} [alreadyConsented] - Called if user has already consented to cookies
|
|
11
|
+
* @property {Function} [alreadyRefused] - Called if user has already refused cookies
|
|
12
|
+
* @property {Function} [setCookies] - Custom function to set cookies
|
|
13
|
+
* @property {Function} [showCC] - Custom function to display cookie consent dialog
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** @type {CookiesOptions} */
|
|
5
17
|
const DEFAULT_OPTIONS = {
|
|
6
|
-
onAccept: c => {
|
|
18
|
+
onAccept: (c) => {
|
|
7
19
|
const oneYearFromNow = new Date()
|
|
8
20
|
oneYearFromNow.setFullYear(oneYearFromNow.getFullYear() + 1)
|
|
9
21
|
|
|
10
|
-
const timeline = gsap.timeline()
|
|
11
22
|
c.setCookie('COOKIES_CONSENT_STATUS', 1, oneYearFromNow, '/')
|
|
12
23
|
c.opts.setCookies(c)
|
|
13
24
|
|
|
14
|
-
timeline
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
25
|
+
const timeline = [
|
|
26
|
+
[c.cc, { y: '120%' }, { duration: 0.35, ease: 'easeIn', at: 0 }],
|
|
27
|
+
[c.inner, { opacity: 0 }, { duration: 0.3, ease: 'easeIn', at: 0 }]
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
animate(timeline).finished.then(() => {
|
|
31
|
+
c.cc.style.display = 'none'
|
|
32
|
+
})
|
|
18
33
|
},
|
|
19
34
|
|
|
20
|
-
onRefuse: c => {
|
|
35
|
+
onRefuse: (c) => {
|
|
21
36
|
const oneYearFromNow = new Date()
|
|
22
37
|
oneYearFromNow.setFullYear(oneYearFromNow.getFullYear() + 1)
|
|
23
38
|
|
|
24
|
-
const timeline = gsap.timeline()
|
|
25
39
|
c.setCookie('COOKIES_CONSENT_STATUS', 0, oneYearFromNow, '/')
|
|
26
40
|
|
|
27
|
-
timeline
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
41
|
+
const timeline = [
|
|
42
|
+
[c.cc, { y: '120%' }, { duration: 0.35, ease: 'easeIn', at: 0 }],
|
|
43
|
+
[c.inner, { opacity: 0 }, { duration: 0.3, ease: 'easeIn', at: 0 }]
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
animate(timeline).finished.then(() => {
|
|
47
|
+
c.cc.style.display = 'none'
|
|
48
|
+
})
|
|
31
49
|
},
|
|
32
50
|
|
|
33
|
-
alreadyConsented: c => {
|
|
51
|
+
alreadyConsented: (c) => {
|
|
34
52
|
// user has already consented to cookies. Can be used to update/load gtm etc.
|
|
35
53
|
},
|
|
36
54
|
|
|
37
|
-
alreadyRefused: c => {
|
|
55
|
+
alreadyRefused: (c) => {
|
|
38
56
|
// user has already refused cookies.
|
|
39
57
|
},
|
|
40
58
|
|
|
41
|
-
setCookies: c => {},
|
|
59
|
+
setCookies: (c) => {},
|
|
42
60
|
|
|
43
|
-
showCC: c => {
|
|
61
|
+
showCC: (c) => {
|
|
44
62
|
if (c.hasCookie('COOKIES_CONSENT_STATUS')) {
|
|
45
63
|
if (c.getCookie('COOKIES_CONSENT_STATUS') === '1') {
|
|
46
64
|
c.opts.alreadyConsented(c)
|
|
@@ -50,54 +68,34 @@ const DEFAULT_OPTIONS = {
|
|
|
50
68
|
return
|
|
51
69
|
}
|
|
52
70
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
)
|
|
71
|
-
.fromTo(
|
|
72
|
-
c.text,
|
|
73
|
-
{
|
|
74
|
-
duration: 0.7,
|
|
75
|
-
opacity: 0
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
duration: 0.7,
|
|
79
|
-
opacity: 1,
|
|
80
|
-
ease: 'power3.out'
|
|
81
|
-
},
|
|
82
|
-
'-=0.35'
|
|
83
|
-
)
|
|
84
|
-
.fromTo(
|
|
85
|
-
c.btns,
|
|
86
|
-
{
|
|
87
|
-
duration: 0.7,
|
|
88
|
-
opacity: 0
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
duration: 0.7,
|
|
92
|
-
opacity: 1,
|
|
93
|
-
ease: 'power3.out'
|
|
94
|
-
},
|
|
95
|
-
'-=0.35'
|
|
96
|
-
)
|
|
97
|
-
}
|
|
71
|
+
// Set display block and reset state immediately
|
|
72
|
+
c.cc.style.display = 'block'
|
|
73
|
+
set(c.cc, { opacity: 1 })
|
|
74
|
+
set(c.inner, { opacity: 1 })
|
|
75
|
+
|
|
76
|
+
// Calculate timeline positions:
|
|
77
|
+
// - c.cc: starts at 1s, duration 0.5s, ends at 1.5s
|
|
78
|
+
// - c.text: starts at 1.15s (0.15s after cc starts), duration 0.7s, ends at 1.85s
|
|
79
|
+
// - c.btns: starts at 1.5s (when cc finishes), duration 0.7s
|
|
80
|
+
const timeline = [
|
|
81
|
+
[c.cc, { y: ['120%', '0%'] }, { duration: 0.5, ease: 'easeOut', at: 1 }],
|
|
82
|
+
[c.text, { opacity: [0, 1] }, { duration: 0.7, ease: 'easeOut', at: 1.15 }],
|
|
83
|
+
[c.btns, { opacity: [0, 1] }, { duration: 0.7, ease: 'easeOut', at: 1.5 }]
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
animate(timeline)
|
|
87
|
+
},
|
|
98
88
|
}
|
|
99
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Cookies module for handling cookie consent
|
|
92
|
+
*/
|
|
100
93
|
export default class Cookies {
|
|
94
|
+
/**
|
|
95
|
+
* Create a new Cookies instance
|
|
96
|
+
* @param {Object} app - Application instance
|
|
97
|
+
* @param {CookiesOptions} [opts={}] - Cookies options
|
|
98
|
+
*/
|
|
101
99
|
constructor(app, opts = {}) {
|
|
102
100
|
this.app = app
|
|
103
101
|
this.opts = _defaultsDeep(opts, DEFAULT_OPTIONS)
|
|
@@ -127,6 +125,11 @@ export default class Cookies {
|
|
|
127
125
|
}
|
|
128
126
|
}
|
|
129
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Get a cookie value by key
|
|
130
|
+
* @param {string} sKey - Cookie key
|
|
131
|
+
* @returns {string|null} Cookie value or null if not found
|
|
132
|
+
*/
|
|
130
133
|
getCookie(sKey) {
|
|
131
134
|
if (!sKey) {
|
|
132
135
|
return null
|
|
@@ -146,6 +149,16 @@ export default class Cookies {
|
|
|
146
149
|
)
|
|
147
150
|
}
|
|
148
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Set a cookie
|
|
154
|
+
* @param {string} sKey - Cookie key
|
|
155
|
+
* @param {string|number} sValue - Cookie value
|
|
156
|
+
* @param {Date|string|number} vEnd - Expiration date, string date, or max age in seconds
|
|
157
|
+
* @param {string} [sPath] - Cookie path
|
|
158
|
+
* @param {string} [sDomain] - Cookie domain
|
|
159
|
+
* @param {boolean} [bSecure] - Secure flag
|
|
160
|
+
* @returns {boolean} Whether cookie was set successfully
|
|
161
|
+
*/
|
|
149
162
|
setCookie(sKey, sValue, vEnd, sPath, sDomain, bSecure) {
|
|
150
163
|
if (!sKey || /^(?:expires|max-age|path|domain|secure)$/i.test(sKey)) {
|
|
151
164
|
return false
|
|
@@ -155,7 +168,9 @@ export default class Cookies {
|
|
|
155
168
|
switch (vEnd.constructor) {
|
|
156
169
|
case Number:
|
|
157
170
|
sExpires =
|
|
158
|
-
vEnd === Infinity
|
|
171
|
+
vEnd === Infinity
|
|
172
|
+
? '; expires=Fri, 31 Dec 9999 23:59:59 GMT'
|
|
173
|
+
: `; max-age=${vEnd}`
|
|
159
174
|
break
|
|
160
175
|
case String:
|
|
161
176
|
sExpires = `; expires=${vEnd}`
|
|
@@ -173,6 +188,13 @@ export default class Cookies {
|
|
|
173
188
|
return true
|
|
174
189
|
}
|
|
175
190
|
|
|
191
|
+
/**
|
|
192
|
+
* Remove a cookie
|
|
193
|
+
* @param {string} sKey - Cookie key
|
|
194
|
+
* @param {string} [sPath] - Cookie path
|
|
195
|
+
* @param {string} [sDomain] - Cookie domain
|
|
196
|
+
* @returns {boolean} Whether cookie was removed successfully
|
|
197
|
+
*/
|
|
176
198
|
removeCookie(sKey, sPath, sDomain) {
|
|
177
199
|
if (!this.hasCookie(sKey)) {
|
|
178
200
|
return false
|
|
@@ -183,6 +205,11 @@ export default class Cookies {
|
|
|
183
205
|
return true
|
|
184
206
|
}
|
|
185
207
|
|
|
208
|
+
/**
|
|
209
|
+
* Check if a cookie exists
|
|
210
|
+
* @param {string} sKey - Cookie key
|
|
211
|
+
* @returns {boolean} Whether cookie exists
|
|
212
|
+
*/
|
|
186
213
|
hasCookie(sKey) {
|
|
187
214
|
if (!sKey || /^(?:expires|max-age|path|domain|secure)$/i.test(sKey)) {
|
|
188
215
|
return false
|
|
@@ -192,6 +219,10 @@ export default class Cookies {
|
|
|
192
219
|
).test(document.cookie)
|
|
193
220
|
}
|
|
194
221
|
|
|
222
|
+
/**
|
|
223
|
+
* Get all cookie keys
|
|
224
|
+
* @returns {string[]} Array of cookie keys
|
|
225
|
+
*/
|
|
195
226
|
keys() {
|
|
196
227
|
const aKeys = document.cookie
|
|
197
228
|
.replace(/((?:^|\s*;)[^=]+)(?=;|$)|^\s*|\s*(?:=[^;]*)?(?:\1|$)/g, '')
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { animate } from 'motion'
|
|
2
2
|
import _defaultsDeep from 'lodash.defaultsdeep'
|
|
3
3
|
|
|
4
4
|
const DEFAULT_OPTIONS = {}
|
|
@@ -13,7 +13,7 @@ export default class CoverOverlay {
|
|
|
13
13
|
initialize() {
|
|
14
14
|
const coveredModules = document.querySelectorAll('[data-cover-overlay]')
|
|
15
15
|
|
|
16
|
-
Array.from(coveredModules).forEach(v => {
|
|
16
|
+
Array.from(coveredModules).forEach((v) => {
|
|
17
17
|
let player
|
|
18
18
|
const overlay = v.querySelector('.picture-wrapper')
|
|
19
19
|
const btn = v.querySelector('[data-cover-overlay-button]')
|
|
@@ -35,18 +35,25 @@ export default class CoverOverlay {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
btn.addEventListener('click', () => {
|
|
38
|
-
const timeline =
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
})
|
|
38
|
+
const timeline = [
|
|
39
|
+
[btn, { opacity: 0 }, { duration: 0.5, ease: 'easeIn', at: 0 }],
|
|
40
|
+
[overlay, { opacity: 0 }, { duration: 1, ease: 'easeIn', at: 0 }],
|
|
41
|
+
[iframe, { opacity: 1 }, { duration: 0.5, ease: 'easeOut', at: 0.5 }],
|
|
42
|
+
[overlay, { display: 'none' }, { duration: 0, at: 1 }]
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
animate(timeline).finished.then(() => {
|
|
46
|
+
if (player) {
|
|
47
|
+
// Vimeo player
|
|
48
|
+
player.play()
|
|
49
|
+
} else if (iframe && iframe.src.includes('youtube.com')) {
|
|
50
|
+
// YouTube postMessage API
|
|
51
|
+
iframe.contentWindow.postMessage(
|
|
52
|
+
'{"event":"command","func":"playVideo","args":""}',
|
|
53
|
+
'*'
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
})
|
|
50
57
|
})
|
|
51
58
|
})
|
|
52
59
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Dom from '../Dom'
|
|
2
2
|
import _defaultsDeep from 'lodash.defaultsdeep'
|
|
3
|
+
import DataloaderUrlSync from './url-sync'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Load data by ajax
|
|
@@ -33,21 +34,30 @@ import _defaultsDeep from 'lodash.defaultsdeep'
|
|
|
33
34
|
*
|
|
34
35
|
* You can also set a target for the canvas if the category selector and canvas are in different modules:
|
|
35
36
|
*
|
|
37
|
+
* Option 1 (legacy): Using data-loader-canvas-target
|
|
36
38
|
* <div data-loader="/api/posts" data-loader-id="news" data-loader-canvas-target="#news-canvas">
|
|
39
|
+
* <div data-loader-canvas id="news-canvas">
|
|
37
40
|
*
|
|
38
|
-
*
|
|
41
|
+
* Option 2 (recommended): Using data-loader-canvas-for
|
|
42
|
+
* <div data-loader="/api/posts" data-loader-id="news">
|
|
43
|
+
* <div data-loader-canvas data-loader-canvas-for="news">
|
|
44
|
+
*
|
|
45
|
+
* And if the "more" button is outside the loader element, use data-loader-more-for:
|
|
46
|
+
* <button data-loader-more-for="news">Load more</button>
|
|
39
47
|
*/
|
|
40
48
|
|
|
41
49
|
const DEFAULT_OPTIONS = {
|
|
42
50
|
page: 0,
|
|
43
51
|
loaderParam: {},
|
|
44
52
|
filter: '',
|
|
45
|
-
|
|
53
|
+
urlSync: null,
|
|
54
|
+
onFetch: dataloader => {
|
|
46
55
|
/**
|
|
47
56
|
* Called after fetch complete. Do your DOM manipulation here
|
|
48
57
|
*
|
|
49
58
|
* Example:
|
|
50
59
|
*
|
|
60
|
+
*
|
|
51
61
|
* const mw = new Moonwalk(dataloader.app, configureMoonwalk(dataloader.app), dataloader.$canvasEl)
|
|
52
62
|
* new Lazyload(dataloader.app, { useNativeLazyloadIfAvailable: false }, dataloader.$canvasEl)
|
|
53
63
|
* new EqualHeightImages(dataloader.app, {}, dataloader.$canvasEl)
|
|
@@ -61,22 +71,33 @@ export default class Dataloader {
|
|
|
61
71
|
this.status = 'available'
|
|
62
72
|
this.app = app
|
|
63
73
|
this.$el = $el
|
|
74
|
+
this.id = $el.dataset.loaderId
|
|
75
|
+
|
|
64
76
|
if ($el.hasAttribute('data-loader-canvas-target')) {
|
|
65
77
|
this.$canvasEl = Dom.find($el.getAttribute('data-loader-canvas-target'))
|
|
66
78
|
} else {
|
|
67
79
|
this.$canvasEl = Dom.find($el, '[data-loader-canvas]')
|
|
68
80
|
}
|
|
81
|
+
|
|
82
|
+
// Support new pattern: data-loader-canvas-for
|
|
83
|
+
if (!this.$canvasEl && this.id) {
|
|
84
|
+
this.$canvasEl = Dom.find(`[data-loader-canvas-for="${this.id}"]`)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (!this.$canvasEl) {
|
|
88
|
+
throw new Error('No canvas element found.')
|
|
89
|
+
}
|
|
69
90
|
this.opts = _defaultsDeep(opts, DEFAULT_OPTIONS)
|
|
70
91
|
this.initialize()
|
|
71
92
|
}
|
|
72
93
|
|
|
73
94
|
static replaceInnerHTML(el, url) {
|
|
74
|
-
return new Promise(
|
|
95
|
+
return new Promise(resolve => {
|
|
75
96
|
fetch(url)
|
|
76
|
-
.then(
|
|
97
|
+
.then(res => {
|
|
77
98
|
return res.text()
|
|
78
99
|
})
|
|
79
|
-
.then(
|
|
100
|
+
.then(html => {
|
|
80
101
|
el.innerHTML = html
|
|
81
102
|
return resolve(el)
|
|
82
103
|
})
|
|
@@ -97,32 +118,55 @@ export default class Dataloader {
|
|
|
97
118
|
this.baseURL = url
|
|
98
119
|
}
|
|
99
120
|
|
|
121
|
+
setInitialParams() {
|
|
122
|
+
// Set initial parameters from pre-selected elements
|
|
123
|
+
this.$paramEls.forEach($paramEl => {
|
|
124
|
+
if ($paramEl.hasAttribute('data-loader-param-selected')) {
|
|
125
|
+
const key = $paramEl.dataset.loaderParamKey || 'defaultParam'
|
|
126
|
+
this.opts.loaderParam[key] = $paramEl.dataset.loaderParam
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
// Update URL with initial params if URL sync is enabled
|
|
131
|
+
if (this.urlSync && this.opts.urlSync[this.id].updateOnInit !== false) {
|
|
132
|
+
this.urlSync.updateUrl(this.opts.loaderParam)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
100
136
|
initialize() {
|
|
101
137
|
this.baseURL = this.$el.dataset.loader
|
|
102
138
|
this.$paramEls = Dom.all(this.$el, '[data-loader-param]')
|
|
139
|
+
|
|
140
|
+
// Initialize URL sync if config exists for this dataloader ID
|
|
141
|
+
if (this.opts.urlSync?.[this.id]) {
|
|
142
|
+
this.urlSync = new DataloaderUrlSync(this, this.opts.urlSync[this.id])
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Set initial parameters from pre-selected elements
|
|
146
|
+
this.setInitialParams()
|
|
103
147
|
|
|
104
|
-
this.$paramEls.forEach(
|
|
148
|
+
this.$paramEls.forEach($paramEl => {
|
|
105
149
|
$paramEl.addEventListener('click', this.onParam.bind(this))
|
|
106
150
|
})
|
|
107
151
|
|
|
108
152
|
this.$moreBtn = Dom.find(this.$el, '[data-loader-more]')
|
|
109
153
|
|
|
154
|
+
if (!this.$moreBtn && this.id) {
|
|
155
|
+
this.$moreBtn = Dom.find(`[data-loader-more-for="${this.id}"]`)
|
|
156
|
+
}
|
|
157
|
+
|
|
110
158
|
if (this.$moreBtn) {
|
|
111
159
|
this.$moreBtn.addEventListener('click', this.onMore.bind(this))
|
|
112
160
|
}
|
|
113
161
|
|
|
114
162
|
this.$filterInput = Dom.find(this.$el, '[data-loader-filter]')
|
|
115
163
|
|
|
116
|
-
if (!this.$filterInput && this
|
|
117
|
-
this.id = this.$el.dataset.loaderId
|
|
164
|
+
if (!this.$filterInput && this.id) {
|
|
118
165
|
this.$filterInput = Dom.find(`[data-loader-filter-for="${this.id}"]`)
|
|
119
166
|
}
|
|
120
167
|
|
|
121
168
|
if (this.$filterInput) {
|
|
122
|
-
this.$filterInput.addEventListener(
|
|
123
|
-
'input',
|
|
124
|
-
this.debounce(this.onFilterInput.bind(this))
|
|
125
|
-
)
|
|
169
|
+
this.$filterInput.addEventListener('input', this.debounce(this.onFilterInput.bind(this)))
|
|
126
170
|
}
|
|
127
171
|
}
|
|
128
172
|
|
|
@@ -159,11 +203,9 @@ export default class Dataloader {
|
|
|
159
203
|
// if already selected, clear it
|
|
160
204
|
const key = e.currentTarget.dataset.loaderParamKey || 'defaultParam'
|
|
161
205
|
if (multiVals) {
|
|
162
|
-
this.opts.loaderParam[key] = this.opts.loaderParam[key].filter(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
166
|
-
)
|
|
206
|
+
this.opts.loaderParam[key] = this.opts.loaderParam[key].filter(val => {
|
|
207
|
+
return val !== e.currentTarget.dataset.loaderParam
|
|
208
|
+
})
|
|
167
209
|
} else {
|
|
168
210
|
delete this.opts.loaderParam[key]
|
|
169
211
|
}
|
|
@@ -178,7 +220,7 @@ export default class Dataloader {
|
|
|
178
220
|
e.currentTarget.setAttribute('data-loader-param-selected', '')
|
|
179
221
|
} else {
|
|
180
222
|
const paramKey = e.currentTarget.dataset.loaderParamKey
|
|
181
|
-
this.$paramEls.forEach(
|
|
223
|
+
this.$paramEls.forEach($paramEl => {
|
|
182
224
|
if (paramKey) {
|
|
183
225
|
if ($paramEl.dataset.loaderParamKey === paramKey) {
|
|
184
226
|
$paramEl.removeAttribute('data-loader-param-selected')
|
|
@@ -194,23 +236,28 @@ export default class Dataloader {
|
|
|
194
236
|
}
|
|
195
237
|
}
|
|
196
238
|
|
|
239
|
+
// Update URL if sync is enabled
|
|
240
|
+
if (this.urlSync) {
|
|
241
|
+
this.urlSync.updateUrl(this.opts.loaderParam)
|
|
242
|
+
}
|
|
243
|
+
|
|
197
244
|
this.fetch()
|
|
198
245
|
}
|
|
199
246
|
|
|
200
247
|
fetch(addEntries = false) {
|
|
201
248
|
const { defaultParam, ...otherParams } = this.opts.loaderParam
|
|
202
249
|
const filter = this.opts.filter
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
`${this.baseURL}/${defaultParam ? defaultParam + '/' : ''}${this.opts.page}?` +
|
|
250
|
+
|
|
251
|
+
const fetchUrl = `${this.baseURL}/${defaultParam ? defaultParam + '/' : ''}${this.opts.page}?` +
|
|
206
252
|
new URLSearchParams({ filter, ...otherParams })
|
|
207
|
-
|
|
208
|
-
|
|
253
|
+
|
|
254
|
+
fetch(fetchUrl)
|
|
255
|
+
.then(res => {
|
|
209
256
|
this.status = res.headers.get('jpt-dataloader') || 'available'
|
|
210
257
|
this.updateButton()
|
|
211
258
|
return res.text()
|
|
212
259
|
})
|
|
213
|
-
.then(
|
|
260
|
+
.then(html => {
|
|
214
261
|
if (addEntries) {
|
|
215
262
|
this.$canvasEl.innerHTML += html
|
|
216
263
|
} else {
|