diff --git a/api/js/etemplate/Et2Tree/Et2Tree.ts b/api/js/etemplate/Et2Tree/Et2Tree.ts index a00c8df3da..50d6cd45ed 100644 --- a/api/js/etemplate/Et2Tree/Et2Tree.ts +++ b/api/js/etemplate/Et2Tree/Et2Tree.ts @@ -77,7 +77,7 @@ export class Et2Tree extends Et2WidgetWithSelectMixin(LitElement) imagePath: String = egw().webserverUrl + "/api/templates/default/images/dhtmlxtree/" //TODO we will need a different path here! maybe just rename the path? // description: "Directory for tree structure images, set on server-side to 'dhtmlx' subdir of templates image-directory" @property() - value = {} + value = [] protected autoloading_url: any; // private selectOptions: TreeItemData[] = []; diff --git a/api/js/etemplate/Et2Tree/Et2TreeDropdown.ts b/api/js/etemplate/Et2Tree/Et2TreeDropdown.ts index 96d9737f5e..55a7e23f02 100644 --- a/api/js/etemplate/Et2Tree/Et2TreeDropdown.ts +++ b/api/js/etemplate/Et2Tree/Et2TreeDropdown.ts @@ -5,7 +5,6 @@ import {property} from "lit/decorators/property.js"; import {classMap} from "lit/directives/class-map.js"; import {state} from "lit/decorators/state.js"; import {HasSlotController} from "../Et2Widget/slot"; -import {keyed} from "lit/directives/keyed.js"; import {map} from "lit/directives/map.js"; import {SlPopup, SlRemoveEvent} from "@shoelace-style/shoelace"; import shoelace from "../Styles/shoelace"; @@ -344,9 +343,22 @@ export class Et2TreeDropdown extends Et2WidgetWithSelectMixin(LitElement) handleTreeChange(event) { - const oldValue = this.value; - this.value = event?.detail?.selection?.map(i => i.id) ?? []; - this.requestUpdate("value", oldValue); + const oldValue = this.value.slice(0); + + // For single value, we can just grab selected from the tree. For multiple, we need to manage it. + if(!this.multiple) + { + this.value = event?.detail?.selection?.map(i => i.id) ?? [] + } + else + { + const id = event?.detail?.selection?.map(i => i.id).pop(); + if(id) + { + // Copy so LitElement knows it changed + this.value = [...this.value, id]; + } + } this.updateComplete.then(() => { @@ -417,12 +429,12 @@ export class Et2TreeDropdown extends Et2WidgetWithSelectMixin(LitElement) tagsTemplate() { const value = this.getValueAsArray(); - return html`${keyed(this._valueUID, map(value, (value, index) => + return html`${map(value, (value, index) => { // Deal with value that is not in options - const option = this.optionSearch(value, this.select_options); + const option = this.optionSearch(value, this.select_options, 'item'); return option ? this.tagTemplate(option) : nothing; - }))}`; + })}`; } tagTemplate(option : TreeItemData) @@ -530,10 +542,9 @@ export class Et2TreeDropdown extends Et2WidgetWithSelectMixin(LitElement) is_readonly($cname, $form_name)) { + $unavailable_name = $form_name . self::UNAVAILABLE_CAT_POSTFIX; + $unavailable_values = (array)self::$request->preserv[$unavailable_name]; $value = $value_in = self::get_array($content, $form_name); // we can not validate if autoloading is enabled @@ -255,12 +259,16 @@ class Tree extends Etemplate\Widget $allowed += self::selOptions($form_name); foreach((array) $value as $val) { + if(in_array($val, $unavailable_values)) + { + continue; + } if ($this->type == 'tree-cat' && !($this->attrs['multiple'] && !$val) && !self::in_cats($val, $allowed) || $this->type == 'tree' && !self::in_tree($val, $allowed)) { self::set_validation_error($form_name,lang("'%1' is NOT allowed%2)!", $val, $this->type == 'tree-cat' ? " ('".implode("','",array_keys($allowed)).')' : ''), ''); - $value = ''; + $val = ''; break; } } @@ -269,7 +277,6 @@ class Tree extends Etemplate\Widget if (is_array($value) && $this->type == 'tree-cat') { // unavailable cats need to be merged in again - $unavailable_name = $form_name.self::UNAVAILABLE_CAT_POSTFIX; if (isset(self::$request->preserv[$unavailable_name])) { if ($this->attrs['multiple']) @@ -474,16 +481,16 @@ class Tree extends Etemplate\Widget } $cat2path=array(); - static::processCategory(0, $options, $categories, !$type); + static::processCategory(0, $options, $categories, !$type, $cat2path); // change cat-ids to pathes and preserv unavailible cats (eg. private user-cats) if ($value) { $pathes = $unavailable = array(); foreach(is_array($value) ? $value : explode(',',$value) as $cat) { - if (isset($cat2path[$cat])) + if(in_array($cat, $cat2path)) { - $pathes[] = $cat2path[$cat]; + $pathes[] = $cat; } else { @@ -508,7 +515,7 @@ class Tree extends Etemplate\Widget return $options; } - protected static function processCategory($cat_id, &$options, &$categories, $globals) + protected static function processCategory($cat_id, &$options, &$categories, $globals, &$cat_id_list) { foreach((array)$categories->return_array($cat_id ? 'subs' : 'mains', 0, false, '', 'ASC', '', $globals, $cat_id) as $cat) { @@ -533,11 +540,12 @@ class Tree extends Etemplate\Widget 'label' => $s, 'title' => $cat['description'] ); + $cat_id_list[] = $cat['id']; if(!empty($cat['children'])) { $category['item'] = []; unset($cat['children']); - static::processCategory($cat['id'], $category['item'], $categories, $globals); + static::processCategory($cat['id'], $category['item'], $categories, $globals, $cat_id_list); } $options[] = $category; }