@profitlich/template-toolkit 4.2.0 → 5.0.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.
|
@@ -5,12 +5,13 @@ export class MenuToggle {
|
|
|
5
5
|
#menuButton;
|
|
6
6
|
#menu;
|
|
7
7
|
#menuLinkSelector;
|
|
8
|
-
#
|
|
8
|
+
#menuItemSelector;
|
|
9
9
|
#scrollbarWidth;
|
|
10
10
|
#shiftElement;
|
|
11
11
|
#shiftDelay;
|
|
12
12
|
#deferPositionFixed;
|
|
13
|
-
#
|
|
13
|
+
#lockScroll;
|
|
14
|
+
#fixElement;
|
|
14
15
|
#y;
|
|
15
16
|
#bodyClickHandler;
|
|
16
17
|
#resizeHandler;
|
|
@@ -19,33 +20,36 @@ export class MenuToggle {
|
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* @param {Object} options
|
|
22
|
-
* @param {string} options.
|
|
23
|
-
* @param {string} options.
|
|
24
|
-
* @param {string} options.menuLinkSelector
|
|
25
|
-
* @param {string} options.
|
|
26
|
-
* @param {string?} options.
|
|
27
|
-
* @param {number} options.shiftDelay
|
|
28
|
-
* @param {boolean} options.deferPositionFixed
|
|
29
|
-
* @param {boolean} options.
|
|
23
|
+
* @param {string} options.menuButtonSelector CSS-Selektor (`querySelector`) des Buttons, der das Menü öffnet/schliesst.
|
|
24
|
+
* @param {string} options.menuSelector CSS-Selektor (`querySelector`) des Menü-Containers.
|
|
25
|
+
* @param {string} options.menuLinkSelector CSS-Selektor für Menü-Links, die das Menü beim Klick schliessen (z.B. '.menu-link').
|
|
26
|
+
* @param {string} options.menuItemSelector CSS-Selektor des Menü-Wrappers; Klicks ausserhalb schliessen das Menü (z.B. '.menu').
|
|
27
|
+
* @param {string?} options.shiftElementSelector Optional: CSS-Selektor des Elements, das beim Öffnen um die Scrollbar-Breite verschoben/verbreitert wird, damit z.B. ein fixierter Header nicht springt.
|
|
28
|
+
* @param {number} options.shiftDelay Verzögerung in Sekunden, bevor Scrollbar gemessen und Body fixiert wird – nützlich, wenn vorher noch eine CSS-Animation läuft, die die Scrollbar entfernt.
|
|
29
|
+
* @param {boolean} options.deferPositionFixed Setzt `data-menu-fixed` erst nach `shiftDelay` statt sofort. Nötig, wenn das Fixieren eine laufende Öffnungs-Animation stören würde.
|
|
30
|
+
* @param {boolean} options.lockScroll Wenn `false`, bleibt das fixierende Element scrollbar; kein Scrollbar-Ausgleich und kein Shift. Für Menüs, die nur einen Teil der Seite bedecken und Hintergrund-Scroll erlauben sollen.
|
|
31
|
+
* @param {string?} options.fixElementSelector Optional: CSS-Selektor des Elements, das beim Öffnen fixiert wird (`position: fixed`, Scrollbar-Ausgleich, Scroll-Position-Trick). Default: `document.body`.
|
|
30
32
|
*/
|
|
31
33
|
constructor({
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
menuButtonSelector,
|
|
35
|
+
menuSelector,
|
|
34
36
|
menuLinkSelector,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
menuItemSelector,
|
|
38
|
+
shiftElementSelector = null,
|
|
37
39
|
shiftDelay = 0,
|
|
38
40
|
deferPositionFixed = false,
|
|
39
|
-
|
|
41
|
+
lockScroll = true,
|
|
42
|
+
fixElementSelector = null,
|
|
40
43
|
}) {
|
|
41
|
-
this.#menuButton = document.
|
|
42
|
-
this.#menu = document.
|
|
44
|
+
this.#menuButton = document.querySelector(menuButtonSelector);
|
|
45
|
+
this.#menu = document.querySelector(menuSelector);
|
|
43
46
|
this.#menuLinkSelector = menuLinkSelector;
|
|
44
|
-
this.#
|
|
45
|
-
this.#shiftElement =
|
|
47
|
+
this.#menuItemSelector = menuItemSelector;
|
|
48
|
+
this.#shiftElement = shiftElementSelector ? document.querySelector(shiftElementSelector) : null;
|
|
46
49
|
this.#shiftDelay = shiftDelay * 1000;
|
|
47
50
|
this.#deferPositionFixed = deferPositionFixed;
|
|
48
|
-
this.#
|
|
51
|
+
this.#lockScroll = lockScroll;
|
|
52
|
+
this.#fixElement = fixElementSelector ? document.querySelector(fixElementSelector) : document.body;
|
|
49
53
|
this.#scrollbarWidth = 0;
|
|
50
54
|
this.isActive = false;
|
|
51
55
|
this.#y = 0;
|
|
@@ -68,13 +72,13 @@ export class MenuToggle {
|
|
|
68
72
|
|
|
69
73
|
this.#setBodyAttribute('data-menu-active', 'false');
|
|
70
74
|
this.#setBodyAttribute('data-menu-moving', 'false');
|
|
71
|
-
this.#
|
|
75
|
+
this.#fixElement.setAttribute('data-menu-fixed', 'false');
|
|
72
76
|
}
|
|
73
77
|
|
|
74
78
|
static getInstance(options) {
|
|
75
79
|
if (!MenuToggle.#instance) {
|
|
76
|
-
if (!options || !options.
|
|
77
|
-
throw new Error("MenuToggle muss beim ersten Aufruf mit
|
|
80
|
+
if (!options || !options.menuButtonSelector || !options.menuSelector || !options.menuLinkSelector || !options.menuItemSelector) {
|
|
81
|
+
throw new Error("MenuToggle muss beim ersten Aufruf mit menuButtonSelector, menuSelector, menuLinkSelector und menuItemSelector initialisiert werden.");
|
|
78
82
|
}
|
|
79
83
|
MenuToggle.#instance = new MenuToggle(options);
|
|
80
84
|
}
|
|
@@ -87,14 +91,14 @@ export class MenuToggle {
|
|
|
87
91
|
document.body.removeEventListener('click', this.#bodyClickHandler);
|
|
88
92
|
window.removeEventListener('resize', this.#resizeHandler);
|
|
89
93
|
this.#setBodyAttribute('data-menu-active', 'false');
|
|
90
|
-
if (this.#
|
|
91
|
-
this.#
|
|
94
|
+
if (this.#lockScroll) {
|
|
95
|
+
this.#fixElement.setAttribute('data-menu-fixed', 'false');
|
|
92
96
|
if (this.#shiftElement) {
|
|
93
97
|
this.#shiftElement.style.marginRight = '';
|
|
94
98
|
this.#shiftElement.style.width = '';
|
|
95
99
|
}
|
|
96
|
-
|
|
97
|
-
|
|
100
|
+
this.#fixElement.style.paddingRight = '';
|
|
101
|
+
this.#fixElement.style.top = '';
|
|
98
102
|
window.scrollTo(0, this.#y);
|
|
99
103
|
}
|
|
100
104
|
this.#toggleEscape(false);
|
|
@@ -102,19 +106,19 @@ export class MenuToggle {
|
|
|
102
106
|
this.isActive = true;
|
|
103
107
|
document.body.addEventListener('click', this.#bodyClickHandler);
|
|
104
108
|
this.#setBodyAttribute('data-menu-active', 'true');
|
|
105
|
-
if (this.#
|
|
109
|
+
if (this.#lockScroll) {
|
|
106
110
|
window.addEventListener('resize', this.#resizeHandler);
|
|
107
111
|
this.#setBodyAttribute('data-menu-moving', 'true');
|
|
108
112
|
if (!this.#deferPositionFixed) {
|
|
109
|
-
this.#
|
|
113
|
+
this.#fixElement.setAttribute('data-menu-fixed', 'true');
|
|
110
114
|
}
|
|
111
115
|
setTimeout(() => {
|
|
112
116
|
this.#scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
|
|
113
117
|
this.#y = window.scrollY;
|
|
114
|
-
|
|
115
|
-
|
|
118
|
+
this.#fixElement.style.paddingRight = `${this.#scrollbarWidth}px`;
|
|
119
|
+
this.#fixElement.style.top = `-${this.#y}px`;
|
|
116
120
|
if (this.#deferPositionFixed) {
|
|
117
|
-
this.#
|
|
121
|
+
this.#fixElement.setAttribute('data-menu-fixed', 'true');
|
|
118
122
|
}
|
|
119
123
|
if (this.#shiftElement) {
|
|
120
124
|
const marginOriginal = parseFloat(window.getComputedStyle(this.#menuButton).marginRight);
|
|
@@ -138,7 +142,7 @@ export class MenuToggle {
|
|
|
138
142
|
}
|
|
139
143
|
|
|
140
144
|
#onBodyClick(event) {
|
|
141
|
-
if (this.isActive && !event.target.closest(
|
|
145
|
+
if (this.isActive && !event.target.closest(this.#menuItemSelector)) {
|
|
142
146
|
this.#toggleMenu();
|
|
143
147
|
}
|
|
144
148
|
}
|
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
width: 100%;
|
|
6
|
-
}
|
|
1
|
+
[data-menu-fixed="true"] {
|
|
2
|
+
position: fixed;
|
|
3
|
+
width: 100%;
|
|
4
|
+
}
|
|
7
5
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
6
|
+
body[data-menu-active="true"] {
|
|
7
|
+
// Bedeckt das Menü nur einen Teil der Seite, ist also ein Teil der Seite weiterhin zu sehen,
|
|
8
|
+
// soll die Maus Interaktionen ausserhalb des Menüs ignorieren
|
|
9
|
+
.main {
|
|
10
|
+
pointer-events: none;
|
|
14
11
|
}
|
|
15
|
-
|
|
16
12
|
}
|
package/package.json
CHANGED