WIP sl-Tree

This commit is contained in:
Milan 2023-09-27 13:05:48 +02:00
parent e3ca0bfacd
commit aa228dad42

View File

@ -1,12 +1,14 @@
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget"; import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
import {SlTree} from "@shoelace-style/shoelace"; import {SlTree} from "@shoelace-style/shoelace";
import {Et2Link} from "../Et2Link/Et2Link"; import {Et2Link} from "../Et2Link/Et2Link";
import {Et2widgetWithSelectMixin} from "../Et2Select/Et2WidgetWithSelectMixin";
import {et2_no_init} from "../et2_core_common"; import {et2_no_init} from "../et2_core_common";
import {egw, framework} from "../../jsapi/egw_global"; import {egw, framework} from "../../jsapi/egw_global";
import {SelectOption, find_select_options, cleanSelectOptions} from "../Et2Select/FindSelectOptions"; import {SelectOption, find_select_options, cleanSelectOptions} from "../Et2Select/FindSelectOptions";
import {html, TemplateResult} from "@lion/core";
import {egwIsMobile} from "../../egw_action/egw_action_common"; import {egwIsMobile} from "../../egw_action/egw_action_common";
import {Et2WidgetWithSelectMixin} from "../Et2Select/Et2WidgetWithSelectMixin";
import {LitElement, css, TemplateResult, html} from "lit";
import {repeat} from "lit/directives/repeat.js";
import shoelace from "../Styles/shoelace";
export type TreeItem = { export type TreeItem = {
child: Boolean | 1, child: Boolean | 1,
@ -25,17 +27,46 @@ export type TreeItem = {
} }
export class Et2Tree extends Et2widgetWithSelectMixin(SlTree) { export class Et2Tree extends Et2WidgetWithSelectMixin(LitElement)
private input: any = null; {
private div: JQuery; static get styles()
private autoloading_url: any; {
private selectOptions: TreeItem[];
constructor() { return [
shoelace,
// @ts-ignore
...super.styles,
css`
`
]
}
private currentItem: TreeItem
private input: any = null;
private autoloading_url: any;
private selectOptions: TreeItem[] = [];
private needsLazyLoading: Boolean = true;
/**
* Limit server searches to 100 results, matches Link::DEFAULT_NUM_ROWS
* @type {number}
*/
static RESULT_LIMIT: number = 100;
constructor()
{
super(); super();
} }
static get properties() { public loadFromXML()
{
//if(this.id)
this.selectOptions = <TreeItem[]><unknown>find_select_options(this)[1]
}
static get properties()
{
return { return {
...super.properties, ...super.properties,
multiple: { multiple: {
@ -123,46 +154,38 @@ export class Et2Tree extends Et2widgetWithSelectMixin(SlTree) {
} }
}; };
public set onOpenStart(_handler: Function) { public set onOpenStart(_handler: Function)
{
this.installHandler("onOpenStart", _handler) this.installHandler("onOpenStart", _handler)
} }
public set onChange(_handler: Function) { public set onChange(_handler: Function)
{
this.installHandler("onChange", _handler) this.installHandler("onChange", _handler)
} }
public set onClick(_handler: Function) { public set onClick(_handler: Function)
{
this.installHandler("onClick", _handler) this.installHandler("onClick", _handler)
} }
public set onSelect(_handler: Function) { public set onSelect(_handler: Function)
{
this.installHandler("onSelect", _handler) this.installHandler("onSelect", _handler)
} }
public set onOpenEnd(_handler: Function) { public set onOpenEnd(_handler: Function)
{
this.installHandler("onOpenEnd", _handler) this.installHandler("onOpenEnd", _handler)
} }
_optionTemplate() {
// @ts-ignore
this.selectOptions= find_select_options(this)[1];
//slot = expanded/collapsed instead of expand/collapse like it is in documentation
let result: TemplateResult<1> = html``
for (const selectOption of this.selectOptions) {
result = html`${result}
<sl-tree-item>
${this.recursivelyAddChildren(selectOption)}
</sl-tree-item>`
}
const h = html`${result}`
return h
}
/** /**
* @deprecated assign to onOpenStart * @deprecated assign to onOpenStart
* @param _handler * @param _handler
*/ */
public set_onopenstart(_handler: Function) { public set_onopenstart(_handler: Function)
{
this.installHandler("onOpenStart", _handler) this.installHandler("onOpenStart", _handler)
} }
@ -170,7 +193,8 @@ export class Et2Tree extends Et2widgetWithSelectMixin(SlTree) {
* @deprecated assign to onChange * @deprecated assign to onChange
* @param _handler * @param _handler
*/ */
public set_onchange(_handler: Function) { public set_onchange(_handler: Function)
{
this.installHandler('onchange', _handler); this.installHandler('onchange', _handler);
} }
@ -178,7 +202,8 @@ export class Et2Tree extends Et2widgetWithSelectMixin(SlTree) {
* @deprecated assign to onClick * @deprecated assign to onClick
* @param _handler * @param _handler
*/ */
public set_onclick(_handler: Function) { public set_onclick(_handler: Function)
{
this.installHandler('onclick', _handler); this.installHandler('onclick', _handler);
} }
@ -186,7 +211,8 @@ export class Et2Tree extends Et2widgetWithSelectMixin(SlTree) {
* @deprecated assign to onSelect * @deprecated assign to onSelect
* @param _handler * @param _handler
*/ */
public set_onselect(_handler: Function) { public set_onselect(_handler: Function)
{
this.installHandler('onselect', _handler); this.installHandler('onselect', _handler);
} }
@ -194,36 +220,15 @@ export class Et2Tree extends Et2widgetWithSelectMixin(SlTree) {
* @deprecated assign to onOpenEnd * @deprecated assign to onOpenEnd
* @param _handler * @param _handler
*/ */
public set_onopenend(_handler: Function) { public set_onopenend(_handler: Function)
{
this.installHandler('onOpenEnd', _handler); this.installHandler('onOpenEnd', _handler);
} }
private recursivelyAddChildren(item: any): TemplateResult<1> {
let img:String =item.im0??item.im1??item.im2;
let attributes = ""
let res: TemplateResult<1> = html`${item.text}`;
if(img){
img = "api/templates/default/images/dhtmlxtree/"+img
//sl-icon images need to be svgs if there is a png try to find the corresponding svg
if(img.endsWith(".png"))img = img.replace(".png",".svg");
res = html`<sl-icon src=${img}></sl-icon>${res}`
}
if (item.item?.length > 0) // there are children available
{
for (const subItem of item.item) {
res = html`
${res}
<sl-tree-item lazy> ${this.recursivelyAddChildren(subItem)}</sl-tree-item>`
}
// }else if(item.child === 1){
// res = html``
// }
}
return res;
}
private installHandler(_name: String, _handler: Function) { private installHandler(_name: String, _handler: Function)
if (this.input == null) this.createTree(this); {
if (this.input == null) this.createTree();
// automatic convert onChange event to oncheck or onSelect depending on multiple is used or not // automatic convert onChange event to oncheck or onSelect depending on multiple is used or not
// if (_name == "onchange") { // if (_name == "onchange") {
// _name = this.options.multiple ? "oncheck" : "onselect" // _name = this.options.multiple ? "oncheck" : "onselect"
@ -240,17 +245,108 @@ export class Et2Tree extends Et2widgetWithSelectMixin(SlTree) {
// }); // });
} }
private createTree(widget: this) { private createTree()
widget.input = document.querySelector("et2-tree"); {
// Allow controlling icon size by CSS // widget.input = document.querySelector("et2-tree");
widget.input.def_img_x = ""; // // Allow controlling icon size by CSS
widget.input.def_img_y = ""; // widget.input.def_img_x = "";
// widget.input.def_img_y = "";
//
// // to allow "," in value, eg. folder-names, IF value is specified as array
// widget.input.dlmtr = ':}-*(';
// @ts-ignore from static get properties
if (this.autoLoading)
{
// @ts-ignore from static get properties
let url = this.autoLoading;
// to allow "," in value, eg. folder-names, IF value is specified as array if (url.charAt(0) != '/' && url.substr(0, 4) != 'http')
widget.input.dlmtr = ':}-*('; {
url = '/json.php?menuaction=' + url;
}
this.autoloading_url = url;
}
}
private handleLazyLoading(_item: TreeItem)
{
let sendOptions = {
num_rows: Et2Tree.RESULT_LIMIT,
}
return egw().request(egw().link(egw().ajaxUrl(egw().decodePath(this.autoloading_url)),
{
id: _item.id
}), [sendOptions])
.then((results) => {
// If results have a total included, pull it out.
// It will cause errors if left in the results
// this._total_result_count = results.length;
// if(typeof results.total !== "undefined")
// {
// this._total_result_count = results.total;
// delete results.total;
// }
// let entries = cleanSelectOptions(results);
// this.processRemoteResults(entries);
// return entries;
return results
});
}
//this.selectOptions = find_select_options(this)[1];
_optionTemplate(selectOption: TreeItem)
{
// @ts-ignore
//slot = expanded/collapsed instead of expand/collapse like it is in documentation
//selectOption.child === 1
return html`
<sl-tree-item
.currentItem=${selectOption}
?lazy=${this.needsLazyLoading}
@sl-lazy-load=${() => this.handleLazyLoading(selectOption)}
>
${selectOption.text}
${repeat(selectOption.item, this._optionTemplate.bind(this))}
</sl-tree-item>`
}
public render(): unknown
{
return html`
<sl-tree
>
${repeat(this.selectOptions, this._optionTemplate.bind(this))}
</sl-tree>
`;
}
protected remoteQuery(search: string, options: object): Promise<SelectOption[]>
{
// Include a limit, even if options don't, to avoid massive lists breaking the UI
let sendOptions = {
num_rows: Et2Tree.RESULT_LIMIT,
...options
}
return this.egw().request(this.egw().link(this.egw().ajaxUrl(this.egw().decodePath(this.searchUrl)),
{query: search, ...sendOptions}), [search, sendOptions]).then((results) => {
// If results have a total included, pull it out.
// It will cause errors if left in the results
this._total_result_count = results.length;
if (typeof results.total !== "undefined")
{
this._total_result_count = results.total;
delete results.total;
}
let entries = cleanSelectOptions(results);
this.processRemoteResults(entries);
return entries;
});
} }
} }
customElements.define("et2-tree", Et2Tree); customElements.define("et2-tree", Et2Tree);
const tree = new Et2Tree();