diff --git a/api/js/etemplate/Et2Link/Et2Link.ts b/api/js/etemplate/Et2Link/Et2Link.ts index e11ca1c34e..44a4c5c14e 100644 --- a/api/js/etemplate/Et2Link/Et2Link.ts +++ b/api/js/etemplate/Et2Link/Et2Link.ts @@ -11,7 +11,7 @@ import {ExposeMixin, ExposeValue} from "../Expose/ExposeMixin"; -import {css, html, LitElement} from "@lion/core"; +import {css, html, LitElement, TemplateResult} from "@lion/core"; import {Et2Widget} from "../Et2Widget/Et2Widget"; import {et2_IDetachedDOM} from "../et2_core_interfaces"; @@ -22,6 +22,7 @@ import {et2_IDetachedDOM} from "../et2_core_interfaces"; * You can set it directly in the properties (application, entryId) or use set_value() to * pass an object {app: string, id: string, [title: string]} or string in the form ::. * If title is not specified, it will be fetched using framework's egw.link_title() + * */ // @ts-ignore TypeScript says there's something wrong with types @@ -32,20 +33,37 @@ export class Et2Link extends ExposeMixin(Et2Widget(LitElement)) imple return [ ...super.styles, css` - :host { + :host { display: block; cursor: pointer; - } - :host:hover { + } + + .link { + display: flex; + gap: 0.5rem; + } + + .link__title { + flex: 2 1 50%; + } + + .link__remark { + flex: 1 1 50% + } + + :host:hover { text-decoration: underline - } - /** Style based on parent **/ - :host-context(et2-link-string) { + } + + /** Style based on parent **/ + + :host(et2-link-string) div { display: inline; - } - :host-context(et2-link-list):hover { + } + + :host-context(et2-link-list):hover { text-decoration: none; - } + } ` ]; } @@ -119,7 +137,7 @@ export class Et2Link extends ExposeMixin(Et2Widget(LitElement)) imple constructor() { super(); - this._title = ""; + this._title = Et2Link.MISSING_TITLE; this.__linkHook = "view"; } @@ -128,9 +146,34 @@ export class Et2Link extends ExposeMixin(Et2Widget(LitElement)) imple super.connectedCallback(); } - createRenderRoot() + /** + * Build a thumbnail for the link + * @param link + * @returns {TemplateResult} + * @protected + */ + protected _thumbnailTemplate(link : LinkInfo) : TemplateResult { - return this; + // If we have a mimetype, use a Et2VfsMime + // Files have path set in 'icon' property, and mime in 'type' + if(link.type && link.icon) + { + return html` + `; + } + return html` + `; } render() @@ -145,7 +188,12 @@ export class Et2Link extends ExposeMixin(Et2Widget(LitElement)) imple .replace(this.breakTitle, this.breakTitle.trimEnd() + "\u200B") .replace(/ /g, '\u00a0'); } - return html`${title}`; + return html` + `; } public set title(_title) @@ -200,7 +248,6 @@ export class Et2Link extends ExposeMixin(Et2Widget(LitElement)) imple { this.app = _value.app; this.entryId = _value.id; - this._title = Et2Link.MISSING_TITLE; if(_value.title) { @@ -216,6 +263,7 @@ export class Et2Link extends ExposeMixin(Et2Widget(LitElement)) imple this.dataset[key] = _value[key]; }) } + this.requestUpdate("value"); } diff --git a/api/js/etemplate/Et2Link/Et2LinkList.ts b/api/js/etemplate/Et2Link/Et2LinkList.ts index 7cd454c4cc..0d16d1a76a 100644 --- a/api/js/etemplate/Et2Link/Et2LinkList.ts +++ b/api/js/etemplate/Et2Link/Et2LinkList.ts @@ -45,47 +45,54 @@ export class Et2LinkList extends Et2LinkString return [ ...super.styles, css` - :host { - display:flex; + :host { + display: flex; flex-direction: column; column-gap: 10px; overflow: hidden; - } - div { + } + + div { display: flex; gap: 10px; - } - div:hover { + } + + div:hover { background-color: var(--highlight-background-color); - } - - div.zip_highlight { + } + + div.zip_highlight { animation-name: new_entry_pulse, new_entry_clear; animation-duration: 5s; animation-delay: 0s, 30s; animation-fill-mode: forwards; - } - - /* CSS for child elements */ - ::slotted(*):after { - /* Reset from Et2LinkString */ - content: initial; - } - ::slotted(et2-vfs-mime), ::slotted(et2-image-expose) { - width: 16px; - } - ::slotted(et2-link) { - flex: 1 1 auto; - } - ::slotted(.remark) { - flex: 1 1 auto; - width: 20%; - } - ::slotted(.delete_button) { - visibility: hidden; - width: 16px; - order: 5; - } + } + + /* CSS for child elements */ + + ::slotted(*):after { + /* Reset from Et2LinkString */ + content: initial; + } + + ::slotted(*)::part(icon) { + width: 1rem; + } + + ::slotted(et2-link) { + flex: 1 1 auto; + } + + ::slotted(.remark) { + flex: 1 1 auto; + width: 20%; + } + + ::slotted(.delete_button) { + visibility: hidden; + width: 16px; + order: 5; + } ` ]; } @@ -181,12 +188,9 @@ export class Et2LinkList extends Et2LinkString { const id = typeof link.id === "string" ? link.id : link.link_id; return html` - ${this._thumbnailTemplate(link)} - ${this._deleteButtonTemplate(link)} `; } @@ -329,31 +333,6 @@ export class Et2LinkList extends Et2LinkString } } - /** - * Build a thumbnail for the link - * @param link - * @returns {TemplateResult} - * @protected - */ - protected _thumbnailTemplate(link) : TemplateResult - { - // If we have a mimetype, use a Et2VfsMime - // Files have path set in 'icon' property, and mime in 'type' - if(link.type && link.icon) - { - return html` - `; - } - return html` - `; - } /** * Build the delete button @@ -658,7 +637,7 @@ export class Et2LinkList extends Et2LinkString protected _set_comment(link, comment) { - let remark = this.querySelector(".remark[slot='" + this._get_row_id(link) + "']"); + let remark = this.querySelector("et2-link[slot='" + this._get_row_id(link) + "']"); if(!remark) { console.warn("Could not find link to comment on", link); @@ -702,10 +681,10 @@ export class Et2LinkList extends Et2LinkString { // Append "" to make sure it's a string, not undefined remark.classList.remove("loading"); - // Update internal data & displayed comment - remark.value = link.remark = comment + ""; + // Update internal data + link.remark = comment + ""; // Update link widget - remark.parentElement.querySelector("et2-link").value = link; + remark.value = link; } }); } diff --git a/api/js/etemplate/Et2Link/Et2LinkString.ts b/api/js/etemplate/Et2Link/Et2LinkString.ts index e46039a1ff..ffdfaaf2ee 100644 --- a/api/js/etemplate/Et2Link/Et2LinkString.ts +++ b/api/js/etemplate/Et2Link/Et2LinkString.ts @@ -32,18 +32,30 @@ export class Et2LinkString extends Et2Widget(LitElement) implements et2_IDetache return [ ...super.styles, css` - :host { + :host { list-style-type: none; display: inline; padding: 0px; - } - /* CSS for child elements */ - ::slotted(*):after { - content: ", " - } - ::slotted(*:last-child):after { - content:initial; - } + } + + ::slotted(*) { + display: inline; + } + + ::slotted(*):hover { + text-decoration: underline; + } + + + /* CSS for child elements */ + + ::slotted(*):after { + content: ", " + } + + ::slotted(*:last-child):after { + content: initial; + } ` ]; } diff --git a/api/templates/default/etemplate2.css b/api/templates/default/etemplate2.css index 8a95e79b44..4ae4d8c0f9 100644 --- a/api/templates/default/etemplate2.css +++ b/api/templates/default/etemplate2.css @@ -1057,24 +1057,33 @@ div.et2_file input.et2_file_upload { * Autocomplete in dialogs - fix so they go over/out of the dialog */ .ui-dialog * ul.ui-autocomplete { - position: fixed; + position: fixed; } /** * Link wiget(s) */ +et2-link-string et2-link::part(base) { + display: inline; +} + +et2-link-string > et2-link::part(icon), et2-link-string > et2-link::part(remark) { + display: none; +} + + /* Link entry - x button*/ div.et2_link_entry { - width: 99%; - white-space: nowrap; + width: 99%; + white-space: nowrap; } div.et2_link_entry:after { - display: inline-block; - content: "."; - height: 0; - visibility: hidden; - margin: -20px; + display: inline-block; + content: "."; + height: 0; + visibility: hidden; + margin: -20px; } /* Special layout for inside nm grid */ @@ -1314,19 +1323,23 @@ ul.et2_link_string { } et2-link-list et2-link { - color: initial; - width: 30%; + color: initial; + width: 30%; } et2-link-list et2-link:hover { - text-decoration: initial; + text-decoration: initial; +} + +et2-link-list > et2-link::part(icon) { + width: 1rem; } .et2_link_list .icon img, .et2_vfs .icon img { - width: 16px; - height: 16px; - display: inline-block; + width: 16px; + height: 16px; + display: inline-block; } div.et2_vfsPath {