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

# Source Code for Module cssutils.css.property

      1  """Property is a single CSS property in a CSSStyleDeclaration
      2
      3  Internal use only, may be removed in the future!
      4  """
      5  __all__ = ['Property']
      6  __docformat__ = 'restructuredtext'
      7  __version__ = '$Id: property.py 1305 2008-06-22 18:42:51Z cthedot $'
      8
      9  import xml.dom
     10  import cssutils
     11  import cssproperties
     12  from cssvalue import CSSValue
     13  from cssutils.helper import Deprecated
     14
     15 -class Property(cssutils.util.Base):
     16      """
     17      (cssutils) a CSS property in a StyleDeclaration of a CSSStyleRule
     18
     19      Properties
     20      ==========
     21      cssText
     22          a parsable textual representation of this property
     23      name
     24          normalized name of the property, e.g. "color" when name is "c\olor"
     25          (since 0.9.5)
     26      literalname (since 0.9.5)
     27          original name of the property in the source CSS which is not normalized
     28          e.g. "C\\OLor"
     29      cssValue
     30          the relevant CSSValue instance for this property
     31      value
     32          the string value of the property, same as cssValue.cssText
     33      priority
     34          of the property (currently only u"important" or None)
     35      literalpriority
     36          original priority of the property in the source CSS which is not
     37          normalized e.g. "IM\portant"
     38      seqs
     39          combination of a list for seq of name, a CSSValue object, and
     40          a list for seq of  priority (empty or [!important] currently)
     41      valid
     42          if this Property is valid
     43      wellformed
     44          if this Property is syntactically ok
     45
     46      DEPRECATED normalname (since 0.9.5)
     47          normalized name of the property, e.g. "color" when name is "c\olor"
     48
     49      Format
     50      ======
     51      ::
     52
     53          property = name
     54            : IDENT S*
     55            ;
     56
     57          expr = value
     58            : term [ operator term ]*
     59            ;
     60          term
     61            : unary_operator?
     62              [ NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* | ANGLE S* |
     63                TIME S* | FREQ S* | function ]
     64            | STRING S* | IDENT S* | URI S* | hexcolor
     65            ;
     66          function
     67            : FUNCTION S* expr ')' S*
     68            ;
     69          /*
     70           * There is a constraint on the color that it must
     71           * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F])
     72           * after the "#"; e.g., "#000" is OK, but "#abcd" is not.
     73           */
     74          hexcolor
     75            : HASH S*
     76            ;
     77
     78          prio
     79            : IMPORTANT_SYM S*
     80            ;
     81
     82      """
     83 -    def __init__(self, name=None, value=None, priority=u'', _mediaQuery=False):
     84          """
     85          inits property
     86
     87          name
     88              a property name string (will be normalized)
     89          value
     90              a property value string
     91          priority
     92              an optional priority string which currently must be u'',
     93              u'!important' or u'important'
     94          _mediaQuery boolean
     95              if True value is optional as used by MediaQuery objects
     96          """
     97          super(Property, self).__init__()
     98
     99          self.seqs = [[], None, []]
    100          self.valid = False
    101          self.wellformed = False
    102          self._mediaQuery = _mediaQuery
    103
    104          if name:
    105              self.name = name
    106          else:
    107              self._name = u''
    108              self._literalname = u''
    109              self.__normalname = u'' # DEPRECATED
    110
    111          if value:
    112              self.cssValue = value
    113          else:
    114              self.seqs[1] = CSSValue()
    115
    116          if priority:
    117              self.priority = priority
    118          else:
    119              self._priority = u''
    120              self._literalpriority = u''
    121
    122 -    def _getCssText(self):
    123          """
    124          returns serialized property cssText
    125          """
    126          return cssutils.ser.do_Property(self)
    127
    128 -    def _setCssText(self, cssText):
    129          """
    130          DOMException on setting
    131
    132          - NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
    133            Raised if the rule is readonly.
    134          - SYNTAX_ERR: (self)
    135            Raised if the specified CSS string value has a syntax error and
    136            is unparsable.
    137          """
    138          # check and prepare tokenlists for setting
    139          tokenizer = self._tokenize2(cssText)
    140          nametokens = self._tokensupto2(tokenizer, propertynameendonly=True)
    141          if nametokens:
    142              wellformed = True
    143
    144              valuetokens = self._tokensupto2(tokenizer,
    145                                              propertyvalueendonly=True)
    146              prioritytokens = self._tokensupto2(tokenizer,
    147                                                 propertypriorityendonly=True)
    148
    149              if self._mediaQuery and not valuetokens:
    150                  # MediaQuery may consist of name only
    151                  self.name = nametokens
    152                  self.cssValue = None
    153                  self.priority = None
    154                  return
    155
    156              # remove colon from nametokens
    157              colontoken = nametokens.pop()
    158              if self._tokenvalue(colontoken) != u':':
    159                  wellformed = False
    160                  self._log.error(u'Property: No ":" after name found: %r' %
    161                                  self._valuestr(cssText), colontoken)
    162              elif not nametokens:
    163                  wellformed = False
    164                  self._log.error(u'Property: No property name found: %r.' %
    165                              self._valuestr(cssText), colontoken)
    166
    167              if valuetokens:
    168                  if self._tokenvalue(valuetokens[-1]) == u'!':
    169                      # priority given, move "!" to prioritytokens
    170                      prioritytokens.insert(0, valuetokens.pop(-1))
    171              else:
    172                  wellformed = False
    173                  self._log.error(u'Property: No property value found: %r.' %
    174                                  self._valuestr(cssText), colontoken)
    175
    176              if wellformed:
    177                  self.wellformed = True
    178                  self.name = nametokens
    179                  self.cssValue = valuetokens
    180                  self.priority = prioritytokens
    181
    182          else:
    183              self._log.error(u'Property: No property name found: %r.' %
    184                              self._valuestr(cssText))
    185
    186      cssText = property(fget=_getCssText, fset=_setCssText,
    187          doc="A parsable textual representation.")
    188
    189 -    def _setName(self, name):
    190          """
    191          DOMException on setting
    192
    193          - SYNTAX_ERR: (self)
    194            Raised if the specified name has a syntax error and is
    195            unparsable.
    196          """
    197          # for closures: must be a mutable
    198          new = {'literalname': None,
    199                 'wellformed': True}
    200
    201          def _ident(expected, seq, token, tokenizer=None):
    202              # name
    203              if 'name' == expected:
    204                  new['literalname'] = self._tokenvalue(token).lower()
    205                  seq.append(new['literalname'])
    206                  return 'EOF'
    207              else:
    208                  new['wellformed'] = False
    209                  self._log.error(u'Property: Unexpected ident.', token)
    210                  return expected
    211
    212          newseq = []
    213          wellformed, expected = self._parse(expected='name',
    214                                             seq=newseq,
    215                                             tokenizer=self._tokenize2(name),
    216                                             productions={'IDENT': _ident})
    217          wellformed = wellformed and new['wellformed']
    218
    219          # post conditions
    220          # define a token for error logging
    221          if isinstance(name, list):
    222              token = name[0]
    223          else:
    224              token = None
    225
    226          if not new['literalname']:
    227              wellformed = False
    228              self._log.error(u'Property: No name found: %r' %
    229                  self._valuestr(name), token=token)
    230
    231          if wellformed:
    232              self.wellformed = True
    233              self._literalname = new['literalname']
    234              self._name = self._normalize(self._literalname)
    235              self.__normalname = self._name # DEPRECATED
    236              self.seqs[0] = newseq
    237
    238              # validate
    239              if self._name not in cssproperties.cssvalues:
    240                  self.valid = False
    241                  tokenizer=self._tokenize2(name)
    242                  self._log.info(u'Property: No CSS2 Property: %r.' %
    243                           new['literalname'], token=token, neverraise=True)
    244              else:
    245                  self.valid = True
    246                  if self.cssValue:
    247                      self.cssValue._propertyName = self._name
    248                      self.valid = self.cssValue.valid
    249          else:
    250              self.wellformed = False
    251
    252      name = property(lambda self: self._name, _setName,
    253          doc="Name of this property")
    254
    255      literalname = property(lambda self: self._literalname,
    256          doc="Readonly literal (not normalized) name of this property")
    257
    258 -    def _getCSSValue(self):
    259          return self.seqs[1]
    260
    261 -    def _setCSSValue(self, cssText):
    262          """
    263          see css.CSSValue
    264
    265          DOMException on setting?
    266
    267          - SYNTAX_ERR: (self)
    268            Raised if the specified CSS string value has a syntax error
    269            (according to the attached property) or is unparsable.
    270          - TODO: INVALID_MODIFICATION_ERR:
    271            Raised if the specified CSS string value represents a different
    272            type of values than the values allowed by the CSS property.
    273          """
    274          if self._mediaQuery and not cssText:
    275              self.seqs[1] = CSSValue()
    276          else:
    277              if not self.seqs[1]:
    278                  self.seqs[1] = CSSValue()
    279
    280              cssvalue = self.seqs[1]
    281              cssvalue._propertyName = self.name
    282              cssvalue.cssText = cssText
    283              if cssvalue._value and cssvalue.wellformed:
    284                  self.seqs[1] = cssvalue
    285              self.valid = self.valid and cssvalue.valid
    286              self.wellformed = self.wellformed and cssvalue.wellformed
    287
    288      cssValue = property(_getCSSValue, _setCSSValue,
    289          doc="(cssutils) CSSValue object of this property")
    290
    291 -    def _getValue(self):
    292          if self.cssValue:
    293              return self.cssValue._value
    294          else:
    295              return u''
    296
    297 -    def _setValue(self, value):
    298          self.cssValue.cssText = value
    299          self.valid = self.valid and self.cssValue.valid
    300          self.wellformed = self.wellformed and self.cssValue.wellformed
    301
    302      value = property(_getValue, _setValue,
    303                       doc="The textual value of this Properties cssValue.")
    304
    305 -    def _setPriority(self, priority):
    306          """
    307          priority
    308              a string, currently either u'', u'!important' or u'important'
    309
    310          Format
    311          ======
    312          ::
    313
    314              prio
    315                : IMPORTANT_SYM S*
    316                ;
    317
    318              "!"{w}"important"   {return IMPORTANT_SYM;}
    319
    320          DOMException on setting
    321
    322          - SYNTAX_ERR: (self)
    323            Raised if the specified priority has a syntax error and is
    324            unparsable.
    325            In this case a priority not equal to None, "" or "!{w}important".
    326            As CSSOM defines CSSStyleDeclaration.getPropertyPriority resulting in
    327            u'important' this value is also allowed to set a Properties priority
    328          """
    329          if self._mediaQuery:
    330              self._priority = u''
    331              self._literalpriority = u''
    332              if priority:
    333                  self._log.error(u'Property: No priority in a MediaQuery - ignored.')
    334              return
    335
    336          if isinstance(priority, basestring) and\
    337             u'important' == self._normalize(priority):
    338              priority = u'!%s' % priority
    339
    340          # for closures: must be a mutable
    341          new = {'literalpriority': u'',
    342                 'wellformed': True}
    343
    344          def _char(expected, seq, token, tokenizer=None):
    345              # "!"
    346              val = self._tokenvalue(token)
    347              if u'!' == expected == val:
    348                  seq.append(val)
    349                  return 'important'
    350              else:
    351                  new['wellformed'] = False
    352                  self._log.error(u'Property: Unexpected char.', token)
    353                  return expected
    354
    355          def _ident(expected, seq, token, tokenizer=None):
    356              # "important"
    357              val = self._tokenvalue(token)
    358              normalval = self._tokenvalue(token, normalize=True)
    359              if 'important' == expected == normalval:
    360                  new['literalpriority'] = val
    361                  seq.append(val)
    362                  return 'EOF'
    363              else:
    364                  new['wellformed'] = False
    365                  self._log.error(u'Property: Unexpected ident.', token)
    366                  return expected
    367
    368          newseq = []
    369          wellformed, expected = self._parse(expected='!',
    370                                             seq=newseq,
    371                                             tokenizer=self._tokenize2(priority),
    372                                             productions={'CHAR': _char,
    373                                                          'IDENT': _ident})
    374          wellformed = wellformed and new['wellformed']
    375
    376          # post conditions
    377          if priority and not new['literalpriority']:
    378              wellformed = False
    379              self._log.info(u'Property: Invalid priority: %r.' %
    380                      self._valuestr(priority))
    381
    382          if wellformed:
    383              self.wellformed = self.wellformed and wellformed
    384              self._literalpriority = new['literalpriority']
    385              self._priority = self._normalize(self.literalpriority)
    386              self.seqs[2] = newseq
    387
    388              # validate
    389              if self._priority not in (u'', u'important'):
    390                  self.valid = False
    391                  self._log.info(u'Property: No CSS2 priority value: %r.' %
    392                      self._priority, neverraise=True)
    393
    394      priority = property(lambda self: self._priority, _setPriority,
    395          doc="(cssutils) Priority of this property")
    396
    397      literalpriority = property(lambda self: self._literalpriority,
    398          doc="Readonly literal (not normalized) priority of this property")
    399
    400 -    def __repr__(self):
    401          return "cssutils.css.%s(name=%r, value=%r, priority=%r)" % (
    402                  self.__class__.__name__,
    403                  self.literalname, self.cssValue.cssText, self.priority)
    404
    405 -    def __str__(self):
    406          return "<%s.%s object name=%r value=%r priority=%r at 0x%x>" % (
    407                  self.__class__.__module__, self.__class__.__name__,
    408                  self.name, self.cssValue.cssText, self.priority, id(self))
    409
    410      @Deprecated(u'Use property ``name`` instead (since cssutils 0.9.5).')
    411 -    def _getNormalname(self):
    412          return self.__normalname
    413      normalname = property(_getNormalname,
    414                            doc="DEPRECATED since 0.9.5, use name instead")
    415