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