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 1423 2008-08-11 12:43:22Z 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              else:
    202                  self.seq.append(newMedium)
    203
    204              return True
    205
    206          else:
    207              return False
    208
    209 -    def append(self, newMedium):
    210          "overwrites ListSeq.append"
    211          self.appendMedium(newMedium)
    212
    213 -    def deleteMedium(self, oldMedium):
    214          """
    215          (DOM)
    216          Deletes the medium indicated by oldMedium from the list.
    217
    218          DOMException
    219
    220          - NO_MODIFICATION_ALLOWED_ERR: (self)
    221            Raised if this list is readonly.
    222          - NOT_FOUND_ERR: (self)
    223            Raised if oldMedium is not in the list.
    224          """
    225          self._checkReadonly()
    226          oldMedium = self._normalize(oldMedium)
    227
    228          for i, mq in enumerate(self):
    229              if self._normalize(mq.mediaType) == oldMedium:
    230                  del self[i]
    231                  break
    232          else:
    233              self._log.error(u'"%s" not in this MediaList' % oldMedium,
    234                              error=xml.dom.NotFoundErr)
    235  #            raise xml.dom.NotFoundErr(
    236  #                u'"%s" not in this MediaList' % oldMedium)
    237
    238 -    def item(self, index):
    239          """
    240          (DOM)
    241          Returns the mediaType of the index'th element in the list.
    242          If index is greater than or equal to the number of media in the
    243          list, returns None.
    244          """
    245          try:
    246              return self[index].mediaType
    247          except IndexError:
    248              return None
    249
    250 -    def __repr__(self):
    251          return "cssutils.stylesheets.%s(mediaText=%r)" % (
    252                  self.__class__.__name__, self.mediaText)
    253
    254 -    def __str__(self):
    255          return "<cssutils.stylesheets.%s object mediaText=%r at 0x%x>" % (
    256                  self.__class__.__name__, self.mediaText, id(self))
    257