Coverage for gws-app/gws/base/client/core.py: 58%
66 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
1"""Client object and UI elements."""
3from typing import Optional
5import gws
8class ElementConfig(gws.ConfigWithAccess):
9 """Client UI element."""
11 tag: str
12 """Element tag."""
13 before: str = ''
14 """Tag of the element to insert this one before."""
15 after: str = ''
16 """Tag of the element to insert this one after."""
17 options: Optional[dict]
18 """Element-specific options passed to the client."""
21class Config(gws.ConfigWithAccess):
22 """UI elements and options of the browser client."""
24 options: Optional[dict]
25 """Client options, merged with the application client options."""
26 elements: Optional[list[ElementConfig]]
27 """Client UI elements, replacing the inherited application list."""
28 addElements: Optional[list[ElementConfig]]
29 """Elements to add to the inherited application element list."""
30 removeElements: Optional[list[ElementConfig]]
31 """Elements to remove from the inherited application element list."""
34class ElementProps(gws.Data):
35 """Client UI element properties."""
37 tag: str
40class Props(gws.Data):
41 """Client properties."""
43 options: Optional[dict]
44 elements: Optional[list[ElementProps]]
47class Element(gws.Node):
48 """Client UI element.
50 An element of the browser client, identified by its tag, with element options
51 and access rules.
52 """
54 tag: str
55 """Element tag, for example ``Toolbar.Print``."""
56 after: str
57 """Tag of the element this one was inserted after."""
58 before: str
59 """Tag of the element this one was inserted before."""
60 options: dict
61 """Element-specific options."""
63 def configure(self):
64 self.tag = self.cfg('tag')
65 self.after = self.cfg('after')
66 self.before = self.cfg('before')
67 self.options = self.cfg('options') or {}
69 def props(self, user):
70 return gws.Data(tag=self.tag, options=self.options)
73class Object(gws.Client):
74 """Client object."""
76 options: dict
77 """Client options."""
78 elements: list[Element]
79 """Client UI elements."""
81 def configure(self):
82 app_client = gws.u.get(self.root.app, 'client')
84 self.elements = self.create_children(Element, self._get_elements(app_client))
86 self.options = gws.u.merge(
87 app_client.options if app_client else {},
88 self.cfg('options'))
90 def props(self, user):
91 return Props(
92 options=self.options,
93 elements=self.elements,
94 )
96 def _get_elements(self, app_client):
97 """Return the element list, either configured or inherited from the application client and modified.
99 An added element replaces an inherited one with the same tag. An element
100 with ``before`` or ``after`` is only added if the referenced tag is present.
101 """
102 elements = self.cfg('elements')
103 if elements:
104 return elements
106 if not app_client:
107 return []
109 add = self.cfg('addElements', default=[])
110 remove = self.cfg('removeElements', default=[])
111 elements = list(app_client.elements)
113 for c in add:
114 n = self._find_element(elements, c.tag)
115 if n >= 0:
116 elements.pop(n)
117 if c.before:
118 n = self._find_element(elements, c.before)
119 if n >= 0:
120 elements.insert(n, c)
121 elif c.after:
122 n = self._find_element(elements, c.after)
123 if n >= 0:
124 elements.insert(n + 1, c)
125 else:
126 elements.append(c)
128 remove_tags = [c.tag for c in remove]
129 return [e for e in elements if e.tag not in remove_tags]
131 def _find_element(self, elements, tag):
132 """Return the index of the element with the given tag, or -1."""
133 for n, el in enumerate(elements):
134 if el.tag == tag:
135 return n
136 return -1