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      wellformed:
     36          if this query is wellformed
     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.seq = []
     76          self._mediaType = u''
     77          if mediaText:
     78              self.mediaText = mediaText # sets self._mediaType too
     79
     80          self._readonly = readonly
     81
     82 -    def _getMediaText(self):
     83          """
     84          returns serialized property mediaText
     85          """
     86          return cssutils.ser.do_stylesheets_mediaquery(self)
     87
     88 -    def _setMediaText(self, mediaText):
     89          """
     90          mediaText
     91              a single media query string, e.g. "print and (min-width: 25cm)"
     92
     93          DOMException
     94
     95          - SYNTAX_ERR: (self)
     96            Raised if the specified string value has a syntax error and is
     97            unparsable.
     98          - INVALID_CHARACTER_ERR: (self)
     99            Raised if the given mediaType is unknown.
    100          - NO_MODIFICATION_ALLOWED_ERR: (self)
    101            Raised if this media query is readonly.
    102          """
    103          self._checkReadonly()
    104          tokenizer = self._tokenize2(mediaText)
    105          if not tokenizer:
    106              self._log.error(u'MediaQuery: No MediaText given.')
    107          else:
    108              # for closures: must be a mutable
    109              new = {'mediatype': None,
    110                     'wellformed': True }
    111
    112              def _ident_or_dim(expected, seq, token, tokenizer=None):
    113                  # only|not or mediatype or and
    114                  val = self._tokenvalue(token)
    115                  nval = self._normalize(val)
    116                  if expected.endswith('mediatype'):
    117                      if nval in (u'only', u'not'):
    118                          # only or not
    119                          seq.append(val)
    120                          return 'mediatype'
    121                      else:
    122                          # mediatype
    123                          new['mediatype'] = val
    124                          seq.append(val)
    125                          return 'and'
    126                  elif 'and' == nval and expected.startswith('and'):
    127                      seq.append(u'and')
    128                      return 'feature'
    129                  else:
    130                      self._log.error(
    131                          u'MediaQuery: Unexpected syntax.', token=token)
    132                      return expected
    133
    134              def _char(expected, seq, token, tokenizer=None):
    135                  # starting a feature which basically is a CSS Property
    136                  # but may simply be a property name too
    137                  val = self._tokenvalue(token)
    138                  if val == u'(' and expected == 'feature':
    139                      proptokens = self._tokensupto2(
    140                          tokenizer, funcendonly=True)
    141                      if proptokens and u')' == self._tokenvalue(proptokens[-1]):
    142                          proptokens.pop()
    143                      property = cssutils.css.Property(_mediaQuery=True)
    144                      property.cssText = proptokens
    145                      seq.append(property)
    146                      return 'and or EOF'
    147                  else:
    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
    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      wellformed = property(lambda self: bool(len(self.seq)))
    229
    230 -    def __repr__(self):
    231          return "cssutils.stylesheets.%s(mediaText=%r)" % (
    232                  self.__class__.__name__, self.mediaText)
    233
    234 -    def __str__(self):
    235          return "<cssutils.stylesheets.%s object mediaText=%r at 0x%x>" % (
    236                  self.__class__.__name__, self.mediaText, id(self))
    237