diff --git a/bin/Controls/NavTabs.js b/bin/Controls/NavTabs.js index b12f2562d7fa118f1dfc1b2000ab215e49c53e0c..fa9a2ff11998146a701b3f3130842bb8ce2f5c99 100644 --- a/bin/Controls/NavTabs.js +++ b/bin/Controls/NavTabs.js @@ -151,6 +151,8 @@ define('package/quiqqer/menu/bin/Controls/NavTabs', [ var self = this; + this.NavContentContainer.setStyle('height', this.NavContentContainer.offsetHeight); + Promise.all([ this.disableNavItem(this.ActiveNavTab), this.hideContent(this.ActiveContent) @@ -239,7 +241,7 @@ define('package/quiqqer/menu/bin/Controls/NavTabs', [ }, /** - * Set heigt of tab content container + * Set height of tab content container * * @param height integer * @return Promise @@ -264,8 +266,6 @@ define('package/quiqqer/menu/bin/Controls/NavTabs', [ * @return Promise */ $slideFadeOut: function (Item) { - this.NavContentContainer.setStyle('height', Item.offsetHeight) - return new Promise(function (resolve) { moofx(Item).animate({ transform: 'translateX(-10px)', diff --git a/bin/Controls/Tabs.Settings.css b/bin/Controls/Tabs.Settings.css new file mode 100644 index 0000000000000000000000000000000000000000..a06d3a46503794a1d1b2a1d551cc667fd46335bc --- /dev/null +++ b/bin/Controls/Tabs.Settings.css @@ -0,0 +1,113 @@ +/*.field-container-item { + flex-shrink: 0; +}*/ + +.qui-controls-formlist-navTabsVerticalSettings { + border: 1px solid #dedede; + border-left: none; + display: flex; + flex-direction: column; + flex-grow: 1; + padding: 15px; +} + +.qui-controls-formlist-navTabsVerticalSettings .qui-controls-formlist-buttons { + order: 2; +} + +.qui-controls-formlist-navTabsVerticalSettings .qui-controls-formlist-container { + display: flex; + flex-wrap: wrap; + margin-right: -15px; + order: 1; +} + +.qui-controls-formlist-navTabsVerticalSettings .qui-controls-formlist-container:after { + content: ''; + flex-basis: 450px; + flex-grow: 1; + height: 0; + margin-right: 20px; + order: 2; + position: relative; + visibility: hidden; +} + +.qui-controls-formlist-navTabsVerticalSettings .qui-controls-formlist-entry { + background: #e8edff; + border-bottom: none; + flex-basis: 450px; + flex-grow: 1; + margin-bottom: 20px; + margin-right: 20px; + padding: 20px; + position: relative; +} + +.qui-controls-formlist-navTabsVerticalSettings .qui-controls-formlist-entry-delete { + padding: 0 !important; + position: absolute; + right: 0; + top: 0; +} + +.qui-controls-formlist-accordion .qui-controls-formlist-entry-delete .qui-button { + background: none; + border: none; + border-radius: 0; + box-shadow: none; + color: #333; +} + +.qui-controls-formlist-navTabsVerticalSettings .qui-controls-formlist-entry-delete .qui-button:hover { + background: #a6abbd; +} + + +.qui-controls-formlist-navTabsVerticalSettings .qui-controls-formlist-entry-data { + padding: 0; + width: 100%; +} + +.quiqqer-menu-navTabsVerticalSettings-entry label { + margin-bottom: 10px; + width: 100% !important; +} + +.quiqqer-menu-navTabsVerticalSettings-entry label:last-child { + margin-bottom: 0; +} + +.quiqqer-menu-navTabsVerticalSettings-entry span.entry-title { + display: block; + margin-bottom: 6px; +} + +.quiqqer-menu-navTabsVerticalSettings-entry input, +.quiqqer-menu-navTabsVerticalSettings-entry textarea { + max-width: 100%; + width: 100%; +} + +.quiqqer-menu-navTabsVerticalSettings-entry .field-container-field { + border: none; + padding: 0; +} + +.quiqqer-menu-navTabsVerticalSettings-entry .control-editor-preview { + background: #fff; + height: 120px !important; +} + +.quiqqer-menu-navTabsVerticalSettings-entry .qui-controls-project-site-input { + display: flex; +} + +.quiqqer-menu-navTabsVerticalSettings-entry .qui-controls-colorpicker { + width: 100%; + display: flex; +} + +.quiqqer-menu-navTabsVerticalSettings-entry .qui-controls-colorpicker-colorContainer { + flex-grow: 1; +} \ No newline at end of file diff --git a/bin/Controls/Tabs.Settings.html b/bin/Controls/Tabs.Settings.html new file mode 100644 index 0000000000000000000000000000000000000000..bdab0f0a1d67bc42da6bcec42ab749ddd1e6168a --- /dev/null +++ b/bin/Controls/Tabs.Settings.html @@ -0,0 +1,84 @@ +<form name="quiqqer-bricks-customerReviewsSlider-settings-entry" + class="quiqqer-bricks-customerReviewsSlider-settings-entry-form" +> + <table class="data-table data-table-flexbox"> + <tbody> + <tr> + <td> + <label class="field-container"> + <span class="field-container-item"> + {{isDisabled}} + </span> + <span id="isDisabledWrapper" class="field-container-field"></span> + </label> + </td> + </tr> + <tr> + <td> + <label class="field-container"> + <span class="field-container-item"> + {{tabIcon}} + </span> + <input name="tabIcon" data-qui-options-cssclasses="1" class="field-container-field media-image"/> + </label> + </td> + </tr> + <tr> + <td> + <label class="field-container"> + <span class="field-container-item"> + {{tabTitle}} + </span> + <input name="tabTitle" class="field-container-field"/> + </label> + </td> + </tr> + <tr> + <td> + <label class="field-container"> + <span class="field-container-item"> + {{entryImage}} + </span> + <input name="entryImage" class="field-container-field media-image"/> + </label> + </td> + </tr> + <tr> + <td> + <label class="field-container"> + <span class="field-container-item"> + {{entryImagePos}} + </span> + <select name="entryImagePos" class="field-container-field"> + <option value="left">{{optionLeft}}</option> + <option value="right">{{optionRight}}</option> + <option value="top">{{optionTop}}</option> + <option value="bottom">{{optionBottom}}</option> + </select> + </label> + </td> + </tr> + <tr> + <td> + <label class="field-container"> + <span class="field-container-item"> + {{entryTitle}} + </span> + <input name="entryTitle" class="field-container-field" /> + </label> + </td> + </tr> + <tr> + <td> + <label class="field-container"> + <span class="field-container-item"> + {{entryContent}} + </span> + <input name="entryContent" class="field-container-field field-entryContent" + data-qui="controls/editors/Input"/> + </label> + </td> + </tr> + </tbody> + </table> +</form> diff --git a/bin/Controls/Tabs.Settings.js b/bin/Controls/Tabs.Settings.js new file mode 100644 index 0000000000000000000000000000000000000000..e49cff094a51aafd0c7adf344c51c644b06d0e96 --- /dev/null +++ b/bin/Controls/Tabs.Settings.js @@ -0,0 +1,806 @@ +/** + * @module package/quiqqer/menu/bin/Controls/NavTabsVertical + * @author Dominik Chrzanowski + * + */ +define('package/quiqqer/menu/bin/Controls/Tabs.Settings', [ + + 'qui/QUI', + 'qui/controls/Control', + 'qui/controls/windows/Confirm', + 'qui/controls/buttons/Button', + 'qui/controls/buttons/Switch', + 'Locale', + 'Mustache', + 'controls/grid/Grid', + 'utils/Controls', + + 'text!package/quiqqer/menu/bin/Controls/Tabs.Settings.html', + 'css!package/quiqqer/menu/bin/Controls/Tabs.Settings.css' + +], function ( + QUI, + QUIControl, + QUIConfirm, + QUIButton, + QUISwitch, + QUILocale, + Mustache, + Grid, + ControlsUtils, + templateEntry +) { + "use strict"; + + var lg = 'quiqqer/menu'; + + return new Class({ + + Extends: QUIControl, + Type : 'package/quiqqer/menu/bin/Controls/Tabs.Settings', + + Binds: [ + '$onImport', + '$openAddDialog', + '$openDeleteDialog', + '$openEditDialog', + '$toggleSlideStatus', + 'update' + ], + + initialize: function (options) { + this.parent(options); + + this.$Input = null; + this.$Grid = null; + + this.$data = []; + + this.addEvents({ + onImport: this.$onImport + }); + }, + + /** + * event: on import + */ + $onImport: function () { + this.$Input = this.getElm(); + + this.$Elm = new Element('div', { + 'class': 'quiqqer-menu-navTabsVertival-settings', + styles : { + clear : 'both', + 'float' : 'left', + height : 400, + overflow: 'hidden', + position: 'relative', + margin : '10px 0 0 0', + width : '100%' + } + }).wraps(this.$Input); + + // grid and sizes + var size = this.$Elm.getSize(); + + var Desktop = new Element('div', { + styles: { + width: size.x + } + }).inject(this.$Elm); + + this.$Grid = new Grid(Desktop, { + height : 400, + width : size.x, + buttons : [ + { + name : 'up', + icon : 'fa fa-angle-up', + disabled: true, + events : { + onClick: function () { + this.$Grid.moveup(); + this.$refreshSorting(); + }.bind(this) + } + }, { + name : 'down', + icon : 'fa fa-angle-down', + disabled: true, + events : { + onClick: function () { + this.$Grid.movedown(); + this.$refreshSorting(); + }.bind(this) + } + }, { + type: 'separator' + }, { + name : 'add', + textimage: 'fa fa-plus', + text : QUILocale.get('quiqqer/quiqqer', 'add'), + events : { + onClick: this.$openAddDialog + } + }, { + type: 'separator' + }, { + name : 'edit', + textimage: 'fa fa-edit', + text : QUILocale.get('quiqqer/quiqqer', 'edit'), + disabled : true, + events : { + onClick: this.$openEditDialog + } + }, { + name : 'delete', + textimage: 'fa fa-trash', + text : QUILocale.get('quiqqer/quiqqer', 'delete'), + disabled : true, + events : { + onClick: this.$openDeleteDialog + } + } + ], + columnModel: [ + { + header : QUILocale.get(lg, 'control.tabs.entries.isDisabled'), + dataIndex: 'isDisabledDisplay', + dataType : 'QUI', + width : 80 + }, { + dataIndex: 'isDisabled', + hidden : true + }, { + header : QUILocale.get(lg, 'control.tabs.entries.tabIcon'), + dataIndex: 'tabIconPreview', + dataType : 'node', + width : 80 + }, + { + header : QUILocale.get(lg, 'control.tabs.entries.tabTitle'), + dataIndex: 'tabTitle', + dataType : 'code', + width : 120 + }, + { + header : QUILocale.get(lg, 'control.tabs.entries.entryImage'), + dataIndex: 'entryImagePreview', + dataType : 'node', + width : 80 + }, + { + header : QUILocale.get(lg, 'control.tabs.entries.entryImagePos'), + dataIndex: 'entryImagePos', + dataType : 'code', + width : 100 + }, + { + header : QUILocale.get(lg, 'control.tabs.entries.entryTitle'), + dataIndex: 'entryTitle', + dataType : 'code', + width : 200 + }, + { + header : QUILocale.get(lg, 'control.tabs.entries.entryContent'), + dataIndex: 'entryContent', + dataType : 'code', + width : 300 + }, + { + dataIndex: 'newTab', + hidden : true + }, { + dataIndex: 'image', + dataType : 'string', + hidden : true + } + ] + }); + + this.$Grid.addEvents({ + onClick: function () { + var buttons = this.$Grid.getButtons(), + + Edit = buttons.filter(function (Btn) { + return Btn.getAttribute('name') === 'edit'; + })[0], + + Up = buttons.filter(function (Btn) { + return Btn.getAttribute('name') === 'up'; + })[0], + + Down = buttons.filter(function (Btn) { + return Btn.getAttribute('name') === 'down'; + })[0], + + Delete = buttons.filter(function (Btn) { + return Btn.getAttribute('name') === 'delete'; + })[0]; + + Up.enable(); + Down.enable(); + Edit.enable(); + Delete.enable(); + }.bind(this), + + onDblClick: this.$openEditDialog + }); + + this.$Grid.getElm().setStyles({ + position: 'absolute' + }); + + try { + this.$data = JSON.decode(this.$Input.value); + + if (typeOf(this.$data) !== 'array') { + this.$data = []; + } + + this.refresh(); + } catch (e) { + } + }, + + /** + * Toggles the slide's status between enabled and disabled + * + * @param {Object} [Caller] - the object calling this event + */ + $toggleSlideStatus: function (Caller) { + if (!Caller) { + return; + } + + // get cell number + var row = Caller.getElm().getParent('li').get('data-row'); + + this.$data[row].isDisabled = Caller.getStatus(); + this.update(); + }, + + /** + * Resize the control + * + * @return {Promise} + */ + resize: function () { + var size = this.getElm().getSize(); + + return this.$Grid.setWidth(size.x).then(function () { + this.$Grid.resize(); + }.bind(this)); + }, + + /** + * refresh the display + */ + refresh: function () { + var i, len, entry, insert; + var data = []; + + for (i = 0, len = this.$data.length; i < len; i++) { + entry = this.$data[i]; + insert = { + tabIcon : '', + entryImage : '', + tabIconPreview : new Element('span', {html: ' '}), + entryImagePreview: new Element('span', {html: ' '}) + }; + + entry.isDisabled = parseInt(entry.isDisabled); + + insert.isDisabledDisplay = new QUISwitch({ + status: entry.isDisabled, + name : i, + uid : i, + events: { + onChange: this.$toggleSlideStatus + } + }); + + // tab icon + if ("tabIcon" in entry && entry.tabIcon !== '') { + insert.tabIcon = entry.tabIcon; + + if (entry.tabIcon.includes('fa ')) { + insert.tabIconPreview = new Element('span', { + 'class': insert.tabIcon + }); + } else { + insert.tabIconPreview = new Element('img', { + src : URL_DIR + insert.tabIcon + '&maxwidth=50&maxheight=50', + width : 50, + height: 50 + }); + } + } + + if ("tabTitle" in entry) { + insert.tabTitle = entry.tabTitle; + } + + // entry image + if ("entryImage" in entry && entry.entryImage !== '') { + insert.entryImage = entry.entryImage; + + if (entry.entryImage.includes('fa ')) { + insert.entryImagePreview = new Element('span', { + 'class': insert.entryImage + }); + } else { + insert.entryImagePreview = new Element('img', { + src : URL_DIR + insert.entryImage + '&maxwidth=50&maxheight=50', + width : 50, + height: 50 + }); + } + } + + if ("entryImagePos" in entry) { + insert.entryImagePos = entry.entryImagePos; + } + + if ("entryTitle" in entry) { + insert.entryTitle = entry.entryTitle; + } + + if ("entryContent" in entry) { + insert.entryContent = entry.entryContent; + } + + data.push(insert); + } + + this.$Grid.setData({ + data: data + }); + + var buttons = this.$Grid.getButtons(), + + Edit = buttons.filter(function (Btn) { + return Btn.getAttribute('name') === 'edit'; + })[0], + + Up = buttons.filter(function (Btn) { + return Btn.getAttribute('name') === 'up'; + })[0], + + Down = buttons.filter(function (Btn) { + return Btn.getAttribute('name') === 'down'; + })[0], + + Delete = buttons.filter(function (Btn) { + return Btn.getAttribute('name') === 'delete'; + })[0]; + + Up.disable(); + Down.disable(); + Edit.disable(); + Delete.disable(); + }, + + /** + * Update the field + */ + update: function () { + this.$Input.value = JSON.encode(this.$data); + }, + + /** + * Add an entry + * + * @param {Object} params + */ + add: function (params) { + var entry = { + isDisabled : 0, + tabIcon : '', + tabTitle : '', + entryImage : '', + entryImagePos: '', + entryTitle : '', + entryContent : '' + }; + + if ("isDisabled" in params) { + entry.isDisabled = parseInt(params.isDisabled); + } + + if ("tabIcon" in params && params.tabIcon !== '') { + entry.tabIcon = params.tabIcon; + } + + if ("tabTitle" in params) { + entry.tabTitle = params.tabTitle; + } + + if ("entryImage" in params && params.entryImage !== '') { + entry.entryImage = params.entryImage; + } + + if ("entryImagePos" in params) { + entry.entryImagePos = params.entryImagePos; + } + + if ("entryTitle" in params) { + entry.entryTitle = params.entryTitle; + } + + if ("entryContent" in params) { + entry.entryContent = params.entryContent; + } + + this.$data.push(entry); + this.refresh(); + this.update(); + }, + + /** + * Edit an entry + * + * @param {number} index + * @param {object} params + */ + edit: function (index, params) { + + if (typeof index === 'undefined') { + return; + } + + var entry = { + isDisabled : 0, + tabIcon : '', + tabTitle : '', + entryImage : '', + entryImagePos: '', + entryTitle : '', + entryContent : '' + }; + + if ("isDisabled" in params) { + entry.isDisabled = parseInt(params.isDisabled); + } + + if ("tabIcon" in params && params.tabIcon !== '') { + entry.tabIcon = params.tabIcon; + } + + if ("tabTitle" in params) { + entry.tabTitle = params.tabTitle; + } + + if ("entryImage" in params && params.entryImage !== '') { + entry.entryImage = params.entryImage; + } + + if ("entryImagePos" in params) { + entry.entryImagePos = params.entryImagePos; + } + + if ("entryTitle" in params) { + entry.entryTitle = params.entryTitle; + } + + if ("entryContent" in params) { + entry.entryContent = params.entryContent; + } + + this.$data[index] = entry; + + this.refresh(); + this.update(); + }, + + /** + * Delete one entry or multiple entries + * + * @param {number|array} index + */ + del: function (index) { + var newList = []; + + if (typeOf(index) !== 'array') { + index = [index]; + } + + for (var i = 0, len = this.$data.length; i < len; i++) { + if (!index.contains(i)) { + newList.push(this.$data[i]); + } + } + + this.$data = newList; + }, + + /** + * Set the used project + * + * @param {string|object} Project + */ + setProject: function (Project) { + this.setAttribute('project', Project); + + var controls = QUI.Controls.getControlsInElement(this.getElm()); + + controls.each(function (Control) { + if (Control === this) { + return; + } + + if ("setProject" in Control) { + Control.setProject(Project); + } + }.bind(this)); + }, + + /** + * Refresh the data sorting in dependence of the grid + */ + $refreshSorting: function () { + var gridData = this.$Grid.getData(), + data = []; + + for (var i = 0, len = gridData.length; i < len; i++) { + data.push({ + isDisabled : parseInt(gridData[i].isDisabled), + titleIcon : gridData[i].titleIcon, + entryTitle : gridData[i].entryTitle, + entryImage : gridData[i].entryImage, + entryContent: gridData[i].entryContent + }); + } + + this.$data = data; + this.update(); + }, + + /** + * Dialogs + */ + + /** + * opens the delete dialog + * + * @return {Promise} + */ + $openDeleteDialog: function () { + new QUIConfirm({ + icon : 'fa fa-icon', + text : QUILocale.get(lg, 'control.navTabsVertical.entries.delete.title'), + information: QUILocale.get(lg, 'control.navTabsVertical.entries.delete.information'), + texticon : false, + maxWidth : 600, + maxHeight : 400, + ok_button : { + text : QUILocale.get('quiqqer/quiqqer', 'delete'), + textimage: 'fa fa-trash' + }, + events : { + onSubmit: function () { + var selected = this.$Grid.getSelectedIndices(); + + this.$Grid.deleteRows(selected); + this.del(selected); + this.update(); + }.bind(this) + } + }).open(); + }, + + /** + * Open edit dialog + * + * @retrun {Promise} + */ + $openEditDialog: function () { + var self = this, + data = this.$Grid.getSelectedData(), + index = this.$Grid.getSelectedIndices(); + + if (!data.length) { + return Promise.resolve(); + } + + data = data[0]; + index = index[0]; + + return this.$createDialog().then(function (Dialog) { + + Dialog.addEvent('onSubmit', function () { + Dialog.Loader.show(); + + var Content = Dialog.getContent(); + var Form = Content.getElement('form'); + + var isDisabled = Dialog.IsDisabledSwitch.getStatus(); + var TabIcon = Form.elements.tabIcon; + var tabTitle = Form.elements.tabTitle; + var entryImage = Form.elements.entryImage; + var entryImagePos = Form.elements.entryImagePos; + var entryTitle = Form.elements.entryTitle; + var entryContent = Form.elements.entryContent; + + self.edit(index, { + isDisabled : isDisabled, + tabIcon : TabIcon.value, + tabTitle : tabTitle.value, + entryImage : entryImage.value, + entryImagePos: entryImagePos.value, + entryTitle : entryTitle.value, + entryContent : entryContent.value, + }); + + Dialog.close(); + }); + + + Dialog.addEvent('onOpenAfterCreate', function () { + + var Content = Dialog.getContent(); + var Form = Content.getElement('form'); + + var TabIcon = Form.elements.tabIcon; + var tabTitle = Form.elements.tabTitle; + var entryImage = Form.elements.entryImage; + var entryImagePos = Form.elements.entryImagePos; + var entryTitle = Form.elements.entryTitle; + var entryContent = Form.elements.entryContent; + + if (data.isDisabled) { + Dialog.IsDisabledSwitch.on(); + } else { + Dialog.IsDisabledSwitch.off(); + } + + TabIcon.value = data.tabIcon; + tabTitle.value = data.tabTitle; + entryImage.value = data.entryImage; + entryImagePos.value = data.entryImagePos; + entryTitle.value = data.entryTitle; + entryContent.value = data.entryContent; + + TabIcon.fireEvent('change'); + tabTitle.fireEvent('change'); + entryImage.fireEvent('change'); + entryImagePos.fireEvent('change'); + entryTitle.fireEvent('change'); + entryContent.fireEvent('change'); + }); + + Dialog.setAttribute('title', QUILocale.get(lg, 'control.navTabsVertical.entries.edit.title')); + Dialog.open(); + }); + }, + + /** + * opens the add dialog + * + * @return {Promise} + */ + $openAddDialog: function () { + var self = this; + + return this.$createDialog().then(function (Dialog) { + Dialog.addEvent('onSubmit', function () { + Dialog.Loader.show(); + + var Content = Dialog.getContent(); + var Form = Content.getElement('form'); + + var isDisabled = Dialog.IsDisabledSwitch.getStatus(); + var TabIcon = Form.elements.tabIcon; + var tabTitle = Form.elements.tabTitle; + var entryImage = Form.elements.entryImage; + var entryImagePos = Form.elements.entryImagePos; + var entryTitle = Form.elements.entryTitle; + var entryContent = Form.elements.entryContent; + + self.add({ + isDisabled : isDisabled, + tabIcon : TabIcon.value, + tabTitle : tabTitle.value, + entryImage : entryImage.value, + entryImagePos: entryImagePos.value, + entryTitle : entryTitle.value, + entryContent : entryContent.value, + + }); + + Dialog.close(); + }); + + Dialog.open(); + }); + }, + + /** + * Create a edit / add entry dialog + * + * @return {Promise} + */ + $createDialog: function () { + var self = this; + + return new Promise(function (resolve) { + var Dialog = new QUIConfirm({ + title : QUILocale.get(lg, 'control.navTabsVertical.entries.add.title'), + icon : 'fa fa-edit', + maxWidth : 800, + maxHeight : 600, + autoclose : false, + IsDisabledSwitch: false, + events : { + onOpen: function (Win) { + Win.Loader.show(); + Win.getContent().set('html', ''); + + + var prefix = 'control.tabs.entries.', + Container = new Element('div', { + html : Mustache.render(templateEntry, { + isDisabled : QUILocale.get(lg, prefix + 'isDisabled'), + tabIcon : QUILocale.get(lg, prefix + 'tabIcon'), + tabTitle : QUILocale.get(lg, prefix + 'tabTitle'), + entryImage : QUILocale.get(lg, prefix + 'entryImage'), + entryImagePos: QUILocale.get(lg, prefix + 'entryImagePos'), + optionLeft : QUILocale.get(lg, prefix + 'entryImagePos.left'), + optionRight : QUILocale.get(lg, prefix + 'entryImagePos.right'), + optionTop : QUILocale.get(lg, prefix + 'entryImagePos.top'), + optionBottom : QUILocale.get(lg, prefix + 'entryImagePos.bottom'), + entryTitle : QUILocale.get(lg, prefix + 'entryTitle'), + entryContent : QUILocale.get(lg, prefix + 'entryContent'), + }), + 'class': 'quiqqer-menu-navTabsVertival-settings' + }).inject(Win.getContent()); + + var Text = Container.getElement('.field-entryContent'); + + Text.getParent().setStyles({ + height: 100 + }); + + Win.IsDisabledSwitch = new QUISwitch({ + name : 'isDisabled', + status: false + }).inject(Container.getElement('#isDisabledWrapper')); + + QUI.parse(Container).then(function () { + return ControlsUtils.parse(Container); + }).then(function () { + var controls = QUI.Controls.getControlsInElement(Container), + project = self.getAttribute('project'); + + controls.each(function (Control) { + if (Control === self) { + return; + } + + if ("setProject" in Control) { + Control.setProject(project); + } + }); + + Win.fireEvent('openAfterCreate', [Win]); + + moofx(Container).animate({ + opacity: 1, + top : 0 + }, { + duration: 250, + callback: function () { + resolve(Container); + Win.Loader.hide(); + } + }); + }); + } + } + }); + + resolve(Dialog); + }); + } + }); +}); diff --git a/bricks.xml b/bricks.xml index 54afccc98f0c419984dd15cffb50c032a0d03b33..2dbc8f43fac6050e2481a0412c6a123495d57db1 100644 --- a/bricks.xml +++ b/bricks.xml @@ -97,7 +97,58 @@ </setting> </settings> </brick> - + + <!-- tabs (horizontal) --> + <brick control="\QUI\Menu\Controls\Tabs"> + <title> + <locale group="quiqqer/menu" + var="control.tabs.title"/> + </title> + <description> + <locale group="quiqqer/menu" + var="control.tabs.description"/> + </description> + + <settings> + <setting name="tabsStyle" type="select"> + <locale group="quiqqer/menu" + var="control.tabs.tabsStyle"/> + + <option value="smallImgLeft"> + <locale group="quiqqer/menu" + var="control.tabs.tabsStyle.smallImgLeft"/> + </option> + </setting> + + <setting name="tabsImgPos" type="select"> + <locale group="quiqqer/menu" + var="control.tabs.imagePos"/> + + <option value="left"> + <locale group="quiqqer/menu" + var="control.tabs.tabsImgPos.left"/> + </option> + <option value="top"> + <locale group="quiqqer/menu" + var="control.tabs.tabsImgPos.top"/> + </option> + <option value="right"> + <locale group="quiqqer/menu" + var="control.tabs.tabsImgPos.right"/> + </option> + <option value="bottom"> + <locale group="quiqqer/menu" + var="control.tabs.tabsImgPos.bottom"/> + </option> + </setting> + + <setting name="entries" type="hidden" data-qui="package/quiqqer/menu/bin/Controls/Tabs.Settings"> + <locale group="quiqqer/menu" var="control.tabs.entries"/> + </setting> + + </settings> + </brick> + <!-- nav tabs vertical --> <brick control="\QUI\Menu\NavTabsVertical"> <title> diff --git a/locale.xml b/locale.xml index 0b809495cdb741cff0e7ebfc00ac1ad664a7c96b..d353136754f6c5ac65dbc90d6317c05346ad862b 100644 --- a/locale.xml +++ b/locale.xml @@ -644,5 +644,56 @@ <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/src/QUI/Menu/Controls/Tabs.css b/src/QUI/Menu/Controls/Tabs.css new file mode 100644 index 0000000000000000000000000000000000000000..ddc52fdb786cb0769526d2ec166bb40b62b5941b --- /dev/null +++ b/src/QUI/Menu/Controls/Tabs.css @@ -0,0 +1,212 @@ +.quiqqer-tabsAdvanced-nav-inner, +.quiqqer-tabsAdvanced-content-inner { + list-style: none; + padding: 0; +} + +.quiqqer-tabsAdvanced-nav-item, +.quiqqer-tabsAdvanced-content-item { + margin: 0; + padding: 0; +} + +/* nav */ +.quiqqer-tabsAdvanced-nav-inner { + display: flex; + flex-wrap: nowrap; + /*width: max-content;*/ + /*margin-inline: auto;*/ +} + +.quiqqer-tabsAdvanced-nav-link { + padding: 1rem; + color: inherit; + display: flex; + align-items: center; + height: 100%; + gap: 1rem; +} + +.quiqqer-tabsAdvanced-nav-link img { + height: var(--quiqqer-tabsAdvanced-navImgHeight, 24px); + vertical-align: middle; + display: block; +} + +.active > .quiqqer-tabsAdvanced-nav-link { + color: var(--qui-color-primary); +} + +/* content */ +.quiqqer-tabsAdvanced-content { + margin-top: var(--qui-spacing-xl, 2rem); +} + +.quiqqer-tabsAdvanced-content-item { + display: grid; + gap: var(--qui-spacing-xl, 2rem); + width: 100%; + max-width: 100%; +} + +.quiqqer-tabsAdvanced-content-item:not(.no-image).left { + grid-template-areas: "image content"; + grid-template-columns: 1fr auto; +} + +.quiqqer-tabsAdvanced-content-item:not(.no-image).right { + grid-template-areas: "content image"; + grid-template-columns: auto 1fr; +} + +.quiqqer-tabsAdvanced-content-item:not(.no-image).top { + grid-template-areas: "image" "content"; + width: max-content; + margin-inline: auto; +} + +.quiqqer-tabsAdvanced-content-item:not(.no-image).bottom { + grid-template-areas: "content" "image"; + width: max-content; + margin-inline: auto; +} + +.quiqqer-tabsAdvanced-content-item.top { + width: max-content; + margin-inline: auto; +} + +.quiqqer-tabsAdvanced-content-item.bottom { + width: max-content; + margin-inline: auto; +} + +.quiqqer-tabsAdvanced-content-image { + grid-area: image; + display: flex; + align-items: center; + justify-content: center; +} + +.quiqqer-tabsAdvanced-content-image img { + max-width: var(--quiqqer-tabsAdvanced-contentImgMaxWidth, 100%); + max-height: var(--quiqqer-tabsAdvanced-contentImgMaxHeight, 100%); + width: auto; + height: auto; +} + +.quiqqer-tabsAdvanced-content-body { + grid-area: content; + max-width: var(--quiqqer-tabsAdvanced-contentTextWidth, 700px); +} + + +/* test */ +.quiqqer-tabsAdvanced-content{ + border: 2px solid; + border-radius: 1rem; +} +.quiqqer-tabsAdvanced-content-item { + padding: 2rem; +} + + + +.quiqqer-menu-navTabsVertical .quiqqer-menu-navTabsVertical-tabs-body { + margin-bottom: 2rem; +} + +.quiqqer-menu-navTabsVertical-container .quiqqer-menu-navTabsVertical-tabs-nav, +.quiqqer-menu-navTabsVertical-container .quiqqer-tab-content { + list-style: none; + margin-left: 0; + padding-left: 0; +} + +.quiqqer-menu-navTabsVertical-container .quiqqer-tab-nav-item, +.quiqqer-menu-navTabsVertical-container .quiqqer-tab-content-item { + margin-left: 0; + padding-left: 0; +} + +.quiqqer-menu-navTabsVertical-container .quiqqer-tab-nav-item a { + display: block; + margin-bottom: 0.5rem; + padding: 1rem; +} + +.quiqqer-menu-navTabsVertical-container .quiqqer-tab-nav-item:not(.active) a { + color: inherit; +} + +.quiqqer-menu-navTabsVertical-container .quiqqer-tab-nav-item.active a { + +} + +.quiqqer-menu-navTabsVertical-container .quiqqer-tab-nav-item .fa, +.quiqqer-menu-navTabsVertical-container .quiqqer-tab-nav-item img { + margin-right: 1rem; +} + +.quiqqer-menu-navTabsVertical-container .quiqqer-tab-nav-item img { + width: 2rem; + height: auto; + vertical-align: middle; +} + +.quiqqer-menu-navTabsVertical-content-image { + text-align: center; + margin-bottom: 1rem; +} + +@media screen and (max-width: 767px) { + .quiqqer-menu-navTabsVertical-container { + flex-wrap: wrap; + gap: 0; + } + + .quiqqer-menu-navTabsVertical-tabs, + .quiqqer-menu-navTabsVertical-content { + width: 100%; + } + + .quiqqer-menu-navTabsVertical .quiqqer-menu-navTabsVertical-tabs { + margin-bottom: 0; + } + + .quiqqer-menu-navTabsVertical-tabs-nav-container { + position: relative; + } + + .quiqqer-menu-navTabsVertical-tabs-nav-container:before, + .quiqqer-menu-navTabsVertical-tabs-nav-container:after { + content: ''; + height: 100%; + position: absolute; + top: 0; + width: 40px; + } + + .quiqqer-menu-navTabsVertical-tabs-nav-container:before { + background: linear-gradient(90deg, #fff, transparent); + left: 0; + } + + .quiqqer-menu-navTabsVertical-tabs-nav-container:after { + background: linear-gradient(90deg, transparent, #fff); + right: 0; + } + + .quiqqer-menu-navTabsVertical-container .quiqqer-menu-navTabsVertical-tabs-nav { + display: flex; + overflow: auto; + padding: 2rem 1rem; + white-space: nowrap; + } + + .quiqqer-menu-navTabsVertical-container .quiqqer-tab-nav-item { + margin-left: 0.5rem; + margin-right: 0.5rem; + flex-shrink: 0; + } +} \ No newline at end of file diff --git a/src/QUI/Menu/Controls/Tabs.html b/src/QUI/Menu/Controls/Tabs.html new file mode 100644 index 0000000000000000000000000000000000000000..a2d7f3e7d1e9be87a9ded02c2d68eab69a3b2ef9 --- /dev/null +++ b/src/QUI/Menu/Controls/Tabs.html @@ -0,0 +1,91 @@ +{if $this->getAttribute('showTitle') && $this->getAttribute('frontendTitle')} +<header class="control-header"> + <h1>{$this->getAttribute('frontendTitle')}</h1> +</header> +{/if} + +{if $this->getAttribute('content') != ""} +<div class="control-body default-content"> + {$this->getAttribute('content')} +</div> +{/if} + +<div class="control-template quiqqer-tabsAdvanced-control" style=" + --quiqqer-tabsAdvanced-navImgHeight: {$navImgHeight}px; + --quiqqer-tabsAdvanced-contentTextWidth: {$contentTextWidth}px; + --quiqqer-tabsAdvanced-contentImgMaxWidth: {$contentImgMaxWidth}px; + --quiqqer-tabsAdvanced-contentImgMaxHeight: {$contentImgMaxHeight}px; +"> + <div class="quiqqer-tabsAdvanced-nav"> + <ul class="quiqqer-tabsAdvanced-nav-inner quiqqer-tab-nav"> + {foreach from=$entries item=entry key=key} + <li class="quiqqer-tabsAdvanced-nav-item quiqqer-tab-nav-item {if $key == $active - 1}active{/if}" data-entry-nav-pos="{$key}"> + <a href="#{QUI\Utils\Security\Orthos::urlEncodeString($entry.tabTitle)}" + data-qui-disableTemplateScroll="1" + class="quiqqer-tabsAdvanced-nav-link"> + {if isset($entry.tabIcon) && $entry.tabIcon} + {image src=$entry.tabIcon width="80" height="80"} + {/if} + + <span class="quiqqer-tabsAdvanced-nav-linkLabel">{$entry.tabTitle}</span> + </a> + </li> + {/foreach} + </ul> + </div> + + <div class="quiqqer-tabsAdvanced-content quiqqer-tab-content"> + <ul class="quiqqer-tabsAdvanced-content-inner"> + {foreach from=$entries item=entry key=key} + {* image *} + {assign var=imgSrc value=false} + {if isset($entry.entryImage) && $entry.entryImage} + {assign var=imgSrc value=$entry.entryImage} + {/if} + + {* image position *} + {assign var=imgPos value=left} + {if isset($entry.entryImagePos) && $entry.entryImagePos} + {assign var=imgPos value=$entry.entryImagePos} + {/if} + + {* content *} + {assign var=content value=false} + {if (isset($entry.entryTitle) && $entry.entryTitle) || (isset($entry.entryContent) && $entry.entryContent)} + {assign var=content value=true} + {/if} + + <li class="quiqqer-tabsAdvanced-content-item quiqqer-tab-content-item {$imgPos} + {if !$imgSrc}no-image{/if} + {if !$content}no-content{/if} + {if $key == $active - 1}active{/if}" + {if $key !== $active - 1}style="display: none;"{/if} + data-entry-content-pos="{$key}" + id="{QUI\Utils\Security\Orthos::urlEncodeString($entry.tabTitle)}"> + + {if $imgSrc} + <div class="quiqqer-tabsAdvanced-content-image"> + {image src=$imgSrc width="600" height="600"} + </div> + {/if} + + {if $content} + <div class="quiqqer-tabsAdvanced-content-body"> + {if isset($entry.entryTitle) && $entry.entryTitle} + <h2 class="quiqqer-tabsAdvanced-content-title"> + {$entry.entryTitle} + </h2> + {/if} + + {if isset($entry.entryContent) && $entry.entryContent} + <div class="quiqqer-tabsAdvanced-content-text default-content"> + {$entry.entryContent} + </div> + {/if} + </div> + {/if} + </li> + {/foreach} + </ul> + </div> +</div> diff --git a/src/QUI/Menu/Controls/Tabs.php b/src/QUI/Menu/Controls/Tabs.php new file mode 100644 index 0000000000000000000000000000000000000000..9729ab0d50e64c70b79d54629a4643ec7278d25c --- /dev/null +++ b/src/QUI/Menu/Controls/Tabs.php @@ -0,0 +1,86 @@ +<?php + +/** + * This file contains QUI\Menu\Controls\Tabs + */ + +namespace QUI\Menu\Controls; + +use QUI; + +/** + * Class NavTabs + * + * @author Michael Danielczok + * @package QUI\Menu + */ +class Tabs extends QUI\Control +{ + /** + * constructor + * + * @param array $attributes + */ + public function __construct($attributes = []) + { + // default options + $this->setAttributes([ + 'class' => 'quiqqer-tabs', + 'qui-class' => 'package/quiqqer/menu/bin/Controls/NavTabs', + 'navImgHeight' => 24, + 'contentImgMaxWidth' => 300, + 'contentImgMaxHeight' => 500, + 'contentTextWidth' => 600, + 'activeEntry' => 2, // number + 'imageMaxHeight' => false, + 'entries' => [], + 'template' => 'simple', + ]); + + parent::__construct($attributes); + + $this->addCSSFile(dirname(__FILE__).'/Tabs.css'); + } + + /** + * (non-PHPdoc) + * + * @see \QUI\Control::create() + */ + public function getBody() + { + $Engine = QUI::getTemplateManager()->getEngine(); + $entries = $this->getAttribute('entries'); + $enabledEntries = []; + + if (is_string($entries)) { + $entries = json_decode($entries, true); + } + + foreach ($entries as $entry) { + if (isset($entry['isDisabled']) && $entry['isDisabled'] === 1) { + continue; + } + + array_push($enabledEntries, $entry); + } + + $active = 1; + + if ($this->getAttribute('activeEntry') && $this->getAttribute('activeEntry') > 0) { + $active = $this->getAttribute('activeEntry'); + } + + $Engine->assign([ + 'this' => $this, + 'entries' => $enabledEntries, + 'active' => $active, + 'navImgHeight' => $this->getAttribute('navImgHeight'), + 'contentTextWidth' => $this->getAttribute('contentTextWidth'), + 'contentImgMaxWidth' => $this->getAttribute('contentImgMaxWidth'), + 'contentImgMaxHeight' => $this->getAttribute('contentImgMaxHeight') + ]); + + return $Engine->fetch(dirname(__FILE__).'/Tabs.html'); + } +}