NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

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] + '/'