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