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