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

# Source Code for Module cssutils.stylesheets.mediaquery

      1  """
      2  MediaQuery, see http://www.w3.org/TR/css3-mediaqueries/
      3
      4  A cssutils own implementation, not defined in official DOM
      5
      6  TODO:
      7      add possibility to
      8
      9  part of a media_query_list: <media_query> [, <media_query> ]*
     10  see stylesheets.MediaList
     11  """
     12  __all__ = ['MediaQuery']
     13  __docformat__ = 'restructuredtext'
     14  __version__ = '$Id: mediaquery.py 1116 2008-03-05 13:52:23Z cthedot $'
     15
     16  import re
     17  import xml.dom
     18  import cssutils
     19
     20 -class MediaQuery(cssutils.util.Base):
     21      """
     22      A Media Query consists of a media type and one or more
     23      expressions involving media features.
     24
     25      Properties
     26      ==========
     27      mediaText: of type DOMString
     28          The parsable textual representation of this MediaQuery
     29      mediaType: of type DOMString
     30          one of MEDIA_TYPES like e.g. 'print'
     31      seq: a list (cssutils)
     32          All parts of this MediaQuery including CSSComments
     33      wellformed:
     34          if this query is wellformed
     35
     36      Format
     37      ======
     38      ::
     39
     40          media_query: [[only | not]? <media_type> [ and <expression> ]*]
     41            | <expression> [ and <expression> ]*
     42          expression: ( <media_feature> [: <value>]? )
     43          media_type: all | aural | braille | handheld | print |
     44            projection | screen | tty | tv | embossed
     45          media_feature: width | min-width | max-width
     46            | height | min-height | max-height
     47            | device-width | min-device-width | max-device-width
     48            | device-height | min-device-height | max-device-height
     49            | device-aspect-ratio | min-device-aspect-ratio | max-device-aspect-ratio
     50            | color | min-color | max-color
     51            | color-index | min-color-index | max-color-index
     52            | monochrome | min-monochrome | max-monochrome
     53            | resolution | min-resolution | max-resolution
     54            | scan | grid
     55
     56      """
     57      MEDIA_TYPES = [u'all', u'aural', u'braille', u'embossed', u'handheld',
     58          u'print', u'projection', u'screen', u'tty', u'tv']
     59
     60      # From the HTML spec (see MediaQuery):
     61      # "[...] character that isn't a US ASCII letter [a-zA-Z] (Unicode
     62      # decimal 65-90, 97-122), digit [0-9] (Unicode hex 30-39), or hyphen (45)."
     63      # so the following is a valid mediaType
     64      __mediaTypeMatch = re.compile(ur'^[-a-zA-Z0-9]+$', re.U).match
     65
     66 -    def __init__(self, mediaText=None, readonly=False):
     67          """
     68          mediaText
     69              unicodestring of parsable media
     70          """
     71          super(MediaQuery, self).__init__()
     72
     73          self.seq = []
     74          self._mediaType = u''
     75          if mediaText:
     76              self.mediaText = mediaText # sets self._mediaType too
     77
     78          self._readonly = readonly
     79
     80 -    def _getMediaText(self):
     81          """
     82          returns serialized property mediaText
     83          """
     84          return cssutils.ser.do_stylesheets_mediaquery(self)
     85
     86 -    def _setMediaText(self, mediaText):
     87          """
     88          mediaText
     89              a single media query string, e.g. "print and (min-width: 25cm)"
     90
     91          DOMException
     92
     93          - SYNTAX_ERR: (self)
     94            Raised if the specified string value has a syntax error and is
     95            unparsable.
     96          - INVALID_CHARACTER_ERR: (self)
     97            Raised if the given mediaType is unknown.
     98          - NO_MODIFICATION_ALLOWED_ERR: (self)
     99            Raised if this media query is readonly.
    100          """
    101          self._checkReadonly()
    102          tokenizer = self._tokenize2(mediaText)
    103          if not tokenizer:
    104              self._log.error(u'MediaQuery: No MediaText given.')
    105          else:
    106              # for closures: must be a mutable
    107              new = {'mediatype': None,
    108                     'wellformed': True }
    109
    110              def _ident_or_dim(expected, seq, token, tokenizer=None):
    111                  # only|not or mediatype or and
    112                  val = self._tokenvalue(token)
    113                  nval = self._normalize(val)
    114                  if expected.endswith('mediatype'):
    115                      if nval in (u'only', u'not'):
    116                          # only or not
    117                          seq.append(val)
    118                          return 'mediatype'
    119                      else:
    120                          # mediatype
    121                          new['mediatype'] = val
    122                          seq.append(val)
    123                          return 'and'
    124                  elif 'and' == nval and expected.startswith('and'):
    125                      seq.append(u'and')
    126                      return 'feature'
    127                  else:
    128                      self._log.error(
    129                          u'MediaQuery: Unexpected syntax.', token=token)
    130                      return expected
    131
    132              def _char(expected, seq, token, tokenizer=None):
    133                  # starting a feature which basically is a CSS Property
    134                  # but may simply be a property name too
    135                  val = self._tokenvalue(token)
    136                  if val == u'(' and expected == 'feature':
    137                      proptokens = self._tokensupto2(
    138                          tokenizer, funcendonly=True)
    139                      if proptokens and u')' == self._tokenvalue(proptokens[-1]):
    140                          proptokens.pop()
    141                      property = cssutils.css.Property(_mediaQuery=True)
    142                      property.cssText = proptokens
    143                      seq.append(property)
    144                      return 'and or EOF'
    145                  else:
    146                      self._log.error(
    147                          u'MediaQuery: Unexpected syntax, expected "and" but found "%s".' %
    148                          val, token)
    149                      return expected
    150
    151              # expected: only|not or mediatype, mediatype, feature, and
    152              newseq = []
    153              wellformed, expected = self._parse(expected='only|not or mediatype',
    154                  seq=newseq, tokenizer=tokenizer,
    155                  productions={'IDENT': _ident_or_dim, # e.g. "print"
    156                               'DIMENSION': _ident_or_dim, # e.g. "3d"
    157                               'CHAR': _char})
    158              wellformed = wellformed and new['wellformed']
    159
    160              # post conditions
    161              if not new['mediatype']:
    162                  wellformed = False
    163                  self._log.error(u'MediaQuery: No mediatype found: %s' %
    164                      self._valuestr(mediaText))
    165
    166              if wellformed:
    167                  # set
    168                  self.mediaType = new['mediatype']
    169                  self.seq = newseq
    170
    171      mediaText = property(_getMediaText, _setMediaText,
    172          doc="""(DOM) The parsable textual representation of the media list.
    173              This is a comma-separated list of media.""")
    174
    175 -    def _getMediaType(self):
    176          """
    177          returns serialized property mediaText
    178          """
    179          return self._mediaType
    180
    181 -    def _setMediaType(self, mediaType):
    182          """
    183          mediaType
    184              one of MEDIA_TYPES
    185
    186          DOMException
    187
    188          - SYNTAX_ERR: (self)
    189            Raised if the specified string value has a syntax error and is
    190            unparsable.
    191          - INVALID_CHARACTER_ERR: (self)
    192            Raised if the given mediaType is unknown.
    193          - NO_MODIFICATION_ALLOWED_ERR: (self)
    194            Raised if this media query is readonly.
    195          """
    196          self._checkReadonly()
    197          nmediaType = self._normalize(mediaType)
    198
    199          if not MediaQuery.__mediaTypeMatch(nmediaType):
    200              self._log.error(
    201                  u'MediaQuery: Syntax Error in media type "%s".' % mediaType,
    202                  error=xml.dom.SyntaxErr)
    203          else:
    204              if nmediaType not in MediaQuery.MEDIA_TYPES:
    205                  self._log.warn(
    206                      u'MediaQuery: Unknown media type "%s".' % mediaType,
    207                      error=xml.dom.InvalidCharacterErr)
    208
    209              # set
    210              self._mediaType = mediaType
    211
    212              # update seq
    213              for i, x in enumerate(self.seq):
    214                  if isinstance(x, basestring):
    215                      if self._normalize(x) in (u'only', u'not'):
    216                          continue
    217                      else:
    218                          self.seq[i] = mediaType
    219                          break
    220              else:
    221                  self.seq.insert(0, mediaType)
    222
    223      mediaType = property(_getMediaType, _setMediaType,
    224          doc="""(DOM) media type (one of MediaQuery.MEDIA_TYPES) of this MediaQuery.""")
    225
    226      wellformed = property(lambda self: bool(len(self.seq)))
    227
    228 -    def __repr__(self):
    229          return "cssutils.stylesheets.%s(mediaText=%r)" % (
    230                  self.__class__.__name__, self.mediaText)
    231
    232 -    def __str__(self):
    233          return "<cssutils.stylesheets.%s object mediaText=%r at 0x%x>" % (
    234                  self.__class__.__name__, self.mediaText, id(self))
    235