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