mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-22 06:30:59 +01:00
Add Et2TabsMobile that has special rendering for tabs on mobile
This commit is contained in:
parent
c466a4e9ab
commit
e532ca176b
@ -413,31 +413,6 @@ function send_template()
|
||||
|
||||
if ($template === 'mobile')
|
||||
{
|
||||
// replace tabs in mobile template with details widgets
|
||||
$str = preg_replace_callback('#^(\s+)<et2-tabbox\s*([^>]*)>\n\s*<tabs>\n(.*)\n\s*</tabs>\n\s*<tabpanels>\n(.*)\n\s*</tabpanels>\n\s*</et2-tabbox>#ms',
|
||||
static function($matches)
|
||||
{
|
||||
$indent = $matches[1];
|
||||
$tabbox_attrs = parseAttrs($matches[2]);
|
||||
unset($tabbox_attrs['align_tabs']);
|
||||
if (preg_match_all('#<tab\s(.*)/>#', $matches[3], $tabs) !==
|
||||
preg_match_all('#<template\s(.*)/>#', $matches[4], $panels))
|
||||
{
|
||||
throw Exception("Error parsing tabbox for mobile template into details");
|
||||
}
|
||||
$details = [];
|
||||
foreach($tabs[1] as $n => $tab)
|
||||
{
|
||||
$tab_attrs = parseAttrs($tab);
|
||||
$tab_attrs['id'] = $tab_attrs['id'] ?? $tabbox_attrs['id'].$n;
|
||||
$tab_attrs['summary'] = $tab_attrs['label'];
|
||||
$tab_attrs['title'] = $tab_attrs['statustext'];
|
||||
unset($tab_attrs['label'], $tab_attrs['statustext']);
|
||||
$details[] = $indent."\t".'<et2-details'.stringAttrs($tab_attrs).'>'."\n$indent\t\t".$panels[0][$n]."\n$indent\t</et2-details>";
|
||||
}
|
||||
unset($tabbox_attrs['id']);
|
||||
return $indent.'<vbox'.stringAttrs($tabbox_attrs).">\n".implode("\n", $details)."\n$indent</vbox>";
|
||||
}, $str);
|
||||
}
|
||||
|
||||
// ^^^^^^^^^^^^^^^^ above widgets get transformed independent of legacy="true" set in overlay ^^^^^^^^^^^^^^^^^^
|
||||
|
@ -1352,12 +1352,21 @@ export function loadWebComponent(_nodeName : string, _template_node : Element|{[
|
||||
}
|
||||
|
||||
// Try to find the class for the given node
|
||||
let mobile = (typeof egwIsMobile != "undefined" && egwIsMobile());
|
||||
if(mobile && typeof window.customElements.get(_nodeName + "_mobile") != "undefined")
|
||||
{
|
||||
_nodeName += "_mobile";
|
||||
}
|
||||
|
||||
let widget_class = window.customElements.get(_nodeName);
|
||||
if(!widget_class)
|
||||
{
|
||||
// Given node has no registered class. Try some of our special things (remove type, fallback to actual node)
|
||||
let tries = [_nodeName.split('-')[0]];
|
||||
if (_template_node.nodeName) tries = tries.concat(_template_node.nodeName.toLowerCase());
|
||||
if(_template_node.nodeName)
|
||||
{
|
||||
tries = tries.concat(_template_node.nodeName.toLowerCase());
|
||||
}
|
||||
for(let i = 0; i < tries.length && !window.customElements.get(_nodeName); i++)
|
||||
{
|
||||
_nodeName = tries[i];
|
||||
@ -1365,6 +1374,7 @@ export function loadWebComponent(_nodeName : string, _template_node : Element|{[
|
||||
widget_class = window.customElements.get(_nodeName);
|
||||
if(!widget_class)
|
||||
{
|
||||
debugger;
|
||||
throw Error("Unknown or unregistered WebComponent '" + _nodeName + "', could not find class. Also checked for " + tries.join(','));
|
||||
}
|
||||
}
|
||||
|
@ -315,10 +315,13 @@ export class Et2Tabs extends Et2InputWidget(SlTabGroup) implements et2_IResizeab
|
||||
if(changedProperties.has("tabHeight"))
|
||||
{
|
||||
const body = this.shadowRoot.querySelector(".tab-group__body");
|
||||
if(body)
|
||||
{
|
||||
body.style.setProperty("height", this.tabHeight == parseInt(this.tabHeight) + "" ? this.tabHeight + "px" : this.tabHeight);
|
||||
body.classList.toggle("tab-group__body-fixed-height", this.tabHeight !== '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the nodes for tabs
|
||||
|
108
api/js/etemplate/Layout/Et2Tabs/Et2TabsMobile.ts
Normal file
108
api/js/etemplate/Layout/Et2Tabs/Et2TabsMobile.ts
Normal file
@ -0,0 +1,108 @@
|
||||
import {Et2Tabs} from "./Et2Tabs";
|
||||
import {classMap, html, repeat, TemplateResult} from "@lion/core";
|
||||
import {et2_createWidget} from "../../et2_core_widget";
|
||||
import {et2_template} from "../../et2_widget_template";
|
||||
import {Et2Details} from "../Et2Details/Et2Details";
|
||||
import {SlTab, SlTabPanel} from "@shoelace-style/shoelace";
|
||||
|
||||
/**
|
||||
* Widget to render tabs in a mobile-friendly way
|
||||
*
|
||||
* We render tabs as a series of details instead of normal tabs.
|
||||
* loadWebComponent() will load this component instead of Et2Tabs on mobile browsers
|
||||
*/
|
||||
export class Et2TabsMobile extends Et2Tabs
|
||||
{
|
||||
connectedCallback()
|
||||
{
|
||||
super.connectedCallback();
|
||||
this.nav = this.shadowRoot.querySelector("et2-vbox");
|
||||
}
|
||||
|
||||
protected createTabs(tabData)
|
||||
{
|
||||
// "Tabs" are created in render()
|
||||
this.tabData = tabData;
|
||||
|
||||
// Create tab panels here though
|
||||
tabData.forEach((tab, index) =>
|
||||
{
|
||||
let panel = this.createPanel(tab, true);
|
||||
panel.slot = tab.id;
|
||||
});
|
||||
}
|
||||
|
||||
getAllTabs(includeDisabled = false)
|
||||
{
|
||||
const slot = <Et2Details[]><unknown>this.shadowRoot.querySelectorAll('et2-details');
|
||||
const tabNames = ["et2-details"];
|
||||
|
||||
// It's really not a list of SlTab...
|
||||
return <SlTab[]><unknown>[...slot].filter((el) =>
|
||||
{
|
||||
return includeDisabled ? tabNames.indexOf(el.tagName.toLowerCase()) != -1 : tabNames.indexOf(el.tagName.toLowerCase()) !== -1 && !el.disabled;
|
||||
});
|
||||
}
|
||||
|
||||
getAllPanels()
|
||||
{
|
||||
const slot = this.querySelector('slot')!;
|
||||
return <[SlTabPanel]><unknown>[...this.querySelectorAll('et2-tab-panel')]
|
||||
}
|
||||
|
||||
syncIndicator()
|
||||
{
|
||||
// Don't have an indicator to sync
|
||||
}
|
||||
|
||||
protected tabTemplate(tab, index : number) : TemplateResult
|
||||
{
|
||||
if(tab.XMLNode)
|
||||
{
|
||||
// Just read the XMLNode
|
||||
let tabContent = this.createElementFromNode(tab.XMLNode);
|
||||
tabContent.getDOMNode().slot = tab.id;
|
||||
}
|
||||
else
|
||||
{
|
||||
let template = <et2_template>et2_createWidget('template', tab.widget_options, this);
|
||||
template.getDOMNode().slot = tab.id;
|
||||
}
|
||||
return html`
|
||||
<et2-details
|
||||
id="${tab.id}"
|
||||
summary="${tab.label}"
|
||||
?open=${index == this._selectedIndex}
|
||||
?disabled=${tab.disabled}
|
||||
?hidden=${tab.hidden}
|
||||
|
||||
>
|
||||
<slot name="${tab.id}"/>
|
||||
</et2-details>`
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
return html`
|
||||
<et2-vbox
|
||||
part="base"
|
||||
class=${classMap({
|
||||
'tab-group': true,
|
||||
'tab-group-mobile': true,
|
||||
// Get styling as if it were top
|
||||
'tab-group--top': true
|
||||
})}
|
||||
@click=${this.handleClick}
|
||||
@keydown=${this.handleKeyDown}
|
||||
>
|
||||
${repeat(this.tabData, this.tabTemplate.bind(this))}
|
||||
<slot>
|
||||
</et2-vbox>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
if(typeof customElements.get("et2-tabbox_mobile") == "undefined")
|
||||
{
|
||||
customElements.define("et2-tabbox_mobile", Et2TabsMobile);
|
||||
}
|
@ -27,6 +27,7 @@ import './Layout/Et2Details/Et2Details';
|
||||
import './Layout/Et2Tabs/Et2Tab';
|
||||
import './Layout/Et2Tabs/Et2Tabs';
|
||||
import './Layout/Et2Tabs/Et2TabPanel';
|
||||
import './Layout/Et2Tabs/Et2TabsMobile';
|
||||
import './Et2Avatar/Et2Avatar';
|
||||
import './Et2Avatar/Et2AvatarGroup';
|
||||
import './Et2Button/Et2Button';
|
||||
|
@ -43,11 +43,14 @@
|
||||
</et2-hbox>
|
||||
</row>
|
||||
<row>
|
||||
<et2-vbox>
|
||||
<et2-details id="tab1" summary="Settings" title="">
|
||||
<et2-tabbox id="tabs">
|
||||
<tabs>
|
||||
<tab id="tab1" label="Settings"/>
|
||||
</tabs>
|
||||
<tabpanels>
|
||||
<template id="preferences.settings.tab1" content="tab1"/>
|
||||
</et2-details>
|
||||
</et2-vbox>
|
||||
</tabpanels>
|
||||
</et2-tabbox>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
|
Loading…
Reference in New Issue
Block a user