Package cssutils :: Module serialize
[hide private]
[frames] | no frames]

Source Code for Module cssutils.serialize

  1  #!/usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3  """serializer classes for CSS classes 
  4   
  5  """ 
  6  __all__ = ['CSSSerializer'] 
  7  __docformat__ = 'restructuredtext' 
  8  __author__ = '$LastChangedBy: cthedot $' 
  9  __date__ = '$LastChangedDate: 2008-01-14 23:21:12 +0100 (Mo, 14 Jan 2008) $' 
 10  __version__ = '$LastChangedRevision: 850 $' 
 11   
 12  import codecs 
 13  import re 
 14  import cssutils 
 15  import util 
 16   
17 -def _escapecss(e):
18 """ 19 Escapes characters not allowed in the current encoding the CSS way 20 with a backslash followed by a uppercase hex code point 21 22 E.g. the german umlaut 'ä' is escaped as \E4 23 """ 24 s = e.args[1][e.start:e.end] 25 return u''.join([ur'\%s ' % str(hex(ord(x)))[2:] # remove 0x from hex 26 .upper() for x in s]), e.end
27 28 codecs.register_error('escapecss', _escapecss) 29 30
31 -class Preferences(object):
32 """ 33 controls output of CSSSerializer 34 35 defaultAtKeyword = True 36 Should the literal @keyword from src CSS be used or the default 37 form, e.g. if ``True``: ``@import`` else: ``@i\mport`` 38 defaultPropertyName = True 39 Should the normalized propertyname be used or the one given in 40 the src file, e.g. if ``True``: ``color`` else: ``c\olor`` 41 42 Only used if ``keepAllProperties==False``. 43 44 importHrefFormat = None 45 Uses hreftype if ``None`` or explicit ``'string'`` or ``'uri'`` 46 indent = 4 * ' ' 47 Indentation of e.g Properties inside a CSSStyleDeclaration 48 indentSpecificities = False 49 Indent rules with subset of Selectors and higher Specitivity 50 51 keepAllProperties = True 52 If ``True`` all properties set in the original CSSStylesheet 53 are kept meaning even properties set twice with the exact same 54 same name are kept! 55 56 defaultAtKeyword=%r, 57 defaultPropertyName=%r, 58 importHrefFormat=%r, 59 indent=%r, 60 keepAllProperties=%r, 61 keepComments=%r, 62 keepEmptyRules=%r, 63 lineNumbers=%r, 64 lineSeparator=%r, 65 listItemSpacer=%r, 66 omitLastSemicolon=%r, 67 paranthesisSpacer=%r, 68 propertyNameSpacer=%r, 69 validOnly=%r, 70 wellformedOnly=%r, 71 72 73 keepComments = True 74 If ``False`` removes all CSSComments 75 keepEmptyRules = False 76 defines if empty rules like e.g. ``a {}`` are kept in the resulting 77 serialized sheet 78 79 lineNumbers = False 80 Only used if a complete CSSStyleSheet is serialized. 81 lineSeparator = u'\\n' 82 How to end a line. This may be set to e.g. u'' for serializing of 83 CSSStyleDeclarations usable in HTML style attribute. 84 listItemSpacer = u' ' 85 string which is used in ``css.SelectorList``, ``css.CSSValue`` and 86 ``stylesheets.MediaList`` after the comma 87 omitLastSemicolon = True 88 If ``True`` omits ; after last property of CSSStyleDeclaration 89 paranthesisSpacer = u' ' 90 string which is used before an opening paranthesis like in a 91 ``css.CSSMediaRule`` or ``css.CSSStyleRule`` 92 propertyNameSpacer = u' ' 93 string which is used after a Property name colon 94 95 validOnly = False (**not anywhere used yet**) 96 if True only valid (Properties or Rules) are kept 97 98 A Property is valid if it is a known Property with a valid value. 99 Currently CSS 2.1 values as defined in cssproperties.py would be 100 valid. 101 102 wellformedOnly = True (**not anywhere used yet**) 103 only wellformed properties and rules are kept 104 105 **DEPRECATED**: removeInvalid = True 106 Omits invalid rules, replaced by ``validOnly`` which will be used 107 more cases 108 109 """
110 - def __init__(self, **initials):
111 """ 112 Always use named instead of positional parameters 113 """ 114 self.useDefaults() 115 116 for key, value in initials.items(): 117 if value: 118 self.__setattr__(key, value)
119
120 - def useDefaults(self):
121 "reset all preference options to the default value" 122 self.defaultAtKeyword = True 123 self.defaultPropertyName = True 124 self.importHrefFormat = None 125 self.indent = 4 * u' ' 126 self.indentSpecificities = False 127 self.keepAllProperties = True 128 self.keepComments = True 129 self.keepEmptyRules = False 130 self.lineNumbers = False 131 self.lineSeparator = u'\n' 132 self.listItemSpacer = u' ' 133 self.omitLastSemicolon = True 134 self.paranthesisSpacer = u' ' 135 self.propertyNameSpacer = u' ' 136 self.validOnly = False 137 self.wellformedOnly = True 138 # DEPRECATED 139 self.removeInvalid = True
140
141 - def useMinified(self):
142 """ 143 sets options to achive a minified stylesheet 144 145 you may want to set preferences with this convinience method 146 and set settings you want adjusted afterwards 147 """ 148 self.importHrefFormat = 'string' 149 self.indent = u'' 150 self.keepComments = False 151 self.keepEmptyRules = False 152 self.lineNumbers = False 153 self.lineSeparator = u'' 154 self.listItemSpacer = u'' 155 self.omitLastSemicolon = True 156 self.paranthesisSpacer = u'' 157 self.propertyNameSpacer = u'' 158 self.validOnly = False 159 self.wellformedOnly = True
160
161 - def __repr__(self):
162 return u"cssutils.css.%s(%s)" % (self.__class__.__name__, 163 u', '.join(['\n %s=%r' % (p, self.__getattribute__(p)) for p in self.__dict__] 164 ))
165
166 - def __str__(self):
167 return u"<cssutils.css.%s object %s at 0x%x" % (self.__class__.__name__, 168 u' '.join(['%s=%r' % (p, self.__getattribute__(p)) for p in self.__dict__] 169 ), 170 id(self))
171 172
173 -class CSSSerializer(object):
174 """ 175 Methods to serialize a CSSStylesheet and its parts 176 177 To use your own serializing method the easiest is to subclass CSS 178 Serializer and overwrite the methods you like to customize. 179 """ 180 __notinurimatcher = re.compile(ur'''.*?[\)\s\;]''', re.U).match 181 # chars not in URI without quotes around 182
183 - def __init__(self, prefs=None):
184 """ 185 prefs 186 instance of Preferences 187 """ 188 if not prefs: 189 prefs = Preferences() 190 self.prefs = prefs 191 self._level = 0 # current nesting level 192 193 self._selectors = [] # holds SelectorList 194 self._selectorlevel = 0 # current specificity nesting level
195
196 - def _serialize(self, text):
197 if self.prefs.lineNumbers: 198 pad = len(str(text.count(self.prefs.lineSeparator)+1)) 199 out = [] 200 for i, line in enumerate(text.split(self.prefs.lineSeparator)): 201 out.append((u'%*i: %s') % (pad, i+1, line)) 202 text = self.prefs.lineSeparator.join(out) 203 return text
204
205 - def _noinvalids(self, x):
206 # DEPRECATED: REMOVE! 207 if self.prefs.removeInvalid and \ 208 hasattr(x, 'valid') and not x.valid: 209 return True 210 else: 211 return False
212
213 - def _valid(self, x):
214 """ 215 checks if valid items only and if yes it item is valid 216 """ 217 return not self.prefs.validOnly or (self.prefs.validOnly and 218 hasattr(x, 'valid') and 219 x.valid)
220
221 - def _wellformed(self, x):
222 """ 223 checks if wellformed items only and if yes it item is wellformed 224 """ 225 return self.prefs.wellformedOnly and hasattr(x, 'wellformed') and\ 226 x.wellformed
227
228 - def _escapestring(self, s, delim=u'"'):
229 """ 230 escapes delim charaters in string s with \delim 231 s might not have " or ' around it! 232 233 escape line breaks \n \r and \f 234 """ 235 # \n = 0xa, \r = 0xd, \f = 0xc 236 s = s.replace('\n', '\\a ').replace( 237 '\r', '\\d ').replace( 238 '\f', '\\c ') 239 return s.replace(delim, u'\\%s' % delim)
240
241 - def _escapeSTRINGtype(self, s):
242 """ 243 escapes unescaped ", ' or \n in s if not escaped already 244 s always has "..." or '...' around 245 """ 246 r = s[0] 247 out = [r] 248 for c in s[1:-1]: 249 if c == '\n': # = 0xa 250 out.append(u'\\a ') 251 continue 252 elif c == '\r': # = 0xd 253 out.append(u'\\d ') 254 continue 255 elif c == '\f': # = 0xc 256 out.append(u'\\c ') 257 continue 258 elif c == r and out[-1] != u'\\': 259 out.append(u'\\') # + c 260 out.append(c) 261 out.append(r) 262 s = u''.join(out) 263 return s
264
265 - def _getatkeyword(self, rule, default):
266 """ 267 used by all @rules to get the keyword used 268 dependent on prefs setting defaultAtKeyword 269 """ 270 if self.prefs.defaultAtKeyword: 271 return default 272 else: 273 return rule.atkeyword
274
275 - def _getpropertyname(self, property, actual):
276 """ 277 used by all styledeclarations to get the propertyname used 278 dependent on prefs setting defaultPropertyName 279 """ 280 if self.prefs.defaultPropertyName and \ 281 not self.prefs.keepAllProperties: 282 return property.name 283 else: 284 return actual
285
286 - def _indentblock(self, text, level):
287 """ 288 indent a block like a CSSStyleDeclaration to the given level 289 which may be higher than self._level (e.g. for CSSStyleDeclaration) 290 """ 291 if not self.prefs.lineSeparator: 292 return text 293 return self.prefs.lineSeparator.join( 294 [u'%s%s' % (level * self.prefs.indent, line) 295 for line in text.split(self.prefs.lineSeparator)] 296 )
297
298 - def _uri(self, uri):
299 """ 300 returns uri enclosed in " if necessary 301 """ 302 if CSSSerializer.__notinurimatcher(uri): 303 return '"%s"' % self._escapestring(uri, '"') 304 else: 305 return uri
306
307 - def do_stylesheets_mediaquery(self, mediaquery):
308 """ 309 a single media used in medialist 310 """ 311 if len(mediaquery.seq) == 0: 312 return u'' 313 else: 314 out = [] 315 for part in mediaquery.seq: 316 if isinstance(part, cssutils.css.Property): # Property 317 out.append(u'(%s)' % part.cssText) 318 elif hasattr(part, 'cssText'): # comments 319 out.append(part.cssText) 320 else: 321 # TODO: media queries! 322 out.append(part) 323 return u' '.join(out)
324
325 - def do_stylesheets_medialist(self, medialist):
326 """ 327 comma-separated list of media, default is 'all' 328 329 If "all" is in the list, every other media *except* "handheld" will 330 be stripped. This is because how Opera handles CSS for PDAs. 331 """ 332 if len(medialist) == 0: 333 return u'all' 334 else: 335 sep = u',%s' % self.prefs.listItemSpacer 336 return sep.join( 337 (mq.mediaText for mq in medialist))
338
339 - def do_CSSStyleSheet(self, stylesheet):
340 out = [] 341 for rule in stylesheet.cssRules: 342 cssText = rule.cssText 343 if cssText: 344 out.append(cssText) 345 text = self._serialize(self.prefs.lineSeparator.join(out)) 346 347 # get encoding of sheet, defaults to UTF-8 348 try: 349 encoding = stylesheet.cssRules[0].encoding 350 except (IndexError, AttributeError): 351 encoding = 'UTF-8' 352 353 return text.encode(encoding, 'escapecss')
354
355 - def do_CSSComment(self, rule):
356 """ 357 serializes CSSComment which consists only of commentText 358 """ 359 if self.prefs.keepComments and rule._cssText: 360 return rule._cssText 361 else: 362 return u''
363
364 - def do_CSSCharsetRule(self, rule):
365 """ 366 serializes CSSCharsetRule 367 encoding: string 368 369 always @charset "encoding"; 370 no comments or other things allowed! 371 """ 372 if not rule.encoding or self._noinvalids(rule): 373 return u'' 374 return u'@charset "%s";' % self._escapestring(rule.encoding)
375
376 - def do_CSSFontFaceRule(self, rule):
377 """ 378 serializes CSSFontFaceRule 379 380 style 381 CSSStyleDeclaration 382 383 + CSSComments 384 """ 385 self._level += 1 386 try: 387 styleText = self.do_css_CSSStyleDeclaration(rule.style) 388 finally: 389 self._level -= 1 390 391 if not styleText or self._noinvalids(rule): 392 return u'' 393 394 before = [] 395 for x in rule.seq: 396 if hasattr(x, 'cssText'): 397 before.append(x.cssText) 398 else: 399 # TODO: resolve 400 raise SyntaxErr('serializing CSSFontFaceRule: unexpected %r' % x) 401 if before: 402 before = u' '.join(before).strip() 403 if before: 404 before = u' %s' % before 405 else: 406 before = u'' 407 408 return u'%s%s {%s%s%s%s}' % ( 409 self._getatkeyword(rule, u'@font-face'), 410 before, 411 self.prefs.lineSeparator, 412 self._indentblock(styleText, self._level + 1), 413 self.prefs.lineSeparator, 414 (self._level + 1) * self.prefs.indent 415 )
416
417 - def do_CSSImportRule(self, rule):
418 """ 419 serializes CSSImportRule 420 421 href 422 string 423 hreftype 424 'uri' or 'string' 425 media 426 cssutils.stylesheets.medialist.MediaList 427 428 + CSSComments 429 """ 430 if not rule.href or self._noinvalids(rule): 431 return u'' 432 out = [u'%s ' % self._getatkeyword(rule, u'@import')] 433 for part in rule.seq: 434 if rule.href == part: 435 if self.prefs.importHrefFormat == 'uri': 436 out.append(u'url(%s)' % self._uri(part)) 437 elif self.prefs.importHrefFormat == 'string' or \ 438 rule.hreftype == 'string': 439 out.append(u'"%s"' % self._escapestring(part)) 440 else: 441 out.append(u'url(%s)' % self._uri(part)) 442 elif isinstance( 443 part, cssutils.stylesheets.medialist.MediaList): 444 mediaText = self.do_stylesheets_medialist(part)#.strip() 445 if mediaText and not mediaText == u'all': 446 out.append(u' %s' % mediaText) 447 elif hasattr(part, 'cssText'): # comments 448 out.append(part.cssText) 449 return u'%s;' % u''.join(out)
450
451 - def do_CSSNamespaceRule(self, rule):
452 """ 453 serializes CSSNamespaceRule 454 455 uri 456 string 457 prefix 458 string 459 460 + CSSComments 461 """ 462 if not rule.namespaceURI or self._noinvalids(rule): 463 return u'' 464 465 out = [u'%s' % self._getatkeyword(rule, u'@namespace')] 466 for part in rule.seq: 467 if rule.prefix == part and part != u'': 468 out.append(u' %s' % part) 469 elif rule.namespaceURI == part: 470 out.append(u' "%s"' % self._escapestring(part)) 471 elif hasattr(part, 'cssText'): # comments 472 out.append(part.cssText) 473 return u'%s;' % u''.join(out)
474
475 - def do_CSSMediaRule(self, rule):
476 """ 477 serializes CSSMediaRule 478 479 + CSSComments 480 """ 481 # reset selectorindent 482 self._selectors = [] 483 self._selectorlevel = 0 484 485 rulesout = [] 486 for r in rule.cssRules: 487 rtext = r.cssText 488 if rtext: 489 # indent each line of cssText 490 rulesout.append(self._indentblock(rtext, self._level + 1)) 491 rulesout.append(self.prefs.lineSeparator) 492 493 if not self.prefs.keepEmptyRules and not u''.join(rulesout).strip() or\ 494 self._noinvalids(rule.media): 495 return u'' 496 497 # if len(rule.cssRules) == 0 and not self.prefs.keepEmptyRules or\ 498 # self._noinvalids(rule.media): 499 # return u'' 500 mediaText = self.do_stylesheets_medialist(rule.media)#.strip() 501 out = [u'%s %s%s{%s' % (self._getatkeyword(rule, u'@media'), 502 mediaText, 503 self.prefs.paranthesisSpacer, 504 self.prefs.lineSeparator)] 505 out.extend(rulesout) 506 return u'%s%s}' % (u''.join(out), 507 (self._level + 1) * self.prefs.indent)
508
509 - def do_CSSPageRule(self, rule):
510 """ 511 serializes CSSPageRule 512 513 selectorText 514 string 515 style 516 CSSStyleDeclaration 517 518 + CSSComments 519 """ 520 self._level += 1 521 try: 522 styleText = self.do_css_CSSStyleDeclaration(rule.style) 523 finally: 524 self._level -= 1 525 526 if not styleText or self._noinvalids(rule): 527 return u'' 528 529 return u'%s%s {%s%s%s%s}' % ( 530 self._getatkeyword(rule, u'@page'), 531 self.do_pageselector(rule.seq), 532 self.prefs.lineSeparator, 533 self._indentblock(styleText, self._level + 1), 534 self.prefs.lineSeparator, 535 (self._level + 1) * self.prefs.indent 536 )
537
538 - def do_pageselector(self, seq):
539 """ 540 a selector of a CSSPageRule including comments 541 """ 542 if len(seq) == 0 or self._noinvalids(seq): 543 return u'' 544 else: 545 out = [] 546 for part in seq: 547 if hasattr(part, 'cssText'): 548 out.append(part.cssText) 549 else: 550 out.append(part) 551 return u' %s' % u''.join(out)
552
553 - def do_CSSUnknownRule(self, rule):
554 """ 555 serializes CSSUnknownRule 556 anything until ";" or "{...}" 557 + CSSComments 558 """ 559 if rule.atkeyword and not self._noinvalids(rule): 560 out = [u'%s' % rule.atkeyword] 561 for part in rule.seq: 562 if isinstance(part, cssutils.css.csscomment.CSSComment): 563 if self.prefs.keepComments: 564 out.append(part.cssText) 565 else: 566 out.append(part) 567 if not (out[-1].endswith(u';') or out[-1].endswith(u'}')): 568 out.append(u';') 569 return u''.join(out) 570 else: 571 return u''
572
573 - def do_CSSStyleRule(self, rule):
574 """ 575 serializes CSSStyleRule 576 577 selectorList 578 style 579 580 + CSSComments 581 """ 582 # prepare for element nested rules 583 # TODO: sort selectors! 584 if self.prefs.indentSpecificities: 585 # subselectorlist? 586 elements = set([s.element for s in rule.selectorList]) 587 specitivities = [s.specificity for s in rule.selectorList] 588 for selector in self._selectors: 589 lastelements = set([s.element for s in selector]) 590 if elements.issubset(lastelements): 591 # higher specificity? 592 lastspecitivities = [s.specificity for s in selector] 593 if specitivities > lastspecitivities: 594 self._selectorlevel += 1 595 break 596 elif self._selectorlevel > 0: 597 self._selectorlevel -= 1 598 else: 599 # save new reference 600 self._selectors.append(rule.selectorList) 601 self._selectorlevel = 0 602 603 # TODO ^ RESOLVE!!!! 604 605 selectorText = self.do_css_SelectorList(rule.selectorList) 606 if not selectorText or self._noinvalids(rule): 607 return u'' 608 self._level += 1 609 styleText = u'' 610 try: 611 styleText = self.do_css_CSSStyleDeclaration(rule.style) 612 finally: 613 self._level -= 1 614 if not styleText: 615 if self.prefs.keepEmptyRules: 616 return u'%s%s{}' % (selectorText, 617 self.prefs.paranthesisSpacer) 618 else: 619 return self._indentblock( 620 u'%s%s{%s%s%s%s}' % ( 621 selectorText, 622 self.prefs.paranthesisSpacer, 623 self.prefs.lineSeparator, 624 self._indentblock(styleText, self._level + 1), 625 self.prefs.lineSeparator, 626 (self._level + 1) * self.prefs.indent), 627 self._selectorlevel)
628
629 - def do_css_SelectorList(self, selectorlist):
630 """ 631 comma-separated list of Selectors 632 """ 633 if selectorlist.seq and self._wellformed(selectorlist) and\ 634 self._valid(selectorlist): 635 out = [] 636 sep = u',%s' % self.prefs.listItemSpacer 637 for part in selectorlist.seq: 638 if hasattr(part, 'cssText'): 639 out.append(part.cssText) 640 # elif u',' == part: 641 # out.append(sep) 642 elif isinstance(part, cssutils.css.Selector): 643 out.append(self.do_css_Selector(part)) 644 else: 645 out.append(part) # ? 646 return sep.join(out) 647 else: 648 return u''
649
650 - def _getprefix(self, namespaces, namespaceURI):
651 """ 652 returns prefix of given nsuri as defined in given 653 dict (prefix: uri} or TODO: from CSSNamespaceRules? 654 """ 655 if namespaceURI is None: 656 return u'*' 657 for prefix, uri in namespaces.items(): 658 if uri == namespaceURI: 659 return prefix 660 return u'' # should not happen!
661
662 - def do_css_Selector(self, selector):
663 """ 664 a single Selector including comments 665 """ 666 if selector.seq and self._wellformed(selector) and\ 667 self._valid(selector): 668 out = [] 669 for item in selector.seq: 670 typ, val = item.type, item.value 671 if hasattr(val, 'cssText'): 672 # e.g. comment 673 out.append(val.cssText) 674 elif type(val) == tuple: 675 # TODO: CHECK IF THIS IS REALLY OK! 676 namespaceURI, name = val 677 # namespaceURI | name (name or att) 678 if namespaceURI != u'': 679 # namespace may be None 680 out.append(u'%s|%s' % (self._getprefix(selector.namespaces, 681 namespaceURI), 682 name)) 683 else: 684 out.append(u'%s' % name) 685 elif type(val) == dict: # OLD??? 686 out.append(val['value']) 687 else: 688 if typ == 'string': 689 val = self._escapeSTRINGtype(val) 690 out.append(val) 691 return u''.join(out) 692 else: 693 return u''
694
695 - def do_css_CSSStyleDeclaration(self, style, separator=None):
696 """ 697 Style declaration of CSSStyleRule 698 """ 699 if len(style.seq) > 0 and self._wellformed(style) and\ 700 self._valid(style): 701 if separator is None: 702 separator = self.prefs.lineSeparator 703 704 if self.prefs.keepAllProperties: 705 # all 706 parts = style.seq 707 else: 708 # only effective ones 709 _effective = style.getProperties() 710 parts = [x for x in style.seq 711 if (isinstance(x, cssutils.css.Property) 712 and x in _effective) 713 or not isinstance(x, cssutils.css.Property)] 714 715 out = [] 716 for i, part in enumerate(parts): 717 if isinstance(part, cssutils.css.CSSComment): 718 # CSSComment 719 if self.prefs.keepComments: 720 out.append(part.cssText) 721 out.append(separator) 722 elif isinstance(part, cssutils.css.Property): 723 # PropertySimilarNameList 724 out.append(self.do_Property(part)) 725 if not (self.prefs.omitLastSemicolon and i==len(parts)-1): 726 out.append(u';') 727 out.append(separator) 728 else: 729 # other? 730 out.append(part) 731 732 if out and out[-1] == separator: 733 del out[-1] 734 735 return u''.join(out) 736 737 else: 738 return u''
739
740 - def do_Property(self, property):
741 """ 742 Style declaration of CSSStyleRule 743 744 Property has a seqs attribute which contains seq lists for 745 name, a CSSvalue and a seq list for priority 746 """ 747 out = [] 748 if property.seqs[0] and self._wellformed(property) and\ 749 self._valid(property): 750 nameseq, cssvalue, priorityseq = property.seqs 751 752 #name 753 for part in nameseq: 754 if hasattr(part, 'cssText'): 755 out.append(part.cssText) 756 elif property.literalname == part: 757 out.append(self._getpropertyname(property, part)) 758 else: 759 out.append(part) 760 761 if out and (not property._mediaQuery or 762 property._mediaQuery and cssvalue.cssText): 763 # MediaQuery may consist of name only 764 out.append(u':') 765 out.append(self.prefs.propertyNameSpacer) 766 767 # value 768 out.append(cssvalue.cssText) 769 770 # priority 771 if out and priorityseq: 772 out.append(u' ') 773 for part in priorityseq: 774 if hasattr(part, 'cssText'): # comments 775 out.append(part.cssText) 776 else: 777 out.append(part) 778 779 return u''.join(out)
780
781 - def do_Property_priority(self, priorityseq):
782 """ 783 a Properties priority "!" S* "important" 784 """ 785 out = [] 786 for part in priorityseq: 787 if hasattr(part, 'cssText'): # comments 788 out.append(u' ') 789 out.append(part.cssText) 790 out.append(u' ') 791 else: 792 out.append(part) 793 return u''.join(out).strip()
794
795 - def do_css_CSSValue(self, cssvalue):
796 """ 797 serializes a CSSValue 798 """ 799 if not cssvalue: 800 return u'' 801 else: 802 sep = u',%s' % self.prefs.listItemSpacer 803 out = [] 804 for part in cssvalue.seq: 805 if hasattr(part, 'cssText'): 806 # comments or CSSValue if a CSSValueList 807 out.append(part.cssText) 808 elif isinstance(part, basestring) and part == u',': 809 out.append(sep) 810 else: 811 # TODO: escape func parameter if STRING! 812 if part and part[0] == part[-1] and part[0] in '\'"': 813 part = self._escapeSTRINGtype(part) 814 out.append(part) 815 return (u''.join(out)).strip()
816