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 1363 2008-07-13 18:14:26Z 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                      new['wellformed'] = False
    129                      self._log.error(
    130                          u'MediaQuery: Unexpected syntax.', token=token)
    131                      return expected
    132
    133              def _char(expected, seq, token, tokenizer=None):
    134                  # starting a feature which basically is a CSS Property
    135                  # but may simply be a property name too
    136                  val = self._tokenvalue(token)
    137                  if val == u'(' and expected == 'feature':
    138                      proptokens = self._tokensupto2(
    139                          tokenizer, funcendonly=True)
    140                      if proptokens and u')' == self._tokenvalue(proptokens[-1]):
    141                          proptokens.pop()
    142                      property = cssutils.css.Property(_mediaQuery=True)
    143                      property.cssText = proptokens
    144                      seq.append(property)
    145                      return 'and or EOF'
    146                  else:
    147                      new['wellformed'] = False
    148                      self._log.error(
    149                          u'MediaQuery: Unexpected syntax, expected "and" but found "%s".' %
    150                          val, token)
    151                      return expected
    152
    153              # expected: only|not or mediatype, mediatype, feature, and
    154              newseq = []
    155              wellformed, expected = self._parse(expected='only|not or mediatype',
    156                  seq=newseq, tokenizer=tokenizer,
    157                  productions={'IDENT': _ident_or_dim, # e.g. "print"
    158                               'DIMENSION': _ident_or_dim, # e.g. "3d"
    159                               'CHAR': _char})
    160              wellformed = wellformed and new['wellformed']
    161
    162              # post conditions
    163              if not new['mediatype']:
    164                  wellformed = False
    165                  self._log.error(u'MediaQuery: No mediatype found: %s' %
    166                      self._valuestr(mediaText))
    167
    168              if wellformed:
    169                  # set
    170                  self.mediaType = new['mediatype']
    171                  self.seq = newseq
    172
    173      mediaText = property(_getMediaText, _setMediaText,
    174          doc="""(DOM) The parsable textual representation of the media list.
    175              This is a comma-separated list of media.""")
    176
    177 -    def _getMediaType(self):
    178          """
    179          returns serialized property mediaText
    180          """
    181          return self._mediaType
    182
    183 -    def _setMediaType(self, mediaType):
    184          """
    185          mediaType
    186              one of MEDIA_TYPES
    187
    188          DOMException
    189
    190          - SYNTAX_ERR: (self)
    191            Raised if the specified string value has a syntax error and is
    192            unparsable.
    193          - INVALID_CHARACTER_ERR: (self)
    194            Raised if the given mediaType is unknown.
    195          - NO_MODIFICATION_ALLOWED_ERR: (self)
    196            Raised if this media query is readonly.
    197          """
    198          self._checkReadonly()
    199          nmediaType = self._normalize(mediaType)
    200
    201          if not MediaQuery.__mediaTypeMatch(nmediaType):
    202              self._log.error(
    203                  u'MediaQuery: Syntax Error in media type "%s".' % mediaType,
    204                  error=xml.dom.SyntaxErr)
    205          else:
    206              if nmediaType not in MediaQuery.MEDIA_TYPES:
    207                  self._log.warn(
    208                      u'MediaQuery: Unknown media type "%s".' % mediaType,
    209                      error=xml.dom.InvalidCharacterErr)
    210                  return
    211
    212              # set
    213              self._mediaType = mediaType
    214
    215              # update seq
    216              for i, x in enumerate(self.seq):
    217                  if isinstance(x, basestring):
    218                      if self._normalize(x) in (u'only', u'not'):
    219                          continue
    220                      else:
    221                          self.seq[i] = mediaType
    222                          break
    223              else:
    224                  self.seq.insert(0, mediaType)
    225
    226      mediaType = property(_getMediaType, _setMediaType,
    227          doc="""(DOM) media type (one of MediaQuery.MEDIA_TYPES) of this MediaQuery.""")
    228
    229      wellformed = property(lambda self: bool(len(self.seq)))
    230
    231 -    def __repr__(self):
    232          return "cssutils.stylesheets.%s(mediaText=%r)" % (
    233                  self.__class__.__name__, self.mediaText)
    234
    235 -    def __str__(self):
    236          return "<cssutils.stylesheets.%s object mediaText=%r at 0x%x>" % (
    237                  self.__class__.__name__, self.mediaText, id(self))
    238