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