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