Package cssutils :: Package css :: Module cssvalue
[hide private]
[frames] | no frames]

Source Code for Module cssutils.css.cssvalue

  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-09-01 18:44:48 +0200 (Sa, 01 Sep 2007) $' 
 12  __version__ = '$LastChangedRevision: 306 $' 
 13   
 14  import re 
 15  import types 
 16  import xml.dom 
 17  import cssutils 
 18  import cssproperties 
 19  from cssutils.token import Token 
 20   
21 -class CSSValue(cssutils.util.Base):
22 """ 23 The CSSValue interface represents a simple or a complex value. 24 A CSSValue object only occurs in a context of a CSS property 25 26 Properties 27 ========== 28 cssText 29 A string representation of the current value. 30 cssValueType 31 A (readonly) code defining the type of the value. 32 33 seq: a list (cssutils) 34 All parts of this style declaration including CSSComments 35 valid: boolean 36 if the value is valid at all, False for e.g. color: #1 37 38 _value 39 value without any comments, used by Property 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 _propertyName 74 used to validate this value in the context of a property 75 the name must be normalized: lowercase with no escapes 76 """ 77 super(CSSValue, self).__init__() 78 79 self.seq = [] 80 self.valid = False 81 self._value = u'' 82 self._linetoken = None # used for line report only 83 84 self._propertyName = _propertyName 85 86 if cssText is not None: # may be 0 87 self.cssText = cssText 88 89 self._readonly = readonly
90
91 - def _getValue(self):
92 v = [] 93 for x in self.seq: 94 if isinstance(x, cssutils.css.CSSComment): 95 continue 96 elif type(x) in types.StringTypes: 97 v.append(x) 98 else: # maybe CSSPrimitiveValue 99 v.append(x.cssText) 100 return u''.join(v).strip()
101
102 - def _setValue(self, value):
103 "overwritten by CSSValueList!" 104 self._valueValue = value
105 106 _value = property(_getValue, _setValue, 107 doc="Actual cssText value of this CSSValue.") 108
109 - def _getCssText(self):
110 return cssutils.ser.do_css_CSSvalue(self)
111
112 - def _setCssText(self, cssText):
113 """ 114 Format 115 ====== 116 :: 117 118 expr = value 119 : term [ operator term ]* 120 ; 121 term 122 : unary_operator? 123 [ NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* | 124 ANGLE S* | TIME S* | FREQ S* | function ] 125 | STRING S* | IDENT S* | URI S* | hexcolor 126 ; 127 function 128 : FUNCTION S* expr ')' S* 129 ; 130 /* 131 * There is a constraint on the color that it must 132 * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F]) 133 * after the "#"; e.g., "#000" is OK, but "#abcd" is not. 134 */ 135 hexcolor 136 : HASH S* 137 ; 138 139 DOMException on setting 140 141 - SYNTAX_ERR: (self) 142 Raised if the specified CSS string value has a syntax error 143 (according to the attached property) or is unparsable. 144 - TODO: INVALID_MODIFICATION_ERR: 145 Raised if the specified CSS string value represents a different 146 type of values than the values allowed by the CSS property. 147 - NO_MODIFICATION_ALLOWED_ERR: (self) 148 Raised if this value is readonly. 149 """ 150 def invalidToken(tokens, x): 151 """ 152 raises SyntaxErr if an INVALID token in tokens 153 154 x 155 used for error message 156 157 returns True if INVALID found, else False 158 """ 159 for t in tokens: 160 if t.type == self._ttypes.INVALID: 161 return u'Invalid token found in %s.' % x, t 162 return False
163 164 self._checkReadonly() 165 tokens = self._tokenize(cssText) 166 msg = invalidToken(tokens, 'value') 167 168 if msg: 169 self._log.error( 170 u'CSSValue: Unknown value syntax: "%s". (%s)' % ( 171 self._valuestr(cssText), msg)) 172 return 173 174 numvalues = numcommas = 0 175 newseq = [] 176 i, imax = 0, len(tokens) 177 while i < imax: 178 t = tokens[i] 179 if self._ttypes.S == t.type: # add single space 180 if not newseq or newseq[-1] in (u', ', u' '): 181 # not 1st and no 2 spaces after each other 182 # also no space after a comma 183 pass 184 else: 185 newseq.append(u' ') 186 elif self._ttypes.COMMENT == t.type: # just add 187 newseq.append(cssutils.css.CSSComment(t)) 188 elif t.type == self._ttypes.COMMA: 189 if newseq and newseq[-1] == u' ': 190 # TODO: COMMA is set as ", " and used as this later 191 # SHOULD be in serializer... 192 # so only a space OR a comma between values 193 newseq[-1] = u', ' 194 else: 195 newseq.append(u', ') 196 numcommas += 1 197 elif t.type in (self._ttypes.IDENT, 198 self._ttypes.STRING, 199 self._ttypes.HASH, 200 self._ttypes.NUMBER, 201 self._ttypes.PERCENTAGE, 202 self._ttypes.DIMENSION, 203 self._ttypes.URI): 204 newseq.append(t.value) 205 numvalues += 1 206 elif self._ttypes.FUNCTION == t.type: 207 _functokens, endi = self._tokensupto( 208 tokens, funcendonly=True) 209 _func = [] 210 for _t in _functokens: 211 _func.append(_t.value) 212 newseq.append(u''.join(_func)) 213 i += endi #-1 214 numvalues += 1 215 # elif t.type in ( 216 # self._ttypes.SEMICOLON, self._ttypes.IMPORTANT_SYM) or\ 217 # u':' == t.value: 218 # self._log.error(u'CSSValue: Syntax error.', t) 219 # return 220 else: 221 self._log.error(u'CSSValue: Unknown value: "%s".' % t) 222 223 i += 1 224 225 if numvalues: 226 if tokens: 227 self._linetoken = tokens[0] # used for line report 228 self.seq = newseq 229 self.valid = False 230 # validate if known 231 if self._propertyName and\ 232 self._propertyName in cssproperties.cssvalues: 233 if cssproperties.cssvalues[self._propertyName](self._value): 234 self.valid = True 235 else: 236 self._log.warn( 237 u'CSSValue: Invalid value for CSS2 property %s: %s' % 238 (self._propertyName, self._value), 239 self._linetoken, neverraise=True) 240 else: 241 self._log.info( 242 u'CSSValue: Unable to validate as no property context set or unknown property: "%s"' 243 % self._value, neverraise=True) 244 245 if self._value == u'inherit': 246 self._cssValueType = CSSValue.CSS_INHERIT 247 self.__class__ = CSSValue # reset 248 elif numvalues == 1: 249 self.__class__ = CSSPrimitiveValue 250 elif numvalues > 1 and numcommas == numvalues - 1: 251 # e.g. value for font-family: a, b 252 self.__class__ = CSSPrimitiveValue 253 elif numvalues > 1: 254 # separated by S 255 self.__class__ = CSSValueList 256 self._init() # inits CSSValueList 257 else: 258 self._cssValueType = CSSValue.CSS_CUSTOM 259 self.__class__ = CSSValue # reset 260 261 else: 262 self._log.error( 263 u'CSSValue: Unknown syntax or no value: "%s".' % self._valuestr( 264 cssText).strip())
265 266 cssText = property(_getCssText, _setCssText, 267 doc="A string representation of the current value.") 268
269 - def _getCssValueType(self):
270 if hasattr(self, '_cssValueType'): 271 return self._cssValueType
272 273 cssValueType = property(_getCssValueType, 274 doc="A (readonly) code defining the type of the value as defined above.") 275
276 - def _getCssValueTypeString(self):
277 t = self.cssValueType 278 if t is not None: # may be 0! 279 return CSSValue._typestrings[t] 280 else: 281 return None
282 283 cssValueTypeString = property(_getCssValueTypeString, 284 doc="cssutils: Name of cssValueType of this CSSValue (readonly).") 285
286 - def __repr__(self):
287 return "cssutils.css.%s(%r, _propertyName=%r)" % ( 288 self.__class__.__name__, self.cssText, self._propertyName)
289
290 - def __str__(self):
291 return "<cssutils.css.%s object cssValueType=%r cssText=%r propname=%r valid=%r at 0x%x>" % ( 292 self.__class__.__name__, self.cssValueTypeString, 293 self.cssText, self._propertyName, self.valid, id(self))
294 295
296 -class CSSPrimitiveValue(CSSValue):
297 """ 298 represents a single CSS Value. May be used to determine the value of a 299 specific style property currently set in a block or to set a specific 300 style property explicitly within the block. Might be obtained from the 301 getPropertyCSSValue method of CSSStyleDeclaration. 302 303 Conversions are allowed between absolute values (from millimeters to 304 centimeters, from degrees to radians, and so on) but not between 305 relative values. (For example, a pixel value cannot be converted to a 306 centimeter value.) Percentage values can't be converted since they are 307 relative to the parent value (or another property value). There is one 308 exception for color percentage values: since a color percentage value 309 is relative to the range 0-255, a color percentage value can be 310 converted to a number; (see also the RGBColor interface). 311 """ 312 # constant: type of this CSSValue class 313 cssValueType = CSSValue.CSS_PRIMITIVE_VALUE 314 315 # An integer indicating which type of unit applies to the value. 316 CSS_UNKNOWN = 0 # only obtainable via cssText 317 CSS_NUMBER = 1 318 CSS_PERCENTAGE = 2 319 CSS_EMS = 3 320 CSS_EXS = 4 321 CSS_PX = 5 322 CSS_CM = 6 323 CSS_MM = 7 324 CSS_IN = 8 325 CSS_PT = 9 326 CSS_PC = 10 327 CSS_DEG = 11 328 CSS_RAD = 12 329 CSS_GRAD = 13 330 CSS_MS = 14 331 CSS_S = 15 332 CSS_HZ = 16 333 CSS_KHZ = 17 334 CSS_DIMENSION = 18 335 CSS_STRING = 19 336 CSS_URI = 20 337 CSS_IDENT = 21 338 CSS_ATTR = 22 339 CSS_COUNTER = 23 340 CSS_RECT = 24 341 CSS_RGBCOLOR = 25 342 # NOT OFFICIAL: 343 CSS_RGBACOLOR = 26 344 345 _floattypes = [CSS_NUMBER, CSS_PERCENTAGE, CSS_EMS, CSS_EXS, 346 CSS_PX, CSS_CM, CSS_MM, CSS_IN, CSS_PT, CSS_PC, 347 CSS_DEG, CSS_RAD, CSS_GRAD, CSS_MS, CSS_S, 348 CSS_HZ, CSS_KHZ, CSS_DIMENSION 349 ] 350 _stringtypes = [CSS_ATTR, CSS_IDENT, CSS_STRING, CSS_URI] 351 _countertypes = [CSS_COUNTER] 352 _recttypes = [CSS_RECT] 353 _rbgtypes = [CSS_RGBCOLOR, CSS_RGBACOLOR] 354 355 #(String representation for unit types, token type of unit type, detail) 356 # used to detect primitiveType and for __repr__ 357 _unitinfos = [ 358 ('CSS_UNKNOWN', None, None), 359 ('CSS_NUMBER', Token.NUMBER, None), 360 ('CSS_PERCENTAGE', Token.PERCENTAGE, None), 361 ('CSS_EMS', Token.DIMENSION, 'em'), 362 ('CSS_EXS', Token.DIMENSION, 'ex'), 363 ('CSS_PX', Token.DIMENSION, 'px'), 364 ('CSS_CM', Token.DIMENSION, 'cm'), 365 ('CSS_MM', Token.DIMENSION, 'mm'), 366 ('CSS_IN', Token.DIMENSION, 'in'), 367 ('CSS_PT', Token.DIMENSION, 'pt'), 368 ('CSS_PC', Token.DIMENSION, 'pc'), 369 ('CSS_DEG', Token.DIMENSION, 'deg'), 370 ('CSS_RAD', Token.DIMENSION, 'rad'), 371 ('CSS_GRAD', Token.DIMENSION, 'grad'), 372 ('CSS_MS', Token.DIMENSION, 'ms'), 373 ('CSS_S', Token.DIMENSION, 's'), 374 ('CSS_HZ', Token.DIMENSION, 'hz'), 375 ('CSS_KHZ', Token.DIMENSION, 'khz'), 376 ('CSS_DIMENSION', Token.DIMENSION, None), 377 ('CSS_STRING', Token.STRING, None), 378 ('CSS_URI', Token.URI, None), 379 ('CSS_IDENT', Token.IDENT, None), 380 ('CSS_ATTR', Token.FUNCTION, 'attr('), 381 ('CSS_COUNTER', Token.FUNCTION, 'counter('), 382 ('CSS_RECT', Token.FUNCTION, 'rect('), 383 ('CSS_RGBCOLOR', Token.FUNCTION, 'rgb('), 384 ('CSS_RGBACOLOR', Token.FUNCTION, 'rgba('), 385 ] 386 387 _reNumDim = re.compile(ur'^(.*?)([a-z]+|%)$', re.I| re.U|re.X) 388 389 # oldtype: newType: converterfunc 390 _converter = { 391 # cm <-> mm <-> in, 1 inch is equal to 2.54 centimeters. 392 # pt <-> pc, the points used by CSS 2.1 are equal to 1/72nd of an inch. 393 # pc: picas - 1 pica is equal to 12 points 394 (CSS_CM, CSS_MM): lambda x: x * 10, 395 (CSS_MM, CSS_CM): lambda x: x / 10, 396 397 (CSS_PT, CSS_PC): lambda x: x * 12, 398 (CSS_PC, CSS_PT): lambda x: x / 12, 399 400 (CSS_CM, CSS_IN): lambda x: x / 2.54, 401 (CSS_IN, CSS_CM): lambda x: x * 2.54, 402 (CSS_MM, CSS_IN): lambda x: x / 25.4, 403 (CSS_IN, CSS_MM): lambda x: x * 25.4, 404 405 (CSS_IN, CSS_PT): lambda x: x / 72, 406 (CSS_PT, CSS_IN): lambda x: x * 72, 407 (CSS_CM, CSS_PT): lambda x: x / 2.54 / 72, 408 (CSS_PT, CSS_CM): lambda x: x * 72 * 2.54, 409 (CSS_MM, CSS_PT): lambda x: x / 25.4 / 72, 410 (CSS_PT, CSS_MM): lambda x: x * 72 * 25.4, 411 412 (CSS_IN, CSS_PC): lambda x: x / 72 / 12, 413 (CSS_PC, CSS_IN): lambda x: x * 12 * 72, 414 (CSS_CM, CSS_PC): lambda x: x / 2.54 / 72 / 12, 415 (CSS_PC, CSS_CM): lambda x: x * 12 * 72 * 2.54, 416 (CSS_MM, CSS_PC): lambda x: x / 25.4 / 72 / 12, 417 (CSS_PC, CSS_MM): lambda x: x * 12 * 72 * 25.4, 418 419 # hz <-> khz 420 (CSS_KHZ, CSS_HZ): lambda x: x * 1000, 421 (CSS_HZ, CSS_KHZ): lambda x: x / 1000, 422 # s <-> ms 423 (CSS_S, CSS_MS): lambda x: x * 1000, 424 (CSS_MS, CSS_S): lambda x: x / 1000 425 426 # TODO: convert deg <-> rad <-> grad 427 } 428
429 - def __set_primitiveType(self):
430 """ 431 primitiveType is readonly but is set lazy if accessed 432 no value is given as self._value is used 433 """ 434 primitiveType = self.CSS_UNKNOWN 435 tokens = self._tokenize(self._value) 436 try: 437 t = tokens[0] 438 except IndexError: 439 self._log.error(u'CSSPrimitiveValue: No value.') 440 441 #if self.valid == False: 442 # primitiveType = CSSPrimitiveValue.CSS_UNKNOWN 443 alltypes = set([x.type for x in tokens]) 444 commalisttypes = set([Token.COMMA, Token.IDENT, Token.STRING]) 445 if commalisttypes.issubset(alltypes): 446 # special case: e.g. for font-family: a, b; 447 primitiveType = CSSPrimitiveValue.CSS_STRING 448 elif t.type == Token.HASH: 449 # special case, maybe should be converted to rgb in any case? 450 primitiveType = CSSPrimitiveValue.CSS_RGBCOLOR 451 else: 452 for i, (name, tokentype, search) in enumerate(CSSPrimitiveValue._unitinfos): 453 if t.type == tokentype: 454 if tokentype == Token.DIMENSION: 455 if not search: 456 primitiveType = i 457 break 458 elif re.match(ur'^[^a-z]*(%s)$' % search, t.value): 459 primitiveType = i 460 break 461 elif tokentype == Token.FUNCTION: 462 if not search: 463 primitiveType = i 464 break 465 elif t.value.startswith(search): 466 primitiveType = i 467 break 468 else: 469 primitiveType = i 470 break 471 self._primitiveType = primitiveType
472
473 - def _getPrimitiveType(self):
474 if not hasattr(self, '_primitivetype'): 475 self.__set_primitiveType() 476 return self._primitiveType
477 478 primitiveType = property(_getPrimitiveType, 479 doc="READONLY: The type of the value as defined by the constants specified above.") 480
481 - def _getPrimitiveTypeString(self):
483 484 primitiveTypeString = property(_getPrimitiveTypeString, 485 doc="Name of primitive type of this value.") 486
487 - def _getCSSPrimitiveTypeString(self, type):
488 "get TypeString by given type which may be unknown, used by setters" 489 try: 490 return CSSPrimitiveValue._unitinfos[type][0] 491 except (IndexError, TypeError): 492 return u'%r (UNKNOWN TYPE)' % type
493
494 - def __getValDim(self):
495 "splits self._value in numerical and dimension part" 496 try: 497 val, dim = self._reNumDim.findall(self._value)[0] 498 except IndexError: 499 val, dim = self._value, u'' 500 try: 501 val = float(val) 502 except ValueError: 503 raise xml.dom.InvalidAccessErr( 504 u'CSSPrimitiveValue: No float value %s' 505 % (self._value)) 506 507 return val, dim
508
509 - def getFloatValue(self, unitType):
510 """ 511 (DOM method) This method is used to get a float value in a 512 specified unit. If this CSS value doesn't contain a float value 513 or can't be converted into the specified unit, a DOMException 514 is raised. 515 516 unitType 517 to get the float value. The unit code can only be a float unit type 518 (i.e. CSS_NUMBER, CSS_PERCENTAGE, CSS_EMS, CSS_EXS, CSS_PX, CSS_CM, 519 CSS_MM, CSS_IN, CSS_PT, CSS_PC, CSS_DEG, CSS_RAD, CSS_GRAD, CSS_MS, 520 CSS_S, CSS_HZ, CSS_KHZ, CSS_DIMENSION). 521 522 returns not necessarily a float but some cases just an int 523 e.g. if the value is ``1px`` it return ``1`` and **not** ``1.0`` 524 525 conversions might return strange values like 1.000000000001 526 """ 527 if unitType not in self._floattypes: 528 raise xml.dom.InvalidAccessErr( 529 u'unitType Parameter is not a float type') 530 531 val, dim = self.__getValDim() 532 533 if self.primitiveType != unitType: 534 try: 535 val = self._converter[self.primitiveType, unitType](val) 536 except KeyError: 537 raise xml.dom.InvalidAccessErr( 538 u'CSSPrimitiveValue: Cannot coerce primitiveType %s to %s' 539 % (self.primitiveTypeString, 540 self._getCSSPrimitiveTypeString(unitType))) 541 542 if val == int(val): 543 val = int(val) 544 545 return val
546
547 - def setFloatValue(self, unitType, floatValue):
548 """ 549 (DOM method) A method to set the float value with a specified unit. 550 If the property attached with this value can not accept the 551 specified unit or the float value, the value will be unchanged and 552 a DOMException will be raised. 553 554 unitType 555 a unit code as defined above. The unit code can only be a float 556 unit type 557 floatValue 558 the new float value which does not have to be a float value but 559 may simple be an int e.g. if setting:: 560 561 setFloatValue(CSS_PX, 1) 562 563 raises DOMException 564 - INVALID_ACCESS_ERR: Raised if the attached property doesn't 565 support the float value or the unit type. 566 - NO_MODIFICATION_ALLOWED_ERR: Raised if this property is readonly. 567 """ 568 self._checkReadonly() 569 if unitType not in self._floattypes: 570 raise xml.dom.InvalidAccessErr( 571 u'CSSPrimitiveValue: unitType %s is not a float type' % 572 self._getCSSPrimitiveTypeString(unitType)) 573 try: 574 val = float(floatValue) 575 except ValueError, e: 576 raise xml.dom.InvalidAccessErr( 577 u'CSSPrimitiveValue: floatValue "%s" is not a float' % 578 floatValue) 579 580 oldval, dim = self.__getValDim() 581 582 if self.primitiveType != unitType: 583 # convert if possible 584 try: 585 val = self._converter[ 586 unitType, self.primitiveType](val) 587 except KeyError: 588 raise xml.dom.InvalidAccessErr( 589 u'CSSPrimitiveValue: Cannot coerce primitiveType %s to %s' 590 % (self.primitiveTypeString, 591 self._getCSSPrimitiveTypeString(unitType))) 592 593 if val == int(val): 594 val = int(val) 595 596 self.cssText = '%s%s' % (val, dim)
597
598 - def getStringValue(self):
599 """ 600 (DOM method) This method is used to get the string value. If the 601 CSS value doesn't contain a string value, a DOMException is raised. 602 603 Some properties (like 'font-family' or 'voice-family') 604 convert a whitespace separated list of idents to a string. 605 606 Only the actual value is returned so e.g. all the following return the 607 actual value ``a``: url(a), attr(a), "a", 'a' 608 """ 609 if self.primitiveType not in self._stringtypes: 610 raise xml.dom.InvalidAccessErr( 611 u'CSSPrimitiveValue %s is not a string type' 612 % self.primitiveTypeString) 613 614 if CSSPrimitiveValue.CSS_STRING == self.primitiveType: 615 return self._value[1:-1] 616 elif CSSPrimitiveValue.CSS_URI == self.primitiveType: 617 url = self._value[4:-1] 618 if url and url[0] in ('"', "'") and url[0] == url[-1]: 619 return url[1:-1] 620 else: 621 return url 622 elif CSSPrimitiveValue.CSS_ATTR == self.primitiveType: 623 return self._value[5:-1] 624 else: 625 return self._value
626
627 - def setStringValue(self, stringType, stringValue):
628 """ 629 (DOM method) A method to set the string value with the specified 630 unit. If the property attached to this value can't accept the 631 specified unit or the string value, the value will be unchanged and 632 a DOMException will be raised. 633 634 stringType 635 a string code as defined above. The string code can only be a 636 string unit type (i.e. CSS_STRING, CSS_URI, CSS_IDENT, and 637 CSS_ATTR). 638 stringValue 639 the new string value 640 Only the actual value is expected so for (CSS_URI, "a") the 641 new value will be ``url(a)``. For (CSS_STRING, "'a'") 642 the new value will be ``"\\'a\\'"`` as the surrounding ``'`` are 643 not part of the string value 644 645 raises 646 DOMException 647 - INVALID_ACCESS_ERR: Raised if the CSS value doesn't contain a 648 string value or if the string value can't be converted into 649 the specified unit. 650 - NO_MODIFICATION_ALLOWED_ERR: Raised if this property is readonly. 651 """ 652 self._checkReadonly() 653 # self not stringType 654 if self.primitiveType not in self._stringtypes: 655 raise xml.dom.InvalidAccessErr( 656 u'CSSPrimitiveValue %s is not a string type' 657 % self.primitiveTypeString) 658 # given stringType is no StringType 659 if stringType not in self._stringtypes: 660 raise xml.dom.InvalidAccessErr( 661 u'CSSPrimitiveValue: stringType %s is not a string type' 662 % self._getCSSPrimitiveTypeString(stringType)) 663 664 if self._primitiveType != stringType: 665 raise xml.dom.InvalidAccessErr( 666 u'CSSPrimitiveValue: Cannot coerce primitiveType %s to %s' 667 % (self.primitiveTypeString, 668 self._getCSSPrimitiveTypeString(stringType))) 669 670 if CSSPrimitiveValue.CSS_STRING == self._primitiveType: 671 self.cssText = u'"%s"' % stringValue.replace(u'"', ur'\\"') 672 elif CSSPrimitiveValue.CSS_URI == self._primitiveType: 673 # Some characters appearing in an unquoted URI, such as 674 # parentheses, commas, whitespace characters, single quotes 675 # (') and double quotes ("), must be escaped with a backslash 676 # so that the resulting URI value is a URI token: 677 # '\(', '\)', '\,'. 678 # 679 # Here the URI is set in quotes alltogether! 680 if u'(' in stringValue or\ 681 u')' in stringValue or\ 682 u',' in stringValue or\ 683 u'"' in stringValue or\ 684 u'\'' in stringValue or\ 685 u'\n' in stringValue or\ 686 u'\t' in stringValue or\ 687 u'\r' in stringValue or\ 688 u'\f' in stringValue or\ 689 u' ' in stringValue: 690 stringValue = '"%s"' % stringValue.replace(u'"', ur'\"') 691 self.cssText = u'url(%s)' % stringValue 692 elif CSSPrimitiveValue.CSS_ATTR == self._primitiveType: 693 self.cssText = u'attr(%s)' % stringValue 694 else: 695 self.cssText = stringValue 696 self._primitiveType = stringType
697
698 - def getCounterValue(self):
699 """ 700 (DOM method) This method is used to get the Counter value. If 701 this CSS value doesn't contain a counter value, a DOMException 702 is raised. Modification to the corresponding style property 703 can be achieved using the Counter interface. 704 """ 705 if not self.CSS_COUNTER == self.primitiveType: 706 raise xml.dom.InvalidAccessErr(u'Value is not a counter type') 707 # TODO: use Counter class 708 raise NotImplementedError()
709
710 - def getRGBColorValue(self):
711 """ 712 (DOM method) This method is used to get the RGB color. If this 713 CSS value doesn't contain a RGB color value, a DOMException 714 is raised. Modification to the corresponding style property 715 can be achieved using the RGBColor interface. 716 """ 717 # TODO: what about coercing #000 to RGBColor? 718 if self.primitiveType not in self._rbgtypes: 719 raise xml.dom.InvalidAccessErr(u'Value is not a RGB value') 720 # TODO: use RGBColor class 721 raise NotImplementedError()
722
723 - def getRectValue(self):
724 """ 725 (DOM method) This method is used to get the Rect value. If this CSS 726 value doesn't contain a rect value, a DOMException is raised. 727 Modification to the corresponding style property can be achieved 728 using the Rect interface. 729 """ 730 if self.primitiveType not in self._recttypes: 731 raise xml.dom.InvalidAccessErr(u'value is not a Rect value') 732 # TODO: use Rect class 733 raise NotImplementedError()
734
735 - def __str__(self):
736 return "<cssutils.css.%s object primitiveType=%s cssText=%r _propertyName=%r valid=%r at 0x%x>" % ( 737 self.__class__.__name__, self.primitiveTypeString, 738 self.cssText, self._propertyName, self.valid, id(self))
739 740
741 -class CSSValueList(CSSValue):
742 """ 743 The CSSValueList interface provides the abstraction of an ordered 744 collection of CSS values. 745 746 Some properties allow an empty list into their syntax. In that case, 747 these properties take the none identifier. So, an empty list means 748 that the property has the value none. 749 750 The items in the CSSValueList are accessible via an integral index, 751 starting from 0. 752 """ 753 cssValueType = CSSValue.CSS_VALUE_LIST 754 __ws = re.compile(ur'^\s*$') 755
756 - def __init__(self, cssText=None, readonly=False, _propertyName=None):
757 """ 758 inits a new CSSValueList 759 """ 760 super(CSSValueList, self).__init__(cssText=cssText, 761 readonly=readonly, 762 _propertyName=_propertyName) 763 self._init()
764
765 - def _init(self):
766 "called by CSSValue if newly identified as CSSValueList" 767 self._items = [] 768 newseq = [] 769 i, max = 0, len(self.seq) 770 while i < max: 771 v = self.seq[i] 772 if type(v) in types.StringTypes and not self.__ws.match(v): 773 if i+1 < max and self.seq[i+1] == u', ': 774 # a comma separated list of values as ONE value 775 # e.g. font-family: a,b 776 fullvalue = [v] 777 expected = 'comma' # or 'value' 778 for j in range(i+1, max): 779 testv = self.seq[j] 780 if u' ' == testv: # a single value follows 781 break 782 elif u', ' == testv and expected == 'comma': 783 fullvalue.append(testv) 784 expected = 'value' 785 elif u', ' != testv and expected == 'value': 786 fullvalue.append(testv) 787 expected = 'comma' 788 else: 789 self._log.error( 790 u'CSSValueList: Unknown syntax: "%s".' 791 % testv) 792 return 793 if expected == 'value': 794 self._log.error( 795 u'CSSValueList: Unknown syntax: "%s".' 796 % u''.join(self.seq)) 797 return 798 # setting _propertyName this way does not work 799 # for compound props like font! 800 i += len(fullvalue) - 1 801 o = CSSValue(cssText=u''.join(fullvalue), 802 _propertyName=self._propertyName) 803 else: 804 # a single value, u' ' or nothing should be following 805 o = CSSValue(cssText=v, _propertyName=self._propertyName) 806 807 self._items.append(o) 808 newseq.append(o) 809 810 else: 811 # S (or TODO: comment?) 812 newseq.append(v) 813 814 i += 1 815 816 self.seq = newseq
817
818 - def _getLength(self):
819 return len(self._items)
820 821 length = property(_getLength, 822 doc="(DOM attribute) The number of CSSValues in the list.") 823
824 - def item(self, index):
825 """ 826 (DOM method) Used to retrieve a CSSValue by ordinal index. The 827 order in this collection represents the order of the values in the 828 CSS style property. If index is greater than or equal to the number 829 of values in the list, this returns None. 830 """ 831 try: 832 return self._items[index] 833 except IndexError: 834 return None
835
836 - def __iter__(self):
837 "CSSValueList is iterable" 838 return CSSValueList.__items(self)
839
840 - def __items(self):
841 "the iterator" 842 for i in range (0, self.length): 843 yield self.item(i)
844
845 - def __str_(self):
846 return "<cssutils.css.%s object length=%s at 0x%x>" % ( 847 self.__class__.__name__, self.length, id(self))
848