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: 2007-11-24 23:32:10 +0100 (Sa, 24 Nov 2007) $'
12 __version__ = '$LastChangedRevision: 678 $'
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, aslist=True)
574 try:
575 t = tokenizer[0]
576 except IndexError:
577 self._log.error(u'CSSPrimitiveValue: No value.')
578
579
580 if self._tokenvalue(t) in (u'-', u'+'):
581 try:
582 t = tokenizer[1]
583 except IndexError:
584 self._log.error(u'CSSPrimitiveValue: No value.')
585
586 _floatType = True
587
588
589
590
591
592
593 fontstring = 0
594 expected = 'ident or string'
595 for x in tokenizer:
596 val, typ = self._tokenvalue(x, normalize=True), self._type(x)
597 if expected == 'ident or string' and typ in (
598 self._prods.IDENT, self._prods.STRING):
599 expected = 'comma'
600 fontstring += 1
601 elif expected == 'comma' and typ == self._prods.CHAR and val == ',':
602 expected = 'ident or string'
603 fontstring += 1
604 elif typ in (self._prods.S, self._prods.COMMENT):
605 continue
606 else:
607 fontstring = False
608 break
609
610 if fontstring > 2:
611
612 primitiveType = CSSPrimitiveValue.CSS_STRING
613 elif self._type(t) == self._prods.HASH:
614
615 primitiveType = CSSPrimitiveValue.CSS_RGBCOLOR
616 else:
617 for i, (name, tokentype, search) in enumerate(self._unitinfos):
618 val, typ = self._tokenvalue(t, normalize=True), self._type(t)
619 if typ == tokentype:
620 if typ == self._prods.DIMENSION:
621 if not search:
622 primitiveType = i
623 break
624 elif re.match(ur'^[^a-z]*(%s)$' % search, val):
625 primitiveType = i
626 break
627 elif typ == self._prods.FUNCTION:
628 if not search:
629 primitiveType = i
630 break
631 elif val.startswith(search):
632 primitiveType = i
633 break
634 else:
635 primitiveType = i
636 break
637
638 if _floatType and primitiveType not in self._floattypes:
639
640 primitiveType = self.CSS_UNKNOWN
641
642 self._primitiveType = primitiveType
643
645 if not hasattr(self, '_primitivetype'):
646 self.__set_primitiveType()
647 return self._primitiveType
648
649 primitiveType = property(_getPrimitiveType,
650 doc="READONLY: The type of the value as defined by the constants specified above.")
651
654
655 primitiveTypeString = property(_getPrimitiveTypeString,
656 doc="Name of primitive type of this value.")
657
659 "get TypeString by given type which may be unknown, used by setters"
660 try:
661 return self._unitinfos[type][0]
662 except (IndexError, TypeError):
663 return u'%r (UNKNOWN TYPE)' % type
664
666 "splits self._value in numerical and dimension part"
667 try:
668 val, dim = self._reNumDim.findall(self._value)[0]
669 except IndexError:
670 val, dim = self._value, u''
671 try:
672 val = float(val)
673 except ValueError:
674 raise xml.dom.InvalidAccessErr(
675 u'CSSPrimitiveValue: No float value %r'
676 % (self._value))
677
678 return val, dim
679
681 """
682 (DOM method) This method is used to get a float value in a
683 specified unit. If this CSS value doesn't contain a float value
684 or can't be converted into the specified unit, a DOMException
685 is raised.
686
687 unitType
688 to get the float value. The unit code can only be a float unit type
689 (i.e. CSS_NUMBER, CSS_PERCENTAGE, CSS_EMS, CSS_EXS, CSS_PX, CSS_CM,
690 CSS_MM, CSS_IN, CSS_PT, CSS_PC, CSS_DEG, CSS_RAD, CSS_GRAD, CSS_MS,
691 CSS_S, CSS_HZ, CSS_KHZ, CSS_DIMENSION).
692
693 returns not necessarily a float but some cases just an int
694 e.g. if the value is ``1px`` it return ``1`` and **not** ``1.0``
695
696 conversions might return strange values like 1.000000000001
697 """
698 if unitType not in self._floattypes:
699 raise xml.dom.InvalidAccessErr(
700 u'unitType Parameter is not a float type')
701
702 val, dim = self.__getValDim()
703
704 if self.primitiveType != unitType:
705 try:
706 val = self._converter[self.primitiveType, unitType](val)
707 except KeyError:
708 raise xml.dom.InvalidAccessErr(
709 u'CSSPrimitiveValue: Cannot coerce primitiveType %r to %r'
710 % (self.primitiveTypeString,
711 self._getCSSPrimitiveTypeString(unitType)))
712
713 if val == int(val):
714 val = int(val)
715
716 return val
717
719 """
720 (DOM method) A method to set the float value with a specified unit.
721 If the property attached with this value can not accept the
722 specified unit or the float value, the value will be unchanged and
723 a DOMException will be raised.
724
725 unitType
726 a unit code as defined above. The unit code can only be a float
727 unit type
728 floatValue
729 the new float value which does not have to be a float value but
730 may simple be an int e.g. if setting::
731
732 setFloatValue(CSS_PX, 1)
733
734 raises DOMException
735 - INVALID_ACCESS_ERR: Raised if the attached property doesn't
736 support the float value or the unit type.
737 - NO_MODIFICATION_ALLOWED_ERR: Raised if this property is readonly.
738 """
739 self._checkReadonly()
740 if unitType not in self._floattypes:
741 raise xml.dom.InvalidAccessErr(
742 u'CSSPrimitiveValue: unitType %r is not a float type' %
743 self._getCSSPrimitiveTypeString(unitType))
744 try:
745 val = float(floatValue)
746 except ValueError, e:
747 raise xml.dom.InvalidAccessErr(
748 u'CSSPrimitiveValue: floatValue %r is not a float' %
749 floatValue)
750
751 oldval, dim = self.__getValDim()
752
753 if self.primitiveType != unitType:
754
755 try:
756 val = self._converter[
757 unitType, self.primitiveType](val)
758 except KeyError:
759 raise xml.dom.InvalidAccessErr(
760 u'CSSPrimitiveValue: Cannot coerce primitiveType %r to %r'
761 % (self.primitiveTypeString,
762 self._getCSSPrimitiveTypeString(unitType)))
763
764 if val == int(val):
765 val = int(val)
766
767 self.cssText = '%s%s' % (val, dim)
768
770 """
771 (DOM method) This method is used to get the string value. If the
772 CSS value doesn't contain a string value, a DOMException is raised.
773
774 Some properties (like 'font-family' or 'voice-family')
775 convert a whitespace separated list of idents to a string.
776
777 Only the actual value is returned so e.g. all the following return the
778 actual value ``a``: url(a), attr(a), "a", 'a'
779 """
780 if self.primitiveType not in self._stringtypes:
781 raise xml.dom.InvalidAccessErr(
782 u'CSSPrimitiveValue %r is not a string type'
783 % self.primitiveTypeString)
784
785 if CSSPrimitiveValue.CSS_STRING == self.primitiveType:
786 return self._value[1:-1]
787 elif CSSPrimitiveValue.CSS_URI == self.primitiveType:
788 url = self._value[4:-1]
789 if url and url[0] in ('"', "'") and url[0] == url[-1]:
790 return url[1:-1]
791 else:
792 return url
793 elif CSSPrimitiveValue.CSS_ATTR == self.primitiveType:
794 return self._value[5:-1]
795 else:
796 return self._value
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 ('background', 'background-position',):
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
1029 return len(self._items)
1030
1031 length = property(_getLength,
1032 doc="(DOM attribute) The number of CSSValues in the list.")
1033
1034 - def item(self, index):
1035 """
1036 (DOM method) Used to retrieve a CSSValue by ordinal index. The
1037 order in this collection represents the order of the values in the
1038 CSS style property. If index is greater than or equal to the number
1039 of values in the list, this returns None.
1040 """
1041 try:
1042 return self._items[index]
1043 except IndexError:
1044 return None
1045
1049
1051 "the iterator"
1052 for i in range (0, self.length):
1053 yield self.item(i)
1054
1056 return "<cssutils.css.%s object length=%s at 0x%x>" % (
1057 self.__class__.__name__, self.length, id(self))
1058