@madj2k/fe-frontend-kit 2.0.38 → 2.0.39

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/index.js CHANGED
@@ -11,3 +11,4 @@ export { Madj2kElementInViewport } from './tools/element-in-viewport';
11
11
  // Menus
12
12
  export { Madj2kFlyoutMenu } from './menus/flyout-menu';
13
13
  export { Madj2kPulldownMenu } from './menus/pulldown-menu';
14
+ export { Madj2kSlideMenu } from './menus/slide-menu';
package/index.scss CHANGED
@@ -4,6 +4,7 @@
4
4
  // Forward all menu styles
5
5
  @forward './menus/flyout-menu';
6
6
  @forward './menus/pulldown-menu';
7
+ @forward './menus/slide-menu';
7
8
 
8
9
  // Forward all tools
9
10
  @forward 'tools/banner/index';
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * @author Steffen Kroggel <developer@steffenkroggel.de>
9
9
  * @copyright 2025 Steffen Kroggel
10
- * @version 2.0.3
10
+ * @version 2.0.4
11
11
  * @license GNU General Public License v3.0
12
12
  * @see https://www.gnu.org/licenses/gpl-3.0.en.html
13
13
  *
@@ -49,9 +49,12 @@ class Madj2kFlyoutMenu {
49
49
  menuCloseClass: "js-flyout-close",
50
50
  menuContainerClass: "js-flyout-container",
51
51
  menuInnerClass: "js-flyout-inner",
52
- heightCalculationClass: 'calculate',
53
52
  hoverParentClass: 'nav-main',
53
+ heightCalculationClass: 'calculate',
54
54
  heightMode: 'full',
55
+ heightModeClassPrefix: 'height-mode',
56
+ scrollMode: 'default',
57
+ scrollModeClassPrefix: 'scroll-mode',
55
58
  eventMode: 'click',
56
59
  paddingBehavior: 0,
57
60
  paddingViewPortMinWidth: 0,
@@ -76,8 +79,11 @@ class Madj2kFlyoutMenu {
76
79
  this.settings.$menuContainer = this.settings.$menu.querySelector(`.${this.settings.menuContainerClass}`);
77
80
  this.settings.$menuInner = this.settings.$menu.querySelector(`.${this.settings.menuInnerClass}`);
78
81
 
79
- // Bind persistent event handlers
82
+ // add mode classes
83
+ this.settings.$menu.classList.add(this.settings.heightModeClassPrefix + '-' + this.settings.heightMode);
84
+ this.settings.$menuInner.classList.add(this.settings.scrollModeClassPrefix + '-' + this.settings.scrollMode);
80
85
 
86
+ // Bind persistent event handlers
81
87
  this.initNoScrollHelper();
82
88
  this.resizeAndPositionMenu();
83
89
  this.paddingMenu();
@@ -444,6 +450,10 @@ class Madj2kFlyoutMenu {
444
450
  newHeight = `${innerHeight}px`;
445
451
  }
446
452
 
453
+ if (this.settings.scrollMode === 'inner') {
454
+ this.settings.$menuInner.style.height = newHeight;
455
+ }
456
+
447
457
  // set max-height again so that longer flyouts do not lead to scrolling on smaller ones
448
458
  this.settings.$menu.classList.remove(this.settings.heightCalculationClass);
449
459
  this.settings.$menu.style.height = newHeight;
@@ -468,6 +478,7 @@ class Madj2kFlyoutMenu {
468
478
 
469
479
  if (!this.settings.$paddingReference) return;
470
480
  if (this.settings.paddingBehavior === 0) return;
481
+
471
482
  // should be re-evaluated on a resize event after re-opening the menu
472
483
  // if (this.settings.paddingBehavior === 1 && this.settings.$menuInner.hasAttribute('data-padding-set')) return;
473
484
 
@@ -504,8 +515,7 @@ class Madj2kFlyoutMenu {
504
515
  */
505
516
  toggleNoScroll() {
506
517
 
507
- // heightMode "full" with deprecated fullHeight-setting as fallback
508
- if (this.settings.heightMode === 'full' || this.settings.fullHeight === true) {
518
+ if (this.settings.scrollHelper) {
509
519
  const body = document.body;
510
520
  const helper = body.querySelector('.no-scroll-helper');
511
521
  const inner = body.querySelector('.no-scroll-helper-inner');
@@ -55,4 +55,10 @@ html, body {
55
55
  background-color: #fff;
56
56
  overflow: hidden;
57
57
  }
58
+
59
+ &-inner.scroll-mode-inner {
60
+ overflow-y: auto;
61
+ overflow-x: hidden;
62
+ }
58
63
  }
64
+
@@ -0,0 +1,146 @@
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the TYPO3 CMS project.
5
+ *
6
+ * It is free software; you can redistribute it and/or modify it under
7
+ * the terms of the GNU General Public License, either version 2
8
+ * of the License, or any later version.
9
+ *
10
+ * For the full copyright and license information, please read the
11
+ * LICENSE.txt file that was distributed with this source code.
12
+ *
13
+ * The TYPO3 project - inspiring people to share!
14
+ */
15
+
16
+ use TYPO3\CMS\Core\Utility\GeneralUtility;
17
+ use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
18
+ use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
19
+ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
20
+
21
+ /**
22
+ * Class JsonMenuViewHelper
23
+ *
24
+ * @author Steffen Kroggel <developer@steffenkroggel.de>
25
+ * @copyright Steffen Kroggel <developer@steffenkroggel.de>
26
+ * @package Madj2k_SiteDefault
27
+ * @license http://www.gnu.org/licenses/gpl.html GNU General Public License, version 3 or later
28
+ */
29
+ class JsonMenuViewHelper extends AbstractViewHelper
30
+ {
31
+
32
+ /**
33
+ * Initialize arguments
34
+ *
35
+ * @return void
36
+ */
37
+ public function initializeArguments(): void
38
+ {
39
+ parent::initializeArguments();
40
+ $this->registerArgument('items', 'array', 'The recursive menu-array');
41
+ $this->registerArgument('parseFuncTSPath', 'string', 'Path to the TypoScript parseFunc setup.', false, '');
42
+ }
43
+
44
+
45
+ /**
46
+ * @param array $arguments
47
+ * @param \Closure $renderChildrenClosure
48
+ * @param \TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface $renderingContext
49
+ * @return string
50
+ */
51
+ public static function renderStatic(
52
+ array $arguments,
53
+ \Closure $renderChildrenClosure,
54
+ RenderingContextInterface $renderingContext
55
+ ): string {
56
+
57
+ /** @var array $items */
58
+ $items = $arguments['items'];
59
+
60
+ /** @var string $parseFuncTSPath */
61
+ $parseFuncTSPath = $arguments['parseFuncTSPath'];
62
+
63
+ /** @var \Psr\Http\Message\ServerRequestInterface $request */
64
+ $request = $renderingContext->getRequest();
65
+
66
+ /** @var \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer $contentObject */
67
+ $contentObject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
68
+ $contentObject->setRequest($request);
69
+ $contentObject->start([]);
70
+
71
+ $result = [];
72
+ foreach ($items as $item) {
73
+ $result[] = self::callback($item, $contentObject, $parseFuncTSPath);
74
+ }
75
+
76
+ return json_encode($result);
77
+ }
78
+
79
+
80
+ /**
81
+ * @param array $item
82
+ * @param \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer $contentObject
83
+ * @param string $parseFuncTSPath
84
+ * @return array
85
+ */
86
+ public static function callback (
87
+ array $item,
88
+ ContentObjectRenderer $contentObject,
89
+ string $parseFuncTSPath = ''
90
+ ): array {
91
+
92
+ /*
93
+ Build a reduced structure:
94
+ "data": {"uid": 2, "pid": 1, "title": "Lorem Ipsum"},
95
+ "title": "Lorem Ipsum",
96
+ "link": "\/lorem\/Ipsum",
97
+ "target": "_blank",
98
+ "active": 1,
99
+ "current": 0,
100
+ "spacer": 0,
101
+ "hasSubpages": 1,
102
+ "children": [ ]
103
+ */
104
+
105
+ $result = $item;
106
+ $result['data'] = [
107
+ 'uid' => $item['data']['uid'],
108
+ 'pid' => $item['data']['pid'],
109
+ 'title'=> $item['data']['title'],
110
+ ];
111
+
112
+ $result['children'] = [];
113
+ if (
114
+ (isset($item['children']))
115
+ && (is_array($item['children']))
116
+ ){
117
+ foreach ($item['children'] as $child) {
118
+ $result['children'][] = self::callback($child, $contentObject, $parseFuncTSPath);
119
+ }
120
+ }
121
+
122
+ if (!isset($result['hasSubpages'])) {
123
+ $result['hasSubpages'] = $result['children'] ? 1 : 0;
124
+ }
125
+
126
+ if (isset($item['data']['doktype'])) {
127
+ $result['linkType'] = $item['data']['doktype'];
128
+ }
129
+
130
+ // Parse title with HTML-parser
131
+ if ($parseFuncTSPath) {
132
+ $result['title'] = $contentObject->parseFunc($result['title'], null, '< ' . $parseFuncTSPath);
133
+ }
134
+
135
+ // do not link sites, that only link to the next subpage!
136
+ $result['isLinked'] = 1;
137
+ if (
138
+ ($item['data']['doktype'] == 4)
139
+ && (in_array($item['data']['shortcut_mode'], [1,3]))
140
+ ){
141
+ $result['isLinked'] = 0;
142
+ }
143
+
144
+ return $result;
145
+ }
146
+ }
@@ -0,0 +1,165 @@
1
+ <html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
2
+ xmlns:siteDefault="http://typo3.org/ns/Madj2k/SiteDefault/ViewHelpers"
3
+ data-namespace-typo3-fluid="true"
4
+ >
5
+
6
+ <f:if condition="{menuItems}">
7
+ <f:then>
8
+ <f:comment>
9
+ <!--
10
+ Templates for mobile menu. We don't want this to be loaded on default because
11
+ it would duplicate the menu for search engines and would enlarge the body to parse
12
+ -->
13
+ </f:comment>
14
+ <template class="js-slide-nav-tmpl" data-type="menuWrap">
15
+ <div class="slide-nav-container js-slide-nav-container">
16
+ <div class="slide-nav-card js-slide-nav-card %levelClass%" id="slide-card-%uid%">
17
+ <div class="slide-nav-inner pd-3">
18
+ <ul class="slide-nav-list" role="none">
19
+ <li class="slide-nav-headline %levelClass%" role="none">
20
+ <a href="/"
21
+ title="{f:translate(key:'menu.home', extensionName:'siteDefault')}"
22
+ role="menuitem"
23
+ class="slide-nav-headline-link level-1">
24
+ <span>{f:translate(key:'menu.home', extensionName:'siteDefault')}</span>
25
+ </a>
26
+ </li>
27
+
28
+ <li class="slide-nav-wrap">
29
+ <ul class="slide-nav-list toggle-list" role="none">
30
+ %menuItems%
31
+ </ul>
32
+ </li>
33
+
34
+ <f:if condition="{topMenuItems}">
35
+ <li class="slide-nav-item-footer" role="none">
36
+ <ul class="slide-nav-meta-list" role="none">
37
+ <f:for each="{topMenuItems}" as="menuItem" iteration="iterator">
38
+ <li class="slide-nav-meta-item level1{f:if(condition:'{menuItem.active}', then:' active')}" role="none">
39
+ <a class="slide-nav-meta-link level1{f:if(condition:'{menuItem.active}', then:' active')}"
40
+ href="{menuItem.link}"
41
+ target="{menuItem.target}"
42
+ title="{menuItem.data.title}"
43
+ role="menuitem"
44
+ >
45
+ <span><f:format.html parseFuncTSPath="lib.parseFunc_Inline">{menuItem.title}</f:format.html></span>
46
+ </a>
47
+ </li>
48
+ </f:for>
49
+ </ul>
50
+ </li>
51
+ </f:if>
52
+
53
+ <f:if condition="{footerMenuItems}">
54
+ <li class="slide-nav-item-footer" role="none">
55
+ <ul class="slide-nav-meta-list" role="none">
56
+ <f:for each="{footerMenuItems}" as="menuItem" iteration="iterator">
57
+ <li class="slide-nav-meta-item level1{f:if(condition:'{menuItem.active}', then:' active')}" role="none">
58
+ <a class="slide-nav-meta-link level1{f:if(condition:'{menuItem.active}', then:' active')}"
59
+ href="{menuItem.link}"
60
+ target="{menuItem.target}"
61
+ title="{menuItem.data.title}"
62
+ role="menuitem"
63
+ >
64
+ <span><f:format.html parseFuncTSPath="lib.parseFunc_Inline">{menuItem.title}</f:format.html></span>
65
+ </a>
66
+ </li>
67
+ </f:for>
68
+ </ul>
69
+ </li>
70
+ </f:if>
71
+ </ul>
72
+ </div>
73
+ </div>
74
+ </div>
75
+ </template>
76
+
77
+ <template class="js-slide-nav-tmpl" data-type="menuItem">
78
+ <li class="slide-nav-item toggle-list-item js-slide-nav-item %activeClass% %hasChildrenClass%" role="none">
79
+ <f:comment><!-- normal link that opens the menu-item --></f:comment>
80
+
81
+ %ifHasNoChildrenStart%
82
+ <a href="%link%"
83
+ title="%titleRaw%"
84
+ role="menuitem"
85
+ class="slide-nav-link toggle-list-link %activeClass% %hasChildrenClass%"
86
+ target="%target%"
87
+ aria-current="%ariaCurrent%">
88
+ <span class="toggle-list-text">%title%</span>
89
+ </a>
90
+ %ifHasNoChildrenEnd%
91
+
92
+ <f:comment><!-- link that opens next card --></f:comment>
93
+ %ifHasChildrenStart%
94
+ <a class="slide-nav-link slide-nav-next toggle-list-link js-slide-nav-next %activeClass% %hasChildrenClass%"
95
+ href="#"
96
+ role="button"
97
+ title="{f:translate(key:'menu.openSubmenu', extensionName:'siteDefault')}"
98
+ aria-label="{f:translate(key:'menu.openSubmenu', extensionName:'siteDefault')}"
99
+ aria-haspopup="true"
100
+ aria-expanded="%ariaExpanded%"
101
+ aria-controls="slide-card-%uid%">
102
+ <span class="toggle-list-text">%title%</span><span class="icon-arrow-right icon"></span>
103
+ </a>
104
+ %ifHasChildrenEnd%
105
+
106
+ %submenu%
107
+ </li>
108
+ </template>
109
+
110
+ <template class="js-slide-nav-tmpl" data-type="subMenuWrap">
111
+ <div class="slide-nav-card js-slide-nav-card %activeClass% %levelClass%" id="slide-card-%uid%">
112
+ <div class="slide-nav-inner pd-3">
113
+ <ul class="slide-nav-list">
114
+ <li class="slide-nav-item-back" role="none">
115
+ <button class="slide-nav-back js-slide-nav-back"
116
+ title="{f:translate(key:'menu.levelUp', extensionName:'siteDefault')}"
117
+ aria-haspopup="true"
118
+ aria-label="{f:translate(key:'menu.levelUp', extensionName:'siteDefault')}"
119
+ aria-controls="slide-card-%uid%"
120
+ data-parent-card="slide-card-%parentUid%"><span class="icon-arrow-left icon"></span><span
121
+ class="slide-nav-back-label">{f:translate(key:'menu.back', extensionName:'siteDefault')}</span>
122
+ </button>
123
+ </li>
124
+ <li class="slide-nav-headline %levelClass%" role="none">
125
+
126
+ <f:comment><!-- normal parent --></f:comment>
127
+ %ifIsNotLinkedStart%
128
+ <span class="slide-nav-headline-text %currentClass% %isLinkedClass%">%title%</span>
129
+ %ifIsNotLinkedEnd%
130
+
131
+ <f:comment><!-- linked parent --></f:comment>
132
+ %ifIsLinkedStart%
133
+ <a href="%link%"
134
+ title="%titleRaw%"
135
+ role="menuitem"
136
+ class="slide-nav-headline-link %currentClass% %hasChildrenClass% %isLinkedClass%"
137
+ target="%target%"
138
+ aria-current="%ariaCurrent%">
139
+ <span>%title%</span>
140
+ </a>
141
+ %ifIsLinkedEnd%
142
+ </li>
143
+
144
+ <li class="slide-nav-wrap">
145
+ <ul class="slide-nav-list toggle-list" role="none">
146
+ %menuItems%
147
+ </ul>
148
+ </li>
149
+
150
+ </ul>
151
+ </div>
152
+ </div>
153
+ </template>
154
+
155
+ <script>
156
+ let slideNavItems = <f:format.raw><siteDefault:jsonMenu items="{menuItems}" parseFuncTSPath="lib.parseFunc_Inline" /></f:format.raw>;
157
+ </script>
158
+ </f:then>
159
+ <f:else>
160
+ <script>
161
+ let slideNavItems = {};
162
+ </script>
163
+ </f:else>
164
+ </f:if>
165
+ </html>
@@ -0,0 +1,2 @@
1
+ import Madj2kSlideMenu from './slide-menu-2.0.js';
2
+ export { Madj2kSlideMenu };
@@ -0,0 +1 @@
1
+ @forward './slide-menu-2.0';