mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-22 14:41:29 +01:00
WIP on Et2LinkList, should be working now
This commit is contained in:
parent
b735b0f218
commit
875a3996aa
@ -59,6 +59,13 @@ export class Et2LinkList extends Et2LinkString
|
|||||||
background-color: var(--highlight-background-color);
|
background-color: var(--highlight-background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 */
|
/* CSS for child elements */
|
||||||
::slotted(*):after {
|
::slotted(*):after {
|
||||||
/* Reset from Et2LinkString */
|
/* Reset from Et2LinkString */
|
||||||
@ -70,9 +77,14 @@ export class Et2LinkList extends Et2LinkString
|
|||||||
::slotted(et2-link) {
|
::slotted(et2-link) {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
::slotted(.remark) {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
width: 20%;
|
||||||
|
}
|
||||||
::slotted(.delete_button) {
|
::slotted(.delete_button) {
|
||||||
display: none;
|
visibility: hidden;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
|
order: 5;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
];
|
];
|
||||||
@ -99,8 +111,6 @@ export class Et2LinkList extends Et2LinkString
|
|||||||
|
|
||||||
this._handleRowHover = this._handleRowHover.bind(this);
|
this._handleRowHover = this._handleRowHover.bind(this);
|
||||||
this._handleRowContext = this._handleRowContext.bind(this);
|
this._handleRowContext = this._handleRowContext.bind(this);
|
||||||
this.addEventListener("mouseover", this._handleRowHover);
|
|
||||||
this.addEventListener("mouseout", this._handleRowHover);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback()
|
connectedCallback()
|
||||||
@ -128,13 +138,13 @@ export class Et2LinkList extends Et2LinkString
|
|||||||
protected _addLinks(links : LinkInfo[])
|
protected _addLinks(links : LinkInfo[])
|
||||||
{
|
{
|
||||||
this._link_list = links;
|
this._link_list = links;
|
||||||
super._addLinks(links);
|
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
|
this.updateComplete.then(() => super._addLinks(links));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render one link
|
* Render one link
|
||||||
|
* These elements are slotted and are found in the light DOM (use this.querySelector(...) to find them)
|
||||||
*
|
*
|
||||||
* @param link
|
* @param link
|
||||||
* @returns {TemplateResult}
|
* @returns {TemplateResult}
|
||||||
@ -145,14 +155,18 @@ export class Et2LinkList extends Et2LinkString
|
|||||||
return html`
|
return html`
|
||||||
${this._thumbnailTemplate(link)}
|
${this._thumbnailTemplate(link)}
|
||||||
<et2-link slot="${this._get_row_id(link)}" app="${link.app}" entry_id="${link.id}"
|
<et2-link slot="${this._get_row_id(link)}" app="${link.app}" entry_id="${link.id}"
|
||||||
@contextmenu=${this._handleRowContext}
|
._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)}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render one link
|
* Render the row for one link.
|
||||||
|
* This is just the structure and slot, actual row contents are done in _linkTemplate.
|
||||||
|
* These rows are found in the shadowRoot. Use this.shadowRoot.querySelector(...) to find them.
|
||||||
*
|
*
|
||||||
* @param link
|
* @param link
|
||||||
* @returns {TemplateResult}
|
* @returns {TemplateResult}
|
||||||
@ -160,13 +174,11 @@ export class Et2LinkList extends Et2LinkString
|
|||||||
*/
|
*/
|
||||||
protected _rowTemplate(link) : TemplateResult
|
protected _rowTemplate(link) : TemplateResult
|
||||||
{
|
{
|
||||||
let hover = () =>
|
|
||||||
{
|
|
||||||
console.log(link);
|
|
||||||
debugger;
|
|
||||||
}
|
|
||||||
return html`
|
return html`
|
||||||
<div id="${this._get_row_id(link)}">
|
<div id="${this._get_row_id(link)}"
|
||||||
|
@mouseover=${this._handleRowHover}
|
||||||
|
@mouseout=${this._handleRowHover}
|
||||||
|
@contextmenu=${this._handleRowContext}>
|
||||||
<slot name="${this._get_row_id(link)}"></slot>
|
<slot name="${this._get_row_id(link)}"></slot>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
@ -178,19 +190,38 @@ export class Et2LinkList extends Et2LinkString
|
|||||||
*/
|
*/
|
||||||
protected _handleRowHover(_ev)
|
protected _handleRowHover(_ev)
|
||||||
{
|
{
|
||||||
// Ignore delete button
|
let slot_name = "";
|
||||||
if(_ev.relatedTarget.classList.contains("delete_button") || _ev.relatedTarget.parentElement.classList.contains("delete_button"))
|
let target = _ev.target;
|
||||||
|
|
||||||
|
// Fist check if target is the row div
|
||||||
|
if(target.firstElementChild?.localName == "slot")
|
||||||
|
{
|
||||||
|
slot_name = target.firstElementChild.name;
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Look up tree for the slot
|
||||||
|
if(target.slot)
|
||||||
|
{
|
||||||
|
slot_name = target.slot;
|
||||||
|
}
|
||||||
|
target = target.parentNode;
|
||||||
|
}
|
||||||
|
while(!slot_name && target.parentNode)
|
||||||
|
if(!slot_name)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_ev.type == "mouseout")
|
if(_ev.type == "mouseout")
|
||||||
{
|
{
|
||||||
this.querySelectorAll(".delete_button").forEach(b => b.style.display = "");
|
this.querySelectorAll(".delete_button").forEach(b => b.style.visibility = "");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_ev.type == "mouseover" && _ev.target.parentNode == this)
|
|
||||||
|
if(_ev.type == "mouseover")
|
||||||
{
|
{
|
||||||
_ev.target.parentNode.querySelector(".delete_button[slot='" + _ev.target.slot + "']").style.display = "initial";
|
this.querySelector(".delete_button[slot='" + slot_name + "']").style.visibility = "initial";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,7 +282,7 @@ export class Et2LinkList extends Et2LinkString
|
|||||||
*/
|
*/
|
||||||
protected _get_row_id(link : any) : string
|
protected _get_row_id(link : any) : string
|
||||||
{
|
{
|
||||||
return "link_" + (link.dom_id ? link.dom_id : (typeof link.link_id == "string" ? link.link_id.replace(/[:\.]/g, '_') : link.link_id || link.id));
|
return "link_" + (link.dom_id ? link.dom_id : (typeof link.link_id == "string" ? link.link_id.replace(/[:.]/g, '_') : link.link_id || link.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -343,10 +374,8 @@ export class Et2LinkList extends Et2LinkString
|
|||||||
this.context = new egwMenu();
|
this.context = new egwMenu();
|
||||||
this.context.addItem("comment", this.egw().lang("Comment"), "", () =>
|
this.context.addItem("comment", this.egw().lang("Comment"), "", () =>
|
||||||
{
|
{
|
||||||
let link_id = typeof this.context.data.link_id == 'number' ? this.context.data.link_id : this.context.data.link_id.replace(/[:\.]/g, '_');
|
|
||||||
|
|
||||||
Et2Dialog.show_prompt(
|
Et2Dialog.show_prompt(
|
||||||
function(button, comment)
|
(button, comment) =>
|
||||||
{
|
{
|
||||||
if(button != Et2Dialog.OK_BUTTON)
|
if(button != Et2Dialog.OK_BUTTON)
|
||||||
{
|
{
|
||||||
@ -358,9 +387,9 @@ export class Et2LinkList extends Et2LinkString
|
|||||||
);
|
);
|
||||||
|
|
||||||
});
|
});
|
||||||
this.context.addItem("file_info", this.egw().lang("File information"), this.egw().image("edit"), (menu_item) =>
|
this.context.addItem("file_info", this.egw().lang("File information"), this.egw().image("edit"), () =>
|
||||||
{
|
{
|
||||||
var link_data = this.context.data;
|
let link_data = this.context.data;
|
||||||
if(link_data.app == 'file')
|
if(link_data.app == 'file')
|
||||||
{
|
{
|
||||||
// File info is always the same
|
// File info is always the same
|
||||||
@ -374,9 +403,9 @@ export class Et2LinkList extends Et2LinkString
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.context.addItem("-", "-");
|
this.context.addItem("-", "-");
|
||||||
this.context.addItem("save", this.egw().lang("Save as"), this.egw().image('save'), (menu_item) =>
|
this.context.addItem("save", this.egw().lang("Save as"), this.egw().image('save'), () =>
|
||||||
{
|
{
|
||||||
var link_data = this.context.data;
|
let link_data = this.context.data;
|
||||||
// Download file
|
// Download file
|
||||||
if(link_data.download_url)
|
if(link_data.download_url)
|
||||||
{
|
{
|
||||||
@ -394,12 +423,11 @@ export class Et2LinkList extends Et2LinkString
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Multiple file download for those that support it
|
// Multiple file download for those that support it
|
||||||
a = jQuery(a)
|
a.setAttribute("href",url);
|
||||||
.prop('href', url)
|
a.setAttribute("download",link_data.title || "");
|
||||||
.prop('download', link_data.title || "")
|
this.getInstanceManager().DOMContainer.appendChild(a);
|
||||||
.appendTo(this.getInstanceManager().DOMContainer);
|
|
||||||
|
|
||||||
var evt = document.createEvent('MouseEvent');
|
let evt = document.createEvent('MouseEvent');
|
||||||
evt.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
|
evt.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
|
||||||
a[0].dispatchEvent(evt);
|
a[0].dispatchEvent(evt);
|
||||||
a.remove();
|
a.remove();
|
||||||
@ -408,30 +436,30 @@ export class Et2LinkList extends Et2LinkString
|
|||||||
|
|
||||||
this.egw().open(link_data, "", "view", 'download', link_data.target ? link_data.target : link_data.app, link_data.app);
|
this.egw().open(link_data, "", "view", 'download', link_data.target ? link_data.target : link_data.app, link_data.app);
|
||||||
});
|
});
|
||||||
this.context.addItem("zip", this.egw().lang("Save as Zip"), this.egw().image('save_zip'), (menu_item) =>
|
this.context.addItem("zip", this.egw().lang("Save as Zip"), this.egw().image('save_zip'), () =>
|
||||||
{
|
{
|
||||||
// Highlight files for nice UI indicating what will be in the zip.
|
// Highlight files for nice UI indicating what will be in the zip.
|
||||||
// Files have negative IDs.
|
// Files have negative IDs.
|
||||||
jQuery('[id^="link_-"]', this.list).effect('highlight', {}, 2000);
|
this.shadowRoot.querySelectorAll('div[id^="link_-"]').forEach((row) => row.classList.add("zip_highlight"));
|
||||||
|
|
||||||
// Download ZIP
|
// Download ZIP
|
||||||
window.location = this.egw().link('/index.php', {
|
window.location.href = this.egw().link('/index.php', {
|
||||||
menuaction: 'api.EGroupware\\Api\\Etemplate\\Widget\\Link.download_zip',
|
menuaction: 'api.EGroupware\\Api\\Etemplate\\Widget\\Link.download_zip',
|
||||||
app: this.to_app,
|
app: this.application,
|
||||||
id: this.to_id
|
id: this.entry_id
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Only allow this option if the entry has been saved, and has a real ID
|
// Only allow this option if the entry has been saved, and has a real ID
|
||||||
if(this.to_id && typeof this.to_id != 'object')
|
if(this.to_id && typeof this.to_id != 'object')
|
||||||
{
|
{
|
||||||
this.context.addItem("copy_to", this.egw().lang("Copy to"), this.egw().image('copy'), (menu_item) =>
|
this.context.addItem("copy_to", this.egw().lang("Copy to"), this.egw().image('copy'), () =>
|
||||||
{
|
{
|
||||||
// Highlight files for nice UI indicating what will be copied
|
// Highlight files for nice UI indicating what will be copied
|
||||||
jQuery('[id="link_' + this.context.data.link_id + ']', this.list).effect('highlight', {}, 2000);
|
this.shadowRoot.querySelectorAll('div[id^="link_-"]').forEach((row) => row.classList.add("zip_highlight"));
|
||||||
|
|
||||||
// Get target
|
// Get target
|
||||||
var select_attrs : any = {
|
let select_attrs : any = {
|
||||||
mode: "select-dir",
|
mode: "select-dir",
|
||||||
button_caption: '',
|
button_caption: '',
|
||||||
button_icon: 'copy',
|
button_icon: 'copy',
|
||||||
@ -449,16 +477,14 @@ export class Et2LinkList extends Et2LinkString
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.context.addItem("-", "-");
|
this.context.addItem("-", "-");
|
||||||
this.context.addItem("delete", this.egw().lang("Delete link"), this.egw().image("delete"), (menu_item) =>
|
this.context.addItem("delete", this.egw().lang("Delete link"), this.egw().image("delete"), () =>
|
||||||
{
|
{
|
||||||
var link_id = isNaN(this.context.data.link_id) ? this.context.data : this.context.data.link_id;
|
|
||||||
var row = jQuery('#link_' + (this.context.data.dom_id ? this.context.data.dom_id : this.context.data.link_id), this);
|
|
||||||
Et2Dialog.show_dialog(
|
Et2Dialog.show_dialog(
|
||||||
function(button)
|
(button) =>
|
||||||
{
|
{
|
||||||
if(button == Et2Dialog.YES_BUTTON)
|
if(button == Et2Dialog.YES_BUTTON)
|
||||||
{
|
{
|
||||||
this._delete_link(link_id, row);
|
this._delete_link(this.context.data);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
egw.lang('Delete link?')
|
egw.lang('Delete link?')
|
||||||
@ -469,7 +495,15 @@ export class Et2LinkList extends Et2LinkString
|
|||||||
|
|
||||||
protected _handleRowContext(_ev)
|
protected _handleRowContext(_ev)
|
||||||
{
|
{
|
||||||
let _link_data = Object.assign({app: _ev.target.app, id: _ev.target.id}, _ev.target.dataset);
|
// Do not trigger expose view if one of the operator keys are held
|
||||||
|
if(_ev.altKey || _ev.ctrlKey || _ev.shiftKey || _ev.metaKey)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Find the link
|
||||||
|
let link = this.querySelector("et2-link[slot='" + _ev.currentTarget.id + "']");
|
||||||
|
|
||||||
|
let _link_data = Object.assign({app: link.app, id: link.entry_id}, link.dataset);
|
||||||
// Comment only available if link_id is there and not readonly
|
// Comment only available if link_id is there and not readonly
|
||||||
this.context.getItem("comment").set_enabled(typeof _link_data.link_id != 'undefined' && !this.readonly);
|
this.context.getItem("comment").set_enabled(typeof _link_data.link_id != 'undefined' && !this.readonly);
|
||||||
// File info only available for existing files
|
// File info only available for existing files
|
||||||
@ -488,7 +522,12 @@ export class Et2LinkList extends Et2LinkString
|
|||||||
|
|
||||||
protected _set_comment(link, comment)
|
protected _set_comment(link, comment)
|
||||||
{
|
{
|
||||||
let remark = this.querySelector(".comment[slot='" + this._get_row_id(link) + "']");
|
let remark = this.querySelector(".remark[slot='" + this._get_row_id(link) + "']");
|
||||||
|
if(!remark)
|
||||||
|
{
|
||||||
|
console.warn("Could not find link to comment on", link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
/* // TODO
|
/* // TODO
|
||||||
if(isNaN(link.link_id)) // new entry, not yet stored
|
if(isNaN(link.link_id)) // new entry, not yet stored
|
||||||
{
|
{
|
||||||
@ -518,7 +557,7 @@ export class Et2LinkList extends Et2LinkString
|
|||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
remark.addClass("loading");
|
remark.classList.add("loading");
|
||||||
egw.json("EGroupware\\Api\\Etemplate\\Widget\\Link::ajax_link_comment",
|
egw.json("EGroupware\\Api\\Etemplate\\Widget\\Link::ajax_link_comment",
|
||||||
[link.link_id, comment]).sendRequest()
|
[link.link_id, comment]).sendRequest()
|
||||||
.then(() =>
|
.then(() =>
|
||||||
@ -526,9 +565,10 @@ export class Et2LinkList extends Et2LinkString
|
|||||||
if(remark)
|
if(remark)
|
||||||
{
|
{
|
||||||
// Append "" to make sure it's a string, not undefined
|
// Append "" to make sure it's a string, not undefined
|
||||||
remark.removeClass("loading").text(comment + "");
|
remark.classList.remove("loading");
|
||||||
// Update internal data
|
// Update internal data
|
||||||
remark.textContent = comment + "";
|
link.comment = comment + "";
|
||||||
|
remark.value = link.comment;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import {css, html, LitElement, render, repeat, TemplateResult, until} from "@lion/core";
|
import {css, html, LitElement, render, TemplateResult, until} from "@lion/core";
|
||||||
import {Et2Widget} from "../Et2Widget/Et2Widget";
|
import {Et2Widget} from "../Et2Widget/Et2Widget";
|
||||||
import {Et2Link, LinkInfo} from "./Et2Link";
|
import {Et2Link, LinkInfo} from "./Et2Link";
|
||||||
import {et2_IDetachedDOM} from "../et2_core_interfaces";
|
import {et2_IDetachedDOM} from "../et2_core_interfaces";
|
||||||
@ -127,7 +127,7 @@ export class Et2LinkString extends Et2Widget(LitElement) implements et2_IDetache
|
|||||||
{
|
{
|
||||||
this.application = _value.to_app;
|
this.application = _value.to_app;
|
||||||
this.entry_id = _value.to_id;
|
this.entry_id = _value.to_id;
|
||||||
this._get_links();
|
this.get_links();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(typeof _value === "string")
|
if(typeof _value === "string")
|
||||||
@ -195,18 +195,40 @@ export class Et2LinkString extends Et2Widget(LitElement) implements et2_IDetache
|
|||||||
*/
|
*/
|
||||||
protected _addLinks(links : LinkInfo[])
|
protected _addLinks(links : LinkInfo[])
|
||||||
{
|
{
|
||||||
|
// Remove anything there right now
|
||||||
|
while(this.lastChild)
|
||||||
|
{
|
||||||
|
this.removeChild(this.lastChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
links.forEach((link) =>
|
||||||
|
{
|
||||||
|
let temp = document.createElement("div");
|
||||||
|
render(this._linkTemplate(link), temp);
|
||||||
|
temp.childNodes.forEach((node) => this.appendChild(node));
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
This should work, and it does, but only once.
|
||||||
|
It fails if you try and update then run it again - none of the children get added
|
||||||
|
Something about how lit renders
|
||||||
render(html`${repeat(links,
|
render(html`${repeat(links,
|
||||||
(link) => link.app + ":" + link.id,
|
(link) => link.app + ":" + link.id,
|
||||||
(link) => this._linkTemplate(link))}`,
|
(link) => this._linkTemplate(link))}`,
|
||||||
<HTMLElement><unknown>this
|
<HTMLElement><unknown>this
|
||||||
);
|
);
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the request for link list to the server
|
* Starts the request for link list to the server
|
||||||
|
*
|
||||||
|
* Called internally to fetch the list. May be called externally to trigger a refresh if a link is added.
|
||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
protected _get_links()
|
public get_links()
|
||||||
{
|
{
|
||||||
let _value = {
|
let _value = {
|
||||||
to_app: this.application,
|
to_app: this.application,
|
||||||
|
@ -36,6 +36,8 @@ import {et2_IDetachedDOM, et2_IExposable} from "./et2_core_interfaces";
|
|||||||
import {expose} from "./expose";
|
import {expose} from "./expose";
|
||||||
import {egwMenu} from "../egw_action/egw_menu.js";
|
import {egwMenu} from "../egw_action/egw_menu.js";
|
||||||
import {Et2Dialog} from "./Et2Dialog/Et2Dialog";
|
import {Et2Dialog} from "./Et2Dialog/Et2Dialog";
|
||||||
|
import {et2_DOMWidget} from "./et2_core_DOMWidget";
|
||||||
|
import {Et2LinkList} from "./Et2Link/Et2LinkList";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UI widgets for Egroupware linking system
|
* UI widgets for Egroupware linking system
|
||||||
@ -444,6 +446,8 @@ export class et2_link_to extends et2_inputWidget
|
|||||||
},
|
},
|
||||||
this, et2_link_list
|
this, et2_link_list
|
||||||
);
|
);
|
||||||
|
// Update any neighbouring link lists
|
||||||
|
(<Et2LinkList><unknown>(<et2_DOMWidget>this.getParent()).getDOMNode().querySelector('et2-link-list'))?.get_links();
|
||||||
|
|
||||||
// If there's an array of data (entry is not yet saved), updating the list will
|
// If there's an array of data (entry is not yet saved), updating the list will
|
||||||
// not work, so add them in explicitly.
|
// not work, so add them in explicitly.
|
||||||
|
@ -1274,7 +1274,7 @@ ul.et2_link_string {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.et2_link_list td.remark {
|
.et2_link_list td.remark, et2-link-list .remark {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user