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