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 1228 2008-05-19 19:59:50Z 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 'operator' == expected:
250
251 val = self._tokenvalue(token)
252 if new['values'] and new['values'][-1] in (u'-', u'+'):
253 new['values'][-1] += val
254 else:
255 new['values'].append(u' ')
256 seq.append(u' ')
257 new['values'].append(val)
258 seq.append(val)
259 return 'operator'
260 elif expected in ('funcend', ')', ']', '}'):
261
262 seq[-1] += self._tokenvalue(token)
263 return expected
264 else:
265 new['wellformed'] = False
266 self._log.error(u'CSSValue: Unexpected token.', token)
267 return expected
268
269 def _string_ident_uri_hexcolor(expected, seq, token, tokenizer=None):
270
271 if expected.startswith('term'):
272
273
274
275 typ = self._type(token)
276 if self._prods.STRING == typ:
277 val = u'"%s"' % self._stringtokenvalue(token)
278
279
280 else:
281 val = self._tokenvalue(token)
282
283 new['values'].append(val)
284 seq.append(val)
285 return 'operator'
286 elif 'operator' == expected:
287
288
289
290 typ = self._type(token)
291 if self._prods.STRING == typ:
292 val = u'"%s"' % self._stringtokenvalue(token)
293
294
295 else:
296 val = self._tokenvalue(token)
297 new['values'].append(u' ')
298 new['values'].append(val)
299 seq.append(u' ')
300 seq.append(val)
301 return 'operator'
302 elif expected in ('funcend', ')', ']', '}'):
303
304 seq[-1] += self._tokenvalue(token)
305 return expected
306 else:
307 new['wellformed'] = False
308 self._log.error(u'CSSValue: Unexpected token.', token)
309 return expected
310
311 def _function(expected, seq, token, tokenizer=None):
312
313 if expected.startswith('term'):
314
315 seq.append(self._tokenvalue(token))
316 return 'funcend'
317 elif 'operator' == expected:
318
319 seq.append(u' ')
320 seq.append(self._tokenvalue(token))
321 return 'funcend'
322 elif expected in ('funcend', ')', ']', '}'):
323
324 seq[-1] += self._tokenvalue(token)
325 return expected
326 else:
327 new['wellformed'] = False
328 self._log.error(u'CSSValue: Unexpected token.', token)
329 return expected
330
331 tokenizer = self._tokenize2(cssText)
332
333 linetoken = self._nexttoken(tokenizer)
334 if not linetoken:
335 self._log.error(u'CSSValue: Unknown syntax or no value: %r.' %
336 self._valuestr(cssText))
337 else:
338
339 tokenizer = self._tokenize2(cssText)
340 newseq = []
341 wellformed, expected = self._parse(expected='term',
342 seq=newseq, tokenizer=tokenizer,
343 productions={'S': _S,
344 'CHAR': _char,
345
346 'NUMBER': _number_percentage_dimension,
347 'PERCENTAGE': _number_percentage_dimension,
348 'DIMENSION': _number_percentage_dimension,
349
350 'STRING': _string_ident_uri_hexcolor,
351 'IDENT': _string_ident_uri_hexcolor,
352 'URI': _string_ident_uri_hexcolor,
353 'HASH': _string_ident_uri_hexcolor,
354 'UNICODE-RANGE': _string_ident_uri_hexcolor,
355
356 'FUNCTION': _function
357 })
358
359 wellformed = wellformed and new['wellformed']
360
361
362 if expected.startswith('term') and newseq and newseq[-1] != u' ' or (
363 expected in ('funcend', ')', ']', '}')):
364 wellformed = False
365 self._log.error(u'CSSValue: Incomplete value: %r.' %
366 self._valuestr(cssText))
367
368 if not new['values']:
369 wellformed = False
370 self._log.error(u'CSSValue: Unknown syntax or no value: %r.' %
371 self._valuestr(cssText))
372
373 else:
374 self._linetoken = linetoken
375 self.seq = newseq
376 self.valid = False
377
378 self._validate()
379
380 if len(new['values']) == 1 and new['values'][0] == u'inherit':
381 self._value = u'inherit'
382 self._cssValueType = CSSValue.CSS_INHERIT
383 self.__class__ = CSSValue
384 elif len(new['values']) == 1:
385 self.__class__ = CSSPrimitiveValue
386 self._init()
387 elif len(new['values']) > 1 and\
388 len(new['values']) == new['commas'] + 1:
389
390 self.__class__ = CSSPrimitiveValue
391 self._init()
392 elif len(new['values']) > 1:
393
394 self.__class__ = CSSValueList
395 self._init()
396 else:
397 self._cssValueType = CSSValue.CSS_CUSTOM
398 self.__class__ = CSSValue
399
400 self.wellformed = wellformed
401
402 cssText = property(_getCssText, _setCssText,
403 doc="A string representation of the current value.")
404
406 if hasattr(self, '_cssValueType'):
407 return self._cssValueType
408
409 cssValueType = property(_getCssValueType,
410 doc="A (readonly) code defining the type of the value as defined above.")
411
418
419 cssValueTypeString = property(_getCssValueTypeString,
420 doc="cssutils: Name of cssValueType of this CSSValue (readonly).")
421
439
441 return self.__propertyName
442
446
447 _propertyName = property(_get_propertyName, _set_propertyName,
448 doc="cssutils: Property this values is validated against")
449
451 return "cssutils.css.%s(%r, _propertyName=%r)" % (
452 self.__class__.__name__, self.cssText, self._propertyName)
453
455 return "<cssutils.css.%s object cssValueType=%r cssText=%r propname=%r valid=%r at 0x%x>" % (
456 self.__class__.__name__, self.cssValueTypeString,
457 self.cssText, self._propertyName, self.valid, id(self))
458
459
461 """
462 represents a single CSS Value. May be used to determine the value of a
463 specific style property currently set in a block or to set a specific
464 style property explicitly within the block. Might be obtained from the
465 getPropertyCSSValue method of CSSStyleDeclaration.
466
467 Conversions are allowed between absolute values (from millimeters to
468 centimeters, from degrees to radians, and so on) but not between
469 relative values. (For example, a pixel value cannot be converted to a
470 centimeter value.) Percentage values can't be converted since they are
471 relative to the parent value (or another property value). There is one
472 exception for color percentage values: since a color percentage value
473 is relative to the range 0-255, a color percentage value can be
474 converted to a number; (see also the RGBColor interface).
475 """
476
477 cssValueType = CSSValue.CSS_PRIMITIVE_VALUE
478
479
480 CSS_UNKNOWN = 0
481 CSS_NUMBER = 1
482 CSS_PERCENTAGE = 2
483 CSS_EMS = 3
484 CSS_EXS = 4
485 CSS_PX = 5
486 CSS_CM = 6
487 CSS_MM = 7
488 CSS_IN = 8
489 CSS_PT = 9
490 CSS_PC = 10
491 CSS_DEG = 11
492 CSS_RAD = 12
493 CSS_GRAD = 13
494 CSS_MS = 14
495 CSS_S = 15
496 CSS_HZ = 16
497 CSS_KHZ = 17
498 CSS_DIMENSION = 18
499 CSS_STRING = 19
500 CSS_URI = 20
501 CSS_IDENT = 21
502 CSS_ATTR = 22
503 CSS_COUNTER = 23
504 CSS_RECT = 24
505 CSS_RGBCOLOR = 25
506
507 CSS_RGBACOLOR = 26
508
509 _floattypes = [CSS_NUMBER, CSS_PERCENTAGE, CSS_EMS, CSS_EXS,
510 CSS_PX, CSS_CM, CSS_MM, CSS_IN, CSS_PT, CSS_PC,
511 CSS_DEG, CSS_RAD, CSS_GRAD, CSS_MS, CSS_S,
512 CSS_HZ, CSS_KHZ, CSS_DIMENSION
513 ]
514 _stringtypes = [CSS_ATTR, CSS_IDENT, CSS_STRING, CSS_URI]
515 _countertypes = [CSS_COUNTER]
516 _recttypes = [CSS_RECT]
517 _rbgtypes = [CSS_RGBCOLOR, CSS_RGBACOLOR]
518
519 _reNumDim = re.compile(ur'^(.*?)([a-z]+|%)$', re.I| re.U|re.X)
520
521
522 _converter = {
523
524
525
526 (CSS_CM, CSS_MM): lambda x: x * 10,
527 (CSS_MM, CSS_CM): lambda x: x / 10,
528
529 (CSS_PT, CSS_PC): lambda x: x * 12,
530 (CSS_PC, CSS_PT): lambda x: x / 12,
531
532 (CSS_CM, CSS_IN): lambda x: x / 2.54,
533 (CSS_IN, CSS_CM): lambda x: x * 2.54,
534 (CSS_MM, CSS_IN): lambda x: x / 25.4,
535 (CSS_IN, CSS_MM): lambda x: x * 25.4,
536
537 (CSS_IN, CSS_PT): lambda x: x / 72,
538 (CSS_PT, CSS_IN): lambda x: x * 72,
539 (CSS_CM, CSS_PT): lambda x: x / 2.54 / 72,
540 (CSS_PT, CSS_CM): lambda x: x * 72 * 2.54,
541 (CSS_MM, CSS_PT): lambda x: x / 25.4 / 72,
542 (CSS_PT, CSS_MM): lambda x: x * 72 * 25.4,
543
544 (CSS_IN, CSS_PC): lambda x: x / 72 / 12,
545 (CSS_PC, CSS_IN): lambda x: x * 12 * 72,
546 (CSS_CM, CSS_PC): lambda x: x / 2.54 / 72 / 12,
547 (CSS_PC, CSS_CM): lambda x: x * 12 * 72 * 2.54,
548 (CSS_MM, CSS_PC): lambda x: x / 25.4 / 72 / 12,
549 (CSS_PC, CSS_MM): lambda x: x * 12 * 72 * 25.4,
550
551
552 (CSS_KHZ, CSS_HZ): lambda x: x * 1000,
553 (CSS_HZ, CSS_KHZ): lambda x: x / 1000,
554
555 (CSS_S, CSS_MS): lambda x: x * 1000,
556 (CSS_MS, CSS_S): lambda x: x / 1000
557
558
559 }
560
561 - def __init__(self, cssText=None, readonly=False, _propertyName=None):
572
574
575 self._unitinfos = [
576 ('CSS_UNKNOWN', None, None),
577 ('CSS_NUMBER', self._prods.NUMBER, None),
578 ('CSS_PERCENTAGE', self._prods.PERCENTAGE, None),
579 ('CSS_EMS', self._prods.DIMENSION, 'em'),
580 ('CSS_EXS', self._prods.DIMENSION, 'ex'),
581 ('CSS_PX', self._prods.DIMENSION, 'px'),
582 ('CSS_CM', self._prods.DIMENSION, 'cm'),
583 ('CSS_MM', self._prods.DIMENSION, 'mm'),
584 ('CSS_IN', self._prods.DIMENSION, 'in'),
585 ('CSS_PT', self._prods.DIMENSION, 'pt'),
586 ('CSS_PC', self._prods.DIMENSION, 'pc'),
587 ('CSS_DEG', self._prods.DIMENSION, 'deg'),
588 ('CSS_RAD', self._prods.DIMENSION, 'rad'),
589 ('CSS_GRAD', self._prods.DIMENSION, 'grad'),
590 ('CSS_MS', self._prods.DIMENSION, 'ms'),
591 ('CSS_S', self._prods.DIMENSION, 's'),
592 ('CSS_HZ', self._prods.DIMENSION, 'hz'),
593 ('CSS_KHZ', self._prods.DIMENSION, 'khz'),
594 ('CSS_DIMENSION', self._prods.DIMENSION, None),
595 ('CSS_STRING', self._prods.STRING, None),
596 ('CSS_URI', self._prods.URI, None),
597 ('CSS_IDENT', self._prods.IDENT, None),
598 ('CSS_ATTR', self._prods.FUNCTION, 'attr('),
599 ('CSS_COUNTER', self._prods.FUNCTION, 'counter('),
600 ('CSS_RECT', self._prods.FUNCTION, 'rect('),
601 ('CSS_RGBCOLOR', self._prods.FUNCTION, 'rgb('),
602 ('CSS_RGBACOLOR', self._prods.FUNCTION, 'rgba('),
603 ]
604
606 """
607 primitiveType is readonly but is set lazy if accessed
608 no value is given as self._value is used
609 """
610 primitiveType = self.CSS_UNKNOWN
611 _floatType = False
612 tokenizer = self._tokenize2(self._value)
613 t = self._nexttoken(tokenizer)
614 if not t:
615 self._log.error(u'CSSPrimitiveValue: No value.')
616
617
618 if self._tokenvalue(t) in (u'-', u'+'):
619 t = self._nexttoken(tokenizer)
620 if not t:
621 self._log.error(u'CSSPrimitiveValue: No value.')
622
623 _floatType = True
624
625
626 fontstring = 0
627 expected = 'ident or string'
628 tokenizer = self._tokenize2(self._value)
629 for token in tokenizer:
630 val, typ = self._tokenvalue(token, normalize=True), self._type(token)
631 if expected == 'ident or string' and typ in (
632 self._prods.IDENT, self._prods.STRING):
633 expected = 'comma'
634 fontstring += 1
635 elif expected == 'comma' and val == ',':
636 expected = 'ident or string'
637 fontstring += 1
638 elif typ in (self._prods.S, self._prods.COMMENT):
639 continue
640 else:
641 fontstring = False
642 break
643
644 if fontstring > 2:
645
646 primitiveType = CSSPrimitiveValue.CSS_STRING
647 elif self._type(t) == self._prods.HASH:
648
649 primitiveType = CSSPrimitiveValue.CSS_RGBCOLOR
650 else:
651 for i, (name, tokentype, search) in enumerate(self._unitinfos):
652 val, typ = self._tokenvalue(t, normalize=True), self._type(t)
653 if typ == tokentype:
654 if typ == self._prods.DIMENSION:
655 if not search:
656 primitiveType = i
657 break
658 elif re.match(ur'^[^a-z]*(%s)$' % search, val):
659 primitiveType = i
660 break
661 elif typ == self._prods.FUNCTION:
662 if not search:
663 primitiveType = i
664 break
665 elif val.startswith(search):
666 primitiveType = i
667 break
668 else:
669 primitiveType = i
670 break
671
672 if _floatType and primitiveType not in self._floattypes:
673
674 primitiveType = self.CSS_UNKNOWN
675
676 self._primitiveType = primitiveType
677
679 if not hasattr(self, '_primitivetype'):
680 self.__set_primitiveType()
681 return self._primitiveType
682
683 primitiveType = property(_getPrimitiveType,
684 doc="READONLY: The type of the value as defined by the constants specified above.")
685
688
689 primitiveTypeString = property(_getPrimitiveTypeString,
690 doc="Name of primitive type of this value.")
691
693 "get TypeString by given type which may be unknown, used by setters"
694 try:
695 return self._unitinfos[type][0]
696 except (IndexError, TypeError):
697 return u'%r (UNKNOWN TYPE)' % type
698
700 "splits self._value in numerical and dimension part"
701 try:
702 val, dim = self._reNumDim.findall(self._value)[0]
703 except IndexError:
704 val, dim = self._value, u''
705 try:
706 val = float(val)
707 except ValueError:
708 raise xml.dom.InvalidAccessErr(
709 u'CSSPrimitiveValue: No float value %r'
710 % (self._value))
711
712 return val, dim
713
715 """
716 (DOM method) This method is used to get a float value in a
717 specified unit. If this CSS value doesn't contain a float value
718 or can't be converted into the specified unit, a DOMException
719 is raised.
720
721 unitType
722 to get the float value. The unit code can only be a float unit type
723 (i.e. CSS_NUMBER, CSS_PERCENTAGE, CSS_EMS, CSS_EXS, CSS_PX, CSS_CM,
724 CSS_MM, CSS_IN, CSS_PT, CSS_PC, CSS_DEG, CSS_RAD, CSS_GRAD, CSS_MS,
725 CSS_S, CSS_HZ, CSS_KHZ, CSS_DIMENSION).
726
727 returns not necessarily a float but some cases just an int
728 e.g. if the value is ``1px`` it return ``1`` and **not** ``1.0``
729
730 conversions might return strange values like 1.000000000001
731 """
732 if unitType not in self._floattypes:
733 raise xml.dom.InvalidAccessErr(
734 u'unitType Parameter is not a float type')
735
736 val, dim = self.__getValDim()
737
738 if self.primitiveType != unitType:
739 try:
740 val = self._converter[self.primitiveType, unitType](val)
741 except KeyError:
742 raise xml.dom.InvalidAccessErr(
743 u'CSSPrimitiveValue: Cannot coerce primitiveType %r to %r'
744 % (self.primitiveTypeString,
745 self._getCSSPrimitiveTypeString(unitType)))
746
747 if val == int(val):
748 val = int(val)
749
750 return val
751
753 """
754 (DOM method) A method to set the float value with a specified unit.
755 If the property attached with this value can not accept the
756 specified unit or the float value, the value will be unchanged and
757 a DOMException will be raised.
758
759 unitType
760 a unit code as defined above. The unit code can only be a float
761 unit type
762 floatValue
763 the new float value which does not have to be a float value but
764 may simple be an int e.g. if setting::
765
766 setFloatValue(CSS_PX, 1)
767
768 raises DOMException
769 - INVALID_ACCESS_ERR: Raised if the attached property doesn't
770 support the float value or the unit type.
771 - NO_MODIFICATION_ALLOWED_ERR: Raised if this property is readonly.
772 """
773 self._checkReadonly()
774 if unitType not in self._floattypes:
775 raise xml.dom.InvalidAccessErr(
776 u'CSSPrimitiveValue: unitType %r is not a float type' %
777 self._getCSSPrimitiveTypeString(unitType))
778 try:
779 val = float(floatValue)
780 except ValueError, e:
781 raise xml.dom.InvalidAccessErr(
782 u'CSSPrimitiveValue: floatValue %r is not a float' %
783 floatValue)
784
785 oldval, dim = self.__getValDim()
786
787 if self.primitiveType != unitType:
788
789 try:
790 val = self._converter[
791 unitType, self.primitiveType](val)
792 except KeyError:
793 raise xml.dom.InvalidAccessErr(
794 u'CSSPrimitiveValue: Cannot coerce primitiveType %r to %r'
795 % (self.primitiveTypeString,
796 self._getCSSPrimitiveTypeString(unitType)))
797
798 if val == int(val):
799 val = int(val)
800
801 self.cssText = '%s%s' % (val, dim)
802
829
831 """
832 (DOM method) A method to set the string value with the specified
833 unit. If the property attached to this value can't accept the
834 specified unit or the string value, the value will be unchanged and
835 a DOMException will be raised.
836
837 stringType
838 a string code as defined above. The string code can only be a
839 string unit type (i.e. CSS_STRING, CSS_URI, CSS_IDENT, and
840 CSS_ATTR).
841 stringValue
842 the new string value
843 Only the actual value is expected so for (CSS_URI, "a") the
844 new value will be ``url(a)``. For (CSS_STRING, "'a'")
845 the new value will be ``"\\'a\\'"`` as the surrounding ``'`` are
846 not part of the string value
847
848 raises
849 DOMException
850
851 - INVALID_ACCESS_ERR: Raised if the CSS value doesn't contain a
852 string value or if the string value can't be converted into
853 the specified unit.
854
855 - NO_MODIFICATION_ALLOWED_ERR: Raised if this property is readonly.
856 """
857 self._checkReadonly()
858
859 if self.primitiveType not in self._stringtypes:
860 raise xml.dom.InvalidAccessErr(
861 u'CSSPrimitiveValue %r is not a string type'
862 % self.primitiveTypeString)
863
864 if stringType not in self._stringtypes:
865 raise xml.dom.InvalidAccessErr(
866 u'CSSPrimitiveValue: stringType %s is not a string type'
867 % self._getCSSPrimitiveTypeString(stringType))
868
869 if self._primitiveType != stringType:
870 raise xml.dom.InvalidAccessErr(
871 u'CSSPrimitiveValue: Cannot coerce primitiveType %r to %r'
872 % (self.primitiveTypeString,
873 self._getCSSPrimitiveTypeString(stringType)))
874
875 if CSSPrimitiveValue.CSS_STRING == self._primitiveType:
876 self.cssText = u'"%s"' % stringValue.replace(u'"', ur'\\"')
877 elif CSSPrimitiveValue.CSS_URI == self._primitiveType:
878
879
880
881
882
883
884
885 if u'(' in stringValue or\
886 u')' in stringValue or\
887 u',' in stringValue or\
888 u'"' in stringValue or\
889 u'\'' in stringValue or\
890 u'\n' in stringValue or\
891 u'\t' in stringValue or\
892 u'\r' in stringValue or\
893 u'\f' in stringValue or\
894 u' ' in stringValue:
895 stringValue = '"%s"' % stringValue.replace(u'"', ur'\"')
896 self.cssText = u'url(%s)' % stringValue
897 elif CSSPrimitiveValue.CSS_ATTR == self._primitiveType:
898 self.cssText = u'attr(%s)' % stringValue
899 else:
900 self.cssText = stringValue
901 self._primitiveType = stringType
902
904 """
905 (DOM method) This method is used to get the Counter value. If
906 this CSS value doesn't contain a counter value, a DOMException
907 is raised. Modification to the corresponding style property
908 can be achieved using the Counter interface.
909 """
910 if not self.CSS_COUNTER == self.primitiveType:
911 raise xml.dom.InvalidAccessErr(u'Value is not a counter type')
912
913 raise NotImplementedError()
914
916 """
917 (DOM method) This method is used to get the RGB color. If this
918 CSS value doesn't contain a RGB color value, a DOMException
919 is raised. Modification to the corresponding style property
920 can be achieved using the RGBColor interface.
921 """
922
923 if self.primitiveType not in self._rbgtypes:
924 raise xml.dom.InvalidAccessErr(u'Value is not a RGB value')
925
926 raise NotImplementedError()
927
929 """
930 (DOM method) This method is used to get the Rect value. If this CSS
931 value doesn't contain a rect value, a DOMException is raised.
932 Modification to the corresponding style property can be achieved
933 using the Rect interface.
934 """
935 if self.primitiveType not in self._recttypes:
936 raise xml.dom.InvalidAccessErr(u'value is not a Rect value')
937
938 raise NotImplementedError()
939
941 return "<cssutils.css.%s object primitiveType=%s cssText=%r _propertyName=%r valid=%r at 0x%x>" % (
942 self.__class__.__name__, self.primitiveTypeString,
943 self.cssText, self._propertyName, self.valid, id(self))
944
945
947 """
948 The CSSValueList interface provides the abstraction of an ordered
949 collection of CSS values.
950
951 Some properties allow an empty list into their syntax. In that case,
952 these properties take the none identifier. So, an empty list means
953 that the property has the value none.
954
955 The items in the CSSValueList are accessible via an integral index,
956 starting from 0.
957 """
958 cssValueType = CSSValue.CSS_VALUE_LIST
959
960 - def __init__(self, cssText=None, readonly=False, _propertyName=None):
968
970 "called by CSSValue if newly identified as CSSValueList"
971
972 ivalueseq, valueseq = 0, self._SHORTHANDPROPERTIES.get(
973 self._propertyName, [])
974 self._items = []
975 newseq = []
976 i, max = 0, len(self.seq)
977 minus = None
978 while i < max:
979 v = self.seq[i]
980
981 if u'-' == v:
982 if minus:
983 self._log.error(
984 u'CSSValueList: Unknown syntax: %r.'
985 % u''.join(self.seq))
986 else:
987 minus = v
988
989 elif isinstance(v, basestring) and not v.strip() == u'' and\
990 not u'/' == v:
991 if minus:
992 v = minus + v
993 minus = None
994
995
996 if ivalueseq < len(valueseq):
997 propname, mandatory = valueseq[ivalueseq]
998 if mandatory:
999 ivalueseq += 1
1000 else:
1001 propname = None
1002 ivalueseq = len(valueseq)
1003 else:
1004 propname = self._propertyName
1005
1006
1007 if propname in self._SHORTHANDPROPERTIES:
1008 propname = None
1009
1010 if i+1 < max and self.seq[i+1] == u',':
1011
1012
1013 fullvalue = [v]
1014
1015 expected = 'comma'
1016 for j in range(i+1, max):
1017 testv = self.seq[j]
1018 if u' ' == testv:
1019 break
1020 elif testv in ('-', '+') and expected == 'value':
1021
1022 fullvalue.append(testv)
1023 expected = 'value'
1024 elif u',' == testv and expected == 'comma':
1025 fullvalue.append(testv)
1026 expected = 'value'
1027 elif u',' != testv and expected == 'value':
1028 fullvalue.append(testv)
1029 expected = 'comma'
1030 else:
1031 self._log.error(
1032 u'CSSValueList: Unknown syntax: %r.'
1033 % testv)
1034 return
1035 if expected == 'value':
1036 self._log.error(
1037 u'CSSValueList: Unknown syntax: %r.'
1038 % u''.join(self.seq))
1039 return
1040
1041
1042 i += len(fullvalue) - 1
1043 o = CSSValue(cssText=u''.join(fullvalue),
1044 _propertyName=propname)
1045 else:
1046
1047 o = CSSValue(cssText=v, _propertyName=propname)
1048
1049 self._items.append(o)
1050 newseq.append(o)
1051
1052 else:
1053
1054 newseq.append(v)
1055
1056 i += 1
1057
1058 self.seq = newseq
1059
1060 length = property(lambda self: len(self._items),
1061 doc="(DOM attribute) The number of CSSValues in the list.")
1062
1063 - def item(self, index):
1064 """
1065 (DOM method) Used to retrieve a CSSValue by ordinal index. The
1066 order in this collection represents the order of the values in the
1067 CSS style property. If index is greater than or equal to the number
1068 of values in the list, this returns None.
1069 """
1070 try:
1071 return self._items[index]
1072 except IndexError:
1073 return None
1074
1078
1080 "the iterator"
1081 for i in range (0, self.length):
1082 yield self.item(i)
1083
1085 return "<cssutils.css.%s object length=%s at 0x%x>" % (
1086 self.__class__.__name__, self.length, id(self))
1087