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