/**
* EGroupware eTemplate2 - Description WebComponent
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api
* @link https://www.egroupware.org
* @author Nathan Gray
*/
import {Et2Widget} from "../Et2Widget/Et2Widget";
import {css, html, LitElement, render} from "lit";
import {et2_IDetachedDOM} from "../et2_core_interfaces";
import {activateLinks} from "../ActivateLinksDirective";
import {et2_csvSplit} from "../et2_core_common";
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
export class Et2Description extends Et2Widget(LitElement) implements et2_IDetachedDOM
{
protected _value : string = "";
protected _forTarget : Et2InputWidget = null;
static get styles()
{
return [
...super.styles,
css`
* {
white-space: pre-wrap;
}
:host {
display:flex;
flex-direction: row;
justify-content: flex-start;
flex: 0 1 auto !important;
}
label {
padding-inline-end: 1ex;
}
.split-label label {
display: contents;
}
::slotted(a) {
cursor: pointer;
color: var(--sl-color-primary-700);
text-decoration: none;
display: inherit;
}`
];
}
static get properties()
{
return {
...super.properties,
/**
* Scan the value, and if there are any links (URL, mailto:) then wrap them in a clickable
* tag
*/
activateLinks: {
type: Boolean,
reflect: true
},
/**
* Extra link target
* Goes with href. If provided, that's the target for opening the link.
*/
extraLinkTarget: {
type: String,
reflect: true
},
/**
* widthxheight, if popup should be used, eg. 640x480
*/
extraLinkPopup: {
type: String,
reflect: true
},
/**
* Link URL
* If provided, will be clickable and open this URL
*/
href: {
type: String,
reflect: true
},
value: {
type: String,
noAccessor: true
},
for: { type: String}
}
}
constructor()
{
super();
// Initialize properties
this.activateLinks = false;
this.extraLinkPopup = "";
this.extraLinkTarget = "_browser";
// Don't initialize this to avoid href(unknown) when rendered
//this.href = "";
this.value = "";
this._handleClick = this._handleClick.bind(this);
}
connectedCallback()
{
super.connectedCallback();
if (this.for)
{
this._forTarget = this.getRoot().getWidgetById(this.for);
if (this._forTarget)
{
this._forTarget.ariaLabel = this.value;
}
}
// Put content directly in DOM
if(this.value)
{
render(this._renderContent(), this);
}
}
set_value(value)
{
this.value = value;
}
get value()
{
return this._value;
}
set value(_value : string)
{
let oldValue = this.value;
if(!_value)
{
_value = "";
}
// Do we do this here, or in transformAttributes()?
if(_value && !this.noLang)
{
_value = this.egw().lang(_value);
}
if(_value && (_value + "").indexOf('%s') != -1)
{
_value = _value.replace(/%s/g, _value);
}
this._value = _value;
this.requestUpdate('value', oldValue);
if (this._forTarget)
{
this._forTarget.ariaLabel = this._value;
}
}
updated(changedProperties)
{
super.updated(changedProperties);
// Due to how we do the rendering into the light DOM (not sure it's right) we need this after
// value change or it won't actually show up
if((changedProperties.has("value") || changedProperties.has("href") || changedProperties.has("activateLinks")) && this.parentNode)
{
render(this._renderContent(), this);
}
}
_renderContent()
{
let render = null;
// Add hover action button (Edit)
if(this.hover_action)
{
// TODO
}
// If there's a link, wrap that
if(this.href && this.value)
{
render = this.wrapLink(this.href, this.value);
}
// If we want to activate links inside, do that
else if(this.activateLinks && this.value)
{
render = this.getActivatedValue(this.value, this.href ? this.extraLinkTarget : '_blank');
}
// Just do the value
else
{
render = html`${this.value}`;
}
return render;
}
render()
{
let label = this.label;
let after;
if(label)
{
// Split the label at the "%s"
let parts = et2_csvSplit(label, 2, "%s");
if(parts.length > 1)
{
after = html``;
label = parts[0];
}
}
// Turn off IDE reformatting, or it will add an extra line break into the template
// @formatter:off
return html`${after}`;
// @formatter:on
}
async firstUpdated()
{
this.removeEventListener('click.extra_link', this._handleClick);
if(this.extraLinkPopup || this.mime)
{
// Add click listener
this.addEventListener('click.extra_link', this._handleClick);
}
}
_handleClick(_ev : MouseEvent) : boolean
{
// call super to get the onclick handling running
if (super._handleClick(_ev) && !_ev.defaultPrevented && this._forTarget?.focus)
{
this._forTarget.focus();
_ev.preventDefault();
return false;
}
if(this.mimeData || this.href)
{
egw(window).open_link(this.mimeData || this.href, this.extraLinkTarget, this.extraLinkPopup, null, null, this.mime);
_ev.preventDefault();
return false;
}
else if(_ev.target.nodeName !== "A")
{
// If it's not an activated link, just stop
_ev.preventDefault();
return false;
}
// Let links (present if activateLinks = true) do their thing normally
}
protected wrapLink(href, value)
{
if(href.indexOf('/') == -1 && href.split('.').length >= 3 &&
!(href.indexOf('mailto:') != -1 || href.indexOf('://') != -1 || href.indexOf('javascript:') != -1)
)
{
href = "/index.php?menuaction=" + href;
}
if(href.charAt(0) == '/') // link relative to eGW
{
href = egw.link(href);
}
return html`${value}`;
}
protected getActivatedValue(value, target)
{
return html`${activateLinks(value, target)}`;
}
getDetachedAttributes(attrs)
{
attrs.push("id", "label", "value", "class", "href", "statustext");
}
getDetachedNodes() : HTMLElement[]
{
return [this];
}
setDetachedAttributes(_nodes : HTMLElement[], _values : object, _data? : any) : void
{
for(let attr in _values)
{
this[attr] = _values[attr];
}
}
loadFromXML()
{
// nope
}
}
// @ts-ignore TypeScript is not recognizing that this widget is a LitElement
customElements.define("et2-description", Et2Description);
export class Et2Label extends Et2Description {}
// @ts-ignore TypeScript is not recognizing that this widget is a LitElement
customElements.define("et2-label", Et2Label);