browserutil.py (37032B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\carbonui\control\browser\browserutil.py 2 from future.utils import raise_ 3 import blue 4 import carbonui.const as uiconst 5 import nturl2path 6 import re 7 import urllib 8 import urllib2 9 import urlparse 10 from carbonui.control.combo import Combo 11 from carbonui.primitives.container import Container 12 from carbonui.primitives.frame import Frame 13 from carbonui.primitives.line import Line 14 from carbonui.util.bunch import Bunch 15 from carbonui.util.various_unsorted import GetBrowser, ParseHTMLColor 16 from player_messaging.client.ui_message import prompt_player_fsd_dialog 17 18 class NewBrowserForm(): 19 20 def __init__(self, attrs, browser): 21 if getattr(attrs, 'action', None) is None: 22 setattr(attrs, 'action', GetBrowser(browser).sr.currentURL.split('?')[0]) 23 if str(getattr(attrs, 'method', 'get')).lower() not in ('get', 'post'): 24 setattr(attrs, 'method', 'get') 25 self.submitting = 0 26 self.attrs = attrs 27 self.browser = browser 28 self.fields = [] 29 30 def fixup(self, m): 31 return '&#' + hex(int(m.group(1)))[1:] + ';' 32 33 def decode(self, u): 34 return re.sub('&#(\\d+);', self.fixup, u.encode('cp1252', 'xmlcharrefreplace')) 35 36 def OnSubmit(self, *etc): 37 if self.submitting: 38 prompt_player_fsd_dialog('Busy') 39 return 40 self.submitting = 1 41 e = [] 42 for attrs, wnd in self.fields: 43 if not attrs.name: 44 continue 45 if getattr(attrs, 'type', None).lower() == 'submit' and wnd not in etc: 46 continue 47 getval = getattr(self, 'GetValue_%s' % attrs.type.lower(), lambda *args: None) 48 val = getval(wnd, attrs) 49 if val is not None: 50 e.append((attrs.name, val)) 51 52 d = [] 53 for key, val in e: 54 if type(val) == list: 55 for v in val: 56 if isinstance(v, unicode): 57 v = self.decode(v) 58 d.append((key, v)) 59 60 else: 61 if isinstance(val, unicode): 62 val = self.decode(val) 63 d.append((key, val)) 64 65 s = urllib.urlencode(d) 66 if isinstance(s, unicode): 67 s = self.decode(val) 68 browser = GetBrowser(self.browser) 69 if not browser: 70 return 71 if getattr(self.attrs, 'method', 'get').lower() == 'get': 72 browser.GoTo('?'.join((self.attrs.action, s))) 73 elif self.attrs.method.lower() == 'post': 74 browser.GoTo(self.attrs.action, s) 75 76 def GetField(self, name = None): 77 if name is None: 78 return self.fields[-1][1] 79 for attrs, wnd in self.fields: 80 if attrs.name == name: 81 return wnd 82 else: 83 return 84 85 def GetFields(self): 86 d = {} 87 for attrs, wnd in self.fields: 88 if not attrs.name: 89 continue 90 if getattr(attrs, 'type', None) in ('submit', 'hidden'): 91 continue 92 getval = getattr(self, 'GetValue_%s' % attrs.type.lower(), lambda *args: None) 93 val = getval(wnd, attrs) 94 if val is not None: 95 d[attrs.name] = val 96 97 return d 98 99 def SetFields(self, d): 100 for attrs, wnd in self.fields: 101 if not attrs.name: 102 continue 103 setval = getattr(self, 'SetValue_%s' % attrs.type.lower(), lambda *args: None) 104 if attrs.name not in d: 105 if getattr(attrs, 'type', None) == 'checkbox': 106 setval(wnd, attrs, 0) 107 continue 108 setval(wnd, attrs, d[attrs.name]) 109 110 def AddInput(self, attrs, add = 1): 111 attrs.vspace = getattr(attrs, 'vspace', 1) 112 if attrs.type is None: 113 attrs.type = 'text' 114 create = getattr(self, 'Create_%s' % attrs.type.lower(), None) 115 if create: 116 wnd = create(attrs) 117 else: 118 wnd = Container() 119 browser = GetBrowser(self.browser) 120 if not browser: 121 return 122 if add: 123 self.fields.append((attrs, wnd)) 124 attrs.control = wnd 125 attrs.align = getattr(attrs, 'align', None) 126 obj = Bunch() 127 obj.font = None 128 obj.key = 'input_%s' % attrs.type.lower() 129 obj.type = '<input>' 130 obj.attrs = attrs 131 wnd.state = uiconst.UI_HIDDEN 132 if hasattr(self.browser, 'sr'): 133 wnd.SetParent(self.browser.sr.cacheContainer) 134 startup = getattr(self, 'Startup_%s' % attrs.type.lower(), None) 135 if startup: 136 startup(wnd, attrs) 137 obj.width = wnd.width + 5 138 obj.height = wnd.height + 5 139 obj.valign = 1 140 if add: 141 obj.control = wnd 142 wnd.loaded = 1 143 else: 144 wnd.Close() 145 return obj 146 147 def AddTextArea(self, attrs, add = 1): 148 attrs.type = 'textarea' 149 return self.AddInput(attrs, add) 150 151 def AddSelect(self, attrs, options, add = 1): 152 attrs.type = 'select' 153 attrs.options = options 154 return self.AddInput(attrs, add) 155 156 def StdGetValue(self, wnd, attrs): 157 return wnd.GetValue() 158 159 def StdSetValue(self, wnd, attrs, val): 160 wnd.SetValue(val) 161 162 def GetValue_submit(self, wnd, attrs): 163 return getattr(attrs, 'value', None) or 'Submit' 164 165 def GetValue_hidden(self, wnd, attrs): 166 return attrs.value 167 168 def Create_textarea(self, attrs): 169 from carbonui.control.edit import EditCoreOverride as Edit 170 wnd = Edit(name='textarea', align=uiconst.RELATIVE) 171 wnd.width = getattr(attrs, 'width', None) or 8 * int(attrs.cols) or 350 172 wnd.height = getattr(attrs, 'height', None) or 18 * int(attrs.rows) or 45 173 return wnd 174 175 def Startup_textarea(self, wnd, attrs): 176 if getattr(attrs, 'maxlength', None): 177 wnd.SetMaxLength(attrs.maxlength) 178 if hasattr(attrs, 'readonly'): 179 wnd.ReadOnly() 180 if attrs.value: 181 wnd.SetValue(attrs.value) 182 color = self.browser.attrStack[-1]['color'] 183 Line(parent=wnd, align=uiconst.TOTOP, color=color, weight=1) 184 Line(parent=wnd, align=uiconst.TOBOTTOM, color=color, weight=1) 185 Line(parent=wnd, align=uiconst.TOLEFT, color=color, weight=1) 186 Line(parent=wnd, align=uiconst.TORIGHT, color=color, weight=1) 187 188 def GetValue_textarea(self, wnd, attrs): 189 return wnd.GetValue().replace('<br>', '\r\n') 190 191 SetValue_textarea = StdSetValue 192 193 def Create_text(self, attrs): 194 from carbonui.control.singlelineedits.singleLineEditText import SingleLineEditText 195 wnd = SingleLineEditText(name='textedit', align=uiconst.RELATIVE, pos=(0, 196 0, 197 getattr(attrs, 'width', None) or min(200, 7 * (attrs.size or 30)), 198 16)) 199 return wnd 200 201 def Startup_text(self, wnd, attrs, password = 0): 202 wnd.OnReturn = self.OnSubmit 203 if password: 204 wnd.SetPasswordChar('*') 205 maxlength = getattr(attrs, 'maxlength', None) 206 if maxlength is not None: 207 wnd.SetMaxLength(int(maxlength)) 208 if attrs.value: 209 wnd.SetValue(attrs.value, updateIndex=0) 210 if hasattr(self.browser, 'attrStack'): 211 color = self.browser.attrStack[-1]['color'] 212 Line(parent=wnd, align=uiconst.TOTOP, color=color, weight=1) 213 Line(parent=wnd, align=uiconst.TOBOTTOM, color=color, weight=1) 214 Line(parent=wnd, align=uiconst.TOLEFT, color=color, weight=1) 215 Line(parent=wnd, align=uiconst.TORIGHT, color=color, weight=1) 216 217 GetValue_text = StdGetValue 218 SetValue_text = StdSetValue 219 Create_password = Create_text 220 221 def Startup_password(self, wnd, attrs): 222 self.Startup_text(wnd, attrs, password=1) 223 wnd.SetPasswordChar('\x95') 224 225 GetValue_password = StdGetValue 226 SetValue_password = StdSetValue 227 228 def Create_checkbox(self, attrs): 229 from carbonui.control.checkbox import Checkbox 230 cbox = Checkbox(pos=(0, 0, 0, 0), align=uiconst.RELATIVE) 231 cbox.data = {} 232 attrs.vspace = 3 233 return cbox 234 235 def Startup_checkbox(self, wnd, attrs): 236 checked = getattr(attrs, 'checked', '').lower() == 'checked' 237 if not checked and 'checked' in attrs.__dict__ and getattr(attrs, 'checked', None) is None: 238 checked = 1 239 wnd.SetChecked(checked, 0) 240 241 def SetValue_checkbox(self, wnd, attrs, val): 242 if val == attrs.value: 243 wnd.SetValue(1) 244 else: 245 wnd.SetValue(0) 246 247 def GetValue_checkbox(self, wnd, attrs): 248 checked = wnd.GetValue() 249 if checked: 250 return attrs.value or 'on' 251 else: 252 return None 253 254 def Create_radio(self, attrs): 255 ret = self.Create_checkbox(attrs) 256 ret.SetGroup(attrs.name) 257 ret.width = ret.height = 14 258 return ret 259 260 Startup_radio = Startup_checkbox 261 GetValue_radio = GetValue_checkbox 262 SetValue_radio = SetValue_checkbox 263 264 def Create_select(self, attrs): 265 if getattr(attrs, 'size', None) is not None or getattr(attrs, 'height', 0): 266 from carbonui.control.combo import SelectCore as Select 267 return Select(name='select', align=uiconst.RELATIVE, pos=(0, 268 0, 269 getattr(attrs, 'width', None) or 128, 270 getattr(attrs, 'height', None) or int(attrs.size) * 18 - 1 + attrs.vspace * 2)) 271 c = Combo(name='selection_%s' % attrs.name, align=uiconst.RELATIVE) 272 if getattr(attrs, 'width', None) is not None: 273 c.width = getattr(attrs, 'width', None) 274 return c 275 276 def Startup_select(self, wnd, attrs): 277 if getattr(attrs, 'size', None) is not None or getattr(attrs, 'height', 0): 278 wnd.Startup([ (k, v, s) for k, v, s in attrs.options ]) 279 if not hasattr(attrs, 'multiple'): 280 wnd.multiSelect = 0 281 for each in wnd.children: 282 if each.name in ('_underlay',): 283 each.Close() 284 if each.name == 'activeframe': 285 each.Flush() 286 Frame(parent=each, color=self.browser.attrStack[-1]['color'], padding=(-1, -1, -1, -1)) 287 288 Line(parent=wnd, align=uiconst.TOTOP, color=getattr(attrs, 'fontcolor', None), weight=1) 289 Line(parent=wnd, align=uiconst.TOBOTTOM, color=getattr(attrs, 'fontcolor', None), weight=1) 290 Line(parent=wnd, align=uiconst.TOLEFT, color=getattr(attrs, 'fontcolor', None), weight=1) 291 Line(parent=wnd, align=uiconst.TORIGHT, color=getattr(attrs, 'fontcolor', None), weight=1) 292 Container(name='push', parent=wnd, align=uiconst.TOTOP, pos=(0, 293 0, 294 0, 295 attrs.vspace), idx=0) 296 Container(name='push', parent=wnd, align=uiconst.TOBOTTOM, pos=(0, 297 0, 298 0, 299 attrs.vspace), idx=0) 300 else: 301 default = None 302 for key, value, selected in attrs.options: 303 if selected: 304 default = key 305 break 306 307 if getattr(attrs, 'width', None) is not None: 308 wnd.Startup([ (k, v) for k, v, s in attrs.options ], default=default) 309 else: 310 wnd.Startup([ (k, v) for k, v, s in attrs.options ], default=default, adjustWidth=1) 311 clipper = wnd.GetChild('clipper') 312 clipper.clipChildren = 1 313 for each in wnd.children: 314 if each.name == 'selected': 315 wnd.sr.activeframe = Frame(parent=each, color=getattr(attrs, 'fontcolor', None), padding=(-1, -1, -1, -1)) 316 wnd.sr.activeframe.state = uiconst.UI_HIDDEN 317 Frame(parent=each, color=getattr(attrs, 'fontcolor', None)) 318 Container(name='push', parent=each, align=uiconst.TOTOP, pos=(0, 319 0, 320 0, 321 attrs.vspace), idx=0) 322 Container(name='push', parent=each, align=uiconst.TOBOTTOM, pos=(0, 323 0, 324 0, 325 attrs.vspace), idx=0) 326 for child in each.children: 327 if child.name in ('_underlay',): 328 child.Close() 329 330 break 331 332 def GetValue_select(self, wnd, attrs): 333 v = wnd.GetValue() 334 if getattr(wnd, 'multiSelect', 1) == 0 and type(v) == list: 335 return v[0] 336 return v 337 338 def SetValue_select(self, wnd, attrs, val): 339 wnd.SetValue(val) 340 341 def Create_submit(self, attrs): 342 raise NotImplementedError('This functionality has been removed') 343 344 345 class Css(): 346 347 def __init__(self): 348 self.Reset() 349 350 def Reset(self): 351 self.classes = [] 352 self.s = {} 353 354 def copy(self): 355 new = Css() 356 new.classes = self.classes[:] 357 return new 358 359 def ApplyCSS(self, tag, attrs, attrStack): 360 classlist = [] 361 for c in self.classes: 362 if self.CompareSelector(attrStack[-1], c) == 1: 363 b = 0 364 if c['deptag']: 365 i = len(attrStack) - 2 366 if i < 0: 367 continue 368 for t in c['deptag']: 369 if b == 1 or i < 0: 370 break 371 if t['op'] == ' ': 372 while not self.CompareSelector(attrStack[i], t): 373 i -= 1 374 if i < 0: 375 b = 1 376 break 377 378 if i < 0: 379 b = 1 380 break 381 i -= 1 382 elif t['op'] == '>': 383 if self.CompareSelector(attrStack[i], t): 384 i -= 1 385 continue 386 else: 387 b = 1 388 break 389 elif t['op'] == '*': 390 i -= 1 391 if i < 0: 392 break 393 while not self.CompareSelector(attrStack[i], t): 394 i -= 1 395 if i < 0: 396 b = 1 397 break 398 399 if i < 0: 400 b = 1 401 break 402 i -= 1 403 elif t['op'] == '+': 404 if attrStack[i]['lasttag'] == t['tag']: 405 i -= 1 406 continue 407 else: 408 b = 1 409 break 410 411 if b == 0: 412 classlist.append(c) 413 414 classlist.sort(lambda x, y: cmp(x['prio'], y['prio'])) 415 c = {} 416 for each in classlist: 417 c.update(each) 418 419 return c 420 421 def CompareSelector(self, astack, csel): 422 tag = astack['tag'] 423 tid = getattr(astack['attr'], 'id', None) 424 cl = getattr(astack['attr'], 'class', '').lower() 425 if csel['tag'] not in (tag, '*') and csel['tag']: 426 return 427 if csel['class']: 428 if csel['class'] not in cl.split(' '): 429 return 430 if csel['id'] and tid != csel['id']: 431 return 432 return 1 433 434 def SplitSelector(self, sel): 435 s = {} 436 s['tag'] = None 437 s['id'] = None 438 s['class'] = None 439 s['attr'] = None 440 s['pclass'] = None 441 sel = sel.strip().lower() 442 if sel.count(':'): 443 sel, pclass = sel.split(':', 1) 444 s['pclass'] = pclass 445 if sel == '': 446 sel = '*' 447 ccount = sel.count('.') 448 acount = sel.count('[') 449 icount = sel.count('#') 450 if ccount + acount + icount > 1: 451 return 452 if ccount == 1: 453 h = sel.split('.') 454 if len(h) == 1: 455 s['class'] = h[0] 456 else: 457 s['tag'] = h[0] 458 s['class'] = h[1] 459 return s 460 if acount == 1: 461 h = sel.split('[') 462 if sel[-1] == ']': 463 if len(h) == 1: 464 s['attr'] = h[0] 465 else: 466 s['tag'] = h[0] 467 s['attr'] = h[1] 468 else: 469 return 470 return s 471 if icount == 1: 472 h = sel.split('#') 473 if len(h) == 1: 474 s['id'] = h[0] 475 else: 476 s['tag'] = h[0] 477 s['id'] = h[1] 478 return s 479 s['tag'] = sel 480 return s 481 482 def GetClass(self, classID): 483 classID = classID.lower() 484 for c in self.classes: 485 if c['id'] == classID: 486 return c 487 if c['class'] == classID: 488 return c 489 490 def HandlePseudoClass(self, pclass): 491 links = [('link', 'link-color'), 492 ('visited', 'vlink-color'), 493 ('active', 'alink-color'), 494 ('hover', 'alink-color')] 495 d = {} 496 for dclass, attr in links: 497 if pclass == dclass and 'color' in self.s: 498 d[attr] = self.s['color'] 499 500 self.s = d.copy() 501 502 def ParseCSSData(self, cssdata): 503 lines = '' 504 for dataAndComment in cssdata.split('*/'): 505 data = dataAndComment.split('/*', 1)[0] 506 lines += data 507 508 for styleClass in lines.split('}'): 509 if not styleClass: 510 continue 511 if styleClass.count('{') != 1: 512 continue 513 attr, styles = styleClass.strip().split('{') 514 self.s = {} 515 prio = 0 516 if not styles: 517 continue 518 data, imp = self.ParseStyleData(styles.strip()) 519 self.ParseStyle(data) 520 selector = depsel = depop = None 521 prio += attr.count('.') * 100 + attr.count('#') * 1000 + attr.count('[') * 10 + attr.count(' ') + 1 - (attr.count('.') + attr.count('#') + attr.count('[')) 522 selectors = attr.replace('\t', ' ').replace(' ', ' ').strip().split(' ') 523 selector = selectors[-1] 524 selectors = selectors[:-1] 525 selectors.reverse() 526 deptags = [] 527 op = ' ' 528 for t in selectors: 529 if t in ('>', '*', '+'): 530 op = t 531 else: 532 d = self.SplitSelector(t) 533 if d: 534 d['op'] = op 535 deptags.append(d) 536 op = ' ' 537 538 for sel in selector.split(','): 539 attrs = self.SplitSelector(sel) 540 if attrs: 541 if attrs['pclass']: 542 self.HandlePseudoClass(attrs['pclass']) 543 s = self.s.copy() 544 s['tag'] = attrs['tag'] 545 s['class'] = attrs['class'] 546 s['id'] = attrs['id'] 547 s['attr'] = attrs['attr'] 548 s['deptag'] = deptags 549 s['prio'] = prio 550 self.classes.append(s) 551 552 if len(imp): 553 self.s = {} 554 self.ParseStyle(imp) 555 for sel in selector.split(','): 556 attrs = self.SplitSelector(sel) 557 if attrs: 558 if attrs['pclass']: 559 self.HandlePseudoClass(attrs['pclass']) 560 s = self.s.copy() 561 s['tag'] = attrs['tag'] 562 s['class'] = attrs['class'] 563 s['id'] = attrs['id'] 564 s['attr'] = attrs['attr'] 565 s['deptag'] = deptags 566 s['prio'] = 10000 567 self.classes.append(s) 568 569 def ParseStyleData(self, cssdata): 570 data = {} 571 imp = {} 572 for attrAndValue in cssdata.split(';'): 573 if not attrAndValue: 574 continue 575 if ':' in attrAndValue: 576 attr, value = attrAndValue.strip().split(':', 1) 577 else: 578 continue 579 if attr and value: 580 attr = attr.strip().lower() 581 if '!' in value: 582 value, important = value.split('!', -1) 583 if important.strip().lower() == 'important': 584 imp[attr] = value.strip() 585 continue 586 data[attr] = value.strip() 587 588 return (data, imp) 589 590 def ParseCSS(self, attrs = None): 591 self.s = {} 592 sattr = getattr(attrs, 'style', None) 593 if sattr: 594 data, imp = self.ParseStyleData(sattr) 595 data.update(imp) 596 return self.ParseStyle(data) 597 598 def ParseStyle(self, style = None): 599 if style: 600 for k, v in style.iteritems(): 601 if k in self.styleDict: 602 eval('self.%s' % self.styleDict[k])(k, v) 603 604 return self.s 605 606 def ParseStyleNum(self, value): 607 value = str(value).lower().strip() 608 if value.isdigit(): 609 return int(value) 610 if value.endswith('%'): 611 return value 612 if value[-2:] in self.absStyleUnits and value[:-2].isdigit(): 613 return int(self.absStyleUnits[value[-2:]] * float(value[:-2].strip())) 614 try: 615 return int(value) 616 except: 617 return None 618 619 absStyleUnits = {'px': 1.0, 620 'in': 100.0, 621 'cm': 100.0 / 2.54, 622 'mm': 100.0 / 25.4, 623 'pt': 100.0 / 72.0, 624 'pc': 100.0 / 6.0} 625 626 def ParseFontSize(self, k, v): 627 if v: 628 if not v.isdigit(): 629 if v in self.fontSize: 630 v = self.fontSize[v] 631 v = self.ParseStyleNum(v) 632 if v is None or not type(v) == int and not v.isdigit(): 633 return 634 if v in self.fontFamilies: 635 self.s['font-size'] = int(v) 636 self.s['font-family'] = self.fontFamilies[int(v)] 637 else: 638 self.s['font-size'] = int(v or 10) 639 self.s['font-family'] = 'sans' 640 641 def ParseFontStyle(self, k, v): 642 if v: 643 if v == 'normal': 644 self.s['font-style'] = 'n' 645 if v in ('italic', 'oblique'): 646 self.s['font-style'] = 'i' 647 648 def ParseFontWeight(self, k, v): 649 if v: 650 if v == 'normal': 651 self.s['font-weight'] = 'n' 652 elif v in ('bold', 'bolder'): 653 self.s['font-weight'] = 'b' 654 655 def ParseTextDecoration(self, k, v): 656 if v: 657 if v == 'none': 658 self.s['text-decoration'] = '' 659 return 660 s = str(v) 661 s = s.replace('underline', 'u').replace('line-through', 's').replace('overline', 'o') 662 for t in s: 663 if t.strip() not in ('u', 's', 'o'): 664 return 665 666 self.s['text-decoration'] = s 667 668 def ParseTextAlign(self, k, v): 669 if v in ('left', 'right', 'center'): 670 self.s['text-align'] = v 671 672 def ParseFont(self, k, v): 673 if v: 674 for param in v.split(' '): 675 self.ParseFontSize('', param) 676 self.ParseFontStyle('', param) 677 self.ParseFontWeight('', param) 678 self.ParseTextDecoration('', param) 679 680 def ParseMargin(self, k, v): 681 if v: 682 a = [] 683 for p in v.replace(' ', ' ').split(' '): 684 p = self.ParseStyleNum(p) 685 if p: 686 a.append(p) 687 688 if len(a) > 0: 689 self.s['margin-left'] = a[[0, 690 1, 691 1, 692 3][len(a) - 1]] 693 self.s['margin-right'] = a[[0, 694 1, 695 1, 696 1][len(a) - 1]] 697 self.s['margin-top'] = a[[0, 698 0, 699 0, 700 0][len(a) - 1]] 701 self.s['margin-bottom'] = a[[0, 702 0, 703 2, 704 2][len(a) - 1]] 705 706 def ParsePadding(self, k, v): 707 if v: 708 v = self.ParseStyleNum(v) 709 if v: 710 self.s['padding-left'] = self.s['padding-right'] = v 711 self.s['padding-top'] = self.s['padding-bottom'] = v 712 713 def ParseBorderWidth(self, k, v): 714 if v: 715 if v in self.borderWidths: 716 v = self.borderWidths[v] 717 else: 718 v = self.ParseStyleNum(v) 719 if v: 720 if k == 'border-width': 721 for i in ('left', 'right', 'top', 'bottom'): 722 self.s['border-' + i + '-width'] = v 723 724 else: 725 self.s[k] = v 726 727 def ParseBorderColor(self, k, v): 728 if v: 729 v = ParseHTMLColor(v, 1, error=1) 730 if v: 731 self.s['border-left-color'] = self.s['border-right-color'] = v 732 self.s['border-top-color'] = self.s['border-bottom-color'] = v 733 734 def ParseBorderStyles(self, k, v): 735 if v: 736 if v in self.borderStyles: 737 self.s[k] = self.borderStyles[v] 738 739 def ParseBorderStyle(self, k, v): 740 if v in self.borderStyles: 741 self.s['border-left-style'] = self.borderStyles[v] 742 self.s['border-right-style'] = self.borderStyles[v] 743 self.s['border-top-style'] = self.borderStyles[v] 744 self.s['border-bottom-style'] = self.borderStyles[v] 745 746 def ParseBorder(self, k, v): 747 for each in v.split(' '): 748 if each in self.borderStyles: 749 self.ParseBorderStyle(k, each) 750 continue 751 self.ParseBorderColor(k, each) 752 self.ParseBorderWidth('border-width', each) 753 754 def ParseBorders(self, k, v): 755 for each in v.split(' '): 756 if each in self.borderStyles: 757 self.ParseBorderStyles(k, each) 758 continue 759 self.ParseColor(k + '-color', each) 760 self.ParseBorder(k + '-width', each) 761 762 def ParseBorderCollapse(self, k, v): 763 if v in self.borderCollapse: 764 self.s['border-collapse'] = self.borderCollapse[v] 765 else: 766 self.s['border-collapse'] = 0 767 768 def ParseColor(self, k, v): 769 if v: 770 v = ParseHTMLColor(v, 1, error=1) 771 if v: 772 self.s[k] = v 773 774 def ParseBackground(self, k, v): 775 for each in v.split(' '): 776 each = each.replace(' ', '').lower() 777 if each.find('url(') != -1: 778 self.ParseBackgroundImage(None, each) 779 elif each.find('repeat') != -1: 780 self.ParseBackgroundRepeat(None, each) 781 elif v: 782 color = ParseHTMLColor(each, 1, error=1) 783 if color: 784 self.s['background-color'] = color 785 786 def ParseBackgroundRepeat(self, k, v): 787 if v in ('repeat', 'repeat-x', 'repeat-y', 'no-repeat'): 788 self.s['background-repeat'] = v 789 790 def ParseBackgroundImage(self, k, v): 791 if v and v.startswith('url(') and v.endswith(')'): 792 self.s['background-image'] = v[4:-1] 793 794 def ParseBackgroundAttachment(self, k, v): 795 if v in ('fixed', 'scroll'): 796 self.s['background-attachment'] = v 797 798 def ParseBackgroundPosition(self, k, v): 799 if v: 800 v = v.split(' ') 801 if len(v) in (2, 4): 802 self.ParseAbsSize('background-image-left', v[0]) 803 self.ParseAbsSize('background-image-top', v[1]) 804 if len(v) == 4: 805 self.ParseAbsSize('background-image-width', v[2]) 806 self.ParseAbsSize('background-image-height', v[3]) 807 self.s['background-position'] = [] 808 for i in v: 809 if i in ('top', 'center', 'middle', 'bottom', 'left', 'right'): 810 self.s['background-position'].append(i) 811 812 def ParseAbsSize(self, k, v): 813 if v: 814 v = self.ParseStyleNum(v) 815 if v: 816 self.s[k] = int(v) 817 818 def ParsePosAbsSize(self, k, v): 819 if v: 820 v = self.ParseStyleNum(v) 821 if v: 822 if type(v) == int: 823 self.s[k] = max(v, 0) 824 else: 825 self.s[k] = v 826 827 def ParseVerticalAlign(self, k, v): 828 if v in self.vertStyles: 829 self.s['vertical-align'] = self.vertStyles[v] 830 831 def ParseHorizontalAlign(self, k, v): 832 if v in ('left', 'right', 'center'): 833 self.s['horizontal-align'] = v 834 835 def ParsePosition(self, k, v): 836 if v in ('absolute', 'fixed', 'relative', 'static'): 837 self.s['position'] = v 838 839 def ParseFloat(self, k, v): 840 if v in ('left', 'right'): 841 self.s['float'] = v 842 elif v == 'none': 843 self.s['float'] = None 844 elif v == 'inherit' and 'float' in self.s: 845 del self.s['float'] 846 847 fontSize = {'small': 8, 848 'x-small': 7, 849 'xx-small': 6, 850 'smaller': 8, 851 'medium': 10, 852 'large': 12, 853 'larger': 14, 854 'x-large': 20} 855 fontFamilies = {8: 'sans', 856 10: 'sans', 857 12: 'sans', 858 14: 'sans', 859 20: 'sans'} 860 vertStyles = {'top': 0, 861 'middle': 1, 862 'bottom': 2, 863 'baseline': 3, 864 'sub': 4, 865 'super': 5} 866 borderStyles = {'none': None, 867 'hidden': 0, 868 'solid': 1, 869 'groove': 2, 870 'ridge': 2, 871 'inset': 2, 872 'outset': 2} 873 borderWidths = {'thin': 1, 874 'medium': 2, 875 'thick': 3} 876 borderCollapse = {'seperate': 0, 877 'collapse': 1} 878 absStyles = ('text-indent', 'margin-left', 'margin-right', 'margin-top', 'margin-bottom', 'padding-left', 'padding-right', 'padding-top', 'padding-bottom', 'border-left-width', 'border-right-width', 'border-top-width', 'border-bottom-width', 'letter-spacing', 'word-spacing', 'line-height') 879 styleDict = {'text-indent': 'ParseAbsSize', 880 'margin-left': 'ParsePosAbsSize', 881 'margin-right': 'ParsePosAbsSize', 882 'margin-top': 'ParsePosAbsSize', 883 'margin-bottom': 'ParsePosAbsSize', 884 'padding-left': 'ParsePosAbsSize', 885 'padding-right': 'ParsePosAbsSize', 886 'padding-top': 'ParsePosAbsSize', 887 'padding-bottom': 'ParsePosAbsSize', 888 'border-left-width': 'ParseBorderWidth', 889 'border-right-width': 'ParseBorderWidth', 890 'border-top-width': 'ParseBorderWidth', 891 'border-bottom-width': 'ParseBorderWidth', 892 'border-left-style': 'ParseBorderStyles', 893 'border-right-style': 'ParseBorderStyles', 894 'border-top-style': 'ParseBorderStyles', 895 'border-bottom-style': 'ParseBorderStyles', 896 'letter-spacing': 'ParseAbsSize', 897 'word-spacing': 'ParseAbsSize', 898 'line-height': 'ParsePosAbsSize', 899 'font-size': 'ParseFontSize', 900 'font-weight': 'ParseFontWeight', 901 'font-style': 'ParseFontStyle', 902 'text-decoration': 'ParseTextDecoration', 903 'text-align': 'ParseTextAlign', 904 'font': 'ParseFont', 905 'margin': 'ParseMargin', 906 'padding': 'ParsePadding', 907 'border-width': 'ParseBorderWidth', 908 'border-color': 'ParseBorderColor', 909 'border-style': 'ParseBorderStyle', 910 'border': 'ParseBorder', 911 'border-left': 'ParseBorders', 912 'border-right': 'ParseBorders', 913 'border-top': 'ParseBorders', 914 'border-bottom': 'ParseBorders', 915 'color': 'ParseColor', 916 'link-color': 'ParseColor', 917 'alink-color': 'ParseColor', 918 'vlink-color': 'ParseColor', 919 'background': 'ParseBackground', 920 'background-color': 'ParseColor', 921 'border-left-color': 'ParseColor', 922 'border-right-color': 'ParseColor', 923 'border-top-color': 'ParseColor', 924 'border-bottom-color': 'ParseColor', 925 'vertical-align': 'ParseVerticalAlign', 926 'align': 'ParseHorizontalAlign', 927 'background-repeat': 'ParseBackgroundRepeat', 928 'background-image': 'ParseBackgroundImage', 929 'background-image-color': 'ParseColor', 930 'background-image-width': 'ParseAbsSize', 931 'background-image-height': 'ParseAbsSize', 932 'background-image-left': 'ParseAbsSize', 933 'background-image-top': 'ParseAbsSize', 934 'background-attachment': 'ParseBackgroundAttachment', 935 'background-position': 'ParseBackgroundPosition', 936 'border-collapse': 'ParseBorderCollapse', 937 'position': 'ParsePosition', 938 'float': 'ParseFloat', 939 'left': 'ParseAbsSize', 940 'right': 'ParseAbsSize', 941 'top': 'ParseAbsSize', 942 'bottom': 'ParseAbsSize', 943 'width': 'ParsePosAbsSize', 944 'min-width': 'ParsePosAbsSize', 945 'max-width': 'ParsePosAbsSize', 946 'height': 'ParsePosAbsSize', 947 'min-height': 'ParsePosAbsSize', 948 'max-height': 'ParsePosAbsSize'} 949 950 951 def GetStringFromURL(url, data = None, cookie = None): 952 if cookie: 953 header = {'Cookie': cookie} 954 else: 955 header = {} 956 header['User-Agent'] = 'CCP-minibrowser/3.0' 957 for k, v in header.iteritems(): 958 if isinstance(v, unicode): 959 header[k] = v.encode('ascii', 'xmlcharrefreplace') 960 else: 961 header[k] = str(v) 962 963 try: 964 url = url.encode('ascii') 965 except: 966 if not url.startswith('file:'): 967 raise urllib2.URLError('URL contained non-ascii characters') 968 969 try: 970 r = urllib2.Request(url, data, header) 971 if url.lower().find('local://') == 0: 972 return OpenLocalURL(url, r, data, cookie) 973 return urllib2.urlopen(r) 974 except ValueError as what: 975 if what.args[0].startswith('invalid literal for int():'): 976 raise urllib2.URLError('malformed URL') 977 raise 978 979 980 def OpenLocalURL(url, r, data, cookie): 981 path = url[url.find(':') + 2:] 982 983 class FakeSocket: 984 985 def __init__(self, req, data): 986 self.request = req 987 self.header = ['HTTP'] 988 self.buff = '' 989 self.isFake = True 990 method = 'GET' 991 contentLength = '' 992 contentType = '' 993 post = '' 994 if data: 995 method = 'POST' 996 contentLength = 'Content-Length: %s\r\n' % len(data) 997 contentType = 'Content-Type: application/x-www-form-urlencoded\r\n' 998 post = data + '\r\n' 999 self.buff = '%(method)s %(path)s HTTP/1.0\r\nHost: dummy:0\r\nUser-agent: EVE\r\nEve.trusted: no\r\n%(contenttype)s%(contentlength)s\r\n%(data)s\r\n' % {'method': method, 1000 'path': path, 1001 'contenttype': contentType, 1002 'contentlength': contentLength, 1003 'data': post} 1004 1005 def Read(self): 1006 return self.buff 1007 1008 def Write(self, what): 1009 self.buff = what 1010 1011 class FakeInfo: 1012 1013 def __init__(self): 1014 self.headers = {} 1015 1016 class FakeResponse: 1017 1018 def __init__(self, buf): 1019 self.buf = buf 1020 self.inf = FakeInfo() 1021 self.url = '' 1022 self.headers = {} 1023 1024 def read(self): 1025 return self.buf 1026 1027 def info(self): 1028 return self.inf 1029 1030 fakeSocket = FakeSocket(r, data) 1031 conn = sm.GetService('http') 1032 conn.Handle(ep) 1033 buf = ep.Read() 1034 code = int(buf[9:12]) 1035 if code == 302: 1036 lines = buf.split('\r\n') 1037 loc = '' 1038 lkey = 'location: ' 1039 for l in lines: 1040 if l.lower().find(lkey) >= 0: 1041 loc = l[len(lkey):] 1042 break 1043 1044 loc, a = ParseURL(loc, 'local://') 1045 return GetStringFromURL(loc, data, cookie) 1046 content = buf[buf.find('\r\n\r\n') + 4:] 1047 return FakeResponse(content) 1048 1049 1050 def ParseURL(url, current = None): 1051 url = url.encode('ascii') 1052 if current: 1053 current = current.encode('ascii') 1054 if current.find('local://') == 0 and url.find('://') == -1: 1055 url = 'local://' + url 1056 else: 1057 url = urlparse.urljoin(current, url) 1058 elif url.find(':/') == -1: 1059 url = 'http://' + url 1060 repl = None 1061 if 'res:/' in url: 1062 repl = ('res:/', blue.paths.ResolvePath(u'res:/')) 1063 elif 'script:/' in url: 1064 repl = ('script:/', blue.paths.ResolvePath(u'script:/')) 1065 elif 'cache:/' in url: 1066 repl = ('cache:/', blue.paths.ResolvePath(u'cache:/')) 1067 if repl: 1068 url = url.replace(repl[0], 'file:' + nturl2path.pathname2url(repl[1])) 1069 scheme, netloc, path, query, fragment = urlparse.urlsplit(url) 1070 return (urlparse.urlunsplit((scheme, 1071 netloc, 1072 path, 1073 query, 1074 '')), fragment) 1075 1076 1077 def DirUp(url, force = 1): 1078 i = url[:-1].rfind('/') 1079 if i == -1: 1080 if force: 1081 raise_(ValueError, 'Bad URL (no parent dir): %s' % url) 1082 return url 1083 return url[:i] + '/'