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 1116 2008-03-05 13:52:23Z 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 """ 174 Appends val. Adds a single S after each token except as follows: 175 176 - typ COMMENT 177 uses cssText depending on self.ser.prefs.keepComments 178 - typ cssutils.css.CSSRule.UNKNOWN_RULE 179 uses cssText 180 - typ STRING 181 escapes ser._string 182 - typ S 183 ignored except ``keepS=True`` 184 - typ URI 185 calls ser_uri 186 - val { 187 adds \n after 188 - val ; 189 removes S before and adds \n after 190 - val , : 191 removes S before 192 - val + > ~ 193 encloses in prefs.selectorCombinatorSpacer 194 - some other vals 195 add *spacer except ``space=False`` 196 """ 197 if val or 'STRING' == typ: 198 # PRE 199 if 'COMMENT' == typ: 200 if self.ser.prefs.keepComments: 201 val = val.cssText 202 else: 203 return 204 elif cssutils.css.CSSRule.UNKNOWN_RULE == typ: 205 val = val.cssText 206 elif 'S' == typ and not keepS: 207 return 208 elif 'STRING' == typ: 209 # may be empty but MUST not be None 210 if val is None: 211 return 212 val = self.ser._string(val) 213 elif 'URI' == typ: 214 val = self.ser._uri(val) 215 elif val in u'+>~,:{;)]': 216 self._remove_last_if_S() 217 218 # APPEND 219 if indent: 220 self.out.append(self.ser._indentblock(val, self.ser._level+1)) 221 else: 222 self.out.append(val) 223 224 # POST 225 if val in u'+>~': # enclose selector combinator 226 self.out.insert(-1, self.ser.prefs.selectorCombinatorSpacer) 227 self.out.append(self.ser.prefs.selectorCombinatorSpacer) 228 elif u',' == val: # list 229 self.out.append(self.ser.prefs.listItemSpacer) 230 elif u':' == val: # prop 231 self.out.append(self.ser.prefs.propertyNameSpacer) 232 elif u'{' == val: # block start 233 self.out.insert(-1, self.ser.prefs.paranthesisSpacer) 234 self.out.append(self.ser.prefs.lineSeparator) 235 elif u';' == val: # end or prop or block 236 self.out.append(self.ser.prefs.lineSeparator) 237 elif val not in u'}[]()' and space: 238 self.out.append(self.ser.prefs.spacer)
239
240 - def value(self, delim=u'', end=None):
241 "returns all items joined by delim" 242 self._remove_last_if_S() 243 if end: 244 self.out.append(end) 245 return delim.join(self.out)
246 247
248 -class CSSSerializer(object):
249 """ 250 Methods to serialize a CSSStylesheet and its parts 251 252 To use your own serializing method the easiest is to subclass CSS 253 Serializer and overwrite the methods you like to customize. 254 """ 255 # chars not in URI without quotes around 256 __forbidden_in_uri_matcher = re.compile(ur'''.*?[\)\s\;]''', re.U).match 257
258 - def __init__(self, prefs=None):
259 """ 260 prefs 261 instance of Preferences 262 """ 263 if not prefs: 264 prefs = Preferences() 265 self.prefs = prefs 266 self._level = 0 # current nesting level 267 268 # TODO: 269 self._selectors = [] # holds SelectorList 270 self._selectorlevel = 0 # current specificity nesting level
271
272 - def _atkeyword(self, rule, default):
273 "returns default or source atkeyword depending on prefs" 274 if self.prefs.defaultAtKeyword: 275 return default 276 else: 277 return rule.atkeyword
278
279 - def _indentblock(self, text, level):
280 """ 281 indent a block like a CSSStyleDeclaration to the given level 282 which may be higher than self._level (e.g. for CSSStyleDeclaration) 283 """ 284 if not self.prefs.lineSeparator: 285 return text 286 return self.prefs.lineSeparator.join( 287 [u'%s%s' % (level * self.prefs.indent, line) 288 for line in text.split(self.prefs.lineSeparator)] 289 )
290
291 - def _propertyname(self, property, actual):
292 """ 293 used by all styledeclarations to get the propertyname used 294 dependent on prefs setting defaultPropertyName and 295 keepAllProperties 296 """ 297 if self.prefs.defaultPropertyName and not self.prefs.keepAllProperties: 298 return property.name 299 else: 300 return actual
301
302 - def _linenumnbers(self, text):
303 if self.prefs.lineNumbers: 304 pad = len(str(text.count(self.prefs.lineSeparator)+1)) 305 out = [] 306 for i, line in enumerate(text.split(self.prefs.lineSeparator)): 307 out.append((u'%*i: %s') % (pad, i+1, line)) 308 text = self.prefs.lineSeparator.join(out) 309 return text
310
311 - def _string(self, s):
312 """ 313 returns s encloded between "..." and escaped delim charater ", 314 escape line breaks \\n \\r and \\f 315 """ 316 # \n = 0xa, \r = 0xd, \f = 0xc 317 s = s.replace('\n', '\\a ').replace( 318 '\r', '\\d ').replace( 319 '\f', '\\c ') 320 return u'"%s"' % s.replace('"', u'\\"')
321
322 - def _uri(self, uri):
323 """returns uri enclosed in url() and "..." if necessary""" 324 if CSSSerializer.__forbidden_in_uri_matcher(uri): 325 return 'url(%s)' % self._string(uri) 326 else: 327 return 'url(%s)' % uri
328
329 - def _valid(self, x):
330 "checks items valid property and prefs.validOnly" 331 return not self.prefs.validOnly or (self.prefs.validOnly and 332 x.valid)
333
334 - def do_CSSStyleSheet(self, stylesheet):
335 """serializes a complete CSSStyleSheet""" 336 useduris = stylesheet._getUsedURIs() 337 out = [] 338 for rule in stylesheet.cssRules: 339 if self.prefs.keepUsedNamespaceRulesOnly and\ 340 rule.NAMESPACE_RULE == rule.type and\ 341 rule.namespaceURI not in useduris and ( 342 rule.prefix or None not in useduris): 343 continue 344 345 cssText = rule.cssText 346 if cssText: 347 out.append(cssText) 348 text = self._linenumnbers(self.prefs.lineSeparator.join(out)) 349 350 # get encoding of sheet, defaults to UTF-8 351 try: 352 encoding = stylesheet.cssRules[0].encoding 353 except (IndexError, AttributeError): 354 encoding = 'UTF-8' 355 356 return text.encode(encoding, 'escapecss')
357
358 - def do_CSSComment(self, rule):
359 """ 360 serializes CSSComment which consists only of commentText 361 """ 362 # no need to use Out() as too simple 363 if rule._cssText and self.prefs.keepComments: 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 # no need to use Out() as too simple 377 if rule.wellformed: 378 return u'@charset %s;' % self._string(rule.encoding) 379 else: 380 return u''
381
382 - def do_CSSFontFaceRule(self, rule):
383 """ 384 serializes CSSFontFaceRule 385 386 style 387 CSSStyleDeclaration 388 389 + CSSComments 390 """ 391 styleText = self.do_css_CSSStyleDeclaration(rule.style) 392 393 if styleText and rule.wellformed: 394 out = Out(self) 395 out.append(self._atkeyword(rule, u'@font-face')) 396 for item in rule.seq: 397 # assume comments { 398 out.append(item.value, item.type) 399 out.append(u'{') 400 out.append(u'%s%s}' % (styleText, self.prefs.lineSeparator), 401 indent=1) 402 return out.value() 403 else: 404 return u''
405
406 - def do_CSSImportRule(self, rule):
407 """ 408 serializes CSSImportRule 409 410 href 411 string 412 media 413 optional cssutils.stylesheets.medialist.MediaList 414 name 415 optional string 416 417 + CSSComments 418 """ 419 if rule.wellformed: 420 out = Out(self) 421 out.append(self._atkeyword(rule, u'@import')) 422 423 for item in rule.seq: 424 typ, val = item.type, item.value 425 if 'href' == typ: 426 # "href" or url(href) 427 if self.prefs.importHrefFormat == 'string' or ( 428 self.prefs.importHrefFormat != 'uri' and 429 rule.hreftype == 'string'): 430 out.append(val, 'STRING') 431 else: 432 out.append(val, 'URI') 433 elif 'media' == typ: 434 # media 435 mediaText = self.do_stylesheets_medialist(val) 436 if mediaText and mediaText != u'all': 437 out.append(mediaText) 438 elif 'name' == typ: 439 out.append(val, 'STRING') 440 else: 441 out.append(val, typ) 442 443 return out.value(end=u';') 444 else: 445 return u''
446
447 - def do_CSSNamespaceRule(self, rule):
448 """ 449 serializes CSSNamespaceRule 450 451 uri 452 string 453 prefix 454 string 455 456 + CSSComments 457 """ 458 if rule.wellformed: 459 out = Out(self) 460 out.append(self._atkeyword(rule, u'@namespace')) 461 462 for item in rule.seq: 463 typ, val = item.type, item.value 464 if 'namespaceURI' == typ: 465 out.append(val, 'STRING') 466 else: 467 out.append(val, typ) 468 469 return out.value(end=u';') 470 else: 471 return u''
472
473 - def do_CSSMediaRule(self, rule):
474 """ 475 serializes CSSMediaRule 476 477 + CSSComments 478 """ 479 # TODO: use Out()? 480 481 # @media 482 out = [self._atkeyword(rule, u'@media')] 483 out.append(self.prefs.spacer) # might be empty 484 485 # mediaquery 486 if not rule.media.wellformed: 487 return u'' 488 out.append(self.do_stylesheets_medialist(rule.media)) 489 490 # name, seq contains content after name only (Comments) 491 if rule.name: 492 out.append(self.prefs.spacer) 493 nameout = Out(self) 494 nameout.append(self._string(rule.name)) 495 for item in rule.seq: 496 nameout.append(item.value, item.type) 497 out.append(nameout.value()) 498 499 # { 500 out.append(self.prefs.paranthesisSpacer) 501 out.append(u'{') 502 out.append(self.prefs.lineSeparator) 503 504 # rules 505 rulesout = [] 506 for r in rule.cssRules: 507 rtext = r.cssText 508 if rtext: 509 # indent each line of cssText 510 rulesout.append(self._indentblock(rtext, self._level + 1)) 511 rulesout.append(self.prefs.lineSeparator) 512 if not self.prefs.keepEmptyRules and not u''.join(rulesout).strip(): 513 return u'' 514 out.extend(rulesout) 515 516 # } 517 out.append(u'%s}' % ((self._level + 1) * self.prefs.indent)) 518 519 return u''.join(out)
520
521 - def do_CSSPageRule(self, rule):
522 """ 523 serializes CSSPageRule 524 525 selectorText 526 string 527 style 528 CSSStyleDeclaration 529 530 + CSSComments 531 """ 532 styleText = self.do_css_CSSStyleDeclaration(rule.style) 533 534 if styleText and rule.wellformed: 535 out = Out(self) 536 out.append(self._atkeyword(rule, u'@page')) 537 538 for item in rule.seq: 539 out.append(item.value, item.type) 540 541 out.append(u'{') 542 out.append(u'%s%s}' % (styleText, self.prefs.lineSeparator), 543 indent=1) 544 return out.value() 545 else: 546 return u''
547
548 - def do_CSSUnknownRule(self, rule):
549 """ 550 serializes CSSUnknownRule 551 anything until ";" or "{...}" 552 + CSSComments 553 """ 554 if rule.wellformed: 555 out = Out(self) 556 out.append(rule.atkeyword) 557 stacks = [] 558 for item in rule.seq: 559 typ, val = item.type, item.value 560 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 # APPEND 570 if stacks: 571 stacks[-1].append(val, typ) 572 else: 573 out.append(val, typ) 574 575 # POST 576 if u'{' == val: 577 # new stack level 578 stacks.append(Out(self)) 579 580 return out.value() 581 else: 582 return u''
583
584 - def do_CSSStyleRule(self, rule):
585 """ 586 serializes CSSStyleRule 587 588 selectorList 589 style 590 591 + CSSComments 592 """ 593 # TODO: use Out() 594 595 # prepare for element nested rules 596 # TODO: sort selectors! 597 if self.prefs.indentSpecificities: 598 # subselectorlist? 599 elements = set([s.element for s in rule.selectorList]) 600 specitivities = [s.specificity for s in rule.selectorList] 601 for selector in self._selectors: 602 lastelements = set([s.element for s in selector]) 603 if elements.issubset(lastelements): 604 # higher specificity? 605 lastspecitivities = [s.specificity for s in selector] 606 if specitivities > lastspecitivities: 607 self._selectorlevel += 1 608 break 609 elif self._selectorlevel > 0: 610 self._selectorlevel -= 1 611 else: 612 # save new reference 613 self._selectors.append(rule.selectorList) 614 self._selectorlevel = 0 615 616 # TODO ^ RESOLVE!!!! 617 618 selectorText = self.do_css_SelectorList(rule.selectorList) 619 if not selectorText or not rule.wellformed: 620 return u'' 621 self._level += 1 622 styleText = u'' 623 try: 624 styleText = self.do_css_CSSStyleDeclaration(rule.style) 625 finally: 626 self._level -= 1 627 if not styleText: 628 if self.prefs.keepEmptyRules: 629 return u'%s%s{}' % (selectorText, 630 self.prefs.paranthesisSpacer) 631 else: 632 return self._indentblock( 633 u'%s%s{%s%s%s%s}' % ( 634 selectorText, 635 self.prefs.paranthesisSpacer, 636 self.prefs.lineSeparator, 637 self._indentblock(styleText, self._level + 1), 638 self.prefs.lineSeparator, 639 (self._level + 1) * self.prefs.indent), 640 self._selectorlevel)
641
642 - def do_css_SelectorList(self, selectorlist):
643 "comma-separated list of Selectors" 644 # does not need Out() as it is too simple 645 if selectorlist.wellformed: 646 out = [] 647 for part in selectorlist.seq: 648 if isinstance(part, cssutils.css.Selector): 649 out.append(part.selectorText) 650 else: 651 out.append(part) # should not happen 652 sep = u',%s' % self.prefs.listItemSpacer 653 return sep.join(out) 654 else: 655 return u''
656
657 - def do_css_Selector(self, selector):
658 """ 659 a single Selector including comments 660 661 an element has syntax (namespaceURI, name) where namespaceURI may be: 662 663 - cssutils._ANYNS => ``*|name`` 664 - None => ``name`` 665 - u'' => ``|name`` 666 - any other value: => ``prefix|name`` 667 """ 668 if selector.wellformed: 669 out = Out(self) 670 671 DEFAULTURI = selector._namespaces.get('', None) 672 for item in selector.seq: 673 typ, val = item.type, item.value 674 if type(val) == tuple: 675 # namespaceURI|name (element or attribute) 676 namespaceURI, name = val 677 if DEFAULTURI == namespaceURI or (not DEFAULTURI and 678 namespaceURI is None): 679 out.append(name, typ, space=False) 680 else: 681 if namespaceURI == cssutils._ANYNS: 682 prefix = u'*' 683 else: 684 try: 685 prefix = selector._namespaces.prefixForNamespaceURI( 686 namespaceURI) 687 except IndexError: 688 prefix = u'' 689 690 out.append(u'%s|%s' % (prefix, name), typ, space=False) 691 else: 692 out.append(val, typ, space=False, keepS=True) 693 694 return out.value() 695 else: 696 return u''
697
698 - def do_css_CSSStyleDeclaration(self, style, separator=None):
699 """ 700 Style declaration of CSSStyleRule 701 """ 702 # TODO: use Out() 703 704 # may be comments only 705 if len(style.seq) > 0: 706 if separator is None: 707 separator = self.prefs.lineSeparator 708 709 if self.prefs.keepAllProperties: 710 # all 711 parts = style.seq 712 else: 713 # only effective ones 714 _effective = style.getProperties() 715 parts = [x for x in style.seq 716 if (isinstance(x, cssutils.css.Property) 717 and x in _effective) 718 or not isinstance(x, cssutils.css.Property)] 719 720 out = [] 721 for i, part in enumerate(parts): 722 if isinstance(part, cssutils.css.CSSComment): 723 # CSSComment 724 if self.prefs.keepComments: 725 out.append(part.cssText) 726 out.append(separator) 727 elif isinstance(part, cssutils.css.Property): 728 # PropertySimilarNameList 729 out.append(self.do_Property(part)) 730 if not (self.prefs.omitLastSemicolon and i==len(parts)-1): 731 out.append(u';') 732 out.append(separator) 733 else: 734 # other? 735 out.append(part) 736 737 if out and out[-1] == separator: 738 del out[-1] 739 740 return u''.join(out) 741 742 else: 743 return u''
744
745 - def do_Property(self, property):
746 """ 747 Style declaration of CSSStyleRule 748 749 Property has a seqs attribute which contains seq lists for 750 name, a CSSvalue and a seq list for priority 751 """ 752 # TODO: use Out() 753 754 out = [] 755 if property.seqs[0] and property.wellformed and self._valid(property): 756 nameseq, cssvalue, priorityseq = property.seqs 757 758 #name 759 for part in nameseq: 760 if hasattr(part, 'cssText'): 761 out.append(part.cssText) 762 elif property.literalname == part: 763 out.append(self._propertyname(property, part)) 764 else: 765 out.append(part) 766 767 if out and (not property._mediaQuery or 768 property._mediaQuery and cssvalue.cssText): 769 # MediaQuery may consist of name only 770 out.append(u':') 771 out.append(self.prefs.propertyNameSpacer) 772 773 # value 774 out.append(cssvalue.cssText) 775 776 # priority 777 if out and priorityseq: 778 out.append(u' ') 779 for part in priorityseq: 780 if hasattr(part, 'cssText'): # comments 781 out.append(part.cssText) 782 else: 783 if part == property.literalpriority and\ 784 self.prefs.defaultPropertyPriority: 785 out.append(property.priority) 786 else: 787 out.append(part) 788 789 return u''.join(out)
790
791 - def do_Property_priority(self, priorityseq):
792 """ 793 a Properties priority "!" S* "important" 794 """ 795 # TODO: use Out() 796 797 out = [] 798 for part in priorityseq: 799 if hasattr(part, 'cssText'): # comments 800 out.append(u' ') 801 out.append(part.cssText) 802 out.append(u' ') 803 else: 804 out.append(part) 805 return u''.join(out).strip()
806
807 - def do_css_CSSValue(self, cssvalue):
808 """ 809 serializes a CSSValue 810 """ 811 # TODO: use Out() 812 # TODO: use self._valid(cssvalue)? 813 814 if not cssvalue: 815 return u'' 816 else: 817 sep = u',%s' % self.prefs.listItemSpacer 818 out = [] 819 for part in cssvalue.seq: 820 if hasattr(part, 'cssText'): 821 # comments or CSSValue if a CSSValueList 822 out.append(part.cssText) 823 elif isinstance(part, basestring) and part == u',': 824 out.append(sep) 825 else: 826 # TODO: escape func parameter if STRING! 827 if part and part[0] == part[-1] and part[0] in '\'"': 828 # string has " " around it in CSSValue! 829 part = self._string(part[1:-1]) 830 out.append(part) 831 return (u''.join(out)).strip()
832
833 - def do_stylesheets_medialist(self, medialist):
834 """ 835 comma-separated list of media, default is 'all' 836 837 If "all" is in the list, every other media *except* "handheld" will 838 be stripped. This is because how Opera handles CSS for PDAs. 839 """ 840 if len(medialist) == 0: 841 return u'all' 842 else: 843 sep = u',%s' % self.prefs.listItemSpacer 844 return sep.join((mq.mediaText for mq in medialist))
845
846 - def do_stylesheets_mediaquery(self, mediaquery):
847 """ 848 a single media used in medialist 849 """ 850 if mediaquery.wellformed: 851 out = [] 852 for part in mediaquery.seq: 853 if isinstance(part, cssutils.css.Property): # Property 854 out.append(u'(%s)' % part.cssText) 855 elif hasattr(part, 'cssText'): # comments 856 out.append(part.cssText) 857 else: 858 # TODO: media queries! 859 out.append(part) 860 return u' '.join(out) 861 else: 862 return u''
863