1 """CSSValue related classes
2
3 - CSSValue implements DOM Level 2 CSS CSSValue
4 - CSSPrimitiveValue implements DOM Level 2 CSS CSSPrimitiveValue
5 - CSSValueList implements DOM Level 2 CSS CSSValueList
6
7 """
8 __all__ = ['CSSValue', 'CSSPrimitiveValue', 'CSSValueList']
9 __docformat__ = 'restructuredtext'
10 __version__ = '$Id: cssvalue.py 1116 2008-03-05 13:52:23Z cthedot $'
11
12 import re
13 import xml.dom
14 import cssutils
15 import cssproperties
16
18 """
19 The CSSValue interface represents a simple or a complex value.
20 A CSSValue object only occurs in a context of a CSS property
21
22 Properties
23 ==========
24 cssText
25 A string representation of the current value.
26 cssValueType
27 A (readonly) code defining the type of the value.
28
29 seq: a list (cssutils)
30 All parts of this style declaration including CSSComments
31 valid: boolean
32 if the value is valid at all, False for e.g. color: #1
33 wellformed
34 if this Property is syntactically ok
35
36 _value (INTERNAL!)
37 value without any comments, used to validate
38 """
39
40 CSS_INHERIT = 0
41 """
42 The value is inherited and the cssText contains "inherit".
43 """
44 CSS_PRIMITIVE_VALUE = 1
45 """
46 The value is a primitive value and an instance of the
47 CSSPrimitiveValue interface can be obtained by using binding-specific
48 casting methods on this instance of the CSSValue interface.
49 """
50 CSS_VALUE_LIST = 2
51 """
52 The value is a CSSValue list and an instance of the CSSValueList
53 interface can be obtained by using binding-specific casting
54 methods on this instance of the CSSValue interface.
55 """
56 CSS_CUSTOM = 3
57 """
58 The value is a custom value.
59 """
60 _typestrings = ['CSS_INHERIT' , 'CSS_PRIMITIVE_VALUE', 'CSS_VALUE_LIST',
61 'CSS_CUSTOM']
62
63 - def __init__(self, cssText=None, readonly=False, _propertyName=None):
64 """
65 inits a new CSS Value
66
67 cssText
68 the parsable cssText of the value
69 readonly
70 defaults to False
71 property
72 used to validate this value in the context of a property
73 """
74 super(CSSValue, self).__init__()
75
76 self.seq = []
77 self.valid = False
78 self.wellformed = False
79 self._valueValue = u''
80 self._linetoken = None
81 self._propertyName = _propertyName
82
83 if cssText is not None:
84 if type(cssText) in (int, float):
85 cssText = unicode(cssText)
86 self.cssText = cssText
87
88 self._readonly = readonly
89
91 v = []
92 for x in self.seq:
93 if isinstance(x, cssutils.css.CSSComment):
94 continue
95 elif isinstance(x, basestring):
96 v.append(x)
97 else:
98 v.append(x.cssText)
99 if v and u'' == v[-1].strip():
100
101 del v[-1]
102 return u''.join(v)
103
105 "overwritten by CSSValueList!"
106 self._valueValue = value
107
108 _value = property(_getValue, _setValue,
109 doc="Actual cssText value of this CSSValue.")
110
111 - def _getCssText(self):
113
114 - def _setCssText(self, cssText):
115 """
116 Format
117 ======
118 ::
119
120 unary_operator
121 : '-' | '+'
122 ;
123 operator
124 : '/' S* | ',' S* | /* empty */
125 ;
126 expr
127 : term [ operator term ]*
128 ;
129 term
130 : unary_operator?
131 [ NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* | ANGLE S* |
132 TIME S* | FREQ S* ]
133 | STRING S* | IDENT S* | URI S* | hexcolor | function
134 ;
135 function
136 : FUNCTION S* expr ')' S*
137 ;
138 /*
139 * There is a constraint on the color that it must
140 * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F])
141 * after the "#"; e.g., "#000" is OK, but "#abcd" is not.
142 */
143 hexcolor
144 : HASH S*
145 ;
146
147 DOMException on setting
148
149 - SYNTAX_ERR: (self)
150 Raised if the specified CSS string value has a syntax error
151 (according to the attached property) or is unparsable.
152 - TODO: INVALID_MODIFICATION_ERR:
153 Raised if the specified CSS string value represents a different
154 type of values than the values allowed by the CSS property.
155 - NO_MODIFICATION_ALLOWED_ERR: (self)
156 Raised if this value is readonly.
157 """
158 self._checkReadonly()
159
160
161 new = {'values': [],
162 'commas': 0,
163 'valid': True,
164 'wellformed': True }
165
166 def _S(expected, seq, token, tokenizer=None):
167 val = self._tokenvalue(token)
168 if expected.endswith('operator'):
169 seq.append(u' ')
170 return 'term or operator'
171 elif expected.endswith('S'):
172 return 'term or S'
173 else:
174 return expected
175
176 def _char(expected, seq, token, tokenizer=None):
177 val = self._tokenvalue(token)
178 if 'funcend' == expected and u')' == val:
179
180 seq[-1] += val
181 new['values'].append(seq[-1])
182 return 'operator'
183
184 elif expected in (')', ']', '}') and expected == val:
185
186 seq[-1] += val
187 return 'operator'
188
189 elif expected in ('funcend', ')', ']', '}'):
190
191 seq[-1] += val
192 return expected
193
194 elif expected.endswith('operator') and ',' == val:
195
196 new['commas'] += 1
197 if seq and seq[-1] == u' ':
198 seq[-1] = val
199 else:
200 seq.append(val)
201 return 'term or S'
202
203 elif expected.endswith('operator') and '/' == val:
204
205 if seq and seq[-1] == u' ':
206 seq[-1] = val
207 else:
208 seq.append(val)
209 return 'term or S'
210
211 elif expected.startswith('term') and u'(' == val:
212
213 seq.append(val)
214 return ')'
215 elif expected.startswith('term') and u'[' == val:
216
217 seq.append(val)
218 return ']'
219 elif expected.startswith('term') and u'{' == val:
220
221 seq.append(val)
222 return '}'
223 elif expected.startswith('term') and u'-' == val or u'+' == 'val':
224
225 seq.append(val)
226 new['values'].append(val)
227 return 'number percentage dimension'
228 elif expected.startswith('term') and u'/' == val:
229
230 seq.append(val)
231 new['values'].append(val)
232 return 'number percentage dimension'
233 else:
234 new['wellformed'] = False
235 self._log.error(u'CSSValue: Unexpected char.', token)
236 return expected
237
238 def _number_percentage_dimension(expected, seq, token, tokenizer=None):
239
240 if expected.startswith('term') or expected == 'number percentage dimension':
241
242 val = self._tokenvalue(token)
243 if new['values'] and new['values'][-1] in (u'-', u'+'):
244 new['values'][-1] += val
245 else:
246 new['values'].append(val)
247 seq.append(val)
248 return 'operator'
249 elif expected in ('funcend', ')', ']', '}'):
250
251 seq[-1] += self._tokenvalue(token)
252 return expected
253 else:
254 new['wellformed'] = False
255 self._log.error(u'CSSValue: Unexpected token.', token)
256 return expected
257
258 def _string_ident_uri_hexcolor(expected, seq, token, tokenizer=None):
259
260 if expected.startswith('term'):
261
262
263
264 typ = self._type(token)
265 if self._prods.STRING == typ:
266 val = u'"%s"' % self._stringtokenvalue(token)
267
268
269 else:
270 val = self._tokenvalue(token)
271
272 new['values'].append(val)
273 seq.append(val)
274 return 'operator'
275 elif expected in ('funcend', ')', ']', '}'):
276
277 seq[-1] += self._tokenvalue(token)
278 return expected
279 else:
280 new['wellformed'] = False
281 self._log.error(u'CSSValue: Unexpected token.', token)
282 return expected
283
284 def _function(expected, seq, token, tokenizer=None):
285
286 if expected.startswith('term'):
287
288 seq.append(self._tokenvalue(token))
289 return 'funcend'
290 elif expected in ('funcend', ')', ']', '}'):
291
292 seq[-1] += self._tokenvalue(token)
293 return expected
294 else:
295 new['wellformed'] = False
296 self._log.error(u'CSSValue: Unexpected token.', token)
297 return expected
298
299 tokenizer = self._tokenize2(cssText)
300
301 linetoken = self._nexttoken(tokenizer)
302 if not linetoken:
303 self._log.error(u'CSSValue: Unknown syntax or no value: %r.' %
304 self._valuestr(cssText))
305 else:
306
307 tokenizer = self._tokenize2(cssText)
308 newseq = []
309 wellformed, expected = self._parse(expected='term',
310 seq=newseq, tokenizer=tokenizer,
311 productions={'S': _S,
312 'CHAR': _char,
313
314 'NUMBER': _number_percentage_dimension,
315 'PERCENTAGE': _number_percentage_dimension,
316 'DIMENSION': _number_percentage_dimension,
317
318 'STRING': _string_ident_uri_hexcolor,
319 'IDENT': _string_ident_uri_hexcolor,
320 'URI': _string_ident_uri_hexcolor,
321 'HASH': _string_ident_uri_hexcolor,
322 'UNICODE-RANGE': _string_ident_uri_hexcolor,
323
324 'FUNCTION': _function
325 })
326
327 wellformed = wellformed and new['wellformed']
328
329
330 if expected.startswith('term') and newseq and newseq[-1] != u' ' or (
331 expected in ('funcend', ')', ']', '}')):
332 wellformed = False
333 self._log.error(u'CSSValue: Incomplete value: %r.' %
334 self._valuestr(cssText))
335
336 if not new['values']:
337 wellformed = False
338 self._log.error(u'CSSValue: Unknown syntax or no value: %r.' %
339 self._valuestr(cssText))
340
341 else:
342 self._linetoken = linetoken
343 self.seq = newseq
344 self.valid = False
345
346 self._validate()
347
348 if len(new['values']) == 1 and new['values'][0] == u'inherit':
349 self._value = u'inherit'
350 self._cssValueType = CSSValue.CSS_INHERIT
351 self.__class__ = CSSValue
352 elif len(new['values']) == 1:
353 self.__class__ = CSSPrimitiveValue
354 self._init()
355 elif len(new['values']) > 1 and\
356 len(new['values']) == new['commas'] + 1:
357
358 self.__class__ = CSSPrimitiveValue
359 self._init()
360 elif len(new['values']) > 1:
361
362 self.__class__ = CSSValueList
363 self._init()
364 else:
365 self._cssValueType = CSSValue.CSS_CUSTOM
366 self.__class__ = CSSValue
367
368 self.wellformed = wellformed
369
370 cssText = property(_getCssText, _setCssText,
371 doc="A string representation of the current value.")
372
374 if hasattr(self, '_cssValueType'):
375 return self._cssValueType
376
377 cssValueType = property(_getCssValueType,
378 doc="A (readonly) code defining the type of the value as defined above.")
379
386
387 cssValueTypeString = property(_getCssValueTypeString,
388 doc="cssutils: Name of cssValueType of this CSSValue (readonly).")
389
407
409 return self.__propertyName
410
414
415 _propertyName = property(_get_propertyName, _set_propertyName,
416 doc="cssutils: Property this values is validated against")
417
419 return "cssutils.css.%s(%r, _propertyName=%r)" % (
420 self.__class__.__name__, self.cssText, self._propertyName)
421
423 return "<cssutils.css.%s object cssValueType=%r cssText=%r propname=%r valid=%r at 0x%x>" % (
424 self.__class__.__name__, self.cssValueTypeString,
425 self.cssText, self._propertyName, self.valid, id(self))
426
427
429 """
430 represents a single CSS Value. May be used to determine the value of a
431 specific style property currently set in a block or to set a specific
432 style property explicitly within the block. Might be obtained from the
433 getPropertyCSSValue method of CSSStyleDeclaration.
434
435 Conversions are allowed between absolute values (from millimeters to
436 centimeters, from degrees to radians, and so on) but not between
437 relative values. (For example, a pixel value cannot be converted to a
438 centimeter value.) Percentage values can't be converted since they are
439 relative to the parent value (or another property value). There is one
440 exception for color percentage values: since a color percentage value
441 is relative to the range 0-255, a color percentage value can be
442 converted to a number; (see also the RGBColor interface).
443 """
444
445 cssValueType = CSSValue.CSS_PRIMITIVE_VALUE
446
447
448 CSS_UNKNOWN = 0
449 CSS_NUMBER = 1
450 CSS_PERCENTAGE = 2
451 CSS_EMS = 3
452 CSS_EXS = 4
453 CSS_PX = 5
454 CSS_CM = 6
455 CSS_MM = 7
456 CSS_IN = 8
457 CSS_PT = 9
458 CSS_PC = 10
459 CSS_DEG = 11
460 CSS_RAD = 12
461 CSS_GRAD = 13
462 CSS_MS = 14
463 CSS_S = 15
464 CSS_HZ = 16
465 CSS_KHZ = 17
466 CSS_DIMENSION = 18
467 CSS_STRING = 19
468 CSS_URI = 20
469 CSS_IDENT = 21
470 CSS_ATTR = 22
471 CSS_COUNTER = 23
472 CSS_RECT = 24
473 CSS_RGBCOLOR = 25
474
475 CSS_RGBACOLOR = 26
476
477 _floattypes = [CSS_NUMBER, CSS_PERCENTAGE, CSS_EMS, CSS_EXS,
478 CSS_PX, CSS_CM, CSS_MM, CSS_IN, CSS_PT, CSS_PC,
479 CSS_DEG, CSS_RAD, CSS_GRAD, CSS_MS, CSS_S,
480 CSS_HZ, CSS_KHZ, CSS_DIMENSION
481 ]
482 _stringtypes = [CSS_ATTR, CSS_IDENT, CSS_STRING, CSS_URI]
483 _countertypes = [CSS_COUNTER]
484 _recttypes = [CSS_RECT]
485 _rbgtypes = [CSS_RGBCOLOR, CSS_RGBACOLOR]
486
487 _reNumDim = re.compile(ur'^(.*?)([a-z]+|%)$', re.I| re.U|re.X)
488
489
490 _converter = {
491
492
493
494 (CSS_CM, CSS_MM): lambda x: x * 10,
495 (CSS_MM, CSS_CM): lambda x: x / 10,
496
497 (CSS_PT, CSS_PC): lambda x: x * 12,
498 (CSS_PC, CSS_PT): lambda x: x / 12,
499
500 (CSS_CM, CSS_IN): lambda x: x / 2.54,
501 (CSS_IN, CSS_CM): lambda x: x * 2.54,
502 (CSS_MM, CSS_IN): lambda x: x / 25.4,
503 (CSS_IN, CSS_MM): lambda x: x * 25.4,
504
505 (CSS_IN, CSS_PT): lambda x: x / 72,
506 (CSS_PT, CSS_IN): lambda x: x * 72,
507 (CSS_CM, CSS_PT): lambda x: x / 2.54 / 72,
508 (CSS_PT, CSS_CM): lambda x: x * 72 * 2.54,
509 (CSS_MM, CSS_PT): lambda x: x / 25.4 / 72,
510 (CSS_PT, CSS_MM): lambda x: x * 72 * 25.4,
511
512 (CSS_IN, CSS_PC): lambda x: x / 72 / 12,
513 (CSS_PC, CSS_IN): lambda x: x * 12 * 72,
514 (CSS_CM, CSS_PC): lambda x: x / 2.54 / 72 / 12,
515 (CSS_PC, CSS_CM): lambda x: x * 12 * 72 * 2.54,
516 (CSS_MM, CSS_PC): lambda x: x / 25.4 / 72 / 12,
517 (CSS_PC, CSS_MM): lambda x: x * 12 * 72 * 25.4,
518
519
520 (CSS_KHZ, CSS_HZ): lambda x: x * 1000,
521 (CSS_HZ, CSS_KHZ): lambda x: x / 1000,
522
523 (CSS_S, CSS_MS): lambda x: x * 1000,
524 (CSS_MS, CSS_S): lambda x: x / 1000
525
526
527 }
528
529 - def __init__(self, cssText=None, readonly=False, _propertyName=None):
540
542
543 self._unitinfos = [
544 ('CSS_UNKNOWN', None, None),
545 ('CSS_NUMBER', self._prods.NUMBER, None),
546 ('CSS_PERCENTAGE', self._prods.PERCENTAGE, None),
547 ('CSS_EMS', self._prods.DIMENSION, 'em'),
548 ('CSS_EXS', self._prods.DIMENSION, 'ex'),
549 ('CSS_PX', self._prods.DIMENSION, 'px'),
550 ('CSS_CM', self._prods.DIMENSION, 'cm'),
551 ('CSS_MM', self._prods.DIMENSION, 'mm'),
552 ('CSS_IN', self._prods.DIMENSION, 'in'),
553 ('CSS_PT', self._prods.DIMENSION, 'pt'),
554 ('CSS_PC', self._prods.DIMENSION, 'pc'),
555 ('CSS_DEG', self._prods.DIMENSION, 'deg'),
556 ('CSS_RAD', self._prods.DIMENSION, 'rad'),
557 ('CSS_GRAD', self._prods.DIMENSION, 'grad'),
558 ('CSS_MS', self._prods.DIMENSION, 'ms'),
559 ('CSS_S', self._prods.DIMENSION, 's'),
560 ('CSS_HZ', self._prods.DIMENSION, 'hz'),
561 ('CSS_KHZ', self._prods.DIMENSION, 'khz'),
562 ('CSS_DIMENSION', self._prods.DIMENSION, None),
563 ('CSS_STRING', self._prods.STRING, None),
564 ('CSS_URI', self._prods.URI, None),
565 ('CSS_IDENT', self._prods.IDENT, None),
566 ('CSS_ATTR', self._prods.FUNCTION, 'attr('),
567 ('CSS_COUNTER', self._prods.FUNCTION, 'counter('),
568 ('CSS_RECT', self._prods.FUNCTION, 'rect('),
569 ('CSS_RGBCOLOR', self._prods.FUNCTION, 'rgb('),
570 ('CSS_RGBACOLOR', self._prods.FUNCTION, 'rgba('),
571 ]
572
574 """
575 primitiveType is readonly but is set lazy if accessed
576 no value is given as self._value is used
577 """
578 primitiveType = self.CSS_UNKNOWN
579 _floatType = False
580 tokenizer = self._tokenize2(self._value)
581 t = self._nexttoken(tokenizer)
582 if not t:
583 self._log.error(u'CSSPrimitiveValue: No value.')
584
585
586 if self._tokenvalue(t) in (u'-', u'+'):
587 t = self._nexttoken(tokenizer)
588 if not t:
589 self._log.error(u'CSSPrimitiveValue: No value.')
590
591 _floatType = True
592
593
594 fontstring = 0
595 expected = 'ident or string'
596 tokenizer = self._tokenize2(self._value)
597 for token in tokenizer:
598 val, typ = self._tokenvalue(token, normalize=True), self._type(token)
599 if expected == 'ident or string' and typ in (
600 self._prods.IDENT, self._prods.STRING):
601 expected = 'comma'
602 fontstring += 1
603 elif expected == 'comma' and val == ',':
604 expected = 'ident or string'
605 fontstring += 1
606 elif typ in (self._prods.S, self._prods.COMMENT):
607 continue
608 else:
609 fontstring = False
610 break
611
612 if fontstring > 2:
613
614 primitiveType = CSSPrimitiveValue.CSS_STRING
615 elif self._type(t) == self._prods.HASH:
616
617 primitiveType = CSSPrimitiveValue.CSS_RGBCOLOR
618 else:
619 for i, (name, tokentype, search) in enumerate(self._unitinfos):
620 val, typ = self._tokenvalue(t, normalize=True), self._type(t)
621 if typ == tokentype:
622 if typ == self._prods.DIMENSION:
623 if not search:
624 primitiveType = i
625 break
626 elif re.match(ur'^[^a-z]*(%s)$' % search, val):
627 primitiveType = i
628 break
629 elif typ == self._prods.FUNCTION:
630 if not search:
631 primitiveType = i
632 break
633 elif val.startswith(search):
634 primitiveType = i
635 break
636 else:
637 primitiveType = i
638 break
639
640 if _floatType and primitiveType not in self._floattypes:
641
642 primitiveType = self.CSS_UNKNOWN
643
644 self._primitiveType = primitiveType
645
647 if not hasattr(self, '_primitivetype'):
648 self.__set_primitiveType()
649 return self._primitiveType
650
651 primitiveType = property(_getPrimitiveType,
652 doc="READONLY: The type of the value as defined by the constants specified above.")
653
656
657 primitiveTypeString = property(_getPrimitiveTypeString,
658 doc="Name of primitive type of this value.")
659
661 "get TypeString by given type which may be unknown, used by setters"
662 try:
663 return self._unitinfos[type][0]
664 except (IndexError, TypeError):
665 return u'%r (UNKNOWN TYPE)' % type
666
668 "splits self._value in numerical and dimension part"
669 try:
670 val, dim = self._reNumDim.findall(self._value)[0]
671 except IndexError:
672 val, dim = self._value, u''
673 try:
674 val = float(val)
675 except ValueError:
676 raise xml.dom.InvalidAccessErr(
677 u'CSSPrimitiveValue: No float value %r'
678 % (self._value))
679
680 return val, dim
681
683 """
684 (DOM method) This method is used to get a float value in a
685 specified unit. If this CSS value doesn't contain a float value
686 or can't be converted into the specified unit, a DOMException
687 is raised.
688
689 unitType
690 to get the float value. The unit code can only be a float unit type
691 (i.e. CSS_NUMBER, CSS_PERCENTAGE, CSS_EMS, CSS_EXS, CSS_PX, CSS_CM,
692 CSS_MM, CSS_IN, CSS_PT, CSS_PC, CSS_DEG, CSS_RAD, CSS_GRAD, CSS_MS,
693 CSS_S, CSS_HZ, CSS_KHZ, CSS_DIMENSION).
694
695 returns not necessarily a float but some cases just an int
696 e.g. if the value is ``1px`` it return ``1`` and **not** ``1.0``
697
698 conversions might return strange values like 1.000000000001
699 """
700 if unitType not in self._floattypes:
701 raise xml.dom.InvalidAccessErr(
702 u'unitType Parameter is not a float type')
703
704 val, dim = self.__getValDim()
705
706 if self.primitiveType != unitType:
707 try:
708 val = self._converter[self.primitiveType, unitType](val)
709 except KeyError:
710 raise xml.dom.InvalidAccessErr(
711 u'CSSPrimitiveValue: Cannot coerce primitiveType %r to %r'
712 % (self.primitiveTypeString,
713 self._getCSSPrimitiveTypeString(unitType)))
714
715 if val == int(val):
716 val = int(val)
717
718 return val
719
721 """
722 (DOM method) A method to set the float value with a specified unit.
723 If the property attached with this value can not accept the
724 specified unit or the float value, the value will be unchanged and
725 a DOMException will be raised.
726
727 unitType
728 a unit code as defined above. The unit code can only be a float
729 unit type
730 floatValue
731 the new float value which does not have to be a float value but
732 may simple be an int e.g. if setting::
733
734 setFloatValue(CSS_PX, 1)
735
736 raises DOMException
737 - INVALID_ACCESS_ERR: Raised if the attached property doesn't
738 support the float value or the unit type.
739 - NO_MODIFICATION_ALLOWED_ERR: Raised if this property is readonly.
740 """
741 self._checkReadonly()
742 if unitType not in self._floattypes:
743 raise xml.dom.InvalidAccessErr(
744 u'CSSPrimitiveValue: unitType %r is not a float type' %
745 self._getCSSPrimitiveTypeString(unitType))
746 try:
747 val = float(floatValue)
748 except ValueError, e:
749 raise xml.dom.InvalidAccessErr(
750 u'CSSPrimitiveValue: floatValue %r is not a float' %
751 floatValue)
752
753 oldval, dim = self.__getValDim()
754
755 if self.primitiveType != unitType:
756
757 try:
758 val = self._converter[
759 unitType, self.primitiveType](val)
760 except KeyError:
761 raise xml.dom.InvalidAccessErr(
762 u'CSSPrimitiveValue: Cannot coerce primitiveType %r to %r'
763 % (self.primitiveTypeString,
764 self._getCSSPrimitiveTypeString(unitType)))
765
766 if val == int(val):
767 val = int(val)
768
769 self.cssText = '%s%s' % (val, dim)
770
797
799 """
800 (DOM method) A method to set the string value with the specified
801 unit. If the property attached to this value can't accept the
802 specified unit or the string value, the value will be unchanged and
803 a DOMException will be raised.
804
805 stringType
806 a string code as defined above. The string code can only be a
807 string unit type (i.e. CSS_STRING, CSS_URI, CSS_IDENT, and
808 CSS_ATTR).
809 stringValue
810 the new string value
811 Only the actual value is expected so for (CSS_URI, "a") the
812 new value will be ``url(a)``. For (CSS_STRING, "'a'")
813 the new value will be ``"\\'a\\'"`` as the surrounding ``'`` are
814 not part of the string value
815
816 raises
817 DOMException
818
819 - INVALID_ACCESS_ERR: Raised if the CSS value doesn't contain a
820 string value or if the string value can't be converted into
821 the specified unit.
822
823 - NO_MODIFICATION_ALLOWED_ERR: Raised if this property is readonly.
824 """
825 self._checkReadonly()
826
827 if self.primitiveType not in self._stringtypes:
828 raise xml.dom.InvalidAccessErr(
829 u'CSSPrimitiveValue %r is not a string type'
830 % self.primitiveTypeString)
831
832 if stringType not in self._stringtypes:
833 raise xml.dom.InvalidAccessErr(
834 u'CSSPrimitiveValue: stringType %s is not a string type'
835 % self._getCSSPrimitiveTypeString(stringType))
836
837 if self._primitiveType != stringType:
838 raise xml.dom.InvalidAccessErr(
839 u'CSSPrimitiveValue: Cannot coerce primitiveType %r to %r'
840 % (self.primitiveTypeString,
841 self._getCSSPrimitiveTypeString(stringType)))
842
843 if CSSPrimitiveValue.CSS_STRING == self._primitiveType:
844 self.cssText = u'"%s"' % stringValue.replace(u'"', ur'\\"')
845 elif CSSPrimitiveValue.CSS_URI == self._primitiveType:
846
847
848
849
850
851
852
853 if u'(' in stringValue or\
854 u')' in stringValue or\
855 u',' in stringValue or\
856 u'"' in stringValue or\
857 u'\'' in stringValue or\
858 u'\n' in stringValue or\
859 u'\t' in stringValue or\
860 u'\r' in stringValue or\
861 u'\f' in stringValue or\
862 u' ' in stringValue:
863 stringValue = '"%s"' % stringValue.replace(u'"', ur'\"')
864 self.cssText = u'url(%s)' % stringValue
865 elif CSSPrimitiveValue.CSS_ATTR == self._primitiveType:
866 self.cssText = u'attr(%s)' % stringValue
867 else:
868 self.cssText = stringValue
869 self._primitiveType = stringType
870
872 """
873 (DOM method) This method is used to get the Counter value. If
874 this CSS value doesn't contain a counter value, a DOMException
875 is raised. Modification to the corresponding style property
876 can be achieved using the Counter interface.
877 """
878 if not self.CSS_COUNTER == self.primitiveType:
879 raise xml.dom.InvalidAccessErr(u'Value is not a counter type')
880
881 raise NotImplementedError()
882
884 """
885 (DOM method) This method is used to get the RGB color. If this
886 CSS value doesn't contain a RGB color value, a DOMException
887 is raised. Modification to the corresponding style property
888 can be achieved using the RGBColor interface.
889 """
890
891 if self.primitiveType not in self._rbgtypes:
892 raise xml.dom.InvalidAccessErr(u'Value is not a RGB value')
893
894 raise NotImplementedError()
895
897 """
898 (DOM method) This method is used to get the Rect value. If this CSS
899 value doesn't contain a rect value, a DOMException is raised.
900 Modification to the corresponding style property can be achieved
901 using the Rect interface.
902 """
903 if self.primitiveType not in self._recttypes:
904 raise xml.dom.InvalidAccessErr(u'value is not a Rect value')
905
906 raise NotImplementedError()
907
909 return "<cssutils.css.%s object primitiveType=%s cssText=%r _propertyName=%r valid=%r at 0x%x>" % (
910 self.__class__.__name__, self.primitiveTypeString,
911 self.cssText, self._propertyName, self.valid, id(self))
912
913
915 """
916 The CSSValueList interface provides the abstraction of an ordered
917 collection of CSS values.
918
919 Some properties allow an empty list into their syntax. In that case,
920 these properties take the none identifier. So, an empty list means
921 that the property has the value none.
922
923 The items in the CSSValueList are accessible via an integral index,
924 starting from 0.
925 """
926 cssValueType = CSSValue.CSS_VALUE_LIST
927
928 - def __init__(self, cssText=None, readonly=False, _propertyName=None):
936
938 "called by CSSValue if newly identified as CSSValueList"
939
940 ivalueseq, valueseq = 0, self._SHORTHANDPROPERTIES.get(
941 self._propertyName, [])
942 self._items = []
943 newseq = []
944 i, max = 0, len(self.seq)
945 minus = None
946 while i < max:
947 v = self.seq[i]
948
949 if u'-' == v:
950 if minus:
951 self._log.error(
952 u'CSSValueList: Unknown syntax: %r.'
953 % u''.join(self.seq))
954 else:
955 minus = v
956
957 elif isinstance(v, basestring) and not v.strip() == u'' and\
958 not u'/' == v:
959 if minus:
960 v = minus + v
961 minus = None
962
963
964 if ivalueseq < len(valueseq):
965 propname, mandatory = valueseq[ivalueseq]
966 if mandatory:
967 ivalueseq += 1
968 else:
969 propname = None
970 ivalueseq = len(valueseq)
971 else:
972 propname = self._propertyName
973
974
975 if propname in self._SHORTHANDPROPERTIES:
976 propname = None
977
978 if i+1 < max and self.seq[i+1] == u',':
979
980
981 fullvalue = [v]
982
983 expected = 'comma'
984 for j in range(i+1, max):
985 testv = self.seq[j]
986 if u' ' == testv:
987 break
988 elif testv in ('-', '+') and expected == 'value':
989
990 fullvalue.append(testv)
991 expected = 'value'
992 elif u',' == testv and expected == 'comma':
993 fullvalue.append(testv)
994 expected = 'value'
995 elif u',' != testv and expected == 'value':
996 fullvalue.append(testv)
997 expected = 'comma'
998 else:
999 self._log.error(
1000 u'CSSValueList: Unknown syntax: %r.'
1001 % testv)
1002 return
1003 if expected == 'value':
1004 self._log.error(
1005 u'CSSValueList: Unknown syntax: %r.'
1006 % u''.join(self.seq))
1007 return
1008
1009
1010 i += len(fullvalue) - 1
1011 o = CSSValue(cssText=u''.join(fullvalue),
1012 _propertyName=propname)
1013 else:
1014
1015 o = CSSValue(cssText=v, _propertyName=propname)
1016
1017 self._items.append(o)
1018 newseq.append(o)
1019
1020 else:
1021
1022 newseq.append(v)
1023
1024 i += 1
1025
1026 self.seq = newseq
1027
1028 length = property(lambda self: len(self._items),
1029 doc="(DOM attribute) The number of CSSValues in the list.")
1030
1031 - def item(self, index):
1032 """
1033 (DOM method) Used to retrieve a CSSValue by ordinal index. The
1034 order in this collection represents the order of the values in the
1035 CSS style property. If index is greater than or equal to the number
1036 of values in the list, this returns None.
1037 """
1038 try:
1039 return self._items[index]
1040 except IndexError:
1041 return None
1042
1046
1048 "the iterator"
1049 for i in range (0, self.length):
1050 yield self.item(i)
1051
1053 return "<cssutils.css.%s object length=%s at 0x%x>" % (
1054 self.__class__.__name__, self.length, id(self))
1055