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