@brandocms/jupiter 3.50.1 → 3.51.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/README.md +6 -0
- package/package.json +9 -14
- package/src/modules/Cookies/index.js +35 -2
- package/src/modules/Dataloader/index.js +67 -8
- package/src/modules/Dropdown/index.js +13 -3
- package/src/modules/EqualHeightImages/index.js +7 -3
- package/src/modules/FeatureTests/index.js +25 -0
- package/src/modules/FixedHeader/index.js +12 -4
- package/src/modules/Links/index.js +6 -0
- package/src/modules/Popover/index.js +10 -2
- package/src/modules/Toggler/index.js +7 -6
package/README.md
CHANGED
|
@@ -321,6 +321,12 @@ togglers.forEach(toggleEl => {
|
|
|
321
321
|
This affects the fixed header amongst other things.
|
|
322
322
|
- `scrollDuration` - `number` - `0.8` - how long the scroll lasts
|
|
323
323
|
|
|
324
|
+
By default anchor links get added to the browser history. You can skip this by setting
|
|
325
|
+
`data-skip-history` on the link **target**:
|
|
326
|
+
|
|
327
|
+
```html
|
|
328
|
+
<a id="content" name="content" data-skip-history></a>
|
|
329
|
+
```
|
|
324
330
|
|
|
325
331
|
|
|
326
332
|
## Moonwalk
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brandocms/jupiter",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.51.0",
|
|
4
4
|
"description": "Frontend helpers.",
|
|
5
5
|
"author": "Univers/Twined",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
"homepage": "https://github.com/brandocms/jupiter#readme",
|
|
21
21
|
"sideEffects": false,
|
|
22
22
|
"scripts": {
|
|
23
|
-
"lint": "eslint src/*.js",
|
|
24
23
|
"test": "jest __tests__ --passWithNoTests",
|
|
25
24
|
"coverage": "jest __tests__ --coverage"
|
|
26
25
|
},
|
|
@@ -33,19 +32,15 @@
|
|
|
33
32
|
"dependencies": {
|
|
34
33
|
"@egjs/hammerjs": "^2.0.17",
|
|
35
34
|
"body-scroll-lock": "^4.0.0-beta.0",
|
|
36
|
-
"gsap": "3.12.
|
|
35
|
+
"gsap": "3.12.5",
|
|
37
36
|
"lodash.defaultsdeep": "^4.6.1"
|
|
38
37
|
},
|
|
39
38
|
"devDependencies": {
|
|
40
|
-
"@babel/core": "^7.
|
|
41
|
-
"@babel/preset-env": "^7.
|
|
42
|
-
"babel-jest": "^29.
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"eslint-plugin-promise": "^6.1.1",
|
|
48
|
-
"jest": "^29.2.1",
|
|
49
|
-
"jest-environment-jsdom": "^29.2.1"
|
|
50
|
-
}
|
|
39
|
+
"@babel/core": "^7.25.2",
|
|
40
|
+
"@babel/preset-env": "^7.25.3",
|
|
41
|
+
"babel-jest": "^29.7.0",
|
|
42
|
+
"jest": "^29.7.0",
|
|
43
|
+
"jest-environment-jsdom": "^29.7.0"
|
|
44
|
+
},
|
|
45
|
+
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
|
51
46
|
}
|
|
@@ -8,7 +8,8 @@ const DEFAULT_OPTIONS = {
|
|
|
8
8
|
oneYearFromNow.setFullYear(oneYearFromNow.getFullYear() + 1)
|
|
9
9
|
|
|
10
10
|
const timeline = gsap.timeline()
|
|
11
|
-
c.setCookie('
|
|
11
|
+
c.setCookie('COOKIES_CONSENT_STATUS', 1, oneYearFromNow, '/')
|
|
12
|
+
c.opts.setCookies(c)
|
|
12
13
|
|
|
13
14
|
timeline
|
|
14
15
|
.to(c.cc, { duration: 0.35, y: '120%', ease: 'power3.in' }, '0')
|
|
@@ -16,8 +17,36 @@ const DEFAULT_OPTIONS = {
|
|
|
16
17
|
.set(c.cc, { display: 'none' })
|
|
17
18
|
},
|
|
18
19
|
|
|
20
|
+
onRefuse: c => {
|
|
21
|
+
const oneYearFromNow = new Date()
|
|
22
|
+
oneYearFromNow.setFullYear(oneYearFromNow.getFullYear() + 1)
|
|
23
|
+
|
|
24
|
+
const timeline = gsap.timeline()
|
|
25
|
+
c.setCookie('COOKIES_CONSENT_STATUS', 0, oneYearFromNow, '/')
|
|
26
|
+
|
|
27
|
+
timeline
|
|
28
|
+
.to(c.cc, { duration: 0.35, y: '120%', ease: 'power3.in' }, '0')
|
|
29
|
+
.to(c.inner, { duration: 0.3, opacity: 0, ease: 'power3.in' }, '0')
|
|
30
|
+
.set(c.cc, { display: 'none' })
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
alreadyConsented: c => {
|
|
34
|
+
// user has already consented to cookies. Can be used to update/load gtm etc.
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
alreadyRefused: c => {
|
|
38
|
+
// user has already refused cookies.
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
setCookies: c => {},
|
|
42
|
+
|
|
19
43
|
showCC: c => {
|
|
20
|
-
if (c.hasCookie('
|
|
44
|
+
if (c.hasCookie('COOKIES_CONSENT_STATUS')) {
|
|
45
|
+
if (c.getCookie('COOKIES_CONSENT_STATUS') === '1') {
|
|
46
|
+
c.opts.alreadyConsented(c)
|
|
47
|
+
} else {
|
|
48
|
+
c.opts.alreadyRefused(c)
|
|
49
|
+
}
|
|
21
50
|
return
|
|
22
51
|
}
|
|
23
52
|
|
|
@@ -78,6 +107,7 @@ export default class Cookies {
|
|
|
78
107
|
this.text = document.querySelector('.cookie-law-text')
|
|
79
108
|
this.btns = document.querySelector('.cookie-law-buttons')
|
|
80
109
|
this.btn = document.querySelector('.dismiss-cookielaw')
|
|
110
|
+
this.btnRefuse = document.querySelector('.refuse-cookielaw')
|
|
81
111
|
|
|
82
112
|
if (!this.btn) {
|
|
83
113
|
return
|
|
@@ -90,6 +120,9 @@ export default class Cookies {
|
|
|
90
120
|
this.btn.addEventListener('click', () => {
|
|
91
121
|
this.opts.onAccept(this)
|
|
92
122
|
})
|
|
123
|
+
this.btnRefuse.addEventListener('click', () => {
|
|
124
|
+
this.opts.onRefuse(this)
|
|
125
|
+
})
|
|
93
126
|
}
|
|
94
127
|
|
|
95
128
|
getCookie(sKey) {
|
|
@@ -48,9 +48,9 @@ const DEFAULT_OPTIONS = {
|
|
|
48
48
|
*
|
|
49
49
|
* Example:
|
|
50
50
|
*
|
|
51
|
-
* const mw = new Moonwalk(dataloader.app, configureMoonwalk(dataloader.app), dataloader.$
|
|
52
|
-
* new Lazyload(dataloader.app, { useNativeLazyloadIfAvailable: false }, dataloader.$
|
|
53
|
-
* new EqualHeightImages(dataloader.app, {}, dataloader.$
|
|
51
|
+
* const mw = new Moonwalk(dataloader.app, configureMoonwalk(dataloader.app), dataloader.$canvasEl)
|
|
52
|
+
* new Lazyload(dataloader.app, { useNativeLazyloadIfAvailable: false }, dataloader.$canvasEl)
|
|
53
|
+
* new EqualHeightImages(dataloader.app, {}, dataloader.$canvasEl)
|
|
54
54
|
* mw.ready()
|
|
55
55
|
*/
|
|
56
56
|
}
|
|
@@ -70,6 +70,19 @@ export default class Dataloader {
|
|
|
70
70
|
this.initialize()
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
static replaceInnerHTML(el, url) {
|
|
74
|
+
return new Promise(resolve => {
|
|
75
|
+
fetch(url)
|
|
76
|
+
.then(res => {
|
|
77
|
+
return res.text()
|
|
78
|
+
})
|
|
79
|
+
.then(html => {
|
|
80
|
+
el.innerHTML = html
|
|
81
|
+
return resolve(el)
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
|
|
73
86
|
debounce(func, delay = 650) {
|
|
74
87
|
let timerId
|
|
75
88
|
return (...args) => {
|
|
@@ -80,6 +93,10 @@ export default class Dataloader {
|
|
|
80
93
|
}
|
|
81
94
|
}
|
|
82
95
|
|
|
96
|
+
updateBaseURL(url) {
|
|
97
|
+
this.baseURL = url
|
|
98
|
+
}
|
|
99
|
+
|
|
83
100
|
initialize() {
|
|
84
101
|
this.baseURL = this.$el.dataset.loader
|
|
85
102
|
this.$paramEls = Dom.all(this.$el, '[data-loader-param]')
|
|
@@ -122,14 +139,56 @@ export default class Dataloader {
|
|
|
122
139
|
}
|
|
123
140
|
|
|
124
141
|
onParam(e) {
|
|
125
|
-
e.preventDefault()
|
|
126
142
|
this.loading()
|
|
127
143
|
// reset page when switching param!
|
|
128
144
|
this.opts.page = 0
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const
|
|
132
|
-
|
|
145
|
+
|
|
146
|
+
// param can have multiple values
|
|
147
|
+
const multiVals = e.currentTarget.hasAttribute('data-loader-param-multi')
|
|
148
|
+
|
|
149
|
+
// special case if it's a checkbox!
|
|
150
|
+
if (e.currentTarget.getAttribute('type') === 'checkbox') {
|
|
151
|
+
const key = e.currentTarget.dataset.loaderParamKey || 'defaultParam'
|
|
152
|
+
this.opts.loaderParam[key] = e.currentTarget.checked
|
|
153
|
+
} else {
|
|
154
|
+
e.preventDefault()
|
|
155
|
+
if (e.currentTarget.hasAttribute('data-loader-param-selected')) {
|
|
156
|
+
// if already selected, clear it
|
|
157
|
+
const key = e.currentTarget.dataset.loaderParamKey || 'defaultParam'
|
|
158
|
+
if (multiVals) {
|
|
159
|
+
this.opts.loaderParam[key] = this.opts.loaderParam[key].filter(val => {
|
|
160
|
+
return val !== e.currentTarget.dataset.loaderParam
|
|
161
|
+
})
|
|
162
|
+
} else {
|
|
163
|
+
delete this.opts.loaderParam[key]
|
|
164
|
+
}
|
|
165
|
+
e.currentTarget.removeAttribute('data-loader-param-selected')
|
|
166
|
+
console.log(this.opts.loaderParam[key])
|
|
167
|
+
} else {
|
|
168
|
+
if (multiVals) {
|
|
169
|
+
const key = e.currentTarget.dataset.loaderParamKey || 'defaultParam'
|
|
170
|
+
if (!this.opts.loaderParam.hasOwnProperty(key)) {
|
|
171
|
+
this.opts.loaderParam[key] = []
|
|
172
|
+
}
|
|
173
|
+
this.opts.loaderParam[key].push(e.currentTarget.dataset.loaderParam)
|
|
174
|
+
e.currentTarget.setAttribute('data-loader-param-selected', '')
|
|
175
|
+
} else {
|
|
176
|
+
const paramKey = e.currentTarget.dataset.loaderParamKey
|
|
177
|
+
this.$paramEls.forEach($paramEl => {
|
|
178
|
+
if (paramKey) {
|
|
179
|
+
if ($paramEl.dataset.loaderParamKey === paramKey) {
|
|
180
|
+
$paramEl.removeAttribute('data-loader-param-selected')
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
$paramEl.removeAttribute('data-loader-param-selected')
|
|
184
|
+
}
|
|
185
|
+
})
|
|
186
|
+
e.currentTarget.setAttribute('data-loader-param-selected', '')
|
|
187
|
+
const key = e.currentTarget.dataset.loaderParamKey || 'defaultParam'
|
|
188
|
+
this.opts.loaderParam[key] = e.currentTarget.dataset.loaderParam
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
133
192
|
|
|
134
193
|
this.fetch()
|
|
135
194
|
}
|
|
@@ -53,6 +53,7 @@ export default class Dropdown {
|
|
|
53
53
|
}
|
|
54
54
|
this.elements.menuItems = Dom.all(this.elements.menu, this.opts.selectors.menuItems)
|
|
55
55
|
this.initialize()
|
|
56
|
+
this.checkForInitialOpen()
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
initialize() {
|
|
@@ -62,9 +63,10 @@ export default class Dropdown {
|
|
|
62
63
|
.from(
|
|
63
64
|
this.elements.menu,
|
|
64
65
|
{
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
className: `${this.elements.menu.className} zero-height`,
|
|
67
|
+
duration: 0.1
|
|
67
68
|
},
|
|
69
|
+
|
|
68
70
|
'open'
|
|
69
71
|
)
|
|
70
72
|
.to(
|
|
@@ -92,7 +94,9 @@ export default class Dropdown {
|
|
|
92
94
|
}
|
|
93
95
|
})
|
|
94
96
|
.to(this.elements.menu, { opacity: 1 })
|
|
95
|
-
|
|
97
|
+
if (this.elements.menuItems.length) {
|
|
98
|
+
this.timeline.from(this.elements.menuItems, this.opts.tweens.items, 'open+=.1')
|
|
99
|
+
}
|
|
96
100
|
|
|
97
101
|
if (!this.elements.trigger) {
|
|
98
102
|
return
|
|
@@ -139,4 +143,10 @@ export default class Dropdown {
|
|
|
139
143
|
this.timeline.reverse()
|
|
140
144
|
}
|
|
141
145
|
}
|
|
146
|
+
|
|
147
|
+
checkForInitialOpen() {
|
|
148
|
+
if (this.elements.trigger.hasAttribute('data-dropdown-active')) {
|
|
149
|
+
this.openMenu()
|
|
150
|
+
}
|
|
151
|
+
}
|
|
142
152
|
}
|
|
@@ -22,9 +22,8 @@ export default class EqualHeightImages {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
Array.from(canvases).forEach(canvas => {
|
|
25
|
+
run() {
|
|
26
|
+
Array.from(this.canvases).forEach(canvas => {
|
|
28
27
|
let lastTop = null
|
|
29
28
|
const actionables = []
|
|
30
29
|
let elements = []
|
|
@@ -71,6 +70,11 @@ export default class EqualHeightImages {
|
|
|
71
70
|
})
|
|
72
71
|
}
|
|
73
72
|
|
|
73
|
+
initialize() {
|
|
74
|
+
this.canvases = Dom.all(this.container, '[data-eq-height-images]')
|
|
75
|
+
this.run()
|
|
76
|
+
}
|
|
77
|
+
|
|
74
78
|
getRenderedSize(contains, cWidth, cHeight, width, height, pos) {
|
|
75
79
|
const oRatio = width / height
|
|
76
80
|
const cRatio = cWidth / cHeight
|
|
@@ -74,6 +74,31 @@ export default class FeatureTests {
|
|
|
74
74
|
* listen for events as well
|
|
75
75
|
*/
|
|
76
76
|
testTouchMouseEvents() {
|
|
77
|
+
if (window.PointerEvent && 'maxTouchPoints' in navigator) {
|
|
78
|
+
// if Pointer Events are supported, just check maxTouchPoints
|
|
79
|
+
if (navigator.maxTouchPoints > 0) {
|
|
80
|
+
this.results.touch = true
|
|
81
|
+
this.results.mouse = false
|
|
82
|
+
this.testFor('touch', true)
|
|
83
|
+
this.testFor('mouse', false)
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
// no Pointer Events...
|
|
87
|
+
if (window.matchMedia && window.matchMedia('(any-pointer:coarse)').matches) {
|
|
88
|
+
// check for any-pointer:coarse which mostly means touchscreen
|
|
89
|
+
this.results.touch = true
|
|
90
|
+
this.results.mouse = false
|
|
91
|
+
this.testFor('touch', true)
|
|
92
|
+
this.testFor('mouse', false)
|
|
93
|
+
} else if (window.TouchEvent || 'ontouchstart' in window) {
|
|
94
|
+
// last resort - check for exposed touch events API / event handler
|
|
95
|
+
this.results.touch = true
|
|
96
|
+
this.results.mouse = false
|
|
97
|
+
this.testFor('touch', true)
|
|
98
|
+
this.testFor('mouse', false)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
77
102
|
const onTouchStart = () => {
|
|
78
103
|
if (!this.results.touch) {
|
|
79
104
|
this.results.touch = true
|
|
@@ -98,6 +98,7 @@ const DEFAULT_OPTIONS = {
|
|
|
98
98
|
on: Events.APPLICATION_REVEALED,
|
|
99
99
|
unpinOnForcedScrollStart: true,
|
|
100
100
|
pinOnForcedScrollEnd: true,
|
|
101
|
+
rafScroll: true,
|
|
101
102
|
|
|
102
103
|
default: {
|
|
103
104
|
unPinOnResize: true,
|
|
@@ -226,7 +227,12 @@ export default class FixedHeader {
|
|
|
226
227
|
}
|
|
227
228
|
|
|
228
229
|
this.app.registerCallback(Events.APPLICATION_REVEALED, () => {
|
|
229
|
-
|
|
230
|
+
let SCROLL_EVENT = Events.APPLICATION_SCROLL
|
|
231
|
+
if (!this.mainOpts.rafScroll) {
|
|
232
|
+
SCROLL_EVENT = 'scroll'
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
window.addEventListener(SCROLL_EVENT, this.redraw.bind(this), {
|
|
230
236
|
capture: false,
|
|
231
237
|
passive: true
|
|
232
238
|
})
|
|
@@ -249,9 +255,11 @@ export default class FixedHeader {
|
|
|
249
255
|
}
|
|
250
256
|
|
|
251
257
|
preflight() {
|
|
252
|
-
this.
|
|
253
|
-
|
|
254
|
-
|
|
258
|
+
if (!this.opts.enter) {
|
|
259
|
+
this.checkSize(true)
|
|
260
|
+
this.checkBg(true)
|
|
261
|
+
this.checkTop(true)
|
|
262
|
+
}
|
|
255
263
|
|
|
256
264
|
this.app.registerCallback(Events.APPLICATION_REVEALED, () => {
|
|
257
265
|
setTimeout(() => {
|
|
@@ -120,6 +120,9 @@ export default class Links {
|
|
|
120
120
|
|
|
121
121
|
if (dataTarget) {
|
|
122
122
|
this.opts.onAnchor(dataTarget, this)
|
|
123
|
+
if (!dataTarget.hasAttribute('data-skip-history')) {
|
|
124
|
+
history.pushState({}, '', href)
|
|
125
|
+
}
|
|
123
126
|
|
|
124
127
|
if (this.app.header && dataTarget.id !== 'top') {
|
|
125
128
|
setTimeout(() => {
|
|
@@ -141,6 +144,9 @@ export default class Links {
|
|
|
141
144
|
bindLinks(links) {
|
|
142
145
|
Array.from(links).forEach(link => {
|
|
143
146
|
const href = link.getAttribute('href')
|
|
147
|
+
if (!href) {
|
|
148
|
+
return
|
|
149
|
+
}
|
|
144
150
|
const internalLink = href.indexOf(document.location.hostname) > -1 || href.startsWith('/')
|
|
145
151
|
if (this.opts.openExternalInWindow && !internalLink) {
|
|
146
152
|
link.setAttribute('target', '_blank')
|
|
@@ -26,8 +26,12 @@ export default class Popover {
|
|
|
26
26
|
|
|
27
27
|
this.popover.classList.add(this.className)
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
if (!app.featureTests.results.touch) {
|
|
30
|
+
this.trigger.addEventListener('mouseenter', this.handleMouseEnter.bind(this))
|
|
31
|
+
this.trigger.addEventListener('mouseleave', this.handleMouseLeave.bind(this))
|
|
32
|
+
} else {
|
|
33
|
+
this.trigger.addEventListener('touchstart', this.handleTouchStart.bind(this))
|
|
34
|
+
}
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
handleMouseEnter(e) {
|
|
@@ -38,6 +42,10 @@ export default class Popover {
|
|
|
38
42
|
this.hide()
|
|
39
43
|
}
|
|
40
44
|
|
|
45
|
+
handleTouchStart(e) {
|
|
46
|
+
this.toggle()
|
|
47
|
+
}
|
|
48
|
+
|
|
41
49
|
get isVisible() {
|
|
42
50
|
return document.body.contains(this.popover)
|
|
43
51
|
}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { gsap } from 'gsap'
|
|
2
2
|
import Dom from '../Dom'
|
|
3
3
|
|
|
4
|
-
const DEFAULT_OPTIONS = {}
|
|
5
|
-
|
|
6
4
|
export default class Toggler {
|
|
7
5
|
constructor(app, el) {
|
|
8
6
|
this.open = false
|
|
9
7
|
this.app = app
|
|
10
8
|
this.el = el
|
|
11
|
-
// this.opts = _defaultsDeep(opts, DEFAULT_OPTIONS)
|
|
12
9
|
this.trigger = Dom.find(this.el, '[data-toggle-trigger]')
|
|
13
10
|
this.triggerIcon = Dom.find(this.trigger, 'span.icon')
|
|
14
11
|
this.content = Dom.find(this.el, '[data-toggle-content]')
|
|
@@ -19,12 +16,16 @@ export default class Toggler {
|
|
|
19
16
|
this.toggleState()
|
|
20
17
|
|
|
21
18
|
if (this.open) {
|
|
22
|
-
this.triggerIcon
|
|
23
|
-
|
|
19
|
+
if (this.triggerIcon) {
|
|
20
|
+
this.triggerIcon.classList.toggle('active')
|
|
21
|
+
}
|
|
22
|
+
gsap.set(this.content, { height: 'auto', display: 'block' })
|
|
24
23
|
this.el.classList.toggle('open')
|
|
25
24
|
gsap.from(this.content, { height: 0, ease: 'power1.inOut' })
|
|
26
25
|
} else {
|
|
27
|
-
this.triggerIcon
|
|
26
|
+
if (this.triggerIcon) {
|
|
27
|
+
this.triggerIcon.classList.toggle('active')
|
|
28
|
+
}
|
|
28
29
|
gsap.to(this.content, {
|
|
29
30
|
duration: 0.25,
|
|
30
31
|
onComplete: () => {
|