1 """
2 Nevow formal custom widgets used by the DC (enumerations, table options,
3 etc)
4 """
5
6
7
8
9
10
11
12 from twisted.python import components
13
14 from nevow import tags as T
15 from nevow import flat
16 from nevow.util import getPOSTCharset
17
18 from zope.interface import implements
19
20 from gavo import base
21 from gavo import rscdef
22 from gavo import utils
23 from gavo.imp import formal
24 from gavo.imp.formal import iformal
25 from gavo.imp.formal import types as formaltypes
26 from gavo.imp.formal import widget
27 from gavo.imp.formal import widgetFactory
28 from gavo.imp.formal.util import render_cssid
29 from gavo.imp.formal.widget import (
30 TextInput, Checkbox, Password, TextArea, ChoiceBase, SelectChoice,
31 SelectOtherChoice, RadioChoice, CheckboxMultiChoice, FileUpload,
32 FileUploadWidget, Hidden)
33
34
36 """A widget that offers limit and sort options for db based cores.
37
38 This is for use in a formal form and goes together with the FormalDict
39 type below.
40 """
41 implements(iformal.IWidget)
42
43 sortWidget = None
44 limitWidget = None
45
46 - def __init__(self, typeOb, service, queryMeta):
54
69
74
79
80 - def render(self, ctx, key, args, errors):
81
82 children = []
83 if '_DBOPTIONS' in args:
84
85 v = [[args["_DBOPTIONS"]["order"]] or "",
86 [args["_DBOPTIONS"]["limit"] or 100],
87 [args["_DBOPTIONS"]["direction"] or "ASC"]]
88 else:
89
90 v = [args.get("_DBOPTIONS_ORDER", ['']),
91 args.get("MAXREC", [100]),
92 args.get("_DBOPTIONS_DIR", "ASC")]
93
94 if errors:
95 args = {"_DBOPTIONS_ORDER": v[0], "MAXREC": v[1],
96 "_DBOPTIONS_DIR": v[2]}
97 else:
98 args = {"_DBOPTIONS_ORDER": v[0][0], "MAXREC": int(v[1][0]),
99 "_DBOPTIONS_DIR": v[2][0]}
100
101 if self.sortWidget:
102 children.extend(["Sort by ",
103 self.sortWidget.render(ctx, "_DBOPTIONS_ORDER", args, errors),
104 " "])
105 children.extend([" ", self.directionWidget.render(ctx,
106 "_DBOPTIONS_DIR", args, errors)])
107
108 if self.limitWidget:
109 children.extend([T.br, "Limit to ",
110 self.limitWidget.render(ctx, "MAXREC", args, errors),
111 " items."])
112 return T.span(id=render_cssid(key))[children]
113
114
115 renderImmutable = render
116
131
132
137
138
139
140
141 PairOf = formaltypes.Sequence
142
143
145 - def __init__(self, original, options, noneLabel=None):
146 if noneLabel is None:
147 noneOption = None
148 else:
149 noneOption = (noneLabel, noneLabel)
150 super(SimpleSelectChoice, self).__init__(original,
151 [(o,o) for o in options], noneOption)
152
153
154
155
157 size = 3
158 - def __init__(self, original, size=None, **kwargs):
162
163 - def _renderTag(self, ctx, key, value, converter, disabled):
164 if not isinstance(value, (list, tuple)):
165 value = [value]
166
167
168
169 def renderOptions(ctx, data):
170 if self.noneOption is not None:
171 noneVal = iformal.IKey(self.noneOption).key()
172 option = T.option(value=noneVal)[
173 iformal.ILabel(self.noneOption).label()]
174 if value is None or value==noneVal:
175 option = option(selected='selected')
176 yield option
177 if data is None:
178 return
179 for item in data:
180 optValue = iformal.IKey(item).key()
181 optLabel = iformal.ILabel(item).label()
182 optValue = converter.fromType(optValue)
183 option = T.option(value=optValue)[optLabel]
184 if optValue in value:
185 option = option(selected='selected')
186 yield option
187
188 tag = T.select(name=key, id=render_cssid(key), data=self.options)[
189 renderOptions]
190 if disabled:
191 tag(class_='disabled', disabled='disabled')
192 return T.span(style="white-space:nowrap")[
193 tag(size=str(self.size), multiple="multiple"),
194 " ",
195 T.span(class_="fieldlegend")[
196 "No selection matches all, multiple values legal."]]
197
198 - def render(self, ctx, key, args, errors):
199 converter = iformal.IStringConvertible(self.original)
200 if errors:
201 value = args.get(key, [])
202 else:
203 value = map(converter.fromType, args.get(key, []) or [])
204 return self._renderTag(ctx, key, value, converter, False)
205
217
218
220 """helps EnumeratedWidget figure out the None option and the options
221 for selection.
222 """
223 noneOption = None
224 options = []
225 default = ik.values.default
226 if ik.value:
227 default = ik.value
228
229 if default is not None:
230 if ik.required:
231
232
233 options = ik.values.options
234 else:
235
236 for o in ik.values.options:
237 if o.content_==ik.values.default:
238 noneOption = o
239 else:
240 options.append(o)
241 else:
242
243 options.extend(ik.values.options)
244 noneOption = None
245 if not ik.required and not ik.values.multiOk or ik.multiplicity=="multiple":
246 noneOption = base.makeStruct(rscdef.Option, title="ANY",
247 content_="__DaCHS__ANY__")
248 return noneOption, options
249
250
287
288
290 """is a text input widget with additional material at the side.
291 """
292 additionalMaterial = ""
293
295 am = kwargs.pop("additionalMaterial", None)
296 widget.TextInput.__init__(self, *args, **kwargs)
297 if am is not None:
298 self.additionalMaterial = am
299
301 plainTag = widget.TextInput._renderTag(self, ctx, key, value,
302 readonly)
303 return T.span(style="white-space:nowrap")[
304 plainTag,
305 " ",
306 T.span(class_="fieldlegend")[self.additionalMaterial]]
307
308
313
314
319
320
325
326
327 -class ScalingTextArea(widget.TextArea):
328 """is a text area that scales with the width of the window.
329 """
330 - def _renderTag(self, ctx, key, value, readonly):
331 tag=T.textarea(name=key, id=render_cssid(key), rows=self.rows,
332 style="width:100% !important")[value or '']
333 if readonly:
334 tag(class_='readonly', readonly='readonly')
335 return tag
336
337
339 """A widget to enter an interval (lower/upper) pair of something.
340
341 As usual with formal widgets, this is constructed with the type, which
342 must be PairOf here; we're taking the widget we're supposed to pair from
343 it.
344 """
348
349 - def _renderTag(self, ctx, key, values, readonly):
350 tags = []
351 for index, seqid in enumerate(["lower", "upper"]):
352 tag = T.input(type="text", name=key+seqid,
353 id=render_cssid(key+seqid), value=values[index])
354 if readonly:
355 tag(class_='readonly', readonly='readonly')
356
357
358
359 tags.append(tag)
360
361 tags[1:1] = u" \u2013 "
362
363 return T.div(class_="form-interval")[tags]
364
365 - def render(self, ctx, key, args, errors):
366 if errors:
367 values = [args.get(key+"lower", [''])[0],
368 args.get(key+"upper", [''])[0]]
369 else:
370 baseType = iformal.IStringConvertible(self.original)
371 values = [baseType.fromType(args.get(key+"lower")),
372 baseType.fromType(args.get(key+"upper"))]
373
374 return self._renderTag(ctx, key, values, False)
375
377 baseType = iformal.IStringConvertible(self.original)
378 values = [baseType.fromType(args.get(key+"lower")),
379 baseType.fromType(args.get(key+"upper"))]
380 return self._renderTag(ctx, key, values, True)
381
391
392
395
396
397
398
399
400 from gavo.rscdef import column
401
413
414 components.registerAdapter(ToFormalAdapter, column.Option, iformal.ILabel)
415 components.registerAdapter(ToFormalAdapter, column.Option, iformal.IKey)
416
417
418 flat.registerFlattener(lambda original, ctx: str(original), utils.QuotedName)
419