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