mirror of
https://github.com/EGroupware/egroupware.git
synced 2025-06-25 12:21:26 +02:00
Home: Fix portlet broken by Shoelace update to 1.8
They made HasSlotController internal only
This commit is contained in:
parent
8814f55ff3
commit
a9fcf05fab
@ -17,7 +17,7 @@ import type {InteractEvent} from "@interactjs/core/InteractEvent";
|
|||||||
import {egw} from "../../jsapi/egw_global";
|
import {egw} from "../../jsapi/egw_global";
|
||||||
import {css, html, TemplateResult} from "lit";
|
import {css, html, TemplateResult} from "lit";
|
||||||
import {classMap} from "lit/directives/class-map.js";
|
import {classMap} from "lit/directives/class-map.js";
|
||||||
import type {HasSlotController} from "../../../../node_modules/@shoelace-style/shoelace/dist/internal/slot";
|
import {HasSlotController} from "../Et2Widget/slot";
|
||||||
import shoelace from "../Styles/shoelace";
|
import shoelace from "../Styles/shoelace";
|
||||||
import {Et2Dialog} from "../Et2Dialog/Et2Dialog";
|
import {Et2Dialog} from "../Et2Dialog/Et2Dialog";
|
||||||
import {et2_IResizeable} from "../et2_core_interfaces";
|
import {et2_IResizeable} from "../et2_core_interfaces";
|
||||||
@ -81,8 +81,7 @@ export class Et2Portlet extends Et2Widget(SlCard)
|
|||||||
font-size: var(--sl-font-size-medium);
|
font-size: var(--sl-font-size-medium);
|
||||||
line-height: var(--sl-line-height-dense);
|
line-height: var(--sl-line-height-dense);
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
padding-left: var(--header-spacing);
|
padding-left: 0px;
|
||||||
padding-right: calc(2em + var(--header-spacing));
|
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
@ -111,8 +110,12 @@ export class Et2Portlet extends Et2Widget(SlCard)
|
|||||||
height: 100%
|
height: 100%
|
||||||
}
|
}
|
||||||
|
|
||||||
.card_header {
|
.card__header {
|
||||||
margin-right: calc(var(--sl-spacing-medium) + 1em);
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0px;
|
||||||
|
padding-left: var(--sl-spacing-medium);
|
||||||
|
padding-right: calc(2em + var(--header-spacing));
|
||||||
}
|
}
|
||||||
|
|
||||||
.card__body {
|
.card__body {
|
||||||
|
129
api/js/etemplate/Et2Widget/slot.ts
Normal file
129
api/js/etemplate/Et2Widget/slot.ts
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
import type {ReactiveController, ReactiveControllerHost} from 'lit';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reactive controller that determines when slots exist.
|
||||||
|
*
|
||||||
|
* Copied from Shoelace
|
||||||
|
* /src/internal/slot.ts
|
||||||
|
*/
|
||||||
|
export class HasSlotController implements ReactiveController
|
||||||
|
{
|
||||||
|
host : ReactiveControllerHost & Element;
|
||||||
|
slotNames : string[] = [];
|
||||||
|
|
||||||
|
constructor(host : ReactiveControllerHost & Element, ...slotNames : string[])
|
||||||
|
{
|
||||||
|
(this.host = host).addController(this);
|
||||||
|
this.slotNames = slotNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
private hasDefaultSlot()
|
||||||
|
{
|
||||||
|
return [...this.host.childNodes].some(node =>
|
||||||
|
{
|
||||||
|
if(node.nodeType === node.TEXT_NODE && node.textContent!.trim() !== '')
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node.nodeType === node.ELEMENT_NODE)
|
||||||
|
{
|
||||||
|
const el = node as HTMLElement;
|
||||||
|
const tagName = el.tagName.toLowerCase();
|
||||||
|
|
||||||
|
// Ignore visually hidden elements since they aren't rendered
|
||||||
|
if(tagName === 'sl-visually-hidden')
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it doesn't have a slot attribute, it's part of the default slot
|
||||||
|
if(!el.hasAttribute('slot'))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private hasNamedSlot(name : string)
|
||||||
|
{
|
||||||
|
return this.host.querySelector(`:scope > [slot="${name}"]`) !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
test(slotName : string)
|
||||||
|
{
|
||||||
|
return slotName === '[default]' ? this.hasDefaultSlot() : this.hasNamedSlot(slotName);
|
||||||
|
}
|
||||||
|
|
||||||
|
hostConnected()
|
||||||
|
{
|
||||||
|
this.host.shadowRoot!.addEventListener('slotchange', this.handleSlotChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
hostDisconnected()
|
||||||
|
{
|
||||||
|
this.host.shadowRoot!.removeEventListener('slotchange', this.handleSlotChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleSlotChange = (event : Event) =>
|
||||||
|
{
|
||||||
|
const slot = event.target as HTMLSlotElement;
|
||||||
|
|
||||||
|
if((this.slotNames.includes('[default]') && !slot.name) || (slot.name && this.slotNames.includes(slot.name)))
|
||||||
|
{
|
||||||
|
this.host.requestUpdate();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a slot, this function iterates over all of its assigned element and text nodes and returns the concatenated
|
||||||
|
* HTML as a string. This is useful because we can't use slot.innerHTML as an alternative.
|
||||||
|
*/
|
||||||
|
export function getInnerHTML(slot : HTMLSlotElement) : string
|
||||||
|
{
|
||||||
|
const nodes = slot.assignedNodes({flatten: true});
|
||||||
|
let html = '';
|
||||||
|
|
||||||
|
[...nodes].forEach(node =>
|
||||||
|
{
|
||||||
|
if(node.nodeType === Node.ELEMENT_NODE)
|
||||||
|
{
|
||||||
|
html += (node as HTMLElement).outerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node.nodeType === Node.TEXT_NODE)
|
||||||
|
{
|
||||||
|
html += node.textContent;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a slot, this function iterates over all of its assigned text nodes and returns the concatenated text as a
|
||||||
|
* string. This is useful because we can't use slot.textContent as an alternative.
|
||||||
|
*/
|
||||||
|
export function getTextContent(slot : HTMLSlotElement | undefined | null) : string
|
||||||
|
{
|
||||||
|
if(!slot)
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const nodes = slot.assignedNodes({flatten: true});
|
||||||
|
let text = '';
|
||||||
|
|
||||||
|
[...nodes].forEach(node =>
|
||||||
|
{
|
||||||
|
if(node.nodeType === Node.TEXT_NODE)
|
||||||
|
{
|
||||||
|
text += node.textContent;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user