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