Package cssutils :: Package css :: Module cssmediarule
[hide private]
[frames] | no frames]

Source Code for Module cssutils.css.cssmediarule

  1  """CSSMediaRule implements DOM Level 2 CSS CSSMediaRule. 
  2  """ 
  3  __all__ = ['CSSMediaRule'] 
  4  __docformat__ = 'restructuredtext' 
  5  __version__ = '$Id: cssmediarule.py 1116 2008-03-05 13:52:23Z cthedot $' 
  6   
  7  import xml.dom 
  8  import cssrule 
  9  import cssutils 
 10   
11 -class CSSMediaRule(cssrule.CSSRule):
12 """ 13 Objects implementing the CSSMediaRule interface can be identified by the 14 MEDIA_RULE constant. On these objects the type attribute must return the 15 value of that constant. 16 17 Properties 18 ========== 19 atkeyword: (cssutils only) 20 the literal keyword used 21 cssRules: A css::CSSRuleList of all CSS rules contained within the 22 media block. 23 cssText: of type DOMString 24 The parsable textual representation of this rule 25 media: of type stylesheets::MediaList, (DOM readonly) 26 A list of media types for this rule of type MediaList. 27 name: 28 An optional name used for cascading 29 30 Format 31 ====== 32 media 33 : MEDIA_SYM S* medium [ COMMA S* medium ]* 34 35 STRING? # the name 36 37 LBRACE S* ruleset* '}' S*; 38 """ 39 # CONSTANT 40 type = cssrule.CSSRule.MEDIA_RULE 41
42 - def __init__(self, mediaText='all', name=None, 43 parentRule=None, parentStyleSheet=None, readonly=False):
44 """ 45 constructor 46 """ 47 super(CSSMediaRule, self).__init__(parentRule=parentRule, 48 parentStyleSheet=parentStyleSheet) 49 self.atkeyword = u'@media' 50 self._media = cssutils.stylesheets.MediaList( 51 mediaText, readonly=readonly) 52 if not self.media.wellformed: 53 self._media = cssutils.stylesheets.MediaList() 54 self.name = name 55 56 self.cssRules = cssutils.css.cssrulelist.CSSRuleList() 57 self.cssRules.append = self.insertRule 58 self.cssRules.extend = self.insertRule 59 self.cssRules.__delitem__ == self.deleteRule 60 61 self._readonly = readonly
62
63 - def __iter__(self):
64 """ 65 generator which iterates over cssRules. 66 """ 67 for rule in self.cssRules: 68 yield rule
69
70 - def _getCssText(self):
71 """ 72 returns serialized property cssText 73 """ 74 return cssutils.ser.do_CSSMediaRule(self)
75
76 - def _setCssText(self, cssText):
77 """ 78 :param cssText: 79 a parseable string or a tuple of (cssText, dict-of-namespaces) 80 :Exceptions: 81 - `NAMESPACE_ERR`: (Selector) 82 Raised if a specified selector uses an unknown namespace 83 prefix. 84 - `SYNTAX_ERR`: (self, StyleDeclaration, etc) 85 Raised if the specified CSS string value has a syntax error and 86 is unparsable. 87 - `INVALID_MODIFICATION_ERR`: (self) 88 Raised if the specified CSS string value represents a different 89 type of rule than the current one. 90 - `HIERARCHY_REQUEST_ERR`: (CSSStylesheet) 91 Raised if the rule cannot be inserted at this point in the 92 style sheet. 93 - `NO_MODIFICATION_ALLOWED_ERR`: (CSSRule) 94 Raised if the rule is readonly. 95 """ 96 super(CSSMediaRule, self)._setCssText(cssText) 97 98 # might be (cssText, namespaces) 99 cssText, namespaces = self._splitNamespacesOff(cssText) 100 try: 101 # use parent style sheet ones if available 102 namespaces = self.parentStyleSheet.namespaces 103 except AttributeError: 104 pass 105 106 tokenizer = self._tokenize2(cssText) 107 attoken = self._nexttoken(tokenizer, None) 108 if self._type(attoken) != self._prods.MEDIA_SYM: 109 self._log.error(u'CSSMediaRule: No CSSMediaRule found: %s' % 110 self._valuestr(cssText), 111 error=xml.dom.InvalidModificationErr) 112 else: 113 # media "name"? { cssRules } 114 115 # media 116 wellformed = True 117 mediatokens, end = self._tokensupto2(tokenizer, 118 mediaqueryendonly=True, 119 separateEnd=True) 120 if u'{' == self._tokenvalue(end) or self._prods.STRING == self._type(end): 121 newmedia = cssutils.stylesheets.MediaList() 122 newmedia.mediaText = mediatokens 123 124 # name (optional) 125 name = None 126 nameseq = self._tempSeq() 127 if self._prods.STRING == self._type(end): 128 name = self._stringtokenvalue(end) 129 # TODO: for now comments are lost after name 130 nametokens, end = self._tokensupto2(tokenizer, 131 blockstartonly=True, 132 separateEnd=True) 133 wellformed, expected = self._parse(None, nameseq, nametokens, {}) 134 if not wellformed: 135 self._log.error(u'CSSMediaRule: Syntax Error: %s' % 136 self._valuestr(cssText)) 137 138 139 # check for { 140 if u'{' != self._tokenvalue(end): 141 self._log.error(u'CSSMediaRule: No "{" found: %s' % 142 self._valuestr(cssText)) 143 return 144 145 # cssRules 146 cssrulestokens, braceOrEOF = self._tokensupto2(tokenizer, 147 mediaendonly=True, 148 separateEnd=True) 149 nonetoken = self._nexttoken(tokenizer, None) 150 if (u'}' != self._tokenvalue(braceOrEOF) and 151 'EOF' != self._type(braceOrEOF)): 152 self._log.error(u'CSSMediaRule: No "}" found.', 153 token=braceOrEOF) 154 elif nonetoken: 155 self._log.error(u'CSSMediaRule: Trailing content found.', 156 token=nonetoken) 157 else: 158 # for closures: must be a mutable 159 newcssrules = [] #cssutils.css.CSSRuleList() 160 new = {'wellformed': True } 161 162 def ruleset(expected, seq, token, tokenizer): 163 rule = cssutils.css.CSSStyleRule(parentRule=self) 164 rule.cssText = (self._tokensupto2(tokenizer, token), 165 namespaces) 166 if rule.wellformed: 167 rule._parentStyleSheet=self.parentStyleSheet 168 seq.append(rule) 169 return expected
170 171 def atrule(expected, seq, token, tokenizer): 172 # TODO: get complete rule! 173 tokens = self._tokensupto2(tokenizer, token) 174 atval = self._tokenvalue(token) 175 if atval in ('@charset ', '@font-face', '@import', '@namespace', 176 '@page', '@media'): 177 self._log.error( 178 u'CSSMediaRule: This rule is not allowed in CSSMediaRule - ignored: %s.' 179 % self._valuestr(tokens), 180 token = token, 181 error=xml.dom.HierarchyRequestErr) 182 else: 183 rule = cssutils.css.CSSUnknownRule(parentRule=self, 184 parentStyleSheet=self.parentStyleSheet) 185 rule.cssText = tokens 186 if rule.wellformed: 187 seq.append(rule) 188 return expected
189 190 def COMMENT(expected, seq, token, tokenizer=None): 191 seq.append(cssutils.css.CSSComment([token])) 192 return expected 193 194 tokenizer = (t for t in cssrulestokens) # TODO: not elegant! 195 wellformed, expected = self._parse(braceOrEOF, 196 newcssrules, 197 tokenizer, { 198 'COMMENT': COMMENT, 199 'CHARSET_SYM': atrule, 200 'FONT_FACE_SYM': atrule, 201 'IMPORT_SYM': atrule, 202 'NAMESPACE_SYM': atrule, 203 'PAGE_SYM': atrule, 204 'MEDIA_SYM': atrule, 205 'ATKEYWORD': atrule 206 }, 207 default=ruleset, 208 new=new) 209 210 # no post condition 211 212 if newmedia.wellformed and wellformed: 213 self._media = newmedia 214 self.name = name 215 self._setSeq(nameseq) 216 del self.cssRules[:] 217 for r in newcssrules: 218 self.cssRules.append(r) 219 220 cssText = property(_getCssText, _setCssText, 221 doc="(DOM attribute) The parsable textual representation.") 222
223 - def _setName(self, name):
224 self._name = name
225 226 name = property(lambda self: self._name, _setName, 227 doc=u"An optional name for the media rules") 228 229 media = property(lambda self: self._media, 230 doc=u"(DOM readonly) A list of media types for this rule of type\ 231 MediaList") 232 233 wellformed = property(lambda self: self.media.wellformed) 234
235 - def deleteRule(self, index):
236 """ 237 index 238 within the media block's rule collection of the rule to remove. 239 240 Used to delete a rule from the media block. 241 242 DOMExceptions 243 244 - INDEX_SIZE_ERR: (self) 245 Raised if the specified index does not correspond to a rule in 246 the media rule list. 247 - NO_MODIFICATION_ALLOWED_ERR: (self) 248 Raised if this media rule is readonly. 249 """ 250 self._checkReadonly() 251 252 try: 253 self.cssRules[index]._parentRule = None # detach 254 del self.cssRules[index] # remove from @media 255 except IndexError: 256 raise xml.dom.IndexSizeErr( 257 u'CSSMediaRule: %s is not a valid index in the rulelist of length %i' % ( 258 index, self.cssRules.length))
259
260 - def add(self, rule):
261 """ 262 Adds rule to end of this mediarule. Same as ``.insertRule(rule)``. 263 """ 264 self.insertRule(rule, index=None)
265
266 - def insertRule(self, rule, index=None):
267 """ 268 rule 269 The parsable text representing the rule. For rule sets this 270 contains both the selector and the style declaration. For 271 at-rules, this specifies both the at-identifier and the rule 272 content. 273 274 cssutils also allows rule to be a valid **CSSRule** object 275 276 index 277 within the media block's rule collection of the rule before 278 which to insert the specified rule. If the specified index is 279 equal to the length of the media blocks's rule collection, the 280 rule will be added to the end of the media block. 281 If index is not given or None rule will be appended to rule 282 list. 283 284 Used to insert a new rule into the media block. 285 286 DOMException on setting 287 288 - HIERARCHY_REQUEST_ERR: 289 (no use case yet as no @charset or @import allowed)) 290 Raised if the rule cannot be inserted at the specified index, 291 e.g., if an @import rule is inserted after a standard rule set 292 or other at-rule. 293 - INDEX_SIZE_ERR: (self) 294 Raised if the specified index is not a valid insertion point. 295 - NO_MODIFICATION_ALLOWED_ERR: (self) 296 Raised if this media rule is readonly. 297 - SYNTAX_ERR: (CSSStyleRule) 298 Raised if the specified rule has a syntax error and is 299 unparsable. 300 301 returns the index within the media block's rule collection of the 302 newly inserted rule. 303 304 """ 305 self._checkReadonly() 306 307 # check position 308 if index is None: 309 index = len(self.cssRules) 310 elif index < 0 or index > self.cssRules.length: 311 raise xml.dom.IndexSizeErr( 312 u'CSSMediaRule: Invalid index %s for CSSRuleList with a length of %s.' % ( 313 index, self.cssRules.length)) 314 315 # parse 316 if isinstance(rule, basestring): 317 tempsheet = cssutils.css.CSSStyleSheet() 318 tempsheet.cssText = rule 319 if len(tempsheet.cssRules) != 1 or (tempsheet.cssRules and 320 not isinstance(tempsheet.cssRules[0], cssutils.css.CSSRule)): 321 self._log.error(u'CSSMediaRule: Invalid Rule: %s' % rule) 322 return 323 rule = tempsheet.cssRules[0] 324 elif not isinstance(rule, cssutils.css.CSSRule): 325 self._log.error(u'CSSMediaRule: Not a CSSRule: %s' % rule) 326 return 327 328 # CHECK HIERARCHY 329 # @charset @import @page @namespace @media 330 if isinstance(rule, cssutils.css.CSSCharsetRule) or \ 331 isinstance(rule, cssutils.css.CSSFontFaceRule) or \ 332 isinstance(rule, cssutils.css.CSSImportRule) or \ 333 isinstance(rule, cssutils.css.CSSNamespaceRule) or \ 334 isinstance(rule, cssutils.css.CSSPageRule) or \ 335 isinstance(rule, CSSMediaRule): 336 self._log.error(u'CSSMediaRule: This type of rule is not allowed here: %s' % 337 rule.cssText, 338 error=xml.dom.HierarchyRequestErr) 339 return 340 341 self.cssRules.insert(index, rule) 342 rule._parentRule = self 343 rule._parentStyleSheet = self.parentStyleSheet 344 return index
345
346 - def __repr__(self):
347 return "cssutils.css.%s(mediaText=%r)" % ( 348 self.__class__.__name__, self.media.mediaText)
349
350 - def __str__(self):
351 return "<cssutils.css.%s object mediaText=%r at 0x%x>" % ( 352 self.__class__.__name__, self.media.mediaText, id(self))
353