htmlwriter.py (190686B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\script\util\htmlwriter.py 2 from __future__ import print_function 3 import sys 4 import time 5 from datetime import datetime 6 import blue 7 import copy 8 import eve.common.lib.appConst as const 9 import functools 10 import json 11 import localization 12 import log 13 import numbers 14 import random 15 import re 16 import scriber 17 import types 18 import urllib 19 import urllib2 20 from carbon.common.lib import iocp 21 from carbon.common.script.net import http, machoNet 22 from carbon.common.script.util.format import FmtDate, FmtDateEng 23 from datetimeutils import deltastr 24 from eveexceptions import RoleNotAssignedError 25 from eveprefs import prefs, boot 26 from localization.const import LANGUAGE_BY_LANGUAGE_ID 27 from stringutil import strx 28 from urllib import unquote_plus 29 from uuid import uuid4 30 scriber.init([blue.paths.ResolvePath('res:/scriber')]) 31 reserved = {';': '%3B', 32 '/': '%2F', 33 '?': '%3F', 34 ':': '%3A', 35 '@': '%40', 36 '&': '%26', 37 '=': '%3D', 38 '+': '%2B', 39 '$': '%24', 40 ',': '%2C', 41 ' ': '%20', 42 '#': '%23'} 43 44 def multiple_replace(text, adict): 45 rx = re.compile('|'.join(map(re.escape, adict))) 46 47 def one_xlat(match): 48 return adict[match.group(0)] 49 50 return rx.sub(one_xlat, text) 51 52 53 def multiple_replacer(adict): 54 rx = re.compile('|'.join(map(re.escape, adict))) 55 56 def one_xlat(match): 57 return adict[match.group(0)] 58 59 def replacer(text): 60 return rx.sub(one_xlat, text) 61 62 return replacer 63 64 65 swing = multiple_replacer({'&': '&', 66 '<': '<', 67 '>': '>'}) 68 69 def Swing(*args, **kwargs): 70 return swing(*args, **kwargs) 71 72 73 def Canonicalize(text): 74 text = text.replace('%', '%25') 75 for k, v in reserved.iteritems(): 76 text = text.replace(k, v) 77 78 return text 79 80 81 def HTMLEncode(text): 82 t = '' 83 text = unicode(text) 84 for i in range(len(text)): 85 tord = ord(text[i]) 86 if tord == 38: 87 testStr = text[i + 1:i + text[i:].find(';')] 88 if testStr in ('quot', 'amp', 'lt', 'gt'): 89 t = t + text[i] 90 continue 91 if tord == 34: 92 t = t + '"' 93 elif tord == 38: 94 t = t + '&' 95 elif tord == 60: 96 t = t + '<' 97 elif tord == 62: 98 t = t + '>' 99 else: 100 t = t + text[i] 101 102 return t 103 104 105 def Link(url, title, args = None, props = '', target = None, bolConfirm = 0): 106 if title is None: 107 return '' 108 if bolConfirm: 109 onClick = ' onClick="return confirm(\'Are you sure?\')"' 110 else: 111 onClick = '' 112 if args: 113 realArgs = args 114 if isinstance(args, list): 115 realArgs = {} 116 for a in args: 117 realArgs.update(a) 118 119 stuff = url.split('#') 120 if len(stuff) > 1: 121 url = stuff[0] 122 url += '?' 123 for k, v in realArgs.iteritems(): 124 if isinstance(v, list): 125 for i in v: 126 url += unicode(k) + '=' + unicode(i) + '&' 127 128 else: 129 url += unicode(k) + '=' + Canonicalize(unicode(v)) + '&' 130 131 if len(stuff) > 1: 132 url += '#' + stuff[1] 133 if '&' in url: 134 url = url.replace('&', '&') 135 if iocp.UsingHTTPS(): 136 url = ConvertLinkForHTTPS(url) 137 if target: 138 return '<a href="%s" %s target="%s"%s>%s</a>' % (url, 139 props, 140 target, 141 onClick, 142 title) 143 else: 144 return '<a href="%s" %s%s>%s</a>' % (url, 145 props, 146 onClick, 147 title) 148 149 150 def Button(url, title, args = None, color = 'black', bolConfirm = 0): 151 props = 'class="button button%s"' % color 152 return Link(url, title, args, props, None, bolConfirm) 153 154 155 def ConvertLinkForHTTPS(url): 156 if url.startswith('http://'): 157 host = url[7:].split('/', 1)[0] 158 if ':' in host: 159 tcpProxy = sm.services.get('tcpRawProxyService', None) 160 if tcpProxy: 161 tunnels = tcpProxy.GetTunnelsByType('esp') 162 if host in (tunnelHost for name, port, tunnelHost in tunnels): 163 return url.replace('http://', 'https://') 164 ourHostIP, tundict = tcpProxy.GetESPTunnelingAddressByNodeID() 165 potentialTunnelingAddresses = (ourHostIP + ':' + str(port) for port in tundict.itervalues()) 166 if host in potentialTunnelingAddresses: 167 return url.replace('http://', 'https://') 168 machoNet = sm.GetService('machoNet') 169 socket = machoNet.GetTransport('tcp:raw:http') 170 espAddress = socket.address 171 if host == espAddress: 172 return url.replace('http://', 'https://') 173 return url 174 175 176 def Image(url, props = 'border=0'): 177 return '<img src="%s" %s />' % (url, props) 178 179 180 def Table(headers, lines, props = 'border=0', rowprops = 'valign=top'): 181 tbl = '' 182 tbl = tbl + '<table %s>\n' % (props,) 183 if len(headers): 184 tbl = tbl + '<tr>' 185 for i in headers: 186 tbl = tbl + '<td><b>%s</b></td>' % (i,) 187 188 tbl = tbl + '</tr>\n' 189 for row in lines: 190 tbl = tbl + '<tr>' 191 for col in row: 192 tbl = tbl + '<td %s>%s</td>' % (rowprops, col) 193 194 tbl = tbl + '</tr>\n' 195 196 tbl = tbl + '</table>\n' 197 return tbl 198 199 200 class UnicodeMemStream(object): 201 __slots__ = ['ms'] 202 203 def __init__(self): 204 self.ms = blue.MemStream() 205 206 def Write(self, s): 207 if s is not None: 208 u = unicode(s) 209 b = buffer(u) 210 self.ms.Write(b) 211 212 def Read(self): 213 return self.ms.Read().decode('utf-16', errors='replace') 214 215 def getpos(self): 216 return self.ms.pos / 2 217 218 def getsize(self): 219 return self.ms.size / 2 220 221 size = property(getsize) 222 pos = property(getpos) 223 224 def Seek(self, x): 225 self.ms.Seek(2 * x) 226 227 228 def JsonFunction(func): 229 230 @functools.wraps(func) 231 def Wrapper(*args, **kwargs): 232 args[0].Write(json.dumps(func(*args, **kwargs))) 233 234 return Wrapper 235 236 237 def HtmlFunction(func): 238 239 @functools.wraps(func) 240 def Wrapper(*args, **kwargs): 241 args[0].Write(func(*args, **kwargs)) 242 243 return Wrapper 244 245 246 def XmlFunction(func): 247 248 @functools.wraps(func) 249 def Wrapper(*args, **kwargs): 250 response = args[0].response 251 headers = [('Content-type', 'text/xml'), ('Content-Disposition', 'attachment; filename=' + 'file.xml'), ('Cache-Control', 'no-cache, must-revalidate, max_age=0, no-store , private')] 252 for h in headers: 253 if hasattr(response, 'AddHeader'): 254 response.AddHeader(h[0], h[1]) 255 else: 256 http.AddHeader(h[0], h[1]) 257 258 response.WriteBinary(func(*args, **kwargs)) 259 response.streamMode = 'b' 260 if hasattr(response, 'Flush'): 261 response.Flush() 262 263 return Wrapper 264 265 266 def StaticImage(func): 267 268 @functools.wraps(func) 269 def Wrapper(*args, **kwargs): 270 fileName = func(*args, **kwargs) 271 fileName = '%swwwroot/%s' % (blue.paths.ResolvePath(u'script:/').replace('eve/server', 'carbon/common'), fileName) 272 response = args[0].response 273 if hasattr(response, 'AddHeader'): 274 response.AddHeader('Content-type', 'image/%s' % fileName.split('.')[-1]) 275 else: 276 http.AddHeader('Content-type', 'image/%s' % fileName.split('.')[-1]) 277 with file(fileName, 'rb') as f: 278 response.WriteBinary(f.read()) 279 if hasattr(response, 'Flush'): 280 response.Flush() 281 282 return Wrapper 283 284 285 def ZipFunction(func): 286 287 @functools.wraps(func) 288 def Wrapper(*args, **kwargs): 289 response = args[0].response 290 headers = [('Content-type', 'application/octet-stream'), ('Content-Disposition', 'attachment; filename=' + 'file.zip'), ('Cache-Control', 'no-cache, must-revalidate, max_age=0, no-store , private')] 291 for h in headers: 292 if hasattr(response, 'AddHeader'): 293 response.AddHeader(h[0], h[1]) 294 else: 295 http.AddHeader(h[0], h[1]) 296 297 response.WriteBinary(func(*args, **kwargs)) 298 response.streamMode = 'b' 299 if hasattr(response, 'Flush'): 300 response.Flush() 301 302 return Wrapper 303 304 305 def GenerateCSRFToken(request): 306 if not hasattr(request.session, 'CSRFToken'): 307 request.session.CSRFToken = str(uuid4()) 308 return request.session.CSRFToken 309 310 311 def CSRFFormField(request): 312 return '<input type="hidden" name="csrf_token" autocomplete="off" value="%s" />' % GenerateCSRFToken(request) 313 314 315 def WaitingMessage(waitingMessage): 316 return '<input type="hidden" name="__waiting_message__" value="%s" />' % waitingMessage 317 318 319 def OutlineDictTable(lines): 320 s = UnicodeMemStream() 321 s.Write('<table border="0" cellpadding="0" cellspacing="0" width="100%">\n') 322 s.Write('<tr>\n') 323 s.Write('<td class="tableOutline" valign="top">\n') 324 s.Write('<table border="0" cellpadding="7" cellspacing="1" width="100%">\n') 325 s.Write('<tr>\n') 326 s.Write('<tr>\n') 327 headers = [] 328 if len(lines) == 0: 329 headers = lines.iterkeys() 330 else: 331 headers = lines[0].iterkeys() 332 for i in headers: 333 s.Write(' <td class="tableHeader"><b>%s</b></td>\n' % header) 334 335 s.Write('</tr>\n') 336 for i in lines: 337 for row in i.itervalues(): 338 s.Write('<tr>\n') 339 for col in row: 340 s.Write(' <td class="tC" valign=top>%s</td>\n' % unicode(col)) 341 342 s.Write('</tr>\n') 343 344 s.Write('</tr>\n') 345 s.Write('</table>\n') 346 s.Write('</td>\n') 347 s.Write('</tr>\n') 348 s.Write('</table>\n') 349 s.Seek(0) 350 return s.Read() 351 352 353 def SortOSST(i, a, b): 354 try: 355 ai = long(a[i]) 356 bi = long(b[i]) 357 return [1, -1][ai < bi] 358 except: 359 sys.exc_clear() 360 return [1, -1][a[i].lower() < b[i].lower()] 361 362 363 def OutlineSortedSegmentedTable(lname, ldict, hd, li, idstr, idx, num, displayNameIDX = None, firstIDX = 0, firstNUM = None): 364 li.sort(lambda a, b, d = displayNameIDX: SortOSST(d, a, b)) 365 return OutlineSegmentedTable(lname, ldict, hd, li, idstr, idx, num, displayNameIDX, firstIDX, firstNUM) 366 367 368 def OutlineSegmentedTable(lname, ldict, hd, li, idstr, idx, num, displayNameIDX = None, firstIDX = 0, firstNUM = None): 369 nTotal = len(li) 370 if firstNUM is None: 371 if nTotal > 10000: 372 firstNUM = 1000 373 elif nTotal > 1000: 374 firstNUM = 250 375 elif nTotal > 500: 376 firstNUM = 100 377 elif nTotal > 250: 378 firstNUM = 50 379 elif nTotal > 100: 380 firstNUM = 25 381 else: 382 firstNUM = 10 383 segmentIDstring = Swing(lname + '/' + ldict['action'] + '/' + str(hd)) 384 if idx is not None and idstr == segmentIDstring: 385 session.SetSessionVariable(segmentIDstring + '.idx', idx) 386 else: 387 idx = firstIDX 388 if num is not None and idstr == segmentIDstring: 389 session.SetSessionVariable(segmentIDstring + '.num', num) 390 else: 391 num = firstNUM 392 if displayNameIDX is not None and idstr == segmentIDstring: 393 session.SetSessionVariable(segmentIDstring + '.what', displayNameIDX) 394 elif displayNameIDX is None: 395 displayNameIDX = 0 396 nStart, nCount, nWhat = session.GetSessionVariable(segmentIDstring + '.idx', firstIDX), session.GetSessionVariable(segmentIDstring + '.num', firstNUM), session.GetSessionVariable(segmentIDstring + '.what', displayNameIDX) 397 if li and nWhat >= len(li[0]): 398 nWhat = len(li[0]) - 1 399 elif nWhat < 0: 400 nWhat = 0 401 l = '' 402 ldict = copy.deepcopy(ldict) 403 ldict['segmentedTableID'] = segmentIDstring 404 ldict['segmentedTableNUM'] = nCount 405 ldict['segmentedTableWHAT'] = nWhat 406 for i in range(0, nTotal, nCount): 407 if nStart < i or nStart >= i + nCount: 408 ldict['segmentedTableIDX'] = i 409 t = i + nCount - 1 410 if t >= len(li): 411 t = len(li) - 1 412 l += Link(lname, Swing(str(li[i][nWhat])) + '..' + Swing(str(li[t][nWhat])), ldict) + ' ' 413 414 li = li[nStart:nStart + nCount] 415 ldict['segmentedTableIDX'] = nStart 416 for i in range(len(hd)): 417 if i != nWhat: 418 ldict['segmentedTableWHAT'] = i 419 hd[i] = Link(lname, hd[i], ldict) 420 421 if l: 422 if li: 423 current = '<br/>Now viewing: ' + Swing(str(li[0][nWhat])) + '..' + Swing(str(li[-1][nWhat])) 424 else: 425 current = '' 426 selected = '<br/>Select: ' + l + '<br/>' 427 return GetTable(hd, li) + current + selected 428 else: 429 return GetTable(hd, li) 430 431 432 def RemoveHtmlTag(tagName = 'font', stringWithTags = None): 433 tagCompiled = re.compile('(\\<%(tag)s[^\\>]+\\>)|(</%(tag)s>)' % {'tag': tagName}) 434 while True: 435 match = tagCompiled.search(stringWithTags) 436 if match is None: 437 break 438 stringWithTags = stringWithTags.replace(match.group(), '') 439 440 return stringWithTags 441 442 443 def _GetElementBegin(elementName, attributes): 444 return '<%s%s>' % (elementName, attributes) 445 446 447 def _GetElementEnd(elementName): 448 return '</%s>' % elementName 449 450 451 def _GetElement(ctrlName, ctrlValue, ctrlID = None, className = None, style = None): 452 controlID = CheckValue('id', ctrlID) 453 controlName = CheckValue('id', ctrlID) 454 className = CheckValue('class', className) 455 style = CheckValue('style', style) 456 return '\n'.join([_GetElementBegin(ctrlName, '%s%s%s%s' % (controlID, 457 controlName, 458 className, 459 style)), unicode(ctrlValue), _GetElementEnd(ctrlName)]) 460 461 462 def _GetElements(elements = None, ctrlName = 'div', ctrlID = None, className = None, style = None, title = None, dataBind = None): 463 ctrlID = CheckValue('id', ctrlID) 464 className = CheckValue('class', className) 465 style = CheckValue('style', style) 466 title = CheckValue('title', title) 467 dataBind = CheckValue('data-bind', dataBind) 468 res = UnicodeMemStream() 469 res.Write(_GetElementBegin(ctrlName, '%s%s%s%s%s' % (ctrlID, 470 className, 471 style, 472 title, 473 dataBind))) 474 if isinstance(elements, list): 475 if elements and len(elements) > 0: 476 for n in elements: 477 res.Write(unicode(n)) 478 479 elif elements is not None: 480 res.Write(unicode(elements)) 481 res.Write(_GetElementEnd(ctrlName)) 482 res.Seek(0) 483 return res.Read() 484 485 486 def GetA(innerText, href, ctrlID = None, className = None, style = None, onClick = None, title = None, rel = None, rev = None, target = None): 487 ctrlID = CheckValue('id', ctrlID) 488 className = CheckValue('class', className) 489 style = CheckValue('style', style) 490 onClick = CheckValue('onclick', onClick) 491 title = CheckValue('title', HTMLEncode(title) if title is not None and len(title) > 0 else '') 492 rel = CheckValue('rel', rel) 493 rev = CheckValue('rev', rev) 494 target = CheckValue('target', target) 495 return '<a href="%s"%s%s%s%s%s%s%s%s>%s</a>' % (href, 496 ctrlID, 497 className, 498 style, 499 onClick, 500 title, 501 rel, 502 rev, 503 target, 504 innerText) 505 506 507 def GetInput(ctrlID, labelCaption, className = None, minLength = None, width = None, value = None, title = ''): 508 minLength = CheckValue('minlength', minLength) 509 if width: 510 width = ' style="width:%spx"' % width 511 else: 512 width = '' 513 className = CheckValue('class', className) 514 value = CheckValue('value', value) 515 title = CheckValue('title', title) 516 res = [] 517 if labelCaption is not None: 518 res.append('<label class="form-label" for="%s">%s</label>' % (ctrlID, labelCaption)) 519 res.append('<input id="%s" name="%s"%s%s%s%s%s/>' % (ctrlID, 520 ctrlID, 521 className, 522 minLength, 523 width, 524 value, 525 title)) 526 return '\n'.join(res) 527 528 529 def GetSelect(elements, controlID, labelCaption = None, elementClass = None, selectedValue = None, attributes = ''): 530 elementClass = CheckValue('class', elementClass) 531 if controlID: 532 controlID = ' id="%s" name="%s"' % (controlID, controlID) 533 opt0 = lambda row: (' selected="selected"' if row[0] == selectedValue else '') 534 opt1 = lambda row: '<option value="%s"%s>%s</option>\n' % (row[0], CheckValue('selected', row[2]) if len(row) > 2 else opt0(row), row[1]) 535 res = [] 536 if labelCaption is not None: 537 res.append('<label class="form-label" for="%s">%s</label>' % (controlID, labelCaption)) 538 res.append(_GetElementBegin('select', '%s%s %s' % (controlID, elementClass, attributes))) 539 res.append(''.join(map(opt1, elements.items() if isinstance(elements, dict) else elements))) 540 res.append(_GetElementEnd('select')) 541 return ''.join(res) 542 543 544 def GetSpan(elements, ctrlID = None, className = None, style = None, title = None, dataBind = None): 545 return _GetElements(elements, 'span', ctrlID, className, style, title, dataBind) 546 547 548 def GetImage(src, ctrlID = None, className = None, style = None, title = None, rel = None): 549 ctrlID = CheckValue('id', ctrlID) 550 className = CheckValue('class', className) 551 style = CheckValue('style', style) 552 title = CheckValue('title', title) 553 rel = CheckValue('rel', rel) 554 return '<img src="%s" %s%s%s%s%s/>' % (src, 555 ctrlID, 556 className, 557 style, 558 title, 559 rel) 560 561 562 def GetTextArea(ctrlID, labelCaption, className, cols, rows, innerHtml = None): 563 className = CheckValue('class', className) 564 cols = CheckValue('cols', cols) 565 rows = CheckValue('rows', rows) 566 ctrlFor = CheckValue('for', ctrlID) 567 ctrlID2 = CheckValue('id', ctrlID) 568 ctrlName = CheckValue('name', ctrlID) 569 if innerHtml is None: 570 innerHtml = '' 571 lines = [] 572 if labelCaption: 573 lines.append('<label class="form-label"%(ctrlID)s>%(labelCaption)s</label>' % {'ctrlID': ctrlFor, 574 'labelCaption': labelCaption}) 575 lines += [_GetElementBegin('textarea', '%(ctrlID)s%(className)s%(cols)s%(rows)s%(ctrlName)s' % {'ctrlID': ctrlID2, 576 'className': className, 577 'cols': cols, 578 'rows': rows, 579 'ctrlName': ctrlName}), innerHtml, _GetElementEnd('textarea')] 580 return ''.join(lines) 581 582 583 def GetTable(header = None, lines = None, className = 'tablesorter', enableEdit = False, editUrl = None, enableDelete = False, deleteUrl = None, useFilter = False, invertSelection = False, paging = None, customActions = None, serverOrder = False, baseUrl = None, keyFields = None, readOnlyFields = None, showCount = True, cssByRow = None): 584 elementSep = '<span class="toolbar-separator"> </span>' 585 customActions2 = [] 586 if customActions is not None: 587 for ca in customActions: 588 customActions2.append(' ' * 5) 589 customActions2.append(ca) 590 591 if keyFields is None: 592 keyFields = [] 593 if readOnlyFields is None: 594 readOnlyFields = [] 595 className = CheckValue('class', className) 596 res = UnicodeMemStream() 597 r = random.randint(1, 1000) 598 id = 'table_%i' % r 599 headerIndexControl = [] 600 xLoop = 0 601 for x in header or []: 602 if '<' in unicode(x): 603 headerIndexControl.append(xLoop) 604 xLoop += 1 605 606 if enableDelete or enableEdit: 607 headerIndexControl.append(len(header)) 608 if header is not None and len(header) > 0: 609 res.Write('\n <script type="text/javascript">\n $(document).ready(function() {\n $("#%s").tablesorter(' % id) 610 if header is not None and serverOrder is True: 611 res.Write('{\n headers: {') 612 t_res = [] 613 for n in xrange(len(header)): 614 t_res.append('%i: {sorter: false}' % n) 615 616 res.Write(', '.join(t_res)) 617 res.Write('}\n}') 618 elif header is not None and len(headerIndexControl) > 0: 619 res.Write('{\n headers: {') 620 t_res = [] 621 for n in headerIndexControl: 622 t_res.append('%i: {sorter: false}' % n) 623 624 res.Write(', '.join(t_res)) 625 res.Write('}\n}') 626 res.Write(');\n });\n </script>') 627 ctrlID = ' id="%s"' % id 628 invertText = '<li><a class="csp-invert button buttongray">Invert</a></li>' if invertSelection else '' 629 filterBar = '\n <div class="csp-tool-strip">\n <a class="button buttonwhite excel" onclick="exportToExcel(\'%(ctrlID)s\');">Excel</a>\n \n <input type="text" size="25" maxlength="30" value="" id="filter_%(ctrlID)s" name="filter_%(ctrlID)s"/>\n </div>\n ' % {'ctrlID': id} 630 toolbar = '\n <div class="csp-tool">\n <div style="float:left;">\n %(leftbar)s\n </div>\n <div style="float:right;">\n <div class="csp-tool-strip">\n <ul>\n %(customActions)s\n %(sep1)s\n %(paging)s\n %(sep2)s\n %(invert)s\n </ul>\n </div>\n </div>\n <div style="clear:both;"></div>\n </div>\n ' 631 res.Write('<div>') 632 if useFilter or invertSelection: 633 res.Write('\n <script type="text/javascript">\n $(function() {\n var $%(ctrlID)s = $("#%(ctrlID)s")\n $("#filter_%(ctrlID)s").keyup(function() {\n $.uiTableFilter( $%(ctrlID)s, this.value );\n });\n $(".csp-invert").click(function(){\n $.each($("#%(ctrlID)s input").not(":disabled"), function(idx,val) {\n if ($(val).is(":visible")) {\n val.checked = !val.checked;\n }\n });\n });\n });\n </script>\n ' % {'ctrlID': id}) 634 if useFilter or paging is not None or len(customActions2) > 0: 635 res.Write(toolbar % {'leftbar': filterBar if useFilter else '', 636 'invert': invertText, 637 'paging': '' if paging is None else '<li>%s</li>' % paging, 638 'customActions': u''.join([ u'<li>%s</li>' % x for x in customActions2 ]), 639 'sep1': '' if paging is None else '<li>%s</li>' % elementSep, 640 'sep2': '<li>%s</li>' % elementSep if len(invertText) > 0 else ''}) 641 res.Write('<table %(className)s%(ctrlID)s>' % {'className': className, 642 'ctrlID': ctrlID}) 643 columnRules = [] 644 if header: 645 res.Write('<thead><tr>') 646 h_idx = 0 647 for h in header or []: 648 th_style = '' 649 w = 0 650 columnRules.append('') 651 if isinstance(h, list): 652 if isinstance(h[1], list): 653 w = h[1][0] 654 if len(h[1]) > 1: 655 columnRules[h_idx] = h[1][1] 656 elif isinstance(h[1], str): 657 columnRules[h_idx] = h[1] 658 elif isinstance(h[1], int): 659 w = h[1] 660 th_style = ' style="width: %spx"' % w if w > 0 else '' 661 h = h[0] 662 if keyFields is not None and h in keyFields: 663 k = ' class="csp-table-key"' 664 elif readOnlyFields is not None and h in readOnlyFields: 665 k = ' class="csp-table-readonly"' 666 else: 667 k = '' 668 if serverOrder is True: 669 res.Write('<th%s%s>%s</a></th>' % (k, th_style, GetA(h, '%s&sortcolumn=%i' % (baseUrl, h_idx)))) 670 else: 671 res.Write('<th%s>%s</a></th>' % (th_style, h)) 672 h_idx += 1 673 674 if enableEdit or enableDelete: 675 res.Write('<th></th>') 676 res.Write('</tr></thead>') 677 if lines: 678 rowNumber = 0 679 for r in lines: 680 blue.pyos.BeNice() 681 if isinstance(cssByRow, dict) and rowNumber in cssByRow: 682 rowCss = cssByRow[rowNumber] 683 res.Write('<tr style="%s">' % rowCss) 684 else: 685 res.Write('<tr>') 686 lnr = 0 687 for c in r: 688 td_style = '' 689 if len(columnRules) and len(columnRules) > lnr: 690 td_style = ' class="csp-%s"' % columnRules[lnr] 691 res.Write('<td%s>' % td_style) 692 if len(columnRules) and len(columnRules) > lnr and columnRules[lnr] in ('number', 'numberleft'): 693 res.Write(AddThousandSeparator(c)) 694 else: 695 res.Write(c) 696 res.Write('</td>') 697 lnr += 1 698 699 if enableEdit or enableDelete: 700 actions = [] 701 if enableEdit: 702 actions.append(GetA('Edit', href='#', className='edit-row', rev=editUrl)) 703 if enableDelete: 704 actions.append(GetA('Delete', href='#', className='delete-row', rev=deleteUrl)) 705 res.Write('<td>%s</td>' % ' | '.join(actions)) 706 res.Write('</tr>') 707 rowNumber += 1 708 709 else: 710 res.Write('<tr>') 711 for h in header or []: 712 res.Write('<td></td>') 713 714 res.Write('</tr>') 715 res.Write('</table>') 716 if len(lines) > 30: 717 if useFilter or paging is not None or len(customActions2) > 0: 718 res.Write(toolbar % {'leftbar': '%i rows' % len(lines) if showCount else '', 719 'invert': invertText, 720 'paging': '' if paging is None else '<li>%s</li>' % paging, 721 'customActions': u''.join([ u'<li>%s</li>' % x for x in customActions2 ]), 722 'sep1': '' if paging is None else '<li>%s</li>' % elementSep, 723 'sep2': '<li>%s</li>' % elementSep if len(invertText) > 0 else ''}) 724 elif showCount: 725 res.Write('<div>%i rows</div>' % len(lines)) 726 elif showCount and len(lines) > 5: 727 res.Write('<div>%i rows</div>' % len(lines)) 728 res.Write('</div>') 729 res.Seek(0) 730 return res.Read() 731 732 733 def GetMessageEnglishByID(messageID, defaultValue): 734 return localization.GetByMessageID(messageID) or defaultValue 735 736 737 def GetLocalizationLabel(labelText, messageID): 738 msgSpan = GetSpan([GetMessageEnglishByID(messageID, labelText)], className='') 739 return msgSpan 740 741 742 def GetLanguagesForSelector(): 743 languages = [] 744 for languageID, language in LANGUAGE_BY_LANGUAGE_ID.iteritems(): 745 languages.append([localization.util.ConvertLanguageIDToMLS(languageID), language]) 746 747 return languages 748 749 750 def OutlineTable(headers, lines, opLink = '', opAct = '', opWidth = None, opHeadClass = 'tableHeader', nobreak = 0, opColClass = None, opHeaderArgs = None, opTDArgs = None): 751 tableStyle = '' 752 for headerValue in headers: 753 if isinstance(headerValue, list) or isinstance(headerValue, tuple): 754 tableStyle = "STYLE='table-layout:fixed'" 755 break 756 757 s = UnicodeMemStream() 758 if opWidth is not None: 759 if opWidth != '': 760 opWidth = 'width="%s"' % opWidth 761 s.Write('<table border="0" cellpadding="0" cellspacing="0" %s %s>\n' % (opWidth, tableStyle)) 762 else: 763 s.Write('<table border="0" cellpadding="0" cellspacing="0" width="100%%" %s>\n' % tableStyle) 764 s.Write('<tr>\n') 765 s.Write('<td class="tableOutline" valign="top">\n') 766 s.Write('<table border="0" cellpadding="7" cellspacing="0" width="100%%" %s>\n' % tableStyle) 767 if len(headers): 768 s.Write('<tr>\n') 769 for headerIndex, headerValue in enumerate(headers): 770 headerTDArgs = '' 771 if opHeaderArgs is not None and headerIndex in opHeaderArgs: 772 headerTDArgs = ' '.join([ '%s="%s"' % (attribute, value) for attribute, value in opHeaderArgs[headerIndex] ]) 773 if isinstance(headerValue, list) or isinstance(headerValue, tuple): 774 headerLabel, width = headerValue 775 s.Write(' <td width=%d class="%s"%s>%s</td>\n' % (width, 776 opHeadClass, 777 headerTDArgs, 778 headerLabel)) 779 else: 780 s.Write(' <td class="%s"%s>%s</td>\n' % (opHeadClass, headerTDArgs, headerValue)) 781 782 s.Write('</tr>\n') 783 c = 1 784 for rowIndex, rowValue in enumerate(lines): 785 if len(rowValue) == 1 and unicode(rowValue[0]).lower().find('<tr') == 0: 786 s.Write(rowValue[0] + '\n') 787 continue 788 klass = 'class="tC"' 789 if c: 790 c = 0 791 else: 792 klass = 'class="tCO"' 793 c = 1 794 if opColClass: 795 klass = 'class="%s"' % opColClass 796 s.Write('<tr>\n') 797 for colIndex, colValue in enumerate(rowValue): 798 tdArgs = '' 799 if opTDArgs is not None and (rowIndex, colIndex) in opTDArgs: 800 tdArgs = ' '.join([ '%s="%s"' % (attribute, value) for attribute, value in opTDArgs[rowIndex, colIndex] ]) 801 if colValue == rowValue[0] and opLink != '': 802 link = opLink % (colValue, colValue) 803 s.Write('<td %s%s>%s</td>\n' % (klass, tdArgs, link)) 804 continue 805 s.Write('<td %s%s>' % (klass, tdArgs)) 806 if nobreak: 807 s.Write('<nobr>') 808 s.Write(colValue) 809 if nobreak: 810 s.Write('</nobr>') 811 s.Write('</td>\n') 812 813 s.Write('</tr>\n') 814 815 s.Write('</table>\n') 816 s.Write('</td>\n') 817 s.Write('</tr>\n') 818 s.Write('</table>\n') 819 s.Seek(0) 820 return s.Read() 821 822 823 def OutlinePropertyTable(keyvaldict, header = None): 824 s = UnicodeMemStream() 825 s.Write('<table border="0" cellpadding="0" cellspacing="0">\n') 826 s.Write('<tr>\n') 827 s.Write('<td class="tableOutline" valign="top">\n') 828 s.Write('<table border="0" cellpadding="7" cellspacing="1">\n') 829 s.Write('<tr>\n') 830 it = keyvaldict.items() 831 if header and len(header): 832 s.Write('<tr>') 833 for i in header: 834 s.Write('<td ') 835 if len(header) == 1: 836 s.Write('colspan = 2 ') 837 s.Write('class="tableHeader"><b>%s</b></td>\n' % (i,)) 838 839 s.Write('</tr>\n') 840 for i in it: 841 s.Write('<tr>\n') 842 s.Write('<td class="tC"><b>%s</b></td>\n' % i[0]) 843 s.Write('<td class="tC">%s</td>\n' % i[1]) 844 s.Write('</tr>\n') 845 846 s.Write('</tr>\n') 847 s.Write('</table>\n') 848 s.Write('</td>\n') 849 s.Write('</tr>\n') 850 s.Write('</table>\n') 851 s.Seek(0) 852 return s.Read() 853 854 855 def OutlineKeyValTable(keyval): 856 s = UnicodeMemStream() 857 s.Write('<table border="0" cellpadding="0" cellspacing="0">\n') 858 s.Write('<tr>\n') 859 s.Write('<td class="tableOutline" valign="top">\n') 860 s.Write('<table border="0" cellpadding="7" cellspacing="1">\n') 861 s.Write('<tr>\n') 862 for i in keyval: 863 s.Write('<tr>\n') 864 s.Write('<td class="tC" valign=top><b>%s</b></td>\n' % unicode(i[0])) 865 s.Write('<td class="tC" valign=top>%s</td>\n' % unicode(i[1])) 866 s.Write('</tr>\n') 867 868 s.Write('</tr>\n') 869 s.Write('</table>\n') 870 s.Write('</td>\n') 871 s.Write('</tr>\n') 872 s.Write('</table>\n') 873 s.Seek(0) 874 return s.Read() 875 876 877 def BarChart(name = '', data = {}, width = 500, height = 500): 878 Tot = 0 879 Max = 0 880 sortedDataKeys = data.keys() 881 sortedDataKeys.sort() 882 for k in sortedDataKeys: 883 Tot = Tot + data[k] 884 if data[k] > Max: 885 Max = data[k] 886 887 strHTML = '\n\n<table border=0 cellspacing=2 width="100%%">\n' 888 for k in sortedDataKeys: 889 strHTML = strHTML + '<tr><td width="50"><b>%s</b><br/>%s times</td><td><table height="100%%" Width="%s%%" border=0 cellpadding=0 bgcolor="#6699cc"><tr><td> </td></tr></table></td></tr>\n' % (k, data[k], int(float(data[k]) / float(Tot) * 100)) 890 891 strHTML = strHTML + '</table>' 892 return strHTML 893 894 895 def HtmlFormatStack(stack): 896 ret = '' 897 for each in stack: 898 ret += Swing(each) + '<br/>' 899 900 return ret 901 902 903 def BrowserCheck(browser): 904 valids = ['MSIE 6.0', 'MSIE 5.5'] 905 ret = 0 906 for valid in valids: 907 if browser.find(valid) > 0: 908 ret = 1 909 910 return ret 911 912 913 def WebPart(title, content, ID = '4', width = '100%', headerClass = '', bodyClass = ''): 914 s = UnicodeMemStream() 915 s.Write('<table class=WebPartTable cellpadding="0" cellspacing="0" width="' + str(width) + '" border="0" id="' + unicode(ID) + '">\n') 916 s.Write('<tr>\n') 917 s.Write(' <td valign="middle" align="left" class="WebPartHeader %s">\n' % headerClass) 918 s.Write(' ' + title + '\n') 919 s.Write(' </td>\n') 920 s.Write('</tr>\n') 921 s.Write('<tr>\n') 922 s.Write(' <td>\n') 923 s.Write(' <table bgcolor="#ffffff" width="100%" cellpadding="0" cellspacing="0" border="0">\n') 924 s.Write(' <tr>\n') 925 s.Write(' <td valign="top" class="WebPartContent %s">\n' % bodyClass) 926 s.Write(content) 927 s.Write(' </td>\n') 928 s.Write(' </tr>\n') 929 s.Write(' </table>\n') 930 s.Write(' </td>\n') 931 s.Write('</tr>\n') 932 s.Write('</table>\n') 933 s.Seek(0) 934 return s.Read() 935 936 937 def GetFrameOf(what): 938 import stackless 939 first = stackless.getcurrent() 940 if type(what) == type(stackless.getcurrent().frame): 941 return what 942 current = first 943 f = None 944 while 1: 945 q = current.frame 946 while 1: 947 if q is not None and not hasattr(q, 'f_locals'): 948 q = None 949 if q is None: 950 break 951 if q.f_locals is what: 952 return q 953 for each in q.f_locals: 954 if each is what: 955 return q 956 957 q = q.f_back 958 959 current = current.next 960 if current == first: 961 break 962 963 964 def FrameIsCallingFrame(f, current = None): 965 import stackless 966 if current is None: 967 current = stackless.getcurrent().frame 968 while 1: 969 if f is current: 970 return 1 971 if current.f_back is None or not hasattr(current.f_back, 'f_locals'): 972 if f is not None: 973 f = f.f_back 974 if f is not None and hasattr(f, 'f_locals'): 975 return FrameIsCallingFrame(f, current) 976 return 0 977 current = current.f_back 978 979 980 def Kapling(s): 981 s = Swing(s) 982 if len(s) > 500: 983 s = 'huge mofu (%d)' % len(s) + s[:500] 984 return s 985 986 987 def GetXyzzyReferrerInfo(each, inst): 988 ok = '<b>' + Kapling(str(type(each))) + '</b>: ' + Kapling(str(each)) 989 done = 0 990 if type(each) == type({}): 991 for yetanother in inst: 992 if yetanother.__dict__ is each: 993 done = 1 994 ok += '<br/><b>This ref is owned by this object: ' + Kapling(str(yetanother)) + '</b>' 995 break 996 for k, attr in yetanother.__dict__.iteritems(): 997 if attr is each: 998 ok += '<br/><b>This ref is ' + Kapling(str(yetanother)) + '.' + k + '</b>' 999 done = 1 1000 elif type(attr) in (types.TupleType, types.ListType): 1001 for i in attr: 1002 if i is each: 1003 ok += '<br/><b>This ref is contained in ' + Kapling(str(yetanother)) + '.' + k + '</b>' 1004 done = 1 1005 1006 elif type(attr) == types.DictType: 1007 for i in attr.itervalues(): 1008 if i is each: 1009 ok += '<br/><b>This ref is contained in ' + Kapling(str(yetanother)) + '.' + k + '</b>' 1010 done = 1 1011 1012 return (ok, done) 1013 1014 1015 def GetXyzzyReferrers(s, inst = None): 1016 import traceback 1017 import gc 1018 ok = '' 1019 gc.collect() 1020 referrers = gc.get_referrers(s) 1021 if inst is None: 1022 inst = [ o for o in gc.get_objects() if type(o) is types.InstanceType ] 1023 for each in referrers: 1024 f = GetFrameOf(each) 1025 ok += '<br/>' 1026 if FrameIsCallingFrame(f): 1027 ok += '<br/><b>It looks like this ref might belong to this web page:</b>' 1028 if f is not None: 1029 ok += '<br/><b>Frame: ' + Kapling(str(f)) + '</b>' 1030 for other in traceback.extract_stack(f, 40): 1031 ok += '<br/>' + Kapling(str(other)) 1032 1033 ri, done = GetXyzzyReferrerInfo(each, inst) 1034 ok += ri 1035 1036 gc.collect() 1037 return ok 1038 1039 1040 def Convert(var): 1041 try: 1042 if isinstance(var, (str, unicode)): 1043 if len(var) > 1: 1044 if var == 'None': 1045 return None 1046 if var.startswith('-'): 1047 rest = var[1:] 1048 if rest.isdigit(): 1049 if rest.startswith('0'): 1050 return var 1051 else: 1052 return int(var) 1053 elif '.' in rest and rest.replace('.', '').isdigit(): 1054 if rest.startswith('0'): 1055 return var 1056 else: 1057 return float(var) 1058 elif var.isdigit(): 1059 if var.startswith('0'): 1060 return var 1061 else: 1062 return int(var) 1063 elif '.' in var and var.replace('.', '').isdigit(): 1064 if var.startswith('0'): 1065 return var 1066 else: 1067 return float(var) 1068 elif var.isdigit(): 1069 return int(var) 1070 except: 1071 sys.exc_clear() 1072 1073 return var 1074 1075 1076 def Pythonize(var): 1077 if type(var) == type([]): 1078 ret = [] 1079 for i in var: 1080 ret.append(Convert(i)) 1081 1082 return ret 1083 return Convert(var) 1084 1085 1086 def Decanonicalize(text): 1087 ix = 0 1088 text = text.replace('+', ' ') 1089 ret = '' 1090 while 1: 1091 newix = text.find('%', ix) 1092 if newix == -1: 1093 break 1094 ret = ret + text[ix:newix] 1095 ix = newix 1096 h2, h1 = text[ix + 1:ix + 3] 1097 ch = 0 1098 if h1 >= '0' and h1 <= '9': 1099 ch = ord(h1) - ord('0') 1100 else: 1101 ch = ord(h1) - ord('A') + 10 1102 if h2 >= '0' and h2 <= '9': 1103 ch = ch + (ord(h2) - ord('0')) * 16 1104 else: 1105 ch = ch + (ord(h2) - ord('A') + 10) * 16 1106 ret = ret + chr(ch) 1107 ix = ix + 3 1108 1109 return ret + text[ix:] 1110 1111 1112 def SplitArgs(args, dest = None): 1113 args = str(args) 1114 if dest is None: 1115 dest = {} 1116 arg = args.split('&') 1117 for i in arg: 1118 kv = i.split('=', 1) 1119 if len(kv) == 2: 1120 s = unquote_plus(kv[1]) 1121 if kv[0] in dest: 1122 if type(dest[kv[0]]) != type([]): 1123 dest[kv[0]] = [dest[kv[0]]] 1124 dest[kv[0]].append(s) 1125 else: 1126 dest[kv[0]] = s 1127 else: 1128 dest[i] = '' 1129 1130 return dest 1131 1132 1133 def SplitMIMEArgs(fields, dest = None): 1134 if dest is None: 1135 dest = {} 1136 for field in fields.list: 1137 if field.name in dest: 1138 if type(dest[field.name]) != type([]): 1139 dest[field.name] = [dest[field.name]] 1140 if field.type != 'text/plain': 1141 dest[field.name].append(field.value) 1142 else: 1143 dest[field.name].append(unquote_plus(field.value)) 1144 elif field.type != 'text/plain': 1145 dest[field.name] = field.value 1146 else: 1147 dest[field.name] = urllib2.unquote(field.value) 1148 1149 return dest 1150 1151 1152 def PythonizeArgs(args): 1153 dest = SplitArgs(str(args)) 1154 for k, v in dest.iteritems(): 1155 dest[k] = Pythonize(v) 1156 1157 return dest 1158 1159 1160 def PackModalDialogueResult(result): 1161 r = '' 1162 for k, v in result.iteritems(): 1163 r += str(k) + '=' + str(v) + '&' 1164 1165 r = r[:-1] 1166 return r 1167 1168 1169 def UnpackModalDialogueResult(result): 1170 ret = {} 1171 if result: 1172 for each in result.split('&'): 1173 k, v = each.split('=') 1174 v = Pythonize(v) 1175 if k in ret: 1176 if type(ret[k]) != types.ListType: 1177 ret[k] = [ret[k]] 1178 ret[k].append(v) 1179 else: 1180 ret[k] = v 1181 1182 return ret 1183 1184 1185 def AddThousandSeparator(s): 1186 res = [] 1187 for i, c in enumerate(reversed(str(s))): 1188 if i and not i % 3: 1189 res.insert(0, '.') 1190 res.insert(0, c) 1191 1192 return ''.join(res) 1193 1194 1195 def CheckValue(id, idValue): 1196 if idValue is not None and idValue is not '': 1197 return ' %s="%s"' % (id, idValue) 1198 return '' 1199 1200 1201 class CSRFException(Exception): 1202 1203 def __init__(self, *args, **kwargs): 1204 Exception.__init__(self, *args, **kwargs) 1205 1206 1207 class HtmlWriter(): 1208 1209 def __init__(self, template = 'script:/wwwroot/lib/template/emptybase.html'): 1210 self.baseTemplate = template 1211 self.Clear() 1212 from carbon.common.script.sys.basesession import GetServiceSession 1213 self.session = GetServiceSession('HtmlWriter') 1214 self.ajaxDefaultURL = None 1215 self.ajaxCSRF = False 1216 1217 def LogInfo(self, *args, **keywords): 1218 self.Log(log.LGINFO, *args, **keywords) 1219 1220 def LogNotice(self, *args, **keywords): 1221 self.Log(log.LGNOTICE, *args, **keywords) 1222 1223 def LogWarn(self, *args, **keywords): 1224 self.Log(log.LGWARN, *args, **keywords) 1225 1226 def LogError(self, *args, **keywords): 1227 self.Log(log.LGERR, *args, **keywords) 1228 1229 def Log(self, severity, *args, **keywords): 1230 try: 1231 if len(args) == 1: 1232 s = strx(args[0]) 1233 else: 1234 s = ' '.join(map(strx, args)) 1235 log.sp.Log(s, severity, 1) 1236 except Exception as e: 1237 log.sp.Log('*** Error logging out logline: %s' % e, severity, 1) 1238 1239 def EspIcon(self, filename = 'none.gif', size = 32): 1240 iconUrl = '/img/' + filename 1241 return self.Image(iconUrl, 'width=%s height=%s border=0 align=absmiddle' % (size, size)) 1242 1243 def Clear(self): 1244 self.redirect = 'mainhtml' 1245 self.inserts = {} 1246 self.visualization = [] 1247 self.scripts = [] 1248 self.cssFiles = [] 1249 self.jsFiles = [] 1250 self.headjsScripts = [] 1251 self.inserts['title'] = 'HTML Writer Title' 1252 self.inserts['heading'] = 'HTML Writer Heading' 1253 self.WriteDirect('icon', self.EspIcon('none.gif', 32)) 1254 self.WriteDirect('stylesheet', '/lib/std.css') 1255 self.start = blue.os.GetCycles()[0] 1256 self.WriteDirect('bottom_left', '') 1257 self.inserts['navigation'] = '' 1258 self.WriteDirect('jscript', '') 1259 self.WriteDirect('head', '') 1260 self.WriteDirect('scripts', '') 1261 self.WriteDirect('visualscripts', '') 1262 self.WriteDirect('trackpage', '') 1263 self.WriteDirect('treeMenu', '') 1264 self.WriteDirect('headjs', '') 1265 self.WriteDirect('footer', '') 1266 self.visualcallbacks = [] 1267 self.enabledJscript = set() 1268 self.current_form_rules = None 1269 self.prettify = False 1270 1271 def CSRFFormField(self): 1272 return '<input type="hidden" name="csrf_token" value="%s" />' % GenerateCSRFToken(self.request) 1273 1274 def CSRF(self): 1275 self.ajaxCSRF = True 1276 1277 def ValidateCSRF(self): 1278 csrf_token = self.request.form['csrf_token'] if self.request.form is not None and 'csrf_token' in self.request.form else '' 1279 if csrf_token is None or len(csrf_token) == 0 or csrf_token != GenerateCSRFToken(self.request): 1280 return False 1281 return True 1282 1283 def toJavascriptDict(self, d = {}): 1284 map_fun = lambda x: ('%s' % x if x.startswith('function') or x.startswith('[') else "'%s'" % x) 1285 map_outer = lambda x: ('%s: %s' % (x, self.toJavascriptDict(d[x])) if isinstance(d[x], types.DictType) else '%s: %s' % (x, str(d[x]).lower())) 1286 map_key = lambda x: ('%s: %s' % (x, map_fun(d[x])) if isinstance(d[x], types.StringType) else map_outer(x)) 1287 return ''.join(['{', ', '.join(map(map_key, d.keys())), '}']) 1288 1289 def GetLocalizationLabel(self, labelText, messageID): 1290 return GetLocalizationLabel(labelText, messageID) 1291 1292 def Swing(self, text): 1293 return Swing(text) 1294 1295 def AddScript(self, src): 1296 self.AddJsFile(src) 1297 1298 def AddScriptRaw(self, source): 1299 self.scripts.append(source) 1300 1301 def AddHeadScript(self, src): 1302 self.headjsScripts.append('<script>head.js("%s")</script>' % src) 1303 1304 def AddJsFile(self, src): 1305 if src not in self.jsFiles: 1306 self.jsFiles.append(src) 1307 1308 def AddCss(self, src): 1309 self.AddCssFile(src) 1310 1311 def AddCssFile(self, src): 1312 if src not in self.cssFiles: 1313 self.cssFiles.append(src) 1314 1315 def AddSyntaxHighlighting(self, element, language = 'python'): 1316 if not self.prettify: 1317 self.AddScript('/js/prettify.js') 1318 self.AddCss('/css/prettify.css') 1319 self.WriteDirect('jscript', '$(document).ready(function(){ prettyPrint(); });') 1320 self.prettify = True 1321 return '<code class="prettyprint lang-%(language)s">%(element)s</code>' % locals() 1322 1323 def AddVisualJScript(self, package, source): 1324 self.EnableVisualTool(package=package) 1325 self.WriteDirect('visualscripts', source) 1326 1327 def AddVisualQueryJScript(self, package, visualTool, ajax, ctrlID, options = None, query = None, reloadData = None): 1328 self.EnableVisualTool(package=package) 1329 temp_reloadData = '\nsetTimeout(doVisual,%i);\n' % reloadData if reloadData is not None else None 1330 temp_script = [] 1331 temp_script.append("var query_%(ctrlID)s = new google.visualization.Query('%(ajax)s');" % {'ctrlID': ctrlID, 1332 'ajax': ajax}) 1333 if query is not None: 1334 temp_script.append("query_%(ctrlID)s.setQuery('%(query)s');" % {'ctrlID': ctrlID, 1335 'query': query}) 1336 temp_script.append('query_%(ctrlID)s.send(handle%(ctrlID)sResponse);' % {'ctrlID': ctrlID}) 1337 if temp_reloadData: 1338 temp_script.append(temp_reloadData) 1339 self.WriteDirect('visualscripts', '\n'.join(temp_script)) 1340 handleResponse = "\n var visual%(ctrlID)s;\n function handle%(ctrlID)sResponse(response) {\n if (response.isError()) {\n alert('Error in query: '+ response.getMessage() + ' ' + response.getDetailedMessage());\n }\n var data = response.getDataTable();\n if (!visual%(ctrlID)s) {\n visual%(ctrlID)s = new google.visualization.%(visualTool)s(document.getElementById('%(ctrlID)s'));\n }\n visual%(ctrlID)s.draw(data, %(opt)s);\n try {\n if (graphLoaded) {\n graphLoaded();\n }\n }\n catch(e) {}\n }\n " % {'ctrlID': ctrlID, 1341 'visualTool': visualTool, 1342 'opt': 'null' if options is None else self.toJavascriptDict(d=options)} 1343 self.visualcallbacks.append(handleResponse) 1344 1345 def _GoogleVisualization(self, ctrlID, header, lines, tool, style = None, options = None, events = None): 1346 if options is None: 1347 options = {} 1348 ms = UnicodeMemStream() 1349 ms.Write('\n <script type="text/javascript">\n function draw%(ctrlID)s() {\n var data = new google.visualization.DataTable();\n' % {'ctrlID': ctrlID}) 1350 ms.Write(''.join([ " data.addColumn('%s', '%s');\n" % (row[0], row[1]) for row in header ])) 1351 lineCount = len(lines) 1352 if lineCount > 0: 1353 ms.Write(' ') 1354 ms.Write('data.addRows([\n') 1355 rowIndex = 0 1356 for row in lines: 1357 cellIndex = 0 1358 ms.Write(' ') 1359 ms.Write('[') 1360 for h in header: 1361 if row[cellIndex] is not None: 1362 if h[0] in ('datetime', 'date'): 1363 ms.Write("Date.parse('%s')" % row[cellIndex]) 1364 elif h[0] in ('number',): 1365 ms.Write(str(row[cellIndex]).replace('L,', ',').replace('L]', ']')) 1366 else: 1367 ms.Write("'%s'" % unicode(row[cellIndex]).replace("u'", "'")) 1368 if len(header) > cellIndex + 1: 1369 ms.Write(',') 1370 cellIndex += 1 1371 1372 ms.Write(']') 1373 if lineCount > rowIndex + 1: 1374 ms.Write(',\n') 1375 rowIndex += 1 1376 1377 ms.Write('\n') 1378 ms.Write(' ') 1379 ms.Write(']);\n') 1380 ms.Write("\n var %(ctrlID)sGraph = new google.visualization.%(tool)s(document.getElementById('%(ctrlID)s'));\n " % {'ctrlID': ctrlID, 1381 'tool': tool}) 1382 if events is not None: 1383 for key in events.iterkeys(): 1384 ms.Write(" google.visualization.events.addListener(%(ctrlID)sGraph, '%(event)s', function() {\n" % {'ctrlID': ctrlID, 1385 'event': key}) 1386 ms.Write(events[key]) 1387 ms.Write(' });\n') 1388 1389 ms.Write("\n %(ctrlID)sGraph.draw(data, %(options)s);\n }\n google.charts.load('current', {'packages':['corechart', 'annotationchart']});\n google.setOnLoadCallback(draw%(ctrlID)s);\n </script>\n " % {'ctrlID': ctrlID, 1390 'options': str(options).replace('True', 'true').replace('False', 'false') if options else 'null', 1391 'tool': tool}) 1392 self.WriteDirect('scripts', ms) 1393 return self.GetDiv(['<img alt="Loading..." src="/static/img/ajax-loader-small.gif" /> '], ctrlID=ctrlID, style=style) 1394 1395 def GetAnnotatedTimeline(self, ctrlID, header, lines, style = None, options = None, events = None): 1396 self.EnableVisualTool('annotatedtimeline') 1397 return self._GoogleVisualization(ctrlID, header, lines, 'AnnotatedTimeLine', style, options, events) 1398 1399 def GetAnnotationChart(self, ctrlID, header, lines, style = None, options = None, events = None): 1400 self.EnableVisualTool('annotationchart') 1401 return self._GoogleVisualization(ctrlID, header, lines, 'AnnotationChart', style, options, events) 1402 1403 def WriteAnnotationChart(self, ctrlID, header, lines, style = None, options = None, events = None): 1404 self.Write(self.GetAnnotationChart(ctrlID, header, lines, style, options, events)) 1405 1406 def WriteAnnotatedTimeline(self, ctrlID, header, lines, style = None, options = None, events = None): 1407 self.Write(self.GetAnnotatedTimeline(ctrlID, header, lines, style, options, events)) 1408 1409 def _SetDefaultChartOptions(self, options, showLegend = True): 1410 if options is None: 1411 options = {} 1412 if 'fontSize' not in options: 1413 options['fontSize'] = '9' 1414 if 'fontName' not in options: 1415 options['fontName'] = 'Verdana' 1416 if 'chartArea' not in options: 1417 options['chartArea'] = {'left': 40, 1418 'top': 25, 1419 'height': '75%'} 1420 if 'legend' not in options and showLegend == False: 1421 options['legend'] = {'position': 'none'} 1422 1423 def GetLineChart(self, ctrlID, header, lines, style = None, options = None, events = None, showLegend = True): 1424 self.EnableVisualTool('corechart') 1425 self._SetDefaultChartOptions(options, showLegend) 1426 return self._GoogleVisualization(ctrlID, header, lines, 'LineChart', style, options, events) 1427 1428 def GetAreaChart(self, ctrlID, header, lines, style = None, options = None, events = None): 1429 self.EnableVisualTool('corechart') 1430 self._SetDefaultChartOptions(options, showLegend) 1431 return self._GoogleVisualization(ctrlID, header, lines, 'AreaChart', style, options, events) 1432 1433 def GetComboChart(self, ctrlID, header, lines, style = None, options = None, events = None, showLegend = True): 1434 self.EnableVisualTool('corechart') 1435 self._SetDefaultChartOptions(options, showLegend) 1436 return self._GoogleVisualization(ctrlID, header, lines, 'ComboChart', style, options, events) 1437 1438 def WriteLineChart(self, ctrlID, header, lines, style = None, options = None, events = None, showLegend = True): 1439 self.Write(self.GetLineChart(ctrlID, header, lines, style, options, events, showLegend)) 1440 1441 def WriteAreaChart(self, ctrlID, header, lines, style = None, options = None, events = None): 1442 self.Write(self.GetAreaChart(ctrlID, header, lines, style, options, events)) 1443 1444 def WriteComboChart(self, ctrlID, header, lines, style = None, options = None, events = None, showLegend = True): 1445 self.Write(self.GetComboChart(ctrlID, header, lines, style, options, events, showLegend)) 1446 1447 def GetColumnChart(self, ctrlID, header, lines, style = None, options = None, events = None, showLegend = True): 1448 self.EnableVisualTool('corechart') 1449 self._SetDefaultChartOptions(options, showLegend) 1450 return self._GoogleVisualization(ctrlID, header, lines, 'ColumnChart', style, options, events) 1451 1452 def WriteColumnChart(self, ctrlID, header, lines, style = None, options = None, events = None, showLegend = True): 1453 self.Write(self.GetColumnChart(ctrlID, header, lines, style, options, events, showLegend)) 1454 1455 def GetAreaChart(self, ctrlID, header, lines, style = None, options = None, events = None, showLegend = True): 1456 self.EnableVisualTool('corechart') 1457 self._SetDefaultChartOptions(options, showLegend) 1458 return self._GoogleVisualization(ctrlID, header, lines, 'AreaChart', style, options, events) 1459 1460 def WriteAreaChart(self, ctrlID, header, lines, style = None, options = None, events = None, showLegend = True): 1461 self.Write(self.GetAreaChart(ctrlID, header, lines, style, options, events, showLegend)) 1462 1463 def Reloader(self, url, sec, caption, className = None): 1464 randNumber = random.randint(1, 1000) 1465 timerID = 'timerSpan%i' % randNumber 1466 reloadID = 'reloadDiv%i' % randNumber 1467 script = '\n <script type="text/javascript">\n function func%(id)s() {\n $("#%(id)s").load(\'%(url)s\');\n }\n func%(id)s();\n var countdown%(rand)i = %(sec)i;\n var countdown%(rand)i_org = %(sec)i;\n function reset%(id)s() {\n countdown%(rand)i = 0;\n }\n function coundownc%(id)s() {\n setTimeout(coundownc%(id)s, 1000);\n var date = new Date(null);\n date.setSeconds(countdown%(rand)i);\n $("#%(timerID)s .csp-sec").html( date.toTimeString().substr(0, 8) );\n countdown%(rand)i = countdown%(rand)i - 1;\n if ( countdown%(rand)i<0 ) {\n countdown%(rand)i = countdown%(rand)i_org;\n func%(id)s();\n }\n }\n $("#%(timerID)s").html("<span class=\'csp-counter\'><img src=\'/static/img/ctrl_end.png\' onclick=\'reset%(id)s();\'/><span class=\'csp-sec\'></span></span>");\n coundownc%(id)s();\n </script>\n ' % {'id': reloadID, 1468 'url': url, 1469 'timerID': timerID, 1470 'rand': randNumber, 1471 'sec': sec} 1472 return self.GetDiv([self.GetDiv([self.GetSpan([caption], className='csp-caption'), self.GetSpan([], timerID)]), self.GetDiv([], reloadID), script], className=className) 1473 1474 def WriteReloader(self, url, sec, caption, className = None): 1475 self.Write(self.Reloader(url, sec, caption, className)) 1476 1477 def WriteJson(self, jsonName, jsonData): 1478 self.Write(['<script type="text/javascript">\nvar ', 1479 jsonName, 1480 ' = ', 1481 json.dumps(jsonData), 1482 ';\n', 1483 '</script>']) 1484 1485 def Canvas(self, ctrlID, width, height): 1486 return '<canvas id="%s" width="%i" height="%i"></canvas>' % (ctrlID, width, height) 1487 1488 def WriteCanvas(self, ctrlID, width, height): 1489 self.Write(self.Canvas(ctrlID, width, height)) 1490 1491 def IFrame(self, src, ctrlID = None, width = None, height = None): 1492 params = (src, 1493 CheckValue('id', ctrlID), 1494 CheckValue('width', width), 1495 CheckValue('height', height), 1496 ' scrolling="no" frameborder="0" marginheight="0" marginwidth="0"') 1497 return '<iframe src="%s"%s%s%s%s></iframe>' % params 1498 1499 def WriteIFrame(self, src, ctrlID = None, width = None, height = None): 1500 self.Write(self.IFrame(src, ctrlID, width, height)) 1501 1502 def DrawList(self, drawList, width, height): 1503 self.AddScript(src='/static/js/libs/excanvas.js') 1504 ctrlID = 'drawListCanvas' 1505 self.WriteJson('drawList', drawList) 1506 self.WriteCanvas(ctrlID, width, height) 1507 self.Write('\n <script type="text/javascript">\n var canvas = document.getElementById("%(ctrlID)s");\n if (typeof(G_vmlCanvasManager) != \'undefined\') {\n canvas = G_vmlCanvasManager.initElement(canvas);\n }\n var ctx = canvas.getContext("2d");\n $.each(drawList, function(index, element) {\n console.log(element);\n if (typeof element.area != \'undefined\') {\n ctx.fillStyle = element.area.color;\n ctx.fillRect(element.area.x, element.area.y, element.area.w, element.area.h);\n }\n else if (typeof element.label != \'undefined\') {\n ctx.fillStyle = element.label.color;\n ctx.font = "bold 36px sans-serif";\n ctx.fillText(element.label.title, element.label.x, element.label.y);\n }\n else if (typeof element.circle != \'undefined\') {\n ctx.fillStyle = element.circle.color;\n ctx.beginPath();\n ctx.arc(element.circle.x, element.circle.y, element.circle.r, 2*Math.PI, false);\n ctx.fill();\n ctx.closePath();\n }\n else if (typeof element.line != \'undefined\') {\n ctx.fillStyle = element.line.color;\n ctx.lineWidth = 2;\n ctx.beginPath();\n ctx.moveTo(element.line.x1, element.line.y1);\n ctx.lineTo(element.line.x2, element.line.y2);\n ctx.stroke();\n }\n });\n </script>\n ' % {'ctrlID': ctrlID}) 1508 1509 def FormatDate(self, dateString): 1510 if dateString is not None: 1511 date_part = [ int(x) for x in dateString.split('.') ] 1512 return blue.os.GetTimeFromParts(date_part[0], date_part[1], date_part[2], 0, 0, 0, 0) 1513 1514 def _Host(self): 1515 try: 1516 func = lambda x: (True if x.lower().startswith('host') else False) 1517 host = filter(func, self.request.raw.split('\r\n'))[0].split(':') 1518 return (host[1].strip(), host[2].strip()) 1519 except: 1520 return ('', '') 1521 1522 def GetExcelWebQuery(self, q, label): 1523 host = self._Host() 1524 url = 'http://%s:%s%s' % (host[0], host[1], q) 1525 return self.GetA(innerText=label, href='/info/iqy.py?q=%s' % url) 1526 1527 def EnableInfoVisToolkit(self, src = None): 1528 self.AddScript('/static/js/libs/excanvas.js') 1529 self.AddScript('/static/js/libs/jit.js') 1530 if src is not None: 1531 self.AddScript(src) 1532 1533 def EnableVisualTool(self, package): 1534 allowedTools = ['annotatedtimeline', 1535 'annotationchart', 1536 'areachart', 1537 'barchart', 1538 'columnchart', 1539 'corechart', 1540 'gauge', 1541 'geomap', 1542 'imageareachart', 1543 'imagebarchart', 1544 'imagechart', 1545 'imagelinechart', 1546 'imagepiechart', 1547 'imagesparkline', 1548 'intensitymap', 1549 'linechart', 1550 'map', 1551 'motionchart', 1552 'orgchart', 1553 'piechart', 1554 'scatterchart', 1555 'table', 1556 'treemap', 1557 'areachart'] 1558 if package not in allowedTools: 1559 raise Exception("The tool '%s' isn't allowed. Allowed tools are %s" % (package, allowedTools)) 1560 if package not in self.visualization: 1561 self.visualization.append(package) 1562 if len(self.visualization) == 1: 1563 temp_script = '\n <script type="text/javascript" src="https://www.google.com/jsapi"></script>\n ' 1564 self.WriteDirect('scripts', temp_script) 1565 1566 def EnableResizable(self, ctrlID): 1567 jscript = '\n <SCRIPT type=text/javascript>\n $(function() {\n $("#%(ctrlID)s").resizable({\n handles: "se" });\n });\n </SCRIPT>' % {'ctrlID': ctrlID} 1568 self.WriteDirect('jscript', jscript) 1569 1570 def EnableFormValidation(self, formID): 1571 jscript = '\n $(document).ready(function() {\n $("#%(formID)s").validate(%(formrules)s);\n });\n ' % {'formID': formID, 1572 'formrules': '' if self.current_form_rules is None else '{rules: %s}' % self.current_form_rules} 1573 self.WriteDirect('jscript', jscript) 1574 1575 def EnableFormRules(self, rules = {}): 1576 self.current_form_rules = self.toJavascriptDict(rules) 1577 1578 def EnableTextEditor(self, ctrlID): 1579 jscript = '\n <script type="text/javascript">\n $(function() {\n $("#%(ctrlID)s").htmlarea();\n })\n </script>\n ' % {'ctrlID': ctrlID} 1580 self.Write(jscript) 1581 1582 def EnableAccordion(self, ctrlID): 1583 jscript = '\n $(function() {\n $("#%(ctrlID)s").accordion();\n });\n ' % {'ctrlID': ctrlID} 1584 self.WriteDirect('jscript', jscript) 1585 1586 def EnableChar(self): 1587 jscript = 'var api = new jGCharts.Api();\n' 1588 self.WriteDirect('jscript', jscript) 1589 1590 def __EnableTabs(self, tabsID): 1591 jscript = '\n <script type="text/javascript">\n $(function() {\n $("#%(tabsID)s").tabs({\n select: function(event, ui) {\n window.location = "#"+ui.index\n },\n spinner: \'Retrieving data\'\n });\n });\n $(function() {\n var loc = window.location.toString().split("#");\n if (loc.length == 2) {\n $("#%(tabsID)s").tabs("option", "selected", parseInt(loc[1]));\n }\n });\n </script>\n ' % {'tabsID': tabsID} 1592 self.Write(jscript) 1593 1594 def GetStyleButton(self, href, innerText, cssClass = 'buttonblack'): 1595 res = UnicodeMemStream() 1596 if cssClass is not None: 1597 cssClass = ' %s' % cssClass 1598 res.Write('<a href="%s" class="button %s">' % (href, cssClass)) 1599 res.Write(innerText) 1600 res.Write('</a>') 1601 res.Seek(0) 1602 return res.Read() 1603 1604 def GetImage(self, src, ctrlID = None, className = None, style = None, title = None, rel = None): 1605 ctrlID = CheckValue('id', ctrlID) 1606 className = CheckValue('class', className) 1607 style = CheckValue('style', style) 1608 title = CheckValue('title', title) 1609 rel = CheckValue('rel', rel) 1610 return '<img src="%s" %s%s%s%s%s/>' % (src, 1611 ctrlID, 1612 className, 1613 style, 1614 title, 1615 rel) 1616 1617 def GetMessage(self, heading, label, cssClass): 1618 if type(label) == types.ListType: 1619 label = '<br/>' + '<br/>'.join(label) 1620 return '<div class="message %s"><p><strong>%s</strong> %s</p></div>' % (cssClass, heading, label) 1621 1622 def GetSuccess(self, label): 1623 return self.GetMessage('Success!', label, 'success') 1624 1625 def GetError(self, label): 1626 return self.GetMessage('Error!', label, 'error') 1627 1628 def GetWarning(self, label): 1629 return self.GetMessage('Warning!', label, 'warning') 1630 1631 def GetTip(self, label): 1632 return self.GetMessage('Tip!', label, 'tip') 1633 1634 def GetInfo(self, label): 1635 return self.GetMessage('Info!', label, 'tip') 1636 1637 def GetInlineHeader(self, ctrlID, innerText, rev): 1638 return '<h3 id="%(ctrlID)s" class="editable" rev="%(rev)s">%(innerText)s</h3>' % {'ctrlID': ctrlID, 1639 'rev': rev, 1640 'innerText': innerText} 1641 1642 def GetInlineArea(self, ctrlID, innerText, rev): 1643 return '<p id="%(ctrlID)s" class="editable-area" rev="%(rev)s">%(innerText)s</p>' % {'ctrlID': ctrlID, 1644 'rev': rev, 1645 'innerText': innerText} 1646 1647 def GetInlineHelp(self, label, header, body): 1648 return '<span class="inlinehelp" title="%(header)s|%(body)s">%(label)s</span>' % {'label': label, 1649 'header': header, 1650 'body': body} 1651 1652 def GetInline(self, ctrlID, innerText, rev): 1653 return '<span id="%(ctrlID)s" class="editable" rev="%(rev)s">%(innerText)s</span>' % {'ctrlID': ctrlID, 1654 'rev': rev, 1655 'innerText': innerText} 1656 1657 def GetWaitingMessage(self, message): 1658 return WaitingMessage(message) 1659 1660 def GetForm(self, ctrlID, formMethod, fileName, formAction, elements, multiPart = False, waitingMessage = None): 1661 self.EnableFormValidation(ctrlID) 1662 encType = ' enctype="multipart/form-data"' if multiPart else '' 1663 formAction = '%(fileName)s?action=%(formAction)s' % {'fileName': fileName, 1664 'formAction': formAction} 1665 res = [] 1666 formMethod = str(formMethod).upper() 1667 res.append(_GetElementBegin('form', ' id="%s" action="%s" method="%s"%s' % (ctrlID, 1668 formAction, 1669 formMethod, 1670 encType))) 1671 if formMethod not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): 1672 res.append(self.CSRFFormField()) 1673 if waitingMessage is not None: 1674 res.append(self.GetWaitingMessage(waitingMessage)) 1675 for n in elements: 1676 res.append(n) 1677 1678 res.append(_GetElementEnd('form')) 1679 return ''.join(res) 1680 1681 def GetLayoutTable(self, ctrlID = None, rows = []): 1682 res = UnicodeMemStream() 1683 ctrlID = CheckValue('id', ctrlID) 1684 res.Write('<div%s class="csp-table">' % ctrlID) 1685 for r in rows: 1686 res.Write('<div class="csp-row">') 1687 if isinstance(r, list): 1688 for c in r: 1689 res.Write('<div class="csp-cell">%s</div>' % c) 1690 1691 else: 1692 res.Write('<div class="csp-cell">%s</div>' % r) 1693 res.Write('</div>') 1694 1695 res.Write('</div>') 1696 res.Seek(0) 1697 return res.Read() 1698 1699 def MaxPageNumber(self, current_page, page_size, num_of_records): 1700 num_of_pages = num_of_records / page_size + (1 if num_of_records % page_size > 0 else 0) 1701 if current_page > num_of_pages: 1702 current_page = 1 1703 return (current_page, num_of_pages) 1704 1705 def GetPagingNext(self, nextOptions = {}, pageCount = 0, nextEnabled = True): 1706 if nextEnabled: 1707 url = urllib.urlencode(nextOptions) 1708 return self.GetA(innerText='Next %s' % str(pageCount) if pageCount > 0 else '', href='?%s' % url, className='button buttonblue') 1709 else: 1710 return self.GetSpan(['Next %s' % str(pageCount) if pageCount > 0 else ''], className='dark-gray') 1711 1712 def GetPagingFirstNext(self, firstOptions = {}, nextOptions = {}, pageCount = 0, firstEnabled = True, nextEnabled = True): 1713 action = [] 1714 if firstEnabled: 1715 url = urllib.urlencode(firstOptions) 1716 action.append(self.GetA(innerText='First', href='?%s' % url, className='button buttonblue')) 1717 else: 1718 action.append(self.GetSpan(['First'], className='dark-gray')) 1719 if nextEnabled: 1720 url = urllib.urlencode(nextOptions) 1721 action.append(self.GetA(innerText='Next %s' % str(pageCount) if pageCount > 0 else '', href='?%s' % url, className='button buttonblue')) 1722 else: 1723 action.append(self.GetSpan(['Next %s' % str(pageCount) if pageCount > 0 else ''], className='dark-gray')) 1724 return ' | '.join(action) 1725 1726 def GetPaging(self, current_page, page_size, num_of_records, page_sizes): 1727 res = UnicodeMemStream() 1728 num_of_pages = num_of_records / page_size + (1 if num_of_records % page_size > 0 else 0) 1729 if page_size not in [0] + page_sizes: 1730 page_sizes.append(page_size) 1731 options = [] 1732 for p in page_sizes: 1733 options.append('<option value="%(num)i"%(sel)s>%(num)i</option>' % {'num': p, 1734 'sel': ' selected="selected"' if page_size == p else ''}) 1735 1736 options.append('<option value="0"%(sel)s>All</option>' % ' selected' if page_size is 0 else '') 1737 res.Write('\n\n <div class="%(tableid)s">\n <span class="csp-paging"><img src="/img/ds_first.png" alt="First"/></span>\n <span class="csp-paging"><img src="/img/ds_previous.png" alt="Previous"/></span>\n <span class="csp-paging"> <input id="%(tableid)s_row" type="text" value="%(current_page)i" style="width:15px;"/> <span class="inlinehelp" title="Count: %(pages)i">of %(numofpages)i</span></span>\n <span class="csp-paging"><img src="/img/ds_next.png" alt="Next"/></span>\n <span class="csp-paging"><img src="/img/ds_last.png" alt="Last"/></span>\n <span class="csp-paging">\n <select id="%(tableid)s_numofpages">\n %(opt)s\n </select>\n </span>\n <span class="csp-paging"> <a class="csp-paging-submit button buttongray">Go</a></span>\n\n <script type="text/javascript">\n $(".csp-paging-submit").click(function(e) {\n p = parseInt($("#%(tableid)s_row").val());\n s = parseInt($("#%(tableid)s_numofpages").val());\n $.paginglocation(location.href, {"page": p, "pagesize": s});\n });\n $(".%(tableid)s").find("img").click(function(e) {\n var src = $(this).attr("src");\n p = parseInt($("#%(tableid)s_row").val());\n if (src.indexOf("ds_first") > 0 && p > 1) {\n $.paginglocation(location.href, {"page": 1, "pagesize": %(pagesize)i});\n }\n else if (src.indexOf("ds_previous") > 0 && p > 1) {\n $.paginglocation(location.href, {"page": p-1, "pagesize": %(pagesize)i});\n }\n else if (src.indexOf("ds_next") > 0 && p < %(numofpages)i) {\n $.paginglocation(location.href, {"page": p+1, "pagesize": %(pagesize)i});\n }\n else if (src.indexOf("ds_last") > 0) {\n $.paginglocation(location.href, {"page": %(numofpages)i, "pagesize": %(pagesize)i});\n }\n });\n </script>\n </div>\n ' % {'current_page': current_page, 1738 'pages': num_of_records, 1739 'pagesize': page_size, 1740 'opt': '\n'.join(options), 1741 'numofpages': num_of_pages, 1742 'tableid': 'csp-table-paging'}) 1743 res.Seek(0) 1744 return res.Read() 1745 1746 def GetTreeTable(self, header = [], lines = [], index = 0, index_parent = 1): 1747 id = 'table_%s' % str(random.randint(1, 1000)) 1748 res = UnicodeMemStream() 1749 res.Write('\n <script type="text/javascript">\n $(document).ready(function() {\n $("#%(tableId)s").treeTable();\n });\n </script>\n ' % {'tableId': id}) 1750 res.Write('<table id="%s" class="treeTable"><thead><tr>' % id) 1751 res.Write(''.join([ '<th>%s</th>' % x for x in header ])) 1752 res.Write('</tr></thead><tbody>') 1753 for row in lines: 1754 res.Write('<tr id="node-%i"%s>' % (row[index], '' if row[index_parent] is None else ' class="child-of-node-%i"' % row[index_parent])) 1755 for i in range(0, len(row)): 1756 if index_parent != i: 1757 res.Write('<td%s>' % (' class="first"' if i == 0 else '')) 1758 res.Write(row[i]) 1759 res.Write('</td>') 1760 1761 res.Write('</tr>') 1762 1763 res.Write('</tbody></table>') 1764 res.Seek(0) 1765 return res.Read() 1766 1767 def GetPropertyTable(self, header = None, lines = None, style = 'width: 250px'): 1768 lines = [ ['<strong>%s</strong>' % x, y] for x, y in lines.items() ] 1769 return self.GetDiv([self.GetTable(header, lines, showCount=False)], style=style) 1770 1771 def GetTable(self, header = None, lines = None, className = 'tablesorter', enableEdit = False, editUrl = None, enableDelete = False, deleteUrl = None, useFilter = False, invertSelection = False, paging = None, customActions = None, serverOrder = False, baseUrl = None, keyFields = None, readOnlyFields = None, showCount = True, cssByRow = None): 1772 return GetTable(header, lines, className, enableEdit, editUrl, enableDelete, deleteUrl, useFilter, invertSelection, paging, customActions, serverOrder, baseUrl, keyFields, readOnlyFields, showCount, cssByRow) 1773 1774 def GetDashboard(self, layout, area1, area2 = None, area3 = None, area4 = None, area5 = None, area6 = None, area7 = None, area8 = None, skin = True): 1775 if layout not in ('dashboard0', 'dashboard1', 'dashboard2', 'dashboard3', 'dashboard4', 'dashboard5', 'dashboard6'): 1776 raise Exception('GetDashboard(layout... only accepts one of those elements [dashboard0, dashboard1, dashboard2, dashboard3, dashboard4, dashboard5, dashboard6]') 1777 layouts = {'dashboard0': '<div class="csp-row"><div class="csp-cell-dash">%(area1)s</div></div><div class="csp-row"><div class="csp-cell-dash">%(area2)s</div></div>', 1778 'dashboard1': '<div class="csp-row"><div class="csp-cell-dash">%(area1)s</div><div class="csp-cell-dash">%(area2)s</div></div>', 1779 'dashboard2': '<div class="csp-row"><div class="csp-cell-dash">%(area1)s</div><div class="csp-cell-dash">%(area2)s</div></div>\n <div class="csp-row"><div class="csp-cell-dash">%(area3)s</div><div class="csp-cell-dash">%(area4)s</div></div>', 1780 'dashboard3': '<div class="csp-row"><div class="csp-cell-dash">%(area1)s</div><div class="csp-cell-dash">%(area2)s</div></div>\n <div class="csp-row"><div class="csp-cell-dash">%(area3)s</div><div class="csp-cell-dash"><div class="csp-table">\n <div class="csp-row"><div class="csp-cell-dash">%(area4)s</div><div class="csp-cell-dash">%(area5)s</div></div></div></div></div>', 1781 'dashboard4': '\n <div class="csp-row">\n <div class="csp-cell-dash">%(area1)s</div>\n <div class="csp-cell-dash">%(area2)s</div>\n <div class="csp-cell-dash">%(area3)s</div>\n </div>\n <div class="csp-row">\n <div class="csp-cell-dash">%(area4)s</div>\n <div class="csp-cell-dash">%(area5)s</div>\n <div class="csp-cell-dash">%(area6)s</div>\n </div>', 1782 'dashboard5': '<div class="csp-row"><div class="csp-cell-dash">%(area1)s</div><div class="csp-cell-dash">%(area2)s</div>\n <div class="csp-cell-dash">%(area3)s</div><div class="csp-cell-dash">%(area4)s</div></div>\n <div class="csp-row"><div class="csp-cell-dash">%(area5)s</div><div class="csp-cell-dash">%(area6)s</div>\n <div class="csp-cell-dash">%(area7)s</div><div class="csp-cell-dash">%(area8)s</div></div>', 1783 'dashboard6': '\n <div class="csp-row">\n <div class="csp-cell-dash">%(area1)s</div>\n </div>\n </div>\n <div class="csp-table-dash">\n <div class="csp-row">\n <div class="csp-cell-dash">%(area2)s</div>\n <div class="csp-cell-dash">%(area3)s</div>\n </div>'} 1784 cssHPart = CheckValue('class', 'csp-part-header' if skin is True else 'csp-part-header-noskin') 1785 cssPart = CheckValue('class', 'csp-part' if skin is True else 'csp-part-noskin') 1786 checkTuple = lambda x, y: '<div%(cssheader)s>%(h)s</div><div%(cssbody)s>%(b)s</div>' % {'h': x, 1787 'b': y, 1788 'cssheader': cssHPart, 1789 'cssbody': cssPart} 1790 checkIndex = lambda area: (''.join([ checkTuple(x, y) for x, y in area ]) if area is not None else '') 1791 res = UnicodeMemStream() 1792 res.Write('<div class="csp-table-dash">') 1793 res.Write(layouts[layout] % {'area1': checkIndex(area1), 1794 'area2': checkIndex(area2), 1795 'area3': checkIndex(area3), 1796 'area4': checkIndex(area4), 1797 'area5': checkIndex(area5), 1798 'area6': checkIndex(area6), 1799 'area7': checkIndex(area7), 1800 'area8': checkIndex(area8)}) 1801 res.Write('</div>') 1802 res.Seek(0) 1803 return res.Read() 1804 1805 def GetProcessCssClass(self, percent, process_scale): 1806 className = 'bar-high' 1807 if process_scale == 3: 1808 if percent < 34: 1809 className = 'bar-low' 1810 elif percent < 67: 1811 className = 'bar-mid' 1812 elif percent < 100: 1813 className = 'bar-high-mid' 1814 elif percent > 99: 1815 className = 'bar-high' 1816 elif process_scale == 5: 1817 if percent < 26: 1818 className = 'bar-low' 1819 elif percent < 51: 1820 className = 'bar-mid-low' 1821 elif percent < 76: 1822 className = 'bar-mid' 1823 elif percent < 100: 1824 className = 'bar-high-mid' 1825 return className 1826 1827 def GetCellBullet(self, percent, process_scale = 3): 1828 className = self.GetProcessCssClass(percent, process_scale) 1829 className = CheckValue('class', className) 1830 return '<div class="csp-bullet"><div %(className)sstyle="width: 100%%"></div></div>' % {'className': className} 1831 1832 def GetCellProcess(self, percent, process_scale = 3): 1833 className = self.GetProcessCssClass(percent, process_scale) 1834 className = CheckValue('class', className) 1835 return '<div class="csp-progress"><div title="%(percenttext)s%%" %(className)sstyle="width: %(percent)s%%"></div></div>' % {'percent': min(int(percent), 100), 1836 'percenttext': int(percent), 1837 'className': className} 1838 1839 def GetFieldset(self, ctrlID = None, elements = [], label = None): 1840 res = [] 1841 res.append(_GetElementBegin('fieldset', '')) 1842 if label: 1843 res.append('<legend>%s</legend>' % label) 1844 for n in elements: 1845 res.append(n) 1846 1847 res.append(_GetElementEnd('fieldset')) 1848 return '\n'.join(res) 1849 1850 def GetSimpleForm(self, formMethod = 'post', fileName = '', formAction = '', elements = None, waitingMessage = None, closeForm = True): 1851 ctrlID = 'form_%s' % str(random.randint(1, 1000)) 1852 self.EnableFormValidation(ctrlID) 1853 formAction = '%(fileName)s?action=%(formAction)s' % {'fileName': fileName, 1854 'formAction': formAction} 1855 res = [] 1856 formMethod = str(formMethod).upper() 1857 res.append(_GetElementBegin('form', ' id="%s" action="%s" method="%s"' % (ctrlID, formAction, str(formMethod).upper()))) 1858 if formMethod not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): 1859 res.append(self.CSRFFormField()) 1860 if waitingMessage is not None: 1861 res.append(self.GetWaitingMessage(waitingMessage)) 1862 res.append(_GetElementBegin('div', '')) 1863 for n in elements: 1864 res.append(self.GetP([n])) 1865 1866 res.append(_GetElementEnd('div')) 1867 if closeForm: 1868 res.append(_GetElementEnd('form')) 1869 return '\n'.join(res) 1870 1871 def GetSimpleDialogForm(self, formMethod = 'post', fileName = '', formAction = '', elements = None, height = 140, width = 300, title = '', autoOpen = True, ctrlID = None, submitButton = 'Submit'): 1872 if ctrlID is None: 1873 ctrlID = 'form_%i' % random.randint(1, 1000) 1874 m_ctrlID = 'dialog-modal_%s' % ctrlID 1875 self.Write('<script type="text/javascript">\n $(function() {\n $( "#%(ctrlID)s" ).dialog({\n autoOpen: %(autoOpen)s,\n height: %(height)s,\n width: %(width)s,\n modal: true,\n buttons: {\n "%(submitButton)s" : function() {\n $("#%(formID)s").submit();\n },\n Cancel: function() {\n $(this).dialog("close");\n }\n }\n });\n });\n </script>' % {'ctrlID': m_ctrlID, 1876 'height': height, 1877 'width': width, 1878 'autoOpen': str(autoOpen).lower(), 1879 'submitButton': submitButton, 1880 'formID': ctrlID}) 1881 form = self.GetForm(ctrlID=ctrlID, formMethod=formMethod, fileName=fileName, formAction=formAction, elements=elements) 1882 return self.GetDiv([form], ctrlID=m_ctrlID, title=title) 1883 1884 def GetHidden(self, name, value = ''): 1885 return '<input type="hidden" name="%(name)s" id="%(name)s" value="%(value)s"/>' % {'name': name, 1886 'value': value} 1887 1888 def GetDiv(self, elements, ctrlID = None, className = None, style = None, title = None, dataBind = None): 1889 return _GetElements(elements, 'div', ctrlID, className, style, title, dataBind) 1890 1891 def GetSpan(self, elements, ctrlID = None, className = None, style = None, title = None, dataBind = None): 1892 return GetSpan(elements, ctrlID, className, style, title, dataBind) 1893 1894 def GetP(self, elements, ctrlID = None, className = None, style = None): 1895 return _GetElements(elements, 'p', ctrlID, className, style) 1896 1897 def GetUl(self, elements, ctrlID = None, className = None, style = None): 1898 return _GetElements(elements, 'ul', ctrlID, className, style) 1899 1900 def GetLi(self, elements, ctrlID = None, className = None, style = None): 1901 return _GetElements(elements, 'li', ctrlID, className, style) 1902 1903 def GetA(self, innerText, href, ctrlID = None, className = None, style = None, onClick = None, title = None, rel = None, rev = None, target = None): 1904 return GetA(innerText, href, ctrlID, className, style, onClick, title, rel, rev, target) 1905 1906 def H1(self, innerText, ctrlID = None, className = None, style = None): 1907 return _GetElement(ctrlName='h1', ctrlValue=innerText, ctrlID=ctrlID, className=className, style=style) 1908 1909 def H2(self, innerText, ctrlID = None, className = None, style = None): 1910 return _GetElement(ctrlName='h2', ctrlValue=innerText, ctrlID=ctrlID, className=className, style=style) 1911 1912 def H3(self, innerText, ctrlID = None, className = None, style = None): 1913 return _GetElement(ctrlName='h3', ctrlValue=innerText, ctrlID=ctrlID, className=className, style=style) 1914 1915 def H4(self, innerText, ctrlID = None, className = None, style = None): 1916 return _GetElement(ctrlName='h4', ctrlValue=innerText, ctrlID=ctrlID, className=className, style=style) 1917 1918 def GetFileInput(self, ctrlID, labelCaption, className = None, width = None, title = ''): 1919 if width: 1920 width = ' style="width:%spx"' % width 1921 else: 1922 width = '' 1923 className = CheckValue('class', className) 1924 title = CheckValue('title', title) 1925 res = [] 1926 if labelCaption is not None: 1927 res.append('<label class="form-label" for="%s">%s</label>' % (ctrlID, labelCaption)) 1928 res.append('<input id="%(ctrlID)s" name="%(ctrlID)s" type="file" %(className)s%(width)s%(title)s/>' % {'ctrlID': ctrlID, 1929 'className': className, 1930 'width': width, 1931 'title': title}) 1932 return '\n'.join(res) 1933 1934 def GetInput(self, ctrlID, labelCaption, className = None, minLength = None, width = None, value = None, title = ''): 1935 return GetInput(ctrlID, labelCaption, className, minLength, width, value, title) 1936 1937 def GetSelect(self, elements, controlID, labelCaption = None, elementClass = None, selectedValue = None, attributes = None): 1938 return GetSelect(elements, controlID, labelCaption, elementClass, selectedValue, attributes) 1939 1940 def GetToggle(self): 1941 return self.GetCheck(ctrlID='', labelCaption='', className='toggle-table', checked=False) 1942 1943 def WriteCheckAndColoredLabel(self, label, isChecked = False, isDisabled = True, isSmall = True, isSubContainer = False): 1944 label = self.FontBoldGreen(label) if isChecked else self.FontBoldBrown(label) 1945 self.WriteCheckAndLabel(label, isChecked, isDisabled, isSmall, isSubContainer) 1946 1947 def WriteCheckAndLabel(self, label, isChecked = False, isDisabled = False, isSmall = True, isSubContainer = False): 1948 checkClass = 'checkbox-small' if isSmall else 'checkbox-big' 1949 check = self.GetCheck(ctrlID='', labelCaption='', className=checkClass, checked=isChecked, disabled=isDisabled) 1950 containerClass = 'flex-subcontainer' if isSubContainer else 'flex-container' 1951 self.WriteInContainer(html=check + label, className=containerClass) 1952 1953 def GetCheck(self, ctrlID, labelCaption, className, checked, disabled = False): 1954 className = CheckValue('class', className) 1955 title = CheckValue('title', labelCaption) 1956 controlID = CheckValue('id', ctrlID) 1957 controlName = CheckValue('name', ctrlID) 1958 res = [] 1959 if labelCaption is not None and len(labelCaption) > 0: 1960 res.append('<label class="form-label" for="%s">%s</label>' % (ctrlID, labelCaption)) 1961 che = ' checked="checked"' if checked else '' 1962 dis = ' disabled' if disabled else '' 1963 res.append('<input type="checkbox"%s%s%s%s%s%s/>' % (controlID, 1964 controlName, 1965 className, 1966 che, 1967 title, 1968 dis)) 1969 return '\n'.join(res) 1970 1971 def GetTextArea(self, ctrlID, labelCaption, className, cols, rows, innerHtml = None): 1972 return GetTextArea(ctrlID, labelCaption, className, cols, rows, innerHtml) 1973 1974 def GetButton(self, className, elementValue): 1975 return '<input class="%(className)s" type="submit" value="%(elementValue)s" />' % {'className': className, 1976 'elementValue': elementValue} 1977 1978 def GetTabs(self, tabs, content, ctrlID): 1979 self.__EnableTabs(ctrlID) 1980 tabs = ['<ul>'] + tabs + ['</ul>'] + content 1981 return self.GetDiv(tabs, ctrlID) 1982 1983 def GetTabsAjax(self, links): 1984 ctrlID = 'tabs_%s' % str(random.randint(1, 1000)) 1985 self.__EnableTabs(ctrlID) 1986 elements = [] 1987 elements.append('<ul>') 1988 for l in links: 1989 if len(l[0]): 1990 elements.append('<li><a href="%s"><span>%s</span></a></li>' % (l[0], l[1])) 1991 else: 1992 elements.append('<li><span>%s</span></li>' % (l[1],)) 1993 1994 elements.append('</ul>') 1995 return self.GetDiv(elements, ctrlID=ctrlID, className=None, style=None) 1996 1997 def GetTab(self, ctrlID, label): 1998 return self.GetLi([self.GetA(label, '#%s' % ctrlID)], None) 1999 2000 def GetFloatMessage(self, messageText): 2001 return '\n <div class="messagebox information">\n Information<br />\n <strong>%s</strong>\n </div>\n <script type="text/javascript">\n var options = {};\n $(".messagebox").show("blind", options, 1500, showCallback);\n\n function showCallback() {\n $(".messagebox").hide("blind", options, 1500);\n }\n </script>\n ' % messageText 2002 2003 def GetTooltip(self, href, ajax, title, caption, ctrlID = None): 2004 return self.GetA(innerText=caption, href=href, ctrlID=ctrlID, className='a-tip', style=None, onClick=None, title=title, rel=ajax) 2005 2006 def GetTooltipActions(self, href, ajax, title, caption, actions = [], ctrlID = None): 2007 html = '<div class="csp-dropmenu"><span>%(tooltip)s<em class="csp-opener"><img alt="dropdown" src="/img/down.png"></em>\n <ul class="csp-sublist">%(links)s</ul></span></div>' % {'tooltip': self.GetTooltip(href, ajax, title, caption + ' '), 2008 'links': ''.join([ '<li>%s</li>' % x for x in actions ])} 2009 return html 2010 2011 def Write(self, html): 2012 if html is not None: 2013 if self.redirect not in self.inserts: 2014 ms = UnicodeMemStream() 2015 self.inserts[self.redirect] = ms 2016 else: 2017 ms = self.inserts[self.redirect] 2018 if isinstance(html, list): 2019 for htmlItem in html: 2020 ms.Write(htmlItem) 2021 2022 elif isinstance(html, UnicodeMemStream): 2023 html.Seek(0) 2024 ms.Write(html.Read()) 2025 else: 2026 ms.Write(html) 2027 2028 def WriteFloatMessage(self, messageText): 2029 self.Write(self.GetFloatMessage(messageText)) 2030 2031 def WriteBeginForm(self, formName, formMethod, formAction): 2032 self.Write('<form id="%s" method="%s" action="%s">' % (formName, formMethod, formAction)) 2033 2034 def WriteEndForm(self): 2035 self.Write('</form>') 2036 2037 def GetDatePicker(self, ctrlID, ctrlCaption, ctrlFormat = 'yy-mm-dd', ctrlValue = None, ctrlTitle = None): 2038 now = datetime.now() 2039 res = [] 2040 res.append('<SCRIPT type=text/javascript>\n $(function() {\n $("#%(ctrlID)s").datepicker({\n dateFormat: \'%(ctrlFormat)s\',\n changeMonth: true,\n changeYear: true,\n showWeek: true,\n showOn: \'button\',\n yearRange: \'%(fromYear)i:%(toYear)s\'\n });\n });\n </SCRIPT>\n' % {'ctrlID': ctrlID, 2041 'ctrlFormat': ctrlFormat, 2042 'fromYear': now.year - 85, 2043 'toYear': now.year + 35}) 2044 ctrlValue = CheckValue('value', ctrlValue) 2045 ctrlTitle = CheckValue('title', ctrlTitle) 2046 if ctrlCaption: 2047 res.append('<label class="form-label" for="%(ctrlID)s">%(ctrlCaption)s</label>' % {'ctrlID': ctrlID, 2048 'ctrlCaption': ctrlCaption}) 2049 res.append('<input id="%(ctrlID)s" name="%(ctrlID)s" type="text" style="width: 80px;"%(ctrlValue)s%(ctrlTitle)s/>' % {'ctrlID': ctrlID, 2050 'ctrlValue': ctrlValue, 2051 'ctrlTitle': ctrlTitle}) 2052 return ''.join(res) 2053 2054 def GetDateTimePicker(self, ctrlID, caption, value = None, title = None): 2055 self.AddJsFile('/static/js/libs/jquery.datetimepicker.js') 2056 self.AddCssFile('/static/css/libs/jquery.datetimepicker.css') 2057 script = "<script> $('#{}').datetimepicker({{step:15, format:'Y.m.d H:i'}}); </script>".format(ctrlID) 2058 field = self.GetInput(ctrlID=ctrlID, labelCaption=caption, className=None, minLength=None, width='150', value=value, title=title) 2059 return field + script 2060 2061 def GetAjaxTree(self, ctrlID, url, child_function, search_function = None, create_function = None, remove_function = None, rename_function = None, move_function = None, contextMenu = None): 2062 mem = UnicodeMemStream() 2063 contextMenu = ' "contextmenu": { "items": %s }, ' % contextMenu if contextMenu is not None else '' 2064 mem.Write('\n<script type="text/javascript">\n$(function () {\n if (!$.jstree) {\n alert("Tree is disabled, please contact help desk!")\n } else {\n $("#%(ctrlID)s")\n .jstree({\n "plugins" : [ "themes", "json_data", "ui", "crrm", "dnd", "search", "types", "hotkeys", "contextmenu" ],\n %(contextMenu)s\n "json_data" : {\n "ajax" : {\n "url" : "%(url)s",\n "data" : function (n) {\n return { "action" : "%(child_function)s", "id" : n.attr ? n.attr("id") : -1 };\n }}},' % {'ctrlID': ctrlID, 2065 'url': url, 2066 'child_function': child_function, 2067 'contextMenu': contextMenu}) 2068 if search_function is not None: 2069 mem.Write('\n "search" : {\n "ajax" : {\n "url" : "%(url)s",\n "data" : function (str) {\n return { "action" : "%(search_function)s", "search" : str };\n }}},' % {'url': url, 2070 'search_function': search_function}) 2071 mem.Write('\n "types" : {\n "max_depth" : -2, "max_children" : -2, "valid_children" : [ "root" ],\n "types" : {\n "default" : { "valid_children" : "none", "icon" : { "image" : "/img/folder.png" } },\n "file" : { "valid_children" : [ ],\n "icon" : { "image" : "/img/file.png" }\n },\n "folder" : { "valid_children" : [ "default", "folder", "file" ],\n "icon" : { "image" : "/img/folder.png" }\n },\n "root" : {\n "valid_children" : [ "default", "folder", "file" ],\n "icon" : { "image" : "/img/root.png" },\n "start_drag" : false, "move_node" : false, "delete_node" : false, "remove" : false\n }\n }\n }\n })') 2072 if create_function is not None: 2073 mem.Write('\n .bind("create.jstree", function (e, data) {\n $.post(\n "%(url)s?action=%(create_function)s",\n {\n "id" : data.rslt.parent.attr("id"),\n "position" : data.rslt.position,\n "title" : data.rslt.name,\n "type" : data.rslt.obj.attr("rel")\n },\n function (r) {\n if(r.status) {\n $(data.rslt.obj).attr("id", r.id);\n $(data.rslt.obj).attr("rel", r.type);\n } else { $.jstree.rollback(data.rlbk); }\n }\n );\n })' % {'url': url, 2074 'create_function': create_function}) 2075 if remove_function is not None: 2076 mem.Write('\n .bind("remove.jstree", function (e, data) {\n data.rslt.obj.each(function () {\n $.ajax({\n async : false,\n type: \'POST\',\n url: "%(url)s?action=%(remove_function)s",\n data : {\n "id" : this.id\n },\n success : function (r) {\n if(!r.status) { data.inst.refresh(); }\n }\n });\n });\n })' % {'url': url, 2077 'remove_function': remove_function}) 2078 if rename_function is not None: 2079 mem.Write('\n .bind("rename.jstree", function (e, data) {\n $.post(\n "%(url)s?action=%(rename_function)s",\n {\n "id" : data.rslt.obj.attr("id"),\n "title" : data.rslt.new_name\n },\n function (r) {\n if(!r.status) { $.jstree.rollback(data.rlbk); }\n }\n );\n })' % {'url': url, 2080 'rename_function': rename_function}) 2081 if move_function is not None: 2082 mem.Write('\n .bind("move_node.jstree", function (e, data) {\n data.rslt.o.each(function (i) {\n $.ajax({\n async : false,\n type: \'POST\',\n url: "%(url)s?action=%(move_function)s",\n data : {\n "id" : $(this).attr("id"),\n "ref" : data.rslt.np.attr("id"),\n "position" : data.rslt.cp + i,\n "title" : data.rslt.name,\n "copy" : data.rslt.cy ? 1 : 0\n },\n success : function (r) {\n if(!r.status) { $.jstree.rollback(data.rlbk); }\n else {\n $(data.rslt.oc).attr("id", r.id);\n if(data.rslt.cy && $(data.rslt.oc).children("UL").length) {\n data.inst.refresh(data.inst._get_parent(data.rslt.oc));\n }\n }\n }\n });\n });\n });' % {'url': url, 2083 'move_function': move_function}) 2084 mem.Write('\n}});\n</script>') 2085 mem.Seek(0) 2086 self.WriteDirect('jscript', mem.Read()) 2087 return '<div id="%s"><a href="base:%s" style="display:hidden;"></a></div>' % (ctrlID, url) 2088 2089 def GetDatetimeWithDelta(self, dt): 2090 if dt is None: 2091 return 2092 elif dt < datetime.now(): 2093 delta = datetime.now() - dt 2094 return '<code>{0}</code> <font color=lightgrey>({1} ago)</font>'.format(dt, deltastr(delta)) 2095 else: 2096 delta = dt - datetime.now() 2097 return '<code>{0}</code> <font color=lightgrey>(In {1})</font>'.format(dt, deltastr(delta)) 2098 2099 def GetTree(self, ctrlID, data, expand = []): 2100 caseCon = [] 2101 treeCon = [] 2102 treeCon.append('<input type="hidden" id="%s" value="" />' % ctrlID) 2103 treeCon.append('<div id="%s_container">' % ctrlID) 2104 if_then = lambda a, b: (b if a is None else '%s:%s' % (a, b)) 2105 recFunc = lambda idel, label, url: '<li id="li_%s"><a href="%s">%s</a>' % (idel, if_then(url, idel), label) 2106 level = {} 2107 last = -1 2108 for idel, par, lab, url in data: 2109 if idel not in level: 2110 if par not in level: 2111 level[par] = 0 2112 level[idel] = 0 2113 else: 2114 level[idel] = level[par] + 1 2115 if last < level[idel]: 2116 treeCon.append('<ul>') 2117 elif last == level[idel]: 2118 treeCon.append('</li>') 2119 if url is not None and url.startswith('js:'): 2120 caseCon.append('case "%s": %s(%s); break;' % (idel, url.split(':')[1], idel)) 2121 if level[idel] < last: 2122 for x in range(0, last - level[idel]): 2123 treeCon.append('</ul></li>') 2124 2125 treeCon.append(recFunc(idel, lab, url)) 2126 last = level[idel] 2127 2128 treeCon.append('</div>') 2129 js = '\n <script type="text/javascript">\n $("#%(ctrlID)s_container").bind("select_node.jstree", function (event, data) {\n var mar = data.args[0];\n try {\n if (mar.href != undefined) {\n var myargs = mar.href.split(\':\');\n if (myargs[0] == "url") {\n window.location.href = mar.href.split(\':\')[1]+":"+mar.href.split(\':\')[2];\n return;\n } else if (myargs[0] == "js") {\n switch(myargs[myargs.length-1])\n {\n %(caselines)s\n }\n }\n var myargs = marhref.split(\'/\');\n a = myargs[myargs.length-1]\n $("#%(ctrlID)s").val(a);\n }\n } catch(err) {}\n })\n $("#%(ctrlID)s_container")\n .jstree({\n "core" : { "initially_open" : %(expand)s },\n "plugins" : ["themes","html_data","ui","crrm","hotkeys"]\n });\n </script>\n ' % {'ctrlID': ctrlID, 2130 'expand': [ 'li_%s' % x for x in expand ], 2131 'caselines': '\n'.join(caseCon)} 2132 return ''.join([''.join(treeCon), js]) 2133 2134 def GetAutoComplete(self, ctrlID, ctrlLabel, callbackPy, minLength = 4, labelClass = 'form-label'): 2135 jscript = '\n <script type="text/javascript">\n $(function() {\n var cache_%(ctrlID)s = {};\n $("#%(ctrlID)s_ac").autocomplete({\n select: function(event,ui) {\n $("#%(ctrlID)s").val(ui.item.id);\n $("#%(ctrlID)s_sr").html(" <span class=\'inlinehelp\' title=\'"+ui.item.label+"\' style=\'display: none\'> Selected: "+ui.item.id+"</span>");\n },\n source: function(request, response) {\n\n if (cache_%(ctrlID)s.term == request.term && cache_%(ctrlID)s.content) {\n response(cache_%(ctrlID)s.content);\n return;\n }\n if (new RegExp(cache_%(ctrlID)s.term).test(request.term) && cache_%(ctrlID)s.content && cache_%(ctrlID)s.content.length < 13) {\n response($.ui.autocomplete.filter(cache_%(ctrlID)s.content, request.term));\n return;\n }\n $.ajax({\n url: "%(callbackPy)s",\n dataType: "json",\n data: request,\n success: function(data) {\n if ( data.length == 0 ) {\n var no = parseInt(request.term);\n if (!isNaN(no)) {\n response($.parseJSON(\'[{"id":"\'+no+\'","label":"\'+no+\'"}]\'));\n $("#%(ctrlID)s").val(no);\n $("#%(ctrlID)s_sr").html(" <span class=\'inlinehelp\' title=\'"+no+"\'> Selected: "+no+"</span>");\n return;\n }\n }\n cache_%(ctrlID)s.term = request.term;\n cache_%(ctrlID)s.content = data;\n response(data);\n }\n });\n },\n minLength: %(minLength)s\n });\n });\n </script>' % {'ctrlID': ctrlID, 2136 'callbackPy': callbackPy, 2137 'minLength': str(minLength)} 2138 labelClass = CheckValue('class', labelClass) 2139 return ''.join([jscript, 2140 '<input type="hidden" id="%(ctrlID)s" name="%(ctrlID)s" value="" />' % {'ctrlID': ctrlID}, 2141 '<label %(labelClass)s for="%(ctrlID)s_ac">%(ctrlLabel)s</label>' % {'labelClass': labelClass, 2142 'ctrlID': ctrlID, 2143 'ctrlLabel': ctrlLabel} if ctrlLabel else '', 2144 '<input id="%(ctrlID)s_ac"/>' % {'ctrlID': ctrlID}, 2145 '<span id="%(ctrlID)s_sr" class=""></span>' % {'ctrlID': ctrlID}]) 2146 2147 def SetAutoCompleteDefault(self, ctrlID, defaultValue, defaultName = None): 2148 self.Write("<script>$(function(){ $('#%s_ac').val('%s'); $('#%s').val(%s); });</script>" % (ctrlID, 2149 defaultName or defaultValue, 2150 ctrlID, 2151 defaultValue)) 2152 2153 def GetGrowl(self, innerText, header, body): 2154 return self.GetA(innerText=innerText, href='#', onClick="javascript:addNotice('<strong>%s</strong><p>%s<p>')" % (header, body)) 2155 2156 def RecordToDateTime(self, r): 2157 year, month, wd, day, hour, mi, sec, ms = blue.os.GetTimeParts(r) 2158 return datetime(year, month, day, hour, mi, sec, ms) 2159 2160 def WriteTable(self, header = None, lines = None, className = 'tablesorter', enableEdit = False, editUrl = None, enableDelete = False, deleteUrl = None, useFilter = False, invertSelection = False, paging = None, customActions = None, serverOrder = False, baseUrl = None, keyFields = None, readOnlyFields = None, showCount = True, maxRows = None, title = None, ctrlID = None, cssByRow = None, paddingLeft = 0): 2161 if maxRows: 2162 if len(lines) == maxRows: 2163 if customActions is None: 2164 customActions = [] 2165 customActions.append(self.FontRed('ONLY TOP %s RECORDS ARE LISTED' % maxRows)) 2166 t = self.GetTable(header, lines, showCount=showCount, customActions=customActions, useFilter=useFilter, invertSelection=invertSelection, paging=paging, enableEdit=enableEdit, editUrl=editUrl, enableDelete=enableDelete, deleteUrl=deleteUrl, serverOrder=serverOrder, baseUrl=baseUrl, keyFields=keyFields, readOnlyFields=readOnlyFields, className=className, cssByRow=cssByRow) 2167 if title is None: 2168 self.WriteWithLeftPadding(t, paddingLeft=paddingLeft) 2169 else: 2170 if ctrlID is None: 2171 if title is None or title == '': 2172 ctrlID = 'wp_1' 2173 else: 2174 ctrlID = 'wp_' + title.lower().replace(' ', '') 2175 self.WriteWithLeftPadding(self.WebPart(title, t, ctrlID), paddingLeft=paddingLeft) 2176 2177 def WriteForm(self, ctrlID, formMethod, fileName, formAction, elements, waitingMessage = None): 2178 self.Write(self.GetForm(ctrlID, formMethod, fileName, formAction, elements, waitingMessage)) 2179 2180 def WriteSimpleForm(self, formMethod = 'post', fileName = '', formAction = '', elements = [], waitingMessage = None): 2181 self.Write(self.GetSimpleForm(formMethod, fileName, formAction, elements, waitingMessage)) 2182 2183 def WriteDatePicker(self, ctrlID, ctrlCaption, ctrlFormat = 'dd-mm-yy', ctrlValue = None, ctrlTitle = None): 2184 self.Write(self.GetDatePicker(ctrlID, ctrlCaption, ctrlFormat, ctrlValue, ctrlTitle)) 2185 2186 def WriteDateTimePicker(self, ctrlDateID, ctrlCaption, ctrlValue = None, ctrlTitle = None): 2187 self.Write(self.GetDateTimePicker(ctrlID=ctrlDateID, caption=ctrlCaption, value=ctrlValue, title=ctrlTitle)) 2188 2189 def WriteAutoComplete(self, ctrlID, ctrlLabel, callbackPy): 2190 self.Write(self.GetAutoComplete(ctrlID, ctrlLabel, callbackPy)) 2191 2192 def WriteAccordion(self, controlId, headers, bodies): 2193 self.EnableAccordion(controlId) 2194 self.Write('<div id="%s">' % controlId) 2195 for i in range(0, len(headers)): 2196 self.Write('<h3><a href="#">%s</a></h3>' % headers[i]) 2197 self.Write('<div><p>%s</p></div>' % bodies[i]) 2198 2199 self.Write('</div>') 2200 2201 def WriteInContainer(self, html, className = 'flex-container'): 2202 self.Write('<div class="%s">' % className) 2203 self.Write(html) 2204 self.Write('</div>') 2205 2206 def WriteWithLeftPadding(self, html, paddingLeft): 2207 self.Write('<div style="padding-left: %dpx">' % paddingLeft) 2208 self.Write(html) 2209 self.Write('</div>') 2210 2211 def WriteLn(self, html, breaks = 1): 2212 self.Write(html + '<br/>' * breaks) 2213 2214 def WriteLi(self, html): 2215 self.Write(' <li>%s</li>\n' % html) 2216 2217 def WriteH1(self, html): 2218 self.Write(self.H1(html)) 2219 2220 def WriteH2(self, html): 2221 self.Write(self.H2(html)) 2222 2223 def WriteH3(self, html): 2224 self.Write(self.H3(html)) 2225 2226 def WriteH4(self, html): 2227 self.Write(self.H4(html)) 2228 2229 def WriteNotice(self, title, txt): 2230 if type(txt) == types.ListType: 2231 self.Write('<br/>' + self.GetMessage(title, txt, 'tip')) 2232 else: 2233 self.Write('<br/>' + self.GetMessage(title, '<br/>' + txt, 'tip')) 2234 2235 def WriteError(self, txt): 2236 self.Write('<br/>' + self.GetError(txt)) 2237 2238 def WriteWarning(self, txt): 2239 self.Write('<br/>' + self.GetWarning(txt)) 2240 2241 def WriteSuccess(self, txt): 2242 self.Write('<br/>' + self.GetSuccess(txt)) 2243 2244 def WriteTip(self, txt): 2245 self.Write('<br/>' + self.GetTip(txt)) 2246 2247 def WriteInfo(self, txt): 2248 self.Write('<br/>' + self.GetInfo(txt)) 2249 2250 def WriteDirect(self, redirect, html): 2251 if html is not None: 2252 if redirect not in self.inserts: 2253 ms = UnicodeMemStream() 2254 self.inserts[redirect] = ms 2255 else: 2256 ms = self.inserts[redirect] 2257 if isinstance(html, list): 2258 for htmlItem in html: 2259 ms.Write(htmlItem) 2260 2261 elif isinstance(html, UnicodeMemStream): 2262 html.Seek(0) 2263 ms.Write(html.Read()) 2264 elif isinstance(ms, basestring): 2265 self.inserts[redirect] += html 2266 else: 2267 ms.Write(html) 2268 2269 def Break(self, num = 1): 2270 return '<br />\n' * num 2271 2272 def WriteBreak(self, num = 1): 2273 self.Write(self.Break(num)) 2274 2275 def WriteScript(self, html): 2276 self.WriteDirect('jscript', html) 2277 2278 def Split(self, breaks = None): 2279 html = '' 2280 if breaks: 2281 html += self.Break(breaks) 2282 html += '<hr />' 2283 if breaks: 2284 html += self.Break(breaks) 2285 return html 2286 2287 def WriteSplit(self, breaks = None): 2288 self.Write(self.Split(breaks)) 2289 2290 def WriteAnchor(self, anchor): 2291 self.Write('<a name="%s"></a>\n' % anchor) 2292 2293 def NoBreak(self, txt): 2294 return '<nobr>%s</nobr>' % txt 2295 2296 def Preformatted(self, txt): 2297 return '<pre>%s</pre>' % txt 2298 2299 def Paragraph(self, p, style = '', ctrlID = '', className = ''): 2300 ms = UnicodeMemStream() 2301 ms.Write('<p%s%s%s>' % (CheckValue('id', ctrlID), CheckValue('style', style), CheckValue('class', className))) 2302 if isinstance(p, types.ListType): 2303 for element in p: 2304 ms.Write(element) 2305 2306 else: 2307 ms.Write(p) 2308 ms.Write('</p>') 2309 ms.Seek(0) 2310 return ms.Read() 2311 2312 def WriteParagraph(self, p, style = '', ctrlID = '', className = ''): 2313 self.Write(self.Paragraph(p, style, ctrlID, className)) 2314 2315 def WriteAligned(self, align, paragraph): 2316 self.Write('<div align="%s">%s</div>' % (align, paragraph)) 2317 2318 def LinkAction(self, bold, linkText, linkAction, linkAttribute, linkID): 2319 if bold: 2320 linkText = '<strong>%s</strong>' % linkText 2321 return self.Link('', linkText, {'action': linkAction, 2322 linkAttribute: linkID}) 2323 2324 def WriteRightActions(self, actions): 2325 self.Write('<ul class="csp-action-list right">') 2326 self.Write([ '<li>%s</li>' % x for x in actions ]) 2327 self.Write('</ul><div class="clear-both"></div>') 2328 2329 def AddNavbar(self, html): 2330 self.inserts['navigation'] = self.inserts['navigation'] + ' ' + html + '<br/>\n' 2331 2332 def UnorderedList(self, lines): 2333 s = UnicodeMemStream() 2334 s.Write('<ul>\n') 2335 for line in lines: 2336 s.Write('<li>') 2337 s.Write(line) 2338 s.Write('</li>\n') 2339 2340 s.Write('</ul>\n') 2341 s.Seek(0) 2342 return s.Read() 2343 2344 def OrderedList(self, lines): 2345 s = UnicodeMemStream() 2346 s.Write('<ol>\n') 2347 for line in lines: 2348 s.Write('<li>') 2349 s.Write(line) 2350 s.Write('</li>\n') 2351 2352 s.Write('</ol>\n') 2353 s.Seek(0) 2354 return s.Read() 2355 2356 def CheckAll(self, element): 2357 return '<input type="checkbox" name="checkall" onclick="ch=false;if(this.checked){ch=true;};o=document.getElementsByName(\'%s\');for(i=0;i<o.length;i++){o[i].checked=ch;};">' % element 2358 2359 def AppBottomLeft(self): 2360 return '' 2361 2362 def AppBottomRight(self): 2363 return '' 2364 2365 def Generate(self): 2366 if hasattr(self, 'response') and getattr(self.response, 'done', False): 2367 return '' 2368 cacheKiller = '?nocache=%d' % boot.sync 2369 if prefs.clusterMode == 'LOCAL': 2370 cacheKiller += '%d' % time.time() 2371 self.inserts['cacheKiller'] = cacheKiller 2372 if self.redirect not in self.inserts: 2373 self.Write('') 2374 if self.visualization: 2375 self.WriteDirect('scripts', ' <script type="text/javascript">\n') 2376 self.WriteDirect('scripts', " google.load('visualization', '1', {packages: [%s]});\n" % ','.join([ "'%s'" % x for x in self.visualization ])) 2377 self.WriteDirect('scripts', ' </script>\n') 2378 if self.cssFiles: 2379 self.WriteDirect('scripts', ''.join([ '\n <link rel="stylesheet" type="text/css" href="%s%s" />' % (src, cacheKiller) for src in self.cssFiles ])) 2380 if self.jsFiles: 2381 self.WriteDirect('scripts', ''.join([ '\n <script type="text/javascript" src="%s%s"></script>' % (src, cacheKiller) for src in self.jsFiles ])) 2382 if self.scripts: 2383 self.WriteDirect('scripts', '\n '.join(self.scripts)) 2384 if self.headjsScripts: 2385 self.WriteDirect('headjs', '\n '.join(self.headjsScripts)) 2386 if self.visualcallbacks: 2387 self.inserts['visualscripts'].Seek(0) 2388 vScript = self.inserts['visualscripts'].Read() 2389 visualScripts = ['function doVisual() {\n', vScript, '\n}\n'] + self.visualcallbacks 2390 self.inserts['visualscripts'] = ''.join(['<script type="text/javascript">\n'] + visualScripts + ['\ngoogle.setOnLoadCallback(doVisual);</script>']) 2391 stop, hz = blue.os.GetCycles() 2392 dt = (stop - self.start) / float(hz) * 1000.0 2393 self.inserts['bottom_left'].Seek(0) 2394 self.WriteDirect('bottom_left', '%s (%.1f ms) %s' % (FmtDate(blue.os.GetWallclockTime()), dt, self.AppBottomLeft())) 2395 trackID = 1 if prefs.clusterMode == 'LOCAL' else prefs.GetValue('webTrackID', -1) 2396 trackUrl = prefs.GetValue('trackUrl', 'http://piwik/') 2397 if not trackUrl.endswith('/'): 2398 trackUrl += '/' 2399 if trackID > -1: 2400 self.WriteDirect('trackpage', '\n <!-- Piwik -->\n <script type="text/javascript">\n var pkBaseURL = (("https:" == document.location.protocol) ? "%(trackHttps)s" : "%(trackHttp)s");\n document.write(unescape("%%3Cscript src=\'" + pkBaseURL + "piwik.js\' type=\'text/javascript\'%%3E%%3C/script%%3E"));\n </script><script type="text/javascript">\n try {\n var user = { \'userID\' : %(userid)s };\n var piwikTracker = Piwik.getTracker(pkBaseURL + "piwik.php", %(trackID)d);\n piwikTracker.setCustomData(user);\n piwikTracker.setDocumentTitle(\'%(documentTitle)s\');\n piwikTracker.trackPageView();\n piwikTracker.enableLinkTracking();\n } catch( err ) {}\n </script><noscript><p><img src="%(trackHttp)spiwik.php?idsite=%(trackID)d" style="border:0" alt="" /></p></noscript>\n <!-- End Piwik Tracking Tag -->\n ' % {'userid': session.userid, 2401 'documentTitle': self.inserts['title'], 2402 'trackID': trackID, 2403 'trackHttp': trackUrl, 2404 'trackHttps': trackUrl.replace('http:', 'https:')}) 2405 nodeInfo = '' 2406 if machoNet.mode == 'server': 2407 nodeID = sm.services['machoNet'].GetNodeID() 2408 nodeInfo = ' · Node: %s' % self.Link('/admin/network.py', '<span id="currentNodeID" clsss="gray">%s</span>' % nodeID, {'action': 'Node', 2409 'nodeID': nodeID}) 2410 self.WriteDirect('bottom_right', '<span class="gray">%s%s</span> %s' % (prefs.clusterName, nodeInfo, self.AppBottomRight())) 2411 for ins in self.inserts.iterkeys(): 2412 m = self.inserts[ins] 2413 if isinstance(m, UnicodeMemStream): 2414 m.Seek(0) 2415 self.inserts[ins] = m.Read() 2416 2417 try: 2418 template = self.baseTemplate 2419 if template.startswith('script:') or template.startswith('wwwroot:'): 2420 template = template.split('/')[-1] 2421 return scriber.scribe(template, **self.inserts) 2422 except Exception as ex: 2423 scriber.log.exception('Exception while Scribing') 2424 self.LogError('Exception while Scribing: %r' % ex) 2425 print('Exception while Scribing: %r' % ex) 2426 raise ex 2427 2428 def Canonicalize(self, *args, **kw): 2429 return Canonicalize(*args, **kw) 2430 2431 def HTMLEncode(self, *args, **kw): 2432 return HTMLEncode(*args, **kw) 2433 2434 def Link(self, *args, **kw): 2435 return Link(*args, **kw) 2436 2437 def Button(self, *args, **kw): 2438 return Button(*args, **kw) 2439 2440 def Image(self, *args, **kw): 2441 return Image(*args, **kw) 2442 2443 def Table(self, *args, **kw): 2444 return Table(*args, **kw) 2445 2446 def OutlineDictTable(self, *args, **kw): 2447 return OutlineDictTable(*args, **kw) 2448 2449 def OutlineSortedSegmentedTable(self, *args, **kw): 2450 return OutlineSortedSegmentedTable(*args, **kw) 2451 2452 def OutlineSegmentedTable(self, *args, **kw): 2453 return OutlineSegmentedTable(*args, **kw) 2454 2455 def OutlineTable(self, *args, **kw): 2456 return OutlineTable(*args, **kw) 2457 2458 def OutlinePropertyTable(self, *args, **kw): 2459 return OutlinePropertyTable(*args, **kw) 2460 2461 def OutlineKeyValTable(self, *args, **kw): 2462 return OutlineKeyValTable(*args, **kw) 2463 2464 def BarChart(self, *args, **kw): 2465 return BarChart(*args, **kw) 2466 2467 def BrowserCheck(self, *args, **kw): 2468 return BrowserCheck(*args, **kw) 2469 2470 def WriteEOFModalDialogue(self, buttonName = 'Done'): 2471 element = self.request.QueryString('modalDialogueElement') 2472 if buttonName is not None: 2473 self.Write('\n <input type="button" value="%s" onClick="all2Element(\'%s\')">\n ' % (buttonName, element)) 2474 self.Write('\n <script language="javascript">\n function all2Element(element){\n var pairs = new Array();\n var disp = new Array();\n\n var allInput = document.getElementsByTagName(\'input\');\n for(i=0;i<allInput.length;i++){\n if((allInput[i].type==\'radio\')||(allInput[i].type==\'checkbox\')){\n if(allInput[i].checked){\n pairs[pairs.length]=allInput[i].name+\'=\'+allInput[i].value;\n disp[disp.length]=allInput[i].name;\n }\n }else if ((allInput[i].type!=\'button\') && (allInput[i].value.length>0)) {\n pairs[pairs.length]=allInput[i].name+\'=\'+allInput[i].value;\n disp[disp.length]=allInput[i].name+\'=\'+allInput[i].value;\n }\n }\n var allSelect = document.getElementsByTagName(\'select\')\n for(i=0;i<allSelect.length;i++){\n for (n=0;n<allSelect[i].options.length;n++){\n if (allSelect[i].options[n].selected && allSelect[i].options[n].value!=\'None\') {\n pairs[pairs.length]= allSelect[i].name+\'=\'+allSelect[i].options[n].value;\n disp[disp.length] = allSelect[i].name+\'=\'+allSelect[i].options[n].text;\n }\n }\n }\n\n window.opener.document.all[element].value=pairs.join("&");\n window.opener.document.all[element+\'Disp\'].value=disp.join(", ");\n\n self.close();\n }\n\n function fetchFromElement(element){\n if(window.opener.document.all[element].value!=\'\'){\n var currentValues = window.opener.document.all[element].value.split("&");\n for(i=0;i<currentValues.length;i++){\n var pair = currentValues[i].split(\'=\');\n var modularElement = document.all[pair[0]]\n if(modularElement){\n if(modularElement.tagName==\'SELECT\'){\n for(si=0;si<modularElement.options.length;si++){\n if(modularElement.options[si].value == pair[1]){\n modularElement.options[si].selected = true;\n }\n }\n }\n if(modularElement.tagName==\'INPUT\'){\n if(modularElement.type==\'text\'){\n document.all[pair[0]].value = pair[1];\n }\n if(modularElement.type==\'checkbox\'){\n if(pair[1]==\'on\'){document.all[pair[0]].checked=true;}\n }\n }\n }\n }\n }\n }\n\n document.onload = fetchFromElement(\'%s\');\n </script>\n ' % element) 2475 2476 def UnpackModalDialogueResult(self, *args): 2477 return UnpackModalDialogueResult(*args) 2478 2479 def PackModalDialogueResult(self, *args): 2480 return PackModalDialogueResult(*args) 2481 2482 def FormatHtmlKWArgs(self, htmlKwargs = {}, prohibitedKeys = []): 2483 result = '' 2484 htmlOpt = lambda each: " %s='%s'" % each 2485 for each in htmlKwargs.iteritems(): 2486 if each[0].lower() not in prohibitedKeys: 2487 result += htmlOpt(each) 2488 2489 return result 2490 2491 def FormatFunctionArguments(self, functionArgs, trailingComma = False): 2492 argStr = '' 2493 if functionArgs is not None: 2494 for each in functionArgs: 2495 if each is None: 2496 argStr += 'null,' 2497 elif type(each) == types.BooleanType: 2498 argStr += '%s,' % str(each).lower() 2499 elif type(each) in types.StringTypes: 2500 if each.startswith('this'): 2501 argStr += '%s,' % each 2502 else: 2503 argStr += "'%s'," % each 2504 else: 2505 argStr += '%s,' % each 2506 2507 if not trailingComma: 2508 argStr = argStr[:-1] 2509 return argStr 2510 2511 def FormatSelectOptions(self, elements): 2512 selectOpt = lambda row: '<option value="%s" %s >%s</option>\n' % (row[0], 'selected' if row[2] else '', row[1]) 2513 return ' '.join(map(selectOpt, elements)) 2514 2515 def FormatAjaxArgs(self, action, arguments, extras): 2516 extraArgs = {} 2517 ajaxArgsStr = 'action=%s' % action 2518 if arguments is not None: 2519 for each in arguments.iteritems(): 2520 if each[1] is None: 2521 ajaxArgsStr += '&%s=None' % each[0] 2522 elif each[0] in extras: 2523 extraArgs[each[0]] = each[1] 2524 elif type(each[1]) in types.StringTypes: 2525 ajaxArgsStr += '&%s=%s' % each 2526 else: 2527 ajaxArgsStr += '&%s=%s' % each 2528 2529 return (ajaxArgsStr, extraArgs) 2530 2531 def SetAjaxDefaultUrl(self, url): 2532 self.ajaxDefaultURL = url 2533 2534 def EnableAjaxInput(self): 2535 if 'EnableAjaxInput' in self.enabledJscript: 2536 return 2537 self.enabledJscript.add('EnableAjaxInput') 2538 jscript = '\n function OnChangeAjax(dataID, attr, value, url, action, successFunc) {\n if (null == successFunc) successFunc = function(data){};\n $.ajax({\n url: url,\n cache: false,\n dataType: \'json\',\n data: "action="+ action + "&dataID=" + dataID + "&attr=" + attr + "&value=" + value,\n success: successFunc\n }); //end Ajax\n };// end Function\n ' 2539 self.WriteDirect('jscript', jscript) 2540 2541 def GetAjaxInput(self, labelCaption, dataID, attr, url, funcName, title = '', ctrlID = '', className = '', minLength = None, width = None, value = None): 2542 self.EnableAjaxInput() 2543 minLength = CheckValue('minlength', str(minLength)) 2544 if width: 2545 width = ' style="width:%spx"' % width 2546 className = CheckValue('class', className) 2547 value = CheckValue('value', value) 2548 res = [] 2549 if labelCaption is not None: 2550 res.append('<label class="form-label" id="lbl_%s">%s</label>' % (ctrlID, labelCaption)) 2551 attrs = {'ctrlID': ctrlID, 2552 'className': className, 2553 'minLength': minLength, 2554 'width': width, 2555 'value': value, 2556 'dataID': dataID, 2557 'attr': attr, 2558 'url': url, 2559 'funcName': funcName, 2560 'title': title, 2561 'successFunc': "function(data){$('#%s').val(data)}" % ctrlID} 2562 res.append('<input id="%(ctrlID)s"\n name="%(ctrlID)s"%(className)s%(minLength)s%(width)s%(value)s\n onchange="OnChangeAjax(%(dataID)s, \'%(attr)s\', this.value, \'%(url)s\', \'%(funcName)s\', %(successFunc)s )"\n title="%(title)s" />\n ' % attrs) 2563 return '\n'.join(res) 2564 2565 def EnableAjaxA(self): 2566 if 'EnableAjaxA' not in self.enabledJscript: 2567 self.enabledJscript.add('EnableAjaxA') 2568 jscript = '\n function OnClickAjaxAnchor(url, action, successFunc) {\n if (null == successFunc) successFunc = function(data){}\n $.ajax({\n url: url,\n cache: false,\n dataType: \'json\',\n data: "action="+ action,\n success: successFunc\n }); //end Ajax\n };// end Function\n ' 2569 self.WriteDirect('jscript', jscript) 2570 2571 def EnableAjaxExpandableTitle(self): 2572 if 'EnableAjaxExpandableTitle' in self.enabledJscript: 2573 return 2574 self.enabledJscript.add('EnableAjaxExpandableTitle') 2575 jscript = '\n function OnClickExpandableTitle(url, action, dataID, ctrlID) {\n var divKey="#div_" + ctrlID;\n var icnKey="#icn_" + ctrlID;\n if ($("div").find(divKey).css("display") == \'none\'){\n $.ajax({\n url: url,\n cache: false,\n data: "action="+ action + "&dataID=" + dataID,\n success: function(html){\n if (html.length > 2){\n $("div").find(divKey).empty();\n $("div").find(divKey).append(html);\n $(icnKey).attr("src", "/img/toggle-collapse-dark.png");\n $("div").find(divKey).toggle( );\n }\n }\n }); //end Ajax\n } // end if\n else {\n $(icnKey).attr("src", "/img/toggle-expand-dark.png");\n $("div").find(divKey).toggle( );\n }\n };// end Function\n ' 2576 self.WriteDirect('jscript', jscript) 2577 2578 def GetAjaxExpandableTitle(self, innerText, dataID, url, action, ctrlID, title = ''): 2579 self.EnableAjaxExpandableTitle() 2580 args = {'ctrlID': ctrlID, 2581 'url': url, 2582 'action': action, 2583 'dataID': dataID, 2584 'innerText': innerText, 2585 'title': title} 2586 args['icon'] = self.Image('/img/toggle-expand-dark.png', 'border=0 id="icn_%(ctrlID)s" onClick="OnClickExpandableTitle(\'%(url)s\', \'%(action)s\', %(dataID)s, %(ctrlID)s)" title="%(title)s" ' % args) 2587 expand = 'toggle-collapse-dark.png' 2588 return '%(icon)s %(innerText)s<div id="div_%(ctrlID)s" style="display:none;" >Hi there this is the div</div>' % args 2589 2590 def GetAjaxSelect(self, elements, dataID, url, action, attr, ctrlID, title = '', labelCaption = '', elementClass = ''): 2591 self.EnableAjaxInput() 2592 args = {'ctrlID': ctrlID, 2593 'url': url or self.ajaxDefaultURL, 2594 'action': action, 2595 'attr': attr, 2596 'dataID': dataID, 2597 'title': title, 2598 'elementClass': elementClass} 2599 if ctrlID: 2600 ctrlID = ' id="%s" name="%s"' % (ctrlID, ctrlID) 2601 opt1 = lambda row: '<option value="%s" %s >%s</option>\n' % (row[0], ['', 'selected'][row[2]], row[1]) 2602 attrTxt = 'class="%(elementClass)s" onchange="OnChangeAjax(%(dataID)s, \'%(attr)s\', this.value, \'%(url)s\', \'%(action)s\', null)" title="%(title)s" ' % args 2603 return ''.join(['<label class="form-label" for="%s">%s</label>' % (ctrlID, labelCaption), 2604 _GetElementBegin('select', '%s %s' % (ctrlID, attrTxt)), 2605 ''.join(map(opt1, elements)), 2606 _GetElementEnd('select')]) 2607 2608 def GetAjaxCheckbox(self, ctrlID, labelCaption, className, checked, dataID, url, action, attr, title = '', disabled = False, successFunc = 'null'): 2609 self.EnableAjaxInput() 2610 className = CheckValue('class', className) 2611 if checked: 2612 checked = ' checked ="true"' 2613 else: 2614 checked = '' 2615 res = [] 2616 if labelCaption: 2617 res.append('<label class="form-label" for="%s">%s</label>' % (ctrlID, labelCaption)) 2618 args = {'ctrlID': ctrlID, 2619 'className': className, 2620 'checked': checked, 2621 'dataID': dataID, 2622 'attr': attr, 2623 'url': url, 2624 'action': action, 2625 'title': title, 2626 'disabled': ['', 'disabled'][disabled or False], 2627 'successFunc': successFunc} 2628 res.append('<input type="checkbox" id="%(ctrlID)s" name="%(ctrlID)s" %(className)s %(checked)s %(disabled)s onchange="OnChangeAjax(%(dataID)s, \'%(attr)s\', this.checked, \'%(url)s\', \'%(action)s\', %(successFunc)s )" title="%(title)s" />' % args) 2629 return '\n'.join(res) 2630 2631 def EnableAjaxBtn(self): 2632 if 'EnableAjaxIconBtn' not in self.enabledJscript: 2633 self.enabledJscript.add('EnableAjaxIconBtn') 2634 jscript = '\n function OnClickAjaxBtn(url, ajaxArgs, successFunc, confirmTxt, dataType) {\n if (null == successFunc) successFunc = function(data){};\n if (confirmTxt.length == 0 || confirm(confirmTxt) ) {\n $.ajax({\n url: url,\n cache: false,\n dataType: dataType,\n data: ajaxArgs,\n success: successFunc\n }); //end Ajax\n };\n };// end Function\n ' 2635 self.WriteDirect('jscript', jscript) 2636 2637 def GetAjaxBtn(self, btnText, action, actionKwargs = {}, htmlKWargs = {}, url = None): 2638 htmlArgStr = self.FormatHtmlKWArgs(htmlKWargs, ['onclick', 'type']) 2639 ajaxArgsStr, extraArgs = self.FormatAjaxArgs(action, actionKwargs, ['successFunc', 'confirm', 'dataType']) 2640 args = {'btnText': btnText, 2641 'url': url or self.ajaxDefaultURL, 2642 'dataType': 'json', 2643 'htmlArgs': htmlArgStr, 2644 'ajaxArgs': ajaxArgsStr, 2645 'confirm': ''} 2646 args.update(extraArgs) 2647 return '<button type="button" onclick="OnClickAjaxBtn(\'%(url)s\', \'%(ajaxArgs)s\', %(successFunc)s, \'%(confirm)s\', \'%(dataType)s\')" \'%(htmlArgs)s\' >%(btnText)s</button>' % args 2648 2649 def GetAjaxIconBtn(self, imageURL, action, actionKwargs = {}, htmlKwargs = {}, url = None): 2650 self.EnableAjaxBtn() 2651 if (url or self.ajaxDefaultURL) is None: 2652 raise RuntimeError('There is no URL for this call, please pass a URL or set the default RLL') 2653 ajaxArgsStr, extraArgs = self.FormatAjaxArgs(action, actionKwargs, ['confirm', 'dataType', 'successFunc']) 2654 htmlArgsStr = self.FormatHtmlKWArgs(htmlKwargs) 2655 args = {'imageUrl': imageURL, 2656 'htmlArgs': htmlArgsStr, 2657 'url': url or self.ajaxDefaultURL, 2658 'action': action, 2659 'ajaxArgs': ajaxArgsStr, 2660 'dataType': 'json', 2661 'successFunc': 'null', 2662 'confirm': ''} 2663 args.update(extraArgs) 2664 return '<img src="%(imageUrl)s" %(htmlArgs)s onclick="OnClickAjaxBtn(\'%(url)s\', \'%(ajaxArgs)s\', %(successFunc)s, \'%(confirm)s\', \'%(dataType)s\')" />' % args 2665 2666 def GetAjaxA(self, innerText, action, actionKwargs = {}, htmlKwargs = {}, url = None): 2667 self.EnableAjaxBtn() 2668 if (url or self.ajaxDefaultURL) is None: 2669 raise RuntimeError('There is no URL for this call, please pass a URL or set the default RLL') 2670 ajaxArgsStr, extraArgs = self.FormatAjaxArgs(action, actionKwargs, ['confirm', 'dataType', 'successFunc']) 2671 htmlArgsStr = self.FormatHtmlKWArgs(htmlKwargs) 2672 args = {'innerText': innerText, 2673 'htmlArgs': htmlArgsStr, 2674 'url': url or self.ajaxDefaultURL, 2675 'action': action, 2676 'ajaxArgs': ajaxArgsStr, 2677 'dataType': 'json', 2678 'successFunc': 'null', 2679 'confirm': ''} 2680 args.update(extraArgs) 2681 return '<a %(htmlArgs)s onclick="OnClickAjaxBtn(\'%(url)s\', \'%(ajaxArgs)s\', %(successFunc)s, \'\', \'%(dataType)s\')">%(innerText)s</a>' % args 2682 2683 def GetJscriptIconBtn(self, func, imgSrc, funcArgs = None, htmlKwargs = {}): 2684 argStr = self.FormatFunctionArguments(funcArgs) 2685 htmlArgsStr = self.FormatHtmlKWArgs(htmlKwargs, ['onclick']) + ' onclick="%s(%s)" ' % (func, argStr) 2686 return '<img src="%(imgSrc)s" %(htmlArgs)s />' % {'imgSrc': imgSrc, 2687 'htmlArgs': htmlArgsStr} 2688 2689 def GetJscriptSelect(self, elements, func, funcArgs = None, htmlKwargs = {}): 2690 argStr = self.FormatFunctionArguments(funcArgs, True) 2691 htmlArgsStr = self.FormatHtmlKWArgs(htmlKwargs, ['onchange']) + ' onchange="%s(%s this.value)" ' % (func, argStr) 2692 selectStr = '<select %s >\n' % htmlArgsStr 2693 selectStr += self.FormatSelectOptions(elements) 2694 selectStr += '</select>\n' 2695 return selectStr 2696 2697 def GetJscriptA(self, innerText, func, funcArgs = None, htmlKwargs = {}): 2698 argStr = self.FormatFunctionArguments(funcArgs) 2699 htmlArgsStr = self.FormatHtmlKWArgs(htmlKwargs, ['onclick']) + ' onclick="%s(%s)" ' % (func, argStr) 2700 return '<a %s ">%s</a>' % (htmlArgsStr, innerText) 2701 2702 def GetExportedForAction(self, action): 2703 exported = self.__exportedactions__.get(action) 2704 if exported is None: 2705 return 2706 if callable(exported): 2707 exported = exported() 2708 return exported 2709 2710 def GetActionArgs(self, request, action): 2711 exported = self.GetExportedForAction(action) 2712 if exported is None: 2713 return 2714 if len(exported) and isinstance(exported[0], numbers.Integral): 2715 if exported[0] & session.role == 0: 2716 roles = self.session.ConnectToAnyService('cache').Rowset(const.cacheUserRoles) 2717 requiredRoles = '' 2718 for role in roles: 2719 if exported[0] & role.roleID == role.roleID: 2720 requiredRoles = requiredRoles + role.roleName + ', ' 2721 2722 session.LogSessionError("Called %s::%s, which requires of the following roles: %s, which the user doesn't have" % (request.path, action, requiredRoles)) 2723 raise RoleNotAssignedError(exported[0]) 2724 preargs = exported[1:] 2725 else: 2726 preargs = exported 2727 if preargs == ['**']: 2728 params = request.QueryStrings() 2729 for k, v in request.FormItems().items(): 2730 params[k] = v 2731 2732 else: 2733 params = {} 2734 for each in preargs: 2735 if request.QueryString(each) is not None: 2736 params[each] = request.QueryString(each) 2737 elif request.Form(each) is not None: 2738 params[each] = request.Form(each) 2739 2740 return ((), params) 2741 2742 def IsPost(self): 2743 try: 2744 return str(self.request.method).upper() == 'POST' 2745 except Exception as ex: 2746 return len(self.request.form) > 0 2747 2748 2749 class HtmlWriterEx(HtmlWriter): 2750 useAutomagicTitles = 1 2751 useItemProps = 0 2752 useOwnerProps = 0 2753 useSessionProps = 0 2754 usePannelUpdate = 1 2755 2756 def __init__(self, template = 'script:/wwwroot/lib/template/base.html', populateGlobals = 1): 2757 HtmlWriter.__init__(self, template) 2758 self.inserts['stylesheet'] = '/lib/ex.css' 2759 self.inserts['topMenu'] = '' 2760 self.inserts['topMenuSub'] = '' 2761 self.inserts['l1Menu'] = '' 2762 self.inserts['l1MenuSub'] = '' 2763 self.inserts['lMenu'] = '' 2764 self.inserts['lSelected'] = '' 2765 self.inserts['rMenu'] = '' 2766 self.inserts['props'] = '' 2767 self.inserts['floaters'] = '' 2768 self.inserts['watchlist'] = '' 2769 self.inserts['body'] = ' onload="SetFocusToFirst();"' 2770 self.inserts['onload'] = '' 2771 self.inserts['rMenuWidth'] = 200 2772 self.request = None 2773 self.response = None 2774 2775 def HandleAction(self, action, request, response): 2776 self.request = request 2777 self.response = response 2778 if self.ajaxCSRF and str(request.method).upper() in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): 2779 response.cookie['csrftoken'] = GenerateCSRFToken(request) 2780 if not (prefs.clusterMode in ('LOCAL', 'MASTER') and prefs.GetValue('csrf_override', '') == 'on'): 2781 if str(request.method).upper() == 'POST' and not self.ValidateCSRF(): 2782 if 'x-csrftoken' not in request.header or request.header['x-csrftoken'] != GenerateCSRFToken(request): 2783 raise CSRFException('CSRF Token not valid') 2784 if action is None: 2785 action = self.__defaultaction__ 2786 argstuple = self.GetActionArgs(request, action) 2787 if argstuple: 2788 args, kwargs = argstuple 2789 try: 2790 getattr(self, action)(*args, **kwargs) 2791 except TypeError as e: 2792 sm.services['http'].LogError('Bad params (', kwargs, ') sent to ', action, ', resulting in exception: ', e) 2793 raise 2794 2795 else: 2796 self.Write('Action not listed ' + str(action) + '<br/>') 2797 if self.useAutomagicTitles == 1: 2798 self.inserts['title'] = self.inserts['title'] + ' - ' + str(action) 2799 self.inserts['heading'] = self.inserts['title'] 2800 elif self.useAutomagicTitles == 2: 2801 self.inserts['heading'] = self.inserts['title'] 2802 2803 def AddTopMenu(self, id, disp, help, url, args = None): 2804 if args: 2805 url = url + '?' 2806 for k, v in args.iteritems(): 2807 url = url + str(k) + '=' + str(v) + '&' 2808 2809 if id: 2810 self.inserts['topMenu'] = self.inserts['topMenu'] + ' addMSMenu("%s", "%s", "%s", "%s");\n' % (id, 2811 disp, 2812 help, 2813 url) 2814 else: 2815 self.inserts['topMenu'] = self.inserts['topMenu'] + ' addMSMenuDivider();\n' 2816 2817 def AddTopButton(self, linkText, url, args = None): 2818 if args: 2819 url = url + '?' 2820 for k, v in args.iteritems(): 2821 url = url + str(k) + '=' + str(v) + '&' 2822 2823 self.inserts['topMenu'] = self.inserts['topMenu'] + ' addMSButton("%s", "%s");\n' % (linkText, url) 2824 self.inserts['topMenu'] = self.inserts['topMenu'] + ' addMSMenuDivider();\n' 2825 2826 def AddTopMenuSub(self, parentid, disp, url, args = None, disabled = False): 2827 if args: 2828 url = url + '?' 2829 for k, v in args.iteritems(): 2830 url = url + str(k) + '=' + str(v) + '&' 2831 2832 d = '%s' % disp 2833 color = 'gray' if disabled else '' 2834 self.inserts['topMenuSub'] = self.inserts['topMenuSub'] + ' addMSSubMenu("%s", "%s", "%s", "%s");\n' % (parentid, 2835 d, 2836 url, 2837 color) 2838 2839 def AddTopMenuSubLine(self, parentid): 2840 self.inserts['topMenuSub'] = self.inserts['topMenuSub'] + ' addMSSubMenuLine("%s");\n' % parentid 2841 2842 def AddMenu(self, id, disp, help, url, args = None): 2843 if args: 2844 url = url + '?' 2845 for k, v in args.iteritems(): 2846 url = url + str(k) + '=' + str(v) + '&' 2847 2848 self.inserts['l1Menu'] = self.inserts['l1Menu'] + ' addICPMenu("%s", "%s", "%s", "%s");\n' % (id, 2849 disp, 2850 help, 2851 url) 2852 2853 def SelectMenu(self, id, color = '#FFB043'): 2854 self.inserts['l1Menu'] = self.inserts['l1Menu'] + ' setICPSeleted("%s", "%s");\n' % (id, color) 2855 2856 def AddMenuSub(self, parentid, disp, url, args = None): 2857 if args: 2858 url = url + '?' 2859 for k, v in args.iteritems(): 2860 url = url + str(k) + '=' + str(v) + '&' 2861 2862 self.inserts['l1MenuSub'] = self.inserts['l1MenuSub'] + ' addICPSubMenu("%s", "%s", "%s");\n' % (parentid, disp, url) 2863 2864 def AddHorMenu(self, id, disp, url, args = None): 2865 if args: 2866 url = url + '?' 2867 for k, v in args.iteritems(): 2868 url = url + str(k) + '=' + str(v) + '&' 2869 2870 self.inserts['l1Menu'] = self.inserts['l1Menu'] + ' AddHorMenuItem("%s", "%s", "%s");\n' % (id, disp, url) 2871 2872 def SelectHorMenu(self, id): 2873 self.inserts['l1Menu'] = self.inserts['l1Menu'] + ' setHorSeleted("%s");\n' % id 2874 2875 def AddLeftHeading(self, id, disp): 2876 self.inserts['lMenu'] = self.inserts['lMenu'] + ' AddLeftMenu("%s", "%s");\n' % (id, disp) 2877 2878 def AddLeftMenu(self, parentid, id, disp, url, args = None, cssClass = None): 2879 if args: 2880 url = url + '?' 2881 for k, v in args.iteritems(): 2882 url = url + str(k) + '=' + str(v) + '&' 2883 2884 if cssClass is None: 2885 cssClass = '' 2886 self.inserts['lMenu'] = self.inserts['lMenu'] + ' AddLeftMenuItem("%s","%s","%s","%s","%s");\n' % (parentid, 2887 id, 2888 disp, 2889 url, 2890 cssClass) 2891 2892 def CurrentHeadingID(self): 2893 return 'm{}'.format(self.currentLeftHeadingIndex) 2894 2895 def CurrentMenuID(self): 2896 return 'm{}{}'.format(self.currentLeftHeadingIndex, chr(ord('a') + self.currentLeftMenuIndex)) 2897 2898 def AddAutonumberedLeftHeading(self, disp): 2899 if not hasattr(self, 'currentLeftHeadingIndex'): 2900 self.currentLeftHeadingIndex = 0 2901 self.currentLeftHeadingIndex += 1 2902 self.currentLeftMenuIndex = 0 2903 self.AddLeftHeading(self.CurrentHeadingID(), disp) 2904 2905 def AddAutonumberedLeftMenu(self, disp, url, args = None, cssClass = None): 2906 self.currentLeftMenuIndex += 1 2907 self.AddLeftMenu(self.CurrentHeadingID(), self.CurrentMenuID(), disp, url, args, cssClass) 2908 2909 def ContainerDetails(self, heading, header, lines, opLink = ''): 2910 s = UnicodeMemStream() 2911 if heading and len(heading): 2912 s.Write('<table border="0" cellpadding="0" cellspacing="0" width="100%">\n') 2913 s.Write('<tr>\n') 2914 s.Write('<td class="tableOutline" valign="top">\n') 2915 s.Write('<table border="0" cellpadding="7" cellspacing="1" width="100%">\n') 2916 s.Write('<tr>\n') 2917 s.Write(' <td class="tableHeader"><small><b>%s</b></small></td>\n' % (heading,)) 2918 s.Write('</tr>\n') 2919 s.Write('</table>\n') 2920 s.Write('</td>\n') 2921 s.Write('</tr>\n') 2922 s.Write('</table>\n') 2923 s.Write('<table border="0" cellpadding="0" cellspacing="0" width="100%">\n') 2924 s.Write('<tr>\n') 2925 s.Write('<td class="tableOutline" valign="top">\n') 2926 s.Write('<table border="0" cellpadding="7" cellspacing="1" width="100%">\n') 2927 if header and len(header): 2928 s.Write('<tr>\n') 2929 for i in header: 2930 s.Write(' <td class="tableHeader"><b>%s</b></td>\n' % i) 2931 2932 s.Write('</tr>\n') 2933 c = 1 2934 if len(lines): 2935 for row in lines: 2936 klass = 'class="tC"' 2937 if c: 2938 c = 0 2939 else: 2940 klass = 'class="tCO"' 2941 c = 1 2942 s.Write('<tr>\n') 2943 for col in row: 2944 if col == row[0] and opLink != '': 2945 link = opLink % (col, col) 2946 s.Write(' <td %s valign=top><small>%s</small></td>\n' % (klass, link)) 2947 else: 2948 s.Write(' <td %s valign=top><small>%s</small></td>\n' % (klass, unicode(col))) 2949 2950 s.Write('</tr>\n') 2951 2952 s.Write('</table>\n') 2953 s.Write('</td>\n') 2954 s.Write('</tr>\n') 2955 s.Write('</table>\n') 2956 s.Seek(0) 2957 return s.Read() 2958 2959 def WebPart(self, *args, **kw): 2960 return WebPart(*args, **kw) 2961 2962 def Floater(self, title, content, ID = 'NotUnique', width = '50%'): 2963 s = UnicodeMemStream() 2964 s.Write('<div id="' + str(ID) + '" class="clsFloaterContainer" style="position:absolute;top:0;left:0;width:' + str(width) + ';visibility:hidden;">') 2965 s.Write('<table id="goup" cellpadding="0" cellspacing="0" class="clsFloater" width="100%" border="0">\n') 2966 s.Write('<tr>\n') 2967 s.Write(' <td class="clsFloaterHead" valign="top" align="left" style="width:15" >') 2968 s.Write(' <img class="clsFloaterHead" src="/lib/webparts/gripgray.gif" height="19" width="15">') 2969 s.Write(' </td>\n') 2970 s.Write(' <td class="clsFloaterHead" valign="middle" align="left" width="' + str(width - 45) + '" STYLE="BORDER-TOP:1px solid #999999;">\n') 2971 s.Write(' <b class="clsFloaterHead">' + title + '</b>\n') 2972 s.Write(' </td>\n') 2973 s.Write(' <td class="clsFloaterRight" valign="top" align="right" height="19" width="25" >\n') 2974 s.Write(' <img class="clsMinimize" src="/lib/webparts/downlevel.gif" height="19" width="25">\n') 2975 s.Write(' </td>\n') 2976 s.Write('</tr>\n') 2977 s.Write('<tr>\n') 2978 s.Write(' <td colspan="3">\n') 2979 s.Write(' <table bgcolor="#ffffff" width="100%" cellpadding="0" cellspacing="0" border="0">\n') 2980 s.Write(' <tr>\n') 2981 s.Write(' <td bgcolor="#aaaaaa" colspan="1" width="1px" valign="top"><div style="margin:1px;padding:0px;"></div></td>\n') 2982 s.Write(' <td colspan="2" bgcolor="#f1f1f1" valign="top" style="padding:10px">\n') 2983 s.Write(content) 2984 s.Write(' </td>\n') 2985 s.Write(' <td bgcolor="#aaaaaa" colspan="1" width="1px" valign="top"><div style="margin:1px;padding:0px;"></div>\n') 2986 s.Write(' </td>\n') 2987 s.Write(' </tr>\n') 2988 s.Write(' <tr>\n') 2989 s.Write(' <td bgcolor="#aaaaaa" colspan="3" height="1" valign="top"><div style="margin:1px;padding:0px;"></div>\n') 2990 s.Write(' </td>\n') 2991 s.Write(' </tr>\n') 2992 s.Write(' </table>\n') 2993 s.Write(' </td>\n') 2994 s.Write('</tr>\n') 2995 s.Write('</table>\n') 2996 s.Write('</div>\n\n<SCRIPT>prepCentralize("' + str(ID) + '")</SCRIPT>') 2997 s.Seek(0) 2998 return s.Read() 2999 3000 def MessageboardStyles(self, Config): 3001 s = UnicodeMemStream() 3002 s.Write('<style type="text/css"> \n') 3003 s.Write('<!-- \n') 3004 s.Write(' a:link {color:%s;text-decoration:%s} \n' % (Config['LinkColor'], Config['LinkTextDecoration'])) 3005 s.Write(' a:visited {color:%s;text-decoration:%s} \n' % (Config['VisitedLinkColor'], Config['VisitedTextDecoration'])) 3006 s.Write(' a:hover {color:%s;text-decoration:%s} \n' % (Config['HoverLinkColor'], Config['HoverTextDecoration'])) 3007 s.Write(' a:active {color:%s;text-decoration:%s} \n' % (Config['ActiveLinkColor'], Config['ActiveTextDecoration'])) 3008 s.Write('.mbHead{ \n') 3009 s.Write(' BACKGROUND-COLOR:%s;\n' % Config['HeadCellColor']) 3010 s.Write(' COLOR:%s;\n' % Config['HeadFontColor']) 3011 s.Write(' FONT-FAMILY:%s;\n' % Config['DefaultFontFace']) 3012 s.Write(' FONT-SIZE:%s;\n' % Config['HeaderFontSize']) 3013 s.Write(' } \n') 3014 s.Write('.mbForum{ \n') 3015 s.Write(' BACKGROUND-COLOR:%s;\n' % Config['ForumCellColor']) 3016 s.Write(' COLOR:%s;\n' % Config['DefaultFontColor']) 3017 s.Write(' FONT-FAMILY:%s;\n' % Config['DefaultFontFace']) 3018 s.Write(' FONT-SIZE:%s;\n' % Config['DefaultFontSize']) 3019 s.Write(' } \n') 3020 s.Write('.mbForumFirst{ \n') 3021 s.Write(' BACKGROUND-COLOR:%s;\n' % Config['ForumFirstCellColor']) 3022 s.Write(' COLOR:%s;\n' % Config['DefaultFontColor']) 3023 s.Write(' FONT-FAMILY:%s;\n' % Config['DefaultFontFace']) 3024 s.Write(' FONT-SIZE:%s;\n' % Config['DefaultFontSize']) 3025 s.Write(' } \n') 3026 s.Write('.mbForumAlt{ \n') 3027 s.Write(' BACKGROUND-COLOR:%s;\n' % Config['ForumAltCellColor']) 3028 s.Write(' COLOR:%s;\n' % Config['DefaultFontColor']) 3029 s.Write(' FONT-FAMILY:%s;\n' % Config['DefaultFontFace']) 3030 s.Write(' FONT-SIZE:%s;\n' % Config['DefaultFontSize']) 3031 s.Write(' } \n') 3032 s.Write('--> \n') 3033 s.Write('</style> \n') 3034 s.Seek(0) 3035 return s.Read() 3036 3037 def MessageboardChannels(self, Data, Config): 3038 s = UnicodeMemStream() 3039 s.Write('<table border="0" cellpadding="0" cellspacing="0" width="100%">\n') 3040 s.Write('<tr>\n') 3041 s.Write('<td valign="top" bgcolor="%s">\n' % Config['TableBorderColor']) 3042 s.Write('<table border="0" cellpadding="4" cellspacing="1" width="100%">\n') 3043 if len(Data): 3044 s.Write('<tr>\n') 3045 s.Write(' <td class="mbHead" align=center valign=middle width="10"> </td>\n') 3046 s.Write(' <td class="mbHead" align=center valign=middle><b>Forums</td>\n') 3047 s.Write(' <td class="mbHead" align=center valign=middle width="10%%"><b>Posts</font></b></td>\n') 3048 s.Write(' <td class="mbHead" align=center valign=middle width="10%%"><b>Last Post</b></td>\n') 3049 s.Write(' <td class="mbHead" align=center valign=middle width="10"> </td>\n') 3050 s.Write('</tr>\n') 3051 for d in Data: 3052 s.Write('<tr>\n') 3053 s.Write(' <td class="mbForum" align=left valign=middle width="10"> </td>\n') 3054 s.Write(' <td class="mbForum" align=left valign=middle><A href="?action=WebTopics&channelID=%s">%s</A><br/>%s</td>\n' % (d['channelID'], d['channelName'], d['description'])) 3055 s.Write(' <td class="mbForum" align=center valign=middle Width="10%%">%s</td>\n' % d['numPosts']) 3056 s.Write(' <td class="mbForum" align=center valign=middle Width="10%%"><nobr>%s</nobr><br/>by: <A href="javascript:pop(\'mb_pop.py?action=character&characterID=%s\',\'mb_popChar\',300,400);">%s</A></td>\n' % (FmtDateEng(d['lastPost'], 'ss'), d['lastAuthor'], d['lastAuthorName'])) 3057 s.Write(' <td class="mbForum" align=left valign=middle width="10"> </td>\n') 3058 s.Write('</tr>\n') 3059 3060 s.Write('</table>\n') 3061 s.Write('</td>\n') 3062 s.Write('</tr>\n') 3063 s.Write('</table>\n') 3064 s.Seek(0) 3065 return self.MessageboardStyles(Config) + s.Read() 3066 3067 def MessageboardThreads(self, Data, Config, Threads, Page): 3068 if not Page: 3069 Page = 1 3070 s = UnicodeMemStream() 3071 s.Write('<table border="0" cellpadding="0" cellspacing="0" width="100%">\n') 3072 s.Write('<tr>\n') 3073 s.Write('<td valign="top" bgcolor="%s">\n' % Config['TableBorderColor']) 3074 s.Write('<table border="0" cellpadding="4" cellspacing="1" width="100%">\n') 3075 if len(Data): 3076 s.Write('<tr>\n') 3077 s.Write(' <td class="mbHead" align=center valign=middle width="10"> </td>\n') 3078 s.Write(' <td class="mbHead" align=center valign=middle><b>Topic</td>\n') 3079 s.Write(' <td class="mbHead" align=center valign=middle><b>Author</td>\n') 3080 s.Write(' <td class="mbHead" align=center valign=middle><b>Replies</td>\n') 3081 s.Write(' <td class="mbHead" align=center valign=middle><b>Read</td>\n') 3082 s.Write(' <td class="mbHead" align=center valign=middle><b>LastPost</td>\n') 3083 s.Write('</tr>\n') 3084 for d in Data: 3085 replies = d['sc_replies'] - 1 3086 if replies == -1: 3087 replies = 0 3088 s.Write('<tr>\n') 3089 s.Write(' <td class="mbForum" align=left valign=middle width="10"> </td>\n') 3090 s.Write(' <td class="mbForum" align=left valign=middle><A href="?action=WebTopic&threadID=%s">%s</A>' % (d['threadID'], d['sc_title'])) 3091 if d['sc_replies'] > int(Config['PageSize']): 3092 s.Write('<br/> ' + self.MessageBoardPages(d['sc_replies'], Config['PageSize'], 0, '?action=WebTopic&threadID=' + str(d['threadID']), Config['ActiveLinkColor'])) 3093 s.Write(' </td>\n') 3094 s.Write(' <td class="mbForum" align=center valign=middle><A href="charpop.py?characterID=%s">%s</A></td>\n' % (d['sc_authorID'], d['authorName'])) 3095 s.Write(' <td class="mbForum" align=center valign=middle>%s</td>\n' % replies) 3096 s.Write(' <td class="mbForum" align=center valign=middle>%s</td>\n' % d['sc_reads']) 3097 s.Write(' <td class="mbForum" align=center valign=middle Width="10%%"><nobr>%s</nobr><br/>by: <A href="javascript:pop(\'mb_pop.py?action=character&characterID=%s\',\'mb_popChar\',300,400);">%s</A></td>\n' % (FmtDateEng(d['sc_modified'], 'ss'), d['sc_lastauthorID'], d['lastAuthorName'])) 3098 s.Write('</tr>\n') 3099 3100 s.Write('</table>\n') 3101 s.Write('</td>\n') 3102 s.Write('</tr>\n') 3103 s.Write('</table>\n') 3104 if Threads > int(Config['PageSize']): 3105 s.Write('<br/>Pages: %s\n' % self.MessageBoardPages(Threads, Config['PageSize'], Page, '?action=WebTopics&channelID=' + str(d['channelID']), Config['ActiveLinkColor'])) 3106 s.Seek(0) 3107 return self.MessageboardStyles(Config) + s.Read() 3108 3109 def MessageboardResponses(self, Data, Config, Replies, Page, User): 3110 if not Page: 3111 Page = 1 3112 s = UnicodeMemStream() 3113 s.Write('<table border="0" cellpadding="0" cellspacing="0" width="100%">\n') 3114 s.Write('<tr>\n') 3115 s.Write('<td valign="top" bgcolor="%s">\n' % Config['TableBorderColor']) 3116 s.Write('<table border="0" cellpadding="4" cellspacing="1" width="100%">\n') 3117 if len(Data): 3118 s.Write('<tr>\n') 3119 s.Write(' <td class="mbHead" align=center valign=middle width="%s"><b>Author</td>\n' % Config['TopicWidthLeft']) 3120 s.Write(' <td class="mbHead" align=center valign=middle ><b>Topic</td>\n') 3121 s.Write('</tr>\n') 3122 i = 0 3123 for d in Data: 3124 if i == 0 and d['line'] == 1: 3125 mbClass = 'mbForumFirst' 3126 elif i % 2 == 0: 3127 mbClass = 'mbForumAlt' 3128 else: 3129 mbClass = 'mbForum' 3130 Edit = '' 3131 if d['userID'] == User: 3132 Edit = ' - <a href="?action=WebEdit&threadID=%s&line=%s">Edit</A>' % (d['threadID'], d['line']) 3133 s.Write('<tr>\n') 3134 s.Write(' <td class="%s" align=left valign=top width="%s"><A href="javascript:pop(\'mb_pop.py?action=character&characterID=%s\',\'mb_popChar\',300,400);">%s</A></td>\n' % (mbClass, 3135 Config['TopicWidthLeft'], 3136 d['authorID'], 3137 d['authorName'])) 3138 s.Write(' <td class="%s" align=left valign=top >Posted - %s %s<hr noshade size="1">%s</td>\n' % (mbClass, 3139 FmtDateEng(d['created'], 'ss'), 3140 Edit, 3141 self.MessageBoardFormat(d['text']))) 3142 s.Write('</tr>\n') 3143 i = i + 1 3144 3145 s.Write('</table>\n') 3146 s.Write('</td>\n') 3147 s.Write('</tr>\n') 3148 s.Write('</table>\n') 3149 if len(Data): 3150 if Replies > int(Config['PageSize']): 3151 s.Write('<br/>Pages: %s\n' % self.MessageBoardPages(Replies, Config['PageSize'], Page, '?action=WebTopic&threadID=' + str(d['threadID']), Config['ActiveLinkColor'])) 3152 s.Seek(0) 3153 return self.MessageboardStyles(Config) + s.Read() 3154 3155 def MessageboardPost(self, postType, channelID, threadID, Data, Config, ActiveCharacter, Characters): 3156 Header = '' 3157 text = '' 3158 line = '' 3159 if postType == 'Post': 3160 Header = 'Post New Topic' 3161 Button = 'Post New Topic' 3162 if postType == 'Reply': 3163 Header = 'Reply to Topic' 3164 Button = 'Post Reply' 3165 if postType == 'Edit': 3166 Header = 'Edit' 3167 Button = ' Update ' 3168 line = threadID[1] 3169 threadID = threadID[0] 3170 text = Data.text 3171 s = UnicodeMemStream() 3172 s.Write('<form name="WebPost" method="post" action="?action=%s">\n' % postType) 3173 s.Write('<table border="0" cellpadding="0" cellspacing="0" width="100%">\n') 3174 s.Write('<tr>\n') 3175 s.Write('<td valign="top" bgcolor="%s">\n' % Config['TableBorderColor']) 3176 s.Write('<table border="0" cellpadding="4" cellspacing="1" width="100%">\n') 3177 s.Write('<tr>\n') 3178 s.Write(' <td class="mbHead" align=center valign=middle colspan=2><b>%s</td>\n' % Header) 3179 s.Write('</tr>\n') 3180 if Config['AllowForumCode'] == '1': 3181 s.Write('<tr>\n') 3182 s.Write(' <td class="mbForum" align=right valign=center >Format:</td>\n') 3183 s.Write(' <td class="mbForum" align=left valign=top >Formating of Forum Code</td>\n') 3184 s.Write('</tr>\n') 3185 if postType == 'Post': 3186 s.Write('<tr>\n') 3187 s.Write(' <td class="mbForum" align=right valign=center >Subject:</td>\n') 3188 s.Write(' <td class="mbForum" align=left valign=top ><input type="text" name="subject" size=63 /></td>\n') 3189 s.Write('</tr>\n') 3190 s.Write('<tr>\n') 3191 s.Write(' <td class="mbForum" align=right valign=center >Message:</td>\n') 3192 s.Write(' <td class="mbForum" align=left valign=top ><textarea name=text cols=48 rows=10>%s</textarea></td>\n' % text) 3193 s.Write('</tr>\n') 3194 if postType == 'Post' or postType == 'Reply': 3195 s.Write('<tr>\n') 3196 s.Write(' <td class="mbForum" align=right valign=center >Character:</td>\n') 3197 s.Write(' <td class="mbForum" align=left valign=top>') 3198 s.Write(' <select name=characterID>') 3199 for char in Characters: 3200 s.Write(' <option ') 3201 if session.charid == char.characterID: 3202 s.Write(' SELECTED ') 3203 s.Write(' value="%s">%s</option>' % (char.characterID, char.characterName)) 3204 3205 s.Write(' </select><input type=checkbox name=signature value=1>Check here to include your profile signature') 3206 s.Write(' </td>\n') 3207 s.Write('</tr>\n') 3208 s.Write('<tr>\n') 3209 s.Write(' <td class="mbForum" align=right valign=center > </td>\n') 3210 s.Write(' <td class="mbForum" align=left valign=top >') 3211 s.Write(' <input type=submit value="%s">\n' % Button) 3212 s.Write(' <input type=button value="Cancel" onClick="JavaScript:history.go(-1);">\n') 3213 s.Write(' <input type=button value="Preview">\n') 3214 s.Write(' <input type=reset value="Reset Fields">\n') 3215 s.Write(' <input type=hidden name="channelID" value="%s">\n' % channelID) 3216 s.Write(' <input type=hidden name="threadID" value="%s">\n' % threadID) 3217 s.Write(' <input type=hidden name="line" value="%s">\n' % line) 3218 s.Write(' </td>\n') 3219 s.Write('</tr>\n') 3220 s.Write('</table>\n') 3221 s.Write('</td>\n') 3222 s.Write('</tr>\n') 3223 s.Write('</table>\n') 3224 s.Write('</form>\n') 3225 s.Seek(0) 3226 return self.MessageboardStyles(Config) + s.Read() 3227 3228 def MessageBoardPages(self, replies, pagesize, current, url, color): 3229 pages = '' 3230 if int(replies) > int(pagesize): 3231 for i in range(1, int(replies / int(pagesize) + 2)): 3232 style = '' 3233 if i == current: 3234 style = 'STYLE="FONT-WEIGHT:bolder;Color:%s;"' % color 3235 pages = pages + '<A href="%s&page=%s" %s>%s</A> ' % (url, 3236 str(i), 3237 style, 3238 str(i)) 3239 3240 return pages 3241 3242 def MessageBoardFormat(self, text): 3243 text = text.replace(chr(13) + chr(10), '<br/>') 3244 return text 3245 3246 def MessageboardNoCharacter(self, Config): 3247 s = UnicodeMemStream() 3248 s.Write('<table border="0" cellpadding="0" cellspacing="0" width="100%">\n') 3249 s.Write('<tr>\n') 3250 s.Write('<td valign="top" bgcolor="%s">\n' % Config['TableBorderColor']) 3251 s.Write('<table border="0" cellpadding="4" cellspacing="1" width="100%">\n') 3252 s.Write('<tr>\n') 3253 s.Write(' <td class="mbHead" align=center valign=middle><b>No Character</b></td>\n') 3254 s.Write('</tr>\n') 3255 s.Write('<tr>\n') 3256 s.Write(' <td class="mbForum" align=center valign=middle> <br/>You must create at least one character before you can participate in the forums.<br/> <br/>\n') 3257 s.Write(' <A href="JavaScript:history.go(-1);">Continue</A></td>\n') 3258 s.Write('</tr>\n') 3259 s.Write('</table>\n') 3260 s.Write('</td>\n') 3261 s.Write('</tr>\n') 3262 s.Write('</table>\n') 3263 s.Seek(0) 3264 return self.MessageboardStyles(Config) + s.Read() 3265 3266 def MessageboardNotYourCharacter(self, Config): 3267 s = UnicodeMemStream() 3268 s.Write('<table border="0" cellpadding="0" cellspacing="0" width="100%">\n') 3269 s.Write('<tr>\n') 3270 s.Write('<td valign="top" bgcolor="%s">\n' % Config['TableBorderColor']) 3271 s.Write('<table border="0" cellpadding="4" cellspacing="1" width="100%">\n') 3272 s.Write('<tr>\n') 3273 s.Write(' <td class="mbHead" align=center valign=middle><b>Not Your Character</b></td>\n') 3274 s.Write('</tr>\n') 3275 s.Write('<tr>\n') 3276 s.Write(' <td class="mbForum" align=center valign=middle> <br/>The character you used to post does for some reason not belong to you!<br/>CONCORD has been notified<br/> <br/>\n') 3277 s.Write(' <A href="JavaScript:history.go(-1);">Continue</A></td>\n') 3278 s.Write('</tr>\n') 3279 s.Write('</table>\n') 3280 s.Write('</td>\n') 3281 s.Write('</tr>\n') 3282 s.Write('</table>\n') 3283 s.Seek(0) 3284 return self.MessageboardStyles(Config) + s.Read() 3285 3286 def MessageBoardNotYourPost(self, Config): 3287 s = UnicodeMemStream() 3288 s.Write('<table border="0" cellpadding="0" cellspacing="0" width="100%">\n') 3289 s.Write('<tr>\n') 3290 s.Write('<td valign="top" bgcolor="%s">\n' % Config['TableBorderColor']) 3291 s.Write('<table border="0" cellpadding="4" cellspacing="1" width="100%">\n') 3292 s.Write('<tr>\n') 3293 s.Write(' <td class="mbHead" align=center valign=middle><b>Not Your Post</b></td>\n') 3294 s.Write('</tr>\n') 3295 s.Write('<tr>\n') 3296 s.Write(' <td class="mbForum" align=center valign=middle> <br/>The Post/Reply you trying to edit does for some reason not belong to you!<br/>CONCORD has been notified<br/> <br/>\n') 3297 s.Write(' <A href="JavaScript:history.go(-1);">Continue</A></td>\n') 3298 s.Write('</tr>\n') 3299 s.Write('</table>\n') 3300 s.Write('</td>\n') 3301 s.Write('</tr>\n') 3302 s.Write('</table>\n') 3303 s.Seek(0) 3304 return self.MessageboardStyles(Config) + s.Read() 3305 3306 def MessageBoardEOF(self, Config): 3307 s = UnicodeMemStream() 3308 s.Write('<table border="0" cellpadding="0" cellspacing="0" width="100%">\n') 3309 s.Write('<tr>\n') 3310 s.Write('<td valign="top" bgcolor="%s">\n' % Config['TableBorderColor']) 3311 s.Write('<table border="0" cellpadding="4" cellspacing="1" width="100%">\n') 3312 s.Write('<tr>\n') 3313 s.Write(' <td class="mbHead" align=center valign=middle><b>Data could not be retrieved</b></td>\n') 3314 s.Write('</tr>\n') 3315 s.Write('<tr>\n') 3316 s.Write(' <td class="mbForum" align=center valign=middle> <br/>For some reason the data you requested could not be retrieved. [EOF]<br/> <br/>\n') 3317 s.Write(' <A href="JavaScript:history.go(-1);">Continue</A></td>\n') 3318 s.Write('</tr>\n') 3319 s.Write('</table>\n') 3320 s.Write('</td>\n') 3321 s.Write('</tr>\n') 3322 s.Write('</table>\n') 3323 s.Seek(0) 3324 return self.MessageboardStyles(Config) + s.Read() 3325 3326 3327 class Form(): 3328 3329 def __init__(self, url = '', action = '', method = 'GET', target = '', formName = 'NeedAName', encType = '', request = None, waitingMessage = None, **kwargs): 3330 self.url = url 3331 self.formName = formName 3332 self.action = action 3333 self.method = str(method).upper() 3334 self.target = target 3335 self.elements = [] 3336 self.encType = encType 3337 self.request = request 3338 self.waitingMessage = waitingMessage 3339 self.extraAttributes = kwargs 3340 3341 def AddFSDLocalizationFields(self, textHolderField, messageIDField, groupPath, messageID, previewWindowSize = 30, preview = True): 3342 if messageID is None: 3343 messageID = '' 3344 html = '<div>{}</div>'.format(self.Input(messageIDField, messageID, 20, '', None, params='')) 3345 self.elements.append([messageIDField, html, '']) 3346 if preview: 3347 text = localization.GetByMessageID(messageID) 3348 html = '<div>{}</div>'.format(self.Input(textHolderField, text, previewWindowSize, '', None, params='disabled')) 3349 self.elements.append([textHolderField, html, '']) 3350 3351 def AddFSDLocalizationFieldsWithTextArea(self, textHolderField, messageIDField, groupPath, messageID, rows = 26, cols = 68): 3352 html = '<div>{}</div>'.format(self.Input(messageIDField, messageID, 20, '', None, params='')) 3353 self.elements.append([messageIDField, html, '']) 3354 text = localization.GetByMessageID(messageID) 3355 textAreaHtml = ' <textarea name="%s" cols=%d rows=%d %s>%s</textarea>' % (textHolderField, 3356 cols, 3357 rows, 3358 'disabled', 3359 text) 3360 html = '<div>{}</div>'.format(textAreaHtml) 3361 self.elements.append([textHolderField, html, '']) 3362 3363 def AddDateTimePicker(self, label, dateName, timeName, value): 3364 v = value.split(' ') 3365 if len(v) == 1: 3366 v = (value, '00:00') 3367 writer = HtmlWriter() 3368 self.elements.append([label, writer.GetDatePicker(ctrlID=dateName, ctrlCaption=None, ctrlFormat='yy-mm-dd', ctrlValue=v[0], ctrlTitle=''), writer.GetInput(ctrlID=timeName, labelCaption=None, className=None, minLength=None, width='60', value=v[1])]) 3369 3370 def AddDateTimeInput(self, label, name, value, text = ''): 3371 writer = HtmlWriter() 3372 self.elements.append([label, writer.GetDateTimePicker(ctrlID=name, caption=None, value=value, title=''), text]) 3373 3374 def AddDatePicker(self, label, name, value): 3375 writer = HtmlWriter() 3376 self.elements.append([label, writer.GetDatePicker(ctrlID=name, ctrlCaption=None, ctrlFormat='yy-mm-dd', ctrlValue=value, ctrlTitle=''), '']) 3377 3378 def AddText(self, text): 3379 self.elements.append(['', text, '']) 3380 3381 def AddHTML(self, html): 3382 self.elements.append(['', html, '']) 3383 3384 def AddHTMLWithLabel(self, label, html): 3385 self.elements.append([label, html, '']) 3386 3387 def AddReadOnly(self, name, value = '', prettyName = None): 3388 if prettyName is None: 3389 prettyName = name 3390 self.elements.append([prettyName, value, '']) 3391 3392 def AddHidden(self, name, value = '', prettyName = None): 3393 self.elements.append(['', '<input type="hidden" name="%s" id="%s" value="%s">' % (name, name, value), '']) 3394 3395 def AddInput(self, name, value = '', size = 20, text = '', prettyName = None, params = ''): 3396 if prettyName is None: 3397 prettyName = name 3398 self.elements.append([prettyName, self.Input(name, value, size, text, prettyName, params), text]) 3399 3400 def AddDeprecatedInput(self, name, value = '', size = 20, text = '', prettyName = None, params = ''): 3401 if prettyName is None: 3402 prettyName = name 3403 self.elements.append([prettyName, '<input style="background-color:yellow" type="text" id="%s" name="%s" size="%d" value="%s" %s>' % (name, 3404 name, 3405 size, 3406 value, 3407 params), text]) 3408 3409 def Input(self, name, value = '', size = 20, text = '', prettyName = None, params = ''): 3410 if prettyName is None: 3411 prettyName = name 3412 return '<input type="text" id="%s" name="%s" size="%d" value="%s" %s>' % (name, 3413 name, 3414 size, 3415 value, 3416 params) 3417 3418 def AddNumberInput(self, name, value = 0.0, min = None, max = None, step = None, size = 20, text = '', prettyName = None, params = ''): 3419 if prettyName is None: 3420 prettyName = name 3421 self.elements.append([prettyName, '<input type="number" id="{id}" name="{name}" size="{size}" value="{value}" min="{min}" max="{max}" step="{step}" {params}>'.format(id=name, name=name, size=size, value=value, min=min, max=max, step=step, params=params), text]) 3422 3423 def AddCheckedInput(self, chkName, edtName, edtValue = '', label = None, chkLabel = '', edtLabel = '', edtSize = 20, chkChecked = 0, chkDisabled = 0, edtParams = '', lblParams = ''): 3424 if label is None: 3425 label = chkName + edtName 3426 self.elements.append([self.Checkbox(chkName, checked=chkChecked, disabled=chkDisabled, prettyName=chkLabel), '<label class="form-label" for="%s" %s>%s</label></td><td>' % (chkName, lblParams, label), self.Input(edtName, value=edtValue, size=edtSize, prettyName=edtLabel, params=edtParams)]) 3427 3428 def AddPassword(self, name, value = '', size = 20, prettyName = None, text = ''): 3429 if prettyName is None: 3430 prettyName = name 3431 self.elements.append([prettyName, '<input type="password" name="%s" size="%d" value="%s">' % (name, size, value), text]) 3432 3433 def AddCheckbox(self, name, text = '', checked = 0, prettyName = None, disabled = 0, value = None): 3434 if prettyName is None: 3435 prettyName = name 3436 self.elements.append(['<label class="form-padding-label" for="%s">%s</label>' % (name, prettyName), self.Checkbox(name, text, checked, prettyName, disabled, value), '<label class="form-label" for="%s">%s</label>' % (name, text)]) 3437 3438 def Checkbox(self, name, text = '', checked = 0, prettyName = None, disabled = 0, value = None): 3439 if prettyName is None: 3440 prettyName = name 3441 value = '' if value is None else 'value="%s"' % str(value) 3442 code = ' <input type="checkbox" id="%s" %s name="%s"%s%s>' % (name, 3443 value, 3444 name, 3445 ['', ' checked'][not not checked], 3446 ['', ' disabled'][not not disabled]) 3447 return code 3448 3449 def AddRadioGroup(self, name, valname, selected = None, prettyName = None): 3450 if prettyName is None: 3451 prettyName = name 3452 bms = UnicodeMemStream() 3453 if selected is not None: 3454 checked = ' ' 3455 else: 3456 checked = 'checked' 3457 if type(valname) == types.DictType: 3458 valname = valname.items() 3459 for k, v in valname: 3460 if selected is not None and selected == k: 3461 bms.Write('<input type=radio name="%s" value="%s" checked>%s\n' % (name, k, v)) 3462 else: 3463 bms.Write('<input type=radio name="%s" value="%s" %s>%s\n' % (name, 3464 k, 3465 checked, 3466 v)) 3467 checked = ' ' 3468 3469 bms.Seek(0) 3470 self.elements.append([prettyName, bms.Read(), '']) 3471 3472 def AddSelect(self, name, valname, prettyName = None, selected = None, multiple = 0, evenhandler = '', Text = '', style = None, sort = True, rel = None, cssByValue = None): 3473 if prettyName is None: 3474 prettyName = name 3475 self.elements.append([prettyName, self.Select(name, valname, prettyName=prettyName, selected=selected, multiple=multiple, evenhandler=evenhandler, Text=Text, style=style, sort=sort, rel=rel, cssByValue=cssByValue), '']) 3476 3477 def Select(self, name, valname, prettyName = None, selected = None, multiple = 0, evenhandler = '', Text = '', style = None, sort = True, rel = None, cssByValue = None): 3478 if prettyName is None: 3479 prettyName = name 3480 style = CheckValue('style', style) 3481 rel = CheckValue('rel', rel) 3482 bms = UnicodeMemStream() 3483 if multiple: 3484 if multiple < 2 or type(multiple) != type(1): 3485 multiple = 4 3486 bms.Write(' <select id="%s" name="%s" %s size=%s%s%s multiple>\n' % (name, 3487 name, 3488 evenhandler, 3489 multiple, 3490 style, 3491 rel)) 3492 else: 3493 bms.Write(' <select id="%s" name="%s" %s%s%s>\n' % (name, 3494 name, 3495 evenhandler, 3496 style, 3497 rel)) 3498 if type(valname) == type([]): 3499 for i in valname: 3500 if selected is not None and (i[0] == selected or multiple and i[0] in selected): 3501 bms.Write(' <option value="%s" Selected>%s</option>\n' % (i[0], i[1])) 3502 else: 3503 bms.Write(' <option value="%s">%s</option>\n' % (i[0], i[1])) 3504 3505 else: 3506 sortedList = valname.items() 3507 if sort: 3508 sortedList.sort(key=lambda key_value: key_value[1]) 3509 for key, value in sortedList: 3510 rowStyleString = '' 3511 if isinstance(cssByValue, dict) and key in cssByValue: 3512 rowStyleString = 'style="%s" ' % cssByValue[key] 3513 if selected is not None and selected == key: 3514 bms.Write(' <option %svalue="%s" selected>%s</option>\n' % (rowStyleString, key, value)) 3515 else: 3516 bms.Write(' <option %svalue="%s">%s</option>\n' % (rowStyleString, key, value)) 3517 3518 bms.Write(' </select> %s\n' % Text) 3519 bms.Seek(0) 3520 return bms.Read() 3521 3522 def AddSoundSelect(self, name, valname, prettyName = None, selected = None, eventHandler = ''): 3523 if prettyName is None: 3524 prettyName = name 3525 self.elements.append([prettyName, self.SoundSelect(name, valname, prettyName, selected, eventHandler), '']) 3526 3527 def SoundSelect(self, name, valname, prettyName = None, selected = None, eventHandler = ''): 3528 if prettyName is None: 3529 prettyName = name 3530 bms = UnicodeMemStream() 3531 bms.Write(' <select id="%s" name="%s" onchange="play_%s(this);">\n' % (name, name, name)) 3532 if type(valname) == type([]): 3533 for i in valname: 3534 if selected is not None and (i[0] == selected or multiple and i[0] in selected): 3535 bms.Write(' <option value="%s" SELECTED> %s </option>\n' % (i[0], i[1])) 3536 else: 3537 bms.Write(' <option value="%s"> %s </option>\n' % (i[0], i[1])) 3538 3539 else: 3540 l = valname.items() 3541 l.sort(lambda x, y: cmp(x[1], y[1])) 3542 for i in l: 3543 if selected is not None and selected == i[0]: 3544 bms.Write(' <option value="%s" SELECTED> %s </option>\n' % (i[0], i[1])) 3545 else: 3546 bms.Write(' <option value="%s"> %s </option>\n' % (i[0], i[1])) 3547 3548 bms.Write(' </select> \n') 3549 bms.Seek(0) 3550 return bms.Read() 3551 3552 def AddTextArea(self, name, value = '', cols = 68, rows = 26, prettyName = None, props = ''): 3553 if prettyName is None: 3554 prettyName = name 3555 self.elements.append([prettyName, ' <textarea name="%s" cols=%d rows=%d %s>%s</textarea>' % (name, 3556 cols, 3557 rows, 3558 props, 3559 value), '']) 3560 3561 def AddReadOnlyTextArea(self, value, cols, rows): 3562 self.AddHTML('\n <textarea style="color: -internal-light-dark-color(black, gray);" disabled cols="{}", rows="{}">{}</textarea>\n '.format(cols, rows, value)) 3563 3564 def AddHtmlArea(self, name, value = '', cols = 68, rows = 26, prettyName = None, props = ''): 3565 if prettyName is None: 3566 prettyName = name 3567 self.elements.append([prettyName, ' <textarea name="%s" cols=%d rows=%d %s>%s</textarea>\n<script language=\'javascript1.2\'>editor_generate(\'%s\');</script>' % (name, 3568 cols, 3569 rows, 3570 props, 3571 value, 3572 name), '']) 3573 3574 def AddPicker(self, name, Action, Strokes = 3, prettyName = None, SubmitOnSelect = 0, default = None): 3575 if prefs.languageID == 'ZH': 3576 Strokes = 100 3577 if prettyName is None: 3578 prettyName = name 3579 self.elements.append([prettyName, self.Picker(name, Action, Strokes, prettyName, SubmitOnSelect, default), '']) 3580 3581 def Picker(self, name, Action, Strokes = 3, prettyName = None, SubmitOnSelect = 0, default = None): 3582 if prettyName is None: 3583 prettyName = name 3584 self.s = UnicodeMemStream() 3585 if self.formName == 'NeedAName': 3586 if default is not None: 3587 OnSelect = '' 3588 if SubmitOnSelect: 3589 OnSelect = 'onChange="this.form.submit();"' 3590 self.s.Write('<!--BegMark--><SELECT Name="%s" ID="%s" onClick ="%sgoBack(this, event);" onContextMenu="%sgoBack(this, event);" %s>\n' % (name, 3591 name, 3592 name, 3593 name, 3594 OnSelect)) 3595 self.s.Write('<OPTION VALUE="%s" Selected>%s</OPTION>\\n\'\n' % (default[0], default[1])) 3596 self.s.Write('</SELECT>\n') 3597 self.s.Write('<!--EndMark-->\n') 3598 else: 3599 self.s.Write('<!--BegMark--><input type="text" name="%s" ID="%s" onKeyUp="%sGetSelect(event)"><!--EndMark-->\n' % (name, name, name)) 3600 self.s.Write('<iframe id="ifrGetSelect%s" style="display: none; width:1;height:1;border:0px;"></iframe>\n' % name) 3601 self.s.Write('<script type="text/javascript">\n') 3602 self.s.Write(' function %sGetSelect(e){\n' % name) 3603 self.s.Write(' var el = $("#%s"); \n' % name) 3604 self.s.Write(' window.status = el.val(); \n') 3605 self.s.Write(' PressEnter = false; \n') 3606 self.s.Write(' if((e.keyCode == 13)&&(el.val().length > 0)){PressEnter = true;}; \n') 3607 self.s.Write(' if(isNaN(el.val())){\n') 3608 self.s.Write(' if((el.val().length >= %s)||(PressEnter == true)){\n' % Strokes) 3609 self.s.Write(" document.getElementById('ifrGetSelect%s').src='/lib/pickpopulate.py?action=%s&ReplaceElement=%s&Search='+UESconvertText(el.val())+'&SubmitOnSelect=%s';\n" % (name, 3610 Action, 3611 name, 3612 SubmitOnSelect)) 3613 self.s.Write(" document.getElementById('%s').disabled=true;\n" % name) 3614 self.s.Write(' }\n') 3615 self.s.Write(' }\n') 3616 self.s.Write(' }\n') 3617 self.s.Write(' function %sgoBack(oElement, e){\n' % name) 3618 self.s.Write(" if((e.ctrlLeft)||(e.type == 'contextmenu')){\n") 3619 self.s.Write(' repCode = \'<input type="text" name="%s" id="%s" onKeyUp="%sGetSelect(event)">\';\n' % (name, name, name)) 3620 self.s.Write(" inJect = oElement.parentNode.innerHTML.replace(/^.*(.|\\n)*?<\\!--EndMark-->/gi,'<\\!--BegMark-->'+repCode+'<\\!--EndMark-->');\n") 3621 self.s.Write(' oElement.parentNode.innerHTML = inJect;\n') 3622 self.s.Write(' e.cancelBubble = true;\n') 3623 self.s.Write(' }\n') 3624 self.s.Write(' }\n') 3625 self.s.Write('</script>\n') 3626 else: 3627 if default is not None: 3628 OnSelect = '' 3629 if SubmitOnSelect: 3630 OnSelect = 'onChange="this.form.submit();"' 3631 self.s.Write('<!--BegMark--><select Name="%s" ID="%s" onClick ="%s%sgoBack(this, event);" onContextMenu="%s%sgoBack(this, event);" %s>\n' % (name, 3632 name, 3633 self.formName, 3634 name, 3635 self.formName, 3636 name, 3637 OnSelect)) 3638 self.s.Write('<option value="%s" Selected>%s</option>\\n\'\n' % (default[0], default[1])) 3639 self.s.Write('</select>\n') 3640 self.s.Write('<!--EndMark-->\n') 3641 else: 3642 self.s.Write('<!--BegMark--><input type="text" name="%s" id="%s" onKeyUp="%s%sGetSelect(event)"><!--EndMark-->\n' % (name, 3643 name, 3644 self.formName, 3645 name)) 3646 self.s.Write('<iframe id="ifrGetSelect%s" style="display: none; width:1;height:1;border:0px;"></iframe>\n\n' % name) 3647 self.s.Write('<script type="text/javascript">\n') 3648 self.s.Write(' function %s%sGetSelect(e){\n' % (self.formName, name)) 3649 self.s.Write(' var el = document.%s.%s;\n' % (self.formName, name)) 3650 self.s.Write(' window.status = el.value; \n') 3651 self.s.Write(' PressEnter = false \n') 3652 self.s.Write(' if((e.keyCode == 13)&&(el.value.length > 0)){PressEnter = true;} \n') 3653 self.s.Write(' if(isNaN(el.value)){\n') 3654 self.s.Write(' if((el.value.length >= %s)||(PressEnter == true)){\n' % Strokes) 3655 self.s.Write(' document.getElementById("ifrGetSelect%s").src=\'/lib/pickpopulate.py?action=%s&ReplaceElement=%s&Search=\'+UESconvertText(el.value)+\'&SubmitOnSelect=%s&FormName=%s\';\n' % (name, 3656 Action, 3657 name, 3658 SubmitOnSelect, 3659 self.formName)) 3660 self.s.Write(' el.disabled=true;\n') 3661 self.s.Write(' }\n') 3662 self.s.Write(' }\n') 3663 self.s.Write(' }\n') 3664 self.s.Write(' function %s%sgoBack(oElement, e){\n' % (self.formName, name)) 3665 self.s.Write(" if((e.ctrlLeft)||(e.type == 'contextmenu')){\n") 3666 self.s.Write(' repCode = \'<input type="text" name="%s" ID="%s" onKeyUp="%s%sGetSelect(event)">\';\n' % (name, 3667 name, 3668 self.formName, 3669 name)) 3670 self.s.Write(" inJect = oElement.parentNode.innerHTML.replace(/^.*(.|\\n)*?<\\!--EndMark-->/gi,'<\\!--BegMark-->'+repCode+'<\\!--EndMark-->');\n") 3671 self.s.Write(' oElement.parentNode.innerHTML = inJect;\n') 3672 self.s.Write(' e.cancelBubble = true;\n') 3673 self.s.Write(' }\n') 3674 self.s.Write(' }\n') 3675 self.s.Write('</script>\n') 3676 self.s.Seek(0) 3677 return self.s.Read() 3678 3679 def AddModal(self, name, url, parameters = {}, initValues = '', size = 20, prettyName = None, width = 350, height = 350, scroll = 0): 3680 if prettyName is None: 3681 prettyName = name 3682 p = '&modalDialoguePopUp=1' 3683 for k, v in parameters.iteritems(): 3684 p += '&%s=%s' % (k, v) 3685 3686 self.elements.append(['<a href="javascript:Wopen%s();">%s</a>\n\n<script>\nfunction Wopen%s(){\nmodal=window.open(\'%s?modalDialogueElement=%s%s\',\'modalForm\',\'toolbar=0,location=0,directories=no,status=no,menubar=no,scrollbars=%s,resizable=no,width=%s,height=%s\');\n}\n</script>\n' % (name, 3687 prettyName, 3688 name, 3689 url, 3690 name, 3691 p, 3692 scroll, 3693 width, 3694 height), '<input type="text" name="%sDisp" size="%s" id="%sDisp"><input type="hidden" value="%s" name="%s" id="%s">' % (name, 3695 size, 3696 name, 3697 initValues, 3698 name, 3699 name), '']) 3700 3701 def AddButton(self, onClick = '', nm = 'Create', error = '', bolConfirm = 0): 3702 if bolConfirm: 3703 onClick = 'onClick="if(confirm(\'Are you sure?\')){%s}"' % onClick 3704 else: 3705 onClick = 'onClick="%s"' % onClick 3706 self.elements.append(['', '<input type="button" name="%s" value="%s" %s>' % (nm, nm, onClick), error]) 3707 3708 def AddFile(self, name = 'file1', prettyName = None): 3709 if prettyName is None: 3710 prettyName = name 3711 self.elements.append([prettyName, '<input type="file" name="%s">' % name, '']) 3712 3713 def AddSubmit(self, action = '', nm = 'Create', error = '', bolConfirm = 0, onClick = 0, style = 1, name = 'Post', confirmMessage = None): 3714 inLineJavaScript = '' 3715 if bolConfirm: 3716 confirmMessage = confirmMessage or 'Are you sure?' 3717 inLineJavaScript = 'onClick="return confirm(\'%s\')"' % confirmMessage 3718 if onClick != 0: 3719 inLineJavaScript = 'onClick="%s"' % onClick 3720 value = '<input type="submit" id="%s" name="%s" value="%s" %s>' % (name, 3721 name, 3722 nm, 3723 inLineJavaScript) 3724 if action: 3725 value += '\n<input type="hidden" name="action" value="%s">' % (action,) 3726 self.elements.append(['', value, error]) 3727 return self.Generate(style) 3728 3729 def SetColumnCount(self, columnCount = 0): 3730 self.elements.append(['/*SETCOLUMNS*/', columnCount]) 3731 3732 def SetColumnWidth(self, n, w = None): 3733 self.elements.append(['/*SETCOLUMNWIDTH*/', n, w]) 3734 3735 def Generate(self, style = 1): 3736 self.s = UnicodeMemStream() 3737 target = '' 3738 if self.target != '': 3739 target = 'target="%s"' % self.target 3740 encType = '' 3741 if self.encType != '': 3742 encType = 'enctype="%s"' % self.encType 3743 extra = [] 3744 if self.extraAttributes and isinstance(self.extraAttributes, dict): 3745 for k, v in self.extraAttributes.iteritems(): 3746 extra.append('%s="%s"' % (k, v)) 3747 3748 if extra: 3749 extra = ' %s' % ' '.join(extra) 3750 else: 3751 extra = '' 3752 if not (self.url or self.action): 3753 self.s.Write('<form name="%s" method="%s" %s%s>\n' % (self.formName, 3754 self.method, 3755 target, 3756 extra)) 3757 elif not self.action: 3758 self.s.Write('<form name="%s" id="%s" action="%s" method="%s" %s %s%s>\n' % (self.formName, 3759 self.formName, 3760 self.url, 3761 self.method, 3762 target, 3763 encType, 3764 extra)) 3765 else: 3766 stuff = self.url.split('#') 3767 if len(stuff) > 1: 3768 self.s.Write('<form name="%s" id="%s" action="%s?action=%s" method="%s" %s %s%s>\n' % (self.formName, 3769 self.formName, 3770 stuff[0], 3771 self.action + '#' + stuff[1], 3772 self.method, 3773 target, 3774 encType, 3775 extra)) 3776 else: 3777 self.s.Write('<form name="%s" id="%s" action="%s?action=%s" method="%s" %s %s%s>\n' % (self.formName, 3778 self.formName, 3779 self.url, 3780 self.action, 3781 self.method, 3782 target, 3783 encType, 3784 extra)) 3785 if self.waitingMessage is not None: 3786 self.s.Write(WaitingMessage(self.waitingMessage)) 3787 if style != 2: 3788 self.s.Write('<table Border=0>\n') 3789 if style == 1: 3790 columns = 1 3791 prevcolumns = [] 3792 width = {} 3793 i = 0 3794 while i < len(self.elements): 3795 self.s.Write('<tr>\n') 3796 istart = i 3797 for n in range(columns): 3798 try: 3799 if istart + n < len(self.elements): 3800 element = self.elements[istart + n] 3801 if element[0] == '/*SETCOLUMNS*/': 3802 if element[1]: 3803 prevcolumns.append(columns) 3804 columns = element[1] 3805 else: 3806 columns = prevcolumns.pop(-1) 3807 self.s.Write('</tr>\n') 3808 self.s.Write('</table>\n') 3809 self.s.Write('<table Border=0>\n') 3810 self.s.Write('<tr>\n') 3811 break 3812 if element[0] == '/*SETCOLUMNWIDTH*/': 3813 width[element[1]] = element[2] 3814 else: 3815 w = width.get(0, None) 3816 if w: 3817 w = 'width=%s' % w 3818 else: 3819 w = '' 3820 self.s.Write(' <td valign=top %s><span>%s</span></td>\n' % (w, element[0])) 3821 w = width.get(n + 1, None) 3822 if w: 3823 w = 'width=%s' % w 3824 else: 3825 w = '' 3826 self.s.Write(' <td %s>\n' % w) 3827 self.s.Write(' %s %s\n' % (element[1], element[2])) 3828 self.s.Write(' </td>\n') 3829 finally: 3830 i += 1 3831 3832 self.s.Write('</tr>\n') 3833 3834 elif style == 0: 3835 self.s.Write('<tr>') 3836 for element in self.elements: 3837 self.s.Write(' <td valign=top>%s</td>\n' % element[0]) 3838 3839 self.s.Write('</tr>') 3840 self.s.Write('<tr>') 3841 for element in self.elements: 3842 self.s.Write(' <td valign=top>%s</font></td>\n' % element[1]) 3843 3844 self.s.Write('</tr>') 3845 elif style == 2: 3846 for element in self.elements: 3847 if not element[0].startswith('/*'): 3848 self.s.Write(element[0]) 3849 self.s.Write(element[1]) 3850 self.s.Write(element[2]) 3851 3852 if style != 2: 3853 self.s.Write('</table>') 3854 if self.request is not None and self.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): 3855 self.s.Write(CSRFFormField(self.request)) 3856 self.s.Write('</form>') 3857 self.s.Seek(0) 3858 return self.s.Read() 3859 3860 3861 MultipleReplacer = multiple_replacer 3862 try: 3863 sm.services['http'].codeCache.clear() 3864 except: 3865 sys.exc_clear()