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

1"""Client object and UI elements.""" 

2 

3from typing import Optional 

4 

5import gws 

6 

7 

8class ElementConfig(gws.ConfigWithAccess): 

9 """Client UI element.""" 

10 

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.""" 

19 

20 

21class Config(gws.ConfigWithAccess): 

22 """UI elements and options of the browser client.""" 

23 

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.""" 

32 

33 

34class ElementProps(gws.Data): 

35 """Client UI element properties.""" 

36 

37 tag: str 

38 

39 

40class Props(gws.Data): 

41 """Client properties.""" 

42 

43 options: Optional[dict] 

44 elements: Optional[list[ElementProps]] 

45 

46 

47class Element(gws.Node): 

48 """Client UI element. 

49 

50 An element of the browser client, identified by its tag, with element options 

51 and access rules. 

52 """ 

53 

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.""" 

62 

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 {} 

68 

69 def props(self, user): 

70 return gws.Data(tag=self.tag, options=self.options) 

71 

72 

73class Object(gws.Client): 

74 """Client object.""" 

75 

76 options: dict 

77 """Client options.""" 

78 elements: list[Element] 

79 """Client UI elements.""" 

80 

81 def configure(self): 

82 app_client = gws.u.get(self.root.app, 'client') 

83 

84 self.elements = self.create_children(Element, self._get_elements(app_client)) 

85 

86 self.options = gws.u.merge( 

87 app_client.options if app_client else {}, 

88 self.cfg('options')) 

89 

90 def props(self, user): 

91 return Props( 

92 options=self.options, 

93 elements=self.elements, 

94 ) 

95 

96 def _get_elements(self, app_client): 

97 """Return the element list, either configured or inherited from the application client and modified. 

98 

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 

105 

106 if not app_client: 

107 return [] 

108 

109 add = self.cfg('addElements', default=[]) 

110 remove = self.cfg('removeElements', default=[]) 

111 elements = list(app_client.elements) 

112 

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) 

127 

128 remove_tags = [c.tag for c in remove] 

129 return [e for e in elements if e.tag not in remove_tags] 

130 

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