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-11-24 23:32:52 +0100 (Sa, 24 Nov 2007) $'
      9  __version__ = '$LastChangedRevision: 679 $'
     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          if not new['name']:
    209              wellformed = False
    210              self._log.error(u'Property: No name found: %r' %
    211                  self._valuestr(name))
    212
    213          if wellformed:
    214              self.wellformed = True
    215              self._name = new['name']
    216              self.normalname = self._normalize(self._name)
    217              self.seqs[0] = newseq
    218
    219              # validate
    220              if self.normalname not in cssproperties.cssvalues:
    221                  self.valid = False
    222                  self._log.info(u'Property: No CSS2 Property: %r.' %
    223                           new['name'], neverraise=True)
    224              else:
    225                  self.valid = True
    226                  if self.cssValue:
    227                      self.cssValue._propertyName = self.normalname
    228                      self.valid = self.cssValue.valid
    229
    230
    231          else:
    232              self.wellformed = False
    233
    234      name = property(_getName, _setName,
    235          doc="(cssutils) Name of this property")
    236
    237 -    def _getCSSValue(self):
    238          return self.seqs[1]
    239
    240 -    def _setCSSValue(self, cssText):
    241          """
    242          see css.CSSValue
    243
    244          DOMException on setting?
    245
    246          - SYNTAX_ERR: (self)
    247            Raised if the specified CSS string value has a syntax error
    248            (according to the attached property) or is unparsable.
    249          - TODO: INVALID_MODIFICATION_ERR:
    250            Raised if the specified CSS string value represents a different
    251            type of values than the values allowed by the CSS property.
    252          """
    253          if self._mediaQuery and not cssText:
    254              self.seqs[1] = CSSValue()
    255          else:
    256              if not self.seqs[1]:
    257                  self.seqs[1] = CSSValue()
    258
    259              cssvalue = self.seqs[1]
    260              cssvalue._propertyName = self.name
    261              cssvalue.cssText = cssText
    262              if cssvalue._value and cssvalue.wellformed:
    263                  self.seqs[1] = cssvalue
    264              self.valid = self.valid and cssvalue.valid
    265              self.wellformed = self.wellformed and cssvalue.wellformed
    266
    267      cssValue = property(_getCSSValue, _setCSSValue,
    268          doc="(cssutils) CSSValue object of this property")
    269
    270 -    def _getValue(self):
    271          if self.cssValue: return self.cssValue._value
    272          else: return u''
    273
    274 -    def _setValue(self, value):
    275          self.cssValue.cssText = value
    276          self.valid = self.valid and self.cssValue.valid
    277          self.wellformed = self.wellformed and self.cssValue.wellformed
    278
    279      value = property(_getValue, _setValue,
    280                       doc="The textual value of this Properties cssValue.")
    281
    282 -    def _getPriority(self):
    283          return cssutils.ser.do_Property_priority(self.seqs[2])
    284
    285 -    def _setPriority(self, priority):
    286          """
    287          priority
    288              a string
    289
    290          Format
    291          ======
    292          ::
    293
    294              prio
    295                : IMPORTANT_SYM S*
    296                ;
    297
    298              "!"{w}"important"   {return IMPORTANT_SYM;}
    299
    300          DOMException on setting
    301
    302          - SYNTAX_ERR: (self)
    303            Raised if the specified priority has a syntax error and is
    304            unparsable.
    305            In this case a priority not equal to None, "" or "!{w}important".
    306          """
    307          if self._mediaQuery:
    308              self._priority = u''
    309              if priority:
    310                  self._log.error(u'Property: No priority in a MediaQuery - ignored.')
    311              return
    312
    313          # for closures: must be a mutable
    314          new = {'priority': u'',
    315                 'wellformed': True}
    316
    317          def _char(expected, seq, token, tokenizer=None):
    318              # "!"
    319              val = self._tokenvalue(token)
    320              if u'!' == expected == val:
    321                  seq.append(val)
    322                  return 'important'
    323              else:
    324                  new['wellformed'] = False
    325                  self._log.error(u'Property: Unexpected char.', token)
    326                  return expected
    327
    328          def _ident(expected, seq, token, tokenizer=None):
    329              # "important"
    330              val = self._tokenvalue(token)
    331              normalval = self._tokenvalue(token, normalize=True)
    332              if 'important' == expected == normalval:
    333                  new['priority'] = val.lower()
    334                  seq.append(val.lower())
    335                  return 'EOF'
    336              else:
    337                  new['wellformed'] = False
    338                  self._log.error(u'Property: Unexpected ident.', token)
    339                  return expected
    340
    341          newseq = []
    342          wellformed, expected = self._parse(expected='!',
    343                                             seq=newseq,
    344                                             tokenizer=self._tokenize2(priority),
    345                                             productions={'CHAR': _char,
    346                                                          'IDENT': _ident})
    347          wellformed = wellformed and new['wellformed']
    348
    349          # post conditions
    350          if priority and not new['priority']:
    351              wellformed = False
    352              self._log.info(u'Property: Invalid priority: %r.' %
    353                      self._valuestr(priority))
    354
    355          if wellformed:
    356              self.wellformed = self.wellformed and wellformed
    357              self._priority = new['priority']
    358              self._normalpriority = self._normalize(self._priority)
    359              self.seqs[2] = newseq
    360
    361              # validate
    362              if self._normalpriority not in (u'', u'important'):
    363                  self.valid = False
    364                  self._log.info(u'Property: No CSS2 priority value: %r.' %
    365                      self._normalpriority, neverraise=True)
    366
    367      priority = property(_getPriority, _setPriority,
    368          doc="(cssutils) Priority of this property")
    369
    370 -    def __repr__(self):
    371          return "cssutils.css.%s(name=%r, value=%r, priority=%r)" % (
    372                  self.__class__.__name__,
    373                  self.name, self.cssValue.cssText, self.priority)
    374
    375 -    def __str__(self):
    376          return "<%s.%s object name=%r value=%r priority=%r at 0x%x>" % (
    377                  self.__class__.__module__, self.__class__.__name__,
    378                  self.name, self.cssValue.cssText, self.priority, id(self))
    379