~ubuntu-branches/ubuntu/jaunty/calibre/jaunty-backports

« back to all changes in this revision

Viewing changes to src/cssutils/stylesheets/mediaquery.py

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-01-20 17:14:02 UTC
  • Revision ID: james.westby@ubuntu.com-20090120171402-8y3znf6nokwqe80k
Tags: upstream-0.4.125+dfsg
ImportĀ upstreamĀ versionĀ 0.4.125+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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))