From 7e9b2f3687d4f574f14865634acc93d868b29a01 Mon Sep 17 00:00:00 2001 From: ralf Date: Wed, 20 Mar 2024 21:49:09 +0200 Subject: [PATCH] WIP allow to specify an optional tab-name for a cf, to create additional tab(s) and show the cfs in them currently an extra namespace prevents storing and reading these cfs --- api/js/etemplate/Layout/Et2Tabs/Et2Tabs.ts | 25 ++++++++++ .../etemplate/et2_extension_customfields.ts | 47 ++++++++++++++++++- api/src/Storage/Customfields.php | 12 +++-- api/templates/default/cf-tab.xet | 7 +++ 4 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 api/templates/default/cf-tab.xet diff --git a/api/js/etemplate/Layout/Et2Tabs/Et2Tabs.ts b/api/js/etemplate/Layout/Et2Tabs/Et2Tabs.ts index fb5d4dbaa3..714ceed841 100644 --- a/api/js/etemplate/Layout/Et2Tabs/Et2Tabs.ts +++ b/api/js/etemplate/Layout/Et2Tabs/Et2Tabs.ts @@ -543,6 +543,31 @@ export class Et2Tabs extends Et2InputWidget(SlTabGroup) implements et2_IResizeab return false; } + /** + * get tab panel-name or label the given widget is in + * + * @param widget + * @param label true: return label, otherwise return panel-name + * @return string panel-name or undefined + */ + static getTabPanel(widget, label) + { + let tab = widget; + while(tab._parent && tab._parent.nodeName !== 'ET2-TABBOX') + { + tab = tab._parent; + } + if (tab.nodeName === 'ET2-TAB-PANEL') + { + if (label) + { + return tab._parent?.querySelector('et2-tab[panel="'+tab.name+'"]')?.innerText; + } + return tab.name; + } + return undefined; + } + /** * Reimplement to allow our existing function signatures too * diff --git a/api/js/etemplate/et2_extension_customfields.ts b/api/js/etemplate/et2_extension_customfields.ts index d4236cd97a..becd4ee419 100644 --- a/api/js/etemplate/et2_extension_customfields.ts +++ b/api/js/etemplate/et2_extension_customfields.ts @@ -27,6 +27,7 @@ import {et2_DOMWidget} from "./et2_core_DOMWidget"; import {loadWebComponent} from "./Et2Widget/Et2Widget"; import {LitElement} from "lit"; import {Et2VfsSelectButton} from "./Et2Vfs/Et2VfsSelectButton"; +import {Et2Tabs} from "./Layout/Et2Tabs/Et2Tabs"; export class et2_customfields_list extends et2_valueWidget implements et2_IDetachedDOM, et2_IInput { @@ -50,7 +51,7 @@ export class et2_customfields_list extends et2_valueWidget implements et2_IDetac 'name': 'Field filter', "default": "", "type": "any", // String or array - "description": "Filter displayed custom fields by their 'type2' attribute" + "description": "Filter displayed custom fields by their 'type2' attribute, use 'previous' for the filter of the previous / regular cf widget" }, 'private': { ignore: true, @@ -68,6 +69,13 @@ export class et2_customfields_list extends et2_valueWidget implements et2_IDetac "default": et2_no_init, "description": "JS code which is executed when the value changes." }, + // filter cfs by a given tab value + 'tab': { + name: "tab", + type: "string", + default: null, + description: "only show cfs with the given tab attribute value, use 'panel' for the tab-panel the widget is in" + }, // Allow changing the field prefix. Normally it's the constant but importexport filter changes it. "prefix": { name: "prefix", @@ -88,6 +96,8 @@ export class et2_customfields_list extends et2_valueWidget implements et2_IDetac widgets = {}; private detachedNodes = []; + static previous_type_filter; + constructor(_parent?, _attrs? : WidgetConfig, _child? : object) { super(_parent, _attrs, ClassWithAttributes.extendAttributes(et2_customfields_list._attributes, _child || {})); @@ -122,6 +132,13 @@ export class et2_customfields_list extends et2_valueWidget implements et2_IDetac } } + // allow to use previous type_filter + if (this.options.type_filter === "previous") + { + this.options.type_filter = et2_customfields_list.previous_type_filter; + } + et2_customfields_list.previous_type_filter = this.options.type_filter; + if(this.options.type_filter && typeof this.options.type_filter == "string") { this.options.type_filter = this.options.type_filter.split(","); @@ -154,6 +171,33 @@ export class et2_customfields_list extends et2_valueWidget implements et2_IDetac } } + // filter fields by tab attribute + if (this.options.tab === 'panel') + { + this.options.tab = Et2Tabs.getTabPanel(this, true); + } + if (typeof this.options.fields === "undefined" || !Object.keys(this.options.fields).length) + { + this.options.fields = {}; + for(let field_name in this.options.customfields) + { + if (this.options.customfields[field_name].tab === this.options.tab) + { + this.options.fields[field_name] = true; + } + } + } + else + { + for(let field_name in this.options.customfields) + { + if (this.options.customfields[field_name].tab !== this.options.tab) + { + delete this.options.fields[field_name]; + } + } + } + this.setDOMNode(this.table[0]); } @@ -232,7 +276,6 @@ export class et2_customfields_list extends et2_valueWidget implements et2_IDetac // Avoid creating field twice if(!this.rows[id]) { - const row = jQuery(document.createElement("tr")) .appendTo(this.tbody) .addClass(this.id + '_' + id); diff --git a/api/src/Storage/Customfields.php b/api/src/Storage/Customfields.php index 33c41fb68e..369410f10d 100644 --- a/api/src/Storage/Customfields.php +++ b/api/src/Storage/Customfields.php @@ -32,7 +32,7 @@ class Customfields implements \IteratorAggregate static protected $db; /** - * app the particular config class is instanciated for + * app the particular config class is instantiated for * * @var string */ @@ -67,9 +67,10 @@ class Customfields implements \IteratorAggregate * @param int $start =0 * @param int $num_rows =null * @param Api\Db $db =null reference to database instance to use + * @param ?bool $tabs false: do NOT return cfs with explicit tab, true: only return cfs with explicit tab, null: return all * @return array with customfields */ - function __construct($app, $account=false, $only_type2=null, $start=0, $num_rows=null, Api\Db $db=null) + function __construct($app, $account=false, $only_type2=null, $start=0, $num_rows=null, Api\Db $db=null, bool $tabs=false) { $this->app = $app; @@ -90,6 +91,10 @@ class Customfields implements \IteratorAggregate { $query[] = $this->commasep_match('cf_type2', $only_type2); } + if (isset($tabs)) + { + $query[] = 'cf_tab IS '.($tabs?'NOT ':'').'NULL'; + } if (!$db) $db = self::$db; $this->iterator = $db->select(self::TABLE, '*', $query, __LINE__, __FILE__, !isset($num_rows) ? false : $start, 'ORDER BY cf_order ASC', 'phpgwapi', $num_rows); @@ -141,9 +146,10 @@ class Customfields implements \IteratorAggregate * false for current user or true for all the private fields be returned too, default current user * @param string $only_type2 =null if given only return fields of type2 == $only_type2 * @param Api\Db $db =null reference to database to use + * @param ?bool $tabs false: do NOT return cfs with explicit tab, true: only return cfs with explicit tab, null: return all * @return array with customfields */ - public static function get($app, $account=false, $only_type2=null, Api\Db $db=null) + public static function get($app, $account=false, $only_type2=null, Api\Db $db=null, ?bool $tabs=false) { $account_key = $account === true ? 'all' : ($account === false ? ($GLOBALS['egw_info']['user']['account_id']??null) : diff --git a/api/templates/default/cf-tab.xet b/api/templates/default/cf-tab.xet new file mode 100644 index 0000000000..04b0c7b675 --- /dev/null +++ b/api/templates/default/cf-tab.xet @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file