Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1"""Types of values in value tables.""" 

2 

3from control.utils import pick as G, E, NBSP 

4from control.html import HtmlElements as H 

5from config import Config as C, Names as N 

6from control.typ.related import Related, castObjectId 

7 

8CW = C.web 

9 

10MESSAGES = CW.messages 

11 

12FILTER_THRESHOLD = CW.filterThreshold 

13 

14QQ = H.icon(CW.unknown[N.generic]) 

15Qq = H.icon(CW.unknown[N.generic], asChar=True) 

16 

17 

18class ConversionError(Exception): 

19 pass 

20 

21 

22class Value(Related): 

23 """Type class for types with values in value tables.""" 

24 

25 widgetType = N.related 

26 

27 def __init__(self, context): 

28 """## Initialization 

29 

30 Store a handle to the Context singleton. 

31 

32 Parameters 

33 ---------- 

34 context: object 

35 See below. 

36 """ 

37 

38 self.context = context 

39 """*object* A `control.context.Context` singleton. 

40 """ 

41 

42 def fromStr(self, editVal, constrain=None, uid=None, eppn=None, extensible=False): 

43 """Convert a value to an object id by looking it up in a value table. 

44 

45 If the value is a singleton list, and if the value list is extensible, 

46 we insert the new value into the value table, and return the new id. 

47 

48 Otherwise, the value must be either: 

49 

50 * the string representation of id of a value 

51 * or a value in the relevant value table. 

52 

53 In all cases the MongoDb object id of that value is returned. 

54 

55 If a `constrain` is given only values in a subset defined by a constraint 

56 qualify. This happens when we look for score records that are bound to a 

57 criterion. 

58 

59 Parameters 

60 ---------- 

61 editVal: string 

62 The value as it has been sent from the client 

63 constrain: 

64 An additional constraint for the value. 

65 See `control.db.Db.getValueRecords`. 

66 """ 

67 

68 if not editVal: 

69 return None 

70 

71 context = self.context 

72 db = context.db 

73 table = self.name 

74 

75 valType = type(editVal) 

76 valuesInv = ( 

77 getattr(db, f"""{table}Inv""", {}) 

78 if constrain is None 

79 else db.getValueInv(table, constrain) 

80 ) 

81 if valType is list or valType is tuple: 

82 if extensible and editVal: 

83 editVal = editVal[0] 

84 if editVal in valuesInv: 84 ↛ 85line 84 didn't jump to line 85, because the condition on line 84 was never true

85 return valuesInv[editVal] 

86 fieldName = N.rep if extensible is True else extensible 

87 field = {fieldName: editVal} 

88 return db.insertItem(table, uid, eppn, True, **field) 

89 raise ConversionError 

90 

91 values = ( 

92 getattr(db, table, {}) 

93 if constrain is None 

94 else db.getValueIds(table, constrain) 

95 ) 

96 valId = castObjectId(editVal) 

97 if valId is None: 

98 valId = G(valuesInv, editVal) 

99 if valId not in values: 

100 raise ConversionError 

101 return valId 

102 

103 def toEdit(self, val): 

104 return val 

105 

106 def toOrig(self, val): 

107 return val if val is None else str(val) 

108 

109 def widget(self, val, multiple, extensible, constrain): 

110 context = self.context 

111 db = context.db 

112 table = self.name 

113 

114 valueRecords = db.getValueRecords(table, constrain=constrain) 

115 

116 filterControl = ( 

117 [ 

118 H.input( 

119 E, 

120 type=N.text, 

121 placeholder=G(MESSAGES, N.filter, default=E), 

122 cls="wfilter", 

123 ), 

124 H.iconx(N.add, cls="small wfilter add", title="add value") 

125 if extensible 

126 else E, 

127 H.iconx(N.clear, cls="small wfilter clear", title="clear filter"), 

128 ] 

129 if len(valueRecords) > FILTER_THRESHOLD 

130 else [] 

131 ) 

132 atts = dict( 

133 markup=True, 

134 clickable=True, 

135 multiple=multiple, 

136 active=val, 

137 hideInActual=True, 

138 hideBlockedUsers=True, 

139 ) 

140 return H.div( 

141 filterControl 

142 + [ 

143 formatted 

144 for (text, formatted) in ( 

145 ([] if multiple else [self.title(record={}, **atts)]) 

146 + sorted( 

147 (self.title(record=record, **atts) for record in valueRecords), 

148 key=lambda x: x[0].lower(), 

149 ) 

150 ) 

151 ], 

152 cls="wvalue", 

153 ) 

154 

155 def title( 

156 self, 

157 eid=None, 

158 record=None, 

159 markup=False, 

160 clickable=False, 

161 multiple=False, 

162 active=None, 

163 hideInActual=False, 

164 hideBlockedUsers=False, 

165 ): 

166 if record is None and eid is None: 

167 return None if markup is None else (QQ, QQ) if markup else Qq 

168 

169 table = self.name 

170 

171 if record is None: 

172 context = self.context 

173 record = context.getItem(table, eid) 

174 

175 titleStr = self.titleStr(record, markup=markup) 

176 titleHint = self.titleHint(record) 

177 

178 if markup: 

179 if eid is None: 

180 eid = G(record, N._id) 

181 

182 isActive = eid in (active or []) if multiple else eid == active 

183 baseCls = ( 

184 ("button " if multiple or not isActive else "label ") 

185 if clickable 

186 else "tag " 

187 ) 

188 activeCls = "active " if isActive else E 

189 inActualCls = self.inActualCls(record=record) 

190 hidden = ( 

191 hideInActual 

192 and inActualCls 

193 and not isActive 

194 or hideBlockedUsers 

195 and table == N.user 

196 and not G(record, N.mayLogin) 

197 ) 

198 if hidden: 198 ↛ 199line 198 didn't jump to line 199, because the condition on line 198 was never true

199 return (E, E) 

200 atts = dict(cls=f"{baseCls}{activeCls}medium {inActualCls}") 

201 if clickable and eid is not None: 

202 atts[N.eid] = str(eid) 

203 

204 if titleHint: 

205 atts[N.title] = titleHint 

206 

207 titleIcon = ( 

208 (NBSP + H.icon(N.cross if isActive else N.add, cls="small")) 

209 if multiple 

210 else E 

211 ) 

212 

213 titleFormatted = H.span( 

214 [titleStr, titleIcon], lab=titleStr.lower(), **atts, 

215 ) 

216 return (titleStr, titleFormatted) 

217 else: 

218 return titleStr