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