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-22 19:03:20 +0100 (Fr, 22 Feb 2008) $' 
 10  __version__ = '$LastChangedRevision: 1070 $' 
 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 spacer = u' ' 86 general spacer, used e.g. by CSSUnknownRule 87 88 validOnly = False **DO NOT CHANGE YET** 89 if True only valid (currently Properties) are kept 90 91 A Property is valid if it is a known Property with a valid value. 92 Currently CSS 2.1 values as defined in cssproperties.py would be 93 valid. 94 95 """
96 - def __init__(self, **initials):
97 """ 98 Always use named instead of positional parameters 99 """ 100 self.useDefaults() 101 102 for key, value in initials.items(): 103 if value: 104 self.__setattr__(key, value)
105
106 - def useDefaults(self):
107 "reset all preference options to the default value" 108 self.defaultAtKeyword = True 109 self.defaultPropertyName = True 110 self.defaultPropertyPriority = True 111 self.importHrefFormat = None 112 self.indent = 4 * u' ' 113 self.indentSpecificities = False 114 self.keepAllProperties = True 115 self.keepComments = True 116 self.keepEmptyRules = False 117 self.keepUsedNamespaceRulesOnly = False 118 self.lineNumbers = False 119 self.lineSeparator = u'\n' 120 self.listItemSpacer = u' ' 121 self.omitLastSemicolon = True 122 self.paranthesisSpacer = u' ' 123 self.propertyNameSpacer = u' ' 124 self.selectorCombinatorSpacer = u' ' 125 self.spacer = u' ' 126 self.validOnly = False # should not be changed currently!!!
127
128 - def useMinified(self):
129 """ 130 sets options to achive a minified stylesheet 131 132 you may want to set preferences with this convinience method 133 and set settings you want adjusted afterwards 134 """ 135 self.importHrefFormat = 'string' 136 self.indent = u'' 137 self.keepComments = False 138 self.keepEmptyRules = False 139 self.keepUsedNamespaceRulesOnly = True 140 self.lineNumbers = False 141 self.lineSeparator = u'' 142 self.listItemSpacer = u'' 143 self.omitLastSemicolon = True 144 self.paranthesisSpacer = u'' 145 self.propertyNameSpacer = u'' 146 self.selectorCombinatorSpacer = u'' 147 self.spacer = u'' 148 self.validOnly = False
149
150 - def __repr__(self):
151 return u"cssutils.css.%s(%s)" % (self.__class__.__name__, 152 u', '.join(['\n %s=%r' % (p, self.__getattribute__(p)) for p in self.__dict__] 153 ))
154
155 - def __str__(self):
156 return u"<cssutils.css.%s object %s at 0x%x" % (self.__class__.__name__, 157 u' '.join(['%s=%r' % (p, self.__getattribute__(p)) for p in self.__dict__] 158 ), 159 id(self))
160 161
162 -class Out(object):
163 """ 164 a simple class which makes appended items available as a combined string 165 """
166 - def __init__(self, ser):
167 self.ser = ser 168 self.out = []
169
170 - def _remove_last_if_S(self):
171 if self.out and not self.out[-1].strip(): 172 # remove trailing S 173 del self.out[-1]
174
175 - def append(self, val, typ=None, space=True, keepS=False, indent=False):
176 """ 177 Appends val. Adds a single S after each token except as follows: 178 179 - typ COMMENT 180 uses cssText depending on self.ser.prefs.keepComments 181 - typ cssutils.css.CSSRule.UNKNOWN_RULE 182 uses cssText 183 - typ STRING 184 escapes ser._string 185 - typ S 186 ignored except ``keepS=True`` 187 - typ URI 188 calls ser_uri 189 - val { 190 adds \n after 191 - val ; 192 removes S before and adds \n after 193 - val , : 194 removes S before 195 - val + > ~ 196 encloses in prefs.selectorCombinatorSpacer 197 - some other vals 198 add *spacer except ``space=False`` 199 """ 200 if val or 'STRING' == typ: 201 # PRE 202 if 'COMMENT' == typ: 203 if self.ser.prefs.keepComments: 204 val = val.cssText 205 else: 206 return 207 elif cssutils.css.CSSRule.UNKNOWN_RULE == typ: 208 val = val.cssText 209 elif 'S' == typ and not keepS: 210 return 211 elif 'STRING' == typ: 212 # may be empty but MUST not be None 213 if val is None: 214 return 215 val = self.ser._string(val) 216 elif 'URI' == typ: 217 val = self.ser._uri(val) 218 elif val in u'+>~,:{;)]': 219 self._remove_last_if_S() 220 221 # APPEND 222 if indent: 223 self.out.append(self.ser._indentblock(val, self.ser._level+1)) 224 else: 225 self.out.append(val) 226 227 # POST 228 if 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 # no need to use Out() as too simple 366 if rule._cssText and self.prefs.keepComments: 367 return rule._cssText 368 else: 369 return u''
370
371 - def do_CSSCharsetRule(self, rule):
372 """ 373 serializes CSSCharsetRule 374 encoding: string 375 376 always @charset "encoding"; 377 no comments or other things allowed! 378 """ 379 # no need to use Out() as too simple 380 if rule.wellformed: 381 return u'@charset %s;' % self._string(rule.encoding) 382 else: 383 return u''
384
385 - def do_CSSFontFaceRule(self, rule):
386 """ 387 serializes CSSFontFaceRule 388 389 style 390 CSSStyleDeclaration 391 392 + CSSComments 393 """ 394 styleText = self.do_css_CSSStyleDeclaration(rule.style) 395 396 if styleText and rule.wellformed: 397 out = Out(self) 398 out.append(self._atkeyword(rule, u'@font-face')) 399 for item in rule.seq: 400 # assume comments { 401 out.append(item.value, item.type) 402 out.append(u'{') 403 out.append(u'%s%s}' % (styleText, self.prefs.lineSeparator), 404 indent=1) 405 return out.value() 406 else: 407 return u''
408
409 - def do_CSSImportRule(self, rule):
410 """ 411 serializes CSSImportRule 412 413 href 414 string 415 media 416 optional cssutils.stylesheets.medialist.MediaList 417 name 418 optional string 419 420 + CSSComments 421 """ 422 if rule.wellformed: 423 out = Out(self) 424 out.append(self._atkeyword(rule, u'@import')) 425 426 for item in rule.seq: 427 typ, val = item.type, item.value 428 if 'href' == typ: 429 # "href" or url(href) 430 if self.prefs.importHrefFormat == 'string' or ( 431 self.prefs.importHrefFormat != 'uri' and 432 rule.hreftype == 'string'): 433 out.append(val, 'STRING') 434 else: 435 out.append(val, 'URI') 436 elif 'media' == typ: 437 # media 438 mediaText = self.do_stylesheets_medialist(val) 439 if mediaText and mediaText != u'all': 440 out.append(mediaText) 441 elif 'name' == typ: 442 out.append(val, 'STRING') 443 else: 444 out.append(val, typ) 445 446 return out.value(end=u';') 447 else: 448 return u''
449
450 - def do_CSSNamespaceRule(self, rule):
451 """ 452 serializes CSSNamespaceRule 453 454 uri 455 string 456 prefix 457 string 458 459 + CSSComments 460 """ 461 if rule.wellformed: 462 out = Out(self) 463 out.append(self._atkeyword(rule, u'@namespace')) 464 465 for item in rule.seq: 466 typ, val = item.type, item.value 467 if 'namespaceURI' == typ: 468 out.append(val, 'STRING') 469 else: 470 out.append(val, typ) 471 472 return out.value(end=u';') 473 else: 474 return u''
475
476 - def do_CSSMediaRule(self, rule):
477 """ 478 serializes CSSMediaRule 479 480 + CSSComments 481 """ 482 # TODO: use Out()? 483 484 # @media 485 out = [self._atkeyword(rule, u'@media')] 486 out.append(self.prefs.spacer) # might be empty 487 488 # mediaquery 489 if not rule.media.wellformed: 490 return u'' 491 out.append(self.do_stylesheets_medialist(rule.media)) 492 493 # name, seq contains content after name only (Comments) 494 if rule.name: 495 out.append(self.prefs.spacer) 496 nameout = Out(self) 497 nameout.append(self._string(rule.name)) 498 for item in rule.seq: 499 nameout.append(item.value, item.type) 500 out.append(nameout.value()) 501 502 # { 503 out.append(self.prefs.paranthesisSpacer) 504 out.append(u'{') 505 out.append(self.prefs.lineSeparator) 506 507 # rules 508 rulesout = [] 509 for r in rule.cssRules: 510 rtext = r.cssText 511 if rtext: 512 # indent each line of cssText 513 rulesout.append(self._indentblock(rtext, self._level + 1)) 514 rulesout.append(self.prefs.lineSeparator) 515 if not self.prefs.keepEmptyRules and not u''.join(rulesout).strip(): 516 return u'' 517 out.extend(rulesout) 518 519 # } 520 out.append(u'%s}' % ((self._level + 1) * self.prefs.indent)) 521 522 return u''.join(out)
523
524 - def do_CSSPageRule(self, rule):
525 """ 526 serializes CSSPageRule 527 528 selectorText 529 string 530 style 531 CSSStyleDeclaration 532 533 + CSSComments 534 """ 535 styleText = self.do_css_CSSStyleDeclaration(rule.style) 536 537 if styleText and rule.wellformed: 538 out = Out(self) 539 out.append(self._atkeyword(rule, u'@page')) 540 541 for item in rule.seq: 542 out.append(item.value, item.type) 543 544 out.append(u'{') 545 out.append(u'%s%s}' % (styleText, self.prefs.lineSeparator), 546 indent=1) 547 return out.value() 548 else: 549 return u''
550
551 - def do_CSSUnknownRule(self, rule):
552 """ 553 serializes CSSUnknownRule 554 anything until ";" or "{...}" 555 + CSSComments 556 """ 557 if rule.wellformed: 558 out = Out(self) 559 out.append(rule.atkeyword) 560 stacks = [] 561 for item in rule.seq: 562 typ, val = item.type, item.value 563 564 # PRE 565 if u'}' == val: 566 # close last open item on stack 567 stackblock = stacks.pop().value() 568 if stackblock: 569 val = self._indentblock( 570 stackblock + self.prefs.lineSeparator + val, 571 min(1, len(stacks)+1)) 572 # APPEND 573 if stacks: 574 stacks[-1].append(val, typ) 575 else: 576 out.append(val, typ) 577 578 # POST 579 if u'{' == val: 580 # new stack level 581 stacks.append(Out(self)) 582 583 return out.value() 584 else: 585 return u''
586
587 - def do_CSSStyleRule(self, rule):
588 """ 589 serializes CSSStyleRule 590 591 selectorList 592 style 593 594 + CSSComments 595 """ 596 # TODO: use Out() 597 598 # prepare for element nested rules 599 # TODO: sort selectors! 600 if self.prefs.indentSpecificities: 601 # subselectorlist? 602 elements = set([s.element for s in rule.selectorList]) 603 specitivities = [s.specificity for s in rule.selectorList] 604 for selector in self._selectors: 605 lastelements = set([s.element for s in selector]) 606 if elements.issubset(lastelements): 607 # higher specificity? 608 lastspecitivities = [s.specificity for s in selector] 609 if specitivities > lastspecitivities: 610 self._selectorlevel += 1 611 break 612 elif self._selectorlevel > 0: 613 self._selectorlevel -= 1 614 else: 615 # save new reference 616 self._selectors.append(rule.selectorList) 617 self._selectorlevel = 0 618 619 # TODO ^ RESOLVE!!!! 620 621 selectorText = self.do_css_SelectorList(rule.selectorList) 622 if not selectorText or not rule.wellformed: 623 return u'' 624 self._level += 1 625 styleText = u'' 626 try: 627 styleText = self.do_css_CSSStyleDeclaration(rule.style) 628 finally: 629 self._level -= 1 630 if not styleText: 631 if self.prefs.keepEmptyRules: 632 return u'%s%s{}' % (selectorText, 633 self.prefs.paranthesisSpacer) 634 else: 635 return self._indentblock( 636 u'%s%s{%s%s%s%s}' % ( 637 selectorText, 638 self.prefs.paranthesisSpacer, 639 self.prefs.lineSeparator, 640 self._indentblock(styleText, self._level + 1), 641 self.prefs.lineSeparator, 642 (self._level + 1) * self.prefs.indent), 643 self._selectorlevel)
644
645 - def do_css_SelectorList(self, selectorlist):
646 "comma-separated list of Selectors" 647 # does not need Out() as it is too simple 648 if selectorlist.wellformed: 649 out = [] 650 for part in selectorlist.seq: 651 if isinstance(part, cssutils.css.Selector): 652 out.append(part.selectorText) 653 else: 654 out.append(part) # should not happen 655 sep = u',%s' % self.prefs.listItemSpacer 656 return sep.join(out) 657 else: 658 return u''
659
660 - def do_css_Selector(self, selector):
661 """ 662 a single Selector including comments 663 664 an element has syntax (namespaceURI, name) where namespaceURI may be: 665 666 - cssutils._ANYNS => ``*|name`` 667 - None => ``name`` 668 - u'' => ``|name`` 669 - any other value: => ``prefix|name`` 670 """ 671 if selector.wellformed: 672 out = Out(self) 673 674 DEFAULTURI = selector._namespaces.get('', None) 675 for item in selector.seq: 676 typ, val = item.type, item.value 677 if type(val) == tuple: 678 # namespaceURI|name (element or attribute) 679 namespaceURI, name = val 680 if DEFAULTURI == namespaceURI or (not DEFAULTURI and 681 namespaceURI is None): 682 out.append(name, typ, space=False) 683 else: 684 if namespaceURI == cssutils._ANYNS: 685 prefix = u'*' 686 else: 687 try: 688 prefix = selector._namespaces.prefixForNamespaceURI( 689 namespaceURI) 690 except IndexError: 691 prefix = u'' 692 693 out.append(u'%s|%s' % (prefix, name), typ, space=False) 694 else: 695 out.append(val, typ, space=False, keepS=True) 696 697 return out.value() 698 else: 699 return u''
700
701 - def do_css_CSSStyleDeclaration(self, style, separator=None):
702 """ 703 Style declaration of CSSStyleRule 704 """ 705 # TODO: use Out() 706 707 # may be comments only 708 if len(style.seq) > 0: 709 if separator is None: 710 separator = self.prefs.lineSeparator 711 712 if self.prefs.keepAllProperties: 713 # all 714 parts = style.seq 715 else: 716 # only effective ones 717 _effective = style.getProperties() 718 parts = [x for x in style.seq 719 if (isinstance(x, cssutils.css.Property) 720 and x in _effective) 721 or not isinstance(x, cssutils.css.Property)] 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 # TODO: use Out() 756 757 out = [] 758 if property.seqs[0] and property.wellformed and self._valid(property): 759 nameseq, cssvalue, priorityseq = property.seqs 760 761 #name 762 for part in nameseq: 763 if hasattr(part, 'cssText'): 764 out.append(part.cssText) 765 elif property.literalname == part: 766 out.append(self._propertyname(property, part)) 767 else: 768 out.append(part) 769 770 if out and (not property._mediaQuery or 771 property._mediaQuery and cssvalue.cssText): 772 # MediaQuery may consist of name only 773 out.append(u':') 774 out.append(self.prefs.propertyNameSpacer) 775 776 # value 777 out.append(cssvalue.cssText) 778 779 # priority 780 if out and priorityseq: 781 out.append(u' ') 782 for part in priorityseq: 783 if hasattr(part, 'cssText'): # comments 784 out.append(part.cssText) 785 else: 786 if part == property.literalpriority and\ 787 self.prefs.defaultPropertyPriority: 788 out.append(property.priority) 789 else: 790 out.append(part) 791 792 return u''.join(out)
793
794 - def do_Property_priority(self, priorityseq):
795 """ 796 a Properties priority "!" S* "important" 797 """ 798 # TODO: use Out() 799 800 out = [] 801 for part in priorityseq: 802 if hasattr(part, 'cssText'): # comments 803 out.append(u' ') 804 out.append(part.cssText) 805 out.append(u' ') 806 else: 807 out.append(part) 808 return u''.join(out).strip()
809
810 - def do_css_CSSValue(self, cssvalue):
811 """ 812 serializes a CSSValue 813 """ 814 # TODO: use Out() 815 # TODO: use self._valid(cssvalue)? 816 817 if not cssvalue: 818 return u'' 819 else: 820 sep = u',%s' % self.prefs.listItemSpacer 821 out = [] 822 for part in cssvalue.seq: 823 if hasattr(part, 'cssText'): 824 # comments or CSSValue if a CSSValueList 825 out.append(part.cssText) 826 elif isinstance(part, basestring) and part == u',': 827 out.append(sep) 828 else: 829 # TODO: escape func parameter if STRING! 830 if part and part[0] == part[-1] and part[0] in '\'"': 831 # string has " " around it in CSSValue! 832 part = self._string(part[1:-1]) 833 out.append(part) 834 return (u''.join(out)).strip()
835
836 - def do_stylesheets_medialist(self, medialist):
837 """ 838 comma-separated list of media, default is 'all' 839 840 If "all" is in the list, every other media *except* "handheld" will 841 be stripped. This is because how Opera handles CSS for PDAs. 842 """ 843 if len(medialist) == 0: 844 return u'all' 845 else: 846 sep = u',%s' % self.prefs.listItemSpacer 847 return sep.join((mq.mediaText for mq in medialist))
848
849 - def do_stylesheets_mediaquery(self, mediaquery):
850 """ 851 a single media used in medialist 852 """ 853 if mediaquery.wellformed: 854 out = [] 855 for part in mediaquery.seq: 856 if isinstance(part, cssutils.css.Property): # Property 857 out.append(u'(%s)' % part.cssText) 858 elif hasattr(part, 'cssText'): # comments 859 out.append(part.cssText) 860 else: 861 # TODO: media queries! 862 out.append(part) 863 return u' '.join(out) 864 else: 865 return u''
866