Mercurial > p > roundup > code
comparison roundup/cgi/templating.py @ 1079:04b44df7af1d
removed some property name clashes
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Mon, 09 Sep 2002 05:28:48 +0000 |
| parents | 344bad728d10 |
| children | 24c9e81fce85 |
comparison
equal
deleted
inserted
replaced
| 1078:344bad728d10 | 1079:04b44df7af1d |
|---|---|
| 185 | 185 |
| 186 class HTMLDatabase: | 186 class HTMLDatabase: |
| 187 ''' Return HTMLClasses for valid class fetches | 187 ''' Return HTMLClasses for valid class fetches |
| 188 ''' | 188 ''' |
| 189 def __init__(self, client): | 189 def __init__(self, client): |
| 190 self.client = client | 190 self._client = client |
| 191 | |
| 192 # we want config to be exposed | |
| 191 self.config = client.db.config | 193 self.config = client.db.config |
| 194 | |
| 192 def __getattr__(self, attr): | 195 def __getattr__(self, attr): |
| 193 try: | 196 try: |
| 194 self.client.db.getclass(attr) | 197 self._client.db.getclass(attr) |
| 195 except KeyError: | 198 except KeyError: |
| 196 raise AttributeError, attr | 199 raise AttributeError, attr |
| 197 return HTMLClass(self.client, attr) | 200 return HTMLClass(self._client, attr) |
| 198 def classes(self): | 201 def classes(self): |
| 199 l = self.client.db.classes.keys() | 202 l = self._client.db.classes.keys() |
| 200 l.sort() | 203 l.sort() |
| 201 return [HTMLClass(self.client, cn) for cn in l] | 204 return [HTMLClass(self._client, cn) for cn in l] |
| 202 | 205 |
| 203 class HTMLClass: | 206 class HTMLClass: |
| 204 ''' Accesses through a class (either through *class* or *db.<classname>*) | 207 ''' Accesses through a class (either through *class* or *db.<classname>*) |
| 205 ''' | 208 ''' |
| 206 def __init__(self, client, classname): | 209 def __init__(self, client, classname): |
| 207 self.client = client | 210 self._client = client |
| 208 self.db = client.db | 211 self._db = client.db |
| 212 | |
| 213 # we want classname to be exposed | |
| 209 self.classname = classname | 214 self.classname = classname |
| 210 if classname is not None: | 215 if classname is not None: |
| 211 self.klass = self.db.getclass(self.classname) | 216 self._klass = self._db.getclass(self.classname) |
| 212 self.props = self.klass.getprops() | 217 self._props = self._klass.getprops() |
| 213 | 218 |
| 214 def __repr__(self): | 219 def __repr__(self): |
| 215 return '<HTMLClass(0x%x) %s>'%(id(self), self.classname) | 220 return '<HTMLClass(0x%x) %s>'%(id(self), self.classname) |
| 216 | 221 |
| 217 def __getitem__(self, item): | 222 def __getitem__(self, item): |
| 222 # we don't exist | 227 # we don't exist |
| 223 if item == 'id': | 228 if item == 'id': |
| 224 return None | 229 return None |
| 225 if item == 'creator': | 230 if item == 'creator': |
| 226 # but we will be created by this user... | 231 # but we will be created by this user... |
| 227 return HTMLUser(self.client, 'user', self.client.userid) | 232 return HTMLUser(self._client, 'user', self._client.userid) |
| 228 | 233 |
| 229 # get the property | 234 # get the property |
| 230 prop = self.props[item] | 235 prop = self._props[item] |
| 231 | 236 |
| 232 # look up the correct HTMLProperty class | 237 # look up the correct HTMLProperty class |
| 233 for klass, htmlklass in propclasses: | 238 for klass, htmlklass in propclasses: |
| 234 if isinstance(prop, hyperdb.Multilink): | 239 if isinstance(prop, hyperdb.Multilink): |
| 235 value = [] | 240 value = [] |
| 236 else: | 241 else: |
| 237 value = None | 242 value = None |
| 238 if isinstance(prop, klass): | 243 if isinstance(prop, klass): |
| 239 return htmlklass(self.client, '', prop, item, value) | 244 return htmlklass(self._client, '', prop, item, value) |
| 240 | 245 |
| 241 # no good | 246 # no good |
| 242 raise KeyError, item | 247 raise KeyError, item |
| 243 | 248 |
| 244 def __getattr__(self, attr): | 249 def __getattr__(self, attr): |
| 250 | 255 |
| 251 def properties(self): | 256 def properties(self): |
| 252 ''' Return HTMLProperty for all props | 257 ''' Return HTMLProperty for all props |
| 253 ''' | 258 ''' |
| 254 l = [] | 259 l = [] |
| 255 for name, prop in self.props.items(): | 260 for name, prop in self._props.items(): |
| 256 for klass, htmlklass in propclasses: | 261 for klass, htmlklass in propclasses: |
| 257 if isinstance(prop, hyperdb.Multilink): | 262 if isinstance(prop, hyperdb.Multilink): |
| 258 value = [] | 263 value = [] |
| 259 else: | 264 else: |
| 260 value = None | 265 value = None |
| 261 if isinstance(prop, klass): | 266 if isinstance(prop, klass): |
| 262 l.append(htmlklass(self.client, '', prop, name, value)) | 267 l.append(htmlklass(self._client, '', prop, name, value)) |
| 263 return l | 268 return l |
| 264 | 269 |
| 265 def list(self): | 270 def list(self): |
| 266 if self.classname == 'user': | 271 if self.classname == 'user': |
| 267 klass = HTMLUser | 272 klass = HTMLUser |
| 268 else: | 273 else: |
| 269 klass = HTMLItem | 274 klass = HTMLItem |
| 270 l = [klass(self.client, self.classname, x) for x in self.klass.list()] | 275 l = [klass(self._client, self.classname, x) for x in self._klass.list()] |
| 271 return l | 276 return l |
| 272 | 277 |
| 273 def csv(self): | 278 def csv(self): |
| 274 ''' Return the items of this class as a chunk of CSV text. | 279 ''' Return the items of this class as a chunk of CSV text. |
| 275 ''' | 280 ''' |
| 282 | 287 |
| 283 props = self.propnames() | 288 props = self.propnames() |
| 284 p = csv.parser() | 289 p = csv.parser() |
| 285 s = StringIO.StringIO() | 290 s = StringIO.StringIO() |
| 286 s.write(p.join(props) + '\n') | 291 s.write(p.join(props) + '\n') |
| 287 for nodeid in self.klass.list(): | 292 for nodeid in self._klass.list(): |
| 288 l = [] | 293 l = [] |
| 289 for name in props: | 294 for name in props: |
| 290 value = self.klass.get(nodeid, name) | 295 value = self._klass.get(nodeid, name) |
| 291 if value is None: | 296 if value is None: |
| 292 l.append('') | 297 l.append('') |
| 293 elif isinstance(value, type([])): | 298 elif isinstance(value, type([])): |
| 294 l.append(':'.join(map(str, value))) | 299 l.append(':'.join(map(str, value))) |
| 295 else: | 300 else: |
| 296 l.append(str(self.klass.get(nodeid, name))) | 301 l.append(str(self._klass.get(nodeid, name))) |
| 297 s.write(p.join(l) + '\n') | 302 s.write(p.join(l) + '\n') |
| 298 return s.getvalue() | 303 return s.getvalue() |
| 299 | 304 |
| 300 def propnames(self): | 305 def propnames(self): |
| 301 ''' Return the list of the names of the properties of this class. | 306 ''' Return the list of the names of the properties of this class. |
| 302 ''' | 307 ''' |
| 303 idlessprops = self.klass.getprops(protected=0).keys() | 308 idlessprops = self._klass.getprops(protected=0).keys() |
| 304 idlessprops.sort() | 309 idlessprops.sort() |
| 305 return ['id'] + idlessprops | 310 return ['id'] + idlessprops |
| 306 | 311 |
| 307 def filter(self, request=None): | 312 def filter(self, request=None): |
| 308 ''' Return a list of items from this class, filtered and sorted | 313 ''' Return a list of items from this class, filtered and sorted |
| 314 group = request.group | 319 group = request.group |
| 315 if self.classname == 'user': | 320 if self.classname == 'user': |
| 316 klass = HTMLUser | 321 klass = HTMLUser |
| 317 else: | 322 else: |
| 318 klass = HTMLItem | 323 klass = HTMLItem |
| 319 l = [klass(self.client, self.classname, x) | 324 l = [klass(self._client, self.classname, x) |
| 320 for x in self.klass.filter(None, filterspec, sort, group)] | 325 for x in self._klass.filter(None, filterspec, sort, group)] |
| 321 return l | 326 return l |
| 322 | 327 |
| 323 def classhelp(self, properties, label='?', width='400', height='400'): | 328 def classhelp(self, properties, label='?', width='400', height='400'): |
| 324 '''pop up a javascript window with class help | 329 '''pop up a javascript window with class help |
| 325 | 330 |
| 346 | 351 |
| 347 def renderWith(self, name, **kwargs): | 352 def renderWith(self, name, **kwargs): |
| 348 ''' Render this class with the given template. | 353 ''' Render this class with the given template. |
| 349 ''' | 354 ''' |
| 350 # create a new request and override the specified args | 355 # create a new request and override the specified args |
| 351 req = HTMLRequest(self.client) | 356 req = HTMLRequest(self._client) |
| 352 req.classname = self.classname | 357 req.classname = self.classname |
| 353 req.update(kwargs) | 358 req.update(kwargs) |
| 354 | 359 |
| 355 # new template, using the specified classname and request | 360 # new template, using the specified classname and request |
| 356 pt = getTemplate(self.db.config.TEMPLATES, self.classname, name) | 361 pt = getTemplate(self._db.config.TEMPLATES, self.classname, name) |
| 357 | 362 |
| 358 # XXX handle PT rendering errors here nicely | 363 # XXX handle PT rendering errors here nicely |
| 359 try: | 364 try: |
| 360 # use our fabricated request | 365 # use our fabricated request |
| 361 return pt.render(self.client, self.classname, req) | 366 return pt.render(self._client, self.classname, req) |
| 362 except PageTemplate.PTRuntimeError, message: | 367 except PageTemplate.PTRuntimeError, message: |
| 363 return '<strong>%s</strong><ol>%s</ol>'%(message, | 368 return '<strong>%s</strong><ol>%s</ol>'%(message, |
| 364 cgi.escape('<li>'.join(pt._v_errors))) | 369 cgi.escape('<li>'.join(pt._v_errors))) |
| 365 | 370 |
| 366 class HTMLItem: | 371 class HTMLItem: |
| 367 ''' Accesses through an *item* | 372 ''' Accesses through an *item* |
| 368 ''' | 373 ''' |
| 369 def __init__(self, client, classname, nodeid): | 374 def __init__(self, client, classname, nodeid): |
| 370 self.client = client | 375 self._client = client |
| 371 self.db = client.db | 376 self._db = client.db |
| 372 self.classname = classname | 377 self._classname = classname |
| 373 self.nodeid = nodeid | 378 self._nodeid = nodeid |
| 374 self.klass = self.db.getclass(classname) | 379 self._klass = self._db.getclass(classname) |
| 375 self.props = self.klass.getprops() | 380 self._props = self._klass.getprops() |
| 376 | 381 |
| 377 def __repr__(self): | 382 def __repr__(self): |
| 378 return '<HTMLItem(0x%x) %s %s>'%(id(self), self.classname, self.nodeid) | 383 return '<HTMLItem(0x%x) %s %s>'%(id(self), self._classname, |
| 384 self._nodeid) | |
| 379 | 385 |
| 380 def __getitem__(self, item): | 386 def __getitem__(self, item): |
| 381 ''' return an HTMLProperty instance | 387 ''' return an HTMLProperty instance |
| 382 ''' | 388 ''' |
| 383 #print 'getitem', (self, item) | 389 #print 'getitem', (self, item) |
| 384 if item == 'id': | 390 if item == 'id': |
| 385 return self.nodeid | 391 return self._nodeid |
| 386 | 392 |
| 387 # get the property | 393 # get the property |
| 388 prop = self.props[item] | 394 prop = self._props[item] |
| 389 | 395 |
| 390 # get the value, handling missing values | 396 # get the value, handling missing values |
| 391 value = self.klass.get(self.nodeid, item, None) | 397 value = self._klass.get(self._nodeid, item, None) |
| 392 if value is None: | 398 if value is None: |
| 393 if isinstance(self.props[item], hyperdb.Multilink): | 399 if isinstance(self._props[item], hyperdb.Multilink): |
| 394 value = [] | 400 value = [] |
| 395 | 401 |
| 396 # look up the correct HTMLProperty class | 402 # look up the correct HTMLProperty class |
| 397 for klass, htmlklass in propclasses: | 403 for klass, htmlklass in propclasses: |
| 398 if isinstance(prop, klass): | 404 if isinstance(prop, klass): |
| 399 return htmlklass(self.client, self.nodeid, prop, item, value) | 405 return htmlklass(self._client, self._nodeid, prop, item, value) |
| 400 | 406 |
| 401 raise KeyErorr, item | 407 raise KeyErorr, item |
| 402 | 408 |
| 403 def __getattr__(self, attr): | 409 def __getattr__(self, attr): |
| 404 ''' convenience access to properties ''' | 410 ''' convenience access to properties ''' |
| 423 _('<th>User</th>'), | 429 _('<th>User</th>'), |
| 424 _('<th>Action</th>'), | 430 _('<th>Action</th>'), |
| 425 _('<th>Args</th>'), | 431 _('<th>Args</th>'), |
| 426 '</tr>'] | 432 '</tr>'] |
| 427 comments = {} | 433 comments = {} |
| 428 history = self.klass.history(self.nodeid) | 434 history = self._klass.history(self._nodeid) |
| 429 history.sort() | 435 history.sort() |
| 430 if direction == 'descending': | 436 if direction == 'descending': |
| 431 history.reverse() | 437 history.reverse() |
| 432 for id, evt_date, user, action, args in history: | 438 for id, evt_date, user, action, args in history: |
| 433 date_s = str(evt_date).replace("."," ") | 439 date_s = str(evt_date).replace("."," ") |
| 452 cell = [] | 458 cell = [] |
| 453 for k in args.keys(): | 459 for k in args.keys(): |
| 454 # try to get the relevant property and treat it | 460 # try to get the relevant property and treat it |
| 455 # specially | 461 # specially |
| 456 try: | 462 try: |
| 457 prop = self.props[k] | 463 prop = self._props[k] |
| 458 except KeyError: | 464 except KeyError: |
| 459 prop = None | 465 prop = None |
| 460 if prop is not None: | 466 if prop is not None: |
| 461 if args[k] and (isinstance(prop, hyperdb.Multilink) or | 467 if args[k] and (isinstance(prop, hyperdb.Multilink) or |
| 462 isinstance(prop, hyperdb.Link)): | 468 isinstance(prop, hyperdb.Link)): |
| 463 # figure what the link class is | 469 # figure what the link class is |
| 464 classname = prop.classname | 470 classname = prop.classname |
| 465 try: | 471 try: |
| 466 linkcl = self.db.getclass(classname) | 472 linkcl = self._db.getclass(classname) |
| 467 except KeyError: | 473 except KeyError: |
| 468 labelprop = None | 474 labelprop = None |
| 469 comments[classname] = _('''The linked class | 475 comments[classname] = _('''The linked class |
| 470 %(classname)s no longer exists''')%locals() | 476 %(classname)s no longer exists''')%locals() |
| 471 labelprop = linkcl.labelprop(1) | 477 labelprop = linkcl.labelprop(1) |
| 472 hrefable = os.path.exists( | 478 hrefable = os.path.exists( |
| 473 os.path.join(self.db.config.TEMPLATES, | 479 os.path.join(self._db.config.TEMPLATES, |
| 474 classname+'.item')) | 480 classname+'.item')) |
| 475 | 481 |
| 476 if isinstance(prop, hyperdb.Multilink) and \ | 482 if isinstance(prop, hyperdb.Multilink) and \ |
| 477 len(args[k]) > 0: | 483 len(args[k]) > 0: |
| 478 ml = [] | 484 ml = [] |
| 565 class HTMLUser(HTMLItem): | 571 class HTMLUser(HTMLItem): |
| 566 ''' Accesses through the *user* (a special case of item) | 572 ''' Accesses through the *user* (a special case of item) |
| 567 ''' | 573 ''' |
| 568 def __init__(self, client, classname, nodeid): | 574 def __init__(self, client, classname, nodeid): |
| 569 HTMLItem.__init__(self, client, 'user', nodeid) | 575 HTMLItem.__init__(self, client, 'user', nodeid) |
| 570 self.default_classname = client.classname | 576 self._default_classname = client.classname |
| 571 | 577 |
| 572 # used for security checks | 578 # used for security checks |
| 573 self.security = client.db.security | 579 self._security = client.db.security |
| 574 _marker = [] | 580 _marker = [] |
| 575 def hasPermission(self, role, classname=_marker): | 581 def hasPermission(self, role, classname=_marker): |
| 576 ''' Determine if the user has the Role. | 582 ''' Determine if the user has the Role. |
| 577 | 583 |
| 578 The class being tested defaults to the template's class, but may | 584 The class being tested defaults to the template's class, but may |
| 579 be overidden for this test by suppling an alternate classname. | 585 be overidden for this test by suppling an alternate classname. |
| 580 ''' | 586 ''' |
| 581 if classname is self._marker: | 587 if classname is self._marker: |
| 582 classname = self.default_classname | 588 classname = self._default_classname |
| 583 return self.security.hasPermission(role, self.nodeid, classname) | 589 return self._security.hasPermission(role, self._nodeid, classname) |
| 584 | 590 |
| 585 class HTMLProperty: | 591 class HTMLProperty: |
| 586 ''' String, Number, Date, Interval HTMLProperty | 592 ''' String, Number, Date, Interval HTMLProperty |
| 587 | 593 |
| 588 A wrapper object which may be stringified for the plain() behaviour. | 594 A wrapper object which may be stringified for the plain() behaviour. |
| 589 ''' | 595 ''' |
| 590 def __init__(self, client, nodeid, prop, name, value): | 596 def __init__(self, client, nodeid, prop, name, value): |
| 591 self.client = client | 597 self._client = client |
| 592 self.db = client.db | 598 self._db = client.db |
| 593 self.nodeid = nodeid | 599 self._nodeid = nodeid |
| 594 self.prop = prop | 600 self._prop = prop |
| 595 self.name = name | 601 self._name = name |
| 596 self.value = value | 602 self._value = value |
| 597 def __repr__(self): | 603 def __repr__(self): |
| 598 return '<HTMLProperty(0x%x) %s %r %r>'%(id(self), self.name, self.prop, self.value) | 604 return '<HTMLProperty(0x%x) %s %r %r>'%(id(self), self._name, self._prop, self._value) |
| 599 def __str__(self): | 605 def __str__(self): |
| 600 return self.plain() | 606 return self.plain() |
| 601 def __cmp__(self, other): | 607 def __cmp__(self, other): |
| 602 if isinstance(other, HTMLProperty): | 608 if isinstance(other, HTMLProperty): |
| 603 return cmp(self.value, other.value) | 609 return cmp(self._value, other._value) |
| 604 return cmp(self.value, other) | 610 return cmp(self._value, other) |
| 605 | 611 |
| 606 class StringHTMLProperty(HTMLProperty): | 612 class StringHTMLProperty(HTMLProperty): |
| 607 def plain(self, escape=0): | 613 def plain(self, escape=0): |
| 608 if self.value is None: | 614 if self._value is None: |
| 609 return '' | 615 return '' |
| 610 if escape: | 616 if escape: |
| 611 return cgi.escape(str(self.value)) | 617 return cgi.escape(str(self._value)) |
| 612 return str(self.value) | 618 return str(self._value) |
| 613 | 619 |
| 614 def stext(self, escape=0): | 620 def stext(self, escape=0): |
| 615 s = self.plain(escape=escape) | 621 s = self.plain(escape=escape) |
| 616 if not StructuredText: | 622 if not StructuredText: |
| 617 return s | 623 return s |
| 618 return StructuredText(s,level=1,header=0) | 624 return StructuredText(s,level=1,header=0) |
| 619 | 625 |
| 620 def field(self, size = 30): | 626 def field(self, size = 30): |
| 621 if self.value is None: | 627 if self._value is None: |
| 622 value = '' | 628 value = '' |
| 623 else: | 629 else: |
| 624 value = cgi.escape(str(self.value)) | 630 value = cgi.escape(str(self._value)) |
| 625 value = '"'.join(value.split('"')) | 631 value = '"'.join(value.split('"')) |
| 626 return '<input name="%s" value="%s" size="%s">'%(self.name, value, size) | 632 return '<input name="%s" value="%s" size="%s">'%(self._name, value, size) |
| 627 | 633 |
| 628 def multiline(self, escape=0, rows=5, cols=40): | 634 def multiline(self, escape=0, rows=5, cols=40): |
| 629 if self.value is None: | 635 if self._value is None: |
| 630 value = '' | 636 value = '' |
| 631 else: | 637 else: |
| 632 value = cgi.escape(str(self.value)) | 638 value = cgi.escape(str(self._value)) |
| 633 value = '"'.join(value.split('"')) | 639 value = '"'.join(value.split('"')) |
| 634 return '<textarea name="%s" rows="%s" cols="%s">%s</textarea>'%( | 640 return '<textarea name="%s" rows="%s" cols="%s">%s</textarea>'%( |
| 635 self.name, rows, cols, value) | 641 self._name, rows, cols, value) |
| 636 | 642 |
| 637 def email(self, escape=1): | 643 def email(self, escape=1): |
| 638 ''' fudge email ''' | 644 ''' fudge email ''' |
| 639 if self.value is None: value = '' | 645 if self.value is None: value = '' |
| 640 else: value = str(self.value) | 646 else: value = str(self._value) |
| 641 value = value.replace('@', ' at ') | 647 value = value.replace('@', ' at ') |
| 642 value = value.replace('.', ' ') | 648 value = value.replace('.', ' ') |
| 643 if escape: | 649 if escape: |
| 644 value = cgi.escape(value) | 650 value = cgi.escape(value) |
| 645 return value | 651 return value |
| 646 | 652 |
| 647 class PasswordHTMLProperty(HTMLProperty): | 653 class PasswordHTMLProperty(HTMLProperty): |
| 648 def plain(self): | 654 def plain(self): |
| 649 if self.value is None: | 655 if self._value is None: |
| 650 return '' | 656 return '' |
| 651 return _('*encrypted*') | 657 return _('*encrypted*') |
| 652 | 658 |
| 653 def field(self, size = 30): | 659 def field(self, size = 30): |
| 654 return '<input type="password" name="%s" size="%s">'%(self.name, size) | 660 return '<input type="password" name="%s" size="%s">'%(self._name, size) |
| 655 | 661 |
| 656 class NumberHTMLProperty(HTMLProperty): | 662 class NumberHTMLProperty(HTMLProperty): |
| 657 def plain(self): | 663 def plain(self): |
| 658 return str(self.value) | 664 return str(self._value) |
| 659 | 665 |
| 660 def field(self, size = 30): | 666 def field(self, size = 30): |
| 661 if self.value is None: | 667 if self._value is None: |
| 662 value = '' | 668 value = '' |
| 663 else: | 669 else: |
| 664 value = cgi.escape(str(self.value)) | 670 value = cgi.escape(str(self._value)) |
| 665 value = '"'.join(value.split('"')) | 671 value = '"'.join(value.split('"')) |
| 666 return '<input name="%s" value="%s" size="%s">'%(self.name, value, size) | 672 return '<input name="%s" value="%s" size="%s">'%(self._name, value, size) |
| 667 | 673 |
| 668 class BooleanHTMLProperty(HTMLProperty): | 674 class BooleanHTMLProperty(HTMLProperty): |
| 669 def plain(self): | 675 def plain(self): |
| 670 if self.value is None: | 676 if self.value is None: |
| 671 return '' | 677 return '' |
| 672 return self.value and "Yes" or "No" | 678 return self._value and "Yes" or "No" |
| 673 | 679 |
| 674 def field(self): | 680 def field(self): |
| 675 checked = self.value and "checked" or "" | 681 checked = self._value and "checked" or "" |
| 676 s = '<input type="radio" name="%s" value="yes" %s>Yes'%(self.name, | 682 s = '<input type="radio" name="%s" value="yes" %s>Yes'%(self._name, |
| 677 checked) | 683 checked) |
| 678 if checked: | 684 if checked: |
| 679 checked = "" | 685 checked = "" |
| 680 else: | 686 else: |
| 681 checked = "checked" | 687 checked = "checked" |
| 682 s += '<input type="radio" name="%s" value="no" %s>No'%(self.name, | 688 s += '<input type="radio" name="%s" value="no" %s>No'%(self._name, |
| 683 checked) | 689 checked) |
| 684 return s | 690 return s |
| 685 | 691 |
| 686 class DateHTMLProperty(HTMLProperty): | 692 class DateHTMLProperty(HTMLProperty): |
| 687 def plain(self): | 693 def plain(self): |
| 688 if self.value is None: | 694 if self._value is None: |
| 689 return '' | 695 return '' |
| 690 return str(self.value) | 696 return str(self._value) |
| 691 | 697 |
| 692 def field(self, size = 30): | 698 def field(self, size = 30): |
| 693 if self.value is None: | 699 if self._value is None: |
| 694 value = '' | 700 value = '' |
| 695 else: | 701 else: |
| 696 value = cgi.escape(str(self.value)) | 702 value = cgi.escape(str(self._value)) |
| 697 value = '"'.join(value.split('"')) | 703 value = '"'.join(value.split('"')) |
| 698 return '<input name="%s" value="%s" size="%s">'%(self.name, value, size) | 704 return '<input name="%s" value="%s" size="%s">'%(self._name, value, size) |
| 699 | 705 |
| 700 def reldate(self, pretty=1): | 706 def reldate(self, pretty=1): |
| 701 if not self.value: | 707 if not self._value: |
| 702 return '' | 708 return '' |
| 703 | 709 |
| 704 # figure the interval | 710 # figure the interval |
| 705 interval = date.Date('.') - self.value | 711 interval = date.Date('.') - self._value |
| 706 if pretty: | 712 if pretty: |
| 707 return interval.pretty() | 713 return interval.pretty() |
| 708 return str(interval) | 714 return str(interval) |
| 709 | 715 |
| 710 class IntervalHTMLProperty(HTMLProperty): | 716 class IntervalHTMLProperty(HTMLProperty): |
| 711 def plain(self): | 717 def plain(self): |
| 712 if self.value is None: | 718 if self._value is None: |
| 713 return '' | 719 return '' |
| 714 return str(self.value) | 720 return str(self._value) |
| 715 | 721 |
| 716 def pretty(self): | 722 def pretty(self): |
| 717 return self.value.pretty() | 723 return self._value.pretty() |
| 718 | 724 |
| 719 def field(self, size = 30): | 725 def field(self, size = 30): |
| 720 if self.value is None: | 726 if self._value is None: |
| 721 value = '' | 727 value = '' |
| 722 else: | 728 else: |
| 723 value = cgi.escape(str(self.value)) | 729 value = cgi.escape(str(self._value)) |
| 724 value = '"'.join(value.split('"')) | 730 value = '"'.join(value.split('"')) |
| 725 return '<input name="%s" value="%s" size="%s">'%(self.name, value, size) | 731 return '<input name="%s" value="%s" size="%s">'%(self._name, value, size) |
| 726 | 732 |
| 727 class LinkHTMLProperty(HTMLProperty): | 733 class LinkHTMLProperty(HTMLProperty): |
| 728 ''' Link HTMLProperty | 734 ''' Link HTMLProperty |
| 729 Include the above as well as being able to access the class | 735 Include the above as well as being able to access the class |
| 730 information. Stringifying the object itself results in the value | 736 information. Stringifying the object itself results in the value |
| 734 entry identified by the assignedto property on item, and then the | 740 entry identified by the assignedto property on item, and then the |
| 735 name property of that user) | 741 name property of that user) |
| 736 ''' | 742 ''' |
| 737 def __getattr__(self, attr): | 743 def __getattr__(self, attr): |
| 738 ''' return a new HTMLItem ''' | 744 ''' return a new HTMLItem ''' |
| 739 #print 'getattr', (self, attr, self.value) | 745 #print 'getattr', (self, attr, self._value) |
| 740 if not self.value: | 746 if not self._value: |
| 741 raise AttributeError, "Can't access missing value" | 747 raise AttributeError, "Can't access missing value" |
| 742 if self.prop.classname == 'user': | 748 if self._prop.classname == 'user': |
| 743 klass = HTMLItem | 749 klass = HTMLItem |
| 744 else: | 750 else: |
| 745 klass = HTMLUser | 751 klass = HTMLUser |
| 746 i = klass(self.client, self.prop.classname, self.value) | 752 i = klass(self._client, self._prop.classname, self._value) |
| 747 return getattr(i, attr) | 753 return getattr(i, attr) |
| 748 | 754 |
| 749 def plain(self, escape=0): | 755 def plain(self, escape=0): |
| 750 if self.value is None: | 756 if self._value is None: |
| 751 return _('[unselected]') | 757 return _('[unselected]') |
| 752 linkcl = self.db.classes[self.prop.classname] | 758 linkcl = self._db.classes[self._prop.classname] |
| 753 k = linkcl.labelprop(1) | 759 k = linkcl.labelprop(1) |
| 754 value = str(linkcl.get(self.value, k)) | 760 value = str(linkcl.get(self._value, k)) |
| 755 if escape: | 761 if escape: |
| 756 value = cgi.escape(value) | 762 value = cgi.escape(value) |
| 757 return value | 763 return value |
| 758 | 764 |
| 759 def field(self): | 765 def field(self): |
| 760 linkcl = self.db.getclass(self.prop.classname) | 766 linkcl = self._db.getclass(self._prop.classname) |
| 761 if linkcl.getprops().has_key('order'): | 767 if linkcl.getprops().has_key('order'): |
| 762 sort_on = 'order' | 768 sort_on = 'order' |
| 763 else: | 769 else: |
| 764 sort_on = linkcl.labelprop() | 770 sort_on = linkcl.labelprop() |
| 765 options = linkcl.filter(None, {}, [sort_on], []) | 771 options = linkcl.filter(None, {}, [sort_on], []) |
| 775 option = linkcl.get(optionid, k) | 781 option = linkcl.get(optionid, k) |
| 776 s = '' | 782 s = '' |
| 777 if optionid == value: | 783 if optionid == value: |
| 778 s = 'selected ' | 784 s = 'selected ' |
| 779 if showid: | 785 if showid: |
| 780 lab = '%s%s: %s'%(self.prop.classname, optionid, option) | 786 lab = '%s%s: %s'%(self._prop.classname, optionid, option) |
| 781 else: | 787 else: |
| 782 lab = option | 788 lab = option |
| 783 if size is not None and len(lab) > size: | 789 if size is not None and len(lab) > size: |
| 784 lab = lab[:size-3] + '...' | 790 lab = lab[:size-3] + '...' |
| 785 lab = cgi.escape(lab) | 791 lab = cgi.escape(lab) |
| 786 l.append('<option %svalue="%s">%s</option>'%(s, optionid, lab)) | 792 l.append('<option %svalue="%s">%s</option>'%(s, optionid, lab)) |
| 787 l.append('</select>') | 793 l.append('</select>') |
| 788 return '\n'.join(l) | 794 return '\n'.join(l) |
| 789 | 795 |
| 790 def download(self, showid=0): | 796 def download(self, showid=0): |
| 791 linkname = self.prop.classname | 797 linkname = self._prop.classname |
| 792 linkcl = self.db.getclass(linkname) | 798 linkcl = self._db.getclass(linkname) |
| 793 k = linkcl.labelprop(1) | 799 k = linkcl.labelprop(1) |
| 794 linkvalue = cgi.escape(str(linkcl.get(self.value, k))) | 800 linkvalue = cgi.escape(str(linkcl.get(self._value, k))) |
| 795 if showid: | 801 if showid: |
| 796 label = value | 802 label = value |
| 797 title = ' title="%s"'%linkvalue | 803 title = ' title="%s"'%linkvalue |
| 798 # note ... this should be urllib.quote(linkcl.get(value, k)) | 804 # note ... this should be urllib.quote(linkcl.get(value, k)) |
| 799 else: | 805 else: |
| 800 label = linkvalue | 806 label = linkvalue |
| 801 title = '' | 807 title = '' |
| 802 return '<a href="%s%s/%s"%s>%s</a>'%(linkname, self.value, | 808 return '<a href="%s%s/%s"%s>%s</a>'%(linkname, self._value, |
| 803 linkvalue, title, label) | 809 linkvalue, title, label) |
| 804 | 810 |
| 805 def menu(self, size=None, height=None, showid=0, additional=[], | 811 def menu(self, size=None, height=None, showid=0, additional=[], |
| 806 **conditions): | 812 **conditions): |
| 807 value = self.value | 813 value = self._value |
| 808 | 814 |
| 809 # sort function | 815 # sort function |
| 810 sortfunc = make_sort_function(self.db, self.prop.classname) | 816 sortfunc = make_sort_function(self._db, self._prop.classname) |
| 811 | 817 |
| 812 # force the value to be a single choice | 818 # force the value to be a single choice |
| 813 if isinstance(value, type('')): | 819 if isinstance(value, type('')): |
| 814 value = value[0] | 820 value = value[0] |
| 815 linkcl = self.db.getclass(self.prop.classname) | 821 linkcl = self._db.getclass(self._prop.classname) |
| 816 l = ['<select name="%s">'%self.name] | 822 l = ['<select name="%s">'%self._name] |
| 817 k = linkcl.labelprop(1) | 823 k = linkcl.labelprop(1) |
| 818 s = '' | 824 s = '' |
| 819 if value is None: | 825 if value is None: |
| 820 s = 'selected ' | 826 s = 'selected ' |
| 821 l.append(_('<option %svalue="-1">- no selection -</option>')%s) | 827 l.append(_('<option %svalue="-1">- no selection -</option>')%s) |
| 828 option = linkcl.get(optionid, k) | 834 option = linkcl.get(optionid, k) |
| 829 s = '' | 835 s = '' |
| 830 if value in [optionid, option]: | 836 if value in [optionid, option]: |
| 831 s = 'selected ' | 837 s = 'selected ' |
| 832 if showid: | 838 if showid: |
| 833 lab = '%s%s: %s'%(self.prop.classname, optionid, option) | 839 lab = '%s%s: %s'%(self._prop.classname, optionid, option) |
| 834 else: | 840 else: |
| 835 lab = option | 841 lab = option |
| 836 if size is not None and len(lab) > size: | 842 if size is not None and len(lab) > size: |
| 837 lab = lab[:size-3] + '...' | 843 lab = lab[:size-3] + '...' |
| 838 if additional: | 844 if additional: |
| 853 Also be iterable, returning a wrapper object like the Link case for | 859 Also be iterable, returning a wrapper object like the Link case for |
| 854 each entry in the multilink. | 860 each entry in the multilink. |
| 855 ''' | 861 ''' |
| 856 def __len__(self): | 862 def __len__(self): |
| 857 ''' length of the multilink ''' | 863 ''' length of the multilink ''' |
| 858 return len(self.value) | 864 return len(self._value) |
| 859 | 865 |
| 860 def __getattr__(self, attr): | 866 def __getattr__(self, attr): |
| 861 ''' no extended attribute accesses make sense here ''' | 867 ''' no extended attribute accesses make sense here ''' |
| 862 raise AttributeError, attr | 868 raise AttributeError, attr |
| 863 | 869 |
| 864 def __getitem__(self, num): | 870 def __getitem__(self, num): |
| 865 ''' iterate and return a new HTMLItem | 871 ''' iterate and return a new HTMLItem |
| 866 ''' | 872 ''' |
| 867 #print 'getitem', (self, num) | 873 #print 'getitem', (self, num) |
| 868 value = self.value[num] | 874 value = self._value[num] |
| 869 if self.prop.classname == 'user': | 875 if self._prop.classname == 'user': |
| 870 klass = HTMLUser | 876 klass = HTMLUser |
| 871 else: | 877 else: |
| 872 klass = HTMLItem | 878 klass = HTMLItem |
| 873 return klass(self.client, self.prop.classname, value) | 879 return klass(self._client, self._prop.classname, value) |
| 874 | 880 |
| 875 def reverse(self): | 881 def reverse(self): |
| 876 ''' return the list in reverse order | 882 ''' return the list in reverse order |
| 877 ''' | 883 ''' |
| 878 l = self.value[:] | 884 l = self._value[:] |
| 879 l.reverse() | 885 l.reverse() |
| 880 if self.prop.classname == 'user': | 886 if self._prop.classname == 'user': |
| 881 klass = HTMLUser | 887 klass = HTMLUser |
| 882 else: | 888 else: |
| 883 klass = HTMLItem | 889 klass = HTMLItem |
| 884 return [klass(self.client, self.prop.classname, value) for value in l] | 890 return [klass(self._client, self._prop.classname, value) for value in l] |
| 885 | 891 |
| 886 def plain(self, escape=0): | 892 def plain(self, escape=0): |
| 887 linkcl = self.db.classes[self.prop.classname] | 893 linkcl = self._db.classes[self._prop.classname] |
| 888 k = linkcl.labelprop(1) | 894 k = linkcl.labelprop(1) |
| 889 labels = [] | 895 labels = [] |
| 890 for v in self.value: | 896 for v in self._value: |
| 891 labels.append(linkcl.get(v, k)) | 897 labels.append(linkcl.get(v, k)) |
| 892 value = ', '.join(labels) | 898 value = ', '.join(labels) |
| 893 if escape: | 899 if escape: |
| 894 value = cgi.escape(value) | 900 value = cgi.escape(value) |
| 895 return value | 901 return value |
| 896 | 902 |
| 897 def field(self, size=30, showid=0): | 903 def field(self, size=30, showid=0): |
| 898 sortfunc = make_sort_function(self.db, self.prop.classname) | 904 sortfunc = make_sort_function(self._db, self._prop.classname) |
| 899 linkcl = self.db.getclass(self.prop.classname) | 905 linkcl = self._db.getclass(self._prop.classname) |
| 900 value = self.value[:] | 906 value = self._value[:] |
| 901 if value: | 907 if value: |
| 902 value.sort(sortfunc) | 908 value.sort(sortfunc) |
| 903 # map the id to the label property | 909 # map the id to the label property |
| 904 if not showid: | 910 if not showid: |
| 905 k = linkcl.labelprop(1) | 911 k = linkcl.labelprop(1) |
| 906 value = [linkcl.get(v, k) for v in value] | 912 value = [linkcl.get(v, k) for v in value] |
| 907 value = cgi.escape(','.join(value)) | 913 value = cgi.escape(','.join(value)) |
| 908 return '<input name="%s" size="%s" value="%s">'%(self.name, size, value) | 914 return '<input name="%s" size="%s" value="%s">'%(self._name, size, value) |
| 909 | 915 |
| 910 def menu(self, size=None, height=None, showid=0, additional=[], | 916 def menu(self, size=None, height=None, showid=0, additional=[], |
| 911 **conditions): | 917 **conditions): |
| 912 value = self.value | 918 value = self._value |
| 913 | 919 |
| 914 # sort function | 920 # sort function |
| 915 sortfunc = make_sort_function(self.db, self.prop.classname) | 921 sortfunc = make_sort_function(self._db, self._prop.classname) |
| 916 | 922 |
| 917 linkcl = self.db.getclass(self.prop.classname) | 923 linkcl = self._db.getclass(self._prop.classname) |
| 918 if linkcl.getprops().has_key('order'): | 924 if linkcl.getprops().has_key('order'): |
| 919 sort_on = ('+', 'order') | 925 sort_on = ('+', 'order') |
| 920 else: | 926 else: |
| 921 sort_on = ('+', linkcl.labelprop()) | 927 sort_on = ('+', linkcl.labelprop()) |
| 922 options = linkcl.filter(None, conditions, sort_on, (None,None)) | 928 options = linkcl.filter(None, conditions, sort_on, (None,None)) |
| 923 height = height or min(len(options), 7) | 929 height = height or min(len(options), 7) |
| 924 l = ['<select multiple name="%s" size="%s">'%(self.name, height)] | 930 l = ['<select multiple name="%s" size="%s">'%(self._name, height)] |
| 925 k = linkcl.labelprop(1) | 931 k = linkcl.labelprop(1) |
| 926 for optionid in options: | 932 for optionid in options: |
| 927 option = linkcl.get(optionid, k) | 933 option = linkcl.get(optionid, k) |
| 928 s = '' | 934 s = '' |
| 929 if optionid in value or option in value: | 935 if optionid in value or option in value: |
| 930 s = 'selected ' | 936 s = 'selected ' |
| 931 if showid: | 937 if showid: |
| 932 lab = '%s%s: %s'%(self.prop.classname, optionid, option) | 938 lab = '%s%s: %s'%(self._prop.classname, optionid, option) |
| 933 else: | 939 else: |
| 934 lab = option | 940 lab = option |
| 935 if size is not None and len(lab) > size: | 941 if size is not None and len(lab) > size: |
| 936 lab = lab[:size-3] + '...' | 942 lab = lab[:size-3] + '...' |
| 937 if additional: | 943 if additional: |
