| 1 |
import re |
|---|
| 2 |
import types |
|---|
| 3 |
|
|---|
| 4 |
from Entry import * |
|---|
| 5 |
from Module import * |
|---|
| 6 |
|
|---|
| 7 |
FORM_TEMPLATE = """ |
|---|
| 8 |
<form action="%(action)s" method="%(method)s"> |
|---|
| 9 |
%(content)s |
|---|
| 10 |
%(submit)s |
|---|
| 11 |
<input type="hidden" name="is_submit" value="1" /> |
|---|
| 12 |
</form> |
|---|
| 13 |
""" |
|---|
| 14 |
|
|---|
| 15 |
AUTO_SUBMIT_JS = """ |
|---|
| 16 |
<script type="text/javascript"> |
|---|
| 17 |
$(document).ready(autosubmit); |
|---|
| 18 |
</script> |
|---|
| 19 |
""" |
|---|
| 20 |
|
|---|
| 21 |
AUTOFORM_TEMPLATE = FORM_TEMPLATE.replace('<form','<form class="auto"') + AUTO_SUBMIT_JS |
|---|
| 22 |
|
|---|
| 23 |
SUBMIT_BUTTON = """ |
|---|
| 24 |
<input type="submit" %(submit_props)s /> |
|---|
| 25 |
""" |
|---|
| 26 |
|
|---|
| 27 |
DEFAULT_SUBMIT_VALUE= 'value="Submit"' |
|---|
| 28 |
|
|---|
| 29 |
class WebComponent: |
|---|
| 30 |
def __init__ (self, id, cfg): |
|---|
| 31 |
self._id = id |
|---|
| 32 |
self._cfg = cfg |
|---|
| 33 |
|
|---|
| 34 |
def _op_handler (self, uri, post): |
|---|
| 35 |
if post.get_val('is_submit'): |
|---|
| 36 |
tmp = self._op_apply_changes (uri, post) |
|---|
| 37 |
if tmp: |
|---|
| 38 |
return tmp |
|---|
| 39 |
return self._op_render() |
|---|
| 40 |
|
|---|
| 41 |
def _op_render (self): |
|---|
| 42 |
raise "Should have been overridden" |
|---|
| 43 |
|
|---|
| 44 |
def _apply_changes (self, uri, post): |
|---|
| 45 |
raise "Should have been overridden" |
|---|
| 46 |
|
|---|
| 47 |
def HandleRequest (self, uri, post): |
|---|
| 48 |
# Is this a form submit |
|---|
| 49 |
is_submit = post.get_val('is_submit') |
|---|
| 50 |
|
|---|
| 51 |
# Check the URL |
|---|
| 52 |
parts = uri.split('/')[2:] |
|---|
| 53 |
if parts: |
|---|
| 54 |
ruri = '/' + '/'.join(parts) |
|---|
| 55 |
else: |
|---|
| 56 |
ruri = '/' |
|---|
| 57 |
|
|---|
| 58 |
if len(ruri) <= 1 and not is_submit: |
|---|
| 59 |
return self._op_render() |
|---|
| 60 |
|
|---|
| 61 |
return self._op_handler(ruri, post) |
|---|
| 62 |
|
|---|
| 63 |
class Form: |
|---|
| 64 |
def __init__ (self, action, method='post', add_submit=True, auto=True): |
|---|
| 65 |
self._action = action |
|---|
| 66 |
self._method = method |
|---|
| 67 |
self._add_submit = add_submit |
|---|
| 68 |
self._auto = auto |
|---|
| 69 |
|
|---|
| 70 |
def Render (self, content='', submit_props='' ): |
|---|
| 71 |
keys = {'submit': '', |
|---|
| 72 |
'submit_props': submit_props, |
|---|
| 73 |
'content': content, |
|---|
| 74 |
'action': self._action, |
|---|
| 75 |
'method': self._method} |
|---|
| 76 |
|
|---|
| 77 |
if self._add_submit: |
|---|
| 78 |
keys['submit'] = SUBMIT_BUTTON |
|---|
| 79 |
|
|---|
| 80 |
if self._auto: |
|---|
| 81 |
render = AUTOFORM_TEMPLATE |
|---|
| 82 |
else: |
|---|
| 83 |
render = FORM_TEMPLATE |
|---|
| 84 |
|
|---|
| 85 |
while '%(' in render: |
|---|
| 86 |
for replacement in re.findall (r'\%\((\w+)\)s', render): |
|---|
| 87 |
macro = '%('+replacement+')s' |
|---|
| 88 |
render = render.replace (macro, keys[replacement]) |
|---|
| 89 |
|
|---|
| 90 |
return render |
|---|
| 91 |
|
|---|
| 92 |
|
|---|
| 93 |
class FormHelper (WebComponent): |
|---|
| 94 |
options_wrap_num = 1 |
|---|
| 95 |
|
|---|
| 96 |
def __init__ (self, id, cfg): |
|---|
| 97 |
WebComponent.__init__ (self, id, cfg) |
|---|
| 98 |
|
|---|
| 99 |
self.errors = {} |
|---|
| 100 |
self.submit_url = None |
|---|
| 101 |
|
|---|
| 102 |
def set_submit_url (self, url): |
|---|
| 103 |
self.submit_url = url |
|---|
| 104 |
|
|---|
| 105 |
def Indent (self, content): |
|---|
| 106 |
return '<div class="indented">%s</div>' %(content) |
|---|
| 107 |
|
|---|
| 108 |
def Dialog (self, txt, type_='information'): |
|---|
| 109 |
return '<div class="dialog-%s">%s</div>' % (type_, txt) |
|---|
| 110 |
|
|---|
| 111 |
def HiddenInput (self, key, value): |
|---|
| 112 |
return '<input type="hidden" value="%s" id="%s" name="%s" />' % (value, key, key) |
|---|
| 113 |
|
|---|
| 114 |
def InstanceEntry (self, cfg_key, type, **kwargs): |
|---|
| 115 |
# Instance an Entry |
|---|
| 116 |
entry = Entry (cfg_key, type, self._cfg, **kwargs) |
|---|
| 117 |
txt = str(entry) |
|---|
| 118 |
|
|---|
| 119 |
# Check whether there is a related error |
|---|
| 120 |
if cfg_key in self.errors.keys(): |
|---|
| 121 |
msg, val = self.errors[cfg_key] |
|---|
| 122 |
if val: |
|---|
| 123 |
txt += '<div class="error"><b>%s</b>: %s</div>' % (val, msg) |
|---|
| 124 |
else: |
|---|
| 125 |
txt += '<div class="error">%s</div>' % (msg) |
|---|
| 126 |
return txt |
|---|
| 127 |
|
|---|
| 128 |
def Label(self, title, for_id): |
|---|
| 129 |
txt = '<label for="%s">%s</label>' % (for_id, title) |
|---|
| 130 |
return txt |
|---|
| 131 |
|
|---|
| 132 |
def InstanceTab (self, entries): |
|---|
| 133 |
# HTML |
|---|
| 134 |
txt = '<dl class="tab" id="tab_%s">' % (self._id) |
|---|
| 135 |
num = 0 |
|---|
| 136 |
for title, content in entries: |
|---|
| 137 |
error_inside = 'class="error"' in content |
|---|
| 138 |
if error_inside: |
|---|
| 139 |
txt += '<dt num="%d"><div class="error">%s</div></dt>\n' % (num, title) |
|---|
| 140 |
else: |
|---|
| 141 |
txt += '<dt num="%d">%s</dt>\n' % (num, title) |
|---|
| 142 |
txt += '<dd>%s</dd>\n' % (content) |
|---|
| 143 |
num += 1 |
|---|
| 144 |
txt += '</dl>' |
|---|
| 145 |
|
|---|
| 146 |
# Javascript |
|---|
| 147 |
txt += ''' |
|---|
| 148 |
<script type="text/javascript"> |
|---|
| 149 |
var settings = { |
|---|
| 150 |
alwaysOpen: true, |
|---|
| 151 |
animated: false |
|---|
| 152 |
}; |
|---|
| 153 |
|
|---|
| 154 |
open_tab = get_cookie('open_tab'); |
|---|
| 155 |
if (open_tab) { |
|---|
| 156 |
settings['active'] = parseInt(open_tab); |
|---|
| 157 |
} |
|---|
| 158 |
|
|---|
| 159 |
jQuery("#tab_%s").Accordion(settings).change( |
|---|
| 160 |
function (event, newHeader, oldHeader) { |
|---|
| 161 |
if (! newHeader) return; |
|---|
| 162 |
document.cookie = "open_tab=" + newHeader.attr("num"); |
|---|
| 163 |
}); |
|---|
| 164 |
</script> |
|---|
| 165 |
''' % (self._id) |
|---|
| 166 |
return txt |
|---|
| 167 |
|
|---|
| 168 |
def AddTableEntry (self, table, title, cfg_key, extra_cols=None): |
|---|
| 169 |
# Get the entry |
|---|
| 170 |
txt = self.InstanceEntry (cfg_key, 'text') |
|---|
| 171 |
|
|---|
| 172 |
# Add to the table |
|---|
| 173 |
label = self.Label(title, cfg_key); |
|---|
| 174 |
tup = (label, txt) |
|---|
| 175 |
if extra_cols: |
|---|
| 176 |
tup += extra_cols |
|---|
| 177 |
table += tup |
|---|
| 178 |
|
|---|
| 179 |
def InstanceButton (self, name, **kwargs): |
|---|
| 180 |
extra = "" |
|---|
| 181 |
for karg in kwargs: |
|---|
| 182 |
extra += '%s="%s" '%(karg, kwargs[karg]) |
|---|
| 183 |
return '<input type="button" value="%s" %s/>' % (name, extra) |
|---|
| 184 |
|
|---|
| 185 |
def InstanceImage (self, name, alt, **kwargs): |
|---|
| 186 |
extra = "" |
|---|
| 187 |
for karg in kwargs: |
|---|
| 188 |
extra += '%s="%s" '%(karg, kwargs[karg]) |
|---|
| 189 |
return '<img src="/static/images/%s" alt="%s" title="%s" %s/>' % (name, alt, alt, extra) |
|---|
| 190 |
|
|---|
| 191 |
def _get_auto_wrap_id (self): |
|---|
| 192 |
return "options_wrap_%d" % (FormHelper.options_wrap_num) |
|---|
| 193 |
|
|---|
| 194 |
def InstanceOptions (self, cfg_key, options, *args, **kwargs): |
|---|
| 195 |
value = self._cfg.get_val (cfg_key) |
|---|
| 196 |
if value != None: |
|---|
| 197 |
ops = EntryOptions (cfg_key, options, selected=value, *args, **kwargs) |
|---|
| 198 |
else: |
|---|
| 199 |
ops = EntryOptions (cfg_key, options, *args, **kwargs) |
|---|
| 200 |
|
|---|
| 201 |
# Auto wrap |
|---|
| 202 |
auto_wrap_id = self._get_auto_wrap_id() |
|---|
| 203 |
FormHelper.options_wrap_num += 1 |
|---|
| 204 |
|
|---|
| 205 |
ops = '<div id="%s" name="%s">%s</div>'%(auto_wrap_id, auto_wrap_id, ops) |
|---|
| 206 |
return (ops, value, auto_wrap_id) |
|---|
| 207 |
|
|---|
| 208 |
def AddTableOptions (self, table, title, cfg_key, options, *args, **kwargs): |
|---|
| 209 |
entry, value, wrap = self.InstanceOptions (cfg_key, options, *args, **kwargs) |
|---|
| 210 |
|
|---|
| 211 |
label = self.Label(title, cfg_key) |
|---|
| 212 |
table += (label, entry) |
|---|
| 213 |
|
|---|
| 214 |
return value |
|---|
| 215 |
|
|---|
| 216 |
def AddTableOptions_Ajax (self, table, title, cfg_key, options, *args, **kwargs): |
|---|
| 217 |
wrap_id = self._get_auto_wrap_id() |
|---|
| 218 |
js = "options_changed('/ajax/update','%s','%s');" % (cfg_key, wrap_id) |
|---|
| 219 |
kwargs['onChange'] = js |
|---|
| 220 |
|
|---|
| 221 |
return self.AddTableOptions (table, title, cfg_key, options, *args, **kwargs) |
|---|
| 222 |
|
|---|
| 223 |
def AddPropOptions_Ajax (self, table, title, cfg_key, options, comment, *args, **kwargs): |
|---|
| 224 |
wrap_id = self._get_auto_wrap_id() |
|---|
| 225 |
js = "options_changed('/ajax/update','%s','%s');" % (cfg_key, wrap_id) |
|---|
| 226 |
kwargs['onChange'] = js |
|---|
| 227 |
|
|---|
| 228 |
return self.AddPropOptions (table, title, cfg_key, options, comment, *args, **kwargs) |
|---|
| 229 |
|
|---|
| 230 |
def AddPropOptions_Reload (self, table, title, cfg_key, options, comment, **kwargs): |
|---|
| 231 |
assert (self.submit_url) |
|---|
| 232 |
|
|---|
| 233 |
# The Table entry itself |
|---|
| 234 |
auto_wrap_id = self._get_auto_wrap_id() |
|---|
| 235 |
js = "options_changed('/ajax/update','%s','%s');" % (cfg_key, auto_wrap_id) |
|---|
| 236 |
kwargs['onChange'] = js |
|---|
| 237 |
kwargs['noautosubmit'] = True |
|---|
| 238 |
name = self.AddPropOptions (table, title, cfg_key, options, comment, **kwargs) |
|---|
| 239 |
|
|---|
| 240 |
# If there was no cfg value, pick the first |
|---|
| 241 |
if not name: |
|---|
| 242 |
name = options[0][0] |
|---|
| 243 |
|
|---|
| 244 |
# Render active option |
|---|
| 245 |
if name: |
|---|
| 246 |
try: |
|---|
| 247 |
# Inherit the errors, if any |
|---|
| 248 |
kwargs['errors'] = self.errors |
|---|
| 249 |
props_widget = module_obj_factory (name, self._cfg, cfg_key, |
|---|
| 250 |
self.submit_url, **kwargs) |
|---|
| 251 |
render = props_widget._op_render() |
|---|
| 252 |
except IOError: |
|---|
| 253 |
render = "Couldn't load the properties module: %s" % (name) |
|---|
| 254 |
else: |
|---|
| 255 |
render = '' |
|---|
| 256 |
|
|---|
| 257 |
return render |
|---|
| 258 |
|
|---|
| 259 |
def AddTableOptions_Reload (self, table, title, cfg_key, options, **kwargs): |
|---|
| 260 |
assert (self.submit_url) |
|---|
| 261 |
print "DEPRECATED: AddTableOptions_Reload" |
|---|
| 262 |
|
|---|
| 263 |
# The Table entry itself |
|---|
| 264 |
auto_wrap_id = self._get_auto_wrap_id() |
|---|
| 265 |
js = "options_changed('/ajax/update','%s','%s');" % (cfg_key, auto_wrap_id) |
|---|
| 266 |
name = self.AddTableOptions (table, title, cfg_key, options, onChange=js) |
|---|
| 267 |
|
|---|
| 268 |
# If there was no cfg value, pick the first |
|---|
| 269 |
if not name: |
|---|
| 270 |
name = options[0][0] |
|---|
| 271 |
|
|---|
| 272 |
# Render active option |
|---|
| 273 |
if name: |
|---|
| 274 |
try: |
|---|
| 275 |
# Inherit the errors, if any |
|---|
| 276 |
kwargs['errors'] = self.errors |
|---|
| 277 |
props_widget = module_obj_factory (name, self._cfg, cfg_key, |
|---|
| 278 |
self.submit_url, **kwargs) |
|---|
| 279 |
render = props_widget._op_render() |
|---|
| 280 |
except IOError: |
|---|
| 281 |
render = "Couldn't load the properties module: %s" % (name) |
|---|
| 282 |
else: |
|---|
| 283 |
render = '' |
|---|
| 284 |
|
|---|
| 285 |
return render |
|---|
| 286 |
|
|---|
| 287 |
def InstanceCheckbox (self, cfg_key, default=None, quiet=False): |
|---|
| 288 |
try: |
|---|
| 289 |
tmp = self._cfg[cfg_key].value.lower() |
|---|
| 290 |
if tmp in ["on", "1", "true"]: |
|---|
| 291 |
value = '1' |
|---|
| 292 |
else: |
|---|
| 293 |
value = '0' |
|---|
| 294 |
except: |
|---|
| 295 |
value = None |
|---|
| 296 |
|
|---|
| 297 |
if value == '1': |
|---|
| 298 |
entry = Entry (cfg_key, 'checkbox', quiet=quiet, checked=value) |
|---|
| 299 |
elif value == '0': |
|---|
| 300 |
entry = Entry (cfg_key, 'checkbox', quiet=quiet) |
|---|
| 301 |
else: |
|---|
| 302 |
if default == True: |
|---|
| 303 |
entry = Entry (cfg_key, 'checkbox', quiet=quiet, checked='1') |
|---|
| 304 |
elif default == False: |
|---|
| 305 |
entry = Entry (cfg_key, 'checkbox', quiet=quiet) |
|---|
| 306 |
else: |
|---|
| 307 |
entry = Entry (cfg_key, 'checkbox', quiet=quiet) |
|---|
| 308 |
|
|---|
| 309 |
return entry |
|---|
| 310 |
|
|---|
| 311 |
def AddTableCheckbox (self, table, title, cfg_key, default=None): |
|---|
| 312 |
entry = self.InstanceCheckbox (cfg_key, default) |
|---|
| 313 |
label = self.Label(title, cfg_key); |
|---|
| 314 |
table += (label, entry) |
|---|
| 315 |
|
|---|
| 316 |
# Errors |
|---|
| 317 |
# |
|---|
| 318 |
|
|---|
| 319 |
def _error_add (self, key, wrong_val, msg): |
|---|
| 320 |
self.errors[key] = (msg, str(wrong_val)) |
|---|
| 321 |
|
|---|
| 322 |
def has_errors (self): |
|---|
| 323 |
return len(self.errors) > 0 |
|---|
| 324 |
|
|---|
| 325 |
# Applying changes |
|---|
| 326 |
# |
|---|
| 327 |
|
|---|
| 328 |
def Validate_NotEmpty (self, post, cfg_key, error_msg): |
|---|
| 329 |
try: |
|---|
| 330 |
cfg_val = self._cfg[cfg_key].value |
|---|
| 331 |
except: |
|---|
| 332 |
cfg_val = None |
|---|
| 333 |
|
|---|
| 334 |
if not cfg_val and \ |
|---|
| 335 |
not post.get_val(cfg_key): |
|---|
| 336 |
self._error_add (cfg_key, '', error_msg) |
|---|
| 337 |
|
|---|
| 338 |
def ValidateChange_SingleKey (self, key, post, validation): |
|---|
| 339 |
for regex, tmp in validation: |
|---|
| 340 |
pass_cfg = False |
|---|
| 341 |
nochroot = False |
|---|
| 342 |
|
|---|
| 343 |
if type(tmp) == types.FunctionType: |
|---|
| 344 |
validation_func = tmp |
|---|
| 345 |
|
|---|
| 346 |
elif type(tmp) == types.TupleType: |
|---|
| 347 |
validation_func = tmp[0] |
|---|
| 348 |
for k in tmp[1:]: |
|---|
| 349 |
if k == 'cfg': |
|---|
| 350 |
pass_cfg = True |
|---|
| 351 |
elif k == 'nochroot': |
|---|
| 352 |
nochroot = True |
|---|
| 353 |
else: |
|---|
| 354 |
print "UNKNOWN validation option:", k |
|---|
| 355 |
|
|---|
| 356 |
p = re.compile (regex) |
|---|
| 357 |
if p.match (key): |
|---|
| 358 |
value = post.get_val(key) |
|---|
| 359 |
if not value: |
|---|
| 360 |
continue |
|---|
| 361 |
try: |
|---|
| 362 |
if pass_cfg: |
|---|
| 363 |
tmp = validation_func (value, self._cfg, nochroot) |
|---|
| 364 |
else: |
|---|
| 365 |
tmp = validation_func (value) |
|---|
| 366 |
post[key] = [tmp] |
|---|
| 367 |
except ValueError, error: |
|---|
| 368 |
self._error_add (key, value, error) |
|---|
| 369 |
|
|---|
| 370 |
def _ValidateChanges (self, post, validation): |
|---|
| 371 |
for post_entry in post: |
|---|
| 372 |
self.ValidateChange_SingleKey (post_entry, post, validation) |
|---|
| 373 |
|
|---|
| 374 |
def ApplyCheckbox (self, post, cfg_key): |
|---|
| 375 |
if cfg_key in self.errors: |
|---|
| 376 |
return |
|---|
| 377 |
|
|---|
| 378 |
if cfg_key in post: |
|---|
| 379 |
value = post.pop(cfg_key) |
|---|
| 380 |
if value.lower() in ['on', '1']: |
|---|
| 381 |
self._cfg[cfg_key] = '1' |
|---|
| 382 |
else: |
|---|
| 383 |
self._cfg[cfg_key] = '0' |
|---|
| 384 |
else: |
|---|
| 385 |
self._cfg[cfg_key] = "0" |
|---|
| 386 |
|
|---|
| 387 |
def ApplyChanges (self, checkboxes, post, validation=None): |
|---|
| 388 |
# Validate changes |
|---|
| 389 |
if validation: |
|---|
| 390 |
self._ValidateChanges (post, validation) |
|---|
| 391 |
|
|---|
| 392 |
# Apply checkboxes |
|---|
| 393 |
for key in checkboxes: |
|---|
| 394 |
self.ApplyCheckbox (post, key) |
|---|
| 395 |
|
|---|
| 396 |
# Apply text entries |
|---|
| 397 |
for confkey in post: |
|---|
| 398 |
if not '!' in confkey: |
|---|
| 399 |
continue |
|---|
| 400 |
|
|---|
| 401 |
if confkey in self.errors: |
|---|
| 402 |
continue |
|---|
| 403 |
if not confkey in checkboxes: |
|---|
| 404 |
value = post[confkey][0] |
|---|
| 405 |
if not value: |
|---|
| 406 |
del (self._cfg[confkey]) |
|---|
| 407 |
else: |
|---|
| 408 |
self._cfg[confkey] = value |
|---|
| 409 |
|
|---|
| 410 |
def ApplyChangesDirectly (self, post): |
|---|
| 411 |
for confkey in post: |
|---|
| 412 |
if not '!' in confkey: |
|---|
| 413 |
continue |
|---|
| 414 |
|
|---|
| 415 |
if confkey in self.errors: |
|---|
| 416 |
continue |
|---|
| 417 |
|
|---|
| 418 |
value = post[confkey][0] |
|---|
| 419 |
if not value: |
|---|
| 420 |
del (self._cfg[confkey]) |
|---|
| 421 |
else: |
|---|
| 422 |
self._cfg[confkey] = value |
|---|
| 423 |
|
|---|
| 424 |
def ApplyChangesPrefix (self, prefix, checkboxes, post, validation=None): |
|---|
| 425 |
checkboxes_pre = ["%s!%s"%(prefix, x) for x in checkboxes] |
|---|
| 426 |
return self.ApplyChanges (checkboxes_pre, post, validation) |
|---|
| 427 |
|
|---|
| 428 |
def ApplyChanges_OptionModule (self, cfg_key, uri, post): |
|---|
| 429 |
# Read the option entry value |
|---|
| 430 |
name = self._cfg.get_val(cfg_key) |
|---|
| 431 |
if not name: return |
|---|
| 432 |
|
|---|
| 433 |
# Instance module and apply the changes |
|---|
| 434 |
module = module_obj_factory (name, self._cfg, cfg_key, self.submit_url) |
|---|
| 435 |
module._op_apply_changes (uri, post) |
|---|
| 436 |
|
|---|
| 437 |
# Include module errors |
|---|
| 438 |
for error in module.errors: |
|---|
| 439 |
self.errors[error] = module.errors[error] |
|---|
| 440 |
|
|---|
| 441 |
# Clean up properties |
|---|
| 442 |
props = module.__class__.PROPERTIES |
|---|
| 443 |
|
|---|
| 444 |
to_be_deleted = [] |
|---|
| 445 |
for entry in self._cfg[cfg_key]: |
|---|
| 446 |
prop_cfg = "%s!%s" % (cfg_key, entry) |
|---|
| 447 |
if entry not in props: |
|---|
| 448 |
to_be_deleted.append (prop_cfg) |
|---|
| 449 |
|
|---|
| 450 |
for entry in to_be_deleted: |
|---|
| 451 |
del(self._cfg[entry]) |
|---|
| 452 |
|
|---|
| 453 |
def AddProp (self, table, title, cfg_key, entry, comment=None): |
|---|
| 454 |
label = self.Label (title, cfg_key); |
|---|
| 455 |
table += (label, entry, comment) |
|---|
| 456 |
|
|---|
| 457 |
def AddPropEntry (self, table, title, cfg_key, comment=None, **kwargs): |
|---|
| 458 |
entry = self.InstanceEntry (cfg_key, 'text', **kwargs) |
|---|
| 459 |
self.AddProp (table, title, cfg_key, entry, comment) |
|---|
| 460 |
|
|---|
| 461 |
def AddPropCheck (self, table, title, cfg_key, default, comment=None): |
|---|
| 462 |
entry = self.InstanceCheckbox (cfg_key, default) |
|---|
| 463 |
self.AddProp (table, title, cfg_key, entry, comment) |
|---|
| 464 |
|
|---|
| 465 |
def AddPropOptions (self, table, title, cfg_key, options, comment=None, **kwargs): |
|---|
| 466 |
entry, v, w = self.InstanceOptions (cfg_key, options, **kwargs) |
|---|
| 467 |
self.AddProp (table, title, cfg_key, entry, comment) |
|---|
| 468 |
return v |
|---|
| 469 |
|
|---|
| 470 |
|
|---|
| 471 |
class TableProps: |
|---|
| 472 |
def __init__ (self): |
|---|
| 473 |
self._content = [] |
|---|
| 474 |
|
|---|
| 475 |
def __add__ (self, (title, content, comment)): |
|---|
| 476 |
self._content.append((title, content, comment)) |
|---|
| 477 |
|
|---|
| 478 |
def _render_entry (self, (title, content, comment)): |
|---|
| 479 |
txt = '<table class="tableprop">' |
|---|
| 480 |
txt += ' <tr><th class="title">%s</th><td>%s</td></tr>' % (title, content) |
|---|
| 481 |
txt += ' <tr><td colspan="2"><div class="comment">%s</div></td></tr>' % (comment) |
|---|
| 482 |
txt += '</table>' |
|---|
| 483 |
return txt |
|---|
| 484 |
|
|---|
| 485 |
def __str__ (self): |
|---|
| 486 |
tmp = [] |
|---|
| 487 |
for entry in self._content: |
|---|
| 488 |
tmp.append (self._render_entry(entry)) |
|---|
| 489 |
|
|---|
| 490 |
txt = "<hr />".join(tmp) |
|---|
| 491 |
return '<div class="tableprop_block">%s</div>' % (txt) |
|---|
| 492 |
|
|---|