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