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-11-25 19:09:25 +0100 (So, 25 Nov 2007) $'
      7  __version__ = '$LastChangedRevision: 697 $'
      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 ', '@font-face', '@import', '@namespace',
    125                                   '@page', '@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                       'FONT_FACE_SYM': atrule,
    140                       'IMPORT_SYM': atrule,
    141                       'NAMESPACE_SYM': atrule,
    142                       'PAGE_SYM': atrule,
    143                       'MEDIA_SYM': atrule,
    144                       'ATKEYWORD': atrule
    145                       },
    146                       default=ruleset)
    147
    148                  # no post condition
    149
    150              if newmedia.valid and valid:
    151                  self._media = newmedia
    152                  self._cssRules = newcssrules
    153                  for r in self.cssRules:
    154                      r.parentRule = self # for CSSComment possible only here
    155
    156
    157
    158      cssText = property(_getCssText, _setCssText,
    159          doc="(DOM attribute) The parsable textual representation.")
    160
    161 -    def _getMedia(self):
    162          "returns MediaList"
    163          return self._media
    164
    165      media = property(_getMedia,
    166          doc=u"(DOM readonly) A list of media types for this rule of type\
    167              MediaList")
    168
    169 -    def _getCssRules(self):
    170          return self._cssRules
    171
    172      cssRules = property(_getCssRules,
    173          doc="(DOM readonly) A css::CSSRuleList of all CSS rules contained\
    174              within the media block.")
    175
    176 -    def deleteRule(self, index):
    177          """
    178          index
    179              within the media block's rule collection of the rule to remove.
    180
    181          Used to delete a rule from the media block.
    182
    183          DOMExceptions
    184
    185          - INDEX_SIZE_ERR: (self)
    186            Raised if the specified index does not correspond to a rule in
    187            the media rule list.
    188          - NO_MODIFICATION_ALLOWED_ERR: (self)
    189            Raised if this media rule is readonly.
    190          """
    191          self._checkReadonly()
    192
    193          try:
    194              self._cssRules[index].parentRule = None # detach
    195              del self._cssRules[index] # remove from @media
    196          except IndexError:
    197              raise xml.dom.IndexSizeErr(
    198                  u'CSSMediaRule: %s is not a valid index in the rulelist of length %i' % (
    199                  index, self.cssRules.length))
    200
    201 -    def insertRule(self, rule, index=None):
    202          """
    203          rule
    204              The parsable text representing the rule. For rule sets this
    205              contains both the selector and the style declaration. For
    206              at-rules, this specifies both the at-identifier and the rule
    207              content.
    208
    209              cssutils also allows rule to be a valid **CSSRule** object
    210
    211          index
    212              within the media block's rule collection of the rule before
    213              which to insert the specified rule. If the specified index is
    214              equal to the length of the media blocks's rule collection, the
    215              rule will be added to the end of the media block.
    216              If index is not given or None rule will be appended to rule
    217              list.
    218
    219          Used to insert a new rule into the media block.
    220
    221          DOMException on setting
    222
    223          - HIERARCHY_REQUEST_ERR:
    224            (no use case yet as no @charset or @import allowed))
    225            Raised if the rule cannot be inserted at the specified index,
    226            e.g., if an @import rule is inserted after a standard rule set
    227            or other at-rule.
    228          - INDEX_SIZE_ERR: (self)
    229            Raised if the specified index is not a valid insertion point.
    230          - NO_MODIFICATION_ALLOWED_ERR: (self)
    231            Raised if this media rule is readonly.
    232          - SYNTAX_ERR: (CSSStyleRule)
    233            Raised if the specified rule has a syntax error and is
    234            unparsable.
    235
    236          returns the index within the media block's rule collection of the
    237          newly inserted rule.
    238
    239          """
    240          self._checkReadonly()
    241
    242          # check position
    243          if index is None:
    244              index = len(self.cssRules)
    245          elif index < 0 or index > self.cssRules.length:
    246              raise xml.dom.IndexSizeErr(
    247                  u'CSSMediaRule: Invalid index %s for CSSRuleList with a length of %s.' % (
    248                      index, self.cssRules.length))
    249
    250          # parse
    251          if isinstance(rule, basestring):
    252              tempsheet = CSSStyleSheet()
    253              tempsheet.cssText = rule
    254              if len(tempsheet.cssRules) != 1 or (tempsheet.cssRules and
    255               not isinstance(tempsheet.cssRules[0], cssutils.css.CSSRule)):
    256                  self._log.error(u'CSSMediaRule: Invalid Rule: %s' % rule)
    257                  return
    258              rule = tempsheet.cssRules[0]
    259          elif not isinstance(rule, cssutils.css.CSSRule):
    260              self._log.error(u'CSSMediaRule: Not a CSSRule: %s' % rule)
    261              return
    262
    263          # CHECK HIERARCHY
    264          # @charset @import @page @namespace @media
    265          if isinstance(rule, cssutils.css.CSSCharsetRule) or \
    266             isinstance(rule, cssutils.css.CSSFontFaceRule) or \
    267             isinstance(rule, cssutils.css.CSSImportRule) or \
    268             isinstance(rule, cssutils.css.CSSNamespaceRule) or \
    269             isinstance(rule, cssutils.css.CSSPageRule) or \
    270             isinstance(rule, CSSMediaRule):
    271              self._log.error(u'CSSMediaRule: This type of rule is not allowed here: %s' %
    272                        rule.cssText,
    273                        error=xml.dom.HierarchyRequestErr)
    274              return
    275
    276          self.cssRules.insert(index, rule)
    277          rule.parentRule = self
    278          return index
    279
    280 -    def __repr__(self):
    281          return "cssutils.css.%s(mediaText=%r)" % (
    282                  self.__class__.__name__, self.media.mediaText)
    283
    284 -    def __str__(self):
    285          return "<cssutils.css.%s object mediaText=%r at 0x%x>" % (
    286                  self.__class__.__name__, self.media.mediaText, id(self))
    287