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