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: 2007-12-28 13:07:34 +0100 (Fr, 28 Dez 2007) $'
      7  __version__ = '$LastChangedRevision: 753 $'
      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      cssRules: A css::CSSRuleList of all CSS rules contained within the
     22          media block.
     23      media: of type stylesheets::MediaList, (DOM readonly)
     24          A list of media types for this rule of type MediaList.
     25      inherited from CSSRule
     26          cssText
     27
     28      cssutils only
     29      -------------
     30      atkeyword:
     31          the literal keyword used
     32
     33      Format
     34      ======
     35      media
     36        : MEDIA_SYM S* medium [ COMMA S* medium ]* LBRACE S* ruleset* '}' S*;
     37      """
     38      # CONSTANT
     39      type = cssrule.CSSRule.MEDIA_RULE
     40
     41 -    def __init__(self, mediaText='all', readonly=False):
     42          """
     43          constructor
     44          """
     45          super(CSSMediaRule, self).__init__()
     46
     47          self.atkeyword = u'@media'
     48          self._media = cssutils.stylesheets.MediaList(
     49              mediaText, readonly=readonly)
     50          if not self.media.valid:
     51              self._media = cssutils.stylesheets.MediaList()
     52
     53          self.cssRules = cssutils.css.cssrulelist.CSSRuleList()
     54          self.cssRules.append = self.insertRule
     55          self.cssRules.extend = self.insertRule
     56
     57          self._readonly = readonly
     58
     59 -    def _getCssText(self):
     60          """
     61          returns serialized property cssText
     62          """
     63          return cssutils.ser.do_CSSMediaRule(self)
     64
     65 -    def _setCssText(self, cssText):
     66          """
     67          DOMException on setting
     68
     69          - NO_MODIFICATION_ALLOWED_ERR: (self)
     70            Raised if the rule is readonly.
     71          - INVALID_MODIFICATION_ERR: (self)
     72            Raised if the specified CSS string value represents a different
     73            type of rule than the current one.
     74          - HIERARCHY_REQUEST_ERR: (self)
     75            Raised if the rule cannot be inserted at this point in the
     76            style sheet.
     77          - SYNTAX_ERR: (self)
     78            Raised if the specified CSS string value has a syntax error and
     79            is unparsable.
     80          """
     81          super(CSSMediaRule, self)._setCssText(cssText)
     82
     83          tokenizer = self._tokenize2(cssText)
     84          attoken = self._nexttoken(tokenizer, None)
     85          if not attoken or u'@media' != self._tokenvalue(
     86                                                      attoken, normalize=True):
     87              self._log.error(u'CSSMediaRule: No CSSMediaRule found: %s' %
     88                  self._valuestr(cssText),
     89                  error=xml.dom.InvalidModificationErr)
     90          else:
     91              # media
     92              valid = True
     93              mediatokens = self._tokensupto2(tokenizer, blockstartonly=True)
     94              if len(mediatokens) < 1 or\
     95                 u'{' != self._tokenvalue(mediatokens[-1]):
     96                  self._log.error(u'CSSMediaRule: No "{" found.')
     97              else:
     98                  newmedia = cssutils.stylesheets.MediaList()
     99                  newmedia.mediaText = mediatokens[:-1] # omit {
    100
    101              # cssRules
    102              cssrulestokens = self._tokensupto2(tokenizer, mediaendonly=True)
    103              newcssrules = [] #cssutils.css.CSSRuleList()
    104              if len(cssrulestokens) < 1 or (
    105                 u'}' != self._tokenvalue(cssrulestokens[-1]) and
    106                 'EOF' != self._type(cssrulestokens[-1])):
    107                  self._log.error(u'CSSMediaRule: No "}" found.')
    108              elif self._nexttoken(tokenizer, None):
    109                  self._log.error(u'CSSMediaRule: Content after "}" found.')
    110              else:
    111                  brace = cssrulestokens.pop()
    112
    113                  # for closures: must be a mutable
    114                  new = {'valid': True }
    115
    116                  def ruleset(expected, seq, token, tokenizer):
    117                      rule = cssutils.css.CSSStyleRule()
    118                      rule.cssText = self._tokensupto2(tokenizer, token)
    119                      if new['valid']:
    120                          seq.append(rule)
    121                      return expected
    122
    123                  def atrule(expected, seq, token, tokenizer):
    124                      # TODO: get complete rule!
    125                      tokens = self._tokensupto2(tokenizer, token)
    126                      atval = self._tokenvalue(token)
    127                      if atval in ('@charset ', '@font-face', '@import', '@namespace',
    128                                   '@page', '@media'):
    129                          self._log.error(
    130                              u'CSSMediaRule: This rule is not allowed in CSSMediaRule - ignored: %s.'
    131                                  % self._valuestr(tokens),
    132                                  token = token,
    133                                  error=xml.dom.HierarchyRequestErr)
    134                      else:
    135                          rule = cssutils.css.CSSUnknownRule()
    136                          rule.cssText = tokens
    137                          seq.append(rule)
    138                      return expected
    139
    140                  tokenizer = (t for t in cssrulestokens) # TODO: not elegant!
    141                  valid, expected = self._parse('}', newcssrules, tokenizer, {
    142                       'CHARSET_SYM': atrule,
    143                       'FONT_FACE_SYM': atrule,
    144                       'IMPORT_SYM': atrule,
    145                       'NAMESPACE_SYM': atrule,
    146                       'PAGE_SYM': atrule,
    147                       'MEDIA_SYM': atrule,
    148                       'ATKEYWORD': atrule
    149                       },
    150                       default=ruleset)
    151
    152                  # no post condition
    153
    154              if newmedia.valid and valid:
    155                  self._media = newmedia
    156                  del self.cssRules[:]# = newcssrules
    157                  for r in newcssrules:
    158                      self.cssRules.append(r)
    159                  for r in self.cssRules:
    160                      r.parentRule = self # for CSSComment possible only here
    161
    162      cssText = property(_getCssText, _setCssText,
    163          doc="(DOM attribute) The parsable textual representation.")
    164
    165 -    def _getMedia(self):
    166          "returns MediaList"
    167          return self._media
    168
    169      media = property(_getMedia,
    170          doc=u"(DOM readonly) A list of media types for this rule of type\
    171              MediaList")
    172
    173 -    def deleteRule(self, index):
    174          """
    175          index
    176              within the media block's rule collection of the rule to remove.
    177
    178          Used to delete a rule from the media block.
    179
    180          DOMExceptions
    181
    182          - INDEX_SIZE_ERR: (self)
    183            Raised if the specified index does not correspond to a rule in
    184            the media rule list.
    185          - NO_MODIFICATION_ALLOWED_ERR: (self)
    186            Raised if this media rule is readonly.
    187          """
    188          self._checkReadonly()
    189
    190          try:
    191              self.cssRules[index].parentRule = None # detach
    192              del self.cssRules[index] # remove from @media
    193          except IndexError:
    194              raise xml.dom.IndexSizeErr(
    195                  u'CSSMediaRule: %s is not a valid index in the rulelist of length %i' % (
    196                  index, self.cssRules.length))
    197
    198 -    def insertRule(self, rule, index=None):
    199          """
    200          rule
    201              The parsable text representing the rule. For rule sets this
    202              contains both the selector and the style declaration. For
    203              at-rules, this specifies both the at-identifier and the rule
    204              content.
    205
    206              cssutils also allows rule to be a valid **CSSRule** object
    207
    208          index
    209              within the media block's rule collection of the rule before
    210              which to insert the specified rule. If the specified index is
    211              equal to the length of the media blocks's rule collection, the
    212              rule will be added to the end of the media block.
    213              If index is not given or None rule will be appended to rule
    214              list.
    215
    216          Used to insert a new rule into the media block.
    217
    218          DOMException on setting
    219
    220          - HIERARCHY_REQUEST_ERR:
    221            (no use case yet as no @charset or @import allowed))
    222            Raised if the rule cannot be inserted at the specified index,
    223            e.g., if an @import rule is inserted after a standard rule set
    224            or other at-rule.
    225          - INDEX_SIZE_ERR: (self)
    226            Raised if the specified index is not a valid insertion point.
    227          - NO_MODIFICATION_ALLOWED_ERR: (self)
    228            Raised if this media rule is readonly.
    229          - SYNTAX_ERR: (CSSStyleRule)
    230            Raised if the specified rule has a syntax error and is
    231            unparsable.
    232
    233          returns the index within the media block's rule collection of the
    234          newly inserted rule.
    235
    236          """
    237          self._checkReadonly()
    238
    239          # check position
    240          if index is None:
    241              index = len(self.cssRules)
    242          elif index < 0 or index > self.cssRules.length:
    243              raise xml.dom.IndexSizeErr(
    244                  u'CSSMediaRule: Invalid index %s for CSSRuleList with a length of %s.' % (
    245                      index, self.cssRules.length))
    246
    247          # parse
    248          if isinstance(rule, basestring):
    249              tempsheet = CSSStyleSheet()
    250              tempsheet.cssText = rule
    251              if len(tempsheet.cssRules) != 1 or (tempsheet.cssRules and
    252               not isinstance(tempsheet.cssRules[0], cssutils.css.CSSRule)):
    253                  self._log.error(u'CSSMediaRule: Invalid Rule: %s' % rule)
    254                  return
    255              rule = tempsheet.cssRules[0]
    256          elif not isinstance(rule, cssutils.css.CSSRule):
    257              self._log.error(u'CSSMediaRule: Not a CSSRule: %s' % rule)
    258              return
    259
    260          # CHECK HIERARCHY
    261          # @charset @import @page @namespace @media
    262          if isinstance(rule, cssutils.css.CSSCharsetRule) or \
    263             isinstance(rule, cssutils.css.CSSFontFaceRule) or \
    264             isinstance(rule, cssutils.css.CSSImportRule) or \
    265             isinstance(rule, cssutils.css.CSSNamespaceRule) or \
    266             isinstance(rule, cssutils.css.CSSPageRule) or \
    267             isinstance(rule, CSSMediaRule):
    268              self._log.error(u'CSSMediaRule: This type of rule is not allowed here: %s' %
    269                        rule.cssText,
    270                        error=xml.dom.HierarchyRequestErr)
    271              return
    272
    273          self.cssRules.insert(index, rule)
    274          rule.parentRule = self
    275          return index
    276
    277 -    def __repr__(self):
    278          return "cssutils.css.%s(mediaText=%r)" % (
    279                  self.__class__.__name__, self.media.mediaText)
    280
    281 -    def __str__(self):
    282          return "<cssutils.css.%s object mediaText=%r at 0x%x>" % (
    283                  self.__class__.__name__, self.media.mediaText, id(self))
    284