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