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

# Source Code for Module cssutils.css.selectorlist

      1  """SelectorList is a list of CSS Selector objects.
      2
      3  TODO
      4      - remove duplicate Selectors. -> CSSOM canonicalize
      5
      6      - ??? CSS2 gives a special meaning to the comma (,) in selectors.
      7          However, since it is not known if the comma may acquire other
      8          meanings in future versions of CSS, the whole statement should be
      9          ignored if there is an error anywhere in the selector, even though
     10          the rest of the selector may look reasonable in CSS2.
     11
     12          Illegal example(s):
     13
     14          For example, since the "&" is not a valid token in a CSS2 selector,
     15          a CSS2 user agent must ignore the whole second line, and not set
     16          the color of H3 to red:
     17  """
     18  __all__ = ['SelectorList']
     19  __docformat__ = 'restructuredtext'
     20  __version__ = '$Id: selectorlist.py 1116 2008-03-05 13:52:23Z cthedot $'
     21
     22  import xml.dom
     23  import cssutils
     24  from selector import Selector
     25
     26 -class SelectorList(cssutils.util.Base, cssutils.util.ListSeq):
     27      """
     28      (cssutils) a list of Selectors of a CSSStyleRule
     29
     30      Properties
     31      ==========
     32      length: of type unsigned long, readonly
     33          The number of Selector elements in the list.
     34      parentRule: of type CSSRule, readonly
     35          The CSS rule that contains this selector list or None if this
     36          list is not attached to a CSSRule.
     37      selectorText: of type DOMString
     38          The textual representation of the selector for the rule set. The
     39          implementation may have stripped out insignificant whitespace while
     40          parsing the selector.
     41      seq: (internal use!)
     42          A list of Selector objects
     43      wellformed
     44          if this selectorlist is wellformed regarding the Selector spec
     45      """
     46 -    def __init__(self, selectorText=None, parentRule=None,
     47                   readonly=False):
     48          """
     49          initializes SelectorList with optional selectorText
     50
     51          :Parameters:
     52              selectorText
     53                  parsable list of Selectors
     54              parentRule
     55                  the parent CSSRule if available
     56          """
     57          super(SelectorList, self).__init__()
     58
     59          self._parentRule = parentRule
     60
     61          if selectorText:
     62              self.selectorText = selectorText
     63
     64          self._readonly = readonly
     65
     66 -    def __prepareset(self, newSelector, namespaces=None):
     67          "used by appendSelector and __setitem__"
     68          if not namespaces:
     69              namespaces = {}
     70          self._checkReadonly()
     71          if not isinstance(newSelector, Selector):
     72              newSelector = Selector((newSelector, namespaces),
     73                                     parentList=self)
     74          if newSelector.wellformed:
     75              newSelector._parent = self # maybe set twice but must be!
     76              return newSelector
     77
     78 -    def __setitem__(self, index, newSelector):
     79          """
     80          overwrites ListSeq.__setitem__
     81
     82          Any duplicate Selectors are **not** removed.
     83          """
     84          newSelector = self.__prepareset(newSelector)
     85          if newSelector:
     86              self.seq[index] = newSelector
     87
     88 -    def append(self, newSelector):
     89          "overwrites ListSeq.append"
     90          self.appendSelector(newSelector)
     91
     92      length = property(lambda self: len(self),
     93          doc="The number of Selector elements in the list.")
     94
     95
     96 -    def __getNamespaces(self):
     97          "uses children namespaces if not attached to a sheet, else the sheet's ones"
     98          try:
     99              return self.parentRule.parentStyleSheet.namespaces
    100          except AttributeError:
    101              namespaces = {}
    102              for selector in self.seq:
    103                  namespaces.update(selector._namespaces)
    104              return namespaces
    105
    106      _namespaces = property(__getNamespaces, doc="""if this SelectorList is
    107          attached to a CSSStyleSheet the namespaces of that sheet are mirrored
    108          here. While the SelectorList (or parentRule(s) are
    109          not attached the namespaces of all children Selectors are used.""")
    110
    111      parentRule = property(lambda self: self._parentRule,
    112          doc="(DOM) The CSS rule that contains this SelectorList or\
    113          None if this SelectorList is not attached to a CSSRule.")
    114
    115 -    def _getSelectorText(self):
    116          "returns serialized format"
    117          return cssutils.ser.do_css_SelectorList(self)
    118
    119 -    def _setSelectorText(self, selectorText):
    120          """
    121          :param selectorText:
    122              comma-separated list of selectors or a tuple of
    123              (selectorText, dict-of-namespaces)
    124          :Exceptions:
    125              - `NAMESPACE_ERR`: (Selector)
    126                Raised if the specified selector uses an unknown namespace
    127                prefix.
    128              - `SYNTAX_ERR`: (self)
    129                Raised if the specified CSS string value has a syntax error
    130                and is unparsable.
    131              - `NO_MODIFICATION_ALLOWED_ERR`: (self)
    132                Raised if this rule is readonly.
    133          """
    134          self._checkReadonly()
    135
    136          # might be (selectorText, namespaces)
    137          selectorText, namespaces = self._splitNamespacesOff(selectorText)
    138          try:
    139              # use parent's only if available
    140              namespaces = self.parentRule.parentStyleSheet.namespaces
    141          except AttributeError:
    142              pass
    143
    144          wellformed = True
    145          tokenizer = self._tokenize2(selectorText)
    146          newseq = []
    147
    148          expected = True
    149          while True:
    150              # find all upto and including next ",", EOF or nothing
    151              selectortokens = self._tokensupto2(tokenizer, listseponly=True)
    152              if selectortokens:
    153                  if self._tokenvalue(selectortokens[-1]) == ',':
    154                      expected = selectortokens.pop()
    155                  else:
    156                      expected = None
    157
    158                  selector = Selector((selectortokens, namespaces),
    159                                      parentList=self)
    160                  if selector.wellformed:
    161                      newseq.append(selector)
    162                  else:
    163                      wellformed = False
    164                      self._log.error(u'SelectorList: Invalid Selector: %s' %
    165                                      self._valuestr(selectortokens))
    166              else:
    167                  break
    168
    169          # post condition
    170          if u',' == expected:
    171              wellformed = False
    172              self._log.error(u'SelectorList: Cannot end with ",": %r' %
    173                              self._valuestr(selectorText))
    174          elif expected:
    175              wellformed = False
    176              self._log.error(u'SelectorList: Unknown Syntax: %r' %
    177                              self._valuestr(selectorText))
    178          if wellformed:
    179              self.seq = newseq
    180  #            for selector in newseq:
    181  #                 self.appendSelector(selector)
    182
    183      selectorText = property(_getSelectorText, _setSelectorText,
    184          doc="""(cssutils) The textual representation of the selector for
    185              a rule set.""")
    186
    187      wellformed = property(lambda self: bool(len(self.seq)))
    188
    189 -    def appendSelector(self, newSelector):
    190          """
    191          Append newSelector (a string will be converted to a new
    192          Selector).
    193
    194          :param newSelector:
    195              comma-separated list of selectors or a tuple of
    196              (selectorText, dict-of-namespaces)
    197          :returns: New Selector or None if newSelector is not wellformed.
    198          :Exceptions:
    199              - `NAMESPACE_ERR`: (self)
    200                Raised if the specified selector uses an unknown namespace
    201                prefix.
    202              - `SYNTAX_ERR`: (self)
    203                Raised if the specified CSS string value has a syntax error
    204                and is unparsable.
    205              - `NO_MODIFICATION_ALLOWED_ERR`: (self)
    206                Raised if this rule is readonly.
    207          """
    208          self._checkReadonly()
    209
    210          # might be (selectorText, namespaces)
    211          newSelector, namespaces = self._splitNamespacesOff(newSelector)
    212          try:
    213              # use parent's only if available
    214              namespaces = self.parentRule.parentStyleSheet.namespaces
    215          except AttributeError:
    216              # use already present namespaces plus new given ones
    217              _namespaces = self._namespaces
    218              _namespaces.update(namespaces)
    219              namespaces = _namespaces
    220
    221          newSelector = self.__prepareset(newSelector, namespaces)
    222          if newSelector:
    223              seq = self.seq[:]
    224              del self.seq[:]
    225              for s in seq:
    226                  if s.selectorText != newSelector.selectorText:
    227                      self.seq.append(s)
    228              self.seq.append(newSelector)
    229              return newSelector
    230
    231 -    def __repr__(self):
    232          if self._namespaces:
    233              st = (self.selectorText, self._namespaces)
    234          else:
    235              st = self.selectorText
    236          return "cssutils.css.%s(selectorText=%r)" % (
    237                  self.__class__.__name__, st)
    238
    239 -    def __str__(self):
    240          return "<cssutils.css.%s object selectorText=%r _namespaces=%r at 0x%x>" % (
    241                  self.__class__.__name__, self.selectorText, self._namespaces,
    242                  id(self))
    243
    244 -    def _getUsedUris(self):
    245          "used by CSSStyleSheet to check if @namespace rules are needed"
    246          uris = set()
    247          for s in self:
    248              uris.update(s._getUsedUris())
    249          return uris
    250