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 1262 2008-05-28 11:29:18Z 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 = property(lambda self: 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          """raises xml.dom.SyntaxErr if name is not a string"""
    286          if isinstance(name, basestring) or name is None:
    287              # "" or ''
    288              if not name:
    289                  name = None
    290              # update seq
    291              for i, item in enumerate(self.seq):
    292                  val, typ = item.value, item.type
    293                  if 'name' == typ:
    294                      self._seq[i] = (name, typ, item.line, item.col)
    295                      break
    296              else:
    297                  # append
    298                  seq = self._tempSeq()
    299                  for item in self.seq:
    300                      # copy current seq
    301                      seq.append(item.value, item.type, item.line, item.col)
    302                  seq.append(name, 'name')
    303                  self._setSeq(seq)
    304              self._name = name
    305              # set title of referred sheet
    306              if self.styleSheet:
    307                  self.styleSheet.title = name
    308          else:
    309              self._log.error(u'CSSImportRule: Not a valid name: %s' % name)
    310
    311      name = property(lambda self: self._name, _setName,
    312                      doc=u"An optional name for the imported sheet")
    313
    314 -    def __setStyleSheet(self):
    315          """Read new CSSStyleSheet cssText from href using parentStyleSheet.href
    316
    317          indirectly called if setting ``href``
    318          """
    319          # should simply fail so all errors are catched!
    320          if self.parentStyleSheet and self.href:
    321              # relative href
    322              href = urlparse.urljoin(self.parentStyleSheet.href, self.href)
    323              # all possible exceptions are ignored and styleSheet is None
    324              try:
    325                  overrideEncoding, cssText = self.parentStyleSheet._resolveImport(href)
    326                  if cssText is None:
    327                      raise IOError()
    328
    329                  refsheet = cssutils.css.CSSStyleSheet(href=href,
    330                                                        media=self.media,
    331                                                        ownerRule=self,
    332                                                        title=self.name)
    333                  # inherit fetcher for @imports in refsheet
    334                  refsheet._setFetcher(self.parentStyleSheet._fetcher)
    335                  # overrideEncoding with parentStyleSheet.overrideEncoding,
    336                  # HTTP or parent
    337                  refsheet._setCssTextWithEncodingOverride(cssText,
    338                                                           overrideEncoding)
    339
    340              except (IOError, ValueError), e:
    341                  self._log.warn(u'CSSImportRule: Error processing imported style sheet href=%r: %r'
    342                                 % (self.href, e), neverraise=True)
    343              else:
    344                  self._styleSheet = refsheet
    345
    346      styleSheet = property(lambda self: self._styleSheet,
    347                            doc="(readonly) The style sheet referred to by this rule.")
    348
    349      wellformed = property(lambda self: bool(self.href and self.media.wellformed))
    350
    351 -    def __repr__(self):
    352          if self.media:
    353              mediaText = self.media.mediaText
    354          else:
    355              mediaText = None
    356          return "cssutils.css.%s(href=%r, mediaText=%r, name=%r)" % (
    357                  self.__class__.__name__,
    358                  self.href, self.media.mediaText, self.name)
    359
    360 -    def __str__(self):
    361          if self.media:
    362              mediaText = self.media.mediaText
    363          else:
    364              mediaText = None
    365          return "<cssutils.css.%s object href=%r mediaText=%r name=%r at 0x%x>" % (
    366                  self.__class__.__name__, self.href, mediaText, self.name, id(self))
    367