Reconfigure Link to include icon & comment for easier drag & drop

This commit is contained in:
nathan 2023-05-17 16:55:05 -06:00
parent e4bdbe256a
commit 8da10cf863
4 changed files with 153 additions and 101 deletions

View File

@ -11,7 +11,7 @@
import {ExposeMixin, ExposeValue} from "../Expose/ExposeMixin"; 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 {Et2Widget} from "../Et2Widget/Et2Widget";
import {et2_IDetachedDOM} from "../et2_core_interfaces"; 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 * 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 <application>::<ID>. * pass an object {app: string, id: string, [title: string]} or string in the form <application>::<ID>.
* If title is not specified, it will be fetched using framework's egw.link_title() * 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 // @ts-ignore TypeScript says there's something wrong with types
@ -32,20 +33,37 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
return [ return [
...super.styles, ...super.styles,
css` css`
:host { :host {
display: block; display: block;
cursor: pointer; 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 text-decoration: underline
} }
/** Style based on parent **/
:host-context(et2-link-string) { /** Style based on parent **/
:host(et2-link-string) div {
display: inline; display: inline;
} }
:host-context(et2-link-list):hover {
:host-context(et2-link-list):hover {
text-decoration: none; text-decoration: none;
} }
` `
]; ];
} }
@ -119,7 +137,7 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
constructor() constructor()
{ {
super(); super();
this._title = ""; this._title = Et2Link.MISSING_TITLE;
this.__linkHook = "view"; this.__linkHook = "view";
} }
@ -128,9 +146,34 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
super.connectedCallback(); 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`
<et2-vfs-mime part="icon" class="link__icon" ._parent=${this} .value=${Object.assign({
name: link.title,
mime: link.type,
path: link.icon
}, link)}
></et2-vfs-mime>`;
}
return html`
<et2-image-expose
part="icon"
class="link__icon"
._parent=${this}
href="${link.href}"
src=${this.egw().image("" + link.icon)}
></et2-image-expose>`;
} }
render() render()
@ -145,7 +188,12 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
.replace(this.breakTitle, this.breakTitle.trimEnd() + "\u200B") .replace(this.breakTitle, this.breakTitle.trimEnd() + "\u200B")
.replace(/ /g, '\u00a0'); .replace(/ /g, '\u00a0');
} }
return html`${title}`; return html`
<div part="base" class="link et2_link">
${this._thumbnailTemplate({id: this.entryId, app: this.app, ...this.dataset})}
<span part="title" class="link__title">${title}</span>
<span part="remark" class="link__remark">${this.dataset.remark}</span>
</div>`;
} }
public set title(_title) public set title(_title)
@ -200,7 +248,6 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
{ {
this.app = _value.app; this.app = _value.app;
this.entryId = _value.id; this.entryId = _value.id;
this._title = Et2Link.MISSING_TITLE;
if(_value.title) if(_value.title)
{ {
@ -216,6 +263,7 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
this.dataset[key] = _value[key]; this.dataset[key] = _value[key];
}) })
} }
this.requestUpdate("value");
} }

View File

@ -45,47 +45,54 @@ export class Et2LinkList extends Et2LinkString
return [ return [
...super.styles, ...super.styles,
css` css`
:host { :host {
display:flex; display: flex;
flex-direction: column; flex-direction: column;
column-gap: 10px; column-gap: 10px;
overflow: hidden; overflow: hidden;
} }
div {
div {
display: flex; display: flex;
gap: 10px; gap: 10px;
} }
div:hover {
background-color: var(--highlight-background-color);
}
div.zip_highlight { div:hover {
background-color: var(--highlight-background-color);
}
div.zip_highlight {
animation-name: new_entry_pulse, new_entry_clear; animation-name: new_entry_pulse, new_entry_clear;
animation-duration: 5s; animation-duration: 5s;
animation-delay: 0s, 30s; animation-delay: 0s, 30s;
animation-fill-mode: forwards; animation-fill-mode: forwards;
} }
/* CSS for child elements */ /* CSS for child elements */
::slotted(*):after {
/* Reset from Et2LinkString */ ::slotted(*):after {
content: initial; /* Reset from Et2LinkString */
} content: initial;
::slotted(et2-vfs-mime), ::slotted(et2-image-expose) { }
width: 16px;
} ::slotted(*)::part(icon) {
::slotted(et2-link) { width: 1rem;
flex: 1 1 auto; }
}
::slotted(.remark) { ::slotted(et2-link) {
flex: 1 1 auto; flex: 1 1 auto;
width: 20%; }
}
::slotted(.delete_button) { ::slotted(.remark) {
visibility: hidden; flex: 1 1 auto;
width: 16px; width: 20%;
order: 5; }
}
::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; const id = typeof link.id === "string" ? link.id : link.link_id;
return html` return html`
${this._thumbnailTemplate(link)}
<et2-link slot="${this._get_row_id(link)}" app="${link.app}" entryId="${id}" <et2-link slot="${this._get_row_id(link)}" app="${link.app}" entryId="${id}"
._parent=${this} ._parent=${this}
.value=${link}></et2-link> .value=${link}></et2-link>
<et2-description slot="${this._get_row_id(link)}" ._parent=${this} class="remark"
value="${link.remark}"></et2-description>
${this._deleteButtonTemplate(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`
<et2-vfs-mime slot="${this._get_row_id(link)}" ._parent=${this} .value=${Object.assign({
name: link.title,
mime: link.type,
path: link.icon
}, link)}></et2-vfs-mime>`;
}
return html`
<et2-image-expose
slot="${this._get_row_id(link)}" ._parent=${this}
href="${link.href}"
src=${this.egw().image("" + link.icon)}></et2-image-expose>`;
}
/** /**
* Build the delete button * Build the delete button
@ -658,7 +637,7 @@ export class Et2LinkList extends Et2LinkString
protected _set_comment(link, comment) 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) if(!remark)
{ {
console.warn("Could not find link to comment on", link); 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 // Append "" to make sure it's a string, not undefined
remark.classList.remove("loading"); remark.classList.remove("loading");
// Update internal data & displayed comment // Update internal data
remark.value = link.remark = comment + ""; link.remark = comment + "";
// Update link widget // Update link widget
remark.parentElement.querySelector("et2-link").value = link; remark.value = link;
} }
}); });
} }

View File

@ -32,18 +32,30 @@ export class Et2LinkString extends Et2Widget(LitElement) implements et2_IDetache
return [ return [
...super.styles, ...super.styles,
css` css`
:host { :host {
list-style-type: none; list-style-type: none;
display: inline; display: inline;
padding: 0px; padding: 0px;
} }
/* CSS for child elements */
::slotted(*):after { ::slotted(*) {
content: ", " display: inline;
} }
::slotted(*:last-child):after {
content:initial; ::slotted(*):hover {
} text-decoration: underline;
}
/* CSS for child elements */
::slotted(*):after {
content: ", "
}
::slotted(*:last-child):after {
content: initial;
}
` `
]; ];
} }

View File

@ -1057,24 +1057,33 @@ div.et2_file input.et2_file_upload {
* Autocomplete in dialogs - fix so they go over/out of the dialog * Autocomplete in dialogs - fix so they go over/out of the dialog
*/ */
.ui-dialog * ul.ui-autocomplete { .ui-dialog * ul.ui-autocomplete {
position: fixed; position: fixed;
} }
/** /**
* Link wiget(s) * 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*/ /* Link entry - x button*/
div.et2_link_entry { div.et2_link_entry {
width: 99%; width: 99%;
white-space: nowrap; white-space: nowrap;
} }
div.et2_link_entry:after { div.et2_link_entry:after {
display: inline-block; display: inline-block;
content: "."; content: ".";
height: 0; height: 0;
visibility: hidden; visibility: hidden;
margin: -20px; margin: -20px;
} }
/* Special layout for inside nm grid */ /* Special layout for inside nm grid */
@ -1314,19 +1323,23 @@ ul.et2_link_string {
} }
et2-link-list et2-link { et2-link-list et2-link {
color: initial; color: initial;
width: 30%; width: 30%;
} }
et2-link-list et2-link:hover { 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_link_list .icon img,
.et2_vfs .icon img { .et2_vfs .icon img {
width: 16px; width: 16px;
height: 16px; height: 16px;
display: inline-block; display: inline-block;
} }
div.et2_vfsPath { div.et2_vfsPath {