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  __author__ = '$LastChangedBy: cthedot $'
     15  __date__ = '$LastChangedDate: 2007-09-16 00:00:19 +0200 (So, 16 Sep 2007) $'
     16  __version__ = '$LastChangedRevision: 357 $'
     17
     18  import re
     19  import xml.dom
     20  import cssutils
     21
     22 -class MediaQuery(cssutils.util.Base):
     23      """
     24      A Media Query consists of a media type and one or more
     25      expressions involving media features.
     26
     27      Properties
     28      ==========
     29      mediaText: of type DOMString
     30          The parsable textual representation of this MediaQuery
     31      mediaType: of type DOMString
     32          one of MEDIA_TYPES like e.g. 'print'
     33      seq: a list (cssutils)
     34          All parts of this MediaQuery including CSSComments
     35      valid:
     36          if this query is valid
     37
     38      Format
     39      ======
     40      ::
     41
     42          media_query: [[only | not]? <media_type> [ and <expression> ]*]
     43            | <expression> [ and <expression> ]*
     44          expression: ( <media_feature> [: <value>]? )
     45          media_type: all | aural | braille | handheld | print |
     46            projection | screen | tty | tv | embossed
     47          media_feature: width | min-width | max-width
     48            | height | min-height | max-height
     49            | device-width | min-device-width | max-device-width
     50            | device-height | min-device-height | max-device-height
     51            | device-aspect-ratio | min-device-aspect-ratio | max-device-aspect-ratio
     52            | color | min-color | max-color
     53            | color-index | min-color-index | max-color-index
     54            | monochrome | min-monochrome | max-monochrome
     55            | resolution | min-resolution | max-resolution
     56            | scan | grid
     57
     58      """
     59      MEDIA_TYPES = [u'all', u'aural', u'braille', u'embossed', u'handheld',
     60          u'print', u'projection', u'screen', u'tty', u'tv']
     61
     62      # From the HTML spec (see MediaQuery):
     63      # "[...] character that isn't a US ASCII letter [a-zA-Z] (Unicode
     64      # decimal 65-90, 97-122), digit [0-9] (Unicode hex 30-39), or hyphen (45)."
     65      # so the following is a valid mediaType
     66      __mediaTypeMatch = re.compile(ur'^[-a-zA-Z0-9]+$', re.U).match
     67
     68 -    def __init__(self, mediaText=None, readonly=False):
     69          """
     70          mediaText
     71              unicodestring of parsable media
     72          """
     73          super(MediaQuery, self).__init__()
     74
     75          self.valid = False
     76          self.seq = []
     77          self._mediaType = u''
     78          if mediaText:
     79              self.mediaText = mediaText # sets self._mediaType too
     80
     81          self._readonly = readonly
     82
     83 -    def _getMediaText(self):
     84          """
     85          returns serialized property mediaText
     86          """
     87          return cssutils.ser.do_stylesheets_mediaquery(self)
     88
     89 -    def _setMediaText(self, mediaText):
     90          """
     91          mediaText
     92              a single media query string, e.g. "print and (min-width: 25cm)"
     93
     94          DOMException
     95
     96          - SYNTAX_ERR: (self)
     97            Raised if the specified string value has a syntax error and is
     98            unparsable.
     99          - INVALID_CHARACTER_ERR: (self)
    100            Raised if the given mediaType is unknown.
    101          - NO_MODIFICATION_ALLOWED_ERR: (self)
    102            Raised if this media query is readonly.
    103          """
    104          self._checkReadonly()
    105          tokenizer = self._tokenize2(mediaText)
    106          if not tokenizer:
    107              self._log.error(u'MediaQuery: No MediaText given.')
    108          else:
    109              # for closures: must be a mutable
    110              new = {'mediatype': None,
    111                     'valid': True }
    112
    113              def _ident_or_dim(expected, seq, token, tokenizer=None):
    114                  # only|not or mediatype or and
    115                  val = self._tokenvalue(token)
    116                  nval = self._normalize(val)
    117                  if expected.endswith('mediatype'):
    118                      if nval in (u'only', u'not'):
    119                          # only or not
    120                          seq.append(val)
    121                          return 'mediatype'
    122                      else:
    123                          # mediatype
    124                          new['mediatype'] = val
    125                          seq.append(val)
    126                          return 'and'
    127                  elif 'and' == nval and expected.startswith('and'):
    128                      seq.append(u'and')
    129                      return 'feature'
    130                  else:
    131                      self._log.error(
    132                          u'MediaQuery: Unexpected syntax.', token=token)
    133                      return expected
    134
    135              def _char(expected, seq, token, tokenizer=None):
    136                  # starting a feature which basically is a CSS Property
    137                  # but may simply be a property name too
    138                  val = self._tokenvalue(token)
    139                  if val == u'(' and expected == 'feature':
    140                      proptokens = self._tokensupto2(
    141                          tokenizer, funcendonly=True, keepEnd=False)
    142                      property = cssutils.css.Property(_mediaQuery=True)
    143                      property.cssText = proptokens
    144                      seq.append(property)
    145                      return 'and or EOF'
    146                  else:
    147                      self._log.error(
    148                          u'MediaQuery: Unexpected syntax, expected "and" but found "%s".' %
    149                          val, token)
    150                      return expected
    151
    152              # expected: only|not or mediatype, mediatype, feature, and
    153              newseq = []
    154              valid, expected = self._parse(expected='only|not or mediatype',
    155                  seq=newseq, tokenizer=tokenizer,
    156                  productions={'IDENT': _ident_or_dim, # e.g. "print"
    157                               'DIMENSION': _ident_or_dim, # e.g. "3d"
    158                               'CHAR': _char})
    159              valid = valid and new['valid']
    160
    161              # post conditions
    162              if not new['mediatype']:
    163                  valid = False
    164                  self._log.error(u'MediaQuery: No mediatype found: %s' %
    165                      self._valuestr(mediaText))
    166
    167              if valid:
    168                  # set
    169                  self.mediaType = new['mediatype']
    170                  self.seq = newseq
    171                  self.valid = valid
    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
    211              # set
    212              self._mediaType = mediaType
    213
    214              # update seq
    215              for i, x in enumerate(self.seq):
    216                  if isinstance(x, basestring):
    217                      if self._normalize(x) in (u'only', u'not'):
    218                          continue
    219                      else:
    220                          self.seq[i] = mediaType
    221                          break
    222              else:
    223                  self.seq.insert(0, mediaType)
    224
    225      mediaType = property(_getMediaType, _setMediaType,
    226          doc="""(DOM) media type (one of MediaQuery.MEDIA_TYPES) of this MediaQuery.""")
    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