From 9acda4b390b912c364e466a58759bbdd11332e95 Mon Sep 17 00:00:00 2001 From: nathan Date: Mon, 12 Dec 2022 10:32:08 -0700 Subject: [PATCH] Link fixes - Fix file that was linked then removed before first save was still linked on save - Use events for better decoupling between Et2LinkTo & Et2LinkList --- api/js/etemplate/Et2Link/Et2LinkList.ts | 50 +++++++++++++++++++++++-- api/js/etemplate/Et2Link/Et2LinkTo.ts | 47 +++++++++++++++++------ 2 files changed, 82 insertions(+), 15 deletions(-) diff --git a/api/js/etemplate/Et2Link/Et2LinkList.ts b/api/js/etemplate/Et2Link/Et2LinkList.ts index bac932b1ba..371c811d02 100644 --- a/api/js/etemplate/Et2Link/Et2LinkList.ts +++ b/api/js/etemplate/Et2Link/Et2LinkList.ts @@ -111,12 +111,29 @@ export class Et2LinkList extends Et2LinkString this._handleRowHover = this._handleRowHover.bind(this); this._handleRowContext = this._handleRowContext.bind(this); + + this._handleChange = this._handleChange.bind(this); } connectedCallback() { super.connectedCallback(); this._createContextMenu(); + + // Look for LinkTo and listen for change so we can update + this.getInstanceManager().DOMContainer.querySelectorAll("et2-link-to").forEach(link => + { + link.addEventListener("et2-change", this._handleChange); + }) + } + + disconnectedCallback() + { + super.disconnectedCallback(); + this.getInstanceManager().DOMContainer.querySelectorAll("et2-link-to").forEach(link => + { + link.removeEventListener("et2-change", this._handleChange); + }) } protected _listTemplate() @@ -230,6 +247,20 @@ export class Et2LinkList extends Et2LinkString } } + /** + * We listen to LinkTo widgets so we can update + * + * @param _ev + * @protected + */ + protected _handleChange(_ev) + { + if(_ev && typeof _ev.currentTarget) + { + this.get_links(_ev.detail || []); + } + } + /** * Build a thumbnail for the link * @param link @@ -300,14 +331,25 @@ export class Et2LinkList extends Et2LinkString let link_element = this.querySelector("et2-link[slot='" + this._get_row_id(link) + "']"); link_element.classList.add("loading"); - this.dispatchEvent(new CustomEvent("before_delete", {detail: link})); + this.dispatchEvent(new CustomEvent("et2-before-delete", {detail: link})); - let removeLink = () => {this.querySelectorAll("[slot='" + this._get_row_id(link) + "']").forEach(e => e.remove());}; + let removeLink = () => + { + this.querySelectorAll("[slot='" + this._get_row_id(link) + "']").forEach(e => e.remove()); + if(this._link_list.indexOf(link) != -1) + { + this._link_list.splice(this._link_list.indexOf(link), 1); + } + this.dispatchEvent(new CustomEvent("et2-delete", {bubbles: true, detail: link})); + }; // Unsaved entry, had no ID yet - if(typeof this.entryId !== "string" && this.entryId[link.link_id]) + if(!this.entryId || typeof this.entryId !== "string" && this.entryId[link.link_id]) { - delete this.entryId[link.link_id]; + if(this.entryId) + { + delete this.entryId[link.link_id]; + } removeLink(); } else if(typeof this.entryId == "string" && link.link_id) diff --git a/api/js/etemplate/Et2Link/Et2LinkTo.ts b/api/js/etemplate/Et2Link/Et2LinkTo.ts index 3006d6d129..2a707403d9 100644 --- a/api/js/etemplate/Et2Link/Et2LinkTo.ts +++ b/api/js/etemplate/Et2Link/Et2LinkTo.ts @@ -21,8 +21,6 @@ import {Et2LinkEntry} from "./Et2LinkEntry"; import {egw} from "../../jsapi/egw_global"; import {et2_vfsSelect} from "../et2_widget_vfs"; import {LinkInfo} from "./Et2Link"; -import {Et2LinkList} from "./Et2LinkList"; -import {et2_DOMWidget} from "../et2_core_DOMWidget"; import {ValidationType} from "@lion/form-core/types/validate/ValidateMixinTypes"; import {ManualMessage} from "../Validators/ManualMessage"; @@ -109,6 +107,8 @@ export class Et2LinkTo extends Et2InputWidget(ScopedElementsMixin(FormControlMix this.handleEntrySelected = this.handleEntrySelected.bind(this); this.handleEntryCleared = this.handleEntryCleared.bind(this); this.handleLinkButtonClick = this.handleLinkButtonClick.bind(this); + + this.handleLinkDeleted = this.handleLinkDeleted.bind(this); } firstUpdated() @@ -118,6 +118,18 @@ export class Et2LinkTo extends Et2InputWidget(ScopedElementsMixin(FormControlMix this._fileButtons(); } + connectedCallback() + { + super.connectedCallback(); + this.getInstanceManager().DOMContainer.addEventListener("et2-delete", this.handleLinkDeleted); + } + + disconnectedCallback() + { + super.disconnectedCallback(); + this.getInstanceManager().DOMContainer.removeEventListener("et2-delete", this.handleLinkDeleted); + } + /** * @return {TemplateResult} * @protected @@ -308,15 +320,11 @@ export class Et2LinkTo extends Et2InputWidget(ScopedElementsMixin(FormControlMix } } - // Look for a link-list so we can refresh it - let list_widget = ((this.getParent()).getDOMNode().querySelector('et2-link-list')); - // If there's an array of data (entry is not yet saved), updating the list with only server info will - // not work, so add them in explicitly. - if(list_widget && success) - { - // Update link list, passing data if server provided it - list_widget.get_links(typeof success == "object" ? Object.values(success) : []); - } + // Send an event so listeners can update + this.dispatchEvent(new CustomEvent("et2-change", { + bubbles: true, + detail: typeof success == "object" ? Object.values(success) : [] + })); } else { @@ -422,6 +430,23 @@ export class Et2LinkTo extends Et2InputWidget(ScopedElementsMixin(FormControlMix this.createLink(link_info) } + /** + * Handle a link being removed + * + * Event is thrown every time a link is removed (from a LinkList) but we only care if the + * entry hasn't been saved yet and has no ID. In this case we've been keeping the list + * to submit and link server-side so we have to remove the deleted link from our list. + * + * @param {CustomEvent} e + */ + handleLinkDeleted(e : CustomEvent) + { + if(e && e.detail && this.value && typeof this.value.to_id == "object") + { + delete this.value.to_id[e.detail.link_id || ""] + } + } + get link_button() : Et2Button { return this.shadowRoot.querySelector("#link_button");