1 """CSSImportRule implements DOM Level 2 CSS CSSImportRule.
2
3 plus:
4
5 ``name`` property
6 http://www.w3.org/TR/css3-cascade/#cascading
7
8 """
9 __all__ = ['CSSImportRule']
10 __docformat__ = 'restructuredtext'
11 __version__ = '$Id: cssimportrule.py 1401 2008-07-29 21:07:54Z cthedot $'
12
13 import os
14 import urllib
15 import urlparse
16 import xml.dom
17 import cssrule
18 import cssutils
19
21 """
22 Represents an @import rule within a CSS style sheet. The @import rule
23 is used to import style rules from other style sheets.
24
25 Properties
26 ==========
27 atkeyword: (cssutils only)
28 the literal keyword used
29 cssText: of type DOMString
30 The parsable textual representation of this rule
31 href: of type DOMString, (DOM readonly, cssutils also writable)
32 The location of the style sheet to be imported. The attribute will
33 not contain the url(...) specifier around the URI.
34 hreftype: 'uri' (serializer default) or 'string' (cssutils only)
35 The original type of href, not really relevant as it may be
36 reconfigured in the serializer but it is kept anyway
37 media: of type stylesheets::MediaList (DOM readonly)
38 A list of media types for this rule of type MediaList.
39 name:
40 An optional name used for cascading
41 styleSheet: of type CSSStyleSheet (DOM readonly)
42 The style sheet referred to by this rule. The value of this
43 attribute is None if the style sheet has not yet been loaded or if
44 it will not be loaded (e.g. if the stylesheet is for a media type
45 not supported by the user agent).
46
47 Inherits properties from CSSRule
48
49 Format
50 ======
51 import
52 : IMPORT_SYM S*
53 [STRING|URI] S* [ medium [ COMMA S* medium]* ]? S* STRING? S* ';' S*
54 ;
55 """
56 type = property(lambda self: cssrule.CSSRule.IMPORT_RULE)
57
58 - def __init__(self, href=None, mediaText=u'all', name=None,
59 parentRule=None, parentStyleSheet=None, readonly=False):
92
93 _usemedia = property(lambda self: self.media.mediaText not in (u'', u'all'),
94 doc="if self._media is used (or simply empty)")
95
96 - def _getCssText(self):
97 """
98 returns serialized property cssText
99 """
100 return cssutils.ser.do_CSSImportRule(self)
101
102 - def _setCssText(self, cssText):
103 """
104 DOMException on setting
105
106 - HIERARCHY_REQUEST_ERR: (CSSStylesheet)
107 Raised if the rule cannot be inserted at this point in the
108 style sheet.
109 - INVALID_MODIFICATION_ERR: (self)
110 Raised if the specified CSS string value represents a different
111 type of rule than the current one.
112 - NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
113 Raised if the rule is readonly.
114 - SYNTAX_ERR: (self)
115 Raised if the specified CSS string value has a syntax error and
116 is unparsable.
117 """
118 super(CSSImportRule, self)._setCssText(cssText)
119 tokenizer = self._tokenize2(cssText)
120 attoken = self._nexttoken(tokenizer, None)
121 if self._type(attoken) != self._prods.IMPORT_SYM:
122 self._log.error(u'CSSImportRule: No CSSImportRule found: %s' %
123 self._valuestr(cssText),
124 error=xml.dom.InvalidModificationErr)
125 else:
126
127 new = {'keyword': self._tokenvalue(attoken),
128 'href': None,
129 'hreftype': None,
130 'media': None,
131 'name': None,
132 'wellformed': True
133 }
134
135 def __doname(seq, token):
136
137 new['name'] = self._stringtokenvalue(token)
138 seq.append(new['name'], 'name')
139 return ';'
140
141 def _string(expected, seq, token, tokenizer=None):
142 if 'href' == expected:
143
144 new['href'] = self._stringtokenvalue(token)
145 new['hreftype'] = 'string'
146 seq.append(new['href'], 'href')
147 return 'media name ;'
148 elif 'name' in expected:
149
150 return __doname(seq, token)
151 else:
152 new['wellformed'] = False
153 self._log.error(
154 u'CSSImportRule: Unexpected string.', token)
155 return expected
156
157 def _uri(expected, seq, token, tokenizer=None):
158
159 if 'href' == expected:
160 uri = self._uritokenvalue(token)
161 new['hreftype'] = 'uri'
162 new['href'] = uri
163 seq.append(new['href'], 'href')
164 return 'media name ;'
165 else:
166 new['wellformed'] = False
167 self._log.error(
168 u'CSSImportRule: Unexpected URI.', token)
169 return expected
170
171 def _ident(expected, seq, token, tokenizer=None):
172
173 if expected.startswith('media'):
174 mediatokens = self._tokensupto2(
175 tokenizer, importmediaqueryendonly=True)
176 mediatokens.insert(0, token)
177
178 last = mediatokens.pop()
179 lastval, lasttyp = self._tokenvalue(last), self._type(last)
180 if lastval != u';' and lasttyp not in ('EOF', self._prods.STRING):
181 new['wellformed'] = False
182 self._log.error(u'CSSImportRule: No ";" found: %s' %
183 self._valuestr(cssText), token=token)
184
185 media = cssutils.stylesheets.MediaList()
186 media.mediaText = mediatokens
187 if media.wellformed:
188 new['media'] = media
189 seq.append(media, 'media')
190 else:
191 new['wellformed'] = False
192 self._log.error(u'CSSImportRule: Invalid MediaList: %s' %
193 self._valuestr(cssText), token=token)
194
195 if lasttyp == self._prods.STRING:
196
197 return __doname(seq, last)
198 else:
199 return 'EOF'
200 else:
201 new['wellformed'] = False
202 self._log.error(
203 u'CSSImportRule: Unexpected ident.', token)
204 return expected
205
206 def _char(expected, seq, token, tokenizer=None):
207
208 val = self._tokenvalue(token)
209 if expected.endswith(';') and u';' == val:
210 return 'EOF'
211 else:
212 new['wellformed'] = False
213 self._log.error(
214 u'CSSImportRule: Unexpected char.', token)
215 return expected
216
217
218
219
220
221 newseq = self._tempSeq()
222 wellformed, expected = self._parse(expected='href',
223 seq=newseq, tokenizer=tokenizer,
224 productions={'STRING': _string,
225 'URI': _uri,
226 'IDENT': _ident,
227 'CHAR': _char},
228 new=new)
229
230
231 wellformed = wellformed and new['wellformed']
232
233
234 if not new['href']:
235 wellformed = False
236 self._log.error(u'CSSImportRule: No href found: %s' %
237 self._valuestr(cssText))
238
239 if expected != 'EOF':
240 wellformed = False
241 self._log.error(u'CSSImportRule: No ";" found: %s' %
242 self._valuestr(cssText))
243
244
245 if wellformed:
246 self.atkeyword = new['keyword']
247 self.hreftype = new['hreftype']
248 if new['media']:
249
250 self.media.mediaText = new['media'].mediaText
251
252 for index, x in enumerate(newseq):
253 if x.type == 'media':
254 newseq.replace(index, self.media,
255 x.type, x.line, x.col)
256 break
257 else:
258
259 self.media.mediaText = u'all'
260 newseq.append(self.media, 'media')
261 self.name = new['name']
262 self._setSeq(newseq)
263 self.href = new['href']
264
265 if self.styleSheet:
266
267
268 self.styleSheet._parentStyleSheet = self.parentStyleSheet
269
270 cssText = property(fget=_getCssText, fset=_setCssText,
271 doc="(DOM attribute) The parsable textual representation.")
272
289
290 href = property(lambda self: self._href, _setHref,
291 doc="Location of the style sheet to be imported.")
292
293 media = property(lambda self: self._media,
294 doc=u"(DOM readonly) A list of media types for this rule"
295 " of type MediaList")
296
298 """raises xml.dom.SyntaxErr if name is not a string"""
299 if isinstance(name, basestring) or name is None:
300
301 if not name:
302 name = None
303
304 for i, item in enumerate(self.seq):
305 val, typ = item.value, item.type
306 if 'name' == typ:
307 self._seq[i] = (name, typ, item.line, item.col)
308 break
309 else:
310
311 seq = self._tempSeq()
312 for item in self.seq:
313
314 seq.append(item.value, item.type, item.line, item.col)
315 seq.append(name, 'name')
316 self._setSeq(seq)
317 self._name = name
318
319 if self.styleSheet:
320 self.styleSheet.title = name
321 else:
322 self._log.error(u'CSSImportRule: Not a valid name: %s' % name)
323
324 name = property(lambda self: self._name, _setName,
325 doc=u"An optional name for the imported sheet")
326
328 """Read new CSSStyleSheet cssText from href using parentStyleSheet.href
329
330 Indirectly called if setting ``href``. In case of any error styleSheet
331 is set to ``None``.
332 """
333
334 if self.parentStyleSheet and self.href:
335
336 parentHref = self.parentStyleSheet.href
337 if parentHref is None:
338
339 parentHref = u'file:' + urllib.pathname2url(os.getcwd()) + '/'
340 href = urlparse.urljoin(parentHref, self.href)
341
342
343 try:
344 usedEncoding, enctype, cssText = self.parentStyleSheet._resolveImport(href)
345 if cssText is None:
346
347 raise IOError('Cannot read Stylesheet.')
348 styleSheet = cssutils.css.CSSStyleSheet(href=href,
349 media=self.media,
350 ownerRule=self,
351 title=self.name)
352
353 styleSheet._setFetcher(self.parentStyleSheet._fetcher)
354
355
356 encodingOverride, encoding = None, None
357 if enctype == 0:
358 encodingOverride = usedEncoding
359 elif 5 > enctype > 0:
360 encoding = usedEncoding
361
362 styleSheet._setCssTextWithEncodingOverride(cssText,
363 encodingOverride=encodingOverride,
364 encoding=encoding)
365
366 except (OSError, IOError, ValueError), e:
367 self._log.warn(u'CSSImportRule: While processing imported style sheet href=%r: %r'
368 % (self.href, e), neverraise=True)
369 else:
370 self._styleSheet = styleSheet
371
372 styleSheet = property(lambda self: self._styleSheet,
373 doc="(readonly) The style sheet referred to by this rule.")
374
381
382 wellformed = property(_getWellformed)
383
392
400