Package cssutils :: Package stylesheets :: Module medialist |
[hide private]
[frames] | no frames]

# Source Code for Module cssutils.stylesheets.medialist

      1  """
      2  MediaList implements DOM Level 2 Style Sheets MediaList.
      3
      4  TODO:
      5      - delete: maybe if deleting from all, replace *all* with all others?
      6      - is unknown media an exception?
      7  """
      8  __all__ = ['MediaList']
      9  __docformat__ = 'restructuredtext'
     10  __version__ = '$Id: medialist.py 1402 2008-07-29 21:35:23Z cthedot $'
     11
     12  import xml.dom
     13  import cssutils
     14  from cssutils.css import csscomment
     15  from mediaquery import MediaQuery
     16
     17 -class MediaList(cssutils.util.Base, cssutils.util.ListSeq):
     18      """
     19      Provides the abstraction of an ordered collection of media,
     20      without defining or constraining how this collection is
     21      implemented.
     22
     23      A media is always an instance of MediaQuery.
     24
     25      An empty list is the same as a list that contains the medium "all".
     26
     27      Properties
     28      ==========
     29      length:
     30          The number of MediaQuery objects in the list.
     31      mediaText: of type DOMString
     32          The parsable textual representation of this MediaList
     33      self: a list (cssutils)
     34          All MediaQueries in this MediaList
     35      wellformed:
     36          if this list is wellformed
     37
     38      Format
     39      ======
     40      ::
     41
     42          medium [ COMMA S* medium ]*
     43
     44      New::
     45
     46          <media_query> [, <media_query> ]*
     47      """
     48 -    def __init__(self, mediaText=None, readonly=False):
     49          """
     50          mediaText
     51              unicodestring of parsable comma separared media
     52              or a list of media
     53          """
     54          super(MediaList, self).__init__()
     55          self._wellformed = False
     56
     57          if isinstance(mediaText, list):
     58              mediaText = u','.join(mediaText)
     59
     60          if mediaText:
     61              self.mediaText = mediaText
     62
     63          self._readonly = readonly
     64
     65      length = property(lambda self: len(self),
     66          doc="(DOM readonly) The number of media in the list.")
     67
     68 -    def _getMediaText(self):
     69          """
     70          returns serialized property mediaText
     71          """
     72          return cssutils.ser.do_stylesheets_medialist(self)
     73
     74 -    def _setMediaText(self, mediaText):
     75          """
     76          mediaText
     77              simple value or comma-separated list of media
     78
     79          DOMException
     80
     81          - SYNTAX_ERR: (MediaQuery)
     82            Raised if the specified string value has a syntax error and is
     83            unparsable.
     84          - NO_MODIFICATION_ALLOWED_ERR: (self)
     85            Raised if this media list is readonly.
     86          """
     87          self._checkReadonly()
     88          wellformed = True
     89          tokenizer = self._tokenize2(mediaText)
     90          newseq = []
     91
     92          expected = None
     93          while True:
     94              # find all upto and including next ",", EOF or nothing
     95              mqtokens = self._tokensupto2(tokenizer, listseponly=True)
     96              if mqtokens:
     97                  if self._tokenvalue(mqtokens[-1]) == ',':
     98                      expected = mqtokens.pop()
     99                  else:
    100                      expected = None
    101
    102                  mq = MediaQuery(mqtokens)
    103                  if mq.wellformed:
    104                      newseq.append(mq)
    105                  else:
    106                      wellformed = False
    107                      self._log.error(u'MediaList: Invalid MediaQuery: %s' %
    108                                      self._valuestr(mqtokens))
    109              else:
    110                  break
    111
    112          # post condition
    113          if expected:
    114              wellformed = False
    115              self._log.error(u'MediaList: Cannot end with ",".')
    116
    117          if wellformed:
    118              del self[:]
    119              for mq in newseq:
    120                  self.appendMedium(mq)
    121              self._wellformed = True
    122
    123      mediaText = property(_getMediaText, _setMediaText,
    124          doc="""(DOM) The parsable textual representation of the media list.
    125              This is a comma-separated list of media.""")
    126
    127      wellformed = property(lambda self: self._wellformed)
    128
    129 -    def __prepareset(self, newMedium):
    130          # used by appendSelector and __setitem__
    131          self._checkReadonly()
    132
    133          if not isinstance(newMedium, MediaQuery):
    134              newMedium = MediaQuery(newMedium)
    135
    136          if newMedium.wellformed:
    137              return newMedium
    138
    139 -    def __setitem__(self, index, newMedium):
    140          """
    141          overwrites ListSeq.__setitem__
    142
    143          Any duplicate items are **not** removed.
    144          """
    145          newMedium = self.__prepareset(newMedium)
    146          if newMedium:
    147              self.seq[index] = newMedium
    148          # TODO: remove duplicates?
    149
    150 -    def appendMedium(self, newMedium):
    151          """
    152          (DOM)
    153          Adds the medium newMedium to the end of the list. If the newMedium
    154          is already used, it is first removed.
    155
    156          newMedium
    157              a string or a MediaQuery object
    158
    159          returns if newMedium is wellformed
    160
    161          DOMException
    162
    163          - INVALID_CHARACTER_ERR: (self)
    164            If the medium contains characters that are invalid in the
    165            underlying style language.
    166          - INVALID_MODIFICATION_ERR (self)
    167            If mediaText is "all" and a new medium is tried to be added.
    168            Exception is "handheld" which is set in any case (Opera does handle
    169            "all, handheld" special, this special case might be removed in the
    170            future).
    171          - NO_MODIFICATION_ALLOWED_ERR: (self)
    172            Raised if this list is readonly.
    173          """
    174          newMedium = self.__prepareset(newMedium)
    175
    176          if newMedium:
    177              mts = [self._normalize(mq.mediaType) for mq in self]
    178              newmt = self._normalize(newMedium.mediaType)
    179
    180              if newmt in mts:
    181                  self.deleteMedium(newmt)
    182                  self.seq.append(newMedium)
    183              elif u'all' == newmt:
    184                  # remove all except handheld (Opera)
    185                  h = None
    186                  for mq in self:
    187                      if mq.mediaType == u'handheld':
    188                          h = mq
    189                  del self[:]
    190                  self.seq.append(newMedium)
    191                  if h:
    192                      self.append(h)
    193              elif u'all' in mts:
    194                  if u'handheld' == newmt:
    195                      self.seq.append(newMedium)
    196                      self._log.warn(u'MediaList: Already specified "all" but still setting new medium: %r' %
    197                                     newMedium, error=xml.dom.InvalidModificationErr, neverraise=True)
    198                  else:
    199                      self._log.warn(u'MediaList: Ignoring new medium %r as already specified "all" (set ``mediaText`` instead).' %
    200                                     newMedium, error=xml.dom.InvalidModificationErr)
    201                      xml.com
    202              else:
    203                  self.seq.append(newMedium)
    204
    205              return True
    206
    207          else:
    208              return False
    209
    210 -    def append(self, newMedium):
    211          "overwrites ListSeq.append"
    212          self.appendMedium(newMedium)
    213
    214 -    def deleteMedium(self, oldMedium):
    215          """
    216          (DOM)
    217          Deletes the medium indicated by oldMedium from the list.
    218
    219          DOMException
    220
    221          - NO_MODIFICATION_ALLOWED_ERR: (self)
    222            Raised if this list is readonly.
    223          - NOT_FOUND_ERR: (self)
    224            Raised if oldMedium is not in the list.
    225          """
    226          self._checkReadonly()
    227          oldMedium = self._normalize(oldMedium)
    228
    229          for i, mq in enumerate(self):
    230              if self._normalize(mq.mediaType) == oldMedium:
    231                  del self[i]
    232                  break
    233          else:
    234              self._log.error(u'"%s" not in this MediaList' % oldMedium,
    235                              error=xml.dom.NotFoundErr)
    236  #            raise xml.dom.NotFoundErr(
    237  #                u'"%s" not in this MediaList' % oldMedium)
    238
    239 -    def item(self, index):
    240          """
    241          (DOM)
    242          Returns the mediaType of the index'th element in the list.
    243          If index is greater than or equal to the number of media in the
    244          list, returns None.
    245          """
    246          try:
    247              return self[index].mediaType
    248          except IndexError:
    249              return None
    250
    251 -    def __repr__(self):
    252          return "cssutils.stylesheets.%s(mediaText=%r)" % (
    253                  self.__class__.__name__, self.mediaText)
    254
    255 -    def __str__(self):
    256          return "<cssutils.stylesheets.%s object mediaText=%r at 0x%x>" % (
    257                  self.__class__.__name__, self.mediaText, id(self))
    258