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-12 22:36:38 +0100 (Sa, 12 Jan 2008) $' 
 10  __version__ = '$LastChangedRevision: 833 $' 
 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 parts = style.seq 706 else: 707 # find distinct names 708 nnames = set() 709 for x in style.seq: 710 if isinstance(x, cssutils.css.Property): 711 nnames.add(x.name) 712 # filter list 713 parts = [] 714 for x in reversed(style.seq): 715 if isinstance(x, cssutils.css.Property): 716 if x.name in nnames: 717 parts.append(x) 718 nnames.remove(x.name) 719 else: 720 parts.append(x) 721 parts.reverse() 722 723 out = [] 724 for (i, part) in enumerate(parts): 725 if isinstance(part, cssutils.css.CSSComment): 726 # CSSComment 727 if self.prefs.keepComments: 728 out.append(part.cssText) 729 out.append(separator) 730 elif isinstance(part, cssutils.css.Property): 731 # PropertySimilarNameList 732 out.append(self.do_Property(part)) 733 if not (self.prefs.omitLastSemicolon and i==len(parts)-1): 734 out.append(u';') 735 out.append(separator) 736 else: 737 # other? 738 out.append(part) 739 740 if out and out[-1] == separator: 741 del out[-1] 742 743 return u''.join(out) 744 745 else: 746 return u''
747
748 - def do_Property(self, property):
749 """ 750 Style declaration of CSSStyleRule 751 752 Property has a seqs attribute which contains seq lists for 753 name, a CSSvalue and a seq list for priority 754 """ 755 out = [] 756 if property.seqs[0] and self._wellformed(property) and\ 757 self._valid(property): 758 nameseq, cssvalue, priorityseq = property.seqs 759 760 #name 761 for part in nameseq: 762 if hasattr(part, 'cssText'): 763 out.append(part.cssText) 764 elif property.literalname == part: 765 out.append(self._getpropertyname(property, part)) 766 else: 767 out.append(part) 768 769 if out and (not property._mediaQuery or 770 property._mediaQuery and cssvalue.cssText): 771 # MediaQuery may consist of name only 772 out.append(u':') 773 out.append(self.prefs.propertyNameSpacer) 774 775 # value 776 out.append(cssvalue.cssText) 777 778 # priority 779 if out and priorityseq: 780 out.append(u' ') 781 for part in priorityseq: 782 if hasattr(part, 'cssText'): # comments 783 out.append(part.cssText) 784 else: 785 out.append(part) 786 787 return u''.join(out)
788
789 - def do_Property_priority(self, priorityseq):
790 """ 791 a Properties priority "!" S* "important" 792 """ 793 out = [] 794 for part in priorityseq: 795 if hasattr(part, 'cssText'): # comments 796 out.append(u' ') 797 out.append(part.cssText) 798 out.append(u' ') 799 else: 800 out.append(part) 801 return u''.join(out).strip()
802
803 - def do_css_CSSValue(self, cssvalue):
804 """ 805 serializes a CSSValue 806 """ 807 if not cssvalue: 808 return u'' 809 else: 810 sep = u',%s' % self.prefs.listItemSpacer 811 out = [] 812 for part in cssvalue.seq: 813 if hasattr(part, 'cssText'): 814 # comments or CSSValue if a CSSValueList 815 out.append(part.cssText) 816 elif isinstance(part, basestring) and part == u',': 817 out.append(sep) 818 else: 819 # TODO: escape func parameter if STRING! 820 if part and part[0] == part[-1] and part[0] in '\'"': 821 part = self._escapeSTRINGtype(part) 822 out.append(part) 823 return (u''.join(out)).strip()
824