Package cssutils :: Package css :: Module cssimportrule |
[hide private]
[frames] | no frames]

# Source Code for Module cssutils.css.cssimportrule

      1  """CSSImportRule implements DOM Level 2 CSS CSSImportRule.
      2
      3  plus:
      4
      5  ``name`` property
      6      http://www.w3.org/TR/css3-cascade/#cascading
      7
      8  """
      9  __all__ = ['CSSImportRule']
     10  __docformat__ = 'restructuredtext'
     11  __version__ = '$Id: cssimportrule.py 1152 2008-03-18 22:36:39Z cthedot $'
     12
     13  import os
     14  import urlparse
     15  import xml.dom
     16  import cssrule
     17  import cssutils
     18
     19 -class CSSImportRule(cssrule.CSSRule):
     20      """
     21      Represents an @import rule within a CSS style sheet.  The @import rule
     22      is used to import style rules from other style sheets.
     23
     24      Properties
     25      ==========
     26      atkeyword: (cssutils only)
     27          the literal keyword used
     28      cssText: of type DOMString
     29          The parsable textual representation of this rule
     30      href: of type DOMString, (DOM readonly, cssutils also writable)
     31          The location of the style sheet to be imported. The attribute will
     32          not contain the url(...) specifier around the URI.
     33      hreftype: 'uri' (serializer default) or 'string' (cssutils only)
     34          The original type of href, not really relevant as it may be
     35          reconfigured in the serializer but it is kept anyway
     36      media: of type stylesheets::MediaList (DOM readonly)
     37          A list of media types for this rule of type MediaList.
     38      name:
     39          An optional name used for cascading
     40      styleSheet: of type CSSStyleSheet (DOM readonly)
     41          The style sheet referred to by this rule. The value of this
     42          attribute is None if the style sheet has not yet been loaded or if
     43          it will not be loaded (e.g. if the stylesheet is for a media type
     44          not supported by the user agent).
     45
     46      Inherits properties from CSSRule
     47
     48      Format
     49      ======
     50      import
     51        : IMPORT_SYM S*
     52        [STRING|URI] S* [ medium [ COMMA S* medium]* ]? S* STRING? S* ';' S*
     53        ;
     54      """
     55      type = cssrule.CSSRule.IMPORT_RULE
     56
     57 -    def __init__(self, href=None, mediaText=u'all', name=None,
     58                   parentRule=None, parentStyleSheet=None, readonly=False):
     59          """
     60          if readonly allows setting of properties in constructor only
     61
     62          Do not use as positional but as keyword attributes only!
     63
     64          href
     65              location of the style sheet to be imported.
     66          mediaText
     67              A list of media types for which this style sheet may be used
     68              as a string
     69          """
     70          super(CSSImportRule, self).__init__(parentRule=parentRule,
     71                                              parentStyleSheet=parentStyleSheet)
     72          self.atkeyword = u'@import'
     73          self.hreftype = None
     74          self._styleSheet = None
     75
     76          self._href = None
     77          self.href = href
     78
     79          self._media = cssutils.stylesheets.MediaList(
     80              mediaText, readonly=readonly)
     81          self._name = name
     82          if not self.media.wellformed:
     83              self._media = cssutils.stylesheets.MediaList()
     84
     85          seq = self._tempSeq()
     86          seq.append(self.href, 'href')
     87          seq.append(self.media, 'media')
     88          seq.append(self.name, 'name')
     89          self._setSeq(seq)
     90
     91          self._readonly = readonly
     92
     93 -    def _getCssText(self):
     94          """
     95          returns serialized property cssText
     96          """
     97          return cssutils.ser.do_CSSImportRule(self)
     98
     99 -    def _setCssText(self, cssText):
    100          """
    101          DOMException on setting
    102
    103          - HIERARCHY_REQUEST_ERR: (CSSStylesheet)
    104            Raised if the rule cannot be inserted at this point in the
    105            style sheet.
    106          - INVALID_MODIFICATION_ERR: (self)
    107            Raised if the specified CSS string value represents a different
    108            type of rule than the current one.
    109          - NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
    110            Raised if the rule is readonly.
    111          - SYNTAX_ERR: (self)
    112            Raised if the specified CSS string value has a syntax error and
    113            is unparsable.
    114          """
    115          super(CSSImportRule, self)._setCssText(cssText)
    116          tokenizer = self._tokenize2(cssText)
    117          attoken = self._nexttoken(tokenizer, None)
    118          if self._type(attoken) != self._prods.IMPORT_SYM:
    119              self._log.error(u'CSSImportRule: No CSSImportRule found: %s' %
    120                  self._valuestr(cssText),
    121                  error=xml.dom.InvalidModificationErr)
    122          else:
    123              # for closures: must be a mutable
    124              new = {'keyword': self._tokenvalue(attoken),
    125                     'href': None,
    126                     'hreftype': None,
    127                     'media': cssutils.stylesheets.MediaList(),
    128                     'name': None,
    129                     'wellformed': True
    130                     }
    131
    132              def __doname(seq, token):
    133                  # called by _string or _ident
    134                  new['name'] = self._stringtokenvalue(token)
    135                  seq.append(new['name'], 'name')
    136                  return ';'
    137
    138              def _string(expected, seq, token, tokenizer=None):
    139                  if 'href' == expected:
    140                      # href
    141                      new['href'] = self._stringtokenvalue(token)
    142                      new['hreftype'] = 'string'
    143                      seq.append(new['href'], 'href')
    144                      return 'media name ;'
    145                  elif 'name' in expected:
    146                      # name
    147                      return __doname(seq, token)
    148                  else:
    149                      new['wellformed'] = False
    150                      self._log.error(
    151                          u'CSSImportRule: Unexpected string.', token)
    152                      return expected
    153
    154              def _uri(expected, seq, token, tokenizer=None):
    155                  # href
    156                  if 'href' == expected:
    157                      uri = self._uritokenvalue(token)
    158                      new['hreftype'] = 'uri'
    159                      new['href'] = uri
    160                      seq.append(new['href'], 'href')
    161                      return 'media name ;'
    162                  else:
    163                      new['wellformed'] = False
    164                      self._log.error(
    165                          u'CSSImportRule: Unexpected URI.', token)
    166                      return expected
    167
    168              def _ident(expected, seq, token, tokenizer=None):
    169                  # medialist ending with ; which is checked upon too
    170                  if expected.startswith('media'):
    171                      mediatokens = self._tokensupto2(
    172                          tokenizer, importmediaqueryendonly=True)
    173                      mediatokens.insert(0, token) # push found token
    174
    175                      last = mediatokens.pop() # retrieve ;
    176                      lastval, lasttyp = self._tokenvalue(last), self._type(last)
    177                      if lastval != u';' and lasttyp not in ('EOF', self._prods.STRING):
    178                          new['wellformed'] = False
    179                          self._log.error(u'CSSImportRule: No ";" found: %s' %
    180                                          self._valuestr(cssText), token=token)
    181
    182                      media = cssutils.stylesheets.MediaList()
    183                      media.mediaText = mediatokens
    184                      if media.wellformed:
    185                          new['media'] = media
    186                          seq.append(media, 'media')
    187                      else:
    188                          new['wellformed'] = False
    189                          self._log.error(u'CSSImportRule: Invalid MediaList: %s' %
    190                                          self._valuestr(cssText), token=token)
    191
    192                      if lasttyp == self._prods.STRING:
    193                          # name
    194                          return __doname(seq, last)
    195                      else:
    196                          return 'EOF' # ';' is token "last"
    197                  else:
    198                      new['wellformed'] = False
    199                      self._log.error(
    200                          u'CSSImportRule: Unexpected ident.', token)
    201                      return expected
    202
    203              def _char(expected, seq, token, tokenizer=None):
    204                  # final ;
    205                  val = self._tokenvalue(token)
    206                  if expected.endswith(';') and u';' == val:
    207                      return 'EOF'
    208                  else:
    209                      new['wellformed'] = False
    210                      self._log.error(
    211                          u'CSSImportRule: Unexpected char.', token)
    212                      return expected
    213
    214              # import : IMPORT_SYM S* [STRING|URI]
    215              #            S* [ medium [ ',' S* medium]* ]? ';' S*
    216              #         STRING? # see http://www.w3.org/TR/css3-cascade/#cascading
    217              #        ;
    218              newseq = self._tempSeq()
    219              wellformed, expected = self._parse(expected='href',
    220                  seq=newseq, tokenizer=tokenizer,
    221                  productions={'STRING': _string,
    222                               'URI': _uri,
    223                               'IDENT': _ident,
    224                               'CHAR': _char},
    225                  new=new)
    226
    227              # wellformed set by parse
    228              wellformed = wellformed and new['wellformed']
    229
    230              # post conditions
    231              if not new['href']:
    232                  wellformed = False
    233                  self._log.error(u'CSSImportRule: No href found: %s' %
    234                      self._valuestr(cssText))
    235
    236              if expected != 'EOF':
    237                  wellformed = False
    238                  self._log.error(u'CSSImportRule: No ";" found: %s' %
    239                      self._valuestr(cssText))
    240
    241              # set all
    242              if wellformed:
    243                  self.atkeyword = new['keyword']
    244                  self.hreftype = new['hreftype']
    245                  self._media = new['media']
    246                  self.name = new['name']
    247                  self._setSeq(newseq)
    248
    249                  self.href = new['href']
    250
    251                  if self.styleSheet:
    252                      # title is set by href
    253                      #self.styleSheet._href = self.href
    254                      self.styleSheet._parentStyleSheet = self.parentStyleSheet
    255
    256      cssText = property(fget=_getCssText, fset=_setCssText,
    257          doc="(DOM attribute) The parsable textual representation.")
    258
    259 -    def _setHref(self, href):
    260          # update seq
    261          for i, item in enumerate(self.seq):
    262              val, typ = item.value, item.type
    263              if 'href' == typ:
    264                  self._seq[i] = (href, typ, item.line, item.col)
    265                  break
    266          else:
    267              seq = self._tempSeq()
    268              seq.append(self.href, 'href')
    269              self._setSeq(seq)
    270          # set new href
    271          self._href = href
    272
    273          if not self.styleSheet:
    274              # set only if not set before
    275              self.__setStyleSheet()
    276
    277      href = property(lambda self: self._href, _setHref,
    278                      doc="Location of the style sheet to be imported.")
    279
    280      media = property(lambda self: self._media,
    281                       doc=u"(DOM readonly) A list of media types for this rule"
    282                       " of type MediaList")
    283
    284 -    def _setName(self, name):
    285          # update seq
    286          for i, item in enumerate(self.seq):
    287              val, typ = item.value, item.type
    288              if 'name' == typ:
    289                  self._seq[i] = (name, typ, item.line, item.col)
    290                  break
    291          else:
    292              # append
    293              seq = self._tempSeq()
    294              for item in self.seq:
    295                  # copy current seq
    296                  seq.append(item.value, item.type, item.line, item.col)
    297              seq.append(self.href, 'href')
    298              self._setSeq(seq)
    299          self._name = name
    300          # set title of referred sheet
    301          if self.styleSheet:
    302              self.styleSheet.title = name
    303
    304      name = property(lambda self: self._name, _setName,
    305                      doc=u"An optional name for the imported sheet")
    306
    307 -    def __setStyleSheet(self):
    308          """Read new CSSStyleSheet cssText from href using parentStyleSheet.base
    309
    310          indirectly called if setting ``href``
    311          """
    312          # should simply fail so all errors are catched!
    313          if self.parentStyleSheet and self.href:
    314              href = urlparse.urljoin(self.parentStyleSheet.href, self.href)
    315
    316              try:
    317                  # all possible exceptions are ignored and styleSheet is None
    318                  sheet = cssutils.css.CSSStyleSheet(href=href,
    319                                                     media=self.media,
    320                                                     ownerRule=self,
    321                                                     title=self.name)
    322                  cssText = cssutils.util._readURL(href)
    323                  if not cssText:
    324                      raise IOError()
    325                  sheet.cssText = cssText
    326              except Exception, e:
    327                  self._log.warn(u'CSSImportRule: Error processing imported style sheet: href=%r: %r'
    328                                 % (self.href, e), neverraise=True)
    329              else:
    330                  self._styleSheet = sheet
    331
    332      styleSheet = property(lambda self: self._styleSheet,
    333                            doc="(readonly) The style sheet referred to by this rule.")
    334
    335      wellformed = property(lambda self: bool(self.href and self.media.wellformed))
    336
    337 -    def __repr__(self):
    338          return "cssutils.css.%s(href=%r, mediaText=%r, name=%r)" % (
    339                  self.__class__.__name__,
    340                  self.href, self.media.mediaText, self.name)
    341
    342 -    def __str__(self):
    343          return "<cssutils.css.%s object href=%r at 0x%x>" % (
    344                  self.__class__.__name__, self.href, id(self))
    345