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 1170 2008-03-20 17:42:07Z 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 = property(lambda self: 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 if isinstance(name, basestring) or name is None: 225 # "" or '' 226 if not name: 227 name = None 228 229 self._name = name 230 else: 231 self._log.error(u'CSSImportRule: Not a valid name: %s' % name)
232 233 234 name = property(lambda self: self._name, _setName, 235 doc=u"An optional name for the media rules") 236 237 media = property(lambda self: self._media, 238 doc=u"(DOM readonly) A list of media types for this rule of type\ 239 MediaList") 240 241 wellformed = property(lambda self: self.media.wellformed) 242
243 - def deleteRule(self, index):
244 """ 245 index 246 within the media block's rule collection of the rule to remove. 247 248 Used to delete a rule from the media block. 249 250 DOMExceptions 251 252 - INDEX_SIZE_ERR: (self) 253 Raised if the specified index does not correspond to a rule in 254 the media rule list. 255 - NO_MODIFICATION_ALLOWED_ERR: (self) 256 Raised if this media rule is readonly. 257 """ 258 self._checkReadonly() 259 260 try: 261 self.cssRules[index]._parentRule = None # detach 262 del self.cssRules[index] # remove from @media 263 except IndexError: 264 raise xml.dom.IndexSizeErr( 265 u'CSSMediaRule: %s is not a valid index in the rulelist of length %i' % ( 266 index, self.cssRules.length))
267
268 - def add(self, rule):
269 """ 270 Adds rule to end of this mediarule. Same as ``.insertRule(rule)``. 271 """ 272 self.insertRule(rule, index=None)
273
274 - def insertRule(self, rule, index=None):
275 """ 276 rule 277 The parsable text representing the rule. For rule sets this 278 contains both the selector and the style declaration. For 279 at-rules, this specifies both the at-identifier and the rule 280 content. 281 282 cssutils also allows rule to be a valid **CSSRule** object 283 284 index 285 within the media block's rule collection of the rule before 286 which to insert the specified rule. If the specified index is 287 equal to the length of the media blocks's rule collection, the 288 rule will be added to the end of the media block. 289 If index is not given or None rule will be appended to rule 290 list. 291 292 Used to insert a new rule into the media block. 293 294 DOMException on setting 295 296 - HIERARCHY_REQUEST_ERR: 297 (no use case yet as no @charset or @import allowed)) 298 Raised if the rule cannot be inserted at the specified index, 299 e.g., if an @import rule is inserted after a standard rule set 300 or other at-rule. 301 - INDEX_SIZE_ERR: (self) 302 Raised if the specified index is not a valid insertion point. 303 - NO_MODIFICATION_ALLOWED_ERR: (self) 304 Raised if this media rule is readonly. 305 - SYNTAX_ERR: (CSSStyleRule) 306 Raised if the specified rule has a syntax error and is 307 unparsable. 308 309 returns the index within the media block's rule collection of the 310 newly inserted rule. 311 312 """ 313 self._checkReadonly() 314 315 # check position 316 if index is None: 317 index = len(self.cssRules) 318 elif index < 0 or index > self.cssRules.length: 319 raise xml.dom.IndexSizeErr( 320 u'CSSMediaRule: Invalid index %s for CSSRuleList with a length of %s.' % ( 321 index, self.cssRules.length)) 322 323 # parse 324 if isinstance(rule, basestring): 325 tempsheet = cssutils.css.CSSStyleSheet() 326 tempsheet.cssText = rule 327 if len(tempsheet.cssRules) != 1 or (tempsheet.cssRules and 328 not isinstance(tempsheet.cssRules[0], cssutils.css.CSSRule)): 329 self._log.error(u'CSSMediaRule: Invalid Rule: %s' % rule) 330 return 331 rule = tempsheet.cssRules[0] 332 elif not isinstance(rule, cssutils.css.CSSRule): 333 self._log.error(u'CSSMediaRule: Not a CSSRule: %s' % rule) 334 return 335 336 # CHECK HIERARCHY 337 # @charset @import @page @namespace @media 338 if isinstance(rule, cssutils.css.CSSCharsetRule) or \ 339 isinstance(rule, cssutils.css.CSSFontFaceRule) or \ 340 isinstance(rule, cssutils.css.CSSImportRule) or \ 341 isinstance(rule, cssutils.css.CSSNamespaceRule) or \ 342 isinstance(rule, cssutils.css.CSSPageRule) or \ 343 isinstance(rule, CSSMediaRule): 344 self._log.error(u'CSSMediaRule: This type of rule is not allowed here: %s' % 345 rule.cssText, 346 error=xml.dom.HierarchyRequestErr) 347 return 348 349 self.cssRules.insert(index, rule) 350 rule._parentRule = self 351 rule._parentStyleSheet = self.parentStyleSheet 352 return index
353
354 - def __repr__(self):
355 return "cssutils.css.%s(mediaText=%r)" % ( 356 self.__class__.__name__, self.media.mediaText)
357
358 - def __str__(self):
359 return "<cssutils.css.%s object mediaText=%r at 0x%x>" % ( 360 self.__class__.__name__, self.media.mediaText, id(self))
361