diff --git a/bin/MegaMenu.js b/bin/MegaMenu.js index 48c4cf64e29309a839f453ef2fe94609620cc57f..39f68bc307e9b9ebf6cce403027a6f3a183a218c 100644 --- a/bin/MegaMenu.js +++ b/bin/MegaMenu.js @@ -176,7 +176,7 @@ define('package/quiqqer/menu/bin/MegaMenu', [ return; } - var SlideNode = document.getElement('[data-qui="package/quiqqer/menu/bin/SlideOut"]'), + var SlideNode = document.getElement('[data-slideOut="mobileMenu-SlideOut"]'), SlideOut = QUI.Controls.getById(SlideNode.get('data-quiid')), MobileMenu = this.getElm().getElement('.quiqqer-menu-megaMenu-mobile'); diff --git a/bin/MenuAdvanced.css b/bin/MenuAdvanced.css new file mode 100644 index 0000000000000000000000000000000000000000..a04c9a119241a02452c5f80ac7df0a66b268252b --- /dev/null +++ b/bin/MenuAdvanced.css @@ -0,0 +1,153 @@ +/** page navigation + * ========================================================== */ + +.page-menu { + background: rgba(37, 33, 34, 1); + bottom: 0; + left: 0; + min-height: 100%; + overflow: hidden; + top: 0; + z-index: 100; +} + +.page-menu li { + padding-left: 0; +} + +.page-menu-close, +.page-menu-opener { + border: none; + border-radius: 3px; + color: #fff; + cursor: pointer; + outline: none; + transition: all 0.3s ease-in-out; + z-index: 2000; +} + +.page-menu-close:hover, +.page-menu-close:focus { + background: rgba(255, 255, 255, 0.1); +} + +.fa-times-thin:before { + content: '\00d7'; +} + +.page-navigation { + position: relative; + z-index: 100; +} + +.page-navigation ul { + padding-left: 0; +} + +.page-navigation li { + list-style-type: none; + text-align: left; + width: 100%; +} + +.page-navigation a { + align-items: flex-start; + color: #fff; + display: flex; + text-decoration: none; + width: 100%; +} + +.page-navigation .page-navigation-home { + font-size: 18px; + padding: 10px 20px; + width: calc(100% - 40px); +} + +.page-navigation .fa { + flex-shrink: 0; + line-height: inherit; + margin-right: 0.5rem; + text-align: left; + width: 1.5rem; +} + +.page-navigation-level-1 .fa { + text-align: center; +} + +.page-navigation-level-2 a { + border-top: none; + font-size: 1rem; + padding: 5px 0; +} + +.page-navigation-level-3 a { + font-size: 0.875rem; +} + +/** page navigation -> mobile + * ========================================================== */ + +.slideout-panel { + display: inline-block; + width: 100%; +} + +.slideout-menu { + bottom: 0; + display: none; + left: 0; + -webkit-overflow-scrolling: touch; + overflow-y: auto; + position: fixed; + right: 0; + top: 0; + z-index: 0; +} + +.slideout-panel { + position: relative; + z-index: 1; +} + +.slideout-open, +.slideout-open body, +.slideout-open .slideout-panel { + overflow: hidden; +} + +.slideout-open .slideout-menu { + display: block; +} + +/** page navigation -> mobile + * ========================================================== */ + +.page-menu-mobile { + background: #dddddd; + color: #333; + cursor: pointer; + left: 0; + padding: 10px; + position: fixed; + top: 0; + width: 100%; + z-index: 100; +} + +.page-menu-mobile .fa { + margin-right: 10px; +} + +@media screen and (max-width: 767px) { + .hide-on-mobile { + display: none !important; + } +} + +@media screen and (min-width: 768px) { + .hide-on-desktop { + display: none !important; + } +} \ No newline at end of file diff --git a/bin/MenuAdvanced.js b/bin/MenuAdvanced.js new file mode 100644 index 0000000000000000000000000000000000000000..fade110fd2a453859a868f63abb846c55544ffe1 --- /dev/null +++ b/bin/MenuAdvanced.js @@ -0,0 +1,627 @@ +/** + * Slideout menu control + * + * @module package/quiqqer/menu/bin/js/MenuAdvanced + * @author www.pcsg.de (Henning Leutz) + * + * @require qui/QUI + * @require qui/utils/Functions + * @require qui/controls/Control + * @require URL_OPT_DIR +quiqqer/menu/bin/slideout.min.js + * @require css!package/quiqqer/menu/bin/SlideOut.css + */ +define('package/quiqqer/menu/bin/MenuAdvanced', [ + + 'qui/QUI', + 'qui/utils/Functions', + 'qui/controls/Control', + + URL_OPT_DIR + 'quiqqer/menu/bin/slideout.min.js', + + 'css!package/quiqqer/menu/bin/MenuAdvanced.css' + +], function (QUI, QUIUtilsFunctions, QUIControl, Slideout) { + "use strict"; + + return new Class({ + + Extends: QUIControl, + Type : 'package/quiqqer/menu/bin/MenuAdvanced', + menuDepth : 0, + + + options: { + top : 10, + left : 10, + bottom : false, + right : false, + 'data-show-button-on-desktop': true, + 'menu-width' : 256, + 'menu-button' : true, + 'touch' : false, + 'buttonids' : false, + collapsemobilemenu : false + }, + + Binds: [ + 'toggle', + '$onImport', + '$onResize' + ], + + initialize: function (options) { + var self = this; + + this.parent(options); + + this.MenuButton = null; + this.$__hideMenu = false; + this.$Url = new URL(location.href); + + // clear hash in url + this.$Url.hash = ''; + + this.clientWidth = QUI.getWindowSize().x; + + this.addEvents({ + onImport: this.$onImport + }); + + QUI.addEvent('resize', function () { + if (self.clientWidth === QUI.getWindowSize().x) { + // do not close the menu when the address bar is shown or hidden + // "resize" was triggered while scrolling down or up (e.g. mobile Chrome). + return; + } + + if (this.Slideout.isOpen()) { + this.Slideout.close(); + } + }.bind(this)); + }, + + /** + * event : on import + */ + $onImport: function () { + var self = this, + Elm = this.getElm(); + + Elm = Elm.getParent(); + + let links = Elm.querySelectorAll('a'); + + links.forEach((Link) => { + let TargetElm = this.$getAnchorTarget(Link); + + if (!TargetElm) { + return; + } + + Link.addEventListener('click', function (event) { + event.preventDefault(); + + self.Slideout.close(); + self.$scrollToElement(TargetElm); + }) + }); + + + let test = Elm.querySelector('.quiqqer-advanced-page-navigation-level-1'); + + this.NavUlContainer = Elm.querySelector('.quiqqer-advanced-page-navigation-level-1'); + var Parent = this.getElm(), // caly nav + NextButton = this.NavUlContainer.getElements(".quiqqer-advanced-menu-icon-next"), + BackButton = this.NavUlContainer.getElements(".quiqqer-advanced-menu-li-back"); + + var runs = false; + + NextButton.addEvent("click", function (e) + { + e.preventDefault(); + + if (runs) { + return; + } + + runs = true; + + var LiLeft = this.getParent('li'); + + var NavSubLeft = LiLeft.getElement("ul.quiqqer-advanced"); + var Prom; + + Prom = self.openMenu(NavSubLeft); + + Prom.then(function () + { + runs = false; + }); + }); + + BackButton.addEvent("click", function (e) + { + e.preventDefault(); + + if (runs) { + return; + } + + runs = true; + + var NavSubLeft = e.target.getParent("ul.quiqqer-advanced"); + var Prom; + + Prom = self.closeMenu(NavSubLeft); + + Prom.then(function () + { + runs = false; + }); + }); + // var Slideout = this.getAttribute('Slideout'); + // Slideout.on('close', () => { + // this.resetMenu(); + // }); + + // fix for IE - z-index must have the value 0 + if (navigator.appName == 'Microsoft Internet Explorer' || + !!(navigator.userAgent.match(/Trident/) || + navigator.userAgent.match(/rv:11/)) || + (typeof $.browser !== "undefined" && $.browser.msie == 1)) { + Elm.setStyle('z-index', 1); + } + + Elm.setStyle('display', 'none'); + + var BodyWrapper = document.getElement('.slideout-panel'); + + if (!BodyWrapper) { + // body childrens + var children = document.body.getChildren(); + BodyWrapper = new Element('div').inject(document.body); + + children.inject(BodyWrapper); + } + + if (BodyWrapper.hasClass('slideout-panel')) { + BodyWrapper.removeClass('slideout-panel'); + } + + Elm.inject(document.body); + + // menu button + this.MenuButton = new Element('button', { + 'class': 'page-menu-opener', + html : '<span class="fa fa-list"></span>' + + '<span class="page-menu-opener-text">MENU</span>', + styles : { + display : 'none', + 'float' : 'left', + opacity : 0, + position: 'fixed' + }, + events : { + click: this.toggle + } + }).inject(document.body); + + if (typeOf(Elm.get('data-show-button-on-desktop')) === 'string') { + this.setAttribute( + 'show-button-on-desktop', + Elm.get('data-show-button-on-desktop').toInt() + ); + } + + if (typeOf(Elm.get('data-qui-options-buttonids')) === 'string') { + this.setAttribute('buttonids', Elm.get('data-qui-options-buttonids')); + } + + + if (this.getAttribute('buttonids')) { + var i, len, Button, + ids = this.getAttribute('buttonids').split(','); + + for (i = 0, len = ids.length; i < len; i++) { + Button = document.id(ids[i]); + + if (Button) { + Button.addEvent('click', this.toggle); + } + } + } + + // button position + if (Elm.get('data-menu-right')) { + this.setAttribute('left', false); + this.setAttribute('right', Elm.get('data-menu-right').toInt()); + } + + if (Elm.get('data-menu-left')) { + this.setAttribute('left', Elm.get('data-menu-left').toInt()); + this.setAttribute('right', false); + } + + if (Elm.get('data-menu-top')) { + this.setAttribute('top', Elm.get('data-menu-top').toInt()); + this.setAttribute('bottom', false); + } + + if (Elm.get('data-menu-bottom')) { + this.setAttribute('bottom', Elm.get('data-menu-bottom').toInt()); + this.setAttribute('top', false); + } + + QUI.addEvent('resize', this.$onResize); + QUI.addEvent('load', this.$onResize); + + if (Elm.get('data-qui-options-menu-button')) { + this.setAttribute( + 'menu-button', + Elm.get('data-qui-options-menu-button').toInt() + ); + } + + + if (Elm.get('data-qui-options-touch')) { + this.setAttribute( + 'touch', + Elm.get('data-qui-options-touch').toInt() ? true : false + ); + } + + + // attributes + if (this.getAttribute('top')) { + this.MenuButton.setStyle('top', this.getAttribute('top')); + this.MenuButton.setStyle('bottom', null); + } + + if (this.getAttribute('left')) { + this.MenuButton.setStyle('left', this.getAttribute('left')); + this.MenuButton.setStyle('right', null); + } + + if (this.getAttribute('right')) { + this.MenuButton.setStyle('right', this.getAttribute('right')); + this.MenuButton.setStyle('left', null); + } + + if (this.getAttribute('bottom')) { + this.MenuButton.setStyle('bottom', this.getAttribute('bottom')); + this.MenuButton.setStyle('top', null); + } + + if (!this.getAttribute('show-button-on-desktop')) { + this.MenuButton.addClass('hide-on-desktop'); + } + + var computedStyle; + + if ("getComputedStyle" in window) { + computedStyle = window.getComputedStyle(document.body); + } else { + computedStyle = document.body.currentStyle; + } + + BodyWrapper.setStyle('background', computedStyle.backgroundColor); + Elm.setStyle('width', this.getAttribute('menu-width')); + + + // init slideout and set events + this.Slideout = new Slideout({ + panel : BodyWrapper, + menu : Elm, + padding : this.getAttribute('menu-width'), + tolerance: 70, + touch : this.getAttribute('touch') + }); + + this.Slideout.on('beforeopen', function () { + self.$onResize(); + Elm.setStyle('display', ''); + + self.Slideout._padding = self.getAttribute('menu-width'); + self.Slideout._translateTo = self.getAttribute('menu-width'); + + Elm.setStyle('width', self.getAttribute('menu-width')); + self.getElm().setStyle('display', null); + + BodyWrapper.setStyle('boxShadow', '2px 0 10px 5px rgba(0, 0, 0, 0.3'); + + self.hideMenuButton(function () { + self.MenuButton.setStyle('display', 'none'); + }); + }); + + this.Slideout.on('open', function () { + self.fireEvent('open'); + + var Closer = new Element('div', { + html : '<span class="fa fa-times-thin"></span>', + 'class': 'page-menu-close', + styles : { + fontSize : 40, + height : 50, + lineHeight: 50, + right : -30, + position : 'absolute', + textAlign : 'center', + top : 0, + width : 50, + zIndex : 1000 + }, + events : { + click: self.toggle + } + }).inject(Elm); + + + moofx(Closer).animate({ + right : 10, + opacity: 1 + }, { + duration: 250, + equation: 'cubic-bezier(.42,.4,.46,1.29)' + }); + + }); + + this.Slideout.on('close', function () { + BodyWrapper.setStyle('boxShadow', null); + + self.MenuButton.setStyle('display', null); + + var Closer = document.getElement('.page-menu-close'); + + if (Closer) { + moofx(Closer).animate({ + left : -100, + opacity: 0 + }, { + duration: 250, + equation: 'cubic-bezier(.42,.4,.46,1.29)', + callback: function () { + Closer.destroy(); + } + }); + } + + + if (self.$__hideMenu === false) { + self.showMenuButton(function () { + self.getElm().setStyle('display', null); + }); + } + }); + + this.showMenuButton(function () { + self.getElm().setStyle('display', null); + }); + + this.$onResize(); + }, + + /** + * event : on resize + */ + $onResize: function () { + if (QUI.getWindowSize().x > 500) { + this.setAttribute('menu-width', 500); + return; + } + + this.setAttribute('menu-width', QUI.getWindowSize().x); + }, + + /** + * Toggle + */ + toggle: function () { + this.Slideout.toggle(); + }, + + /** + * Dont show menu button + */ + disableMenuButton: function () { + this.$__hideMenu = true; + }, + + /** + * Show menu button + */ + enableMenuButton: function () { + this.$__hideMenu = false; + }, + + /** + * Hide Menu button + * + * @param callback + */ + hideMenuButton: function (callback) { + moofx(this.MenuButton).animate({ + opacity: 0 + }, { + duration: 250, + equation: 'cubic-bezier(.42,.4,.46,1.29)', + callback: function () { + this.MenuButton.setStyle('display', 'none'); + + if (typeof callback === 'function') { + callback(); + } + }.bind(this) + }); + }, + + /** + * Show Menu button + * + * @param callback + */ + showMenuButton: function (callback) { + if (this.$__hideMenu) { + return; + } + + if (!this.getAttribute('menu-button')) { + return; + } + + this.MenuButton.setStyle('display', null); + + moofx(this.MenuButton).animate({ + opacity: 1 + }, { + duration: 250, + equation: 'cubic-bezier(.42,.4,.46,1.29)', + callback: function () { + if (typeof callback === 'function') { + callback(); + } + }.bind(this) + }); + }, + + /** + * Get anchor target + * + * @param {HTMLElement} Link - <a> HTML node + * @return {boolean|HTMLElement} + */ + $getAnchorTarget: function (Link) { + let href = Link.href; + + if (href.indexOf('#') === -1) { + return false; + } + + if (href.indexOf('#') > 0) { + let linkUrl = href.substring(0, href.indexOf('#')); + + if (linkUrl !== this.$Url.href) { + return false; + } + } + + let targetString = href.substring(href.indexOf('#') + 1); + + if (targetString.length < 1) { + return false; + } + + let TargetElm = document.getElementById(targetString); + + if (!TargetElm) { + return false; + } + + return TargetElm; + }, + + /** + * Scroll to given element (Target) + * + * @param {HTMLElement} Target + */ + $scrollToElement: function (Target) { + let offset = Target.get('data-qui-offset'); + + if (!offset) { + offset = window.SCROLL_OFFSET ? window.SCROLL_OFFSET : 0; + } + + setTimeout(() => { + new Fx.Scroll(window, { + offset: { + y: -offset + } + }).toElement(Target); + }, 300); + }, + + openMenu: function (NavSubLeft) + { + var self = this; + + return new Promise(function (resolve) + { + self.menuDepth = self.menuDepth + 1; + var translateValue = (100 * self.menuDepth) * (-1); + + NavSubLeft.setStyles({ + display : "block" + }); + + moofx(self.NavUlContainer).animate({ + transform: "translateX(" + translateValue + "%)", + }, { + duration: 500, + equation: 'cubic-bezier(0.77, 0, 0.175, 1)', + callback: function () + { + resolve(); + } + }); + }); + }, + + /** + * close the next level of sub menu + * + * @param {HTMLLIElement} NavSubLeft + * + * @return Promise + */ + closeMenu: function (NavSubLeft) + { + var self = this; + + return new Promise(function (resolve) + { + self.menuDepth = self.menuDepth - 1; + var translateValue = (100 * self.menuDepth) * (-1); + + moofx(self.NavUlContainer).animate({ + transform: "translateX(" + translateValue + "%)", + }, { + duration: 500, + equation: 'cubic-bezier(0.77, 0, 0.175, 1)', + callback: function () + { + NavSubLeft.setStyles({ + display : "none" + }); + resolve(); + } + }); + }); + }, + + /** + * Restore menu to the initial state + */ + resetMenu: function () { + this.menuDepth = 0; + + var UlElements = this.Parent.getElements('.quiqqer-advanced'); + + UlElements.forEach((UlElement) => { + var ulClass = UlElement.classList; + + if (ulClass != "quiqqer-advanced quiqqer-advanced-page-navigation-level-1") { + UlElement.setStyles({ + display : "none" + }); + } + }); + + this.NavUlContainer.setStyles({ + transform: 'translateX(0)', + }); + } + }); + +}); diff --git a/locale.xml b/locale.xml index 94cb1620556089c1b4a849dda310cebc3122257f..a0df1a34764b685f5e0837dd7ef804a772c2af67 100644 --- a/locale.xml +++ b/locale.xml @@ -60,18 +60,34 @@ <de><![CDATA[Mobiles Menü]]></de> <en><![CDATA[Mobile Menu]]></en> </locale> + <locale name="mobileMenu.settings.template"> + <de><![CDATA[Mobile Menüvorlage]]></de> + <en><![CDATA[Mobile Menu Template]]></en> + </locale> + <locale name="mobileMenu.settings.template.standard"> + <de><![CDATA[Standard]]></de> + <en><![CDATA[Standard]]></en> + </locale> + <locale name="mobileMenu.settings.template.advanced"> + <de><![CDATA[Fortgeschrittene]]></de> + <en><![CDATA[Advanced]]></en> + </locale> <locale name="mobileMenu.settings.collapseMobileSubmenu"> - <de><![CDATA[Untermenüs zuklappen]]></de> - <en><![CDATA[Collpase submenu]]></en> + <de><![CDATA[Collpase-Untermenü in der mobilen Version]]></de> + <en><![CDATA[Collpase submenu in mobile version]]></en> </locale> <locale name="mobileMenu.settings.showLevel"> - <de><![CDATA[Ebenen anzeigen]]></de> - <en><![CDATA[Show levels]]></en> + <de><![CDATA[Ebene anzeigen]]></de> + <en><![CDATA[Show level]]></en> </locale> <locale name="mobileMenu.settings.showLevel.desc"> <de><![CDATA[Wie viele Ebenen des mobilen Menüs sollen angezeigt werden?]]></de> <en><![CDATA[How many levels of mobile menu should be shown?]]></en> </locale> + <locale name="mobileMenu.advanced.backBtn.text"> + <de><![CDATA[Zurück]]></de> + <en><![CDATA[Back]]></en> + </locale> <!-- sidebar menu --> <locale name="menu.control.sidebarDropDownMenu.title"> @@ -96,18 +112,10 @@ <pl><![CDATA[Zaawansowany]]></pl> </locale> <locale name="menu.control.sidebarDropDownMenu.setting.startId"> - <de><![CDATA[Start-ID uu]]></de> + <de><![CDATA[Start-ID]]></de> <en><![CDATA[Start ID]]></en> <pl><![CDATA[Pierwsza strona]]></pl> </locale> - <locale name="menu.control.sidebarDropDownMenu.setting.menuId"> - <de><![CDATA[Menu auswählen]]></de> - <en><![CDATA[Select the menu]]></en> - </locale> - <locale name="menu.control.sidebarDropDownMenu.setting.menuId.desc"> - <de><![CDATA[Diese Option ermöglicht, eigenes Menü auszuwählen. <strong>Wichtig!</strong> Diese Option hat Vorrang. Wird ein eigenes Menü ausgewählt, hat die Option "Start-ID" keine Auswirkung mehr.]]></de> - <en><![CDATA[This option allows you to choose your own menu. <strong>Important!</strong> This option takes precedence. If a custom menu is selected, the "Start ID" option has no effect anymore.]]></en> - </locale> <locale name="menu.control.sidebarDropDownMenu.setting.parentLink"> <de><![CDATA[Eltern-Seite Link anzeigen]]></de> <en><![CDATA[Show the parent site link]]></en> @@ -302,113 +310,6 @@ <de><![CDATA[QUIQQER Menüs REST API]]></de> <en><![CDATA[QUIQQER Menus REST API]]></en> </locale> - - <!-- Control: Tabs --> - <locale name="control.tabs.title"> - <de><![CDATA[Menü: Erweiterte Tabs (Registrierkarten)]]></de> - <en><![CDATA[Menu: Advanced Tabs]]></en> - </locale> - <locale name="control.tabs.description"> - <de><![CDATA[Erstelle Tabs mit verschiedenen Inhalten. Wähle für die Tabs eigene Icons und die Anordnung aus. Platziere im Inhalt nicht nur Texte, sondern auch Bilder.]]></de> - <en><![CDATA[This brick allows you to generate a tabbed interface with different content. Choose your own icons and layout for the tabs. Place not only texts but also images in the content.]]></en> - </locale> - <locale name="control.tabs.template"> - <de><![CDATA[Design]]></de> - <en><![CDATA[Design]]></en> - </locale> - <locale name="control.tabs.template.simple"> - <de><![CDATA[Einfach]]></de> - <en><![CDATA[Simple]]></en> - </locale> - <!-- Control: Tabs: nav img height --> - <locale name="control.tabs.navImgHeight"> - <de><![CDATA[Höhe der Navigation-Icons]]></de> - <en><![CDATA[Nav icons height]]></en> - </locale> - <locale name="control.tabs.navImgHeight.desc"> - <de><![CDATA[Dieser Wert bestimmt, wie groß die Icons in der Tab-Navigation sein werden (in Pixel). Standardwert ist 20.]]></de> - <en><![CDATA[This value determines how big the icons will be in the tab navigation (in pixel). Default value ist 20.]]></en> - </locale> - <!-- Control: Tabs: nav img style (position) --> - <locale name="control.tabs.navStyle"> - <de><![CDATA[Navigation-Icons Style]]></de> - <en><![CDATA[Nav icons style]]></en> - </locale> - <locale name="control.tabs.navStyle.imgLeft"> - <de><![CDATA[Icon links]]></de> - <en><![CDATA[Icon on the left]]></en> - </locale> - <locale name="control.tabs.navStyle.imgTop"> - <de><![CDATA[Icon oben]]></de> - <en><![CDATA[Icon on the top]]></en> - </locale> - <locale name="control.tabs.navStyle.onlyImg"> - <de><![CDATA[Nur das Icon. Titel wird ausgeblendet.]]></de> - <en><![CDATA[Only the icon. Titel is hidden.]]></en> - </locale> - <!-- Control: Tabs: nav break text --> - <locale name="control.tabs.navWrapText"> - <de><![CDATA[Navigations-Titel umbrechen]]></de> - <en><![CDATA[Break nav title]]></en> - </locale> - <locale name="control.tabs.navWrapText.wrap"> - <de><![CDATA[Standard: der Titel umbrechen]]></de> - <en><![CDATA[Default: wrap the title]]></en> - </locale> - <locale name="control.tabs.navWrapText.noWrap"> - <de><![CDATA[Der Titel wird nicht umgebrochen]]></de> - <en><![CDATA[The title will not be wrapped]]></en> - </locale> - <!-- Control: Tabs: nav fill --> - <locale name="control.tabs.navFillSpace"> - <de><![CDATA[Navigation-Tabs: volle Breite nutzen]]></de> - <en><![CDATA[Nav tabs: use full width]]></en> - </locale> - <locale name="control.tabs.navFillSpace.desc"> - <de><![CDATA[Wenn eingeschaltet, die Navigationspunkte werden gestreckt, sodass die gesamte verfügbare Fläche benutzt wird.]]></de> - <en><![CDATA[If enabled, the navigation entries are stretched so that the entire available area is used.]]></en> - </locale> - <!-- Control: Tabs: nav center --> - <locale name="control.tabs.navCenter"> - <de><![CDATA[Navigation-Tabs zentrieren]]></de> - <en><![CDATA[Center nav tabs]]></en> - </locale> - <locale name="control.tabs.navCenter.desc"> - <de><![CDATA[Wenn eingeschaltet, werden die Navigationspunkte zentriert. Wenn die Option "Volle Breite nutzen" aktiv ist, hat diese Einstellung keine Auswirkung.]]></de> - <en><![CDATA[If enabled, the navigation entries are centered. If the "Use full width" option is active, this setting has no effect.]]></en> - </locale> - <!-- Control: content: img min width --> - <locale name="control.tabs.contentImgMinWidth"> - <de><![CDATA[Inhalts-Bild: minimale Breit]]></de> - <en><![CDATA[Content image: min width]]></en> - </locale> - <locale name="control.tabs.contentImgMinWidth.desc"> - <de><![CDATA[Minimale Bildbreite in Pixel. Bitte keine großen Werte verwenden. Empfohlen ist 100px bis 600px. Standardwert ist 200px.]]></de> - <en><![CDATA[Minimum image width in pixels. Please do not use large values. Recommended is 100px to 600px. Default value is 200px.]]></en> - </locale> - <!-- Control: content: img max width --> - <locale name="control.tabs.contentImgMaxWidth"> - <de><![CDATA[Inhalts-Bild: maximale Breit]]></de> - <en><![CDATA[Content image: max width]]></en> - </locale> - <locale name="control.tabs.contentImgMaxWidth.desc"> - <de><![CDATA[Maximale Bildbreite in Pixel. Bitte keine großen Werte verwenden. Empfohlen ist 200px bis 600px. Standardwert ist 400px.]]></de> - <en><![CDATA[Maximum image width in pixels. Please do not use large values. Recommended is 200px to 600px. Default value is 400px.]]></en> - </locale> - <!-- Control: content: text max width --> - <locale name="control.tabs.contentTextWidth"> - <de><![CDATA[Maximale Textbreite]]></de> - <en><![CDATA[Text max width]]></en> - </locale> - <locale name="control.tabs.contentTextWidth.desc"> - <de><![CDATA[Maximale Textbreite in Pixel. Bitte keine großen Werte verwenden. Empfohlen ist 200px bis 1000px. Standardwert ist 600px.]]></de> - <en><![CDATA[Maximum text width in pixels. Please do not use large values. Recommended is 200px to 1000px. Default value is 600px.]]></en> - </locale> - <!-- Control: content: entries --> - <locale name="control.tabs.entries"> - <de><![CDATA[Tab Einträge]]></de> - <en><![CDATA[Tab entries]]></en> - </locale> </groups> <groups name="quiqqer/menu" datatype="php"> @@ -430,7 +331,7 @@ <en><![CDATA[Menu entry: To an internal page from a project]]></en> </locale> <locale name="item.url.title"> - <de><![CDATA[Menu Eintrag: Zu einer anderen URL]]></de> + <de><![CDATA[Menu Eintrag: Zur einer anderen URL]]></de> <en><![CDATA[Menu entry: To another URL]]></en> </locale> <locale name="menu.saved.successfully"> @@ -743,7 +644,7 @@ <en><![CDATA[Assign a menu]]></en> </locale> <locale name="quiqqer.menu.select.win.content"> - <de><![CDATA[Bitte wähle ein Menü aus, welches du zuweisen möchtest.]]></de> + <de><![CDATA[Bitte wähle ein Menü aus welches du zuweisen möchtest.]]></de> <en><![CDATA[Please select a menu you want to assign.]]></en> </locale> <locale name="quiqqer.menu.select.win.button"> @@ -751,56 +652,5 @@ <en><![CDATA[Select menu]]></en> </locale> - <!-- Tabs: settings --> - <locale name="control.tabs.entries.isDisabled"> - <de><![CDATA[Deaktiviert]]></de> - <en><![CDATA[Disabled]]></en> - </locale> - - <!-- Tabs: qui window settings --> - <locale name="control.tabs.entries.isDisabled"> - <de><![CDATA[Deaktiviert]]></de> - <en><![CDATA[Disabled]]></en> - </locale> - <locale name="control.tabs.entries.tabIcon"> - <de><![CDATA[Tab Icon]]></de> - <en><![CDATA[Tab icon]]></en> - </locale> - <locale name="control.tabs.entries.tabTitle"> - <de><![CDATA[Tab Titel]]></de> - <en><![CDATA[Tab title]]></en> - </locale> - <locale name="control.tabs.entries.entryImage"> - <de><![CDATA[Bild]]></de> - <en><![CDATA[Image]]></en> - </locale> - <locale name="control.tabs.entries.entryImagePos"> - <de><![CDATA[Bildposition]]></de> - <en><![CDATA[Image position]]></en> - </locale> - <locale name="control.tabs.entries.entryImagePos.left"> - <de><![CDATA[Links]]></de> - <en><![CDATA[Left]]></en> - </locale> - <locale name="control.tabs.entries.entryImagePos.right"> - <de><![CDATA[Rechts]]></de> - <en><![CDATA[Right]]></en> - </locale> - <locale name="control.tabs.entries.entryImagePos.top"> - <de><![CDATA[Oben]]></de> - <en><![CDATA[Top]]></en> - </locale> - <locale name="control.tabs.entries.entryImagePos.bottom"> - <de><![CDATA[Unten]]></de> - <en><![CDATA[Bottom]]></en> - </locale> - <locale name="control.tabs.entries.entryTitle"> - <de><![CDATA[Titel]]></de> - <en><![CDATA[Title]]></en> - </locale> - <locale name="control.tabs.entries.entryContent"> - <de><![CDATA[Inhalt]]></de> - <en><![CDATA[Content]]></en> - </locale> </groups> </locales> diff --git a/settings.xml b/settings.xml index 458665cead43901ccc834b4f1e8b68bdd243bead..9660bf3784f7a008eb9f458ebc6f447e048853e5 100644 --- a/settings.xml +++ b/settings.xml @@ -9,11 +9,22 @@ <type><![CDATA[number]]></type> <defaultvalue>250</defaultvalue> </conf> + <conf name="collapseMobileSubmenu"> + <type><![CDATA[bool]]></type> + </conf> + <conf name="showLevel"> + <type><![CDATA[number]]></type> + <defaultvalue>1</defaultvalue> + </conf> <conf name="type"> <type><![CDATA[string]]></type> </conf> </section> <section name="mobileMenu.settings"> + <conf name="template"> + <type><![CDATA[string]]></type> + <defaultvalue>standard</defaultvalue> + </conf> <conf name="collapseMobileSubmenu"> <type><![CDATA[bool]]></type> </conf> @@ -76,6 +87,18 @@ <locale group="quiqqer/menu" var="mobileMenu.settings.title"/> </title> + <select conf="mobileMenu.settings.template"> + <text> + <locale group="quiqqer/menu" var="mobileMenu.settings.template"/> + </text> + <option value="standard"> + <locale group="quiqqer/menu" var="mobileMenu.settings.template.standard"/> + </option> + <option value="advanced"> + <locale group="quiqqer/menu" var="mobileMenu.settings.template.advanced"/> + </option> + </select> + <input conf="mobileMenu.settings.collapseMobileSubmenu" type="checkbox"> <text> <locale group="quiqqer/menu" var="mobileMenu.settings.collapseMobileSubmenu"/> diff --git a/src/QUI/Menu/MegaMenu.php b/src/QUI/Menu/MegaMenu.php index 422f26bfcdb9466596e64fdb0a5d2645fbc688d7..29f265c7b36fdd2e3335838077201df99381c153 100644 --- a/src/QUI/Menu/MegaMenu.php +++ b/src/QUI/Menu/MegaMenu.php @@ -65,7 +65,12 @@ public function __construct($attributes = []) $slideOutParam['menuId'] = $this->getAttribute('menuId'); } - $this->Mobile = new QUI\Menu\SlideOut($slideOutParam); + if ($this->getProject()->getConfig('mobileMenu.settings.template') == 'advanced') { + $this->Mobile = new QUI\Menu\MenuAdvanced($slideOutParam); + + } else { + $this->Mobile = new QUI\Menu\SlideOut($slideOutParam); + } // defaults $this->Mobile->setAttribute('Project', $this->getProject()); diff --git a/src/QUI/Menu/Menu.html b/src/QUI/Menu/Menu.html index 718e8f432ad5f8e0715b0484b9655ec3df9b57b2..b218323b32cd9c6a48e364163237da250cb3c432 100644 --- a/src/QUI/Menu/Menu.html +++ b/src/QUI/Menu/Menu.html @@ -1,4 +1,4 @@ -<nav class="page-menu" data-qui="{$jsControl}" style="display: none;" data-qui-options-collapse-mobile-submenu={$collapseMobileSubmenu}> +<nav class="page-menu" data-qui="{$jsControl}" data-slideOut="mobileMenu-SlideOut" style="display: none;" data-qui-options-collapse-mobile-submenu={$collapseMobileSubmenu}> <div class="page-navigation {if !$showHomeLink}page-navigation__noHomeLink{/if}"> {if $showHomeLink} diff --git a/src/QUI/Menu/MenuAdvanced.Children.html b/src/QUI/Menu/MenuAdvanced.Children.html new file mode 100644 index 0000000000000000000000000000000000000000..8fd53ec053ef35e8fed54274d638266ef0888133 --- /dev/null +++ b/src/QUI/Menu/MenuAdvanced.Children.html @@ -0,0 +1,52 @@ + +{assign var=children value=$Site->getNavigation()} + +{if !isset($level)} +{assign var=level value=1} +{else} +{assign var=level value=$level+1} +{/if} + +{if count($children)} + +<ul class="quiqqer-advanced quiqqer-advanced-page-navigation-level-{$level}"> + {foreach from=$children key=k item=Child} + + {if $level > 1 and $k == 0} + <li class="quiqqer-advanced-menu-li-back"> + <div class="quiqqer-advanced-navigation-entry"> + <span class="fa fa-angle-left categories-menu-list-entry-next quiqqer-advanced-menu-icon quiqqer-advanced-menu-icon-back"></span> + + <span class="left-menu-text quiqqer-advanced-backBtn"> + {$BackBtn} + </span> + + </div> + </li> + {/if} + + <li> + <div class="quiqqer-advanced-navigation-entry"> + <a href="{url site=$Child}" class="left-menu-a"> + + <span class="left-menu-text"> + {$Child->getAttribute('title')} + </span> + + </a> + + {if count($Child->getNavigation())} + <span class="fa fa-angle-right categories-menu-list-entry-next quiqqer-advanced-menu-icon quiqqer-advanced-menu-icon-next"></span> + {/if} + </div> + + {include file="`$FileMenu`" + Site=$Child + ActiveSite=$ActiveSite + level=$level + } + </li> + {/foreach} +</ul> + +{/if} diff --git a/src/QUI/Menu/MenuAdvanced.css b/src/QUI/Menu/MenuAdvanced.css new file mode 100755 index 0000000000000000000000000000000000000000..3e81e38a7be5b79a826660d7d417e9db09fbdc5d --- /dev/null +++ b/src/QUI/Menu/MenuAdvanced.css @@ -0,0 +1,75 @@ +:root { + --qui-menuAdvanced-color: #eaeaea; +} + +.page-navigation .quiqqer-menu-advanced { + margin-left: 0; + position: relative; + overflow: hidden; +} + +.page-menu ul.quiqqer-advanced-page-navigation-level-1 { + position: initial; + display: block; + transform: translateX(0); +} + +ul.quiqqer-advanced { + display: none; + position: absolute; + left: 0; + top: 0; + width: 100%; + transform: translateX(100%); +} + +.page-navigation ul.quiqqer-advanced { + margin-left: 0; +} + +.page-navigation.quiqqer-menu-advanced { + padding: 0; + overflow: hidden; +} + +.page-navigation .quiqqer-advanced li { + font-size: 1.125rem; + border-top: 1px solid #636363; +} + +.page-navigation .quiqqer-advanced li:last-child { + border-bottom: 1px solid #636363; +} + +.quiqqer-advanced-navigation-entry { + display: flex; +} + +.page-navigation .quiqqer-advanced a { + padding: 10px 20px; +} + +.page-navigation .quiqqer-advanced .quiqqer-advanced-menu-icon { + color: white; + font-size: 1.5rem; + display: flex; + justify-content: center; + align-items: center; + padding: 0 20px; + margin-right: 0; + border-left: 1px solid #636363; +} + +.page-navigation .quiqqer-advanced .quiqqer-advanced-menu-icon-back { + border-left: none; + border-right: 1px solid #636363; + margin-right: 1rem; +} + +.quiqqer-advanced-backBtn { + font-size: 1.125rem; + color: var(--qui-menuAdvanced-color); + display: flex; + justify-content: center; + align-items: center; +} \ No newline at end of file diff --git a/src/QUI/Menu/MenuAdvanced.html b/src/QUI/Menu/MenuAdvanced.html new file mode 100755 index 0000000000000000000000000000000000000000..8114d1aa5f78fd6519971d0021a1657b4ed59461 --- /dev/null +++ b/src/QUI/Menu/MenuAdvanced.html @@ -0,0 +1,19 @@ +<nav class="page-menu" data-qui="{$jsControl}" data-slideOut="mobileMenu-SlideOut" style="display: none;"> + + <div class="page-navigation quiqqer-menu-advanced {if !$showHomeLink}page-navigation__noHomeLink{/if}"> + {if $showHomeLink} + <a href="{url site=$Project->firstChild()}" class="page-navigation-home"> + <span class="fa fa-home"></span> + {$Project->firstChild()->getAttribute('title')} + </a> + {/if} + + {include file="`$FileMenu`" + Site=$Project->firstChild() + ActiveSite=$Site + CollapseMobileSubmenu=$collapseMobileSubmenu + ShowLevel=$showLevel + BackBtn=$backBtn + } + </div> +</nav> diff --git a/src/QUI/Menu/MenuAdvanced.php b/src/QUI/Menu/MenuAdvanced.php new file mode 100644 index 0000000000000000000000000000000000000000..e9888f630414df3ae34f3633a5df70b47b4b3cd3 --- /dev/null +++ b/src/QUI/Menu/MenuAdvanced.php @@ -0,0 +1,98 @@ +<?php + +/** + * This file contains \QUI\Menu\MenuAdvanced + */ + +namespace QUI\Menu; + +use QUI; + +/** + * Class MenuAdvanced + * Creates an slideout menu + * + * @package QUI\Menu + */ +class MenuAdvanced extends QUI\Control +{ + /** + * @param array $attributes + */ + public function __construct($attributes = []) + { + $this->setAttributes([ + 'showHomeLink' => true, + 'menuId' => false, // if set independent menu template will be used + 'showFirstLevelIcons' => false // current it works only for independent menu + ]); + + parent::__construct($attributes); + } + + /** + * @return string + * @throws QUI\Exception + */ + public function getBody() + { + + $Engine = QUI::getTemplateManager()->getEngine(); + + $collapseMobileSubmenu = $this->getAttribute('collapseMobileSubmenu'); + $showLevel = $this->getAttribute('showLevel'); + + $backBtnText = QUI::getLocale()->get( + 'quiqqer/menu', + 'mobileMenu.advanced.backBtn.text' + ); + + $this->addCSSFile( + \dirname(__FILE__) . '/MenuAdvanced.css' + ); + + $params = [ + 'this' => $this, + 'Project' => $this->getProject(), + 'jsControl' => 'package/quiqqer/menu/bin/MenuAdvanced', + 'showHomeLink' => $this->getAttribute('showHomeLink'), + 'backBtn' => $backBtnText + ]; + + if ($this->getAttribute('menuId')) { + $IndependentMenu = Independent\Handler::getMenu($this->getAttribute('menuId')); + + $template = dirname(__FILE__) . '/Menu.Independent.html'; + $params['FileMenu'] = dirname(__FILE__) . '/Menu.Children.Independent.html'; + $params['IndependentMenu'] = $IndependentMenu; + $params['Site'] = $this->getSite(); + $params['collapseMobileSubmenu'] = $collapseMobileSubmenu; + $params['showLevel'] = $showLevel; + $params['showFirstLevelIcons'] = $this->getAttribute('showFirstLevelIcons'); + } else { + $template = dirname(__FILE__) . '/MenuAdvanced.html'; + $params['collapseMobileSubmenu'] = $collapseMobileSubmenu; + $params['showLevel'] = $showLevel; + $params['FileMenu'] = dirname(__FILE__) . '/MenuAdvanced.Children.html'; + $params['Site'] = $this->getSite(); + } + + $Engine->assign($params); + + return $Engine->fetch($template); + } + + /** + * Return the current site + * + * @return mixed|QUI\Projects\Site + */ + protected function getSite() + { + if ($this->getAttribute('Site')) { + return $this->getAttribute('Site'); + } + + return QUI::getRewrite()->getSite(); + } +}