1
2 """serializer classes for CSS classes
3
4 TODO:
5 - indent subrules if selector is subselector
6
7 """
8 __all__ = ['CSSSerializer']
9 __docformat__ = 'restructuredtext'
10 __author__ = '$LastChangedBy: cthedot $'
11 __date__ = '$LastChangedDate: 2007-06-17 19:49:45 +0200 (So, 17 Jun 2007) $'
12 __version__ = '0.9.2a2 $LastChangedRevision: 89 $'
13
14 import cssutils
15
17 """
18 controls output of CSSSerializer
19
20 defaultAtKeyword = True
21 Should the literal @keyword from src CSS be used or the default
22 form, e.g. if ``True``: ``@import`` else: ``@i\mport``
23 defaultPropertyName = True
24 Should the normalized propertyname be used or the one given in
25 the src file, e.g. if ``True``: ``color`` else: ``c\olor``
26
27 Only used if ``keepAllProperties==False``.
28
29 importHrefFormat = None
30 Uses hreftype if ``None`` or explicit 'string' or 'uri'
31 indent = 4 * ' '
32 Indentation of e.g Properties inside a CSSStyleDeclaration
33 keepAllProperties = False
34 If ``True`` all properties set in the original CSSStylesheet
35 are kept meaning even properties set twice with the exact same
36 same name are kept!
37 keepComments = True
38 If ``False`` removes all CSSComments
39 omitLastSemicolon = True
40 If ``True`` omits ; after last property of CSSStyleDeclaration
41 lineNumbers = False
42 Only used if a complete CSSStyleSheet is serialized.
43 removeInvalid = True
44 Omits invalid rules, MAY CHANGE!
45 setBOM = False
46 NOT USED YET
47 """
49 """
50 Always use named instead of positional parameters!
51 """
52 self.defaultAtKeyword = True
53 self.defaultPropertyName = True
54 self.indent = indent
55 self.importHrefFormat = None
56 self.keepAllProperties = False
57 self.keepComments = True
58 self.omitLastSemicolon = True
59 self.lineNumbers = False
60 self.removeInvalid = True
61 self.setBOM = False
62
63
65 """
66 Methods to serialize a CSSStylesheet and its parts
67
68 To use your own serializing method the easiest is to subclass CSS
69 Serializer and overwrite the methods you like to customize.
70 """
99
100
102 if self.prefs.lineNumbers:
103 pad = text.count(u'\n') / 10 + 1
104 out = []
105 for i, line in enumerate(text.split(u'\n')):
106 out.append((u'%'+str(pad)+'i: %s') % (i+1, line))
107 text = u'\n'.join(out)
108 return text
109
110
112 """
113 returns
114 True if x.valid or prefs.removeInvalid == False
115 else False
116 """
117 if self.prefs.removeInvalid and \
118 hasattr(x, 'valid') and not x.valid:
119 return True
120 else:
121 return False
122
123
125 """
126 escapes delim charaters in string s with \delim
127 """
128 return s.replace(delim, u'\%s' % delim)
129
131 """
132 used by all @rules to get the keyword used
133 dependent on prefs setting defaultAtKeyword
134 """
135 if self.prefs.defaultAtKeyword:
136 return default
137 else:
138 return rule.atkeyword
139
141 """
142 used by all styledeclarations to get the propertyname used
143 dependent on prefs setting defaultPropertyName
144 """
145 if self.prefs.defaultPropertyName and \
146 not self.prefs.keepAllProperties:
147 return property.normalname
148 else:
149 return actual
150
151
153 raise NotImplementedError(
154 "Serializer not implemented for %s" % rule)
155
156
194
195
203
204
213
214
216 """
217 serializes CSSCharsetRule
218 encoding: string
219
220 always @charset "encoding";
221 no comments or other things allowed!
222 """
223 if not rule.encoding or self._noinvalids(rule):
224 return u''
225 return u'@charset "%s";' % self._escapestring(rule.encoding)
226
227
229 """
230 serializes CSSImportRule
231
232 href
233 string
234 hreftype
235 'uri' or 'string'
236 media
237 cssutils.stylesheets.medialist.MediaList
238
239 + CSSComments
240 """
241 if not rule.href or self._noinvalids(rule):
242 return u''
243 out = [u'%s ' % self._getatkeyword(rule, u'@import')]
244 for part in rule.seq:
245 if rule.href == part:
246 if self.prefs.importHrefFormat == 'uri':
247 out.append('url(%s)' % part)
248 elif self.prefs.importHrefFormat == 'string' or \
249 rule.hreftype == 'string':
250 out.append('"%s"' % self._escapestring(part))
251 else:
252 out.append('url(%s)' % part)
253 elif isinstance(
254 part, cssutils.stylesheets.medialist.MediaList):
255 mediaText = self.do_stylesheets_medialist(part).strip()
256 if mediaText and not mediaText == u'all':
257 out.append(u' %s' % mediaText)
258 elif hasattr(part, 'cssText'):
259 out.append(part.cssText)
260 out.append(';')
261 return u''.join(out)
262
263
265 """
266 serializes CSSNamespaceRule
267
268 uri
269 string
270 prefix
271 string
272
273 + CSSComments
274 """
275 if not rule.uri or self._noinvalids(rule):
276 return u''
277
278 out = [u'%s' % self._getatkeyword(rule, u'@namespace')]
279 for part in rule.seq:
280 if rule.prefix == part and part != u'':
281 out.append(' %s' % part)
282 elif rule.uri == part:
283 out.append(' "%s"' % self._escapestring(part))
284 elif hasattr(part, 'cssText'):
285 out.append(part.cssText)
286 out.append(';')
287 return u''.join(out)
288
289
310
311
313 """
314 serializes CSSPageRule
315
316 selectorText
317 string
318 style
319 CSSStyleDeclaration
320
321 + CSSComments
322 """
323 styleText = self.do_css_CSSStyleDeclaration(rule.style)
324 if not styleText or self._noinvalids(rule):
325 return u''
326
327 sel = self.do_pageselector(rule.seq)
328 return u'%s%s {%s}' % (
329 self._getatkeyword(rule, u'@page'),
330 sel,
331 self.do_css_CSSStyleDeclaration(rule.style))
332
333
334 - def do_pageselector(self, seq):
335 """
336 a selector of a CSSPageRule including comments
337 """
338 if len(seq) == 0 or self._noinvalids(seq):
339 return u''
340 else:
341 out = []
342 for part in seq:
343 if isinstance(part, cssutils.css.csscomment.CSSComment):
344 out.append(part.cssText)
345 else:
346 out.append(part)
347 return u' %s' % u''.join(out)
348
349
351 """
352 serializes CSSUnknownRule
353 anything until ";" or "{...}"
354 + CSSComments
355 """
356 if rule.atkeyword and not self._noinvalids(rule):
357 out = [u'@%s' % rule.atkeyword]
358 for part in rule.seq:
359 if isinstance(part, cssutils.css.csscomment.CSSComment):
360 if self.prefs.keepComments:
361 out.append(part.cssText)
362 else:
363 out.append(part)
364 if not (out[-1].endswith(';') or out[-1].endswith('}')):
365 out.append(u';')
366 return u''.join(out)
367 else:
368 return u''
369
370
388
389
408
409
411 """
412 a single selector including comments
413
414 TODO: style combinators like + >
415 """
416 if len(selector.seq) == 0 or self._noinvalids(selector):
417 return u''
418 else:
419 out = []
420 for part in selector.seq:
421 if isinstance(part, cssutils.css.csscomment.CSSComment):
422 out.append(part.cssText)
423 else:
424 if type(part) == dict:
425 out.append(part['value'])
426 else:
427 out.append(part)
428 return u''.join(out)
429
430
432 """
433 Style declaration of CSSStyleRule
434 """
435 if len(style.seq) == 0 or self._noinvalids(style):
436 return u''
437 else:
438 out = ['\n']
439 done1 = False
440 lastwasprop = False
441 for part in style.seq:
442
443 if isinstance(part,
444 cssutils.css.csscomment.CSSComment):
445 if self.prefs.keepComments:
446 done1 = True
447 if lastwasprop:
448 out.append(u';\n')
449 out.append(self.prefs.indent)
450 out.append(part.cssText)
451 out.append(u'\n')
452 lastwasprop = False
453
454
455 elif isinstance(part,
456 cssutils.css.cssstyledeclaration.SameNamePropertyList):
457
458 if not self.prefs.keepAllProperties:
459 _index = part._currentIndex()
460 propertytext = self.do_css_Property(part[_index])
461 else:
462
463 o = []
464 for p in part:
465 pt = self.do_css_Property(p)
466 if pt:
467 o.append(pt)
468 o.append(u';\n')
469 o.append(self.prefs.indent)
470 propertytext = u''.join(o[:-2])
471
472 if propertytext:
473 done1 = True
474 if lastwasprop:
475 out.append(u';\n')
476 out.append(self.prefs.indent)
477 out.append(propertytext)
478 lastwasprop = True
479
480
481 else:
482 done1 = True
483 if lastwasprop:
484 out.append(u';\n')
485 out.append(part)
486 lastwasprop = False
487 if not done1:
488 return u''
489 if lastwasprop:
490 if self.prefs.omitLastSemicolon:
491 out.append(u'\n')
492 else:
493 out.append(u';\n')
494 out.append(self.prefs.indent)
495 return u''.join(out)
496
497
499 """
500 Style declaration of CSSStyleRule
501
502 Property has a seqs attribute which contains seq lists for
503 name, a CSSvalue and a seq list for priority
504 """
505 if not property.seqs[0] or self._noinvalids(property):
506 return u''
507 else:
508 out = []
509 nameseq, cssvalue, priorityseq = property.seqs
510
511 for part in nameseq:
512 if isinstance(part, cssutils.css.csscomment.CSSComment):
513 out.append(part.cssText)
514 elif property.name == part:
515 out.append(self._getpropertyname(property, part))
516 else:
517 out.append(part)
518 if out:
519 out.append(u': ')
520 v = self.do_css_CSSvalue(cssvalue)
521 if v:
522 out.append(v)
523
524 if out and priorityseq:
525 out.append(u' ')
526 for part in priorityseq:
527 if hasattr(part, 'cssText'):
528 out.append(part.cssText)
529 else:
530 out.append(part)
531
532 return u''.join(out)
533
534
536 """
537 serializes a CSSValue
538 """
539 if not cssvalue:
540 return u''
541 else:
542 out = []
543 for part in cssvalue.seq:
544 if hasattr(part, 'cssText'):
545 out.append(part.cssText)
546 else:
547 out.append(part)
548 return (u''.join(out)).strip()
549