mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-30 21:41:57 -04:00
Update cssutils to 0.9.6a1. Fixes #1869 (TypeError: 'NoneType' object is not iterable / [ERROR] CSSColor: No match in choice: ('HASH', u'#FFBCCB67B', 20, 19))
This commit is contained in:
parent
ee950ce4c7
commit
1d5aaaf830
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
"""cssutils - CSS Cascading Style Sheets library for Python
|
"""cssutils - CSS Cascading Style Sheets library for Python
|
||||||
|
|
||||||
Copyright (C) 2004-2008 Christof Hoeke
|
Copyright (C) 2004-2009 Christof Hoeke
|
||||||
|
|
||||||
cssutils is free software: you can redistribute it and/or modify
|
cssutils is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
@ -63,18 +63,18 @@ Usage may be::
|
|||||||
>>> sheet = parser.parseString(u'a { color: red}')
|
>>> sheet = parser.parseString(u'a { color: red}')
|
||||||
>>> print sheet.cssText
|
>>> print sheet.cssText
|
||||||
a {
|
a {
|
||||||
color: red
|
color: red
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
__all__ = ['css', 'stylesheets', 'CSSParser', 'CSSSerializer']
|
__all__ = ['css', 'stylesheets', 'CSSParser', 'CSSSerializer']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__author__ = 'Christof Hoeke with contributions by Walter Doerwald'
|
__author__ = 'Christof Hoeke with contributions by Walter Doerwald'
|
||||||
__date__ = '$LastChangedDate:: 2008-08-11 11:11:23 -0700 #$:'
|
__date__ = '$LastChangedDate:: 2009-02-16 12:05:02 -0800 #$:'
|
||||||
|
|
||||||
VERSION = '0.9.5.1'
|
VERSION = '0.9.6a1'
|
||||||
|
|
||||||
__version__ = '%s $Id: __init__.py 1426 2008-08-11 18:11:23Z cthedot $' % VERSION
|
__version__ = '%s $Id: __init__.py 1669 2009-02-16 20:05:02Z cthedot $' % VERSION
|
||||||
|
|
||||||
import codec
|
import codec
|
||||||
import xml.dom
|
import xml.dom
|
||||||
@ -84,9 +84,9 @@ from helper import Deprecated
|
|||||||
import errorhandler
|
import errorhandler
|
||||||
log = errorhandler.ErrorHandler()
|
log = errorhandler.ErrorHandler()
|
||||||
|
|
||||||
import util
|
|
||||||
import css
|
import css
|
||||||
import stylesheets
|
import stylesheets
|
||||||
|
import util
|
||||||
from parse import CSSParser
|
from parse import CSSParser
|
||||||
|
|
||||||
from serialize import CSSSerializer
|
from serialize import CSSSerializer
|
||||||
@ -96,8 +96,7 @@ ser = CSSSerializer()
|
|||||||
_ANYNS = -1
|
_ANYNS = -1
|
||||||
|
|
||||||
class DOMImplementationCSS(object):
|
class DOMImplementationCSS(object):
|
||||||
"""
|
"""This interface allows the DOM user to create a CSSStyleSheet
|
||||||
This interface allows the DOM user to create a CSSStyleSheet
|
|
||||||
outside the context of a document. There is no way to associate
|
outside the context of a document. There is no way to associate
|
||||||
the new CSSStyleSheet with a document in DOM Level 2.
|
the new CSSStyleSheet with a document in DOM Level 2.
|
||||||
|
|
||||||
@ -166,21 +165,21 @@ parse.__doc__ = CSSParser.parse.__doc__
|
|||||||
|
|
||||||
# set "ser", default serializer
|
# set "ser", default serializer
|
||||||
def setSerializer(serializer):
|
def setSerializer(serializer):
|
||||||
"""
|
"""Set the global serializer used by all class in cssutils."""
|
||||||
sets the global serializer used by all class in cssutils
|
|
||||||
"""
|
|
||||||
global ser
|
global ser
|
||||||
ser = serializer
|
ser = serializer
|
||||||
|
|
||||||
|
|
||||||
def getUrls(sheet):
|
def getUrls(sheet):
|
||||||
"""
|
"""Retrieve all ``url(urlstring)`` values (in e.g.
|
||||||
Utility function to get all ``url(urlstring)`` values in
|
:class:`cssutils.css.CSSImportRule` or :class:`cssutils.css.CSSValue`
|
||||||
``CSSImportRules`` and ``CSSStyleDeclaration`` objects (properties)
|
objects of given `sheet`.
|
||||||
of given CSSStyleSheet ``sheet``.
|
|
||||||
|
|
||||||
This function is a generator. The url values exclude ``url(`` and ``)``
|
:param sheet:
|
||||||
and surrounding single or double quotes.
|
:class:`cssutils.css.CSSStyleSheet` object whose URLs are yielded
|
||||||
|
|
||||||
|
This function is a generator. The generated URL values exclude ``url(`` and
|
||||||
|
``)`` and surrounding single or double quotes.
|
||||||
"""
|
"""
|
||||||
for importrule in (r for r in sheet if r.type == r.IMPORT_RULE):
|
for importrule in (r for r in sheet if r.type == r.IMPORT_RULE):
|
||||||
yield importrule.href
|
yield importrule.href
|
||||||
@ -213,14 +212,15 @@ def getUrls(sheet):
|
|||||||
yield u
|
yield u
|
||||||
|
|
||||||
def replaceUrls(sheet, replacer):
|
def replaceUrls(sheet, replacer):
|
||||||
"""
|
"""Replace all URLs in :class:`cssutils.css.CSSImportRule` or
|
||||||
Utility function to replace all ``url(urlstring)`` values in
|
:class:`cssutils.css.CSSValue` objects of given `sheet`.
|
||||||
``CSSImportRules`` and ``CSSStyleDeclaration`` objects (properties)
|
|
||||||
of given CSSStyleSheet ``sheet``.
|
|
||||||
|
|
||||||
``replacer`` must be a function which is called with a single
|
:param sheet:
|
||||||
argument ``urlstring`` which is the current value of url()
|
:class:`cssutils.css.CSSStyleSheet` which is changed
|
||||||
excluding ``url(`` and ``)`` and surrounding single or double quotes.
|
:param replacer:
|
||||||
|
a function which is called with a single argument `urlstring` which is
|
||||||
|
the current value of each url() excluding ``url(`` and ``)`` and
|
||||||
|
surrounding single or double quotes.
|
||||||
"""
|
"""
|
||||||
for importrule in (r for r in sheet if r.type == r.IMPORT_RULE):
|
for importrule in (r for r in sheet if r.type == r.IMPORT_RULE):
|
||||||
importrule.href = replacer(importrule.href)
|
importrule.href = replacer(importrule.href)
|
||||||
@ -249,6 +249,37 @@ def replaceUrls(sheet, replacer):
|
|||||||
elif v.CSS_PRIMITIVE_VALUE == v.cssValueType:
|
elif v.CSS_PRIMITIVE_VALUE == v.cssValueType:
|
||||||
setProperty(v)
|
setProperty(v)
|
||||||
|
|
||||||
|
def resolveImports(sheet, target=None):
|
||||||
|
"""Recurcively combine all rules in given `sheet` into a `target` sheet.
|
||||||
|
|
||||||
|
:param sheet:
|
||||||
|
in this given :class:`cssutils.css.CSSStyleSheet` all import rules are
|
||||||
|
resolved and added to a resulting *flat* sheet.
|
||||||
|
:param target:
|
||||||
|
A :class:`cssutils.css.CSSStyleSheet` object which will be the resulting
|
||||||
|
*flat* sheet if given
|
||||||
|
:returns: given `target` or a new :class:`cssutils.css.CSSStyleSheet` object
|
||||||
|
"""
|
||||||
|
if not target:
|
||||||
|
target = css.CSSStyleSheet()
|
||||||
|
|
||||||
|
#target.add(css.CSSComment(cssText=u'/* START %s */' % sheet.href))
|
||||||
|
for rule in sheet.cssRules:
|
||||||
|
if rule.type == rule.CHARSET_RULE:
|
||||||
|
pass
|
||||||
|
elif rule.type == rule.IMPORT_RULE:
|
||||||
|
log.info(u'Processing @import %r' % rule.href, neverraise=True)
|
||||||
|
if rule.styleSheet:
|
||||||
|
target.add(css.CSSComment(cssText=u'/* START @import "%s" */' % rule.href))
|
||||||
|
resolveImports(rule.styleSheet, target)
|
||||||
|
target.add(css.CSSComment(cssText=u'/* END "%s" */' % rule.href))
|
||||||
|
else:
|
||||||
|
log.error(u'Cannot get referenced stylesheet %r' %
|
||||||
|
rule.href, neverraise=True)
|
||||||
|
target.add(rule)
|
||||||
|
else:
|
||||||
|
target.add(rule)
|
||||||
|
return target
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
print __doc__
|
print __doc__
|
||||||
|
40
src/cssutils/_fetch.py
Normal file
40
src/cssutils/_fetch.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
"""Default URL reading functions"""
|
||||||
|
__all__ = ['_defaultFetcher', '_readUrl']
|
||||||
|
__docformat__ = 'restructuredtext'
|
||||||
|
__version__ = '$Id: tokenize2.py 1547 2008-12-10 20:42:26Z cthedot $'
|
||||||
|
|
||||||
|
import encutils
|
||||||
|
import errorhandler
|
||||||
|
import urllib2
|
||||||
|
import util
|
||||||
|
|
||||||
|
log = errorhandler.ErrorHandler()
|
||||||
|
|
||||||
|
def _defaultFetcher(url):
|
||||||
|
"""Retrieve data from ``url``. cssutils default implementation of fetch
|
||||||
|
URL function.
|
||||||
|
|
||||||
|
Returns ``(encoding, string)`` or ``None``
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
res = urllib2.urlopen(url)
|
||||||
|
except OSError, e:
|
||||||
|
# e.g if file URL and not found
|
||||||
|
log.warn(e, error=OSError)
|
||||||
|
except (OSError, ValueError), e:
|
||||||
|
# invalid url, e.g. "1"
|
||||||
|
log.warn(u'ValueError, %s' % e.args[0], error=ValueError)
|
||||||
|
except urllib2.HTTPError, e:
|
||||||
|
# http error, e.g. 404, e can be raised
|
||||||
|
log.warn(u'HTTPError opening url=%r: %s %s' %
|
||||||
|
(url, e.code, e.msg), error=e)
|
||||||
|
except urllib2.URLError, e:
|
||||||
|
# URLError like mailto: or other IO errors, e can be raised
|
||||||
|
log.warn(u'URLError, %s' % e.reason, error=e)
|
||||||
|
else:
|
||||||
|
if res:
|
||||||
|
mimeType, encoding = encutils.getHTTPInfo(res)
|
||||||
|
if mimeType != u'text/css':
|
||||||
|
log.error(u'Expected "text/css" mime type for url=%r but found: %r' %
|
||||||
|
(url, mimeType), error=ValueError)
|
||||||
|
return encoding, res.read()
|
68
src/cssutils/_fetchgae.py
Normal file
68
src/cssutils/_fetchgae.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
"""GAE specific URL reading functions"""
|
||||||
|
__all__ = ['_defaultFetcher', '_readUrl']
|
||||||
|
__docformat__ = 'restructuredtext'
|
||||||
|
__version__ = '$Id: tokenize2.py 1547 2008-12-10 20:42:26Z cthedot $'
|
||||||
|
|
||||||
|
# raises ImportError of not on GAE
|
||||||
|
from google.appengine.api import urlfetch
|
||||||
|
import cgi
|
||||||
|
import errorhandler
|
||||||
|
import util
|
||||||
|
|
||||||
|
log = errorhandler.ErrorHandler()
|
||||||
|
|
||||||
|
def _defaultFetcher(url):
|
||||||
|
"""
|
||||||
|
uses GoogleAppEngine (GAE)
|
||||||
|
fetch(url, payload=None, method=GET, headers={}, allow_truncated=False)
|
||||||
|
|
||||||
|
Response
|
||||||
|
content
|
||||||
|
The body content of the response.
|
||||||
|
content_was_truncated
|
||||||
|
True if the allow_truncated parameter to fetch() was True and
|
||||||
|
the response exceeded the maximum response size. In this case,
|
||||||
|
the content attribute contains the truncated response.
|
||||||
|
status_code
|
||||||
|
The HTTP status code.
|
||||||
|
headers
|
||||||
|
The HTTP response headers, as a mapping of names to values.
|
||||||
|
|
||||||
|
Exceptions
|
||||||
|
exception InvalidURLError()
|
||||||
|
The URL of the request was not a valid URL, or it used an
|
||||||
|
unsupported method. Only http and https URLs are supported.
|
||||||
|
exception DownloadError()
|
||||||
|
There was an error retrieving the data.
|
||||||
|
|
||||||
|
This exception is not raised if the server returns an HTTP
|
||||||
|
error code: In that case, the response data comes back intact,
|
||||||
|
including the error code.
|
||||||
|
|
||||||
|
exception ResponseTooLargeError()
|
||||||
|
The response data exceeded the maximum allowed size, and the
|
||||||
|
allow_truncated parameter passed to fetch() was False.
|
||||||
|
"""
|
||||||
|
#from google.appengine.api import urlfetch
|
||||||
|
try:
|
||||||
|
r = urlfetch.fetch(url, method=urlfetch.GET)
|
||||||
|
except urlfetch.Error, e:
|
||||||
|
log.warn(u'Error opening url=%r: %s' % (url, e),
|
||||||
|
error=IOError)
|
||||||
|
else:
|
||||||
|
if r.status_code == 200:
|
||||||
|
# find mimetype and encoding
|
||||||
|
mimetype = 'application/octet-stream'
|
||||||
|
try:
|
||||||
|
mimetype, params = cgi.parse_header(r.headers['content-type'])
|
||||||
|
encoding = params['charset']
|
||||||
|
except KeyError:
|
||||||
|
encoding = None
|
||||||
|
if mimetype != u'text/css':
|
||||||
|
log.error(u'Expected "text/css" mime type for url %r but found: %r' %
|
||||||
|
(url, mimetype), error=ValueError)
|
||||||
|
return encoding, r.content
|
||||||
|
else:
|
||||||
|
# TODO: 301 etc
|
||||||
|
log.warn(u'Error opening url=%r: HTTP status %s' %
|
||||||
|
(url, r.status_code), error=IOError)
|
@ -4,7 +4,8 @@ __docformat__ = 'restructuredtext'
|
|||||||
__author__ = 'Walter Doerwald'
|
__author__ = 'Walter Doerwald'
|
||||||
__version__ = '$Id: util.py 1114 2008-03-05 13:22:59Z cthedot $'
|
__version__ = '$Id: util.py 1114 2008-03-05 13:22:59Z cthedot $'
|
||||||
|
|
||||||
import codecs, marshal
|
import codecs
|
||||||
|
import marshal
|
||||||
|
|
||||||
# We're using bits to store all possible candidate encodings (or variants, i.e.
|
# We're using bits to store all possible candidate encodings (or variants, i.e.
|
||||||
# we have two bits for the variants of UTF-16 and two for the
|
# we have two bits for the variants of UTF-16 and two for the
|
||||||
@ -26,17 +27,17 @@ import codecs, marshal
|
|||||||
def detectencoding_str(input, final=False):
|
def detectencoding_str(input, final=False):
|
||||||
"""
|
"""
|
||||||
Detect the encoding of the byte string ``input``, which contains the
|
Detect the encoding of the byte string ``input``, which contains the
|
||||||
beginning of a CSS file. This function returs the detected encoding (or
|
beginning of a CSS file. This function returns the detected encoding (or
|
||||||
``None`` if it hasn't got enough data), and a flag that indicates whether
|
``None`` if it hasn't got enough data), and a flag that indicates whether
|
||||||
to encoding has been detected explicitely or implicitely. To detect the
|
that encoding has been detected explicitely or implicitely. To detect the
|
||||||
encoding the first few bytes are used (or if ``input`` is ASCII compatible
|
encoding the first few bytes are used (or if ``input`` is ASCII compatible
|
||||||
and starts with a charset rule the encoding name from the rule). "Explicit"
|
and starts with a charset rule the encoding name from the rule). "Explicit"
|
||||||
detection means that the bytes start with a BOM or a charset rule.
|
detection means that the bytes start with a BOM or a charset rule.
|
||||||
|
|
||||||
If the encoding can't be detected yet, ``None`` is returned as the encoding.
|
If the encoding can't be detected yet, ``None`` is returned as the encoding.
|
||||||
``final`` specifies whether more data is available in later calls or not.
|
``final`` specifies whether more data will be available in later calls or
|
||||||
If ``final`` is true, ``detectencoding_str()`` will never return ``None``
|
not. If ``final`` is true, ``detectencoding_str()`` will never return
|
||||||
as the encoding.
|
``None`` as the encoding.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# A bit for every candidate
|
# A bit for every candidate
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
"""
|
"""Implements Document Object Model Level 2 CSS
|
||||||
Document Object Model Level 2 CSS
|
|
||||||
http://www.w3.org/TR/2000/PR-DOM-Level-2-Style-20000927/css.html
|
http://www.w3.org/TR/2000/PR-DOM-Level-2-Style-20000927/css.html
|
||||||
|
|
||||||
currently implemented
|
currently implemented
|
||||||
@ -43,7 +42,7 @@ __all__ = [
|
|||||||
'CSSValue', 'CSSPrimitiveValue', 'CSSValueList'
|
'CSSValue', 'CSSPrimitiveValue', 'CSSValueList'
|
||||||
]
|
]
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: __init__.py 1116 2008-03-05 13:52:23Z cthedot $'
|
__version__ = '$Id: __init__.py 1610 2009-01-03 21:07:57Z cthedot $'
|
||||||
|
|
||||||
from cssstylesheet import *
|
from cssstylesheet import *
|
||||||
from cssrulelist import *
|
from cssrulelist import *
|
||||||
@ -60,4 +59,5 @@ from cssunknownrule import *
|
|||||||
from selector import *
|
from selector import *
|
||||||
from selectorlist import *
|
from selectorlist import *
|
||||||
from cssstyledeclaration import *
|
from cssstyledeclaration import *
|
||||||
|
from property import *
|
||||||
from cssvalue import *
|
from cssvalue import *
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
"""CSSCharsetRule implements DOM Level 2 CSS CSSCharsetRule.
|
"""CSSCharsetRule implements DOM Level 2 CSS CSSCharsetRule."""
|
||||||
|
|
||||||
TODO:
|
|
||||||
- check encoding syntax and not codecs.lookup?
|
|
||||||
"""
|
|
||||||
__all__ = ['CSSCharsetRule']
|
__all__ = ['CSSCharsetRule']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: csscharsetrule.py 1170 2008-03-20 17:42:07Z cthedot $'
|
__version__ = '$Id: csscharsetrule.py 1605 2009-01-03 18:27:32Z cthedot $'
|
||||||
|
|
||||||
import codecs
|
import codecs
|
||||||
import xml.dom
|
|
||||||
import cssrule
|
import cssrule
|
||||||
import cssutils
|
import cssutils
|
||||||
|
import xml.dom
|
||||||
|
|
||||||
class CSSCharsetRule(cssrule.CSSRule):
|
class CSSCharsetRule(cssrule.CSSRule):
|
||||||
"""
|
"""
|
||||||
@ -29,34 +25,25 @@ class CSSCharsetRule(cssrule.CSSRule):
|
|||||||
(see CSS document representation) but this is not reflected in the
|
(see CSS document representation) but this is not reflected in the
|
||||||
CSSCharsetRule.
|
CSSCharsetRule.
|
||||||
|
|
||||||
Properties
|
This rule is not really needed anymore as setting
|
||||||
==========
|
:attr:`CSSStyleSheet.encoding` is much easier.
|
||||||
cssText: of type DOMString
|
|
||||||
The parsable textual representation of this rule
|
|
||||||
encoding: of type DOMString
|
|
||||||
The encoding information used in this @charset rule.
|
|
||||||
|
|
||||||
Inherits properties from CSSRule
|
Format::
|
||||||
|
|
||||||
Format
|
charsetrule:
|
||||||
======
|
CHARSET_SYM S* STRING S* ';'
|
||||||
charsetrule:
|
|
||||||
CHARSET_SYM S* STRING S* ';'
|
BUT: Only valid format is (single space, double quotes!)::
|
||||||
|
|
||||||
BUT: Only valid format is:
|
|
||||||
@charset "ENCODING";
|
@charset "ENCODING";
|
||||||
"""
|
"""
|
||||||
type = property(lambda self: cssrule.CSSRule.CHARSET_RULE)
|
|
||||||
|
|
||||||
def __init__(self, encoding=None, parentRule=None,
|
def __init__(self, encoding=None, parentRule=None,
|
||||||
parentStyleSheet=None, readonly=False):
|
parentStyleSheet=None, readonly=False):
|
||||||
"""
|
"""
|
||||||
encoding:
|
:param encoding:
|
||||||
a valid character encoding
|
a valid character encoding
|
||||||
readonly:
|
:param readonly:
|
||||||
defaults to False, not used yet
|
defaults to False, not used yet
|
||||||
|
|
||||||
if readonly allows setting of properties in constructor only
|
|
||||||
"""
|
"""
|
||||||
super(CSSCharsetRule, self).__init__(parentRule=parentRule,
|
super(CSSCharsetRule, self).__init__(parentRule=parentRule,
|
||||||
parentStyleSheet=parentStyleSheet)
|
parentStyleSheet=parentStyleSheet)
|
||||||
@ -67,25 +54,34 @@ class CSSCharsetRule(cssrule.CSSRule):
|
|||||||
|
|
||||||
self._readonly = readonly
|
self._readonly = readonly
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "cssutils.css.%s(encoding=%r)" % (
|
||||||
|
self.__class__.__name__, self.encoding)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "<cssutils.css.%s object encoding=%r at 0x%x>" % (
|
||||||
|
self.__class__.__name__, self.encoding, id(self))
|
||||||
|
|
||||||
def _getCssText(self):
|
def _getCssText(self):
|
||||||
"""returns serialized property cssText"""
|
"""The parsable textual representation."""
|
||||||
return cssutils.ser.do_CSSCharsetRule(self)
|
return cssutils.ser.do_CSSCharsetRule(self)
|
||||||
|
|
||||||
def _setCssText(self, cssText):
|
def _setCssText(self, cssText):
|
||||||
"""
|
"""
|
||||||
DOMException on setting
|
:param cssText:
|
||||||
|
A parsable DOMString.
|
||||||
- SYNTAX_ERR: (self)
|
:exceptions:
|
||||||
Raised if the specified CSS string value has a syntax error and
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
is unparsable.
|
Raised if the specified CSS string value has a syntax error and
|
||||||
- INVALID_MODIFICATION_ERR: (self)
|
is unparsable.
|
||||||
Raised if the specified CSS string value represents a different
|
- :exc:`~xml.dom.InvalidModificationErr`:
|
||||||
type of rule than the current one.
|
Raised if the specified CSS string value represents a different
|
||||||
- HIERARCHY_REQUEST_ERR: (CSSStylesheet)
|
type of rule than the current one.
|
||||||
Raised if the rule cannot be inserted at this point in the
|
- :exc:`~xml.dom.HierarchyRequestErr`:
|
||||||
style sheet.
|
Raised if the rule cannot be inserted at this point in the
|
||||||
- NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
|
style sheet.
|
||||||
Raised if the rule is readonly.
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
|
Raised if the rule is readonly.
|
||||||
"""
|
"""
|
||||||
super(CSSCharsetRule, self)._setCssText(cssText)
|
super(CSSCharsetRule, self)._setCssText(cssText)
|
||||||
|
|
||||||
@ -120,14 +116,15 @@ class CSSCharsetRule(cssrule.CSSRule):
|
|||||||
|
|
||||||
def _setEncoding(self, encoding):
|
def _setEncoding(self, encoding):
|
||||||
"""
|
"""
|
||||||
DOMException on setting
|
:param encoding:
|
||||||
|
a valid encoding to be used. Currently only valid Python encodings
|
||||||
- NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
|
are allowed.
|
||||||
Raised if this encoding rule is readonly.
|
:exceptions:
|
||||||
- SYNTAX_ERR: (self)
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
Raised if the specified encoding value has a syntax error and
|
Raised if this encoding rule is readonly.
|
||||||
is unparsable.
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
Currently only valid Python encodings are allowed.
|
Raised if the specified encoding value has a syntax error and
|
||||||
|
is unparsable.
|
||||||
"""
|
"""
|
||||||
self._checkReadonly()
|
self._checkReadonly()
|
||||||
tokenizer = self._tokenize2(encoding)
|
tokenizer = self._tokenize2(encoding)
|
||||||
@ -154,12 +151,8 @@ class CSSCharsetRule(cssrule.CSSRule):
|
|||||||
encoding = property(lambda self: self._encoding, _setEncoding,
|
encoding = property(lambda self: self._encoding, _setEncoding,
|
||||||
doc="(DOM)The encoding information used in this @charset rule.")
|
doc="(DOM)The encoding information used in this @charset rule.")
|
||||||
|
|
||||||
|
type = property(lambda self: self.CHARSET_RULE,
|
||||||
|
doc="The type of this rule, as defined by a CSSRule "
|
||||||
|
"type constant.")
|
||||||
|
|
||||||
wellformed = property(lambda self: bool(self.encoding))
|
wellformed = property(lambda self: bool(self.encoding))
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "cssutils.css.%s(encoding=%r)" % (
|
|
||||||
self.__class__.__name__, self.encoding)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "<cssutils.css.%s object encoding=%r at 0x%x>" % (
|
|
||||||
self.__class__.__name__, self.encoding, id(self))
|
|
||||||
|
@ -1,36 +1,24 @@
|
|||||||
"""CSSComment is not defined in DOM Level 2 at all but a cssutils defined
|
"""CSSComment is not defined in DOM Level 2 at all but a cssutils defined
|
||||||
class only.
|
class only.
|
||||||
Implements CSSRule which is also extended for a CSSComment rule type
|
|
||||||
|
Implements CSSRule which is also extended for a CSSComment rule type.
|
||||||
"""
|
"""
|
||||||
__all__ = ['CSSComment']
|
__all__ = ['CSSComment']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: csscomment.py 1170 2008-03-20 17:42:07Z cthedot $'
|
__version__ = '$Id: csscomment.py 1638 2009-01-13 20:39:33Z cthedot $'
|
||||||
|
|
||||||
import xml.dom
|
|
||||||
import cssrule
|
import cssrule
|
||||||
import cssutils
|
import cssutils
|
||||||
|
import xml.dom
|
||||||
|
|
||||||
class CSSComment(cssrule.CSSRule):
|
class CSSComment(cssrule.CSSRule):
|
||||||
"""
|
"""
|
||||||
(cssutils) a CSS comment
|
Represents a CSS comment (cssutils only).
|
||||||
|
|
||||||
Properties
|
Format::
|
||||||
==========
|
|
||||||
cssText: of type DOMString
|
|
||||||
The comment text including comment delimiters
|
|
||||||
|
|
||||||
Inherits properties from CSSRule
|
|
||||||
|
|
||||||
Format
|
|
||||||
======
|
|
||||||
::
|
|
||||||
|
|
||||||
/*...*/
|
/*...*/
|
||||||
"""
|
"""
|
||||||
type = property(lambda self: cssrule.CSSRule.COMMENT) # value = -1
|
|
||||||
# constant but needed:
|
|
||||||
wellformed = True
|
|
||||||
|
|
||||||
def __init__(self, cssText=None, parentRule=None,
|
def __init__(self, cssText=None, parentRule=None,
|
||||||
parentStyleSheet=None, readonly=False):
|
parentStyleSheet=None, readonly=False):
|
||||||
super(CSSComment, self).__init__(parentRule=parentRule,
|
super(CSSComment, self).__init__(parentRule=parentRule,
|
||||||
@ -42,28 +30,33 @@ class CSSComment(cssrule.CSSRule):
|
|||||||
|
|
||||||
self._readonly = readonly
|
self._readonly = readonly
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "cssutils.css.%s(cssText=%r)" % (
|
||||||
|
self.__class__.__name__, self.cssText)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "<cssutils.css.%s object cssText=%r at 0x%x>" % (
|
||||||
|
self.__class__.__name__, self.cssText, id(self))
|
||||||
|
|
||||||
def _getCssText(self):
|
def _getCssText(self):
|
||||||
"""returns serialized property cssText"""
|
"""Return serialized property cssText."""
|
||||||
return cssutils.ser.do_CSSComment(self)
|
return cssutils.ser.do_CSSComment(self)
|
||||||
|
|
||||||
def _setCssText(self, cssText):
|
def _setCssText(self, cssText):
|
||||||
"""
|
"""
|
||||||
cssText
|
:param cssText:
|
||||||
textual text to set or tokenlist which is not tokenized
|
textual text to set or tokenlist which is not tokenized
|
||||||
anymore. May also be a single token for this rule
|
anymore. May also be a single token for this rule
|
||||||
parser
|
|
||||||
if called from cssparser directly this is Parser instance
|
|
||||||
|
|
||||||
DOMException on setting
|
:exceptions:
|
||||||
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
- SYNTAX_ERR: (self)
|
Raised if the specified CSS string value has a syntax error and
|
||||||
Raised if the specified CSS string value has a syntax error and
|
is unparsable.
|
||||||
is unparsable.
|
- :exc:`~xml.dom.InvalidModificationErr`:
|
||||||
- INVALID_MODIFICATION_ERR: (self)
|
Raised if the specified CSS string value represents a different
|
||||||
Raised if the specified CSS string value represents a different
|
type of rule than the current one.
|
||||||
type of rule than the current one.
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
- NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
|
Raised if the rule is readonly.
|
||||||
Raised if the rule is readonly.
|
|
||||||
"""
|
"""
|
||||||
super(CSSComment, self)._setCssText(cssText)
|
super(CSSComment, self)._setCssText(cssText)
|
||||||
tokenizer = self._tokenize2(cssText)
|
tokenizer = self._tokenize2(cssText)
|
||||||
@ -81,12 +74,11 @@ class CSSComment(cssrule.CSSRule):
|
|||||||
self._cssText = self._tokenvalue(commenttoken)
|
self._cssText = self._tokenvalue(commenttoken)
|
||||||
|
|
||||||
cssText = property(_getCssText, _setCssText,
|
cssText = property(_getCssText, _setCssText,
|
||||||
doc=u"(cssutils) Textual representation of this comment")
|
doc=u"The parsable textual representation of this rule.")
|
||||||
|
|
||||||
def __repr__(self):
|
type = property(lambda self: self.COMMENT,
|
||||||
return "cssutils.css.%s(cssText=%r)" % (
|
doc="The type of this rule, as defined by a CSSRule "
|
||||||
self.__class__.__name__, self.cssText)
|
"type constant.")
|
||||||
|
|
||||||
def __str__(self):
|
# constant but needed:
|
||||||
return "<cssutils.css.%s object cssText=%r at 0x%x>" % (
|
wellformed = property(lambda self: True)
|
||||||
self.__class__.__name__, self.cssText, id(self))
|
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
"""
|
"""
|
||||||
__all__ = ['CSSFontFaceRule']
|
__all__ = ['CSSFontFaceRule']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: cssfontfacerule.py 1284 2008-06-05 16:29:17Z cthedot $'
|
__version__ = '$Id: cssfontfacerule.py 1638 2009-01-13 20:39:33Z cthedot $'
|
||||||
|
|
||||||
import xml.dom
|
from cssstyledeclaration import CSSStyleDeclaration
|
||||||
import cssrule
|
import cssrule
|
||||||
import cssutils
|
import cssutils
|
||||||
from cssstyledeclaration import CSSStyleDeclaration
|
import xml.dom
|
||||||
|
|
||||||
class CSSFontFaceRule(cssrule.CSSRule):
|
class CSSFontFaceRule(cssrule.CSSRule):
|
||||||
"""
|
"""
|
||||||
@ -15,36 +15,19 @@ class CSSFontFaceRule(cssrule.CSSRule):
|
|||||||
style sheet. The @font-face rule is used to hold a set of font
|
style sheet. The @font-face rule is used to hold a set of font
|
||||||
descriptions.
|
descriptions.
|
||||||
|
|
||||||
Properties
|
Format::
|
||||||
==========
|
|
||||||
atkeyword (cssutils only)
|
|
||||||
the literal keyword used
|
|
||||||
cssText: of type DOMString
|
|
||||||
The parsable textual representation of this rule
|
|
||||||
style: of type CSSStyleDeclaration
|
|
||||||
The declaration-block of this rule.
|
|
||||||
|
|
||||||
Inherits properties from CSSRule
|
|
||||||
|
|
||||||
Format
|
|
||||||
======
|
|
||||||
::
|
|
||||||
|
|
||||||
font_face
|
font_face
|
||||||
: FONT_FACE_SYM S*
|
: FONT_FACE_SYM S*
|
||||||
'{' S* declaration [ ';' S* declaration ]* '}' S*
|
'{' S* declaration [ ';' S* declaration ]* '}' S*
|
||||||
;
|
;
|
||||||
"""
|
"""
|
||||||
type = property(lambda self: cssrule.CSSRule.FONT_FACE_RULE)
|
|
||||||
# constant but needed:
|
|
||||||
wellformed = True
|
|
||||||
|
|
||||||
def __init__(self, style=None, parentRule=None,
|
def __init__(self, style=None, parentRule=None,
|
||||||
parentStyleSheet=None, readonly=False):
|
parentStyleSheet=None, readonly=False):
|
||||||
"""
|
"""
|
||||||
if readonly allows setting of properties in constructor only
|
If readonly allows setting of properties in constructor only.
|
||||||
|
|
||||||
style
|
:param style:
|
||||||
CSSStyleDeclaration for this CSSStyleRule
|
CSSStyleDeclaration for this CSSStyleRule
|
||||||
"""
|
"""
|
||||||
super(CSSFontFaceRule, self).__init__(parentRule=parentRule,
|
super(CSSFontFaceRule, self).__init__(parentRule=parentRule,
|
||||||
@ -57,27 +40,32 @@ class CSSFontFaceRule(cssrule.CSSRule):
|
|||||||
|
|
||||||
self._readonly = readonly
|
self._readonly = readonly
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "cssutils.css.%s(style=%r)" % (
|
||||||
|
self.__class__.__name__, self.style.cssText)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "<cssutils.css.%s object style=%r at 0x%x>" % (
|
||||||
|
self.__class__.__name__, self.style.cssText, id(self))
|
||||||
|
|
||||||
def _getCssText(self):
|
def _getCssText(self):
|
||||||
"""
|
"""Return serialized property cssText."""
|
||||||
returns serialized property cssText
|
|
||||||
"""
|
|
||||||
return cssutils.ser.do_CSSFontFaceRule(self)
|
return cssutils.ser.do_CSSFontFaceRule(self)
|
||||||
|
|
||||||
def _setCssText(self, cssText):
|
def _setCssText(self, cssText):
|
||||||
"""
|
"""
|
||||||
DOMException on setting
|
:exceptions:
|
||||||
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
- SYNTAX_ERR: (self, StyleDeclaration)
|
Raised if the specified CSS string value has a syntax error and
|
||||||
Raised if the specified CSS string value has a syntax error and
|
is unparsable.
|
||||||
is unparsable.
|
- :exc:`~xml.dom.InvalidModificationErr`:
|
||||||
- INVALID_MODIFICATION_ERR: (self)
|
Raised if the specified CSS string value represents a different
|
||||||
Raised if the specified CSS string value represents a different
|
type of rule than the current one.
|
||||||
type of rule than the current one.
|
- :exc:`~xml.dom.HierarchyRequestErr`:
|
||||||
- HIERARCHY_REQUEST_ERR: (CSSStylesheet)
|
Raised if the rule cannot be inserted at this point in the
|
||||||
Raised if the rule cannot be inserted at this point in the
|
style sheet.
|
||||||
style sheet.
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
- NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
|
Raised if the rule is readonly.
|
||||||
Raised if the rule is readonly.
|
|
||||||
"""
|
"""
|
||||||
super(CSSFontFaceRule, self)._setCssText(cssText)
|
super(CSSFontFaceRule, self)._setCssText(cssText)
|
||||||
|
|
||||||
@ -135,15 +123,12 @@ class CSSFontFaceRule(cssrule.CSSRule):
|
|||||||
self._setSeq(newseq) # contains (probably comments) upto { only
|
self._setSeq(newseq) # contains (probably comments) upto { only
|
||||||
|
|
||||||
cssText = property(_getCssText, _setCssText,
|
cssText = property(_getCssText, _setCssText,
|
||||||
doc="(DOM) The parsable textual representation of the rule.")
|
doc="(DOM) The parsable textual representation of this rule.")
|
||||||
|
|
||||||
def _getStyle(self):
|
|
||||||
return self._style
|
|
||||||
|
|
||||||
def _setStyle(self, style):
|
def _setStyle(self, style):
|
||||||
"""
|
"""
|
||||||
style
|
:param style:
|
||||||
StyleDeclaration or string
|
a CSSStyleDeclaration or string
|
||||||
"""
|
"""
|
||||||
self._checkReadonly()
|
self._checkReadonly()
|
||||||
if isinstance(style, basestring):
|
if isinstance(style, basestring):
|
||||||
@ -151,13 +136,13 @@ class CSSFontFaceRule(cssrule.CSSRule):
|
|||||||
else:
|
else:
|
||||||
self._style._seq = style.seq
|
self._style._seq = style.seq
|
||||||
|
|
||||||
style = property(_getStyle, _setStyle,
|
style = property(lambda self: self._style, _setStyle,
|
||||||
doc="(DOM) The declaration-block of this rule set.")
|
doc="(DOM) The declaration-block of this rule set, "
|
||||||
|
"a :class:`~cssutils.css.CSSStyleDeclaration`.")
|
||||||
|
|
||||||
def __repr__(self):
|
type = property(lambda self: self.FONT_FACE_RULE,
|
||||||
return "cssutils.css.%s(style=%r)" % (
|
doc="The type of this rule, as defined by a CSSRule "
|
||||||
self.__class__.__name__, self.style.cssText)
|
"type constant.")
|
||||||
|
|
||||||
def __str__(self):
|
# constant but needed:
|
||||||
return "<cssutils.css.%s object style=%r at 0x%x>" % (
|
wellformed = property(lambda self: True)
|
||||||
self.__class__.__name__, self.style.cssText, id(self))
|
|
||||||
|
@ -1,60 +1,30 @@
|
|||||||
"""CSSImportRule implements DOM Level 2 CSS CSSImportRule.
|
"""CSSImportRule implements DOM Level 2 CSS CSSImportRule plus the
|
||||||
|
``name`` property from http://www.w3.org/TR/css3-cascade/#cascading.
|
||||||
plus:
|
|
||||||
|
|
||||||
``name`` property
|
|
||||||
http://www.w3.org/TR/css3-cascade/#cascading
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
__all__ = ['CSSImportRule']
|
__all__ = ['CSSImportRule']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: cssimportrule.py 1401 2008-07-29 21:07:54Z cthedot $'
|
__version__ = '$Id: cssimportrule.py 1638 2009-01-13 20:39:33Z cthedot $'
|
||||||
|
|
||||||
|
import cssrule
|
||||||
|
import cssutils
|
||||||
import os
|
import os
|
||||||
import urllib
|
import urllib
|
||||||
import urlparse
|
import urlparse
|
||||||
import xml.dom
|
import xml.dom
|
||||||
import cssrule
|
|
||||||
import cssutils
|
|
||||||
|
|
||||||
class CSSImportRule(cssrule.CSSRule):
|
class CSSImportRule(cssrule.CSSRule):
|
||||||
"""
|
"""
|
||||||
Represents an @import rule within a CSS style sheet. The @import rule
|
Represents an @import rule within a CSS style sheet. The @import rule
|
||||||
is used to import style rules from other style sheets.
|
is used to import style rules from other style sheets.
|
||||||
|
|
||||||
Properties
|
Format::
|
||||||
==========
|
|
||||||
atkeyword: (cssutils only)
|
|
||||||
the literal keyword used
|
|
||||||
cssText: of type DOMString
|
|
||||||
The parsable textual representation of this rule
|
|
||||||
href: of type DOMString, (DOM readonly, cssutils also writable)
|
|
||||||
The location of the style sheet to be imported. The attribute will
|
|
||||||
not contain the url(...) specifier around the URI.
|
|
||||||
hreftype: 'uri' (serializer default) or 'string' (cssutils only)
|
|
||||||
The original type of href, not really relevant as it may be
|
|
||||||
reconfigured in the serializer but it is kept anyway
|
|
||||||
media: of type stylesheets::MediaList (DOM readonly)
|
|
||||||
A list of media types for this rule of type MediaList.
|
|
||||||
name:
|
|
||||||
An optional name used for cascading
|
|
||||||
styleSheet: of type CSSStyleSheet (DOM readonly)
|
|
||||||
The style sheet referred to by this rule. The value of this
|
|
||||||
attribute is None if the style sheet has not yet been loaded or if
|
|
||||||
it will not be loaded (e.g. if the stylesheet is for a media type
|
|
||||||
not supported by the user agent).
|
|
||||||
|
|
||||||
Inherits properties from CSSRule
|
import
|
||||||
|
: IMPORT_SYM S*
|
||||||
Format
|
[STRING|URI] S* [ medium [ COMMA S* medium]* ]? S* STRING? S* ';' S*
|
||||||
======
|
;
|
||||||
import
|
|
||||||
: IMPORT_SYM S*
|
|
||||||
[STRING|URI] S* [ medium [ COMMA S* medium]* ]? S* STRING? S* ';' S*
|
|
||||||
;
|
|
||||||
"""
|
"""
|
||||||
type = property(lambda self: cssrule.CSSRule.IMPORT_RULE)
|
|
||||||
|
|
||||||
def __init__(self, href=None, mediaText=u'all', name=None,
|
def __init__(self, href=None, mediaText=u'all', name=None,
|
||||||
parentRule=None, parentStyleSheet=None, readonly=False):
|
parentRule=None, parentStyleSheet=None, readonly=False):
|
||||||
"""
|
"""
|
||||||
@ -90,30 +60,44 @@ class CSSImportRule(cssrule.CSSRule):
|
|||||||
self._setSeq(seq)
|
self._setSeq(seq)
|
||||||
self._readonly = readonly
|
self._readonly = readonly
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
if self._usemedia:
|
||||||
|
mediaText = self.media.mediaText
|
||||||
|
else:
|
||||||
|
mediaText = None
|
||||||
|
return "cssutils.css.%s(href=%r, mediaText=%r, name=%r)" % (
|
||||||
|
self.__class__.__name__,
|
||||||
|
self.href, self.media.mediaText, self.name)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self._usemedia:
|
||||||
|
mediaText = self.media.mediaText
|
||||||
|
else:
|
||||||
|
mediaText = None
|
||||||
|
return "<cssutils.css.%s object href=%r mediaText=%r name=%r at 0x%x>" % (
|
||||||
|
self.__class__.__name__, self.href, mediaText, self.name, id(self))
|
||||||
|
|
||||||
_usemedia = property(lambda self: self.media.mediaText not in (u'', u'all'),
|
_usemedia = property(lambda self: self.media.mediaText not in (u'', u'all'),
|
||||||
doc="if self._media is used (or simply empty)")
|
doc="if self._media is used (or simply empty)")
|
||||||
|
|
||||||
def _getCssText(self):
|
def _getCssText(self):
|
||||||
"""
|
"""Return serialized property cssText."""
|
||||||
returns serialized property cssText
|
|
||||||
"""
|
|
||||||
return cssutils.ser.do_CSSImportRule(self)
|
return cssutils.ser.do_CSSImportRule(self)
|
||||||
|
|
||||||
def _setCssText(self, cssText):
|
def _setCssText(self, cssText):
|
||||||
"""
|
"""
|
||||||
DOMException on setting
|
:exceptions:
|
||||||
|
- :exc:`~xml.dom.HierarchyRequestErr`:
|
||||||
- HIERARCHY_REQUEST_ERR: (CSSStylesheet)
|
Raised if the rule cannot be inserted at this point in the
|
||||||
Raised if the rule cannot be inserted at this point in the
|
style sheet.
|
||||||
style sheet.
|
- :exc:`~xml.dom.InvalidModificationErr`:
|
||||||
- INVALID_MODIFICATION_ERR: (self)
|
Raised if the specified CSS string value represents a different
|
||||||
Raised if the specified CSS string value represents a different
|
type of rule than the current one.
|
||||||
type of rule than the current one.
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
- NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
|
Raised if the rule is readonly.
|
||||||
Raised if the rule is readonly.
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
- SYNTAX_ERR: (self)
|
Raised if the specified CSS string value has a syntax error and
|
||||||
Raised if the specified CSS string value has a syntax error and
|
is unparsable.
|
||||||
is unparsable.
|
|
||||||
"""
|
"""
|
||||||
super(CSSImportRule, self)._setCssText(cssText)
|
super(CSSImportRule, self)._setCssText(cssText)
|
||||||
tokenizer = self._tokenize2(cssText)
|
tokenizer = self._tokenize2(cssText)
|
||||||
@ -268,7 +252,7 @@ class CSSImportRule(cssrule.CSSRule):
|
|||||||
self.styleSheet._parentStyleSheet = self.parentStyleSheet
|
self.styleSheet._parentStyleSheet = self.parentStyleSheet
|
||||||
|
|
||||||
cssText = property(fget=_getCssText, fset=_setCssText,
|
cssText = property(fget=_getCssText, fset=_setCssText,
|
||||||
doc="(DOM attribute) The parsable textual representation.")
|
doc="(DOM) The parsable textual representation of this rule.")
|
||||||
|
|
||||||
def _setHref(self, href):
|
def _setHref(self, href):
|
||||||
# update seq
|
# update seq
|
||||||
@ -291,11 +275,11 @@ class CSSImportRule(cssrule.CSSRule):
|
|||||||
doc="Location of the style sheet to be imported.")
|
doc="Location of the style sheet to be imported.")
|
||||||
|
|
||||||
media = property(lambda self: self._media,
|
media = property(lambda self: self._media,
|
||||||
doc=u"(DOM readonly) A list of media types for this rule"
|
doc="(DOM readonly) A list of media types for this rule "
|
||||||
" of type MediaList")
|
"of type :class:`~cssutils.stylesheets.MediaList`.")
|
||||||
|
|
||||||
def _setName(self, name):
|
def _setName(self, name):
|
||||||
"""raises xml.dom.SyntaxErr if name is not a string"""
|
"""Raises xml.dom.SyntaxErr if name is not a string."""
|
||||||
if isinstance(name, basestring) or name is None:
|
if isinstance(name, basestring) or name is None:
|
||||||
# "" or ''
|
# "" or ''
|
||||||
if not name:
|
if not name:
|
||||||
@ -322,7 +306,7 @@ class CSSImportRule(cssrule.CSSRule):
|
|||||||
self._log.error(u'CSSImportRule: Not a valid name: %s' % name)
|
self._log.error(u'CSSImportRule: Not a valid name: %s' % name)
|
||||||
|
|
||||||
name = property(lambda self: self._name, _setName,
|
name = property(lambda self: self._name, _setName,
|
||||||
doc=u"An optional name for the imported sheet")
|
doc=u"An optional name for the imported sheet.")
|
||||||
|
|
||||||
def __setStyleSheet(self):
|
def __setStyleSheet(self):
|
||||||
"""Read new CSSStyleSheet cssText from href using parentStyleSheet.href
|
"""Read new CSSStyleSheet cssText from href using parentStyleSheet.href
|
||||||
@ -372,28 +356,15 @@ class CSSImportRule(cssrule.CSSRule):
|
|||||||
styleSheet = property(lambda self: self._styleSheet,
|
styleSheet = property(lambda self: self._styleSheet,
|
||||||
doc="(readonly) The style sheet referred to by this rule.")
|
doc="(readonly) The style sheet referred to by this rule.")
|
||||||
|
|
||||||
|
type = property(lambda self: self.IMPORT_RULE,
|
||||||
|
doc="The type of this rule, as defined by a CSSRule "
|
||||||
|
"type constant.")
|
||||||
|
|
||||||
def _getWellformed(self):
|
def _getWellformed(self):
|
||||||
"depending if media is used at all"
|
"Depending if media is used at all."
|
||||||
if self._usemedia:
|
if self._usemedia:
|
||||||
return bool(self.href and self.media.wellformed)
|
return bool(self.href and self.media.wellformed)
|
||||||
else:
|
else:
|
||||||
return bool(self.href)
|
return bool(self.href)
|
||||||
|
|
||||||
wellformed = property(_getWellformed)
|
wellformed = property(_getWellformed)
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
if self._usemedia:
|
|
||||||
mediaText = self.media.mediaText
|
|
||||||
else:
|
|
||||||
mediaText = None
|
|
||||||
return "cssutils.css.%s(href=%r, mediaText=%r, name=%r)" % (
|
|
||||||
self.__class__.__name__,
|
|
||||||
self.href, self.media.mediaText, self.name)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
if self._usemedia:
|
|
||||||
mediaText = self.media.mediaText
|
|
||||||
else:
|
|
||||||
mediaText = None
|
|
||||||
return "<cssutils.css.%s object href=%r mediaText=%r name=%r at 0x%x>" % (
|
|
||||||
self.__class__.__name__, self.href, mediaText, self.name, id(self))
|
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
"""CSSMediaRule implements DOM Level 2 CSS CSSMediaRule.
|
"""CSSMediaRule implements DOM Level 2 CSS CSSMediaRule."""
|
||||||
"""
|
|
||||||
__all__ = ['CSSMediaRule']
|
__all__ = ['CSSMediaRule']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: cssmediarule.py 1370 2008-07-14 20:15:03Z cthedot $'
|
__version__ = '$Id: cssmediarule.py 1641 2009-01-13 21:05:37Z cthedot $'
|
||||||
|
|
||||||
import xml.dom
|
|
||||||
import cssrule
|
import cssrule
|
||||||
import cssutils
|
import cssutils
|
||||||
|
import xml.dom
|
||||||
|
|
||||||
class CSSMediaRule(cssrule.CSSRule):
|
class CSSMediaRule(cssrule.CSSRule):
|
||||||
"""
|
"""
|
||||||
@ -14,31 +13,17 @@ class CSSMediaRule(cssrule.CSSRule):
|
|||||||
MEDIA_RULE constant. On these objects the type attribute must return the
|
MEDIA_RULE constant. On these objects the type attribute must return the
|
||||||
value of that constant.
|
value of that constant.
|
||||||
|
|
||||||
Properties
|
Format::
|
||||||
==========
|
|
||||||
atkeyword: (cssutils only)
|
|
||||||
the literal keyword used
|
|
||||||
cssRules: A css::CSSRuleList of all CSS rules contained within the
|
|
||||||
media block.
|
|
||||||
cssText: of type DOMString
|
|
||||||
The parsable textual representation of this rule
|
|
||||||
media: of type stylesheets::MediaList, (DOM readonly)
|
|
||||||
A list of media types for this rule of type MediaList.
|
|
||||||
name:
|
|
||||||
An optional name used for cascading
|
|
||||||
|
|
||||||
Format
|
|
||||||
======
|
|
||||||
media
|
|
||||||
: MEDIA_SYM S* medium [ COMMA S* medium ]*
|
: MEDIA_SYM S* medium [ COMMA S* medium ]*
|
||||||
|
|
||||||
STRING? # the name
|
STRING? # the name
|
||||||
|
|
||||||
LBRACE S* ruleset* '}' S*;
|
LBRACE S* ruleset* '}' S*;
|
||||||
"""
|
|
||||||
# CONSTANT
|
|
||||||
type = property(lambda self: cssrule.CSSRule.MEDIA_RULE)
|
|
||||||
|
|
||||||
|
``cssRules``
|
||||||
|
All Rules in this media rule, a :class:`~cssutils.css.CSSRuleList`.
|
||||||
|
"""
|
||||||
def __init__(self, mediaText='all', name=None,
|
def __init__(self, mediaText='all', name=None,
|
||||||
parentRule=None, parentStyleSheet=None, readonly=False):
|
parentRule=None, parentStyleSheet=None, readonly=False):
|
||||||
"""constructor"""
|
"""constructor"""
|
||||||
@ -56,12 +41,20 @@ class CSSMediaRule(cssrule.CSSRule):
|
|||||||
self._readonly = readonly
|
self._readonly = readonly
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
"""generator which iterates over cssRules."""
|
"""Generator iterating over these rule's cssRules."""
|
||||||
for rule in self.cssRules:
|
for rule in self.cssRules:
|
||||||
yield rule
|
yield rule
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "cssutils.css.%s(mediaText=%r)" % (
|
||||||
|
self.__class__.__name__, self.media.mediaText)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "<cssutils.css.%s object mediaText=%r at 0x%x>" % (
|
||||||
|
self.__class__.__name__, self.media.mediaText, id(self))
|
||||||
|
|
||||||
def _getCssText(self):
|
def _getCssText(self):
|
||||||
"""return serialized property cssText"""
|
"""Return serialized property cssText."""
|
||||||
return cssutils.ser.do_CSSMediaRule(self)
|
return cssutils.ser.do_CSSMediaRule(self)
|
||||||
|
|
||||||
def _setCssText(self, cssText):
|
def _setCssText(self, cssText):
|
||||||
@ -69,19 +62,19 @@ class CSSMediaRule(cssrule.CSSRule):
|
|||||||
:param cssText:
|
:param cssText:
|
||||||
a parseable string or a tuple of (cssText, dict-of-namespaces)
|
a parseable string or a tuple of (cssText, dict-of-namespaces)
|
||||||
:Exceptions:
|
:Exceptions:
|
||||||
- `NAMESPACE_ERR`: (Selector)
|
- :exc:`~xml.dom.NamespaceErr`:
|
||||||
Raised if a specified selector uses an unknown namespace
|
Raised if a specified selector uses an unknown namespace
|
||||||
prefix.
|
prefix.
|
||||||
- `SYNTAX_ERR`: (self, StyleDeclaration, etc)
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
Raised if the specified CSS string value has a syntax error and
|
Raised if the specified CSS string value has a syntax error and
|
||||||
is unparsable.
|
is unparsable.
|
||||||
- `INVALID_MODIFICATION_ERR`: (self)
|
- :exc:`~xml.dom.InvalidModificationErr`:
|
||||||
Raised if the specified CSS string value represents a different
|
Raised if the specified CSS string value represents a different
|
||||||
type of rule than the current one.
|
type of rule than the current one.
|
||||||
- `HIERARCHY_REQUEST_ERR`: (CSSStylesheet)
|
- :exc:`~xml.dom.HierarchyRequestErr`:
|
||||||
Raised if the rule cannot be inserted at this point in the
|
Raised if the rule cannot be inserted at this point in the
|
||||||
style sheet.
|
style sheet.
|
||||||
- `NO_MODIFICATION_ALLOWED_ERR`: (CSSRule)
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
Raised if the rule is readonly.
|
Raised if the rule is readonly.
|
||||||
"""
|
"""
|
||||||
super(CSSMediaRule, self)._setCssText(cssText)
|
super(CSSMediaRule, self)._setCssText(cssText)
|
||||||
@ -209,7 +202,7 @@ class CSSMediaRule(cssrule.CSSRule):
|
|||||||
self.cssRules.append(r)
|
self.cssRules.append(r)
|
||||||
|
|
||||||
cssText = property(_getCssText, _setCssText,
|
cssText = property(_getCssText, _setCssText,
|
||||||
doc="(DOM attribute) The parsable textual representation.")
|
doc="(DOM) The parsable textual representation of this rule.")
|
||||||
|
|
||||||
def _setName(self, name):
|
def _setName(self, name):
|
||||||
if isinstance(name, basestring) or name is None:
|
if isinstance(name, basestring) or name is None:
|
||||||
@ -221,30 +214,26 @@ class CSSMediaRule(cssrule.CSSRule):
|
|||||||
else:
|
else:
|
||||||
self._log.error(u'CSSImportRule: Not a valid name: %s' % name)
|
self._log.error(u'CSSImportRule: Not a valid name: %s' % name)
|
||||||
|
|
||||||
|
|
||||||
name = property(lambda self: self._name, _setName,
|
name = property(lambda self: self._name, _setName,
|
||||||
doc=u"An optional name for the media rules")
|
doc=u"An optional name for this media rule.")
|
||||||
|
|
||||||
media = property(lambda self: self._media,
|
media = property(lambda self: self._media,
|
||||||
doc=u"(DOM readonly) A list of media types for this rule of type\
|
doc=u"(DOM readonly) A list of media types for this rule of type "
|
||||||
MediaList")
|
u":class:`~cssutils.stylesheets.MediaList`.")
|
||||||
|
|
||||||
wellformed = property(lambda self: self.media.wellformed)
|
|
||||||
|
|
||||||
def deleteRule(self, index):
|
def deleteRule(self, index):
|
||||||
"""
|
"""
|
||||||
index
|
Delete the rule at `index` from the media block.
|
||||||
within the media block's rule collection of the rule to remove.
|
|
||||||
|
|
||||||
Used to delete a rule from the media block.
|
:param index:
|
||||||
|
of the rule to remove within the media block's rule collection
|
||||||
|
|
||||||
DOMExceptions
|
:Exceptions:
|
||||||
|
- :exc:`~xml.dom.IndexSizeErr`:
|
||||||
- INDEX_SIZE_ERR: (self)
|
Raised if the specified index does not correspond to a rule in
|
||||||
Raised if the specified index does not correspond to a rule in
|
the media rule list.
|
||||||
the media rule list.
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
Raised if this media rule is readonly.
|
||||||
Raised if this media rule is readonly.
|
|
||||||
"""
|
"""
|
||||||
self._checkReadonly()
|
self._checkReadonly()
|
||||||
|
|
||||||
@ -257,46 +246,47 @@ class CSSMediaRule(cssrule.CSSRule):
|
|||||||
index, self.cssRules.length))
|
index, self.cssRules.length))
|
||||||
|
|
||||||
def add(self, rule):
|
def add(self, rule):
|
||||||
"""Add rule to end of this mediarule. Same as ``.insertRule(rule)``."""
|
"""Add `rule` to end of this mediarule.
|
||||||
|
Same as :meth:`~cssutils.css.CSSMediaRule.insertRule`."""
|
||||||
self.insertRule(rule, index=None)
|
self.insertRule(rule, index=None)
|
||||||
|
|
||||||
def insertRule(self, rule, index=None):
|
def insertRule(self, rule, index=None):
|
||||||
"""
|
"""
|
||||||
rule
|
Insert `rule` into the media block.
|
||||||
The parsable text representing the rule. For rule sets this
|
|
||||||
contains both the selector and the style declaration. For
|
:param rule:
|
||||||
at-rules, this specifies both the at-identifier and the rule
|
the parsable text representing the `rule` to be inserted. For rule
|
||||||
|
sets this contains both the selector and the style declaration.
|
||||||
|
For at-rules, this specifies both the at-identifier and the rule
|
||||||
content.
|
content.
|
||||||
|
|
||||||
cssutils also allows rule to be a valid **CSSRule** object
|
cssutils also allows rule to be a valid :class:`~cssutils.css.CSSRule`
|
||||||
|
object.
|
||||||
|
|
||||||
index
|
:param index:
|
||||||
within the media block's rule collection of the rule before
|
before the specified `rule` will be inserted.
|
||||||
which to insert the specified rule. If the specified index is
|
If the specified `index` is
|
||||||
equal to the length of the media blocks's rule collection, the
|
equal to the length of the media blocks's rule collection, the
|
||||||
rule will be added to the end of the media block.
|
rule will be added to the end of the media block.
|
||||||
If index is not given or None rule will be appended to rule
|
If index is not given or None rule will be appended to rule
|
||||||
list.
|
list.
|
||||||
|
|
||||||
Used to insert a new rule into the media block.
|
:returns:
|
||||||
|
the index within the media block's rule collection of the
|
||||||
|
newly inserted rule.
|
||||||
|
|
||||||
DOMException on setting
|
:exceptions:
|
||||||
|
- :exc:`~xml.dom.HierarchyRequestErr`:
|
||||||
- HIERARCHY_REQUEST_ERR:
|
Raised if the `rule` cannot be inserted at the specified `index`,
|
||||||
(no use case yet as no @charset or @import allowed))
|
e.g., if an @import rule is inserted after a standard rule set
|
||||||
Raised if the rule cannot be inserted at the specified index,
|
or other at-rule.
|
||||||
e.g., if an @import rule is inserted after a standard rule set
|
- :exc:`~xml.dom.IndexSizeErr`:
|
||||||
or other at-rule.
|
Raised if the specified `index` is not a valid insertion point.
|
||||||
- INDEX_SIZE_ERR: (self)
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
Raised if the specified index is not a valid insertion point.
|
Raised if this media rule is readonly.
|
||||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
Raised if this media rule is readonly.
|
Raised if the specified `rule` has a syntax error and is
|
||||||
- SYNTAX_ERR: (CSSStyleRule)
|
unparsable.
|
||||||
Raised if the specified rule has a syntax error and is
|
|
||||||
unparsable.
|
|
||||||
|
|
||||||
returns the index within the media block's rule collection of the
|
|
||||||
newly inserted rule.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._checkReadonly()
|
self._checkReadonly()
|
||||||
@ -340,10 +330,8 @@ class CSSMediaRule(cssrule.CSSRule):
|
|||||||
rule._parentStyleSheet = self.parentStyleSheet
|
rule._parentStyleSheet = self.parentStyleSheet
|
||||||
return index
|
return index
|
||||||
|
|
||||||
def __repr__(self):
|
type = property(lambda self: self.MEDIA_RULE,
|
||||||
return "cssutils.css.%s(mediaText=%r)" % (
|
doc="The type of this rule, as defined by a CSSRule "
|
||||||
self.__class__.__name__, self.media.mediaText)
|
"type constant.")
|
||||||
|
|
||||||
def __str__(self):
|
wellformed = property(lambda self: self.media.wellformed)
|
||||||
return "<cssutils.css.%s object mediaText=%r at 0x%x>" % (
|
|
||||||
self.__class__.__name__, self.media.mediaText, id(self))
|
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
"""CSSNamespaceRule currently implements
|
"""CSSNamespaceRule currently implements http://dev.w3.org/csswg/css3-namespace/"""
|
||||||
http://dev.w3.org/csswg/css3-namespace/
|
|
||||||
|
|
||||||
(until 0.9.5a2: http://www.w3.org/TR/2006/WD-css3-namespace-20060828/)
|
|
||||||
"""
|
|
||||||
__all__ = ['CSSNamespaceRule']
|
__all__ = ['CSSNamespaceRule']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: cssnamespacerule.py 1305 2008-06-22 18:42:51Z cthedot $'
|
__version__ = '$Id: cssnamespacerule.py 1638 2009-01-13 20:39:33Z cthedot $'
|
||||||
|
|
||||||
import xml.dom
|
from cssutils.helper import Deprecated
|
||||||
import cssrule
|
import cssrule
|
||||||
import cssutils
|
import cssutils
|
||||||
from cssutils.helper import Deprecated
|
import xml.dom
|
||||||
|
|
||||||
class CSSNamespaceRule(cssrule.CSSRule):
|
class CSSNamespaceRule(cssrule.CSSRule):
|
||||||
"""
|
"""
|
||||||
@ -21,35 +17,18 @@ class CSSNamespaceRule(cssrule.CSSRule):
|
|||||||
used in namespace-qualified names such as those described in the
|
used in namespace-qualified names such as those described in the
|
||||||
Selectors Module [SELECT] or the Values and Units module [CSS3VAL].
|
Selectors Module [SELECT] or the Values and Units module [CSS3VAL].
|
||||||
|
|
||||||
Properties
|
Dealing with these rules directly is not needed anymore, easier is
|
||||||
==========
|
the use of :attr:`cssutils.css.CSSStyleSheet.namespaces`.
|
||||||
atkeyword (cssutils only)
|
|
||||||
the literal keyword used
|
|
||||||
cssText: of type DOMString
|
|
||||||
The parsable textual representation of this rule
|
|
||||||
namespaceURI: of type DOMString
|
|
||||||
The namespace URI (a simple string!) which is bound to the given
|
|
||||||
prefix. If no prefix is set (``CSSNamespaceRule.prefix==''``)
|
|
||||||
the namespace defined by ``namespaceURI`` is set as the default
|
|
||||||
namespace.
|
|
||||||
prefix: of type DOMString
|
|
||||||
The prefix used in the stylesheet for the given
|
|
||||||
``CSSNamespaceRule.nsuri``. If prefix is empty namespaceURI sets a
|
|
||||||
default namespace for the stylesheet.
|
|
||||||
|
|
||||||
Inherits properties from CSSRule
|
Format::
|
||||||
|
|
||||||
Format
|
namespace
|
||||||
======
|
: NAMESPACE_SYM S* [namespace_prefix S*]? [STRING|URI] S* ';' S*
|
||||||
namespace
|
;
|
||||||
: NAMESPACE_SYM S* [namespace_prefix S*]? [STRING|URI] S* ';' S*
|
namespace_prefix
|
||||||
;
|
: IDENT
|
||||||
namespace_prefix
|
;
|
||||||
: IDENT
|
|
||||||
;
|
|
||||||
"""
|
"""
|
||||||
type = property(lambda self: cssrule.CSSRule.NAMESPACE_RULE)
|
|
||||||
|
|
||||||
def __init__(self, namespaceURI=None, prefix=None, cssText=None,
|
def __init__(self, namespaceURI=None, prefix=None, cssText=None,
|
||||||
parentRule=None, parentStyleSheet=None, readonly=False):
|
parentRule=None, parentStyleSheet=None, readonly=False):
|
||||||
"""
|
"""
|
||||||
@ -102,27 +81,31 @@ class CSSNamespaceRule(cssrule.CSSRule):
|
|||||||
|
|
||||||
self._readonly = readonly
|
self._readonly = readonly
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "cssutils.css.%s(namespaceURI=%r, prefix=%r)" % (
|
||||||
|
self.__class__.__name__, self.namespaceURI, self.prefix)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "<cssutils.css.%s object namespaceURI=%r prefix=%r at 0x%x>" % (
|
||||||
|
self.__class__.__name__, self.namespaceURI, self.prefix, id(self))
|
||||||
|
|
||||||
def _getCssText(self):
|
def _getCssText(self):
|
||||||
"""
|
"""Return serialized property cssText"""
|
||||||
returns serialized property cssText
|
|
||||||
"""
|
|
||||||
return cssutils.ser.do_CSSNamespaceRule(self)
|
return cssutils.ser.do_CSSNamespaceRule(self)
|
||||||
|
|
||||||
def _setCssText(self, cssText):
|
def _setCssText(self, cssText):
|
||||||
"""
|
"""
|
||||||
DOMException on setting
|
|
||||||
|
|
||||||
:param cssText: initial value for this rules cssText which is parsed
|
:param cssText: initial value for this rules cssText which is parsed
|
||||||
:Exceptions:
|
:exceptions:
|
||||||
- `HIERARCHY_REQUEST_ERR`: (CSSStylesheet)
|
- :exc:`~xml.dom.HierarchyRequestErr`:
|
||||||
Raised if the rule cannot be inserted at this point in the
|
Raised if the rule cannot be inserted at this point in the
|
||||||
style sheet.
|
style sheet.
|
||||||
- `INVALID_MODIFICATION_ERR`: (self)
|
- :exc:`~xml.dom.InvalidModificationErr`:
|
||||||
Raised if the specified CSS string value represents a different
|
Raised if the specified CSS string value represents a different
|
||||||
type of rule than the current one.
|
type of rule than the current one.
|
||||||
- `NO_MODIFICATION_ALLOWED_ERR`: (CSSRule)
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
Raised if the rule is readonly.
|
Raised if the rule is readonly.
|
||||||
- `SYNTAX_ERR`: (self)
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
Raised if the specified CSS string value has a syntax error and
|
Raised if the specified CSS string value has a syntax error and
|
||||||
is unparsable.
|
is unparsable.
|
||||||
"""
|
"""
|
||||||
@ -222,15 +205,13 @@ class CSSNamespaceRule(cssrule.CSSRule):
|
|||||||
self._setSeq(newseq)
|
self._setSeq(newseq)
|
||||||
|
|
||||||
cssText = property(fget=_getCssText, fset=_setCssText,
|
cssText = property(fget=_getCssText, fset=_setCssText,
|
||||||
doc="(DOM attribute) The parsable textual representation.")
|
doc="(DOM) The parsable textual representation of this rule.")
|
||||||
|
|
||||||
def _setNamespaceURI(self, namespaceURI):
|
def _setNamespaceURI(self, namespaceURI):
|
||||||
"""
|
"""
|
||||||
DOMException on setting
|
|
||||||
|
|
||||||
:param namespaceURI: the initial value for this rules namespaceURI
|
:param namespaceURI: the initial value for this rules namespaceURI
|
||||||
:Exceptions:
|
:exceptions:
|
||||||
- `NO_MODIFICATION_ALLOWED_ERR`:
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
(CSSRule) Raised if this rule is readonly or a namespaceURI is
|
(CSSRule) Raised if this rule is readonly or a namespaceURI is
|
||||||
already set in this rule.
|
already set in this rule.
|
||||||
"""
|
"""
|
||||||
@ -246,18 +227,16 @@ class CSSNamespaceRule(cssrule.CSSRule):
|
|||||||
error=xml.dom.NoModificationAllowedErr)
|
error=xml.dom.NoModificationAllowedErr)
|
||||||
|
|
||||||
namespaceURI = property(lambda self: self._namespaceURI, _setNamespaceURI,
|
namespaceURI = property(lambda self: self._namespaceURI, _setNamespaceURI,
|
||||||
doc="URI (string!) of the defined namespace.")
|
doc="URI (handled as simple string) of the defined namespace.")
|
||||||
|
|
||||||
def _setPrefix(self, prefix=None):
|
def _setPrefix(self, prefix=None):
|
||||||
"""
|
"""
|
||||||
DOMException on setting
|
|
||||||
|
|
||||||
:param prefix: the new prefix
|
:param prefix: the new prefix
|
||||||
:Exceptions:
|
:exceptions:
|
||||||
- `SYNTAX_ERR`: (TODO)
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
Raised if the specified CSS string value has a syntax error and
|
Raised if the specified CSS string value has a syntax error and
|
||||||
is unparsable.
|
is unparsable.
|
||||||
- `NO_MODIFICATION_ALLOWED_ERR`: CSSRule)
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
Raised if this rule is readonly.
|
Raised if this rule is readonly.
|
||||||
"""
|
"""
|
||||||
self._checkReadonly()
|
self._checkReadonly()
|
||||||
@ -295,12 +274,9 @@ class CSSNamespaceRule(cssrule.CSSRule):
|
|||||||
# _setParentStyleSheet,
|
# _setParentStyleSheet,
|
||||||
# doc=u"Containing CSSStyleSheet.")
|
# doc=u"Containing CSSStyleSheet.")
|
||||||
|
|
||||||
|
type = property(lambda self: self.NAMESPACE_RULE,
|
||||||
|
doc="The type of this rule, as defined by a CSSRule "
|
||||||
|
"type constant.")
|
||||||
|
|
||||||
wellformed = property(lambda self: self.namespaceURI is not None)
|
wellformed = property(lambda self: self.namespaceURI is not None)
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "cssutils.css.%s(namespaceURI=%r, prefix=%r)" % (
|
|
||||||
self.__class__.__name__, self.namespaceURI, self.prefix)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "<cssutils.css.%s object namespaceURI=%r prefix=%r at 0x%x>" % (
|
|
||||||
self.__class__.__name__, self.namespaceURI, self.prefix, id(self))
|
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
"""
|
"""
|
||||||
__all__ = ['CSSPageRule']
|
__all__ = ['CSSPageRule']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: csspagerule.py 1284 2008-06-05 16:29:17Z cthedot $'
|
__version__ = '$Id: csspagerule.py 1658 2009-02-07 18:24:40Z cthedot $'
|
||||||
|
|
||||||
import xml.dom
|
from cssstyledeclaration import CSSStyleDeclaration
|
||||||
|
from selectorlist import SelectorList
|
||||||
import cssrule
|
import cssrule
|
||||||
import cssutils
|
import cssutils
|
||||||
from selectorlist import SelectorList
|
import xml.dom
|
||||||
from cssstyledeclaration import CSSStyleDeclaration
|
|
||||||
|
|
||||||
class CSSPageRule(cssrule.CSSRule):
|
class CSSPageRule(cssrule.CSSRule):
|
||||||
"""
|
"""
|
||||||
@ -16,22 +16,7 @@ class CSSPageRule(cssrule.CSSRule):
|
|||||||
sheet. The @page rule is used to specify the dimensions, orientation,
|
sheet. The @page rule is used to specify the dimensions, orientation,
|
||||||
margins, etc. of a page box for paged media.
|
margins, etc. of a page box for paged media.
|
||||||
|
|
||||||
Properties
|
Format::
|
||||||
==========
|
|
||||||
atkeyword (cssutils only)
|
|
||||||
the literal keyword used
|
|
||||||
cssText: of type DOMString
|
|
||||||
The parsable textual representation of this rule
|
|
||||||
selectorText: of type DOMString
|
|
||||||
The parsable textual representation of the page selector for the rule.
|
|
||||||
style: of type CSSStyleDeclaration
|
|
||||||
The declaration-block of this rule.
|
|
||||||
|
|
||||||
Inherits properties from CSSRule
|
|
||||||
|
|
||||||
Format
|
|
||||||
======
|
|
||||||
::
|
|
||||||
|
|
||||||
page
|
page
|
||||||
: PAGE_SYM S* pseudo_page? S*
|
: PAGE_SYM S* pseudo_page? S*
|
||||||
@ -40,20 +25,15 @@ class CSSPageRule(cssrule.CSSRule):
|
|||||||
pseudo_page
|
pseudo_page
|
||||||
: ':' IDENT # :first, :left, :right in CSS 2.1
|
: ':' IDENT # :first, :left, :right in CSS 2.1
|
||||||
;
|
;
|
||||||
|
|
||||||
"""
|
"""
|
||||||
type = property(lambda self: cssrule.CSSRule.PAGE_RULE)
|
|
||||||
# constant but needed:
|
|
||||||
wellformed = True
|
|
||||||
|
|
||||||
def __init__(self, selectorText=None, style=None, parentRule=None,
|
def __init__(self, selectorText=None, style=None, parentRule=None,
|
||||||
parentStyleSheet=None, readonly=False):
|
parentStyleSheet=None, readonly=False):
|
||||||
"""
|
"""
|
||||||
if readonly allows setting of properties in constructor only
|
If readonly allows setting of properties in constructor only.
|
||||||
|
|
||||||
selectorText
|
:param selectorText:
|
||||||
type string
|
type string
|
||||||
style
|
:param style:
|
||||||
CSSStyleDeclaration for this CSSStyleRule
|
CSSStyleDeclaration for this CSSStyleRule
|
||||||
"""
|
"""
|
||||||
super(CSSPageRule, self).__init__(parentRule=parentRule,
|
super(CSSPageRule, self).__init__(parentRule=parentRule,
|
||||||
@ -64,7 +44,7 @@ class CSSPageRule(cssrule.CSSRule):
|
|||||||
self.selectorText = selectorText
|
self.selectorText = selectorText
|
||||||
tempseq.append(self.selectorText, 'selectorText')
|
tempseq.append(self.selectorText, 'selectorText')
|
||||||
else:
|
else:
|
||||||
self._selectorText = u''
|
self._selectorText = self._tempSeq()
|
||||||
if style:
|
if style:
|
||||||
self.style = style
|
self.style = style
|
||||||
tempseq.append(self.style, 'style')
|
tempseq.append(self.style, 'style')
|
||||||
@ -74,20 +54,29 @@ class CSSPageRule(cssrule.CSSRule):
|
|||||||
|
|
||||||
self._readonly = readonly
|
self._readonly = readonly
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "cssutils.css.%s(selectorText=%r, style=%r)" % (
|
||||||
|
self.__class__.__name__, self.selectorText, self.style.cssText)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "<cssutils.css.%s object selectorText=%r style=%r at 0x%x>" % (
|
||||||
|
self.__class__.__name__, self.selectorText, self.style.cssText,
|
||||||
|
id(self))
|
||||||
|
|
||||||
def __parseSelectorText(self, selectorText):
|
def __parseSelectorText(self, selectorText):
|
||||||
"""
|
"""
|
||||||
parses selectorText which may also be a list of tokens
|
Parse `selectorText` which may also be a list of tokens
|
||||||
and returns (selectorText, seq)
|
and returns (selectorText, seq).
|
||||||
|
|
||||||
see _setSelectorText for details
|
see _setSelectorText for details
|
||||||
"""
|
"""
|
||||||
# for closures: must be a mutable
|
# for closures: must be a mutable
|
||||||
new = {'selector': None, 'wellformed': True}
|
new = {'wellformed': True, 'last-S': False}
|
||||||
|
|
||||||
def _char(expected, seq, token, tokenizer=None):
|
def _char(expected, seq, token, tokenizer=None):
|
||||||
# pseudo_page, :left, :right or :first
|
# pseudo_page, :left, :right or :first
|
||||||
val = self._tokenvalue(token)
|
val = self._tokenvalue(token)
|
||||||
if ':' == expected and u':' == val:
|
if not new['last-S'] and expected in ['page', ': or EOF'] and u':' == val:
|
||||||
try:
|
try:
|
||||||
identtoken = tokenizer.next()
|
identtoken = tokenizer.next()
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
@ -100,8 +89,7 @@ class CSSPageRule(cssrule.CSSRule):
|
|||||||
u'CSSPageRule selectorText: Expected IDENT but found: %r' %
|
u'CSSPageRule selectorText: Expected IDENT but found: %r' %
|
||||||
ival, token)
|
ival, token)
|
||||||
else:
|
else:
|
||||||
new['selector'] = val + ival
|
seq.append(val + ival, 'pseudo')
|
||||||
seq.append(new['selector'], 'selector')
|
|
||||||
return 'EOF'
|
return 'EOF'
|
||||||
return expected
|
return expected
|
||||||
else:
|
else:
|
||||||
@ -112,22 +100,37 @@ class CSSPageRule(cssrule.CSSRule):
|
|||||||
|
|
||||||
def S(expected, seq, token, tokenizer=None):
|
def S(expected, seq, token, tokenizer=None):
|
||||||
"Does not raise if EOF is found."
|
"Does not raise if EOF is found."
|
||||||
|
if expected == ': or EOF':
|
||||||
|
# pseudo must directly follow IDENT if given
|
||||||
|
new['last-S'] = True
|
||||||
return expected
|
return expected
|
||||||
|
|
||||||
|
def IDENT(expected, seq, token, tokenizer=None):
|
||||||
|
""
|
||||||
|
val = self._tokenvalue(token)
|
||||||
|
if 'page' == expected:
|
||||||
|
seq.append(val, 'IDENT')
|
||||||
|
return ': or EOF'
|
||||||
|
else:
|
||||||
|
new['wellformed'] = False
|
||||||
|
self._log.error(
|
||||||
|
u'CSSPageRule selectorText: Unexpected IDENT: %r' % val, token)
|
||||||
|
return expected
|
||||||
|
|
||||||
def COMMENT(expected, seq, token, tokenizer=None):
|
def COMMENT(expected, seq, token, tokenizer=None):
|
||||||
"Does not raise if EOF is found."
|
"Does not raise if EOF is found."
|
||||||
seq.append(cssutils.css.CSSComment([token]), 'COMMENT')
|
seq.append(cssutils.css.CSSComment([token]), 'COMMENT')
|
||||||
return expected
|
return expected
|
||||||
|
|
||||||
newseq = self._tempSeq()
|
newseq = self._tempSeq()
|
||||||
wellformed, expected = self._parse(expected=':',
|
wellformed, expected = self._parse(expected='page',
|
||||||
seq=newseq, tokenizer=self._tokenize2(selectorText),
|
seq=newseq, tokenizer=self._tokenize2(selectorText),
|
||||||
productions={'CHAR': _char,
|
productions={'CHAR': _char,
|
||||||
|
'IDENT': IDENT,
|
||||||
'COMMENT': COMMENT,
|
'COMMENT': COMMENT,
|
||||||
'S': S},
|
'S': S},
|
||||||
new=new)
|
new=new)
|
||||||
wellformed = wellformed and new['wellformed']
|
wellformed = wellformed and new['wellformed']
|
||||||
newselector = new['selector']
|
|
||||||
|
|
||||||
# post conditions
|
# post conditions
|
||||||
if expected == 'ident':
|
if expected == 'ident':
|
||||||
@ -135,33 +138,30 @@ class CSSPageRule(cssrule.CSSRule):
|
|||||||
u'CSSPageRule selectorText: No valid selector: %r' %
|
u'CSSPageRule selectorText: No valid selector: %r' %
|
||||||
self._valuestr(selectorText))
|
self._valuestr(selectorText))
|
||||||
|
|
||||||
if not newselector in (None, u':first', u':left', u':right'):
|
# if not newselector in (None, u':first', u':left', u':right'):
|
||||||
self._log.warn(u'CSSPageRule: Unknown CSS 2.1 @page selector: %r' %
|
# self._log.warn(u'CSSPageRule: Unknown CSS 2.1 @page selector: %r' %
|
||||||
newselector, neverraise=True)
|
# newselector, neverraise=True)
|
||||||
|
|
||||||
return newselector, newseq
|
return wellformed, newseq
|
||||||
|
|
||||||
def _getCssText(self):
|
def _getCssText(self):
|
||||||
"""
|
"""Return serialized property cssText."""
|
||||||
returns serialized property cssText
|
|
||||||
"""
|
|
||||||
return cssutils.ser.do_CSSPageRule(self)
|
return cssutils.ser.do_CSSPageRule(self)
|
||||||
|
|
||||||
def _setCssText(self, cssText):
|
def _setCssText(self, cssText):
|
||||||
"""
|
"""
|
||||||
DOMException on setting
|
:exceptions:
|
||||||
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
- SYNTAX_ERR: (self, StyleDeclaration)
|
Raised if the specified CSS string value has a syntax error and
|
||||||
Raised if the specified CSS string value has a syntax error and
|
is unparsable.
|
||||||
is unparsable.
|
- :exc:`~xml.dom.InvalidModificationErr`:
|
||||||
- INVALID_MODIFICATION_ERR: (self)
|
Raised if the specified CSS string value represents a different
|
||||||
Raised if the specified CSS string value represents a different
|
type of rule than the current one.
|
||||||
type of rule than the current one.
|
- :exc:`~xml.dom.HierarchyRequestErr`:
|
||||||
- HIERARCHY_REQUEST_ERR: (CSSStylesheet)
|
Raised if the rule cannot be inserted at this point in the
|
||||||
Raised if the rule cannot be inserted at this point in the
|
style sheet.
|
||||||
style sheet.
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
- NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
|
Raised if the rule is readonly.
|
||||||
Raised if the rule is readonly.
|
|
||||||
"""
|
"""
|
||||||
super(CSSPageRule, self)._setCssText(cssText)
|
super(CSSPageRule, self)._setCssText(cssText)
|
||||||
|
|
||||||
@ -190,7 +190,7 @@ class CSSPageRule(cssrule.CSSRule):
|
|||||||
u'CSSPageRule: Trailing content found.', token=nonetoken)
|
u'CSSPageRule: Trailing content found.', token=nonetoken)
|
||||||
|
|
||||||
|
|
||||||
newselector, newselectorseq = self.__parseSelectorText(selectortokens)
|
wellformed, newselectorseq = self.__parseSelectorText(selectortokens)
|
||||||
|
|
||||||
newstyle = CSSStyleDeclaration()
|
newstyle = CSSStyleDeclaration()
|
||||||
val, typ = self._tokenvalue(braceorEOFtoken), self._type(braceorEOFtoken)
|
val, typ = self._tokenvalue(braceorEOFtoken), self._type(braceorEOFtoken)
|
||||||
@ -206,63 +206,49 @@ class CSSPageRule(cssrule.CSSRule):
|
|||||||
newstyle.cssText = styletokens
|
newstyle.cssText = styletokens
|
||||||
|
|
||||||
if wellformed:
|
if wellformed:
|
||||||
self._selectorText = newselector # already parsed
|
self._selectorText = newselectorseq # already parsed
|
||||||
self.style = newstyle
|
self.style = newstyle
|
||||||
self._setSeq(newselectorseq) # contains upto style only
|
self._setSeq(newselectorseq) # contains upto style only
|
||||||
|
|
||||||
cssText = property(_getCssText, _setCssText,
|
cssText = property(_getCssText, _setCssText,
|
||||||
doc="(DOM) The parsable textual representation of the rule.")
|
doc="(DOM) The parsable textual representation of this rule.")
|
||||||
|
|
||||||
def _getSelectorText(self):
|
def _getSelectorText(self):
|
||||||
"""
|
"""Wrapper for cssutils Selector object."""
|
||||||
wrapper for cssutils Selector object
|
return cssutils.ser.do_CSSPageRuleSelector(self._selectorText)#self._selectorText
|
||||||
"""
|
|
||||||
return self._selectorText
|
|
||||||
|
|
||||||
def _setSelectorText(self, selectorText):
|
def _setSelectorText(self, selectorText):
|
||||||
"""
|
"""Wrapper for cssutils Selector object.
|
||||||
wrapper for cssutils Selector object
|
|
||||||
|
:param selectorText:
|
||||||
|
DOM String, in CSS 2.1 one of
|
||||||
|
|
||||||
selector: DOM String
|
|
||||||
in CSS 2.1 one of
|
|
||||||
- :first
|
- :first
|
||||||
- :left
|
- :left
|
||||||
- :right
|
- :right
|
||||||
- empty
|
- empty
|
||||||
|
|
||||||
If WS or Comments are included they are ignored here! Only
|
:exceptions:
|
||||||
way to add a comment is via setting ``cssText``
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
|
Raised if the specified CSS string value has a syntax error
|
||||||
DOMException on setting
|
and is unparsable.
|
||||||
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
- SYNTAX_ERR:
|
Raised if this rule is readonly.
|
||||||
Raised if the specified CSS string value has a syntax error
|
|
||||||
and is unparsable.
|
|
||||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
|
||||||
Raised if this rule is readonly.
|
|
||||||
"""
|
"""
|
||||||
self._checkReadonly()
|
self._checkReadonly()
|
||||||
|
|
||||||
# may raise SYNTAX_ERR
|
# may raise SYNTAX_ERR
|
||||||
newselectortext, newseq = self.__parseSelectorText(selectorText)
|
wellformed, newseq = self.__parseSelectorText(selectorText)
|
||||||
|
if wellformed and newseq:
|
||||||
if newselectortext:
|
self._selectorText = newseq
|
||||||
for i, x in enumerate(self.seq):
|
|
||||||
if x == self._selectorText:
|
|
||||||
self.seq[i] = newselectortext
|
|
||||||
self._selectorText = newselectortext
|
|
||||||
|
|
||||||
selectorText = property(_getSelectorText, _setSelectorText,
|
selectorText = property(_getSelectorText, _setSelectorText,
|
||||||
doc="""(DOM) The parsable textual representation of the page selector for the rule.""")
|
doc="""(DOM) The parsable textual representation of the page selector for the rule.""")
|
||||||
|
|
||||||
def _getStyle(self):
|
|
||||||
|
|
||||||
return self._style
|
|
||||||
|
|
||||||
def _setStyle(self, style):
|
def _setStyle(self, style):
|
||||||
"""
|
"""
|
||||||
style
|
:param style:
|
||||||
StyleDeclaration or string
|
a CSSStyleDeclaration or string
|
||||||
"""
|
"""
|
||||||
self._checkReadonly()
|
self._checkReadonly()
|
||||||
|
|
||||||
@ -273,14 +259,14 @@ class CSSPageRule(cssrule.CSSRule):
|
|||||||
# so use seq!
|
# so use seq!
|
||||||
self._style._seq = style.seq
|
self._style._seq = style.seq
|
||||||
|
|
||||||
style = property(_getStyle, _setStyle,
|
style = property(lambda self: self._style, _setStyle,
|
||||||
doc="(DOM) The declaration-block of this rule set.")
|
doc="(DOM) The declaration-block of this rule set, "
|
||||||
|
"a :class:`~cssutils.css.CSSStyleDeclaration`.")
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "cssutils.css.%s(selectorText=%r, style=%r)" % (
|
|
||||||
self.__class__.__name__, self.selectorText, self.style.cssText)
|
|
||||||
|
|
||||||
def __str__(self):
|
type = property(lambda self: self.PAGE_RULE,
|
||||||
return "<cssutils.css.%s object selectorText=%r style=%r at 0x%x>" % (
|
doc="The type of this rule, as defined by a CSSRule "
|
||||||
self.__class__.__name__, self.selectorText, self.style.cssText,
|
"type constant.")
|
||||||
id(self))
|
|
||||||
|
# constant but needed:
|
||||||
|
wellformed = property(lambda self: True)
|
||||||
|
@ -45,264 +45,16 @@ TODO: CSS2Properties DOMImplementation
|
|||||||
string for this extended interface listed in this section is "CSS2"
|
string for this extended interface listed in this section is "CSS2"
|
||||||
and the version is "2.0".
|
and the version is "2.0".
|
||||||
|
|
||||||
|
|
||||||
cssvalues
|
|
||||||
=========
|
|
||||||
contributed by Kevin D. Smith, thanks!
|
|
||||||
|
|
||||||
"cssvalues" is used as a property validator.
|
|
||||||
it is an importable object that contains a dictionary of compiled regular
|
|
||||||
expressions. The keys of this dictionary are all of the valid CSS property
|
|
||||||
names. The values are compiled regular expressions that can be used to
|
|
||||||
validate the values for that property. (Actually, the values are references
|
|
||||||
to the 'match' method of a compiled regular expression, so that they are
|
|
||||||
simply called like functions.)
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
__all__ = ['CSS2Properties', 'cssvalues']
|
__all__ = ['CSS2Properties']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: cssproperties.py 1469 2008-09-15 19:06:00Z cthedot $'
|
__version__ = '$Id: cssproperties.py 1638 2009-01-13 20:39:33Z cthedot $'
|
||||||
|
|
||||||
|
import cssutils.profiles
|
||||||
import re
|
import re
|
||||||
|
|
||||||
"""
|
|
||||||
Define some regular expression fragments that will be used as
|
|
||||||
macros within the CSS property value regular expressions.
|
|
||||||
"""
|
|
||||||
MACROS = {
|
|
||||||
'ident': r'[-]?{nmstart}{nmchar}*',
|
|
||||||
'name': r'{nmchar}+',
|
|
||||||
'nmstart': r'[_a-z]|{nonascii}|{escape}',
|
|
||||||
'nonascii': r'[^\0-\177]',
|
|
||||||
'unicode': r'\\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?',
|
|
||||||
'escape': r'{unicode}|\\[ -~\200-\777]',
|
|
||||||
# 'escape': r'{unicode}|\\[ -~\200-\4177777]',
|
|
||||||
'int': r'[-]?\d+',
|
|
||||||
'nmchar': r'[\w-]|{nonascii}|{escape}',
|
|
||||||
'num': r'[-]?\d+|[-]?\d*\.\d+',
|
|
||||||
'number': r'{num}',
|
|
||||||
'string': r'{string1}|{string2}',
|
|
||||||
'string1': r'"(\\\"|[^\"])*"',
|
|
||||||
'string2': r"'(\\\'|[^\'])*'",
|
|
||||||
'nl': r'\n|\r\n|\r|\f',
|
|
||||||
'w': r'\s*',
|
|
||||||
|
|
||||||
'integer': r'{int}',
|
|
||||||
'length': r'0|{num}(em|ex|px|in|cm|mm|pt|pc)',
|
|
||||||
'angle': r'0|{num}(deg|grad|rad)',
|
|
||||||
'time': r'0|{num}m?s',
|
|
||||||
'frequency': r'0|{num}k?Hz',
|
|
||||||
'color': r'(maroon|red|orange|yellow|olive|purple|fuchsia|white|lime|green|navy|blue|aqua|teal|black|silver|gray|ActiveBorder|ActiveCaption|AppWorkspace|Background|ButtonFace|ButtonHighlight|ButtonShadow|ButtonText|CaptionText|GrayText|Highlight|HighlightText|InactiveBorder|InactiveCaption|InactiveCaptionText|InfoBackground|InfoText|Menu|MenuText|Scrollbar|ThreeDDarkShadow|ThreeDFace|ThreeDHighlight|ThreeDLightShadow|ThreeDShadow|Window|WindowFrame|WindowText)|#[0-9a-f]{3}|#[0-9a-f]{6}|rgb\({w}{int}{w},{w}{int}{w},{w}{int}{w}\)|rgb\({w}{num}%{w},{w}{num}%{w},{w}{num}%{w}\)',
|
|
||||||
'uri': r'url\({w}({string}|(\\\)|[^\)])+){w}\)',
|
|
||||||
'percentage': r'{num}%',
|
|
||||||
'border-style': 'none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset',
|
|
||||||
'border-color': '{color}',
|
|
||||||
'border-width': '{length}|thin|medium|thick',
|
|
||||||
|
|
||||||
'background-color': r'{color}|transparent|inherit',
|
|
||||||
'background-image': r'{uri}|none|inherit',
|
|
||||||
'background-position': r'({percentage}|{length})(\s*({percentage}|{length}))?|((top|center|bottom)\s*(left|center|right))|((left|center|right)\s*(top|center|bottom))|inherit',
|
|
||||||
'background-repeat': r'repeat|repeat-x|repeat-y|no-repeat|inherit',
|
|
||||||
'background-attachment': r'scroll|fixed|inherit',
|
|
||||||
|
|
||||||
'shape': r'rect\(({w}({length}|auto}){w},){3}{w}({length}|auto){w}\)',
|
|
||||||
'counter': r'counter\({w}{identifier}{w}(?:,{w}{list-style-type}{w})?\)',
|
|
||||||
'identifier': r'{ident}',
|
|
||||||
'family-name': r'{string}|{identifier}',
|
|
||||||
'generic-family': r'serif|sans-serif|cursive|fantasy|monospace',
|
|
||||||
'absolute-size': r'(x?x-)?(small|large)|medium',
|
|
||||||
'relative-size': r'smaller|larger',
|
|
||||||
'font-family': r'(({family-name}|{generic-family}){w},{w})*({family-name}|{generic-family})|inherit',
|
|
||||||
'font-size': r'{absolute-size}|{relative-size}|{length}|{percentage}|inherit',
|
|
||||||
'font-style': r'normal|italic|oblique|inherit',
|
|
||||||
'font-variant': r'normal|small-caps|inherit',
|
|
||||||
'font-weight': r'normal|bold|bolder|lighter|[1-9]00|inherit',
|
|
||||||
'line-height': r'normal|{number}|{length}|{percentage}|inherit',
|
|
||||||
'list-style-image': r'{uri}|none|inherit',
|
|
||||||
'list-style-position': r'inside|outside|inherit',
|
|
||||||
'list-style-type': r'disc|circle|square|decimal|decimal-leading-zero|lower-roman|upper-roman|lower-greek|lower-(latin|alpha)|upper-(latin|alpha)|armenian|georgian|none|inherit',
|
|
||||||
'margin-width': r'{length}|{percentage}|auto',
|
|
||||||
'outline-color': r'{color}|invert|inherit',
|
|
||||||
'outline-style': r'{border-style}|inherit',
|
|
||||||
'outline-width': r'{border-width}|inherit',
|
|
||||||
'padding-width': r'{length}|{percentage}',
|
|
||||||
'specific-voice': r'{identifier}',
|
|
||||||
'generic-voice': r'male|female|child',
|
|
||||||
'content': r'{string}|{uri}|{counter}|attr\({w}{identifier}{w}\)|open-quote|close-quote|no-open-quote|no-close-quote',
|
|
||||||
'border-attrs': r'{border-width}|{border-style}|{border-color}',
|
|
||||||
'background-attrs': r'{background-color}|{background-image}|{background-repeat}|{background-attachment}|{background-position}',
|
|
||||||
'list-attrs': r'{list-style-type}|{list-style-position}|{list-style-image}',
|
|
||||||
'font-attrs': r'{font-style}|{font-variant}|{font-weight}',
|
|
||||||
'outline-attrs': r'{outline-color}|{outline-style}|{outline-width}',
|
|
||||||
'text-attrs': r'underline|overline|line-through|blink',
|
|
||||||
}
|
|
||||||
|
|
||||||
"""
|
|
||||||
Define the regular expressions for validation all CSS values
|
|
||||||
"""
|
|
||||||
cssvalues = {
|
|
||||||
'azimuth': r'{angle}|(behind\s+)?(left-side|far-left|left|center-left|center|center-right|right|far-right|right-side)(\s+behind)?|behind|leftwards|rightwards|inherit',
|
|
||||||
'background-attachment': r'{background-attachment}',
|
|
||||||
'background-color': r'{background-color}',
|
|
||||||
'background-image': r'{background-image}',
|
|
||||||
'background-position': r'{background-position}',
|
|
||||||
'background-repeat': r'{background-repeat}',
|
|
||||||
# Each piece should only be allowed one time
|
|
||||||
'background': r'{background-attrs}(\s+{background-attrs})*|inherit',
|
|
||||||
'border-collapse': r'collapse|separate|inherit',
|
|
||||||
'border-color': r'({border-color}|transparent)(\s+({border-color}|transparent)){0,3}|inherit',
|
|
||||||
'border-spacing': r'{length}(\s+{length})?|inherit',
|
|
||||||
'border-style': r'{border-style}(\s+{border-style}){0,3}|inherit',
|
|
||||||
'border-top': r'{border-attrs}(\s+{border-attrs})*|inherit',
|
|
||||||
'border-right': r'{border-attrs}(\s+{border-attrs})*|inherit',
|
|
||||||
'border-bottom': r'{border-attrs}(\s+{border-attrs})*|inherit',
|
|
||||||
'border-left': r'{border-attrs}(\s+{border-attrs})*|inherit',
|
|
||||||
'border-top-color': r'{border-color}|transparent|inherit',
|
|
||||||
'border-right-color': r'{border-color}|transparent|inherit',
|
|
||||||
'border-bottom-color': r'{border-color}|transparent|inherit',
|
|
||||||
'border-left-color': r'{border-color}|transparent|inherit',
|
|
||||||
'border-top-style': r'{border-style}|inherit',
|
|
||||||
'border-right-style': r'{border-style}|inherit',
|
|
||||||
'border-bottom-style': r'{border-style}|inherit',
|
|
||||||
'border-left-style': r'{border-style}|inherit',
|
|
||||||
'border-top-width': r'{border-width}|inherit',
|
|
||||||
'border-right-width': r'{border-width}|inherit',
|
|
||||||
'border-bottom-width': r'{border-width}|inherit',
|
|
||||||
'border-left-width': r'{border-width}|inherit',
|
|
||||||
'border-width': r'{border-width}(\s+{border-width}){0,3}|inherit',
|
|
||||||
'border': r'{border-attrs}(\s+{border-attrs})*|inherit',
|
|
||||||
'bottom': r'{length}|{percentage}|auto|inherit',
|
|
||||||
'caption-side': r'top|bottom|inherit',
|
|
||||||
'clear': r'none|left|right|both|inherit',
|
|
||||||
'clip': r'{shape}|auto|inherit',
|
|
||||||
'color': r'{color}|inherit',
|
|
||||||
'content': r'normal|{content}(\s+{content})*|inherit',
|
|
||||||
'counter-increment': r'({identifier}(\s+{integer})?)(\s+({identifier}(\s+{integer})))*|none|inherit',
|
|
||||||
'counter-reset': r'({identifier}(\s+{integer})?)(\s+({identifier}(\s+{integer})))*|none|inherit',
|
|
||||||
'cue-after': r'{uri}|none|inherit',
|
|
||||||
'cue-before': r'{uri}|none|inherit',
|
|
||||||
'cue': r'({uri}|none|inherit){1,2}|inherit',
|
|
||||||
'cursor': r'((({uri}{w},{w})*)?(auto|crosshair|default|pointer|move|(e|ne|nw|n|se|sw|s|w)-resize|text|wait|help|progress))|inherit',
|
|
||||||
'direction': r'ltr|rtl|inherit',
|
|
||||||
'display': r'inline|block|list-item|run-in|inline-block|table|inline-table|table-row-group|table-header-group|table-footer-group|table-row|table-column-group|table-column|table-cell|table-caption|none|inherit',
|
|
||||||
'elevation': r'{angle}|below|level|above|higher|lower|inherit',
|
|
||||||
'empty-cells': r'show|hide|inherit',
|
|
||||||
'float': r'left|right|none|inherit',
|
|
||||||
'font-family': r'{font-family}',
|
|
||||||
'font-size': r'{font-size}',
|
|
||||||
'font-style': r'{font-style}',
|
|
||||||
'font-variant': r'{font-variant}',
|
|
||||||
'font-weight': r'{font-weight}',
|
|
||||||
'font': r'({font-attrs}\s+)*{font-size}({w}/{w}{line-height})?\s+{font-family}|caption|icon|menu|message-box|small-caption|status-bar|inherit',
|
|
||||||
'height': r'{length}|{percentage}|auto|inherit',
|
|
||||||
'left': r'{length}|{percentage}|auto|inherit',
|
|
||||||
'letter-spacing': r'normal|{length}|inherit',
|
|
||||||
'line-height': r'{line-height}',
|
|
||||||
'list-style-image': r'{list-style-image}',
|
|
||||||
'list-style-position': r'{list-style-position}',
|
|
||||||
'list-style-type': r'{list-style-type}',
|
|
||||||
'list-style': r'{list-attrs}(\s+{list-attrs})*|inherit',
|
|
||||||
'margin-right': r'{margin-width}|inherit',
|
|
||||||
'margin-left': r'{margin-width}|inherit',
|
|
||||||
'margin-top': r'{margin-width}|inherit',
|
|
||||||
'margin-bottom': r'{margin-width}|inherit',
|
|
||||||
'margin': r'{margin-width}(\s+{margin-width}){0,3}|inherit',
|
|
||||||
'max-height': r'{length}|{percentage}|none|inherit',
|
|
||||||
'max-width': r'{length}|{percentage}|none|inherit',
|
|
||||||
'min-height': r'{length}|{percentage}|none|inherit',
|
|
||||||
'min-width': r'{length}|{percentage}|none|inherit',
|
|
||||||
'orphans': r'{integer}|inherit',
|
|
||||||
'outline-color': r'{outline-color}',
|
|
||||||
'outline-style': r'{outline-style}',
|
|
||||||
'outline-width': r'{outline-width}',
|
|
||||||
'outline': r'{outline-attrs}(\s+{outline-attrs})*|inherit',
|
|
||||||
'overflow': r'visible|hidden|scroll|auto|inherit',
|
|
||||||
'padding-top': r'{padding-width}|inherit',
|
|
||||||
'padding-right': r'{padding-width}|inherit',
|
|
||||||
'padding-bottom': r'{padding-width}|inherit',
|
|
||||||
'padding-left': r'{padding-width}|inherit',
|
|
||||||
'padding': r'{padding-width}(\s+{padding-width}){0,3}|inherit',
|
|
||||||
'page-break-after': r'auto|always|avoid|left|right|inherit',
|
|
||||||
'page-break-before': r'auto|always|avoid|left|right|inherit',
|
|
||||||
'page-break-inside': r'avoid|auto|inherit',
|
|
||||||
'pause-after': r'{time}|{percentage}|inherit',
|
|
||||||
'pause-before': r'{time}|{percentage}|inherit',
|
|
||||||
'pause': r'({time}|{percentage}){1,2}|inherit',
|
|
||||||
'pitch-range': r'{number}|inherit',
|
|
||||||
'pitch': r'{frequency}|x-low|low|medium|high|x-high|inherit',
|
|
||||||
'play-during': r'{uri}(\s+(mix|repeat))*|auto|none|inherit',
|
|
||||||
'position': r'static|relative|absolute|fixed|inherit',
|
|
||||||
'quotes': r'({string}\s+{string})(\s+{string}\s+{string})*|none|inherit',
|
|
||||||
'richness': r'{number}|inherit',
|
|
||||||
'right': r'{length}|{percentage}|auto|inherit',
|
|
||||||
'speak-header': r'once|always|inherit',
|
|
||||||
'speak-numeral': r'digits|continuous|inherit',
|
|
||||||
'speak-punctuation': r'code|none|inherit',
|
|
||||||
'speak': r'normal|none|spell-out|inherit',
|
|
||||||
'speech-rate': r'{number}|x-slow|slow|medium|fast|x-fast|faster|slower|inherit',
|
|
||||||
'stress': r'{number}|inherit',
|
|
||||||
'table-layout': r'auto|fixed|inherit',
|
|
||||||
'text-align': r'left|right|center|justify|inherit',
|
|
||||||
'text-decoration': r'none|{text-attrs}(\s+{text-attrs})*|inherit',
|
|
||||||
'text-indent': r'{length}|{percentage}|inherit',
|
|
||||||
'text-transform': r'capitalize|uppercase|lowercase|none|inherit',
|
|
||||||
'top': r'{length}|{percentage}|auto|inherit',
|
|
||||||
'unicode-bidi': r'normal|embed|bidi-override|inherit',
|
|
||||||
'vertical-align': r'baseline|sub|super|top|text-top|middle|bottom|text-bottom|{percentage}|{length}|inherit',
|
|
||||||
'visibility': r'visible|hidden|collapse|inherit',
|
|
||||||
'voice-family': r'({specific-voice}|{generic-voice}{w},{w})*({specific-voice}|{generic-voice})|inherit',
|
|
||||||
'volume': r'{number}|{percentage}|silent|x-soft|soft|medium|loud|x-loud|inherit',
|
|
||||||
'white-space': r'normal|pre|nowrap|pre-wrap|pre-line|inherit',
|
|
||||||
'widows': r'{integer}|inherit',
|
|
||||||
'width': r'{length}|{percentage}|auto|inherit',
|
|
||||||
'word-spacing': r'normal|{length}|inherit',
|
|
||||||
'z-index': r'auto|{integer}|inherit',
|
|
||||||
}
|
|
||||||
|
|
||||||
def _expand_macros(tokdict):
|
|
||||||
""" Expand macros in token dictionary """
|
|
||||||
def macro_value(m):
|
|
||||||
return '(?:%s)' % MACROS[m.groupdict()['macro']]
|
|
||||||
for key, value in tokdict.items():
|
|
||||||
while re.search(r'{[a-z][a-z0-9-]*}', value):
|
|
||||||
value = re.sub(r'{(?P<macro>[a-z][a-z0-9-]*)}',
|
|
||||||
macro_value, value)
|
|
||||||
tokdict[key] = value
|
|
||||||
return tokdict
|
|
||||||
|
|
||||||
def _compile_regexes(tokdict):
|
|
||||||
""" Compile all regular expressions into callable objects """
|
|
||||||
for key, value in tokdict.items():
|
|
||||||
tokdict[key] = re.compile('^(?:%s)$' % value, re.I).match
|
|
||||||
return tokdict
|
|
||||||
|
|
||||||
_compile_regexes(_expand_macros(cssvalues))
|
|
||||||
|
|
||||||
|
|
||||||
# functions to convert between CSS and DOM name
|
|
||||||
|
|
||||||
_reCSStoDOMname = re.compile('-[a-z]', re.I)
|
|
||||||
def _toDOMname(CSSname):
|
|
||||||
"""
|
|
||||||
returns DOMname for given CSSname e.g. for CSSname 'font-style' returns
|
|
||||||
'fontStyle'
|
|
||||||
"""
|
|
||||||
def _doCSStoDOMname2(m): return m.group(0)[1].capitalize()
|
|
||||||
return _reCSStoDOMname.sub(_doCSStoDOMname2, CSSname)
|
|
||||||
|
|
||||||
_reDOMtoCSSname = re.compile('([A-Z])[a-z]+')
|
|
||||||
def _toCSSname(DOMname):
|
|
||||||
"""
|
|
||||||
returns CSSname for given DOMname e.g. for DOMname 'fontStyle' returns
|
|
||||||
'font-style'
|
|
||||||
"""
|
|
||||||
def _doDOMtoCSSname2(m): return '-' + m.group(0).lower()
|
|
||||||
return _reDOMtoCSSname.sub(_doDOMtoCSSname2, DOMname)
|
|
||||||
|
|
||||||
|
|
||||||
class CSS2Properties(object):
|
class CSS2Properties(object):
|
||||||
"""
|
"""The CSS2Properties interface represents a convenience mechanism
|
||||||
The CSS2Properties interface represents a convenience mechanism
|
|
||||||
for retrieving and setting properties within a CSSStyleDeclaration.
|
for retrieving and setting properties within a CSSStyleDeclaration.
|
||||||
The attributes of this interface correspond to all the properties
|
The attributes of this interface correspond to all the properties
|
||||||
specified in CSS2. Getting an attribute of this interface is
|
specified in CSS2. Getting an attribute of this interface is
|
||||||
@ -326,16 +78,37 @@ class CSS2Properties(object):
|
|||||||
def _setP(self, CSSname, value): pass
|
def _setP(self, CSSname, value): pass
|
||||||
def _delP(self, CSSname): pass
|
def _delP(self, CSSname): pass
|
||||||
|
|
||||||
|
|
||||||
|
_reCSStoDOMname = re.compile('-[a-z]', re.I)
|
||||||
|
def _toDOMname(CSSname):
|
||||||
|
"""Returns DOMname for given CSSname e.g. for CSSname 'font-style' returns
|
||||||
|
'fontStyle'.
|
||||||
|
"""
|
||||||
|
def _doCSStoDOMname2(m): return m.group(0)[1].capitalize()
|
||||||
|
return _reCSStoDOMname.sub(_doCSStoDOMname2, CSSname)
|
||||||
|
|
||||||
|
_reDOMtoCSSname = re.compile('([A-Z])[a-z]+')
|
||||||
|
def _toCSSname(DOMname):
|
||||||
|
"""Return CSSname for given DOMname e.g. for DOMname 'fontStyle' returns
|
||||||
|
'font-style'.
|
||||||
|
"""
|
||||||
|
def _doDOMtoCSSname2(m): return '-' + m.group(0).lower()
|
||||||
|
return _reDOMtoCSSname.sub(_doDOMtoCSSname2, DOMname)
|
||||||
|
|
||||||
# add list of DOMname properties to CSS2Properties
|
# add list of DOMname properties to CSS2Properties
|
||||||
# used for CSSStyleDeclaration to check if allowed properties
|
# used for CSSStyleDeclaration to check if allowed properties
|
||||||
# but somehow doubled, any better way?
|
# but somehow doubled, any better way?
|
||||||
CSS2Properties._properties = [_toDOMname(p) for p in cssvalues.keys()]
|
CSS2Properties._properties = []
|
||||||
|
for group in cssutils.profiles.properties:
|
||||||
|
for name in cssutils.profiles.properties[group]:
|
||||||
|
CSS2Properties._properties.append(_toDOMname(name))
|
||||||
|
|
||||||
|
|
||||||
# add CSS2Properties to CSSStyleDeclaration:
|
# add CSS2Properties to CSSStyleDeclaration:
|
||||||
def __named_property_def(DOMname):
|
def __named_property_def(DOMname):
|
||||||
"""
|
"""
|
||||||
closure to keep name known in each properties accessor function
|
Closure to keep name known in each properties accessor function
|
||||||
DOMname is converted to CSSname here, so actual calls use CSSname
|
DOMname is converted to CSSname here, so actual calls use CSSname.
|
||||||
"""
|
"""
|
||||||
CSSname = _toCSSname(DOMname)
|
CSSname = _toCSSname(DOMname)
|
||||||
def _get(self): return self._getP(CSSname)
|
def _get(self): return self._getP(CSSname)
|
||||||
|
@ -1,46 +1,17 @@
|
|||||||
"""CSSRule implements DOM Level 2 CSS CSSRule."""
|
"""CSSRule implements DOM Level 2 CSS CSSRule."""
|
||||||
__all__ = ['CSSRule']
|
__all__ = ['CSSRule']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: cssrule.py 1177 2008-03-20 17:47:23Z cthedot $'
|
__version__ = '$Id: cssrule.py 1638 2009-01-13 20:39:33Z cthedot $'
|
||||||
|
|
||||||
import xml.dom
|
|
||||||
import cssutils
|
import cssutils
|
||||||
|
import xml.dom
|
||||||
|
|
||||||
class CSSRule(cssutils.util.Base2):
|
class CSSRule(cssutils.util.Base2):
|
||||||
"""
|
"""Abstract base interface for any type of CSS statement. This includes
|
||||||
Abstract base interface for any type of CSS statement. This includes
|
|
||||||
both rule sets and at-rules. An implementation is expected to preserve
|
both rule sets and at-rules. An implementation is expected to preserve
|
||||||
all rules specified in a CSS style sheet, even if the rule is not
|
all rules specified in a CSS style sheet, even if the rule is not
|
||||||
recognized by the parser. Unrecognized rules are represented using the
|
recognized by the parser. Unrecognized rules are represented using the
|
||||||
CSSUnknownRule interface.
|
:class:`CSSUnknownRule` interface.
|
||||||
|
|
||||||
Properties
|
|
||||||
==========
|
|
||||||
cssText: of type DOMString
|
|
||||||
The parsable textual representation of the rule. This reflects the
|
|
||||||
current state of the rule and not its initial value.
|
|
||||||
parentRule: of type CSSRule, readonly
|
|
||||||
If this rule is contained inside another rule (e.g. a style rule
|
|
||||||
inside an @media block), this is the containing rule. If this rule
|
|
||||||
is not nested inside any other rules, this returns None.
|
|
||||||
parentStyleSheet: of type CSSStyleSheet, readonly
|
|
||||||
The style sheet that contains this rule.
|
|
||||||
type: of type unsigned short, readonly
|
|
||||||
The type of the rule, as defined above. The expectation is that
|
|
||||||
binding-specific casting methods can be used to cast down from an
|
|
||||||
instance of the CSSRule interface to the specific derived interface
|
|
||||||
implied by the type.
|
|
||||||
|
|
||||||
cssutils only
|
|
||||||
-------------
|
|
||||||
seq (READONLY):
|
|
||||||
contains sequence of parts of the rule including comments but
|
|
||||||
excluding @KEYWORD and braces
|
|
||||||
typeString: string
|
|
||||||
A string name of the type of this rule, e.g. 'STYLE_RULE'. Mainly
|
|
||||||
useful for debugging
|
|
||||||
wellformed:
|
|
||||||
if a rule is valid
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -61,21 +32,8 @@ class CSSRule(cssutils.util.Base2):
|
|||||||
'MEDIA_RULE', 'FONT_FACE_RULE', 'PAGE_RULE', 'NAMESPACE_RULE',
|
'MEDIA_RULE', 'FONT_FACE_RULE', 'PAGE_RULE', 'NAMESPACE_RULE',
|
||||||
'COMMENT']
|
'COMMENT']
|
||||||
|
|
||||||
type = UNKNOWN_RULE
|
|
||||||
"""
|
|
||||||
The type of this rule, as defined by a CSSRule type constant.
|
|
||||||
Overwritten in derived classes.
|
|
||||||
|
|
||||||
The expectation is that binding-specific casting methods can be used to
|
|
||||||
cast down from an instance of the CSSRule interface to the specific
|
|
||||||
derived interface implied by the type.
|
|
||||||
(Casting not for this Python implementation I guess...)
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, parentRule=None, parentStyleSheet=None, readonly=False):
|
def __init__(self, parentRule=None, parentStyleSheet=None, readonly=False):
|
||||||
"""
|
"""Set common attributes for all rules."""
|
||||||
set common attributes for all rules
|
|
||||||
"""
|
|
||||||
super(CSSRule, self).__init__()
|
super(CSSRule, self).__init__()
|
||||||
self._parentRule = parentRule
|
self._parentRule = parentRule
|
||||||
self._parentStyleSheet = parentStyleSheet
|
self._parentStyleSheet = parentStyleSheet
|
||||||
@ -83,33 +41,8 @@ class CSSRule(cssutils.util.Base2):
|
|||||||
# must be set after initialization of #inheriting rule is done
|
# must be set after initialization of #inheriting rule is done
|
||||||
self._readonly = False
|
self._readonly = False
|
||||||
|
|
||||||
def _setCssText(self, cssText):
|
|
||||||
"""
|
|
||||||
DOMException on setting
|
|
||||||
|
|
||||||
- SYNTAX_ERR:
|
|
||||||
Raised if the specified CSS string value has a syntax error and
|
|
||||||
is unparsable.
|
|
||||||
- INVALID_MODIFICATION_ERR:
|
|
||||||
Raised if the specified CSS string value represents a different
|
|
||||||
type of rule than the current one.
|
|
||||||
- HIERARCHY_REQUEST_ERR:
|
|
||||||
Raised if the rule cannot be inserted at this point in the
|
|
||||||
style sheet.
|
|
||||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
|
||||||
Raised if the rule is readonly.
|
|
||||||
"""
|
|
||||||
self._checkReadonly()
|
|
||||||
|
|
||||||
cssText = property(lambda self: u'', _setCssText,
|
|
||||||
doc="""(DOM) The parsable textual representation of the rule. This
|
|
||||||
reflects the current state of the rule and not its initial value.
|
|
||||||
The initial value is saved, but this may be removed in a future
|
|
||||||
version!
|
|
||||||
MUST BE OVERWRITTEN IN SUBCLASS TO WORK!""")
|
|
||||||
|
|
||||||
def _setAtkeyword(self, akw):
|
def _setAtkeyword(self, akw):
|
||||||
"""checks if new keyword is normalized same as old"""
|
"""Check if new keyword fits the rule it is used for."""
|
||||||
if not self.atkeyword or (self._normalize(akw) ==
|
if not self.atkeyword or (self._normalize(akw) ==
|
||||||
self._normalize(self.atkeyword)):
|
self._normalize(self.atkeyword)):
|
||||||
self._atkeyword = akw
|
self._atkeyword = akw
|
||||||
@ -119,16 +52,48 @@ class CSSRule(cssutils.util.Base2):
|
|||||||
error=xml.dom.InvalidModificationErr)
|
error=xml.dom.InvalidModificationErr)
|
||||||
|
|
||||||
atkeyword = property(lambda self: self._atkeyword, _setAtkeyword,
|
atkeyword = property(lambda self: self._atkeyword, _setAtkeyword,
|
||||||
doc=u"@keyword for @rules")
|
doc=u"Literal keyword of an @rule (e.g. ``@IMport``).")
|
||||||
|
|
||||||
|
def _setCssText(self, cssText):
|
||||||
|
"""
|
||||||
|
:param cssText:
|
||||||
|
A parsable DOMString.
|
||||||
|
:exceptions:
|
||||||
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
|
Raised if the specified CSS string value has a syntax error and
|
||||||
|
is unparsable.
|
||||||
|
- :exc:`~xml.dom.InvalidModificationErr`:
|
||||||
|
Raised if the specified CSS string value represents a different
|
||||||
|
type of rule than the current one.
|
||||||
|
- :exc:`~xml.dom.HierarchyRequestErr`:
|
||||||
|
Raised if the rule cannot be inserted at this point in the
|
||||||
|
style sheet.
|
||||||
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
|
Raised if the rule is readonly.
|
||||||
|
"""
|
||||||
|
self._checkReadonly()
|
||||||
|
|
||||||
|
cssText = property(lambda self: u'', _setCssText,
|
||||||
|
doc="(DOM) The parsable textual representation of the "
|
||||||
|
"rule. This reflects the current state of the rule "
|
||||||
|
"and not its initial value.")
|
||||||
|
|
||||||
parentRule = property(lambda self: self._parentRule,
|
parentRule = property(lambda self: self._parentRule,
|
||||||
doc=u"READONLY")
|
doc="If this rule is contained inside "
|
||||||
|
"another rule (e.g. a style rule inside "
|
||||||
|
"an @media block), this is the containing "
|
||||||
|
"rule. If this rule is not nested inside "
|
||||||
|
"any other rules, this returns None.")
|
||||||
|
|
||||||
parentStyleSheet = property(lambda self: self._parentStyleSheet,
|
parentStyleSheet = property(lambda self: self._parentStyleSheet,
|
||||||
doc=u"READONLY")
|
doc="The style sheet that contains this rule.")
|
||||||
|
|
||||||
wellformed = property(lambda self: False,
|
type = property(lambda self: self.UNKNOWN_RULE,
|
||||||
doc=u"READONLY")
|
doc="The type of this rule, as defined by a CSSRule "
|
||||||
|
"type constant.")
|
||||||
|
|
||||||
typeString = property(lambda self: CSSRule._typestrings[self.type],
|
typeString = property(lambda self: CSSRule._typestrings[self.type],
|
||||||
doc="Name of this rules type.")
|
doc="Descriptive name of this rule's type.")
|
||||||
|
|
||||||
|
wellformed = property(lambda self: False,
|
||||||
|
doc=u"If the rule is wellformed.")
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
"""
|
"""CSSRuleList implements DOM Level 2 CSS CSSRuleList.
|
||||||
CSSRuleList implements DOM Level 2 CSS CSSRuleList.
|
Partly also http://dev.w3.org/csswg/cssom/#the-cssrulelist
|
||||||
|
|
||||||
Partly also
|
|
||||||
* http://dev.w3.org/csswg/cssom/#the-cssrulelist
|
|
||||||
"""
|
"""
|
||||||
__all__ = ['CSSRuleList']
|
__all__ = ['CSSRuleList']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: cssrulelist.py 1116 2008-03-05 13:52:23Z cthedot $'
|
__version__ = '$Id: cssrulelist.py 1641 2009-01-13 21:05:37Z cthedot $'
|
||||||
|
|
||||||
class CSSRuleList(list):
|
class CSSRuleList(list):
|
||||||
"""
|
"""The CSSRuleList object represents an (ordered) list of statements.
|
||||||
The CSSRuleList object represents an (ordered) list of statements.
|
|
||||||
|
|
||||||
The items in the CSSRuleList are accessible via an integral index,
|
The items in the CSSRuleList are accessible via an integral index,
|
||||||
starting from 0.
|
starting from 0.
|
||||||
@ -21,28 +17,20 @@ class CSSRuleList(list):
|
|||||||
class if so desired.
|
class if so desired.
|
||||||
E.g. CSSStyleSheet adds ``append`` which is not available in a simple
|
E.g. CSSStyleSheet adds ``append`` which is not available in a simple
|
||||||
instance of this class!
|
instance of this class!
|
||||||
|
|
||||||
Properties
|
|
||||||
==========
|
|
||||||
length: of type unsigned long, readonly
|
|
||||||
The number of CSSRules in the list. The range of valid child rule
|
|
||||||
indices is 0 to length-1 inclusive.
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, *ignored):
|
def __init__(self, *ignored):
|
||||||
"nothing is set as this must also be defined later"
|
"Nothing is set as this must also be defined later."
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __notimplemented(self, *ignored):
|
def __notimplemented(self, *ignored):
|
||||||
"no direct setting possible"
|
"Implemented in class using a CSSRuleList only."
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
'Must be implemented by class using an instance of this class.')
|
'Must be implemented by class using an instance of this class.')
|
||||||
|
|
||||||
append = extend = __setitem__ = __setslice__ = __notimplemented
|
append = extend = __setitem__ = __setslice__ = __notimplemented
|
||||||
|
|
||||||
def item(self, index):
|
def item(self, index):
|
||||||
"""
|
"""(DOM) Retrieve a CSS rule by ordinal `index`. The order in this
|
||||||
(DOM)
|
|
||||||
Used to retrieve a CSS rule by ordinal index. The order in this
|
|
||||||
collection represents the order of the rules in the CSS style
|
collection represents the order of the rules in the CSS style
|
||||||
sheet. If index is greater than or equal to the number of rules in
|
sheet. If index is greater than or equal to the number of rules in
|
||||||
the list, this returns None.
|
the list, this returns None.
|
||||||
|
@ -51,16 +51,15 @@ TODO:
|
|||||||
"""
|
"""
|
||||||
__all__ = ['CSSStyleDeclaration', 'Property']
|
__all__ = ['CSSStyleDeclaration', 'Property']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: cssstyledeclaration.py 1284 2008-06-05 16:29:17Z cthedot $'
|
__version__ = '$Id: cssstyledeclaration.py 1658 2009-02-07 18:24:40Z cthedot $'
|
||||||
|
|
||||||
import xml.dom
|
|
||||||
import cssutils
|
|
||||||
from cssproperties import CSS2Properties
|
from cssproperties import CSS2Properties
|
||||||
from property import Property
|
from property import Property
|
||||||
|
import cssutils
|
||||||
|
import xml.dom
|
||||||
|
|
||||||
class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
||||||
"""
|
"""The CSSStyleDeclaration class represents a single CSS declaration
|
||||||
The CSSStyleDeclaration class represents a single CSS declaration
|
|
||||||
block. This class may be used to determine the style properties
|
block. This class may be used to determine the style properties
|
||||||
currently set in a block or to set style properties explicitly
|
currently set in a block or to set style properties explicitly
|
||||||
within the block.
|
within the block.
|
||||||
@ -76,24 +75,6 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
|||||||
|
|
||||||
Additionally the CSS2Properties interface is implemented.
|
Additionally the CSS2Properties interface is implemented.
|
||||||
|
|
||||||
Properties
|
|
||||||
==========
|
|
||||||
cssText
|
|
||||||
The parsable textual representation of the declaration block
|
|
||||||
(excluding the surrounding curly braces). Setting this attribute
|
|
||||||
will result in the parsing of the new value and resetting of the
|
|
||||||
properties in the declaration block. It also allows the insertion
|
|
||||||
of additional properties and their values into the block.
|
|
||||||
length: of type unsigned long, readonly
|
|
||||||
The number of properties that have been explicitly set in this
|
|
||||||
declaration block. The range of valid indices is 0 to length-1
|
|
||||||
inclusive.
|
|
||||||
parentRule: of type CSSRule, readonly
|
|
||||||
The CSS rule that contains this declaration block or None if this
|
|
||||||
CSSStyleDeclaration is not attached to a CSSRule.
|
|
||||||
seq: a list (cssutils)
|
|
||||||
All parts of this style declaration including CSSComments
|
|
||||||
|
|
||||||
$css2propertyname
|
$css2propertyname
|
||||||
All properties defined in the CSS2Properties class are available
|
All properties defined in the CSS2Properties class are available
|
||||||
as direct properties of CSSStyleDeclaration with their respective
|
as direct properties of CSSStyleDeclaration with their respective
|
||||||
@ -106,33 +87,32 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
|||||||
>>> print style.color
|
>>> print style.color
|
||||||
green
|
green
|
||||||
>>> del style.color
|
>>> del style.color
|
||||||
>>> print style.color # print empty string
|
>>> print style.color
|
||||||
|
<BLANKLINE>
|
||||||
|
|
||||||
Format
|
Format::
|
||||||
======
|
|
||||||
[Property: Value Priority?;]* [Property: Value Priority?]?
|
[Property: Value Priority?;]* [Property: Value Priority?]?
|
||||||
"""
|
"""
|
||||||
def __init__(self, cssText=u'', parentRule=None, readonly=False):
|
def __init__(self, cssText=u'', parentRule=None, readonly=False):
|
||||||
"""
|
"""
|
||||||
cssText
|
:param cssText:
|
||||||
Shortcut, sets CSSStyleDeclaration.cssText
|
Shortcut, sets CSSStyleDeclaration.cssText
|
||||||
parentRule
|
:param parentRule:
|
||||||
The CSS rule that contains this declaration block or
|
The CSS rule that contains this declaration block or
|
||||||
None if this CSSStyleDeclaration is not attached to a CSSRule.
|
None if this CSSStyleDeclaration is not attached to a CSSRule.
|
||||||
readonly
|
:param readonly:
|
||||||
defaults to False
|
defaults to False
|
||||||
"""
|
"""
|
||||||
super(CSSStyleDeclaration, self).__init__()
|
super(CSSStyleDeclaration, self).__init__()
|
||||||
self._parentRule = parentRule
|
self._parentRule = parentRule
|
||||||
#self._seq = self._tempSeq()
|
|
||||||
self.cssText = cssText
|
self.cssText = cssText
|
||||||
self._readonly = readonly
|
self._readonly = readonly
|
||||||
|
|
||||||
def __contains__(self, nameOrProperty):
|
def __contains__(self, nameOrProperty):
|
||||||
"""
|
"""Check if a property (or a property with given name) is in style.
|
||||||
checks if a property (or a property with given name is in style
|
|
||||||
|
|
||||||
name
|
:param name:
|
||||||
a string or Property, uses normalized name and not literalname
|
a string or Property, uses normalized name and not literalname
|
||||||
"""
|
"""
|
||||||
if isinstance(nameOrProperty, Property):
|
if isinstance(nameOrProperty, Property):
|
||||||
@ -142,47 +122,12 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
|||||||
return name in self.__nnames()
|
return name in self.__nnames()
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
"""
|
"""Iterator of set Property objects with different normalized names."""
|
||||||
iterator of set Property objects with different normalized names.
|
|
||||||
"""
|
|
||||||
def properties():
|
def properties():
|
||||||
for name in self.__nnames():
|
for name in self.__nnames():
|
||||||
yield self.getProperty(name)
|
yield self.getProperty(name)
|
||||||
return properties()
|
return properties()
|
||||||
|
|
||||||
def __setattr__(self, n, v):
|
|
||||||
"""
|
|
||||||
Prevent setting of unknown properties on CSSStyleDeclaration
|
|
||||||
which would not work anyway. For these
|
|
||||||
``CSSStyleDeclaration.setProperty`` MUST be called explicitly!
|
|
||||||
|
|
||||||
TODO:
|
|
||||||
implementation of known is not really nice, any alternative?
|
|
||||||
"""
|
|
||||||
known = ['_tokenizer', '_log', '_ttypes',
|
|
||||||
'_seq', 'seq', 'parentRule', '_parentRule', 'cssText',
|
|
||||||
'valid', 'wellformed',
|
|
||||||
'_readonly']
|
|
||||||
known.extend(CSS2Properties._properties)
|
|
||||||
if n in known:
|
|
||||||
super(CSSStyleDeclaration, self).__setattr__(n, v)
|
|
||||||
else:
|
|
||||||
raise AttributeError(
|
|
||||||
'Unknown CSS Property, ``CSSStyleDeclaration.setProperty("%s", ...)`` MUST be used.'
|
|
||||||
% n)
|
|
||||||
|
|
||||||
def __nnames(self):
|
|
||||||
"""
|
|
||||||
returns iterator for all different names in order as set
|
|
||||||
if names are set twice the last one is used (double reverse!)
|
|
||||||
"""
|
|
||||||
names = []
|
|
||||||
for item in reversed(self.seq):
|
|
||||||
val = item.value
|
|
||||||
if isinstance(val, Property) and not val.name in names:
|
|
||||||
names.append(val.name)
|
|
||||||
return reversed(names)
|
|
||||||
|
|
||||||
def __getitem__(self, CSSName):
|
def __getitem__(self, CSSName):
|
||||||
"""Retrieve the value of property ``CSSName`` from this declaration.
|
"""Retrieve the value of property ``CSSName`` from this declaration.
|
||||||
|
|
||||||
@ -211,11 +156,49 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
|||||||
"""
|
"""
|
||||||
return self.removeProperty(CSSName)
|
return self.removeProperty(CSSName)
|
||||||
|
|
||||||
|
def __setattr__(self, n, v):
|
||||||
|
"""Prevent setting of unknown properties on CSSStyleDeclaration
|
||||||
|
which would not work anyway. For these
|
||||||
|
``CSSStyleDeclaration.setProperty`` MUST be called explicitly!
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
implementation of known is not really nice, any alternative?
|
||||||
|
"""
|
||||||
|
known = ['_tokenizer', '_log', '_ttypes',
|
||||||
|
'_seq', 'seq', 'parentRule', '_parentRule', 'cssText',
|
||||||
|
'valid', 'wellformed',
|
||||||
|
'_readonly', '_profiles']
|
||||||
|
known.extend(CSS2Properties._properties)
|
||||||
|
if n in known:
|
||||||
|
super(CSSStyleDeclaration, self).__setattr__(n, v)
|
||||||
|
else:
|
||||||
|
raise AttributeError(
|
||||||
|
'Unknown CSS Property, ``CSSStyleDeclaration.setProperty("%s", ...)`` MUST be used.'
|
||||||
|
% n)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "cssutils.css.%s(cssText=%r)" % (
|
||||||
|
self.__class__.__name__, self.getCssText(separator=u' '))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "<cssutils.css.%s object length=%r (all: %r) at 0x%x>" % (
|
||||||
|
self.__class__.__name__, self.length,
|
||||||
|
len(self.getProperties(all=True)), id(self))
|
||||||
|
|
||||||
|
def __nnames(self):
|
||||||
|
"""Return iterator for all different names in order as set
|
||||||
|
if names are set twice the last one is used (double reverse!)
|
||||||
|
"""
|
||||||
|
names = []
|
||||||
|
for item in reversed(self.seq):
|
||||||
|
val = item.value
|
||||||
|
if isinstance(val, Property) and not val.name in names:
|
||||||
|
names.append(val.name)
|
||||||
|
return reversed(names)
|
||||||
|
|
||||||
# overwritten accessor functions for CSS2Properties' properties
|
# overwritten accessor functions for CSS2Properties' properties
|
||||||
def _getP(self, CSSName):
|
def _getP(self, CSSName):
|
||||||
"""
|
"""(DOM CSS2Properties) Overwritten here and effectively the same as
|
||||||
(DOM CSS2Properties)
|
|
||||||
Overwritten here and effectively the same as
|
|
||||||
``self.getPropertyValue(CSSname)``.
|
``self.getPropertyValue(CSSname)``.
|
||||||
|
|
||||||
Parameter is in CSSname format ('font-style'), see CSS2Properties.
|
Parameter is in CSSname format ('font-style'), see CSS2Properties.
|
||||||
@ -229,9 +212,7 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
|||||||
return self.getPropertyValue(CSSName)
|
return self.getPropertyValue(CSSName)
|
||||||
|
|
||||||
def _setP(self, CSSName, value):
|
def _setP(self, CSSName, value):
|
||||||
"""
|
"""(DOM CSS2Properties) Overwritten here and effectively the same as
|
||||||
(DOM CSS2Properties)
|
|
||||||
Overwritten here and effectively the same as
|
|
||||||
``self.setProperty(CSSname, value)``.
|
``self.setProperty(CSSname, value)``.
|
||||||
|
|
||||||
Only known CSS2Properties may be set this way, otherwise an
|
Only known CSS2Properties may be set this way, otherwise an
|
||||||
@ -247,44 +228,40 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
|||||||
>>> style.fontStyle = 'italic'
|
>>> style.fontStyle = 'italic'
|
||||||
>>> # or
|
>>> # or
|
||||||
>>> style.setProperty('font-style', 'italic', '!important')
|
>>> style.setProperty('font-style', 'italic', '!important')
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.setProperty(CSSName, value)
|
self.setProperty(CSSName, value)
|
||||||
# TODO: Shorthand ones
|
# TODO: Shorthand ones
|
||||||
|
|
||||||
def _delP(self, CSSName):
|
def _delP(self, CSSName):
|
||||||
"""
|
"""(cssutils only) Overwritten here and effectively the same as
|
||||||
(cssutils only)
|
|
||||||
Overwritten here and effectively the same as
|
|
||||||
``self.removeProperty(CSSname)``.
|
``self.removeProperty(CSSname)``.
|
||||||
|
|
||||||
Example::
|
Example::
|
||||||
|
|
||||||
>>> style = CSSStyleDeclaration(cssText='font-style:italic;')
|
>>> style = CSSStyleDeclaration(cssText='font-style:italic;')
|
||||||
>>> del style.fontStyle
|
>>> del style.fontStyle
|
||||||
>>> print style.fontStyle # prints u''
|
>>> print style.fontStyle
|
||||||
|
<BLANKLINE>
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.removeProperty(CSSName)
|
self.removeProperty(CSSName)
|
||||||
|
|
||||||
def _getCssText(self):
|
def _getCssText(self):
|
||||||
"""
|
"""Return serialized property cssText."""
|
||||||
returns serialized property cssText
|
|
||||||
"""
|
|
||||||
return cssutils.ser.do_css_CSSStyleDeclaration(self)
|
return cssutils.ser.do_css_CSSStyleDeclaration(self)
|
||||||
|
|
||||||
def _setCssText(self, cssText):
|
def _setCssText(self, cssText):
|
||||||
"""
|
"""Setting this attribute will result in the parsing of the new value
|
||||||
Setting this attribute will result in the parsing of the new value
|
|
||||||
and resetting of all the properties in the declaration block
|
and resetting of all the properties in the declaration block
|
||||||
including the removal or addition of properties.
|
including the removal or addition of properties.
|
||||||
|
|
||||||
DOMException on setting
|
:exceptions:
|
||||||
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
Raised if this declaration is readonly or a property is readonly.
|
||||||
Raised if this declaration is readonly or a property is readonly.
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
- SYNTAX_ERR: (self)
|
Raised if the specified CSS string value has a syntax error and
|
||||||
Raised if the specified CSS string value has a syntax error and
|
is unparsable.
|
||||||
is unparsable.
|
|
||||||
"""
|
"""
|
||||||
self._checkReadonly()
|
self._checkReadonly()
|
||||||
tokenizer = self._tokenize2(cssText)
|
tokenizer = self._tokenize2(cssText)
|
||||||
@ -336,11 +313,12 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
|||||||
|
|
||||||
def getCssText(self, separator=None):
|
def getCssText(self, separator=None):
|
||||||
"""
|
"""
|
||||||
returns serialized property cssText, each property separated by
|
:returns:
|
||||||
given ``separator`` which may e.g. be u'' to be able to use
|
serialized property cssText, each property separated by
|
||||||
cssText directly in an HTML style attribute. ";" is always part of
|
given `separator` which may e.g. be ``u''`` to be able to use
|
||||||
each property (except the last one) and can **not** be set with
|
cssText directly in an HTML style attribute. ``;`` is part of
|
||||||
separator!
|
each property (except the last one) and **cannot** be set with
|
||||||
|
separator!
|
||||||
"""
|
"""
|
||||||
return cssutils.ser.do_css_CSSStyleDeclaration(self, separator)
|
return cssutils.ser.do_css_CSSStyleDeclaration(self, separator)
|
||||||
|
|
||||||
@ -351,25 +329,27 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
|||||||
self._parentRule = parentRule
|
self._parentRule = parentRule
|
||||||
|
|
||||||
parentRule = property(_getParentRule, _setParentRule,
|
parentRule = property(_getParentRule, _setParentRule,
|
||||||
doc="(DOM) The CSS rule that contains this declaration block or\
|
doc="(DOM) The CSS rule that contains this declaration block or "
|
||||||
None if this CSSStyleDeclaration is not attached to a CSSRule.")
|
"None if this CSSStyleDeclaration is not attached to a CSSRule.")
|
||||||
|
|
||||||
def getProperties(self, name=None, all=False):
|
def getProperties(self, name=None, all=False):
|
||||||
"""
|
"""
|
||||||
Returns a list of Property objects set in this declaration.
|
:param name:
|
||||||
|
optional `name` of properties which are requested.
|
||||||
|
Only properties with this **always normalized** `name` are returned.
|
||||||
|
If `name` is ``None`` all properties are returned (at least one for
|
||||||
|
each set name depending on parameter `all`).
|
||||||
|
:param all:
|
||||||
|
if ``False`` (DEFAULT) only the effective properties are returned.
|
||||||
|
If name is given a list with only one property is returned.
|
||||||
|
|
||||||
name
|
if ``True`` all properties including properties set multiple times
|
||||||
optional name of properties which are requested (a filter).
|
with different values or priorities for different UAs are returned.
|
||||||
Only properties with this **always normalized** name are returned.
|
|
||||||
all=False
|
|
||||||
if False (DEFAULT) only the effective properties (the ones set
|
|
||||||
last) are returned. If name is given a list with only one property
|
|
||||||
is returned.
|
|
||||||
|
|
||||||
if True all properties including properties set multiple times with
|
|
||||||
different values or priorities for different UAs are returned.
|
|
||||||
The order of the properties is fully kept as in the original
|
The order of the properties is fully kept as in the original
|
||||||
stylesheet.
|
stylesheet.
|
||||||
|
:returns:
|
||||||
|
a list of :class:`~cssutils.css.Property` objects set in
|
||||||
|
this declaration.
|
||||||
"""
|
"""
|
||||||
if name and not all:
|
if name and not all:
|
||||||
# single prop but list
|
# single prop but list
|
||||||
@ -394,16 +374,16 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
|||||||
|
|
||||||
def getProperty(self, name, normalize=True):
|
def getProperty(self, name, normalize=True):
|
||||||
"""
|
"""
|
||||||
Returns the effective Property object.
|
:param name:
|
||||||
|
|
||||||
name
|
|
||||||
of the CSS property, always lowercase (even if not normalized)
|
of the CSS property, always lowercase (even if not normalized)
|
||||||
normalize
|
:param normalize:
|
||||||
if True (DEFAULT) name will be normalized (lowercase, no simple
|
if ``True`` (DEFAULT) name will be normalized (lowercase, no simple
|
||||||
escapes) so "color", "COLOR" or "C\olor" will all be equivalent
|
escapes) so "color", "COLOR" or "C\olor" will all be equivalent
|
||||||
|
|
||||||
If False may return **NOT** the effective value but the effective
|
If ``False`` may return **NOT** the effective value but the
|
||||||
for the unnormalized name.
|
effective for the unnormalized name.
|
||||||
|
:returns:
|
||||||
|
the effective :class:`~cssutils.css.Property` object.
|
||||||
"""
|
"""
|
||||||
nname = self._normalize(name)
|
nname = self._normalize(name)
|
||||||
found = None
|
found = None
|
||||||
@ -419,17 +399,17 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
|||||||
|
|
||||||
def getPropertyCSSValue(self, name, normalize=True):
|
def getPropertyCSSValue(self, name, normalize=True):
|
||||||
"""
|
"""
|
||||||
Returns CSSValue, the value of the effective property if it has been
|
:param name:
|
||||||
explicitly set for this declaration block.
|
|
||||||
|
|
||||||
name
|
|
||||||
of the CSS property, always lowercase (even if not normalized)
|
of the CSS property, always lowercase (even if not normalized)
|
||||||
normalize
|
:param normalize:
|
||||||
if True (DEFAULT) name will be normalized (lowercase, no simple
|
if ``True`` (DEFAULT) name will be normalized (lowercase, no simple
|
||||||
escapes) so "color", "COLOR" or "C\olor" will all be equivalent
|
escapes) so "color", "COLOR" or "C\olor" will all be equivalent
|
||||||
|
|
||||||
If False may return **NOT** the effective value but the effective
|
If ``False`` may return **NOT** the effective value but the effective
|
||||||
for the unnormalized name.
|
for the unnormalized name.
|
||||||
|
:returns:
|
||||||
|
:class:`~cssutils.css.CSSValue`, the value of the effective
|
||||||
|
property if it has been explicitly set for this declaration block.
|
||||||
|
|
||||||
(DOM)
|
(DOM)
|
||||||
Used to retrieve the object representation of the value of a CSS
|
Used to retrieve the object representation of the value of a CSS
|
||||||
@ -461,18 +441,18 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
|||||||
|
|
||||||
def getPropertyValue(self, name, normalize=True):
|
def getPropertyValue(self, name, normalize=True):
|
||||||
"""
|
"""
|
||||||
Returns the value of the effective property if it has been explicitly
|
:param name:
|
||||||
set for this declaration block. Returns the empty string if the
|
|
||||||
property has not been set.
|
|
||||||
|
|
||||||
name
|
|
||||||
of the CSS property, always lowercase (even if not normalized)
|
of the CSS property, always lowercase (even if not normalized)
|
||||||
normalize
|
:param normalize:
|
||||||
if True (DEFAULT) name will be normalized (lowercase, no simple
|
if ``True`` (DEFAULT) name will be normalized (lowercase, no simple
|
||||||
escapes) so "color", "COLOR" or "C\olor" will all be equivalent
|
escapes) so "color", "COLOR" or "C\olor" will all be equivalent
|
||||||
|
|
||||||
If False may return **NOT** the effective value but the effective
|
If ``False`` may return **NOT** the effective value but the
|
||||||
for the unnormalized name.
|
effective for the unnormalized name.
|
||||||
|
:returns:
|
||||||
|
the value of the effective property if it has been explicitly set
|
||||||
|
for this declaration block. Returns the empty string if the
|
||||||
|
property has not been set.
|
||||||
"""
|
"""
|
||||||
p = self.getProperty(name, normalize)
|
p = self.getProperty(name, normalize)
|
||||||
if p:
|
if p:
|
||||||
@ -482,18 +462,18 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
|||||||
|
|
||||||
def getPropertyPriority(self, name, normalize=True):
|
def getPropertyPriority(self, name, normalize=True):
|
||||||
"""
|
"""
|
||||||
Returns the priority of the effective CSS property (e.g. the
|
:param name:
|
||||||
"important" qualifier) if the property has been explicitly set in
|
|
||||||
this declaration block. The empty string if none exists.
|
|
||||||
|
|
||||||
name
|
|
||||||
of the CSS property, always lowercase (even if not normalized)
|
of the CSS property, always lowercase (even if not normalized)
|
||||||
normalize
|
:param normalize:
|
||||||
if True (DEFAULT) name will be normalized (lowercase, no simple
|
if ``True`` (DEFAULT) name will be normalized (lowercase, no simple
|
||||||
escapes) so "color", "COLOR" or "C\olor" will all be equivalent
|
escapes) so "color", "COLOR" or "C\olor" will all be equivalent
|
||||||
|
|
||||||
If False may return **NOT** the effective value but the effective
|
If ``False`` may return **NOT** the effective value but the
|
||||||
for the unnormalized name.
|
effective for the unnormalized name.
|
||||||
|
:returns:
|
||||||
|
the priority of the effective CSS property (e.g. the
|
||||||
|
"important" qualifier) if the property has been explicitly set in
|
||||||
|
this declaration block. The empty string if none exists.
|
||||||
"""
|
"""
|
||||||
p = self.getProperty(name, normalize)
|
p = self.getProperty(name, normalize)
|
||||||
if p:
|
if p:
|
||||||
@ -507,28 +487,28 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
|||||||
Used to remove a CSS property if it has been explicitly set within
|
Used to remove a CSS property if it has been explicitly set within
|
||||||
this declaration block.
|
this declaration block.
|
||||||
|
|
||||||
Returns the value of the property if it has been explicitly set for
|
:param name:
|
||||||
this declaration block. Returns the empty string if the property
|
|
||||||
has not been set or the property name does not correspond to a
|
|
||||||
known CSS property
|
|
||||||
|
|
||||||
name
|
|
||||||
of the CSS property
|
of the CSS property
|
||||||
normalize
|
:param normalize:
|
||||||
if True (DEFAULT) name will be normalized (lowercase, no simple
|
if ``True`` (DEFAULT) name will be normalized (lowercase, no simple
|
||||||
escapes) so "color", "COLOR" or "C\olor" will all be equivalent.
|
escapes) so "color", "COLOR" or "C\olor" will all be equivalent.
|
||||||
The effective Property value is returned and *all* Properties
|
The effective Property value is returned and *all* Properties
|
||||||
with ``Property.name == name`` are removed.
|
with ``Property.name == name`` are removed.
|
||||||
|
|
||||||
If False may return **NOT** the effective value but the effective
|
If ``False`` may return **NOT** the effective value but the
|
||||||
for the unnormalized ``name`` only. Also only the Properties with
|
effective for the unnormalized `name` only. Also only the
|
||||||
the literal name ``name`` are removed.
|
Properties with the literal name `name` are removed.
|
||||||
|
:returns:
|
||||||
|
the value of the property if it has been explicitly set for
|
||||||
|
this declaration block. Returns the empty string if the property
|
||||||
|
has not been set or the property name does not correspond to a
|
||||||
|
known CSS property
|
||||||
|
|
||||||
raises DOMException
|
|
||||||
|
|
||||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
:exceptions:
|
||||||
Raised if this declaration is readonly or the property is
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
readonly.
|
Raised if this declaration is readonly or the property is
|
||||||
|
readonly.
|
||||||
"""
|
"""
|
||||||
self._checkReadonly()
|
self._checkReadonly()
|
||||||
r = self.getPropertyValue(name, normalize=normalize)
|
r = self.getPropertyValue(name, normalize=normalize)
|
||||||
@ -548,36 +528,35 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
|||||||
return r
|
return r
|
||||||
|
|
||||||
def setProperty(self, name, value=None, priority=u'', normalize=True):
|
def setProperty(self, name, value=None, priority=u'', normalize=True):
|
||||||
"""
|
"""(DOM) Set a property value and priority within this declaration
|
||||||
(DOM)
|
|
||||||
Used to set a property value and priority within this declaration
|
|
||||||
block.
|
block.
|
||||||
|
|
||||||
name
|
:param name:
|
||||||
of the CSS property to set (in W3C DOM the parameter is called
|
of the CSS property to set (in W3C DOM the parameter is called
|
||||||
"propertyName"), always lowercase (even if not normalized)
|
"propertyName"), always lowercase (even if not normalized)
|
||||||
|
|
||||||
If a property with this name is present it will be reset
|
If a property with this `name` is present it will be reset.
|
||||||
|
|
||||||
cssutils also allowed name to be a Property object, all other
|
cssutils also allowed `name` to be a
|
||||||
|
:class:`~cssutils.css.Property` object, all other
|
||||||
parameter are ignored in this case
|
parameter are ignored in this case
|
||||||
|
|
||||||
value
|
:param value:
|
||||||
the new value of the property, omit if name is already a Property
|
the new value of the property, ignored if `name` is a Property.
|
||||||
priority
|
:param priority:
|
||||||
the optional priority of the property (e.g. "important")
|
the optional priority of the property (e.g. "important"),
|
||||||
normalize
|
ignored if `name` is a Property.
|
||||||
if True (DEFAULT) name will be normalized (lowercase, no simple
|
:param normalize:
|
||||||
|
if True (DEFAULT) `name` will be normalized (lowercase, no simple
|
||||||
escapes) so "color", "COLOR" or "C\olor" will all be equivalent
|
escapes) so "color", "COLOR" or "C\olor" will all be equivalent
|
||||||
|
|
||||||
DOMException on setting
|
:exceptions:
|
||||||
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
- SYNTAX_ERR: (self)
|
Raised if the specified value has a syntax error and is
|
||||||
Raised if the specified value has a syntax error and is
|
unparsable.
|
||||||
unparsable.
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
Raised if this declaration is readonly or the property is
|
||||||
Raised if this declaration is readonly or the property is
|
readonly.
|
||||||
readonly.
|
|
||||||
"""
|
"""
|
||||||
self._checkReadonly()
|
self._checkReadonly()
|
||||||
|
|
||||||
@ -607,27 +586,26 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
|||||||
self.seq._readonly = True
|
self.seq._readonly = True
|
||||||
|
|
||||||
def item(self, index):
|
def item(self, index):
|
||||||
"""
|
"""(DOM) Retrieve the properties that have been explicitly set in
|
||||||
(DOM)
|
|
||||||
Used to retrieve the properties that have been explicitly set in
|
|
||||||
this declaration block. The order of the properties retrieved using
|
this declaration block. The order of the properties retrieved using
|
||||||
this method does not have to be the order in which they were set.
|
this method does not have to be the order in which they were set.
|
||||||
This method can be used to iterate over all properties in this
|
This method can be used to iterate over all properties in this
|
||||||
declaration block.
|
declaration block.
|
||||||
|
|
||||||
index
|
:param index:
|
||||||
of the property to retrieve, negative values behave like
|
of the property to retrieve, negative values behave like
|
||||||
negative indexes on Python lists, so -1 is the last element
|
negative indexes on Python lists, so -1 is the last element
|
||||||
|
|
||||||
returns the name of the property at this ordinal position. The
|
:returns:
|
||||||
empty string if no property exists at this position.
|
the name of the property at this ordinal position. The
|
||||||
|
empty string if no property exists at this position.
|
||||||
|
|
||||||
ATTENTION:
|
**ATTENTION:**
|
||||||
Only properties with a different name are counted. If two
|
Only properties with different names are counted. If two
|
||||||
properties with the same name are present in this declaration
|
properties with the same name are present in this declaration
|
||||||
only the effective one is included.
|
only the effective one is included.
|
||||||
|
|
||||||
``item()`` and ``length`` work on the same set here.
|
:meth:`item` and :attr:`length` work on the same set here.
|
||||||
"""
|
"""
|
||||||
names = list(self.__nnames())
|
names = list(self.__nnames())
|
||||||
try:
|
try:
|
||||||
@ -636,16 +614,7 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
|||||||
return u''
|
return u''
|
||||||
|
|
||||||
length = property(lambda self: len(self.__nnames()),
|
length = property(lambda self: len(self.__nnames()),
|
||||||
doc="(DOM) The number of distinct properties that have been explicitly\
|
doc="(DOM) The number of distinct properties that have been explicitly "
|
||||||
in this declaration block. The range of valid indices is 0 to\
|
"in this declaration block. The range of valid indices is 0 to "
|
||||||
length-1 inclusive. These are properties with a different ``name``\
|
"length-1 inclusive. These are properties with a different ``name`` "
|
||||||
only. ``item()`` and ``length`` work on the same set here.")
|
"only. :meth:`item` and :attr:`length` work on the same set here.")
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "cssutils.css.%s(cssText=%r)" % (
|
|
||||||
self.__class__.__name__, self.getCssText(separator=u' '))
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "<cssutils.css.%s object length=%r (all: %r) at 0x%x>" % (
|
|
||||||
self.__class__.__name__, self.length,
|
|
||||||
len(self.getProperties(all=True)), id(self))
|
|
||||||
|
@ -1,49 +1,25 @@
|
|||||||
"""CSSStyleRule implements DOM Level 2 CSS CSSStyleRule.
|
"""CSSStyleRule implements DOM Level 2 CSS CSSStyleRule."""
|
||||||
"""
|
|
||||||
__all__ = ['CSSStyleRule']
|
__all__ = ['CSSStyleRule']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: cssstylerule.py 1284 2008-06-05 16:29:17Z cthedot $'
|
__version__ = '$Id: cssstylerule.py 1638 2009-01-13 20:39:33Z cthedot $'
|
||||||
|
|
||||||
import xml.dom
|
from cssstyledeclaration import CSSStyleDeclaration
|
||||||
|
from selectorlist import SelectorList
|
||||||
import cssrule
|
import cssrule
|
||||||
import cssutils
|
import cssutils
|
||||||
from selectorlist import SelectorList
|
import xml.dom
|
||||||
from cssstyledeclaration import CSSStyleDeclaration
|
|
||||||
|
|
||||||
class CSSStyleRule(cssrule.CSSRule):
|
class CSSStyleRule(cssrule.CSSRule):
|
||||||
"""
|
"""The CSSStyleRule object represents a ruleset specified (if any) in a CSS
|
||||||
The CSSStyleRule object represents a ruleset specified (if any) in a CSS
|
|
||||||
style sheet. It provides access to a declaration block as well as to the
|
style sheet. It provides access to a declaration block as well as to the
|
||||||
associated group of selectors.
|
associated group of selectors.
|
||||||
|
|
||||||
Properties
|
Format::
|
||||||
==========
|
|
||||||
selectorList: of type SelectorList (cssutils only)
|
|
||||||
A list of all Selector elements for the rule set.
|
|
||||||
selectorText: of type DOMString
|
|
||||||
The textual representation of the selector for the rule set. The
|
|
||||||
implementation may have stripped out insignificant whitespace while
|
|
||||||
parsing the selector.
|
|
||||||
style: of type CSSStyleDeclaration, (DOM)
|
|
||||||
The declaration-block of this rule set.
|
|
||||||
type
|
|
||||||
the type of this rule, constant cssutils.CSSRule.STYLE_RULE
|
|
||||||
|
|
||||||
inherited properties:
|
|
||||||
- cssText
|
|
||||||
- parentRule
|
|
||||||
- parentStyleSheet
|
|
||||||
|
|
||||||
Format
|
|
||||||
======
|
|
||||||
ruleset::
|
|
||||||
|
|
||||||
: selector [ COMMA S* selector ]*
|
: selector [ COMMA S* selector ]*
|
||||||
LBRACE S* declaration [ ';' S* declaration ]* '}' S*
|
LBRACE S* declaration [ ';' S* declaration ]* '}' S*
|
||||||
;
|
;
|
||||||
"""
|
"""
|
||||||
type = property(lambda self: cssrule.CSSRule.STYLE_RULE)
|
|
||||||
|
|
||||||
def __init__(self, selectorText=None, style=None, parentRule=None,
|
def __init__(self, selectorText=None, style=None, parentRule=None,
|
||||||
parentStyleSheet=None, readonly=False):
|
parentStyleSheet=None, readonly=False):
|
||||||
"""
|
"""
|
||||||
@ -67,31 +43,41 @@ class CSSStyleRule(cssrule.CSSRule):
|
|||||||
|
|
||||||
self._readonly = readonly
|
self._readonly = readonly
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
if self._namespaces:
|
||||||
|
st = (self.selectorText, self._namespaces)
|
||||||
|
else:
|
||||||
|
st = self.selectorText
|
||||||
|
return "cssutils.css.%s(selectorText=%r, style=%r)" % (
|
||||||
|
self.__class__.__name__, st, self.style.cssText)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "<cssutils.css.%s object selector=%r style=%r _namespaces=%r at 0x%x>" % (
|
||||||
|
self.__class__.__name__, self.selectorText, self.style.cssText,
|
||||||
|
self._namespaces, id(self))
|
||||||
|
|
||||||
def _getCssText(self):
|
def _getCssText(self):
|
||||||
"""
|
"""Return serialized property cssText."""
|
||||||
returns serialized property cssText
|
|
||||||
"""
|
|
||||||
return cssutils.ser.do_CSSStyleRule(self)
|
return cssutils.ser.do_CSSStyleRule(self)
|
||||||
|
|
||||||
def _setCssText(self, cssText):
|
def _setCssText(self, cssText):
|
||||||
"""
|
"""
|
||||||
:param cssText:
|
:param cssText:
|
||||||
a parseable string or a tuple of (cssText, dict-of-namespaces)
|
a parseable string or a tuple of (cssText, dict-of-namespaces)
|
||||||
:Exceptions:
|
:exceptions:
|
||||||
- `NAMESPACE_ERR`: (Selector)
|
- :exc:`~xml.dom.NamespaceErr`:
|
||||||
Raised if the specified selector uses an unknown namespace
|
Raised if the specified selector uses an unknown namespace
|
||||||
prefix.
|
prefix.
|
||||||
- `SYNTAX_ERR`: (self, StyleDeclaration, etc)
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
Raised if the specified CSS string value has a syntax error and
|
Raised if the specified CSS string value has a syntax error and
|
||||||
is unparsable.
|
is unparsable.
|
||||||
- `INVALID_MODIFICATION_ERR`: (self)
|
- :exc:`~xml.dom.InvalidModificationErr`:
|
||||||
Raised if the specified CSS string value represents a different
|
Raised if the specified CSS string value represents a different
|
||||||
type of rule than the current one.
|
type of rule than the current one.
|
||||||
- `HIERARCHY_REQUEST_ERR`: (CSSStylesheet)
|
- :exc:`~xml.dom.HierarchyRequestErr`:
|
||||||
Raised if the rule cannot be inserted at this point in the
|
Raised if the rule cannot be inserted at this point in the
|
||||||
style sheet.
|
style sheet.
|
||||||
- `NO_MODIFICATION_ALLOWED_ERR`: (CSSRule)
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
Raised if the rule is readonly.
|
Raised if the rule is readonly.
|
||||||
"""
|
"""
|
||||||
super(CSSStyleRule, self)._setCssText(cssText)
|
super(CSSStyleRule, self)._setCssText(cssText)
|
||||||
@ -160,20 +146,21 @@ class CSSStyleRule(cssrule.CSSRule):
|
|||||||
self.style = newstyle
|
self.style = newstyle
|
||||||
|
|
||||||
cssText = property(_getCssText, _setCssText,
|
cssText = property(_getCssText, _setCssText,
|
||||||
doc="(DOM) The parsable textual representation of the rule.")
|
doc="(DOM) The parsable textual representation of this rule.")
|
||||||
|
|
||||||
|
|
||||||
def __getNamespaces(self):
|
def __getNamespaces(self):
|
||||||
"uses children namespaces if not attached to a sheet, else the sheet's ones"
|
"Uses children namespaces if not attached to a sheet, else the sheet's ones."
|
||||||
try:
|
try:
|
||||||
return self.parentStyleSheet.namespaces
|
return self.parentStyleSheet.namespaces
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return self.selectorList._namespaces
|
return self.selectorList._namespaces
|
||||||
|
|
||||||
_namespaces = property(__getNamespaces, doc=u"""if this Rule is
|
_namespaces = property(__getNamespaces,
|
||||||
attached to a CSSStyleSheet the namespaces of that sheet are mirrored
|
doc="If this Rule is attached to a CSSStyleSheet "
|
||||||
here. While the Rule is not attached the namespaces of selectorList
|
"the namespaces of that sheet are mirrored "
|
||||||
are used.""")
|
"here. While the Rule is not attached the "
|
||||||
|
"namespaces of selectorList are used.""")
|
||||||
|
|
||||||
def _setSelectorList(self, selectorList):
|
def _setSelectorList(self, selectorList):
|
||||||
"""
|
"""
|
||||||
@ -190,16 +177,17 @@ class CSSStyleRule(cssrule.CSSRule):
|
|||||||
"""
|
"""
|
||||||
wrapper for cssutils SelectorList object
|
wrapper for cssutils SelectorList object
|
||||||
|
|
||||||
:param selectorText: of type string, might also be a comma separated list
|
:param selectorText:
|
||||||
|
of type string, might also be a comma separated list
|
||||||
of selectors
|
of selectors
|
||||||
:Exceptions:
|
:exceptions:
|
||||||
- `NAMESPACE_ERR`: (Selector)
|
- :exc:`~xml.dom.NamespaceErr`:
|
||||||
Raised if the specified selector uses an unknown namespace
|
Raised if the specified selector uses an unknown namespace
|
||||||
prefix.
|
prefix.
|
||||||
- `SYNTAX_ERR`: (SelectorList, Selector)
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
Raised if the specified CSS string value has a syntax error
|
Raised if the specified CSS string value has a syntax error
|
||||||
and is unparsable.
|
and is unparsable.
|
||||||
- `NO_MODIFICATION_ALLOWED_ERR`: (self)
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
Raised if this rule is readonly.
|
Raised if this rule is readonly.
|
||||||
"""
|
"""
|
||||||
self._checkReadonly()
|
self._checkReadonly()
|
||||||
@ -207,8 +195,8 @@ class CSSStyleRule(cssrule.CSSRule):
|
|||||||
|
|
||||||
selectorText = property(lambda self: self._selectorList.selectorText,
|
selectorText = property(lambda self: self._selectorList.selectorText,
|
||||||
_setSelectorText,
|
_setSelectorText,
|
||||||
doc="""(DOM) The textual representation of the selector for the
|
doc="(DOM) The textual representation of the "
|
||||||
rule set.""")
|
"selector for the rule set.")
|
||||||
|
|
||||||
def _setStyle(self, style):
|
def _setStyle(self, style):
|
||||||
"""
|
"""
|
||||||
@ -224,19 +212,10 @@ class CSSStyleRule(cssrule.CSSRule):
|
|||||||
self._style._seq = style._seq
|
self._style._seq = style._seq
|
||||||
|
|
||||||
style = property(lambda self: self._style, _setStyle,
|
style = property(lambda self: self._style, _setStyle,
|
||||||
doc="(DOM) The declaration-block of this rule set.")
|
doc="(DOM) The declaration-block of this rule set.")
|
||||||
|
|
||||||
|
type = property(lambda self: self.STYLE_RULE,
|
||||||
|
doc="The type of this rule, as defined by a CSSRule "
|
||||||
|
"type constant.")
|
||||||
|
|
||||||
wellformed = property(lambda self: self.selectorList.wellformed)
|
wellformed = property(lambda self: self.selectorList.wellformed)
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
if self._namespaces:
|
|
||||||
st = (self.selectorText, self._namespaces)
|
|
||||||
else:
|
|
||||||
st = self.selectorText
|
|
||||||
return "cssutils.css.%s(selectorText=%r, style=%r)" % (
|
|
||||||
self.__class__.__name__, st, self.style.cssText)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "<cssutils.css.%s object selector=%r style=%r _namespaces=%r at 0x%x>" % (
|
|
||||||
self.__class__.__name__, self.selectorText, self.style.cssText,
|
|
||||||
self._namespaces, id(self))
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
"""
|
"""CSSStyleSheet implements DOM Level 2 CSS CSSStyleSheet.
|
||||||
CSSStyleSheet implements DOM Level 2 CSS CSSStyleSheet.
|
|
||||||
|
|
||||||
Partly also:
|
Partly also:
|
||||||
- http://dev.w3.org/csswg/cssom/#the-cssstylesheet
|
- http://dev.w3.org/csswg/cssom/#the-cssstylesheet
|
||||||
@ -10,53 +9,32 @@ TODO:
|
|||||||
"""
|
"""
|
||||||
__all__ = ['CSSStyleSheet']
|
__all__ = ['CSSStyleSheet']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: cssstylesheet.py 1429 2008-08-11 19:01:52Z cthedot $'
|
__version__ = '$Id: cssstylesheet.py 1641 2009-01-13 21:05:37Z cthedot $'
|
||||||
|
|
||||||
import xml.dom
|
|
||||||
import cssutils.stylesheets
|
|
||||||
from cssutils.util import _Namespaces, _SimpleNamespaces, _readUrl
|
|
||||||
from cssutils.helper import Deprecated
|
from cssutils.helper import Deprecated
|
||||||
|
from cssutils.util import _Namespaces, _SimpleNamespaces, _readUrl
|
||||||
|
import cssutils.stylesheets
|
||||||
|
import xml.dom
|
||||||
|
|
||||||
class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
|
class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
|
||||||
"""
|
"""CSSStyleSheet represents a CSS style sheet.
|
||||||
The CSSStyleSheet interface represents a CSS style sheet.
|
|
||||||
|
|
||||||
Properties
|
Format::
|
||||||
==========
|
|
||||||
CSSOM
|
|
||||||
-----
|
|
||||||
cssRules
|
|
||||||
of type CSSRuleList, (DOM readonly)
|
|
||||||
encoding
|
|
||||||
reflects the encoding of an @charset rule or 'utf-8' (default)
|
|
||||||
if set to ``None``
|
|
||||||
ownerRule
|
|
||||||
of type CSSRule, readonly. If this sheet is imported this is a ref
|
|
||||||
to the @import rule that imports it.
|
|
||||||
|
|
||||||
Inherits properties from stylesheet.StyleSheet
|
stylesheet
|
||||||
|
: [ CHARSET_SYM S* STRING S* ';' ]?
|
||||||
|
[S|CDO|CDC]* [ import [S|CDO|CDC]* ]*
|
||||||
|
[ namespace [S|CDO|CDC]* ]* # according to @namespace WD
|
||||||
|
[ [ ruleset | media | page ] [S|CDO|CDC]* ]*
|
||||||
|
|
||||||
cssutils
|
``cssRules``
|
||||||
--------
|
All Rules in this style sheet, a :class:`~cssutils.css.CSSRuleList`.
|
||||||
cssText: string
|
|
||||||
a textual representation of the stylesheet
|
|
||||||
namespaces
|
|
||||||
reflects set @namespace rules of this rule.
|
|
||||||
A dict of {prefix: namespaceURI} mapping.
|
|
||||||
|
|
||||||
Format
|
|
||||||
======
|
|
||||||
stylesheet
|
|
||||||
: [ CHARSET_SYM S* STRING S* ';' ]?
|
|
||||||
[S|CDO|CDC]* [ import [S|CDO|CDC]* ]*
|
|
||||||
[ namespace [S|CDO|CDC]* ]* # according to @namespace WD
|
|
||||||
[ [ ruleset | media | page ] [S|CDO|CDC]* ]*
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, href=None, media=None, title=u'', disabled=None,
|
def __init__(self, href=None, media=None, title=u'', disabled=None,
|
||||||
ownerNode=None, parentStyleSheet=None, readonly=False,
|
ownerNode=None, parentStyleSheet=None, readonly=False,
|
||||||
ownerRule=None):
|
ownerRule=None):
|
||||||
"""
|
"""
|
||||||
init parameters are the same as for stylesheets.StyleSheet
|
For parameters see :class:`~cssutils.stylesheets.StyleSheet`
|
||||||
"""
|
"""
|
||||||
super(CSSStyleSheet, self).__init__(
|
super(CSSStyleSheet, self).__init__(
|
||||||
'text/css', href, media, title, disabled,
|
'text/css', href, media, title, disabled,
|
||||||
@ -74,12 +52,32 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
|
|||||||
self._fetcher = None
|
self._fetcher = None
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
"generator which iterates over cssRules."
|
"Generator which iterates over cssRules."
|
||||||
for rule in self.cssRules:
|
for rule in self.cssRules:
|
||||||
yield rule
|
yield rule
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
if self.media:
|
||||||
|
mediaText = self.media.mediaText
|
||||||
|
else:
|
||||||
|
mediaText = None
|
||||||
|
return "cssutils.css.%s(href=%r, media=%r, title=%r)" % (
|
||||||
|
self.__class__.__name__,
|
||||||
|
self.href, mediaText, self.title)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self.media:
|
||||||
|
mediaText = self.media.mediaText
|
||||||
|
else:
|
||||||
|
mediaText = None
|
||||||
|
return "<cssutils.css.%s object encoding=%r href=%r "\
|
||||||
|
"media=%r title=%r namespaces=%r at 0x%x>" % (
|
||||||
|
self.__class__.__name__, self.encoding, self.href,
|
||||||
|
mediaText, self.title, self.namespaces.namespaces,
|
||||||
|
id(self))
|
||||||
|
|
||||||
def _cleanNamespaces(self):
|
def _cleanNamespaces(self):
|
||||||
"removes all namespace rules with same namespaceURI but last one set"
|
"Remove all namespace rules with same namespaceURI but last one set."
|
||||||
rules = self.cssRules
|
rules = self.cssRules
|
||||||
namespaceitems = self.namespaces.items()
|
namespaceitems = self.namespaces.items()
|
||||||
i = 0
|
i = 0
|
||||||
@ -92,7 +90,7 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
|
|||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
def _getUsedURIs(self):
|
def _getUsedURIs(self):
|
||||||
"returns set of URIs used in the sheet"
|
"Return set of URIs used in the sheet."
|
||||||
useduris = set()
|
useduris = set()
|
||||||
for r1 in self:
|
for r1 in self:
|
||||||
if r1.STYLE_RULE == r1.type:
|
if r1.STYLE_RULE == r1.type:
|
||||||
@ -104,21 +102,20 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
|
|||||||
return useduris
|
return useduris
|
||||||
|
|
||||||
def _getCssText(self):
|
def _getCssText(self):
|
||||||
|
"Textual representation of the stylesheet (a byte string)."
|
||||||
return cssutils.ser.do_CSSStyleSheet(self)
|
return cssutils.ser.do_CSSStyleSheet(self)
|
||||||
|
|
||||||
def _setCssText(self, cssText):
|
def _setCssText(self, cssText):
|
||||||
"""
|
"""Parse `cssText` and overwrites the whole stylesheet.
|
||||||
(cssutils)
|
|
||||||
Parses ``cssText`` and overwrites the whole stylesheet.
|
|
||||||
|
|
||||||
:param cssText:
|
:param cssText:
|
||||||
a parseable string or a tuple of (cssText, dict-of-namespaces)
|
a parseable string or a tuple of (cssText, dict-of-namespaces)
|
||||||
:Exceptions:
|
:exceptions:
|
||||||
- `NAMESPACE_ERR`:
|
- :exc:`~xml.dom.NamespaceErr`:
|
||||||
If a namespace prefix is found which is not declared.
|
If a namespace prefix is found which is not declared.
|
||||||
- `NO_MODIFICATION_ALLOWED_ERR`: (self)
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
Raised if the rule is readonly.
|
Raised if the rule is readonly.
|
||||||
- `SYNTAX_ERR`:
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
Raised if the specified CSS string value has a syntax error and
|
Raised if the specified CSS string value has a syntax error and
|
||||||
is unparsable.
|
is unparsable.
|
||||||
"""
|
"""
|
||||||
@ -269,10 +266,10 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
|
|||||||
self._cleanNamespaces()
|
self._cleanNamespaces()
|
||||||
|
|
||||||
cssText = property(_getCssText, _setCssText,
|
cssText = property(_getCssText, _setCssText,
|
||||||
"(cssutils) a textual representation of the stylesheet")
|
"Textual representation of the stylesheet (a byte string)")
|
||||||
|
|
||||||
def _resolveImport(self, url):
|
def _resolveImport(self, url):
|
||||||
"""Read (encoding, enctype, decodedContent) from ``url`` for @import
|
"""Read (encoding, enctype, decodedContent) from `url` for @import
|
||||||
sheets."""
|
sheets."""
|
||||||
try:
|
try:
|
||||||
# only available during parse of a complete sheet
|
# only available during parse of a complete sheet
|
||||||
@ -291,10 +288,10 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
|
|||||||
|
|
||||||
def _setCssTextWithEncodingOverride(self, cssText, encodingOverride=None,
|
def _setCssTextWithEncodingOverride(self, cssText, encodingOverride=None,
|
||||||
encoding=None):
|
encoding=None):
|
||||||
"""Set cssText but use ``encodingOverride`` to overwrite detected
|
"""Set `cssText` but use `encodingOverride` to overwrite detected
|
||||||
encoding. This is used by parse and @import during setting of cssText.
|
encoding. This is used by parse and @import during setting of cssText.
|
||||||
|
|
||||||
If ``encoding`` is given use this but do not save it as encodingOverride"""
|
If `encoding` is given use this but do not save it as `encodingOverride`."""
|
||||||
if encodingOverride:
|
if encodingOverride:
|
||||||
# encoding during resolving of @import
|
# encoding during resolving of @import
|
||||||
self.__encodingOverride = encodingOverride
|
self.__encodingOverride = encodingOverride
|
||||||
@ -312,14 +309,14 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
|
|||||||
self.encoding = encoding
|
self.encoding = encoding
|
||||||
|
|
||||||
def _setFetcher(self, fetcher=None):
|
def _setFetcher(self, fetcher=None):
|
||||||
"""sets @import URL loader, if None the default is used"""
|
"""Set @import URL loader, if None the default is used."""
|
||||||
self._fetcher = fetcher
|
self._fetcher = fetcher
|
||||||
|
|
||||||
def _setEncoding(self, encoding):
|
def _setEncoding(self, encoding):
|
||||||
"""
|
"""Set `encoding` of charset rule if present in sheet or insert a new
|
||||||
sets encoding of charset rule if present or inserts new charsetrule
|
:class:`~cssutils.css.CSSCharsetRule` with given `encoding`.
|
||||||
with given encoding. If encoding if None removes charsetrule if
|
If `encoding` is None removes charsetrule if present resulting in
|
||||||
present.
|
default encoding of utf-8.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
rule = self.cssRules[0]
|
rule = self.cssRules[0]
|
||||||
@ -334,41 +331,41 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
|
|||||||
self.insertRule(cssutils.css.CSSCharsetRule(encoding=encoding), 0)
|
self.insertRule(cssutils.css.CSSCharsetRule(encoding=encoding), 0)
|
||||||
|
|
||||||
def _getEncoding(self):
|
def _getEncoding(self):
|
||||||
"return encoding if @charset rule if given or default of 'utf-8'"
|
"""Encoding set in :class:`~cssutils.css.CSSCharsetRule` or if ``None``
|
||||||
|
resulting in default ``utf-8`` encoding being used."""
|
||||||
try:
|
try:
|
||||||
return self.cssRules[0].encoding
|
return self.cssRules[0].encoding
|
||||||
except (IndexError, AttributeError):
|
except (IndexError, AttributeError):
|
||||||
return 'utf-8'
|
return 'utf-8'
|
||||||
|
|
||||||
encoding = property(_getEncoding, _setEncoding,
|
encoding = property(_getEncoding, _setEncoding,
|
||||||
"(cssutils) reflects the encoding of an @charset rule or 'UTF-8' (default) if set to ``None``")
|
"(cssutils) Reflect encoding of an @charset rule or 'utf-8' "
|
||||||
|
"(default) if set to ``None``")
|
||||||
|
|
||||||
namespaces = property(lambda self: self._namespaces,
|
namespaces = property(lambda self: self._namespaces,
|
||||||
doc="Namespaces used in this CSSStyleSheet.")
|
doc="All Namespaces used in this CSSStyleSheet.")
|
||||||
|
|
||||||
def add(self, rule):
|
def add(self, rule):
|
||||||
"""
|
"""Add `rule` to style sheet at appropriate position.
|
||||||
Adds rule to stylesheet at appropriate position.
|
Same as ``insertRule(rule, inOrder=True)``.
|
||||||
Same as ``sheet.insertRule(rule, inOrder=True)``.
|
|
||||||
"""
|
"""
|
||||||
return self.insertRule(rule, index=None, inOrder=True)
|
return self.insertRule(rule, index=None, inOrder=True)
|
||||||
|
|
||||||
def deleteRule(self, index):
|
def deleteRule(self, index):
|
||||||
"""
|
"""Delete rule at `index` from the style sheet.
|
||||||
Used to delete a rule from the style sheet.
|
|
||||||
|
|
||||||
:param index:
|
:param index:
|
||||||
of the rule to remove in the StyleSheet's rule list. For an
|
of the rule to remove in the StyleSheet's rule list. For an
|
||||||
index < 0 **no** INDEX_SIZE_ERR is raised but rules for
|
`index` < 0 **no** :exc:`~xml.dom.IndexSizeErr` is raised but
|
||||||
normal Python lists are used. E.g. ``deleteRule(-1)`` removes
|
rules for normal Python lists are used. E.g. ``deleteRule(-1)``
|
||||||
the last rule in cssRules.
|
removes the last rule in cssRules.
|
||||||
:Exceptions:
|
:exceptions:
|
||||||
- `INDEX_SIZE_ERR`: (self)
|
- :exc:`~xml.dom.IndexSizeErr`:
|
||||||
Raised if the specified index does not correspond to a rule in
|
Raised if the specified index does not correspond to a rule in
|
||||||
the style sheet's rule list.
|
the style sheet's rule list.
|
||||||
- `NAMESPACE_ERR`: (self)
|
- :exc:`~xml.dom.NamespaceErr`:
|
||||||
Raised if removing this rule would result in an invalid StyleSheet
|
Raised if removing this rule would result in an invalid StyleSheet
|
||||||
- `NO_MODIFICATION_ALLOWED_ERR`: (self)
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
Raised if this style sheet is readonly.
|
Raised if this style sheet is readonly.
|
||||||
"""
|
"""
|
||||||
self._checkReadonly()
|
self._checkReadonly()
|
||||||
@ -398,32 +395,31 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
|
|||||||
Used to insert a new rule into the style sheet. The new rule now
|
Used to insert a new rule into the style sheet. The new rule now
|
||||||
becomes part of the cascade.
|
becomes part of the cascade.
|
||||||
|
|
||||||
:Parameters:
|
:param rule:
|
||||||
rule
|
a parsable DOMString, in cssutils also a
|
||||||
a parsable DOMString, in cssutils also a CSSRule or a
|
:class:`~cssutils.css.CSSRule` or :class:`~cssutils.css.CSSRuleList`
|
||||||
CSSRuleList
|
:param index:
|
||||||
index
|
of the rule before the new rule will be inserted.
|
||||||
of the rule before the new rule will be inserted.
|
If the specified `index` is equal to the length of the
|
||||||
If the specified index is equal to the length of the
|
StyleSheet's rule collection, the rule will be added to the end
|
||||||
StyleSheet's rule collection, the rule will be added to the end
|
of the style sheet.
|
||||||
of the style sheet.
|
If `index` is not given or ``None`` rule will be appended to rule
|
||||||
If index is not given or None rule will be appended to rule
|
list.
|
||||||
list.
|
:param inOrder:
|
||||||
inOrder
|
if ``True`` the rule will be put to a proper location while
|
||||||
if True the rule will be put to a proper location while
|
ignoring `index` and without raising :exc:`~xml.dom.HierarchyRequestErr`.
|
||||||
ignoring index but without raising HIERARCHY_REQUEST_ERR.
|
The resulting index is returned nevertheless.
|
||||||
The resulting index is returned nevertheless
|
:returns: The index within the style sheet's rule collection
|
||||||
:returns: the index within the stylesheet's rule collection
|
|
||||||
:Exceptions:
|
:Exceptions:
|
||||||
- `HIERARCHY_REQUEST_ERR`: (self)
|
- :exc:`~xml.dom.HierarchyRequestErr`:
|
||||||
Raised if the rule cannot be inserted at the specified index
|
Raised if the rule cannot be inserted at the specified `index`
|
||||||
e.g. if an @import rule is inserted after a standard rule set
|
e.g. if an @import rule is inserted after a standard rule set
|
||||||
or other at-rule.
|
or other at-rule.
|
||||||
- `INDEX_SIZE_ERR`: (self)
|
- :exc:`~xml.dom.IndexSizeErr`:
|
||||||
Raised if the specified index is not a valid insertion point.
|
Raised if the specified `index` is not a valid insertion point.
|
||||||
- `NO_MODIFICATION_ALLOWED_ERR`: (self)
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
Raised if this style sheet is readonly.
|
Raised if this style sheet is readonly.
|
||||||
- `SYNTAX_ERR`: (rule)
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
Raised if the specified rule has a syntax error and is
|
Raised if the specified rule has a syntax error and is
|
||||||
unparsable.
|
unparsable.
|
||||||
"""
|
"""
|
||||||
@ -618,57 +614,18 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
|
|||||||
return index
|
return index
|
||||||
|
|
||||||
ownerRule = property(lambda self: self._ownerRule,
|
ownerRule = property(lambda self: self._ownerRule,
|
||||||
doc="(DOM attribute) NOT IMPLEMENTED YET")
|
doc="A ref to an @import rule if it is imported, else ``None``.")
|
||||||
|
|
||||||
@Deprecated('Use cssutils.replaceUrls(sheet, replacer) instead.')
|
|
||||||
def replaceUrls(self, replacer):
|
|
||||||
"""
|
|
||||||
**EXPERIMENTAL**
|
|
||||||
|
|
||||||
Utility method to replace all ``url(urlstring)`` values in
|
|
||||||
``CSSImportRules`` and ``CSSStyleDeclaration`` objects (properties).
|
|
||||||
|
|
||||||
``replacer`` must be a function which is called with a single
|
|
||||||
argument ``urlstring`` which is the current value of url()
|
|
||||||
excluding ``url(`` and ``)``. It still may have surrounding
|
|
||||||
single or double quotes though.
|
|
||||||
"""
|
|
||||||
cssutils.replaceUrls(self, replacer)
|
|
||||||
|
|
||||||
def setSerializer(self, cssserializer):
|
def setSerializer(self, cssserializer):
|
||||||
"""
|
"""Set the cssutils global Serializer used for all output."""
|
||||||
Sets the global Serializer used for output of all stylesheet
|
|
||||||
output.
|
|
||||||
"""
|
|
||||||
if isinstance(cssserializer, cssutils.CSSSerializer):
|
if isinstance(cssserializer, cssutils.CSSSerializer):
|
||||||
cssutils.ser = cssserializer
|
cssutils.ser = cssserializer
|
||||||
else:
|
else:
|
||||||
raise ValueError(u'Serializer must be an instance of cssutils.CSSSerializer.')
|
raise ValueError(u'Serializer must be an instance of cssutils.CSSSerializer.')
|
||||||
|
|
||||||
def setSerializerPref(self, pref, value):
|
def setSerializerPref(self, pref, value):
|
||||||
"""
|
"""Set a Preference of CSSSerializer used for output.
|
||||||
Sets Preference of CSSSerializer used for output of this
|
See :class:`cssutils.serialize.Preferences` for possible
|
||||||
stylesheet. See cssutils.serialize.Preferences for possible
|
|
||||||
preferences to be set.
|
preferences to be set.
|
||||||
"""
|
"""
|
||||||
cssutils.ser.prefs.__setattr__(pref, value)
|
cssutils.ser.prefs.__setattr__(pref, value)
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
if self.media:
|
|
||||||
mediaText = self.media.mediaText
|
|
||||||
else:
|
|
||||||
mediaText = None
|
|
||||||
return "cssutils.css.%s(href=%r, media=%r, title=%r)" % (
|
|
||||||
self.__class__.__name__,
|
|
||||||
self.href, mediaText, self.title)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
if self.media:
|
|
||||||
mediaText = self.media.mediaText
|
|
||||||
else:
|
|
||||||
mediaText = None
|
|
||||||
return "<cssutils.css.%s object encoding=%r href=%r "\
|
|
||||||
"media=%r title=%r namespaces=%r at 0x%x>" % (
|
|
||||||
self.__class__.__name__, self.encoding, self.href,
|
|
||||||
mediaText, self.title, self.namespaces.namespaces,
|
|
||||||
id(self))
|
|
||||||
|
@ -1,44 +1,25 @@
|
|||||||
"""CSSUnknownRule implements DOM Level 2 CSS CSSUnknownRule.
|
"""CSSUnknownRule implements DOM Level 2 CSS CSSUnknownRule."""
|
||||||
"""
|
|
||||||
__all__ = ['CSSUnknownRule']
|
__all__ = ['CSSUnknownRule']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: cssunknownrule.py 1170 2008-03-20 17:42:07Z cthedot $'
|
__version__ = '$Id: cssunknownrule.py 1638 2009-01-13 20:39:33Z cthedot $'
|
||||||
|
|
||||||
import xml.dom
|
|
||||||
import cssrule
|
import cssrule
|
||||||
import cssutils
|
import cssutils
|
||||||
|
import xml.dom
|
||||||
|
|
||||||
class CSSUnknownRule(cssrule.CSSRule):
|
class CSSUnknownRule(cssrule.CSSRule):
|
||||||
"""
|
"""
|
||||||
represents an at-rule not supported by this user agent.
|
Represents an at-rule not supported by this user agent, so in
|
||||||
|
effect all other at-rules not defined in cssutils.
|
||||||
|
|
||||||
Properties
|
Format::
|
||||||
==========
|
|
||||||
inherited from CSSRule
|
|
||||||
- cssText
|
|
||||||
- type
|
|
||||||
|
|
||||||
cssutils only
|
|
||||||
-------------
|
|
||||||
atkeyword
|
|
||||||
the literal keyword used
|
|
||||||
seq
|
|
||||||
All parts of this rule excluding @KEYWORD but including CSSComments
|
|
||||||
wellformed
|
|
||||||
if this Rule is wellformed, for Unknown rules if an atkeyword is set
|
|
||||||
at all
|
|
||||||
|
|
||||||
Format
|
|
||||||
======
|
|
||||||
unknownrule:
|
|
||||||
@xxx until ';' or block {...}
|
@xxx until ';' or block {...}
|
||||||
"""
|
"""
|
||||||
type = property(lambda self: cssrule.CSSRule.UNKNOWN_RULE)
|
|
||||||
|
|
||||||
def __init__(self, cssText=u'', parentRule=None,
|
def __init__(self, cssText=u'', parentRule=None,
|
||||||
parentStyleSheet=None, readonly=False):
|
parentStyleSheet=None, readonly=False):
|
||||||
"""
|
"""
|
||||||
cssText
|
:param cssText:
|
||||||
of type string
|
of type string
|
||||||
"""
|
"""
|
||||||
super(CSSUnknownRule, self).__init__(parentRule=parentRule,
|
super(CSSUnknownRule, self).__init__(parentRule=parentRule,
|
||||||
@ -49,25 +30,32 @@ class CSSUnknownRule(cssrule.CSSRule):
|
|||||||
|
|
||||||
self._readonly = readonly
|
self._readonly = readonly
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "cssutils.css.%s(cssText=%r)" % (
|
||||||
|
self.__class__.__name__, self.cssText)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "<cssutils.css.%s object cssText=%r at 0x%x>" % (
|
||||||
|
self.__class__.__name__, self.cssText, id(self))
|
||||||
|
|
||||||
def _getCssText(self):
|
def _getCssText(self):
|
||||||
""" returns serialized property cssText """
|
"""Return serialized property cssText."""
|
||||||
return cssutils.ser.do_CSSUnknownRule(self)
|
return cssutils.ser.do_CSSUnknownRule(self)
|
||||||
|
|
||||||
def _setCssText(self, cssText):
|
def _setCssText(self, cssText):
|
||||||
"""
|
"""
|
||||||
DOMException on setting
|
:exceptions:
|
||||||
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
- SYNTAX_ERR:
|
Raised if the specified CSS string value has a syntax error and
|
||||||
Raised if the specified CSS string value has a syntax error and
|
is unparsable.
|
||||||
is unparsable.
|
- :exc:`~xml.dom.InvalidModificationErr`:
|
||||||
- INVALID_MODIFICATION_ERR:
|
Raised if the specified CSS string value represents a different
|
||||||
Raised if the specified CSS string value represents a different
|
type of rule than the current one.
|
||||||
type of rule than the current one.
|
- :exc:`~xml.dom.HierarchyRequestErr`:
|
||||||
- HIERARCHY_REQUEST_ERR: (never raised)
|
Raised if the rule cannot be inserted at this point in the
|
||||||
Raised if the rule cannot be inserted at this point in the
|
style sheet.
|
||||||
style sheet.
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
- NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
|
Raised if the rule is readonly.
|
||||||
Raised if the rule is readonly.
|
|
||||||
"""
|
"""
|
||||||
super(CSSUnknownRule, self)._setCssText(cssText)
|
super(CSSUnknownRule, self)._setCssText(cssText)
|
||||||
tokenizer = self._tokenize2(cssText)
|
tokenizer = self._tokenize2(cssText)
|
||||||
@ -197,12 +185,9 @@ class CSSUnknownRule(cssrule.CSSRule):
|
|||||||
cssText = property(fget=_getCssText, fset=_setCssText,
|
cssText = property(fget=_getCssText, fset=_setCssText,
|
||||||
doc="(DOM) The parsable textual representation.")
|
doc="(DOM) The parsable textual representation.")
|
||||||
|
|
||||||
|
type = property(lambda self: self.UNKNOWN_RULE,
|
||||||
|
doc="The type of this rule, as defined by a CSSRule "
|
||||||
|
"type constant.")
|
||||||
|
|
||||||
wellformed = property(lambda self: bool(self.atkeyword))
|
wellformed = property(lambda self: bool(self.atkeyword))
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "cssutils.css.%s(cssText=%r)" % (
|
|
||||||
self.__class__.__name__, self.cssText)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "<cssutils.css.%s object cssText=%r at 0x%x>" % (
|
|
||||||
self.__class__.__name__, self.cssText, id(self))
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,55 +1,18 @@
|
|||||||
"""Property is a single CSS property in a CSSStyleDeclaration
|
"""Property is a single CSS property in a CSSStyleDeclaration."""
|
||||||
|
|
||||||
Internal use only, may be removed in the future!
|
|
||||||
"""
|
|
||||||
__all__ = ['Property']
|
__all__ = ['Property']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: property.py 1444 2008-08-31 18:45:35Z cthedot $'
|
__version__ = '$Id: property.py 1664 2009-02-07 22:47:09Z cthedot $'
|
||||||
|
|
||||||
import xml.dom
|
from cssutils.helper import Deprecated
|
||||||
import cssutils
|
|
||||||
#import cssproperties
|
|
||||||
from cssutils.profiles import profiles
|
from cssutils.profiles import profiles
|
||||||
from cssvalue import CSSValue
|
from cssvalue import CSSValue
|
||||||
from cssutils.helper import Deprecated
|
import cssutils
|
||||||
|
import xml.dom
|
||||||
|
|
||||||
class Property(cssutils.util.Base):
|
class Property(cssutils.util.Base):
|
||||||
"""
|
"""A CSS property in a StyleDeclaration of a CSSStyleRule (cssutils).
|
||||||
(cssutils) a CSS property in a StyleDeclaration of a CSSStyleRule
|
|
||||||
|
|
||||||
Properties
|
Format::
|
||||||
==========
|
|
||||||
cssText
|
|
||||||
a parsable textual representation of this property
|
|
||||||
name
|
|
||||||
normalized name of the property, e.g. "color" when name is "c\olor"
|
|
||||||
(since 0.9.5)
|
|
||||||
literalname (since 0.9.5)
|
|
||||||
original name of the property in the source CSS which is not normalized
|
|
||||||
e.g. "C\\OLor"
|
|
||||||
cssValue
|
|
||||||
the relevant CSSValue instance for this property
|
|
||||||
value
|
|
||||||
the string value of the property, same as cssValue.cssText
|
|
||||||
priority
|
|
||||||
of the property (currently only u"important" or None)
|
|
||||||
literalpriority
|
|
||||||
original priority of the property in the source CSS which is not
|
|
||||||
normalized e.g. "IM\portant"
|
|
||||||
seqs
|
|
||||||
combination of a list for seq of name, a CSSValue object, and
|
|
||||||
a list for seq of priority (empty or [!important] currently)
|
|
||||||
valid
|
|
||||||
if this Property is valid
|
|
||||||
wellformed
|
|
||||||
if this Property is syntactically ok
|
|
||||||
|
|
||||||
DEPRECATED normalname (since 0.9.5)
|
|
||||||
normalized name of the property, e.g. "color" when name is "c\olor"
|
|
||||||
|
|
||||||
Format
|
|
||||||
======
|
|
||||||
::
|
|
||||||
|
|
||||||
property = name
|
property = name
|
||||||
: IDENT S*
|
: IDENT S*
|
||||||
@ -81,60 +44,67 @@ class Property(cssutils.util.Base):
|
|||||||
;
|
;
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, name=None, value=None, priority=u'', _mediaQuery=False):
|
def __init__(self, name=None, value=None, priority=u'',
|
||||||
|
_mediaQuery=False, _parent=None):
|
||||||
"""
|
"""
|
||||||
inits property
|
:param name:
|
||||||
|
|
||||||
name
|
|
||||||
a property name string (will be normalized)
|
a property name string (will be normalized)
|
||||||
value
|
:param value:
|
||||||
a property value string
|
a property value string
|
||||||
priority
|
:param priority:
|
||||||
an optional priority string which currently must be u'',
|
an optional priority string which currently must be u'',
|
||||||
u'!important' or u'important'
|
u'!important' or u'important'
|
||||||
_mediaQuery boolean
|
:param _mediaQuery:
|
||||||
if True value is optional as used by MediaQuery objects
|
if ``True`` value is optional (used by MediaQuery)
|
||||||
|
:param _parent:
|
||||||
|
the parent object, normally a
|
||||||
|
:class:`cssutils.css.CSSStyleDeclaration`
|
||||||
"""
|
"""
|
||||||
super(Property, self).__init__()
|
super(Property, self).__init__()
|
||||||
|
|
||||||
self.seqs = [[], None, []]
|
self.seqs = [[], None, []]
|
||||||
self.valid = False
|
|
||||||
self.wellformed = False
|
self.wellformed = False
|
||||||
self._mediaQuery = _mediaQuery
|
self._mediaQuery = _mediaQuery
|
||||||
|
self._parent = _parent
|
||||||
|
|
||||||
|
self._name = u''
|
||||||
|
self._literalname = u''
|
||||||
if name:
|
if name:
|
||||||
self.name = name
|
self.name = name
|
||||||
else:
|
|
||||||
self._name = u''
|
|
||||||
self._literalname = u''
|
|
||||||
self.__normalname = u'' # DEPRECATED
|
|
||||||
|
|
||||||
if value:
|
if value:
|
||||||
self.cssValue = value
|
self.cssValue = value
|
||||||
else:
|
else:
|
||||||
self.seqs[1] = CSSValue()
|
self.seqs[1] = CSSValue()
|
||||||
|
|
||||||
|
self._priority = u''
|
||||||
|
self._literalpriority = u''
|
||||||
if priority:
|
if priority:
|
||||||
self.priority = priority
|
self.priority = priority
|
||||||
else:
|
|
||||||
self._priority = u''
|
def __repr__(self):
|
||||||
self._literalpriority = u''
|
return "cssutils.css.%s(name=%r, value=%r, priority=%r)" % (
|
||||||
|
self.__class__.__name__,
|
||||||
|
self.literalname, self.cssValue.cssText, self.priority)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "<%s.%s object name=%r value=%r priority=%r valid=%r at 0x%x>" % (
|
||||||
|
self.__class__.__module__, self.__class__.__name__,
|
||||||
|
self.name, self.cssValue.cssText, self.priority,
|
||||||
|
self.valid, id(self))
|
||||||
|
|
||||||
def _getCssText(self):
|
def _getCssText(self):
|
||||||
"""
|
"""Return serialized property cssText."""
|
||||||
returns serialized property cssText
|
|
||||||
"""
|
|
||||||
return cssutils.ser.do_Property(self)
|
return cssutils.ser.do_Property(self)
|
||||||
|
|
||||||
def _setCssText(self, cssText):
|
def _setCssText(self, cssText):
|
||||||
"""
|
"""
|
||||||
DOMException on setting
|
:exceptions:
|
||||||
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
- NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
|
Raised if the specified CSS string value has a syntax error and
|
||||||
Raised if the rule is readonly.
|
is unparsable.
|
||||||
- SYNTAX_ERR: (self)
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
Raised if the specified CSS string value has a syntax error and
|
Raised if the rule is readonly.
|
||||||
is unparsable.
|
|
||||||
"""
|
"""
|
||||||
# check and prepare tokenlists for setting
|
# check and prepare tokenlists for setting
|
||||||
tokenizer = self._tokenize2(cssText)
|
tokenizer = self._tokenize2(cssText)
|
||||||
@ -180,6 +150,9 @@ class Property(cssutils.util.Base):
|
|||||||
self.cssValue = valuetokens
|
self.cssValue = valuetokens
|
||||||
self.priority = prioritytokens
|
self.priority = prioritytokens
|
||||||
|
|
||||||
|
# also invalid values are set!
|
||||||
|
self.validate()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self._log.error(u'Property: No property name found: %r.' %
|
self._log.error(u'Property: No property name found: %r.' %
|
||||||
self._valuestr(cssText))
|
self._valuestr(cssText))
|
||||||
@ -189,11 +162,10 @@ class Property(cssutils.util.Base):
|
|||||||
|
|
||||||
def _setName(self, name):
|
def _setName(self, name):
|
||||||
"""
|
"""
|
||||||
DOMException on setting
|
:exceptions:
|
||||||
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
- SYNTAX_ERR: (self)
|
Raised if the specified name has a syntax error and is
|
||||||
Raised if the specified name has a syntax error and is
|
unparsable.
|
||||||
unparsable.
|
|
||||||
"""
|
"""
|
||||||
# for closures: must be a mutable
|
# for closures: must be a mutable
|
||||||
new = {'literalname': None,
|
new = {'literalname': None,
|
||||||
@ -233,43 +205,42 @@ class Property(cssutils.util.Base):
|
|||||||
self.wellformed = True
|
self.wellformed = True
|
||||||
self._literalname = new['literalname']
|
self._literalname = new['literalname']
|
||||||
self._name = self._normalize(self._literalname)
|
self._name = self._normalize(self._literalname)
|
||||||
self.__normalname = self._name # DEPRECATED
|
|
||||||
self.seqs[0] = newseq
|
self.seqs[0] = newseq
|
||||||
|
|
||||||
# validate
|
# # validate
|
||||||
if self._name not in profiles.propertiesByProfile():
|
if self._name not in profiles.knownnames:
|
||||||
self.valid = False
|
# self.valid = False
|
||||||
tokenizer=self._tokenize2(name)
|
self._log.warn(u'Property: Unknown Property.',
|
||||||
self._log.warn(u'Property: Unknown Property: %r.' %
|
token=token, neverraise=True)
|
||||||
new['literalname'], token=token, neverraise=True)
|
|
||||||
else:
|
else:
|
||||||
self.valid = True
|
pass
|
||||||
if self.cssValue:
|
# self.valid = True
|
||||||
self.cssValue._propertyName = self._name
|
# if self.cssValue:
|
||||||
self.valid = self.cssValue.valid
|
# self.cssValue._propertyName = self._name
|
||||||
|
# #self.valid = self.cssValue.valid
|
||||||
else:
|
else:
|
||||||
self.wellformed = False
|
self.wellformed = False
|
||||||
|
|
||||||
name = property(lambda self: self._name, _setName,
|
name = property(lambda self: self._name, _setName,
|
||||||
doc="Name of this property")
|
doc="Name of this property.")
|
||||||
|
|
||||||
literalname = property(lambda self: self._literalname,
|
literalname = property(lambda self: self._literalname,
|
||||||
doc="Readonly literal (not normalized) name of this property")
|
doc="Readonly literal (not normalized) name "
|
||||||
|
"of this property")
|
||||||
|
|
||||||
def _getCSSValue(self):
|
def _getCSSValue(self):
|
||||||
return self.seqs[1]
|
return self.seqs[1]
|
||||||
|
|
||||||
def _setCSSValue(self, cssText):
|
def _setCSSValue(self, cssText):
|
||||||
"""
|
"""
|
||||||
see css.CSSValue
|
See css.CSSValue
|
||||||
|
|
||||||
DOMException on setting?
|
:exceptions:
|
||||||
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
- SYNTAX_ERR: (self)
|
|
||||||
Raised if the specified CSS string value has a syntax error
|
Raised if the specified CSS string value has a syntax error
|
||||||
(according to the attached property) or is unparsable.
|
(according to the attached property) or is unparsable.
|
||||||
- TODO: INVALID_MODIFICATION_ERR:
|
- :exc:`~xml.dom.InvalidModificationErr`:
|
||||||
Raised if the specified CSS string value represents a different
|
TODO: Raised if the specified CSS string value represents a different
|
||||||
type of values than the values allowed by the CSS property.
|
type of values than the values allowed by the CSS property.
|
||||||
"""
|
"""
|
||||||
if self._mediaQuery and not cssText:
|
if self._mediaQuery and not cssText:
|
||||||
@ -279,25 +250,24 @@ class Property(cssutils.util.Base):
|
|||||||
self.seqs[1] = CSSValue()
|
self.seqs[1] = CSSValue()
|
||||||
|
|
||||||
cssvalue = self.seqs[1]
|
cssvalue = self.seqs[1]
|
||||||
cssvalue._propertyName = self.name
|
|
||||||
cssvalue.cssText = cssText
|
cssvalue.cssText = cssText
|
||||||
if cssvalue._value and cssvalue.wellformed:
|
if cssvalue.wellformed: #cssvalue._value and
|
||||||
self.seqs[1] = cssvalue
|
self.seqs[1] = cssvalue
|
||||||
self.valid = self.valid and cssvalue.valid
|
|
||||||
self.wellformed = self.wellformed and cssvalue.wellformed
|
self.wellformed = self.wellformed and cssvalue.wellformed
|
||||||
|
|
||||||
cssValue = property(_getCSSValue, _setCSSValue,
|
cssValue = property(_getCSSValue, _setCSSValue,
|
||||||
doc="(cssutils) CSSValue object of this property")
|
doc="(cssutils) CSSValue object of this property")
|
||||||
|
|
||||||
|
|
||||||
def _getValue(self):
|
def _getValue(self):
|
||||||
if self.cssValue:
|
if self.cssValue:
|
||||||
return self.cssValue._value
|
return self.cssValue.cssText # _value # [0]
|
||||||
else:
|
else:
|
||||||
return u''
|
return u''
|
||||||
|
|
||||||
def _setValue(self, value):
|
def _setValue(self, value):
|
||||||
self.cssValue.cssText = value
|
self.cssValue.cssText = value
|
||||||
self.valid = self.valid and self.cssValue.valid
|
# self.valid = self.valid and self.cssValue.valid
|
||||||
self.wellformed = self.wellformed and self.cssValue.wellformed
|
self.wellformed = self.wellformed and self.cssValue.wellformed
|
||||||
|
|
||||||
value = property(_getValue, _setValue,
|
value = property(_getValue, _setValue,
|
||||||
@ -308,9 +278,7 @@ class Property(cssutils.util.Base):
|
|||||||
priority
|
priority
|
||||||
a string, currently either u'', u'!important' or u'important'
|
a string, currently either u'', u'!important' or u'important'
|
||||||
|
|
||||||
Format
|
Format::
|
||||||
======
|
|
||||||
::
|
|
||||||
|
|
||||||
prio
|
prio
|
||||||
: IMPORTANT_SYM S*
|
: IMPORTANT_SYM S*
|
||||||
@ -318,14 +286,13 @@ class Property(cssutils.util.Base):
|
|||||||
|
|
||||||
"!"{w}"important" {return IMPORTANT_SYM;}
|
"!"{w}"important" {return IMPORTANT_SYM;}
|
||||||
|
|
||||||
DOMException on setting
|
:exceptions:
|
||||||
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
- SYNTAX_ERR: (self)
|
Raised if the specified priority has a syntax error and is
|
||||||
Raised if the specified priority has a syntax error and is
|
unparsable.
|
||||||
unparsable.
|
In this case a priority not equal to None, "" or "!{w}important".
|
||||||
In this case a priority not equal to None, "" or "!{w}important".
|
As CSSOM defines CSSStyleDeclaration.getPropertyPriority resulting in
|
||||||
As CSSOM defines CSSStyleDeclaration.getPropertyPriority resulting in
|
u'important' this value is also allowed to set a Properties priority
|
||||||
u'important' this value is also allowed to set a Properties priority
|
|
||||||
"""
|
"""
|
||||||
if self._mediaQuery:
|
if self._mediaQuery:
|
||||||
self._priority = u''
|
self._priority = u''
|
||||||
@ -356,8 +323,7 @@ class Property(cssutils.util.Base):
|
|||||||
def _ident(expected, seq, token, tokenizer=None):
|
def _ident(expected, seq, token, tokenizer=None):
|
||||||
# "important"
|
# "important"
|
||||||
val = self._tokenvalue(token)
|
val = self._tokenvalue(token)
|
||||||
normalval = self._tokenvalue(token, normalize=True)
|
if 'important' == expected:
|
||||||
if 'important' == expected == normalval:
|
|
||||||
new['literalpriority'] = val
|
new['literalpriority'] = val
|
||||||
seq.append(val)
|
seq.append(val)
|
||||||
return 'EOF'
|
return 'EOF'
|
||||||
@ -378,38 +344,66 @@ class Property(cssutils.util.Base):
|
|||||||
if priority and not new['literalpriority']:
|
if priority and not new['literalpriority']:
|
||||||
wellformed = False
|
wellformed = False
|
||||||
self._log.info(u'Property: Invalid priority: %r.' %
|
self._log.info(u'Property: Invalid priority: %r.' %
|
||||||
self._valuestr(priority))
|
self._valuestr(priority))
|
||||||
|
|
||||||
if wellformed:
|
if wellformed:
|
||||||
self.wellformed = self.wellformed and wellformed
|
self.wellformed = self.wellformed and wellformed
|
||||||
self._literalpriority = new['literalpriority']
|
self._literalpriority = new['literalpriority']
|
||||||
self._priority = self._normalize(self.literalpriority)
|
self._priority = self._normalize(self.literalpriority)
|
||||||
self.seqs[2] = newseq
|
self.seqs[2] = newseq
|
||||||
|
# validate priority
|
||||||
# validate
|
|
||||||
if self._priority not in (u'', u'important'):
|
if self._priority not in (u'', u'important'):
|
||||||
self.valid = False
|
self._log.error(u'Property: No CSS priority value: %r.' %
|
||||||
self._log.info(u'Property: No CSS2 priority value: %r.' %
|
self._priority)
|
||||||
self._priority, neverraise=True)
|
|
||||||
|
|
||||||
priority = property(lambda self: self._priority, _setPriority,
|
priority = property(lambda self: self._priority, _setPriority,
|
||||||
doc="(cssutils) Priority of this property")
|
doc="Priority of this property.")
|
||||||
|
|
||||||
literalpriority = property(lambda self: self._literalpriority,
|
literalpriority = property(lambda self: self._literalpriority,
|
||||||
doc="Readonly literal (not normalized) priority of this property")
|
doc="Readonly literal (not normalized) priority of this property")
|
||||||
|
|
||||||
def __repr__(self):
|
def validate(self, profile=None):
|
||||||
return "cssutils.css.%s(name=%r, value=%r, priority=%r)" % (
|
"""Validate value against `profile`.
|
||||||
self.__class__.__name__,
|
|
||||||
self.literalname, self.cssValue.cssText, self.priority)
|
|
||||||
|
|
||||||
def __str__(self):
|
:param profile:
|
||||||
return "<%s.%s object name=%r value=%r priority=%r at 0x%x>" % (
|
A profile name used for validating. If no `profile` is given
|
||||||
self.__class__.__module__, self.__class__.__name__,
|
``Property.profiles
|
||||||
self.name, self.cssValue.cssText, self.priority, id(self))
|
"""
|
||||||
|
valid = False
|
||||||
|
|
||||||
@Deprecated(u'Use property ``name`` instead (since cssutils 0.9.5).')
|
if self.name and self.value:
|
||||||
def _getNormalname(self):
|
if profile is None:
|
||||||
return self.__normalname
|
usedprofile = cssutils.profiles.defaultprofile
|
||||||
normalname = property(_getNormalname,
|
else:
|
||||||
doc="DEPRECATED since 0.9.5, use name instead")
|
usedprofile = profile
|
||||||
|
|
||||||
|
if self.name in profiles.knownnames:
|
||||||
|
valid, validprofiles = profiles.validateWithProfile(self.name,
|
||||||
|
self.value,
|
||||||
|
usedprofile)
|
||||||
|
|
||||||
|
if not valid:
|
||||||
|
self._log.error(u'Property: Invalid value for "%s" property: %s: %s'
|
||||||
|
% (u'/'.join(validprofiles),
|
||||||
|
self.name,
|
||||||
|
self.value),
|
||||||
|
neverraise=True)
|
||||||
|
elif valid and (usedprofile and usedprofile not in validprofiles):
|
||||||
|
self._log.warn(u'Property: Not valid for profile "%s": %s: %s'
|
||||||
|
% (usedprofile, self.name, self.value),
|
||||||
|
neverraise=True)
|
||||||
|
|
||||||
|
if valid:
|
||||||
|
self._log.info(u'Property: Found valid "%s" property: %s: %s'
|
||||||
|
% (u'/'.join(validprofiles),
|
||||||
|
self.name,
|
||||||
|
self.value),
|
||||||
|
neverraise=True)
|
||||||
|
|
||||||
|
if self._priority not in (u'', u'important'):
|
||||||
|
valid = False
|
||||||
|
|
||||||
|
return valid
|
||||||
|
|
||||||
|
valid = property(validate, doc="Check if value of this property is valid "
|
||||||
|
"in the properties context.")
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
"""Selector is a single Selector of a CSSStyleRule SelectorList.
|
"""Selector is a single Selector of a CSSStyleRule SelectorList.
|
||||||
|
Partly implements http://www.w3.org/TR/css3-selectors/.
|
||||||
Partly implements
|
|
||||||
http://www.w3.org/TR/css3-selectors/
|
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
- .contains(selector)
|
- .contains(selector)
|
||||||
@ -9,45 +7,18 @@ TODO
|
|||||||
"""
|
"""
|
||||||
__all__ = ['Selector']
|
__all__ = ['Selector']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: selector.py 1429 2008-08-11 19:01:52Z cthedot $'
|
__version__ = '$Id: selector.py 1638 2009-01-13 20:39:33Z cthedot $'
|
||||||
|
|
||||||
import xml.dom
|
|
||||||
import cssutils
|
|
||||||
from cssutils.util import _SimpleNamespaces
|
from cssutils.util import _SimpleNamespaces
|
||||||
|
import cssutils
|
||||||
|
import xml.dom
|
||||||
|
|
||||||
class Selector(cssutils.util.Base2):
|
class Selector(cssutils.util.Base2):
|
||||||
"""
|
"""
|
||||||
(cssutils) a single selector in a SelectorList of a CSSStyleRule
|
(cssutils) a single selector in a :class:`~cssutils.css.SelectorList`
|
||||||
|
of a :class:`~cssutils.css.CSSStyleRule`.
|
||||||
|
|
||||||
Properties
|
Format::
|
||||||
==========
|
|
||||||
element
|
|
||||||
Effective element target of this selector
|
|
||||||
parentList: of type SelectorList, readonly
|
|
||||||
The SelectorList that contains this selector or None if this
|
|
||||||
Selector is not attached to a SelectorList.
|
|
||||||
selectorText
|
|
||||||
textual representation of this Selector
|
|
||||||
seq
|
|
||||||
sequence of Selector parts including comments
|
|
||||||
specificity (READONLY)
|
|
||||||
tuple of (a, b, c, d) where:
|
|
||||||
|
|
||||||
a
|
|
||||||
presence of style in document, always 0 if not used on a document
|
|
||||||
b
|
|
||||||
number of ID selectors
|
|
||||||
c
|
|
||||||
number of .class selectors
|
|
||||||
d
|
|
||||||
number of Element (type) selectors
|
|
||||||
|
|
||||||
wellformed
|
|
||||||
if this selector is wellformed regarding the Selector spec
|
|
||||||
|
|
||||||
Format
|
|
||||||
======
|
|
||||||
::
|
|
||||||
|
|
||||||
# implemented in SelectorList
|
# implemented in SelectorList
|
||||||
selectors_group
|
selectors_group
|
||||||
@ -150,14 +121,46 @@ class Selector(cssutils.util.Base2):
|
|||||||
|
|
||||||
self._readonly = readonly
|
self._readonly = readonly
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
if self.__getNamespaces():
|
||||||
|
st = (self.selectorText, self._getUsedNamespaces())
|
||||||
|
else:
|
||||||
|
st = self.selectorText
|
||||||
|
return u"cssutils.css.%s(selectorText=%r)" % (
|
||||||
|
self.__class__.__name__, st)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return u"<cssutils.css.%s object selectorText=%r specificity=%r _namespaces=%r at 0x%x>" % (
|
||||||
|
self.__class__.__name__, self.selectorText, self.specificity,
|
||||||
|
self._getUsedNamespaces(), id(self))
|
||||||
|
|
||||||
|
def _getUsedUris(self):
|
||||||
|
"Return list of actually used URIs in this Selector."
|
||||||
|
uris = set()
|
||||||
|
for item in self.seq:
|
||||||
|
type_, val = item.type, item.value
|
||||||
|
if type_.endswith(u'-selector') or type_ == u'universal' and \
|
||||||
|
type(val) == tuple and val[0] not in (None, u'*'):
|
||||||
|
uris.add(val[0])
|
||||||
|
return uris
|
||||||
|
|
||||||
|
def _getUsedNamespaces(self):
|
||||||
|
"Return actually used namespaces only."
|
||||||
|
useduris = self._getUsedUris()
|
||||||
|
namespaces = _SimpleNamespaces(log=self._log)
|
||||||
|
for p, uri in self._namespaces.items():
|
||||||
|
if uri in useduris:
|
||||||
|
namespaces[p] = uri
|
||||||
|
return namespaces
|
||||||
|
|
||||||
def __getNamespaces(self):
|
def __getNamespaces(self):
|
||||||
"uses own namespaces if not attached to a sheet, else the sheet's ones"
|
"Use own namespaces if not attached to a sheet, else the sheet's ones."
|
||||||
try:
|
try:
|
||||||
return self._parent.parentRule.parentStyleSheet.namespaces
|
return self._parent.parentRule.parentStyleSheet.namespaces
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return self.__namespaces
|
return self.__namespaces
|
||||||
|
|
||||||
_namespaces = property(__getNamespaces, doc="""if this Selector is attached
|
_namespaces = property(__getNamespaces, doc="""If this Selector is attached
|
||||||
to a CSSStyleSheet the namespaces of that sheet are mirrored here.
|
to a CSSStyleSheet the namespaces of that sheet are mirrored here.
|
||||||
While the Selector (or parent SelectorList or parentRule(s) of that are
|
While the Selector (or parent SelectorList or parentRule(s) of that are
|
||||||
not attached a own dict of {prefix: namespaceURI} is used.""")
|
not attached a own dict of {prefix: namespaceURI} is used.""")
|
||||||
@ -171,9 +174,7 @@ class Selector(cssutils.util.Base2):
|
|||||||
None if this Selector is not attached to a SelectorList.")
|
None if this Selector is not attached to a SelectorList.")
|
||||||
|
|
||||||
def _getSelectorText(self):
|
def _getSelectorText(self):
|
||||||
"""
|
"""Return serialized format."""
|
||||||
returns serialized format
|
|
||||||
"""
|
|
||||||
return cssutils.ser.do_css_Selector(self)
|
return cssutils.ser.do_css_Selector(self)
|
||||||
|
|
||||||
def _setSelectorText(self, selectorText):
|
def _setSelectorText(self, selectorText):
|
||||||
@ -183,14 +184,14 @@ class Selector(cssutils.util.Base2):
|
|||||||
Given namespaces are ignored if this object is attached to a
|
Given namespaces are ignored if this object is attached to a
|
||||||
CSSStyleSheet!
|
CSSStyleSheet!
|
||||||
|
|
||||||
:Exceptions:
|
:exceptions:
|
||||||
- `NAMESPACE_ERR`: (self)
|
- :exc:`~xml.dom.NamespaceErr`:
|
||||||
Raised if the specified selector uses an unknown namespace
|
Raised if the specified selector uses an unknown namespace
|
||||||
prefix.
|
prefix.
|
||||||
- `SYNTAX_ERR`: (self)
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
Raised if the specified CSS string value has a syntax error
|
Raised if the specified CSS string value has a syntax error
|
||||||
and is unparsable.
|
and is unparsable.
|
||||||
- `NO_MODIFICATION_ALLOWED_ERR`: (self)
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
Raised if this rule is readonly.
|
Raised if this rule is readonly.
|
||||||
"""
|
"""
|
||||||
self._checkReadonly()
|
self._checkReadonly()
|
||||||
@ -763,38 +764,17 @@ class Selector(cssutils.util.Base2):
|
|||||||
|
|
||||||
|
|
||||||
specificity = property(lambda self: self._specificity,
|
specificity = property(lambda self: self._specificity,
|
||||||
doc="Specificity of this selector (READONLY).")
|
doc="""Specificity of this selector (READONLY).
|
||||||
|
Tuple of (a, b, c, d) where:
|
||||||
|
|
||||||
|
a
|
||||||
|
presence of style in document, always 0 if not used on a document
|
||||||
|
b
|
||||||
|
number of ID selectors
|
||||||
|
c
|
||||||
|
number of .class selectors
|
||||||
|
d
|
||||||
|
number of Element (type) selectors
|
||||||
|
""")
|
||||||
|
|
||||||
wellformed = property(lambda self: bool(len(self.seq)))
|
wellformed = property(lambda self: bool(len(self.seq)))
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
if self.__getNamespaces():
|
|
||||||
st = (self.selectorText, self._getUsedNamespaces())
|
|
||||||
else:
|
|
||||||
st = self.selectorText
|
|
||||||
return u"cssutils.css.%s(selectorText=%r)" % (
|
|
||||||
self.__class__.__name__, st)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return u"<cssutils.css.%s object selectorText=%r specificity=%r _namespaces=%r at 0x%x>" % (
|
|
||||||
self.__class__.__name__, self.selectorText, self.specificity,
|
|
||||||
self._getUsedNamespaces(), id(self))
|
|
||||||
|
|
||||||
def _getUsedUris(self):
|
|
||||||
"returns list of actually used URIs in this Selector"
|
|
||||||
uris = set()
|
|
||||||
for item in self.seq:
|
|
||||||
type_, val = item.type, item.value
|
|
||||||
if type_.endswith(u'-selector') or type_ == u'universal' and \
|
|
||||||
type(val) == tuple and val[0] not in (None, u'*'):
|
|
||||||
uris.add(val[0])
|
|
||||||
return uris
|
|
||||||
|
|
||||||
def _getUsedNamespaces(self):
|
|
||||||
"returns actually used namespaces only"
|
|
||||||
useduris = self._getUsedUris()
|
|
||||||
namespaces = _SimpleNamespaces(log=self._log)
|
|
||||||
for p, uri in self._namespaces.items():
|
|
||||||
if uri in useduris:
|
|
||||||
namespaces[p] = uri
|
|
||||||
return namespaces
|
|
||||||
|
@ -17,37 +17,18 @@ TODO
|
|||||||
"""
|
"""
|
||||||
__all__ = ['SelectorList']
|
__all__ = ['SelectorList']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: selectorlist.py 1174 2008-03-20 17:43:07Z cthedot $'
|
__version__ = '$Id: selectorlist.py 1638 2009-01-13 20:39:33Z cthedot $'
|
||||||
|
|
||||||
import xml.dom
|
|
||||||
import cssutils
|
|
||||||
from selector import Selector
|
from selector import Selector
|
||||||
|
import cssutils
|
||||||
|
import xml.dom
|
||||||
|
|
||||||
class SelectorList(cssutils.util.Base, cssutils.util.ListSeq):
|
class SelectorList(cssutils.util.Base, cssutils.util.ListSeq):
|
||||||
"""
|
"""A list of :class:`~cssutils.css.Selector` objects
|
||||||
(cssutils) a list of Selectors of a CSSStyleRule
|
of a :class:`~cssutils.css.CSSStyleRule`."""
|
||||||
|
|
||||||
Properties
|
|
||||||
==========
|
|
||||||
length: of type unsigned long, readonly
|
|
||||||
The number of Selector elements in the list.
|
|
||||||
parentRule: of type CSSRule, readonly
|
|
||||||
The CSS rule that contains this selector list or None if this
|
|
||||||
list is not attached to a CSSRule.
|
|
||||||
selectorText: of type DOMString
|
|
||||||
The textual representation of the selector for the rule set. The
|
|
||||||
implementation may have stripped out insignificant whitespace while
|
|
||||||
parsing the selector.
|
|
||||||
seq: (internal use!)
|
|
||||||
A list of Selector objects
|
|
||||||
wellformed
|
|
||||||
if this selectorlist is wellformed regarding the Selector spec
|
|
||||||
"""
|
|
||||||
def __init__(self, selectorText=None, parentRule=None,
|
def __init__(self, selectorText=None, parentRule=None,
|
||||||
readonly=False):
|
readonly=False):
|
||||||
"""
|
"""
|
||||||
initializes SelectorList with optional selectorText
|
|
||||||
|
|
||||||
:Parameters:
|
:Parameters:
|
||||||
selectorText
|
selectorText
|
||||||
parsable list of Selectors
|
parsable list of Selectors
|
||||||
@ -63,8 +44,30 @@ class SelectorList(cssutils.util.Base, cssutils.util.ListSeq):
|
|||||||
|
|
||||||
self._readonly = readonly
|
self._readonly = readonly
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
if self._namespaces:
|
||||||
|
st = (self.selectorText, self._namespaces)
|
||||||
|
else:
|
||||||
|
st = self.selectorText
|
||||||
|
return "cssutils.css.%s(selectorText=%r)" % (
|
||||||
|
self.__class__.__name__, st)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "<cssutils.css.%s object selectorText=%r _namespaces=%r at 0x%x>" % (
|
||||||
|
self.__class__.__name__, self.selectorText, self._namespaces,
|
||||||
|
id(self))
|
||||||
|
|
||||||
|
def __setitem__(self, index, newSelector):
|
||||||
|
"""Overwrite ListSeq.__setitem__
|
||||||
|
|
||||||
|
Any duplicate Selectors are **not** removed.
|
||||||
|
"""
|
||||||
|
newSelector = self.__prepareset(newSelector)
|
||||||
|
if newSelector:
|
||||||
|
self.seq[index] = newSelector
|
||||||
|
|
||||||
def __prepareset(self, newSelector, namespaces=None):
|
def __prepareset(self, newSelector, namespaces=None):
|
||||||
"used by appendSelector and __setitem__"
|
"Used by appendSelector and __setitem__"
|
||||||
if not namespaces:
|
if not namespaces:
|
||||||
namespaces = {}
|
namespaces = {}
|
||||||
self._checkReadonly()
|
self._checkReadonly()
|
||||||
@ -75,26 +78,8 @@ class SelectorList(cssutils.util.Base, cssutils.util.ListSeq):
|
|||||||
newSelector._parent = self # maybe set twice but must be!
|
newSelector._parent = self # maybe set twice but must be!
|
||||||
return newSelector
|
return newSelector
|
||||||
|
|
||||||
def __setitem__(self, index, newSelector):
|
|
||||||
"""
|
|
||||||
overwrites ListSeq.__setitem__
|
|
||||||
|
|
||||||
Any duplicate Selectors are **not** removed.
|
|
||||||
"""
|
|
||||||
newSelector = self.__prepareset(newSelector)
|
|
||||||
if newSelector:
|
|
||||||
self.seq[index] = newSelector
|
|
||||||
|
|
||||||
def append(self, newSelector):
|
|
||||||
"same as appendSelector(newSelector)"
|
|
||||||
self.appendSelector(newSelector)
|
|
||||||
|
|
||||||
length = property(lambda self: len(self),
|
|
||||||
doc="The number of Selector elements in the list.")
|
|
||||||
|
|
||||||
|
|
||||||
def __getNamespaces(self):
|
def __getNamespaces(self):
|
||||||
"uses children namespaces if not attached to a sheet, else the sheet's ones"
|
"Use children namespaces if not attached to a sheet, else the sheet's ones."
|
||||||
try:
|
try:
|
||||||
return self.parentRule.parentStyleSheet.namespaces
|
return self.parentRule.parentStyleSheet.namespaces
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
@ -103,17 +88,67 @@ class SelectorList(cssutils.util.Base, cssutils.util.ListSeq):
|
|||||||
namespaces.update(selector._namespaces)
|
namespaces.update(selector._namespaces)
|
||||||
return namespaces
|
return namespaces
|
||||||
|
|
||||||
_namespaces = property(__getNamespaces, doc="""if this SelectorList is
|
def _getUsedUris(self):
|
||||||
|
"Used by CSSStyleSheet to check if @namespace rules are needed"
|
||||||
|
uris = set()
|
||||||
|
for s in self:
|
||||||
|
uris.update(s._getUsedUris())
|
||||||
|
return uris
|
||||||
|
|
||||||
|
_namespaces = property(__getNamespaces, doc="""If this SelectorList is
|
||||||
attached to a CSSStyleSheet the namespaces of that sheet are mirrored
|
attached to a CSSStyleSheet the namespaces of that sheet are mirrored
|
||||||
here. While the SelectorList (or parentRule(s) are
|
here. While the SelectorList (or parentRule(s) are
|
||||||
not attached the namespaces of all children Selectors are used.""")
|
not attached the namespaces of all children Selectors are used.""")
|
||||||
|
|
||||||
parentRule = property(lambda self: self._parentRule,
|
def append(self, newSelector):
|
||||||
doc="(DOM) The CSS rule that contains this SelectorList or\
|
"Same as :meth:`appendSelector`."
|
||||||
None if this SelectorList is not attached to a CSSRule.")
|
self.appendSelector(newSelector)
|
||||||
|
|
||||||
|
def appendSelector(self, newSelector):
|
||||||
|
"""
|
||||||
|
Append `newSelector` to this list (a string will be converted to a
|
||||||
|
:class:`~cssutils.css.Selector`).
|
||||||
|
|
||||||
|
:param newSelector:
|
||||||
|
comma-separated list of selectors (as a single string) or a tuple of
|
||||||
|
`(newSelector, dict-of-namespaces)`
|
||||||
|
:returns: New :class:`~cssutils.css.Selector` or ``None`` if
|
||||||
|
`newSelector` is not wellformed.
|
||||||
|
:exceptions:
|
||||||
|
- :exc:`~xml.dom.NamespaceErr`:
|
||||||
|
Raised if the specified selector uses an unknown namespace
|
||||||
|
prefix.
|
||||||
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
|
Raised if the specified CSS string value has a syntax error
|
||||||
|
and is unparsable.
|
||||||
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
|
Raised if this rule is readonly.
|
||||||
|
"""
|
||||||
|
self._checkReadonly()
|
||||||
|
|
||||||
|
# might be (selectorText, namespaces)
|
||||||
|
newSelector, namespaces = self._splitNamespacesOff(newSelector)
|
||||||
|
try:
|
||||||
|
# use parent's only if available
|
||||||
|
namespaces = self.parentRule.parentStyleSheet.namespaces
|
||||||
|
except AttributeError:
|
||||||
|
# use already present namespaces plus new given ones
|
||||||
|
_namespaces = self._namespaces
|
||||||
|
_namespaces.update(namespaces)
|
||||||
|
namespaces = _namespaces
|
||||||
|
|
||||||
|
newSelector = self.__prepareset(newSelector, namespaces)
|
||||||
|
if newSelector:
|
||||||
|
seq = self.seq[:]
|
||||||
|
del self.seq[:]
|
||||||
|
for s in seq:
|
||||||
|
if s.selectorText != newSelector.selectorText:
|
||||||
|
self.seq.append(s)
|
||||||
|
self.seq.append(newSelector)
|
||||||
|
return newSelector
|
||||||
|
|
||||||
def _getSelectorText(self):
|
def _getSelectorText(self):
|
||||||
"returns serialized format"
|
"Return serialized format."
|
||||||
return cssutils.ser.do_css_SelectorList(self)
|
return cssutils.ser.do_css_SelectorList(self)
|
||||||
|
|
||||||
def _setSelectorText(self, selectorText):
|
def _setSelectorText(self, selectorText):
|
||||||
@ -121,14 +156,14 @@ class SelectorList(cssutils.util.Base, cssutils.util.ListSeq):
|
|||||||
:param selectorText:
|
:param selectorText:
|
||||||
comma-separated list of selectors or a tuple of
|
comma-separated list of selectors or a tuple of
|
||||||
(selectorText, dict-of-namespaces)
|
(selectorText, dict-of-namespaces)
|
||||||
:Exceptions:
|
:exceptions:
|
||||||
- `NAMESPACE_ERR`: (Selector)
|
- :exc:`~xml.dom.NamespaceErr`:
|
||||||
Raised if the specified selector uses an unknown namespace
|
Raised if the specified selector uses an unknown namespace
|
||||||
prefix.
|
prefix.
|
||||||
- `SYNTAX_ERR`: (self)
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
Raised if the specified CSS string value has a syntax error
|
Raised if the specified CSS string value has a syntax error
|
||||||
and is unparsable.
|
and is unparsable.
|
||||||
- `NO_MODIFICATION_ALLOWED_ERR`: (self)
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
Raised if this rule is readonly.
|
Raised if this rule is readonly.
|
||||||
"""
|
"""
|
||||||
self._checkReadonly()
|
self._checkReadonly()
|
||||||
@ -184,66 +219,12 @@ class SelectorList(cssutils.util.Base, cssutils.util.ListSeq):
|
|||||||
doc="""(cssutils) The textual representation of the selector for
|
doc="""(cssutils) The textual representation of the selector for
|
||||||
a rule set.""")
|
a rule set.""")
|
||||||
|
|
||||||
|
length = property(lambda self: len(self),
|
||||||
|
doc="The number of :class:`~cssutils.css.Selector` objects in the list.")
|
||||||
|
|
||||||
|
parentRule = property(lambda self: self._parentRule,
|
||||||
|
doc="(DOM) The CSS rule that contains this SelectorList or "
|
||||||
|
"``None`` if this SelectorList is not attached to a CSSRule.")
|
||||||
|
|
||||||
wellformed = property(lambda self: bool(len(self.seq)))
|
wellformed = property(lambda self: bool(len(self.seq)))
|
||||||
|
|
||||||
def appendSelector(self, newSelector):
|
|
||||||
"""
|
|
||||||
Append newSelector (a string will be converted to a new
|
|
||||||
Selector).
|
|
||||||
|
|
||||||
:param newSelector:
|
|
||||||
comma-separated list of selectors or a tuple of
|
|
||||||
(selectorText, dict-of-namespaces)
|
|
||||||
:returns: New Selector or None if newSelector is not wellformed.
|
|
||||||
:Exceptions:
|
|
||||||
- `NAMESPACE_ERR`: (self)
|
|
||||||
Raised if the specified selector uses an unknown namespace
|
|
||||||
prefix.
|
|
||||||
- `SYNTAX_ERR`: (self)
|
|
||||||
Raised if the specified CSS string value has a syntax error
|
|
||||||
and is unparsable.
|
|
||||||
- `NO_MODIFICATION_ALLOWED_ERR`: (self)
|
|
||||||
Raised if this rule is readonly.
|
|
||||||
"""
|
|
||||||
self._checkReadonly()
|
|
||||||
|
|
||||||
# might be (selectorText, namespaces)
|
|
||||||
newSelector, namespaces = self._splitNamespacesOff(newSelector)
|
|
||||||
try:
|
|
||||||
# use parent's only if available
|
|
||||||
namespaces = self.parentRule.parentStyleSheet.namespaces
|
|
||||||
except AttributeError:
|
|
||||||
# use already present namespaces plus new given ones
|
|
||||||
_namespaces = self._namespaces
|
|
||||||
_namespaces.update(namespaces)
|
|
||||||
namespaces = _namespaces
|
|
||||||
|
|
||||||
newSelector = self.__prepareset(newSelector, namespaces)
|
|
||||||
if newSelector:
|
|
||||||
seq = self.seq[:]
|
|
||||||
del self.seq[:]
|
|
||||||
for s in seq:
|
|
||||||
if s.selectorText != newSelector.selectorText:
|
|
||||||
self.seq.append(s)
|
|
||||||
self.seq.append(newSelector)
|
|
||||||
return newSelector
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
if self._namespaces:
|
|
||||||
st = (self.selectorText, self._namespaces)
|
|
||||||
else:
|
|
||||||
st = self.selectorText
|
|
||||||
return "cssutils.css.%s(selectorText=%r)" % (
|
|
||||||
self.__class__.__name__, st)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "<cssutils.css.%s object selectorText=%r _namespaces=%r at 0x%x>" % (
|
|
||||||
self.__class__.__name__, self.selectorText, self._namespaces,
|
|
||||||
id(self))
|
|
||||||
|
|
||||||
def _getUsedUris(self):
|
|
||||||
"used by CSSStyleSheet to check if @namespace rules are needed"
|
|
||||||
uris = set()
|
|
||||||
for s in self:
|
|
||||||
uris.update(s._getUsedUris())
|
|
||||||
return uris
|
|
||||||
|
@ -12,42 +12,33 @@ open issues
|
|||||||
"""
|
"""
|
||||||
__all__ = ['CSSProductions', 'MACROS', 'PRODUCTIONS']
|
__all__ = ['CSSProductions', 'MACROS', 'PRODUCTIONS']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: cssproductions.py 1378 2008-07-15 20:02:19Z cthedot $'
|
__version__ = '$Id: cssproductions.py 1537 2008-12-03 14:37:10Z cthedot $'
|
||||||
|
|
||||||
# a complete list of css3 macros
|
# a complete list of css3 macros
|
||||||
MACROS = {
|
MACROS = {
|
||||||
'ident': r'[-]?{nmstart}{nmchar}*',
|
|
||||||
'name': r'{nmchar}+',
|
|
||||||
'nmstart': r'[_a-zA-Z]|{nonascii}|{escape}',
|
|
||||||
'nonascii': r'[^\0-\177]',
|
'nonascii': r'[^\0-\177]',
|
||||||
'unicode': r'\\[0-9a-f]{1,6}(?:{nl}|{wc})?',
|
'unicode': r'\\[0-9a-f]{1,6}(?:{nl}|{s})?',
|
||||||
|
# 'escape': r'{unicode}|\\[ -~\200-\4177777]',
|
||||||
'escape': r'{unicode}|\\[ -~\200-\777]',
|
'escape': r'{unicode}|\\[ -~\200-\777]',
|
||||||
# 'escape': r'{unicode}|\\[ -~\200-\4177777]',
|
'nmstart': r'[_a-zA-Z]|{nonascii}|{escape}',
|
||||||
'nmchar': r'[-_a-zA-Z0-9]|{nonascii}|{escape}',
|
'nmchar': r'[-_a-zA-Z0-9]|{nonascii}|{escape}',
|
||||||
|
'string1': r'"([^\n\r\f\\"]|\\{nl}|{escape})*"',
|
||||||
'num': r'[0-9]*\.[0-9]+|[0-9]+', #r'[-]?\d+|[-]?\d*\.\d+',
|
'string2': r"'([^\n\r\f\\']|\\{nl}|{escape})*'",
|
||||||
'string': r"""\'({stringesc1}|{stringchar}|")*\'""" + "|" + '''\"({stringesc2}|{stringchar}|')*\"''',
|
|
||||||
# seems an error in CSS 3 but is allowed in CSS 2.1
|
|
||||||
'stringesc1' : r"\\'",
|
|
||||||
'stringesc2' : r'\\"',
|
|
||||||
|
|
||||||
'stringchar': r'{urlchar}| |\\{nl}',
|
|
||||||
|
|
||||||
# urlchar ::= [#x9#x21#x23-#x26#x27-#x7E] | nonascii | escape
|
|
||||||
# 0x27 is "'" which should not be in here..., should ) be in here???
|
|
||||||
'urlchar': r'[\x09\x21\x23-\x26\x28-\x7E]|{nonascii}|{escape}',
|
|
||||||
|
|
||||||
# from CSS2.1
|
|
||||||
'invalid': r'{invalid1}|{invalid2}',
|
|
||||||
'invalid1': r'\"([^\n\r\f\\"]|\\{nl}|{escape})*',
|
'invalid1': r'\"([^\n\r\f\\"]|\\{nl}|{escape})*',
|
||||||
'invalid2': r"\'([^\n\r\f\\']|\\{nl}|{escape})*",
|
'invalid2': r"\'([^\n\r\f\\']|\\{nl}|{escape})*",
|
||||||
|
|
||||||
# \r\n should be counted as one char see unicode above
|
|
||||||
'nl': r'\n|\r\n|\r|\f',
|
|
||||||
'w': r'{wc}*',
|
|
||||||
'wc': r'\t|\r|\n|\f|\x20',
|
|
||||||
|
|
||||||
'comment': r'\/\*[^*]*\*+([^/][^*]*\*+)*\/',
|
'comment': r'\/\*[^*]*\*+([^/][^*]*\*+)*\/',
|
||||||
|
'ident': r'[-]?{nmstart}{nmchar}*',
|
||||||
|
'name': r'{nmchar}+',
|
||||||
|
'num': r'[0-9]*\.[0-9]+|[0-9]+', #r'[-]?\d+|[-]?\d*\.\d+',
|
||||||
|
'string': r'{string1}|{string2}',
|
||||||
|
# from CSS2.1
|
||||||
|
'invalid': r'{invalid1}|{invalid2}',
|
||||||
|
'url': r'[\x09\x21\x23-\x26\x28\x2a-\x7E]|{nonascii}|{escape}',
|
||||||
|
|
||||||
|
's': r'\t|\r|\n|\f|\x20',
|
||||||
|
'w': r'{s}*',
|
||||||
|
'nl': r'\n|\r\n|\r|\f',
|
||||||
|
|
||||||
'A': r'A|a|\\0{0,4}(?:41|61)(?:\r\n|[ \t\r\n\f])?',
|
'A': r'A|a|\\0{0,4}(?:41|61)(?:\r\n|[ \t\r\n\f])?',
|
||||||
'C': r'C|c|\\0{0,4}(?:43|63)(?:\r\n|[ \t\r\n\f])?',
|
'C': r'C|c|\\0{0,4}(?:43|63)(?:\r\n|[ \t\r\n\f])?',
|
||||||
@ -77,8 +68,8 @@ MACROS = {
|
|||||||
PRODUCTIONS = [
|
PRODUCTIONS = [
|
||||||
('BOM', r'\xFEFF'), # will only be checked at beginning of CSS
|
('BOM', r'\xFEFF'), # will only be checked at beginning of CSS
|
||||||
|
|
||||||
('S', r'{wc}+'), # 1st in list of general productions
|
('S', r'{s}+'), # 1st in list of general productions
|
||||||
('URI', r'{U}{R}{L}\({w}({string}|{urlchar}*){w}\)'),
|
('URI', r'{U}{R}{L}\({w}({string}|{url}*){w}\)'),
|
||||||
('FUNCTION', r'{ident}\('),
|
('FUNCTION', r'{ident}\('),
|
||||||
('IDENT', r'{ident}'),
|
('IDENT', r'{ident}'),
|
||||||
('STRING', r'{string}'),
|
('STRING', r'{string}'),
|
||||||
|
@ -16,12 +16,12 @@ log
|
|||||||
"""
|
"""
|
||||||
__all__ = ['ErrorHandler']
|
__all__ = ['ErrorHandler']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: errorhandler.py 1361 2008-07-13 18:12:40Z cthedot $'
|
__version__ = '$Id: errorhandler.py 1560 2008-12-14 16:13:16Z cthedot $'
|
||||||
|
|
||||||
|
from helper import Deprecated
|
||||||
import logging
|
import logging
|
||||||
import urllib2
|
import urllib2
|
||||||
import xml.dom
|
import xml.dom
|
||||||
from helper import Deprecated
|
|
||||||
|
|
||||||
class _ErrorHandler(object):
|
class _ErrorHandler(object):
|
||||||
"""
|
"""
|
||||||
@ -74,17 +74,22 @@ class _ErrorHandler(object):
|
|||||||
handles all calls
|
handles all calls
|
||||||
logs or raises exception
|
logs or raises exception
|
||||||
"""
|
"""
|
||||||
|
line, col = None, None
|
||||||
if token:
|
if token:
|
||||||
if isinstance(token, tuple):
|
if isinstance(token, tuple):
|
||||||
msg = u'%s [%s:%s: %s]' % (
|
value, line, col = token[1], token[2], token[3]
|
||||||
msg, token[2], token[3], token[1])
|
|
||||||
else:
|
else:
|
||||||
msg = u'%s [%s:%s: %s]' % (
|
value, line, col = token.value, token.line, token.col
|
||||||
msg, token.line, token.col, token.value)
|
msg = u'%s [%s:%s: %s]' % (
|
||||||
|
msg, line, col, value)
|
||||||
|
|
||||||
if error and self.raiseExceptions and not neverraise:
|
if error and self.raiseExceptions and not neverraise:
|
||||||
if isinstance(error, urllib2.HTTPError) or isinstance(error, urllib2.URLError):
|
if isinstance(error, urllib2.HTTPError) or isinstance(error, urllib2.URLError):
|
||||||
raise error
|
raise
|
||||||
|
elif issubclass(error, xml.dom.DOMException):
|
||||||
|
error.line = line
|
||||||
|
error.col = col
|
||||||
|
raise error(msg, line, col)
|
||||||
else:
|
else:
|
||||||
raise error(msg)
|
raise error(msg)
|
||||||
else:
|
else:
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
"""cssutils helper
|
"""cssutils helper
|
||||||
"""
|
"""
|
||||||
__all__ = ['Deprecated', 'normalize']
|
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: errorhandler.py 1234 2008-05-22 20:26:12Z cthedot $'
|
__version__ = '$Id: errorhandler.py 1234 2008-05-22 20:26:12Z cthedot $'
|
||||||
|
|
||||||
@ -32,7 +31,6 @@ class Deprecated(object):
|
|||||||
|
|
||||||
# simple escapes, all non unicodes
|
# simple escapes, all non unicodes
|
||||||
_simpleescapes = re.compile(ur'(\\[^0-9a-fA-F])').sub
|
_simpleescapes = re.compile(ur'(\\[^0-9a-fA-F])').sub
|
||||||
|
|
||||||
def normalize(x):
|
def normalize(x):
|
||||||
"""
|
"""
|
||||||
normalizes x, namely:
|
normalizes x, namely:
|
||||||
@ -49,3 +47,81 @@ def normalize(x):
|
|||||||
return x.lower()
|
return x.lower()
|
||||||
else:
|
else:
|
||||||
return x
|
return x
|
||||||
|
|
||||||
|
def pushtoken(token, tokens):
|
||||||
|
"""Return new generator starting with token followed by all tokens in
|
||||||
|
``tokens``"""
|
||||||
|
# TODO: may use itertools.chain?
|
||||||
|
yield token
|
||||||
|
for x in tokens:
|
||||||
|
yield x
|
||||||
|
|
||||||
|
def string(value):
|
||||||
|
"""
|
||||||
|
Serialize value with quotes e.g.::
|
||||||
|
|
||||||
|
``a \'string`` => ``'a \'string'``
|
||||||
|
"""
|
||||||
|
# \n = 0xa, \r = 0xd, \f = 0xc
|
||||||
|
value = value.replace(u'\n', u'\\a ').replace(
|
||||||
|
u'\r', u'\\d ').replace(
|
||||||
|
u'\f', u'\\c ').replace(
|
||||||
|
u'"', u'\\"')
|
||||||
|
|
||||||
|
return u'"%s"' % value
|
||||||
|
|
||||||
|
def stringvalue(string):
|
||||||
|
"""
|
||||||
|
Retrieve actual value of string without quotes. Escaped
|
||||||
|
quotes inside the value are resolved, e.g.::
|
||||||
|
|
||||||
|
``'a \'string'`` => ``a 'string``
|
||||||
|
"""
|
||||||
|
return string.replace('\\'+string[0], string[0])[1:-1]
|
||||||
|
|
||||||
|
_match_forbidden_in_uri = re.compile(ur'''.*?[\(\)\s\;,'"]''', re.U).match
|
||||||
|
def uri(value):
|
||||||
|
"""
|
||||||
|
Serialize value by adding ``url()`` and with quotes if needed e.g.::
|
||||||
|
|
||||||
|
``"`` => ``url("\"")``
|
||||||
|
"""
|
||||||
|
if _match_forbidden_in_uri(value):
|
||||||
|
value = string(value)
|
||||||
|
return u'url(%s)' % value
|
||||||
|
|
||||||
|
def urivalue(uri):
|
||||||
|
"""
|
||||||
|
Return actual content without surrounding "url(" and ")"
|
||||||
|
and removed surrounding quotes too including contained
|
||||||
|
escapes of quotes, e.g.::
|
||||||
|
|
||||||
|
``url("\"")`` => ``"``
|
||||||
|
"""
|
||||||
|
uri = uri[uri.find('(')+1:-1].strip()
|
||||||
|
if uri and (uri[0] in '\'"') and (uri[0] == uri[-1]):
|
||||||
|
return stringvalue(uri)
|
||||||
|
else:
|
||||||
|
return uri
|
||||||
|
|
||||||
|
def normalnumber(num):
|
||||||
|
"""
|
||||||
|
Return normalized number as string.
|
||||||
|
"""
|
||||||
|
sign = ''
|
||||||
|
if num.startswith('-'):
|
||||||
|
sign = '-'
|
||||||
|
num = num[1:]
|
||||||
|
elif num.startswith('+'):
|
||||||
|
num = num[1:]
|
||||||
|
|
||||||
|
if float(num) == 0.0:
|
||||||
|
return '0'
|
||||||
|
else:
|
||||||
|
if num.find('.') == -1:
|
||||||
|
return sign + str(int(num))
|
||||||
|
else:
|
||||||
|
a, b = num.split('.')
|
||||||
|
if not a:
|
||||||
|
a = '0'
|
||||||
|
return '%s%s.%s' % (sign, int(a), b)
|
||||||
|
@ -1,31 +1,26 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
"""a validating CSSParser
|
"""A validating CSSParser"""
|
||||||
"""
|
|
||||||
__all__ = ['CSSParser']
|
__all__ = ['CSSParser']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: parse.py 1418 2008-08-09 19:27:50Z cthedot $'
|
__version__ = '$Id: parse.py 1656 2009-02-03 20:31:06Z cthedot $'
|
||||||
|
|
||||||
import codecs
|
|
||||||
import os
|
|
||||||
import urllib
|
|
||||||
from helper import Deprecated
|
from helper import Deprecated
|
||||||
import tokenize2
|
import codecs
|
||||||
import cssutils
|
import cssutils
|
||||||
|
import os
|
||||||
|
import tokenize2
|
||||||
|
import urllib
|
||||||
|
|
||||||
class CSSParser(object):
|
class CSSParser(object):
|
||||||
"""
|
"""Parse a CSS StyleSheet from URL, string or file and return a DOM Level 2
|
||||||
parses a CSS StyleSheet string or file and
|
CSS StyleSheet object.
|
||||||
returns a DOM Level 2 CSS StyleSheet object
|
|
||||||
|
|
||||||
Usage::
|
Usage::
|
||||||
|
|
||||||
parser = CSSParser()
|
parser = CSSParser()
|
||||||
|
|
||||||
# optionally
|
# optionally
|
||||||
parser.setFetcher(fetcher)
|
parser.setFetcher(fetcher)
|
||||||
|
|
||||||
sheet = parser.parseFile('test1.css', 'ascii')
|
sheet = parser.parseFile('test1.css', 'ascii')
|
||||||
|
|
||||||
print sheet.cssText
|
print sheet.cssText
|
||||||
"""
|
"""
|
||||||
def __init__(self, log=None, loglevel=None, raiseExceptions=None,
|
def __init__(self, log=None, loglevel=None, raiseExceptions=None,
|
||||||
@ -40,7 +35,7 @@ class CSSParser(object):
|
|||||||
parsing. Later while working with the resulting sheets
|
parsing. Later while working with the resulting sheets
|
||||||
the setting used in cssutils.log.raiseExeptions is used
|
the setting used in cssutils.log.raiseExeptions is used
|
||||||
fetcher
|
fetcher
|
||||||
see ``setFetchUrl(fetcher)``
|
see ``setFetcher(fetcher)``
|
||||||
"""
|
"""
|
||||||
if log is not None:
|
if log is not None:
|
||||||
cssutils.log.setLog(log)
|
cssutils.log.setLog(log)
|
||||||
@ -69,26 +64,28 @@ class CSSParser(object):
|
|||||||
|
|
||||||
def parseString(self, cssText, encoding=None, href=None, media=None,
|
def parseString(self, cssText, encoding=None, href=None, media=None,
|
||||||
title=None):
|
title=None):
|
||||||
"""Return parsed CSSStyleSheet from given string cssText.
|
"""Parse `cssText` as :class:`~cssutils.css.CSSStyleSheet`.
|
||||||
Raises errors during retrieving (e.g. UnicodeDecodeError).
|
Errors may be raised (e.g. UnicodeDecodeError).
|
||||||
|
|
||||||
cssText
|
:param cssText:
|
||||||
CSS string to parse
|
CSS string to parse
|
||||||
encoding
|
:param encoding:
|
||||||
If ``None`` the encoding will be read from BOM or an @charset
|
If ``None`` the encoding will be read from BOM or an @charset
|
||||||
rule or defaults to UTF-8.
|
rule or defaults to UTF-8.
|
||||||
If given overrides any found encoding including the ones for
|
If given overrides any found encoding including the ones for
|
||||||
imported sheets.
|
imported sheets.
|
||||||
It also will be used to decode ``cssText`` if given as a (byte)
|
It also will be used to decode `cssText` if given as a (byte)
|
||||||
string.
|
string.
|
||||||
href
|
:param href:
|
||||||
The href attribute to assign to the parsed style sheet.
|
The ``href`` attribute to assign to the parsed style sheet.
|
||||||
Used to resolve other urls in the parsed sheet like @import hrefs
|
Used to resolve other urls in the parsed sheet like @import hrefs.
|
||||||
media
|
:param media:
|
||||||
The media attribute to assign to the parsed style sheet
|
The ``media`` attribute to assign to the parsed style sheet
|
||||||
(may be a MediaList, list or a string)
|
(may be a MediaList, list or a string).
|
||||||
title
|
:param title:
|
||||||
The title attribute to assign to the parsed style sheet
|
The ``title`` attribute to assign to the parsed style sheet.
|
||||||
|
:returns:
|
||||||
|
:class:`~cssutils.css.CSSStyleSheet`.
|
||||||
"""
|
"""
|
||||||
self.__parseSetting(True)
|
self.__parseSetting(True)
|
||||||
if isinstance(cssText, str):
|
if isinstance(cssText, str):
|
||||||
@ -107,23 +104,23 @@ class CSSParser(object):
|
|||||||
|
|
||||||
def parseFile(self, filename, encoding=None,
|
def parseFile(self, filename, encoding=None,
|
||||||
href=None, media=None, title=None):
|
href=None, media=None, title=None):
|
||||||
"""Retrieve and return a CSSStyleSheet from given filename.
|
"""Retrieve content from `filename` and parse it. Errors may be raised
|
||||||
Raises errors during retrieving (e.g. IOError).
|
(e.g. IOError).
|
||||||
|
|
||||||
filename
|
:param filename:
|
||||||
of the CSS file to parse, if no ``href`` is given filename is
|
of the CSS file to parse, if no `href` is given filename is
|
||||||
converted to a (file:) URL and set as ``href`` of resulting
|
converted to a (file:) URL and set as ``href`` of resulting
|
||||||
stylesheet.
|
stylesheet.
|
||||||
If href is given it is set as ``sheet.href``. Either way
|
If `href` is given it is set as ``sheet.href``. Either way
|
||||||
``sheet.href`` is used to resolve e.g. stylesheet imports via
|
``sheet.href`` is used to resolve e.g. stylesheet imports via
|
||||||
@import rules.
|
@import rules.
|
||||||
encoding
|
:param encoding:
|
||||||
Value ``None`` defaults to encoding detection via BOM or an
|
Value ``None`` defaults to encoding detection via BOM or an
|
||||||
@charset rule.
|
@charset rule.
|
||||||
Other values override detected encoding for the sheet at
|
Other values override detected encoding for the sheet at
|
||||||
``filename`` including any imported sheets.
|
`filename` including any imported sheets.
|
||||||
|
:returns:
|
||||||
for other parameters see ``parseString``
|
:class:`~cssutils.css.CSSStyleSheet`.
|
||||||
"""
|
"""
|
||||||
if not href:
|
if not href:
|
||||||
# prepend // for file URL, urllib does not do this?
|
# prepend // for file URL, urllib does not do this?
|
||||||
@ -134,19 +131,19 @@ class CSSParser(object):
|
|||||||
href=href, media=media, title=title)
|
href=href, media=media, title=title)
|
||||||
|
|
||||||
def parseUrl(self, href, encoding=None, media=None, title=None):
|
def parseUrl(self, href, encoding=None, media=None, title=None):
|
||||||
"""Retrieve and return a CSSStyleSheet from given href (an URL).
|
"""Retrieve content from URL `href` and parse it. Errors may be raised
|
||||||
In case of any errors while reading the URL returns None.
|
(e.g. URLError).
|
||||||
|
|
||||||
href
|
:param href:
|
||||||
URL of the CSS file to parse, will also be set as ``href`` of
|
URL of the CSS file to parse, will also be set as ``href`` of
|
||||||
resulting stylesheet
|
resulting stylesheet
|
||||||
encoding
|
:param encoding:
|
||||||
Value ``None`` defaults to encoding detection via HTTP, BOM or an
|
Value ``None`` defaults to encoding detection via HTTP, BOM or an
|
||||||
@charset rule.
|
@charset rule.
|
||||||
A value overrides detected encoding for the sheet at ``href``
|
A value overrides detected encoding for the sheet at ``href``
|
||||||
including any imported sheets.
|
including any imported sheets.
|
||||||
|
:returns:
|
||||||
for other parameters see ``parseString``
|
:class:`~cssutils.css.CSSStyleSheet`.
|
||||||
"""
|
"""
|
||||||
encoding, enctype, text = cssutils.util._readUrl(href,
|
encoding, enctype, text = cssutils.util._readUrl(href,
|
||||||
overrideEncoding=encoding)
|
overrideEncoding=encoding)
|
||||||
@ -160,20 +157,24 @@ class CSSParser(object):
|
|||||||
|
|
||||||
def setFetcher(self, fetcher=None):
|
def setFetcher(self, fetcher=None):
|
||||||
"""Replace the default URL fetch function with a custom one.
|
"""Replace the default URL fetch function with a custom one.
|
||||||
The fetcher function gets a single parameter
|
|
||||||
|
|
||||||
``url``
|
:param fetcher:
|
||||||
the URL to read
|
A function which gets a single parameter
|
||||||
|
|
||||||
and returns ``(encoding, content)`` where ``encoding`` is the HTTP
|
``url``
|
||||||
charset normally given via the Content-Type header (which may simply
|
the URL to read
|
||||||
omit the charset) and ``content`` being the (byte) string content.
|
|
||||||
The Mimetype should be 'text/css' but this has to be checked by the
|
|
||||||
fetcher itself (the default fetcher emits a warning if encountering
|
|
||||||
a different mimetype).
|
|
||||||
|
|
||||||
Calling ``setFetcher`` with ``fetcher=None`` resets cssutils
|
and must return ``(encoding, content)`` where ``encoding`` is the
|
||||||
to use its default function.
|
HTTP charset normally given via the Content-Type header (which may
|
||||||
|
simply omit the charset in which case ``encoding`` would be
|
||||||
|
``None``) and ``content`` being the string (or unicode) content.
|
||||||
|
|
||||||
|
The Mimetype should be 'text/css' but this has to be checked by the
|
||||||
|
fetcher itself (the default fetcher emits a warning if encountering
|
||||||
|
a different mimetype).
|
||||||
|
|
||||||
|
Calling ``setFetcher`` with ``fetcher=None`` resets cssutils
|
||||||
|
to use its default function.
|
||||||
"""
|
"""
|
||||||
self.__fetcher = fetcher
|
self.__fetcher = fetcher
|
||||||
|
|
||||||
|
@ -19,100 +19,152 @@ __docformat__ = 'restructuredtext'
|
|||||||
__version__ = '$Id: parse.py 1418 2008-08-09 19:27:50Z cthedot $'
|
__version__ = '$Id: parse.py 1418 2008-08-09 19:27:50Z cthedot $'
|
||||||
|
|
||||||
import cssutils
|
import cssutils
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
class ParseError(Exception):
|
class ParseError(Exception):
|
||||||
"""Base Exception class for ProdParser (used internally)."""
|
"""Base Exception class for ProdParser (used internally)."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class Done(ParseError):
|
||||||
|
"""Raised if Sequence or Choice is finished and no more Prods left."""
|
||||||
|
pass
|
||||||
|
|
||||||
class Exhausted(ParseError):
|
class Exhausted(ParseError):
|
||||||
"""Raised if Sequence or Choice is done."""
|
"""Raised if Sequence or Choice is finished but token is given."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Missing(ParseError):
|
||||||
|
"""Raised if Sequence or Choice is not finished but no matching token given."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class NoMatch(ParseError):
|
class NoMatch(ParseError):
|
||||||
"""Raised if Sequence or Choice do not match."""
|
"""Raised if nothing in Sequence or Choice does match."""
|
||||||
pass
|
|
||||||
|
|
||||||
class MissingToken(ParseError):
|
|
||||||
"""Raised if Sequence or Choice are not exhausted."""
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Choice(object):
|
class Choice(object):
|
||||||
"""A Choice of productions (Sequence or single Prod)."""
|
"""A Choice of productions (Sequence or single Prod)."""
|
||||||
def __init__(self, prods):
|
|
||||||
|
def __init__(self, *prods, **options):
|
||||||
"""
|
"""
|
||||||
prods
|
*prods
|
||||||
Prod or Sequence objects
|
Prod or Sequence objects
|
||||||
|
options:
|
||||||
|
optional=False
|
||||||
"""
|
"""
|
||||||
self._prods = prods
|
self._prods = prods
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.optional = options['optional']
|
||||||
|
except KeyError, e:
|
||||||
|
for p in self._prods:
|
||||||
|
if p.optional:
|
||||||
|
self.optional = True
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.optional = False
|
||||||
|
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
"""Start Choice from zero"""
|
||||||
self._exhausted = False
|
self._exhausted = False
|
||||||
|
|
||||||
|
def matches(self, token):
|
||||||
|
"""Check if token matches"""
|
||||||
|
for prod in self._prods:
|
||||||
|
if prod.matches(token):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def nextProd(self, token):
|
def nextProd(self, token):
|
||||||
"""
|
"""
|
||||||
Return:
|
Return:
|
||||||
|
|
||||||
- next matching Prod or Sequence
|
- next matching Prod or Sequence
|
||||||
- raises ParseError if nothing matches
|
- ``None`` if any Prod or Sequence is optional and no token matched
|
||||||
- raises Exhausted if choice already done
|
- raise ParseError if nothing matches and all are mandatory
|
||||||
|
- raise Exhausted if choice already done
|
||||||
|
|
||||||
``token`` may be None but this occurs when no tokens left."""
|
``token`` may be None but this occurs when no tokens left."""
|
||||||
if not self._exhausted:
|
if not self._exhausted:
|
||||||
|
optional = False
|
||||||
for x in self._prods:
|
for x in self._prods:
|
||||||
if isinstance(x, Prod):
|
if x.matches(token):
|
||||||
test = x
|
self._exhausted = True
|
||||||
else:
|
x.reset()
|
||||||
# nested Sequence matches if 1st prod matches
|
return x
|
||||||
test = x.first()
|
elif x.optional:
|
||||||
try:
|
optional = True
|
||||||
if test.matches(token):
|
|
||||||
self._exhausted = True
|
|
||||||
return x
|
|
||||||
except ParseError, e:
|
|
||||||
# do not raise if other my match
|
|
||||||
continue
|
|
||||||
else:
|
else:
|
||||||
# None matched
|
if not optional:
|
||||||
raise ParseError(u'No match in choice')
|
# None matched but also None is optional
|
||||||
else:
|
raise ParseError(u'No match in %s' % self)
|
||||||
|
elif token:
|
||||||
raise Exhausted(u'Extra token')
|
raise Exhausted(u'Extra token')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return u'Choice(%s)' % u', '.join([str(x) for x in self._prods])
|
||||||
|
|
||||||
|
|
||||||
class Sequence(object):
|
class Sequence(object):
|
||||||
"""A Sequence of productions (Choice or single Prod)."""
|
"""A Sequence of productions (Choice or single Prod)."""
|
||||||
def __init__(self, prods, minmax=None):
|
def __init__(self, *prods, **options):
|
||||||
"""
|
"""
|
||||||
prods
|
*prods
|
||||||
Prod or Sequence objects
|
Prod or Sequence objects
|
||||||
minmax = lambda: (1, 1)
|
**options:
|
||||||
callback returning number of times this sequence may run
|
minmax = lambda: (1, 1)
|
||||||
|
callback returning number of times this sequence may run
|
||||||
"""
|
"""
|
||||||
self._prods = prods
|
self._prods = prods
|
||||||
if not minmax:
|
try:
|
||||||
|
minmax = options['minmax']
|
||||||
|
except KeyError:
|
||||||
minmax = lambda: (1, 1)
|
minmax = lambda: (1, 1)
|
||||||
|
|
||||||
self._min, self._max = minmax()
|
self._min, self._max = minmax()
|
||||||
|
if self._max is None:
|
||||||
|
# unlimited
|
||||||
|
try:
|
||||||
|
# py2.6/3
|
||||||
|
self._max = sys.maxsize
|
||||||
|
except AttributeError:
|
||||||
|
# py<2.6
|
||||||
|
self._max = sys.maxint
|
||||||
|
|
||||||
self._number = len(self._prods)
|
self._prodcount = len(self._prods)
|
||||||
self._round = 1 # 1 based!
|
self.reset()
|
||||||
self._pos = 0
|
|
||||||
|
|
||||||
def first(self):
|
def matches(self, token):
|
||||||
"""Return 1st element of Sequence, used by Choice"""
|
"""Called by Choice to try to find if Sequence matches."""
|
||||||
# TODO: current impl first only if 1st if an prod!
|
|
||||||
for prod in self._prods:
|
for prod in self._prods:
|
||||||
if not prod.optional:
|
if prod.matches(token):
|
||||||
return prod
|
return True
|
||||||
|
try:
|
||||||
|
if not prod.optional:
|
||||||
|
break
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
return False
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
"""Reset this Sequence if it is nested."""
|
||||||
|
self._roundstarted = False
|
||||||
|
self._i = 0
|
||||||
|
self._round = 0
|
||||||
|
|
||||||
def _currentName(self):
|
def _currentName(self):
|
||||||
"""Return current element of Sequence, used by name"""
|
"""Return current element of Sequence, used by name"""
|
||||||
# TODO: current impl first only if 1st if an prod!
|
# TODO: current impl first only if 1st if an prod!
|
||||||
for prod in self._prods[self._pos:]:
|
for prod in self._prods[self._i:]:
|
||||||
if not prod.optional:
|
if not prod.optional:
|
||||||
return prod.name
|
return str(prod)
|
||||||
else:
|
else:
|
||||||
return 'Unknown'
|
return 'Sequence'
|
||||||
|
|
||||||
name = property(_currentName, doc='Used for Error reporting')
|
optional = property(lambda self: self._min == 0)
|
||||||
|
|
||||||
def nextProd(self, token):
|
def nextProd(self, token):
|
||||||
"""Return
|
"""Return
|
||||||
@ -121,51 +173,53 @@ class Sequence(object):
|
|||||||
- raises ParseError if nothing matches
|
- raises ParseError if nothing matches
|
||||||
- raises Exhausted if sequence already done
|
- raises Exhausted if sequence already done
|
||||||
"""
|
"""
|
||||||
while self._pos < self._number:
|
while self._round < self._max:
|
||||||
x = self._prods[self._pos]
|
# for this round
|
||||||
thisround = self._round
|
i = self._i
|
||||||
|
round = self._round
|
||||||
|
p = self._prods[i]
|
||||||
|
if i == 0:
|
||||||
|
self._roundstarted = False
|
||||||
|
|
||||||
self._pos += 1
|
# for next round
|
||||||
if self._pos == self._number:
|
self._i += 1
|
||||||
if self._round < self._max:
|
if self._i == self._prodcount:
|
||||||
# new round?
|
self._round += 1
|
||||||
self._pos = 0
|
self._i = 0
|
||||||
self._round += 1
|
|
||||||
|
|
||||||
if isinstance(x, Prod):
|
if p.matches(token):
|
||||||
if not token and (x.optional or thisround > self._min):
|
self._roundstarted = True
|
||||||
# token is None if nothing expected
|
# reset nested Choice or Prod to use from start
|
||||||
raise Exhausted()
|
p.reset()
|
||||||
elif not token and not x.optional:
|
return p
|
||||||
raise MissingToken(u'Missing token for production %s'
|
|
||||||
% x.name)
|
elif p.optional:
|
||||||
elif x.matches(token):
|
continue
|
||||||
return x
|
|
||||||
elif x.optional:
|
elif round < self._min:
|
||||||
# try next
|
raise Missing(u'Missing token for production %s' % p)
|
||||||
continue
|
|
||||||
# elif thisround > self._min:
|
elif not token:
|
||||||
# # minimum done
|
if self._roundstarted:
|
||||||
# self._round = self._max
|
raise Missing(u'Missing token for production %s' % p)
|
||||||
# self._pos = self._number
|
|
||||||
# return None
|
|
||||||
else:
|
else:
|
||||||
# should have matched
|
raise Done()
|
||||||
raise NoMatch(u'No matching production for token')
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# nested Sequence or Choice
|
raise NoMatch(u'No matching production for token')
|
||||||
return x
|
|
||||||
|
|
||||||
# Sequence is exhausted
|
if token:
|
||||||
if self._round >= self._max:
|
|
||||||
raise Exhausted(u'Extra token')
|
raise Exhausted(u'Extra token')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return u'Sequence(%s)' % u', '.join([str(x) for x in self._prods])
|
||||||
|
|
||||||
|
|
||||||
class Prod(object):
|
class Prod(object):
|
||||||
"""Single Prod in Sequence or Choice."""
|
"""Single Prod in Sequence or Choice."""
|
||||||
def __init__(self, name, match, toSeq=None, toStore=None,
|
def __init__(self, name, match, optional=False,
|
||||||
optional=False):
|
toSeq=None, toStore=None,
|
||||||
|
stop=False, nextSor=False, mayEnd=False):
|
||||||
"""
|
"""
|
||||||
name
|
name
|
||||||
name used for error reporting
|
name used for error reporting
|
||||||
@ -173,16 +227,24 @@ class Prod(object):
|
|||||||
function called with parameters tokentype and tokenvalue
|
function called with parameters tokentype and tokenvalue
|
||||||
returning True, False or raising ParseError
|
returning True, False or raising ParseError
|
||||||
toSeq callback (optional)
|
toSeq callback (optional)
|
||||||
if given calling toSeq(token) will be appended to seq
|
calling toSeq(token, tokens) returns (type_, val) == (token[0], token[1])
|
||||||
else simply seq
|
to be appended to seq else simply unaltered (type_, val)
|
||||||
toStore (optional)
|
toStore (optional)
|
||||||
key to save util.Item to store or callback(store, util.Item)
|
key to save util.Item to store or callback(store, util.Item)
|
||||||
optional = False
|
optional = False
|
||||||
wether Prod is optional or not
|
wether Prod is optional or not
|
||||||
|
stop = False
|
||||||
|
if True stop parsing of tokens here
|
||||||
|
mayEnd = False
|
||||||
|
no token must follow even defined by Sequence.
|
||||||
|
Used for operator ',/ ' currently only
|
||||||
"""
|
"""
|
||||||
self.name = name
|
self._name = name
|
||||||
self.match = match
|
self.match = match
|
||||||
self.optional=optional
|
self.optional = optional
|
||||||
|
self.stop = stop
|
||||||
|
self.nextSor = nextSor
|
||||||
|
self.mayEnd = mayEnd
|
||||||
|
|
||||||
def makeToStore(key):
|
def makeToStore(key):
|
||||||
"Return a function used by toStore."
|
"Return a function used by toStore."
|
||||||
@ -198,9 +260,9 @@ class Prod(object):
|
|||||||
# called: seq.append(toSeq(value))
|
# called: seq.append(toSeq(value))
|
||||||
self.toSeq = toSeq
|
self.toSeq = toSeq
|
||||||
else:
|
else:
|
||||||
self.toSeq = lambda val: val
|
self.toSeq = lambda t, tokens: (t[0], t[1])
|
||||||
|
|
||||||
if callable(toStore):
|
if hasattr(toStore, '__call__'):
|
||||||
self.toStore = toStore
|
self.toStore = toStore
|
||||||
elif toStore:
|
elif toStore:
|
||||||
self.toStore = makeToStore(toStore)
|
self.toStore = makeToStore(toStore)
|
||||||
@ -210,12 +272,20 @@ class Prod(object):
|
|||||||
|
|
||||||
def matches(self, token):
|
def matches(self, token):
|
||||||
"""Return if token matches."""
|
"""Return if token matches."""
|
||||||
|
if not token:
|
||||||
|
return False
|
||||||
type_, val, line, col = token
|
type_, val, line, col = token
|
||||||
return self.match(type_, val)
|
return self.match(type_, val)
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self._name
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<cssutils.prodsparser.%s object name=%r at 0x%x>" % (
|
return "<cssutils.prodsparser.%s object name=%r at 0x%x>" % (
|
||||||
self.__class__.__name__, self.name, id(self))
|
self.__class__.__name__, self._name, id(self))
|
||||||
|
|
||||||
|
|
||||||
class ProdParser(object):
|
class ProdParser(object):
|
||||||
@ -225,6 +295,70 @@ class ProdParser(object):
|
|||||||
self._log = cssutils.log
|
self._log = cssutils.log
|
||||||
self._tokenizer = cssutils.tokenize2.Tokenizer()
|
self._tokenizer = cssutils.tokenize2.Tokenizer()
|
||||||
|
|
||||||
|
def _texttotokens(self, text):
|
||||||
|
"""Build a generator which is the only thing that is parsed!
|
||||||
|
old classes may use lists etc
|
||||||
|
"""
|
||||||
|
if isinstance(text, basestring):
|
||||||
|
# to tokenize strip space
|
||||||
|
tokens = self._tokenizer.tokenize(text.strip())
|
||||||
|
elif isinstance(text, tuple):
|
||||||
|
# (token, tokens) or a single token
|
||||||
|
if len(text) == 2:
|
||||||
|
# (token, tokens)
|
||||||
|
def gen(token, tokens):
|
||||||
|
"new generator appending token and tokens"
|
||||||
|
yield token
|
||||||
|
for t in tokens:
|
||||||
|
yield t
|
||||||
|
|
||||||
|
tokens = (t for t in gen(*text))
|
||||||
|
|
||||||
|
else:
|
||||||
|
# single token
|
||||||
|
tokens = (t for t in [text])
|
||||||
|
elif isinstance(text, list):
|
||||||
|
# generator from list
|
||||||
|
tokens = (t for t in text)
|
||||||
|
else:
|
||||||
|
# already tokenized, assume generator
|
||||||
|
tokens = text
|
||||||
|
|
||||||
|
return tokens
|
||||||
|
|
||||||
|
def _SorTokens(self, tokens, until=',/'):
|
||||||
|
"""New tokens generator which has S tokens removed,
|
||||||
|
if followed by anything in ``until``, normally a ``,``."""
|
||||||
|
def removedS(tokens):
|
||||||
|
for token in tokens:
|
||||||
|
if token[0] == self.types.S:
|
||||||
|
try:
|
||||||
|
next_ = tokens.next()
|
||||||
|
except StopIteration:
|
||||||
|
yield token
|
||||||
|
else:
|
||||||
|
if next_[1] in until:
|
||||||
|
# omit S as e.g. ``,`` has been found
|
||||||
|
yield next_
|
||||||
|
elif next_[0] == self.types.COMMENT:
|
||||||
|
# pass COMMENT
|
||||||
|
yield next_
|
||||||
|
else:
|
||||||
|
yield token
|
||||||
|
yield next_
|
||||||
|
|
||||||
|
elif token[0] == self.types.COMMENT:
|
||||||
|
# pass COMMENT
|
||||||
|
yield token
|
||||||
|
else:
|
||||||
|
yield token
|
||||||
|
break
|
||||||
|
# normal mode again
|
||||||
|
for token in tokens:
|
||||||
|
yield token
|
||||||
|
|
||||||
|
return (token for token in removedS(tokens))
|
||||||
|
|
||||||
def parse(self, text, name, productions, store=None):
|
def parse(self, text, name, productions, store=None):
|
||||||
"""
|
"""
|
||||||
text (or token generator)
|
text (or token generator)
|
||||||
@ -255,129 +389,140 @@ class ProdParser(object):
|
|||||||
:store: filled keys defined by Prod.toStore
|
:store: filled keys defined by Prod.toStore
|
||||||
:unusedtokens: token generator containing tokens not used yet
|
:unusedtokens: token generator containing tokens not used yet
|
||||||
"""
|
"""
|
||||||
if isinstance(text, basestring):
|
tokens = self._texttotokens(text)
|
||||||
# to tokenize
|
if not tokens:
|
||||||
tokens = self._tokenizer.tokenize(text)
|
self._log.error(u'No content to parse.')
|
||||||
elif isinstance(text, tuple):
|
# TODO: return???
|
||||||
# (token, tokens) or a single token
|
|
||||||
if len(text) == 2:
|
|
||||||
# (token, tokens)
|
|
||||||
def gen(token, tokens):
|
|
||||||
"new generator appending token and tokens"
|
|
||||||
yield token
|
|
||||||
for t in tokens:
|
|
||||||
yield t
|
|
||||||
|
|
||||||
tokens = (t for t in gen(*text))
|
|
||||||
|
|
||||||
else:
|
|
||||||
# single token
|
|
||||||
tokens = [text]
|
|
||||||
else:
|
|
||||||
# already tokenized, assume generator
|
|
||||||
tokens = text
|
|
||||||
|
|
||||||
# a new seq to append all Items to
|
|
||||||
seq = cssutils.util.Seq(readonly=False)
|
seq = cssutils.util.Seq(readonly=False)
|
||||||
|
if not store: # store for specific values
|
||||||
# store for specific values
|
|
||||||
if not store:
|
|
||||||
store = {}
|
store = {}
|
||||||
# store['_raw'] = []
|
prods = [productions] # stack of productions
|
||||||
|
|
||||||
# stack of productions
|
|
||||||
prods = [productions]
|
|
||||||
|
|
||||||
wellformed = True
|
wellformed = True
|
||||||
for token in tokens:
|
|
||||||
|
# while no real token is found any S are ignored
|
||||||
|
started = False
|
||||||
|
prod = None
|
||||||
|
# flag if default S handling should be done
|
||||||
|
defaultS = True
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
token = tokens.next()
|
||||||
|
except StopIteration:
|
||||||
|
break
|
||||||
type_, val, line, col = token
|
type_, val, line, col = token
|
||||||
# store['_raw'].append(val)
|
|
||||||
|
|
||||||
# default productions
|
# default productions
|
||||||
if type_ == self.types.S:
|
if type_ == self.types.COMMENT:
|
||||||
# always append S?
|
|
||||||
seq.append(val, type_, line, col)
|
|
||||||
elif type_ == self.types.COMMENT:
|
|
||||||
# always append COMMENT
|
# always append COMMENT
|
||||||
seq.append(val, type_, line, col)
|
seq.append(cssutils.css.CSSComment(val),
|
||||||
|
cssutils.css.CSSComment, line, col)
|
||||||
|
elif defaultS and type_ == self.types.S:
|
||||||
|
# append S (but ignore starting ones)
|
||||||
|
if started:
|
||||||
|
seq.append(val, type_, line, col)
|
||||||
|
else:
|
||||||
|
continue
|
||||||
# elif type_ == self.types.ATKEYWORD:
|
# elif type_ == self.types.ATKEYWORD:
|
||||||
# # @rule
|
# # @rule
|
||||||
# r = cssutils.css.CSSUnknownRule(cssText=val)
|
# r = cssutils.css.CSSUnknownRule(cssText=val)
|
||||||
# seq.append(r, type(r), line, col)
|
# seq.append(r, type(r), line, col)
|
||||||
elif type_ == self.types.EOF:
|
elif type_ == self.types.INVALID:
|
||||||
# do nothing
|
# invalidate parse
|
||||||
|
wellformed = False
|
||||||
|
self._log.error(u'Invalid token: %r' % (token,))
|
||||||
|
break
|
||||||
|
elif type_ == 'EOF':
|
||||||
|
# do nothing? (self.types.EOF == True!)
|
||||||
pass
|
pass
|
||||||
# next = 'EOF'
|
|
||||||
else:
|
else:
|
||||||
# check prods
|
started = True # check S now
|
||||||
|
nextSor = False # reset
|
||||||
|
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
# find next matching production
|
# find next matching production
|
||||||
try:
|
try:
|
||||||
prod = prods[-1].nextProd(token)
|
prod = prods[-1].nextProd(token)
|
||||||
except (NoMatch, Exhausted), e:
|
except (Exhausted, NoMatch), e:
|
||||||
# try next
|
# try next
|
||||||
prod = None
|
prod = None
|
||||||
|
|
||||||
if isinstance(prod, Prod):
|
if isinstance(prod, Prod):
|
||||||
|
# found actual Prod, not a Choice or Sequence
|
||||||
break
|
break
|
||||||
elif not prod:
|
elif prod:
|
||||||
if len(prods) > 1:
|
|
||||||
# nested exhausted, next in parent
|
|
||||||
prods.pop()
|
|
||||||
else:
|
|
||||||
raise Exhausted('Extra token')
|
|
||||||
else:
|
|
||||||
# nested Sequence, Choice
|
# nested Sequence, Choice
|
||||||
prods.append(prod)
|
prods.append(prod)
|
||||||
|
else:
|
||||||
|
# nested exhausted, try in parent
|
||||||
|
if len(prods) > 1:
|
||||||
|
prods.pop()
|
||||||
|
else:
|
||||||
|
raise ParseError('No match')
|
||||||
except ParseError, e:
|
except ParseError, e:
|
||||||
wellformed = False
|
wellformed = False
|
||||||
self._log.error(u'%s: %s: %r' % (name, e, token))
|
self._log.error(u'%s: %s: %r' % (name, e, token))
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
# process prod
|
# process prod
|
||||||
if prod.toSeq:
|
if prod.toSeq:
|
||||||
seq.append(prod.toSeq(val), type_, line, col)
|
type_, val = prod.toSeq(token, tokens)
|
||||||
else:
|
if val is not None:
|
||||||
seq.append(val, type_, line, col)
|
seq.append(val, type_, line, col)
|
||||||
|
|
||||||
if prod.toStore:
|
if prod.toStore:
|
||||||
prod.toStore(store, seq[-1])
|
prod.toStore(store, seq[-1])
|
||||||
|
if prod.stop: # EOF?
|
||||||
|
# stop here and ignore following tokens
|
||||||
|
break
|
||||||
|
if prod.nextSor:
|
||||||
|
# following is S or other token (e.g. ",")?
|
||||||
|
# remove S if
|
||||||
|
tokens = self._SorTokens(tokens, ',/')
|
||||||
|
defaultS = False
|
||||||
|
else:
|
||||||
|
defaultS = True
|
||||||
|
|
||||||
# if 'STOP' == next: # EOF?
|
lastprod = prod
|
||||||
# # stop here and ignore following tokens
|
|
||||||
# break
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
# all productions exhausted?
|
# all productions exhausted?
|
||||||
try:
|
try:
|
||||||
prod = prods[-1].nextProd(token=None)
|
prod = prods[-1].nextProd(token=None)
|
||||||
except Exhausted, e:
|
except Done, e:
|
||||||
prod = None # ok
|
# ok
|
||||||
except (MissingToken, NoMatch), e:
|
prod = None
|
||||||
wellformed = False
|
|
||||||
self._log.error(u'%s: %s'
|
|
||||||
% (name, e))
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
if prod.optional:
|
|
||||||
# ignore optional ones
|
|
||||||
continue
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if prod:
|
except Missing, e:
|
||||||
|
prod = None
|
||||||
|
# last was a S operator which may End a Sequence, then ok
|
||||||
|
if hasattr(lastprod, 'mayEnd') and not lastprod.mayEnd:
|
||||||
|
wellformed = False
|
||||||
|
self._log.error(u'%s: %s' % (name, e))
|
||||||
|
|
||||||
|
except ParseError, e:
|
||||||
|
prod = None
|
||||||
|
wellformed = False
|
||||||
|
self._log.error(u'%s: %s' % (name, e))
|
||||||
|
|
||||||
|
else:
|
||||||
|
if prods[-1].optional:
|
||||||
|
prod = None
|
||||||
|
elif prod and prod.optional:
|
||||||
|
# ignore optional
|
||||||
|
continue
|
||||||
|
|
||||||
|
if prod and not prod.optional:
|
||||||
wellformed = False
|
wellformed = False
|
||||||
self._log.error(u'%s: Missing token for production %r'
|
self._log.error(u'%s: Missing token for production %r'
|
||||||
% (name, prod.name))
|
% (name, str(prod)))
|
||||||
|
break
|
||||||
elif len(prods) > 1:
|
elif len(prods) > 1:
|
||||||
# nested exhausted, next in parent
|
# nested exhausted, next in parent
|
||||||
prods.pop()
|
prods.pop()
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
# bool, Seq, None or generator
|
# trim S from end
|
||||||
|
seq.rstrip()
|
||||||
return wellformed, seq, store, tokens
|
return wellformed, seq, store, tokens
|
||||||
|
|
||||||
|
|
||||||
@ -385,18 +530,108 @@ class PreDef(object):
|
|||||||
"""Predefined Prod definition for use in productions definition
|
"""Predefined Prod definition for use in productions definition
|
||||||
for ProdParser instances.
|
for ProdParser instances.
|
||||||
"""
|
"""
|
||||||
@staticmethod
|
types = cssutils.cssproductions.CSSProductions
|
||||||
def comma():
|
|
||||||
","
|
|
||||||
return Prod(name=u'comma', match=lambda t, v: v == u',')
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def funcEnd():
|
def CHAR(name='char', char=u',', toSeq=None, toStore=None, stop=False,
|
||||||
|
nextSor=False):
|
||||||
|
"any CHAR"
|
||||||
|
return Prod(name=name, match=lambda t, v: v == char,
|
||||||
|
toSeq=toSeq,
|
||||||
|
toStore=toStore,
|
||||||
|
stop=stop,
|
||||||
|
nextSor=nextSor)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def comma(toStore=None):
|
||||||
|
return PreDef.CHAR(u'comma', u',', toStore=toStore)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def dimension(toStore=None, nextSor=False):
|
||||||
|
return Prod(name=u'dimension',
|
||||||
|
match=lambda t, v: t == PreDef.types.DIMENSION,
|
||||||
|
toStore=toStore,
|
||||||
|
toSeq=lambda t, tokens: (t[0], cssutils.helper.normalize(t[1])),
|
||||||
|
nextSor=nextSor)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def function(toSeq=None, toStore=None, nextSor=False):
|
||||||
|
return Prod(name=u'function',
|
||||||
|
match=lambda t, v: t == PreDef.types.FUNCTION,
|
||||||
|
toSeq=toSeq,
|
||||||
|
toStore=toStore,
|
||||||
|
nextSor=nextSor)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def funcEnd(toStore=None, stop=False, nextSor=False):
|
||||||
")"
|
")"
|
||||||
return Prod(name=u'end FUNC ")"', match=lambda t, v: v == u')')
|
return PreDef.CHAR(u'end FUNC ")"', u')',
|
||||||
|
toStore=toStore,
|
||||||
|
stop=stop,
|
||||||
|
nextSor=nextSor)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def unary():
|
def ident(toStore=None, nextSor=False):
|
||||||
|
return Prod(name=u'ident',
|
||||||
|
match=lambda t, v: t == PreDef.types.IDENT,
|
||||||
|
toStore=toStore,
|
||||||
|
nextSor=nextSor)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def number(toStore=None, nextSor=False):
|
||||||
|
return Prod(name=u'number',
|
||||||
|
match=lambda t, v: t == PreDef.types.NUMBER,
|
||||||
|
toStore=toStore,
|
||||||
|
nextSor=nextSor)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def string(toStore=None, nextSor=False):
|
||||||
|
"string delimiters are removed by default"
|
||||||
|
return Prod(name=u'string',
|
||||||
|
match=lambda t, v: t == PreDef.types.STRING,
|
||||||
|
toStore=toStore,
|
||||||
|
toSeq=lambda t, tokens: (t[0], cssutils.helper.stringvalue(t[1])),
|
||||||
|
nextSor=nextSor)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def percentage(toStore=None, nextSor=False):
|
||||||
|
return Prod(name=u'percentage',
|
||||||
|
match=lambda t, v: t == PreDef.types.PERCENTAGE,
|
||||||
|
toStore=toStore,
|
||||||
|
nextSor=nextSor)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def S(name=u'whitespace', optional=True, toSeq=None, toStore=None, nextSor=False,
|
||||||
|
mayEnd=False):
|
||||||
|
return Prod(name=name,
|
||||||
|
match=lambda t, v: t == PreDef.types.S,
|
||||||
|
optional=optional,
|
||||||
|
toSeq=toSeq,
|
||||||
|
toStore=toStore,
|
||||||
|
mayEnd=mayEnd)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def unary(optional=True, toStore=None):
|
||||||
"+ or -"
|
"+ or -"
|
||||||
return Prod(name=u'unary +-', match=lambda t, v: v in u'+-',
|
return Prod(name=u'unary +-', match=lambda t, v: v in (u'+', u'-'),
|
||||||
optional=True)
|
optional=optional,
|
||||||
|
toStore=toStore)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def uri(toStore=None, nextSor=False):
|
||||||
|
"'url(' and ')' are removed and URI is stripped"
|
||||||
|
return Prod(name=u'URI',
|
||||||
|
match=lambda t, v: t == PreDef.types.URI,
|
||||||
|
toStore=toStore,
|
||||||
|
toSeq=lambda t, tokens: (t[0], cssutils.helper.urivalue(t[1])),
|
||||||
|
nextSor=nextSor)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def hexcolor(toStore=None, toSeq=None, nextSor=False):
|
||||||
|
return Prod(name='HEX color',
|
||||||
|
match=lambda t, v: t == PreDef.types.HASH and
|
||||||
|
len(v) == 4 or len(v) == 7,
|
||||||
|
toStore=toStore,
|
||||||
|
toSeq=toSeq,
|
||||||
|
nextSor=nextSor
|
||||||
|
)
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
"""CSS profiles. Predefined are:
|
"""CSS profiles.
|
||||||
|
|
||||||
- 'CSS level 2'
|
css2 is based on cssvalues
|
||||||
|
contributed by Kevin D. Smith, thanks!
|
||||||
|
|
||||||
|
"cssvalues" is used as a property validator.
|
||||||
|
it is an importable object that contains a dictionary of compiled regular
|
||||||
|
expressions. The keys of this dictionary are all of the valid CSS property
|
||||||
|
names. The values are compiled regular expressions that can be used to
|
||||||
|
validate the values for that property. (Actually, the values are references
|
||||||
|
to the 'match' method of a compiled regular expression, so that they are
|
||||||
|
simply called like functions.)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
__all__ = ['profiles']
|
__all__ = ['profiles']
|
||||||
@ -10,6 +19,7 @@ __version__ = '$Id: cssproperties.py 1116 2008-03-05 13:52:23Z cthedot $'
|
|||||||
import cssutils
|
import cssutils
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
properties = {}
|
||||||
"""
|
"""
|
||||||
Define some regular expression fragments that will be used as
|
Define some regular expression fragments that will be used as
|
||||||
macros within the CSS property value regular expressions.
|
macros within the CSS property value regular expressions.
|
||||||
@ -56,12 +66,13 @@ css2macros = {
|
|||||||
'font-attrs': r'{font-style}|{font-variant}|{font-weight}',
|
'font-attrs': r'{font-style}|{font-variant}|{font-weight}',
|
||||||
'outline-attrs': r'{outline-color}|{outline-style}|{outline-width}',
|
'outline-attrs': r'{outline-color}|{outline-style}|{outline-width}',
|
||||||
'text-attrs': r'underline|overline|line-through|blink',
|
'text-attrs': r'underline|overline|line-through|blink',
|
||||||
|
'overflow': r'visible|hidden|scroll|auto|inherit',
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Define the regular expressions for validation all CSS values
|
Define the regular expressions for validation all CSS values
|
||||||
"""
|
"""
|
||||||
css2 = {
|
properties['css2'] = {
|
||||||
'azimuth': r'{angle}|(behind\s+)?(left-side|far-left|left|center-left|center|center-right|right|far-right|right-side)(\s+behind)?|behind|leftwards|rightwards|inherit',
|
'azimuth': r'{angle}|(behind\s+)?(left-side|far-left|left|center-left|center|center-right|right|far-right|right-side)(\s+behind)?|behind|leftwards|rightwards|inherit',
|
||||||
'background-attachment': r'{background-attachment}',
|
'background-attachment': r'{background-attachment}',
|
||||||
'background-color': r'{background-color}',
|
'background-color': r'{background-color}',
|
||||||
@ -137,7 +148,7 @@ css2 = {
|
|||||||
'outline-style': r'{outline-style}',
|
'outline-style': r'{outline-style}',
|
||||||
'outline-width': r'{outline-width}',
|
'outline-width': r'{outline-width}',
|
||||||
'outline': r'{outline-attrs}(\s+{outline-attrs})*|inherit',
|
'outline': r'{outline-attrs}(\s+{outline-attrs})*|inherit',
|
||||||
'overflow': r'visible|hidden|scroll|auto|inherit',
|
'overflow': r'{overflow}',
|
||||||
'padding-top': r'{padding-width}|inherit',
|
'padding-top': r'{padding-width}|inherit',
|
||||||
'padding-right': r'{padding-width}|inherit',
|
'padding-right': r'{padding-width}|inherit',
|
||||||
'padding-bottom': r'{padding-width}|inherit',
|
'padding-bottom': r'{padding-width}|inherit',
|
||||||
@ -187,14 +198,22 @@ css3colormacros = {
|
|||||||
# orange?
|
# orange?
|
||||||
'rgbacolor': r'rgba\({w}{int}{w},{w}{int}{w},{w}{int}{w},{w}{int}{w}\)|rgba\({w}{num}%{w},{w}{num}%{w},{w}{num}%{w},{w}{num}{w}\)',
|
'rgbacolor': r'rgba\({w}{int}{w},{w}{int}{w},{w}{int}{w},{w}{int}{w}\)|rgba\({w}{num}%{w},{w}{num}%{w},{w}{num}%{w},{w}{num}{w}\)',
|
||||||
'hslcolor': r'hsl\({w}{int}{w},{w}{num}%{w},{w}{num}%{w}\)|hsla\({w}{int}{w},{w}{num}%{w},{w}{num}%{w},{w}{num}{w}\)',
|
'hslcolor': r'hsl\({w}{int}{w},{w}{num}%{w},{w}{num}%{w}\)|hsla\({w}{int}{w},{w}{num}%{w},{w}{num}%{w},{w}{num}{w}\)',
|
||||||
|
'x11color': r'aliceblue|antiquewhite|aqua|aquamarine|azure|beige|bisque|black|blanchedalmond|blue|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan|darkblue|darkcyan|darkgoldenrod|darkgray|darkgreen|darkgrey|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkslategrey|darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dimgrey|dodgerblue|firebrick|floralwhite|forestgreen|fuchsia|gainsboro|ghostwhite|gold|goldenrod|gray|green|greenyellow|grey|honeydew|hotpink|indianred|indigo|ivory|khaki|lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|lightgoldenrodyellow|lightgray|lightgreen|lightgrey|lightpink|lightsalmon|lightseagreen|lightskyblue|lightslategray|lightslategrey|lightsteelblue|lightyellow|lime|limegreen|linen|magenta|maroon|mediumaquamarine|mediumblue|mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|navajowhite|navy|oldlace|olive|olivedrab|orange|orangered|orchid|palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|peru|pink|plum|powderblue|purple|red|rosybrown|royalblue|saddlebrown|salmon|sandybrown|seagreen|seashell|sienna|silver|skyblue|slateblue|slategray|slategrey|snow|springgreen|steelblue|tan|teal|thistle|tomato|turquoise|violet|wheat|white|whitesmoke|yellow|yellowgreen',
|
||||||
|
'uicolor': r'(ActiveBorder|ActiveCaption|AppWorkspace|Background|ButtonFace|ButtonHighlight|ButtonShadow|ButtonText|CaptionText|GrayText|Highlight|HighlightText|InactiveBorder|InactiveCaption|InactiveCaptionText|InfoBackground|InfoText|Menu|MenuText|Scrollbar|ThreeDDarkShadow|ThreeDFace|ThreeDHighlight|ThreeDLightShadow|ThreeDShadow|Window|WindowFrame|WindowText)',
|
||||||
|
|
||||||
}
|
}
|
||||||
|
properties['css3color'] = {
|
||||||
|
|
||||||
css3color = {
|
|
||||||
'color': r'{namedcolor}|{hexcolor}|{rgbcolor}|{rgbacolor}|{hslcolor}|inherit',
|
'color': r'{namedcolor}|{hexcolor}|{rgbcolor}|{rgbacolor}|{hslcolor}|inherit',
|
||||||
'opacity': r'{num}|inherit'
|
'opacity': r'{num}|inherit'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# CSS Box Module Level 3
|
||||||
|
properties['css3box'] = {
|
||||||
|
'overflow': '{overflow}\s?{overflow}?',
|
||||||
|
'overflow-x': '{overflow}',
|
||||||
|
'overflow-y': '{overflow}'
|
||||||
|
}
|
||||||
|
|
||||||
class NoSuchProfileException(Exception):
|
class NoSuchProfileException(Exception):
|
||||||
"""Raised if no profile with given name is found"""
|
"""Raised if no profile with given name is found"""
|
||||||
pass
|
pass
|
||||||
@ -202,17 +221,25 @@ class NoSuchProfileException(Exception):
|
|||||||
|
|
||||||
class Profiles(object):
|
class Profiles(object):
|
||||||
"""
|
"""
|
||||||
A dictionary of::
|
All profiles used for validation. ``cssutils.profiles.profiles`` is a
|
||||||
|
preset object of this class and used by all properties for validation.
|
||||||
|
|
||||||
profilename: {
|
Predefined profiles are (use
|
||||||
propname: propvalue_regex*
|
:meth:`~cssutils.profiles.Profiles.propertiesByProfile` to
|
||||||
}
|
get a list of defined properties):
|
||||||
|
|
||||||
Predefined profiles are:
|
:attr:`~cssutils.profiles.Profiles.Profiles.CSS_LEVEL_2`
|
||||||
|
Properties defined by CSS2.1
|
||||||
- 'CSS level 2': Properties defined by CSS2
|
:attr:`~cssutils.profiles.Profiles.Profiles.CSS_COLOR_LEVEL_3`
|
||||||
|
CSS 3 color properties
|
||||||
|
:attr:`~cssutils.profiles.Profiles.Profiles.CSS_BOX_LEVEL_3`
|
||||||
|
Currently overflow related properties only
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
CSS_LEVEL_2 = 'CSS Level 2.1'
|
||||||
|
CSS_COLOR_LEVEL_3 = 'CSS Color Module Level 3'
|
||||||
|
CSS_BOX_LEVEL_3 = 'CSS Box Module Level 3'
|
||||||
|
|
||||||
basicmacros = {
|
basicmacros = {
|
||||||
'ident': r'[-]?{nmstart}{nmchar}*',
|
'ident': r'[-]?{nmstart}{nmchar}*',
|
||||||
'name': r'{nmchar}+',
|
'name': r'{nmchar}+',
|
||||||
@ -247,22 +274,24 @@ class Profiles(object):
|
|||||||
'percentage': r'{num}%',
|
'percentage': r'{num}%',
|
||||||
}
|
}
|
||||||
|
|
||||||
CSS_LEVEL_2 = 'CSS Level 2.1'
|
|
||||||
CSS_COLOR_LEVEL_3 = 'CSS Color Module Level 3'
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
"""A few known profiles are predefined."""
|
||||||
self._log = cssutils.log
|
self._log = cssutils.log
|
||||||
self._profilenames = [] # to keep order, REFACTOR!
|
self._profilenames = [] # to keep order, REFACTOR!
|
||||||
self._profiles = {}
|
self._profiles = {}
|
||||||
self.addProfile(self.CSS_LEVEL_2, css2, css2macros)
|
|
||||||
self.addProfile(self.CSS_COLOR_LEVEL_3, css3color, css3colormacros)
|
self.addProfile(self.CSS_LEVEL_2, properties['css2'], css2macros)
|
||||||
|
self.addProfile(self.CSS_COLOR_LEVEL_3, properties['css3color'], css3colormacros)
|
||||||
|
self.addProfile(self.CSS_BOX_LEVEL_3, properties['css3box'])
|
||||||
|
|
||||||
|
self.__update_knownnames()
|
||||||
|
|
||||||
def _expand_macros(self, dictionary, macros):
|
def _expand_macros(self, dictionary, macros):
|
||||||
"""Expand macros in token dictionary"""
|
"""Expand macros in token dictionary"""
|
||||||
def macro_value(m):
|
def macro_value(m):
|
||||||
return '(?:%s)' % macros[m.groupdict()['macro']]
|
return '(?:%s)' % macros[m.groupdict()['macro']]
|
||||||
for key, value in dictionary.items():
|
for key, value in dictionary.items():
|
||||||
if not callable(value):
|
if not hasattr(value, '__call__'):
|
||||||
while re.search(r'{[a-z][a-z0-9-]*}', value):
|
while re.search(r'{[a-z][a-z0-9-]*}', value):
|
||||||
value = re.sub(r'{(?P<macro>[a-z][a-z0-9-]*)}',
|
value = re.sub(r'{(?P<macro>[a-z][a-z0-9-]*)}',
|
||||||
macro_value, value)
|
macro_value, value)
|
||||||
@ -272,23 +301,31 @@ class Profiles(object):
|
|||||||
def _compile_regexes(self, dictionary):
|
def _compile_regexes(self, dictionary):
|
||||||
"""Compile all regular expressions into callable objects"""
|
"""Compile all regular expressions into callable objects"""
|
||||||
for key, value in dictionary.items():
|
for key, value in dictionary.items():
|
||||||
if not callable(value):
|
if not hasattr(value, '__call__'):
|
||||||
value = re.compile('^(?:%s)$' % value, re.I).match
|
value = re.compile('^(?:%s)$' % value, re.I).match
|
||||||
dictionary[key] = value
|
dictionary[key] = value
|
||||||
|
|
||||||
return dictionary
|
return dictionary
|
||||||
|
|
||||||
|
def __update_knownnames(self):
|
||||||
|
self._knownnames = []
|
||||||
|
for properties in self._profiles.values():
|
||||||
|
self._knownnames.extend(properties.keys())
|
||||||
|
|
||||||
profiles = property(lambda self: sorted(self._profiles.keys()),
|
profiles = property(lambda self: sorted(self._profiles.keys()),
|
||||||
doc=u'Names of all profiles.')
|
doc=u'Names of all profiles.')
|
||||||
|
|
||||||
def addProfile(self, profile, properties, macros=None):
|
knownnames = property(lambda self: self._knownnames,
|
||||||
"""Add a new profile with name ``profile`` (e.g. 'CSS level 2')
|
doc="All known property names of all profiles.")
|
||||||
and the given ``properties``. ``macros`` are
|
|
||||||
|
|
||||||
``profile``
|
def addProfile(self, profile, properties, macros=None):
|
||||||
The new profile's name
|
"""Add a new profile with name `profile` (e.g. 'CSS level 2')
|
||||||
``properties``
|
and the given `properties`.
|
||||||
A dictionary of ``{ property-name: propery-value }`` items where
|
|
||||||
|
:param profile:
|
||||||
|
the new `profile`'s name
|
||||||
|
:param properties:
|
||||||
|
a dictionary of ``{ property-name: propery-value }`` items where
|
||||||
property-value is a regex which may use macros defined in given
|
property-value is a regex which may use macros defined in given
|
||||||
``macros`` or the standard macros Profiles.tokens and
|
``macros`` or the standard macros Profiles.tokens and
|
||||||
Profiles.generalvalues.
|
Profiles.generalvalues.
|
||||||
@ -300,6 +337,10 @@ class Profiles(object):
|
|||||||
are reported or raised as all other cssutils exceptions depending
|
are reported or raised as all other cssutils exceptions depending
|
||||||
on cssutils.log.raiseExceptions which e.g during parsing normally
|
on cssutils.log.raiseExceptions which e.g during parsing normally
|
||||||
is False so the exceptions would be logged only.
|
is False so the exceptions would be logged only.
|
||||||
|
:param macros:
|
||||||
|
may be used in the given properties definitions. There are some
|
||||||
|
predefined basic macros which may always be used in
|
||||||
|
:attr:`Profiles.basicmacros` and :attr:`Profiles.generalmacros`.
|
||||||
"""
|
"""
|
||||||
if not macros:
|
if not macros:
|
||||||
macros = {}
|
macros = {}
|
||||||
@ -310,14 +351,40 @@ class Profiles(object):
|
|||||||
self._profilenames.append(profile)
|
self._profilenames.append(profile)
|
||||||
self._profiles[profile] = self._compile_regexes(properties)
|
self._profiles[profile] = self._compile_regexes(properties)
|
||||||
|
|
||||||
|
self.__update_knownnames()
|
||||||
|
|
||||||
|
def removeProfile(self, profile=None, all=False):
|
||||||
|
"""Remove `profile` or remove `all` profiles.
|
||||||
|
|
||||||
|
:param profile:
|
||||||
|
profile name to remove
|
||||||
|
:param all:
|
||||||
|
if ``True`` removes all profiles to start with a clean state
|
||||||
|
:exceptions:
|
||||||
|
- :exc:`cssutils.profiles.NoSuchProfileException`:
|
||||||
|
If given `profile` cannot be found.
|
||||||
|
"""
|
||||||
|
if all:
|
||||||
|
self._profiles.clear()
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
del self._profiles[profile]
|
||||||
|
except KeyError:
|
||||||
|
raise NoSuchProfileException(u'No profile %r.' % profile)
|
||||||
|
|
||||||
|
self.__update_knownnames()
|
||||||
|
|
||||||
def propertiesByProfile(self, profiles=None):
|
def propertiesByProfile(self, profiles=None):
|
||||||
"""Generator: Yield property names, if no profile(s) is given all
|
"""Generator: Yield property names, if no `profiles` is given all
|
||||||
profile's properties are used."""
|
profile's properties are used.
|
||||||
|
|
||||||
|
:param profiles:
|
||||||
|
a single profile name or a list of names.
|
||||||
|
"""
|
||||||
if not profiles:
|
if not profiles:
|
||||||
profiles = self.profiles
|
profiles = self.profiles
|
||||||
elif isinstance(profiles, basestring):
|
elif isinstance(profiles, basestring):
|
||||||
profiles = (profiles, )
|
profiles = (profiles, )
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for profile in sorted(profiles):
|
for profile in sorted(profiles):
|
||||||
for name in sorted(self._profiles[profile].keys()):
|
for name in sorted(self._profiles[profile].keys()):
|
||||||
@ -326,12 +393,22 @@ class Profiles(object):
|
|||||||
raise NoSuchProfileException(e)
|
raise NoSuchProfileException(e)
|
||||||
|
|
||||||
def validate(self, name, value):
|
def validate(self, name, value):
|
||||||
"""Check if value is valid for given property name using any profile."""
|
"""Check if `value` is valid for given property `name` using **any**
|
||||||
|
profile.
|
||||||
|
|
||||||
|
:param name:
|
||||||
|
a property name
|
||||||
|
:param value:
|
||||||
|
a CSS value (string)
|
||||||
|
:returns:
|
||||||
|
if the `value` is valid for the given property `name` in any
|
||||||
|
profile
|
||||||
|
"""
|
||||||
for profile in self.profiles:
|
for profile in self.profiles:
|
||||||
if name in self._profiles[profile]:
|
if name in self._profiles[profile]:
|
||||||
try:
|
try:
|
||||||
# custom validation errors are caught
|
# custom validation errors are caught
|
||||||
r = bool(self._profiles[profile][name](value))
|
r = bool(self._profiles[profile][name](value))
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
self._log.error(e, error=Exception)
|
self._log.error(e, error=Exception)
|
||||||
return False
|
return False
|
||||||
@ -339,29 +416,63 @@ class Profiles(object):
|
|||||||
return r
|
return r
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def validateWithProfile(self, name, value):
|
def validateWithProfile(self, name, value, profiles=None):
|
||||||
"""Check if value is valid for given property name returning
|
"""Check if `value` is valid for given property `name` returning
|
||||||
(valid, valid_in_profile).
|
``(valid, profile)``.
|
||||||
|
|
||||||
You may want to check if valid_in_profile is what you expected.
|
:param name:
|
||||||
|
a property name
|
||||||
|
:param value:
|
||||||
|
a CSS value (string)
|
||||||
|
:returns:
|
||||||
|
``valid, profiles`` where ``valid`` is if the `value` is valid for
|
||||||
|
the given property `name` in any profile of given `profiles`
|
||||||
|
and ``profiles`` the profile names for which the value is valid
|
||||||
|
(or ``[]`` if not valid at all)
|
||||||
|
|
||||||
Example: You might expect a valid Profiles.CSS_LEVEL_2 value but
|
Example: You might expect a valid Profiles.CSS_LEVEL_2 value but
|
||||||
e.g. ``validateWithProfile('color', 'rgba(1,1,1,1)')`` returns
|
e.g. ``validateWithProfile('color', 'rgba(1,1,1,1)')`` returns
|
||||||
(True, Profiles.CSS_COLOR_LEVEL_3)
|
(True, Profiles.CSS_COLOR_LEVEL_3)
|
||||||
"""
|
"""
|
||||||
for profilename in self._profilenames:
|
if name not in self.knownnames:
|
||||||
if name in self._profiles[profilename]:
|
return False, []
|
||||||
try:
|
else:
|
||||||
# custom validation errors are caught
|
if not profiles:
|
||||||
r = (bool(self._profiles[profilename][name](value)),
|
profiles = self._profilenames
|
||||||
profilename)
|
elif isinstance(profiles, basestring):
|
||||||
except Exception, e:
|
profiles = (profiles, )
|
||||||
self._log.error(e, error=Exception)
|
|
||||||
r = False, None
|
|
||||||
if r[0]:
|
|
||||||
return r
|
|
||||||
return False, None
|
|
||||||
|
|
||||||
|
for profilename in profiles:
|
||||||
|
# check given profiles
|
||||||
|
if name in self._profiles[profilename]:
|
||||||
|
validate = self._profiles[profilename][name]
|
||||||
|
try:
|
||||||
|
if validate(value):
|
||||||
|
return True, [profilename]
|
||||||
|
except Exception, e:
|
||||||
|
self._log.error(e, error=Exception)
|
||||||
|
|
||||||
|
for profilename in (p for p in self._profilenames if p not in profiles):
|
||||||
|
# check remaining profiles as well
|
||||||
|
if name in self._profiles[profilename]:
|
||||||
|
validate = self._profiles[profilename][name]
|
||||||
|
try:
|
||||||
|
if validate(value):
|
||||||
|
return True, [profilename]
|
||||||
|
except Exception, e:
|
||||||
|
self._log.error(e, error=Exception)
|
||||||
|
|
||||||
|
names = []
|
||||||
|
for profilename, properties in self._profiles.items():
|
||||||
|
# return profile to which name belongs
|
||||||
|
if name in properties.keys():
|
||||||
|
names.append(profilename)
|
||||||
|
names.sort()
|
||||||
|
return False, names
|
||||||
|
|
||||||
|
# used by
|
||||||
profiles = Profiles()
|
profiles = Profiles()
|
||||||
|
|
||||||
|
# set for validation to e.g.``Profiles.CSS_LEVEL_2``
|
||||||
|
defaultprofile = None
|
||||||
|
|
||||||
|
@ -4,16 +4,16 @@ __all__ = ['CSSCapture', 'csscombine']
|
|||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: parse.py 1323 2008-07-06 18:13:57Z cthedot $'
|
__version__ = '$Id: parse.py 1323 2008-07-06 18:13:57Z cthedot $'
|
||||||
|
|
||||||
import codecs
|
|
||||||
import errno
|
|
||||||
import HTMLParser
|
import HTMLParser
|
||||||
|
import codecs
|
||||||
|
import cssutils
|
||||||
|
import errno
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import urllib2
|
import urllib2
|
||||||
import urlparse
|
import urlparse
|
||||||
|
|
||||||
import cssutils
|
|
||||||
try:
|
try:
|
||||||
import cssutils.encutils as encutils
|
import cssutils.encutils as encutils
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@ -307,65 +307,47 @@ class CSSCapture(object):
|
|||||||
sf.write(sheet.cssText)
|
sf.write(sheet.cssText)
|
||||||
sf.close()
|
sf.close()
|
||||||
|
|
||||||
|
def csscombine(path=None, url=None,
|
||||||
def csscombine(proxypath, sourceencoding=None, targetencoding='utf-8',
|
sourceencoding=None, targetencoding=None,
|
||||||
minify=True):
|
minify=True):
|
||||||
"""Combine sheets referred to by @import rules in given CSS proxy sheet
|
"""Combine sheets referred to by @import rules in given CSS proxy sheet
|
||||||
into a single new sheet.
|
into a single new sheet.
|
||||||
|
|
||||||
:returns: combined cssText, normal or minified
|
:returns: combined cssText, normal or minified
|
||||||
:Parameters:
|
:Parameters:
|
||||||
`proxypath`
|
`path` or `url`
|
||||||
url or path to a CSSStyleSheet which imports other sheets which
|
path or URL to a CSSStyleSheet which imports other sheets which
|
||||||
are then combined into one sheet
|
are then combined into one sheet
|
||||||
`sourceencoding`
|
|
||||||
encoding of the source sheets including the proxy sheet
|
|
||||||
`targetencoding`
|
`targetencoding`
|
||||||
encoding of the combined stylesheet, default 'utf-8'
|
encoding of the combined stylesheet, default 'utf-8'
|
||||||
`minify`
|
`minify`
|
||||||
defines if the combined sheet should be minified, default True
|
defines if the combined sheet should be minified, default True
|
||||||
"""
|
"""
|
||||||
log = cssutils.log
|
cssutils.log.info(u'Combining files from %r' % url,
|
||||||
|
neverraise=True)
|
||||||
log.info('Combining files in proxy %r' % proxypath, neverraise=True)
|
|
||||||
|
|
||||||
if sourceencoding is not None:
|
if sourceencoding is not None:
|
||||||
log.info('Using source encoding %r' % sourceencoding,
|
cssutils.log.info(u'Using source encoding %r' % sourceencoding,
|
||||||
neverraise=True)
|
neverraise=True)
|
||||||
|
if path:
|
||||||
|
src = cssutils.parseFile(path, encoding=sourceencoding)
|
||||||
|
elif url:
|
||||||
|
src = cssutils.parseUrl(url, encoding=sourceencoding)
|
||||||
|
else:
|
||||||
|
sys.exit('Path or URL must be given')
|
||||||
|
|
||||||
src = cssutils.parseFile(proxypath, encoding=sourceencoding)
|
result = cssutils.resolveImports(src)
|
||||||
srcpath = os.path.dirname(proxypath)
|
result.encoding = targetencoding
|
||||||
combined = cssutils.css.CSSStyleSheet()
|
cssutils.log.info(u'Using target encoding: %r' % targetencoding, neverraise=True)
|
||||||
for rule in src.cssRules:
|
|
||||||
if rule.type == rule.IMPORT_RULE:
|
|
||||||
fn = os.path.join(srcpath, rule.href)
|
|
||||||
log.info('Processing @import %r' % fn,
|
|
||||||
neverraise=True)
|
|
||||||
importsheet = cssutils.parseFile(fn, encoding=sourceencoding)
|
|
||||||
importsheet.encoding = None # remove @charset
|
|
||||||
combined.add(cssutils.css.CSSComment(cssText=u'/* %s */' %
|
|
||||||
rule.cssText))
|
|
||||||
for x in importsheet.cssRules:
|
|
||||||
if x.type == x.IMPORT_RULE:
|
|
||||||
log.info('Nested @imports are not combined: %s' % x.cssText,
|
|
||||||
neverraise=True)
|
|
||||||
|
|
||||||
combined.add(x)
|
|
||||||
|
|
||||||
else:
|
|
||||||
combined.add(rule)
|
|
||||||
|
|
||||||
log.info('Setting target encoding %r' % targetencoding, neverraise=True)
|
|
||||||
combined.encoding = targetencoding
|
|
||||||
|
|
||||||
if minify:
|
if minify:
|
||||||
# save old setting and use own serializer
|
# save old setting and use own serializer
|
||||||
oldser = cssutils.ser
|
oldser = cssutils.ser
|
||||||
cssutils.setSerializer(cssutils.serialize.CSSSerializer())
|
cssutils.setSerializer(cssutils.serialize.CSSSerializer())
|
||||||
cssutils.ser.prefs.useMinified()
|
cssutils.ser.prefs.useMinified()
|
||||||
cssText = combined.cssText
|
cssText = result.cssText
|
||||||
cssutils.setSerializer(oldser)
|
cssutils.setSerializer(oldser)
|
||||||
else:
|
else:
|
||||||
cssText = combined.cssText
|
cssText = result.cssText
|
||||||
|
|
||||||
return cssText
|
return cssText
|
||||||
|
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""serializer classes for CSS classes
|
"""cssutils serializer"""
|
||||||
|
|
||||||
"""
|
|
||||||
__all__ = ['CSSSerializer', 'Preferences']
|
__all__ = ['CSSSerializer', 'Preferences']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: serialize.py 1472 2008-09-15 21:14:54Z cthedot $'
|
__version__ = '$Id: serialize.py 1606 2009-01-03 20:32:17Z cthedot $'
|
||||||
|
|
||||||
import codecs
|
import codecs
|
||||||
|
import cssutils
|
||||||
|
import helper
|
||||||
import re
|
import re
|
||||||
import xml.dom
|
import xml.dom
|
||||||
import cssutils
|
|
||||||
|
|
||||||
def _escapecss(e):
|
def _escapecss(e):
|
||||||
"""
|
"""
|
||||||
@ -26,8 +26,7 @@ codecs.register_error('escapecss', _escapecss)
|
|||||||
|
|
||||||
|
|
||||||
class Preferences(object):
|
class Preferences(object):
|
||||||
"""
|
"""Control output of CSSSerializer.
|
||||||
controls output of CSSSerializer
|
|
||||||
|
|
||||||
defaultAtKeyword = True
|
defaultAtKeyword = True
|
||||||
Should the literal @keyword from src CSS be used or the default
|
Should the literal @keyword from src CSS be used or the default
|
||||||
@ -39,11 +38,12 @@ class Preferences(object):
|
|||||||
Only used if ``keepAllProperties==False``.
|
Only used if ``keepAllProperties==False``.
|
||||||
|
|
||||||
defaultPropertyPriority = True
|
defaultPropertyPriority = True
|
||||||
Should the normalized or literal priority be used, e.g. '!important'
|
Should the normalized or literal priority be used, e.g. ``!important``
|
||||||
or u'!Im\portant'
|
or ``!Im\portant``
|
||||||
|
|
||||||
importHrefFormat = None
|
importHrefFormat = None
|
||||||
Uses hreftype if ``None`` or explicit ``'string'`` or ``'uri'``
|
Uses hreftype if ``None`` or format ``"URI"`` if ``'string'`` or
|
||||||
|
format ``url(URI)`` if ``'uri'``
|
||||||
indent = 4 * ' '
|
indent = 4 * ' '
|
||||||
Indentation of e.g Properties inside a CSSStyleDeclaration
|
Indentation of e.g Properties inside a CSSStyleDeclaration
|
||||||
indentSpecificities = False
|
indentSpecificities = False
|
||||||
@ -88,20 +88,27 @@ class Preferences(object):
|
|||||||
A Property is valid if it is a known Property with a valid value.
|
A Property is valid if it is a known Property with a valid value.
|
||||||
Currently CSS 2.1 values as defined in cssproperties.py would be
|
Currently CSS 2.1 values as defined in cssproperties.py would be
|
||||||
valid.
|
valid.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, **initials):
|
def __init__(self, **initials):
|
||||||
"""
|
"""Always use named instead of positional parameters."""
|
||||||
Always use named instead of positional parameters
|
|
||||||
"""
|
|
||||||
self.useDefaults()
|
self.useDefaults()
|
||||||
|
|
||||||
for key, value in initials.items():
|
for key, value in initials.items():
|
||||||
if value:
|
if value:
|
||||||
self.__setattr__(key, value)
|
self.__setattr__(key, value)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return u"cssutils.css.%s(%s)" % (self.__class__.__name__,
|
||||||
|
u', '.join(['\n %s=%r' % (p, self.__getattribute__(p)) for p in self.__dict__]
|
||||||
|
))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return u"<cssutils.css.%s object %s at 0x%x" % (self.__class__.__name__,
|
||||||
|
u' '.join(['%s=%r' % (p, self.__getattribute__(p)) for p in self.__dict__]
|
||||||
|
),
|
||||||
|
id(self))
|
||||||
|
|
||||||
def useDefaults(self):
|
def useDefaults(self):
|
||||||
"reset all preference options to the default value"
|
"Reset all preference options to their default value."
|
||||||
self.defaultAtKeyword = True
|
self.defaultAtKeyword = True
|
||||||
self.defaultPropertyName = True
|
self.defaultPropertyName = True
|
||||||
self.defaultPropertyPriority = True
|
self.defaultPropertyPriority = True
|
||||||
@ -123,11 +130,10 @@ class Preferences(object):
|
|||||||
self.validOnly = False # should not be changed currently!!!
|
self.validOnly = False # should not be changed currently!!!
|
||||||
|
|
||||||
def useMinified(self):
|
def useMinified(self):
|
||||||
"""
|
"""Set options resulting in a minified stylesheet.
|
||||||
sets options to achive a minified stylesheet
|
|
||||||
|
|
||||||
you may want to set preferences with this convenience method
|
You may want to set preferences with this convenience method
|
||||||
and set settings you want adjusted afterwards
|
and set settings you want adjusted afterwards.
|
||||||
"""
|
"""
|
||||||
self.importHrefFormat = 'string'
|
self.importHrefFormat = 'string'
|
||||||
self.indent = u''
|
self.indent = u''
|
||||||
@ -144,22 +150,9 @@ class Preferences(object):
|
|||||||
self.spacer = u''
|
self.spacer = u''
|
||||||
self.validOnly = False
|
self.validOnly = False
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return u"cssutils.css.%s(%s)" % (self.__class__.__name__,
|
|
||||||
u', '.join(['\n %s=%r' % (p, self.__getattribute__(p)) for p in self.__dict__]
|
|
||||||
))
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return u"<cssutils.css.%s object %s at 0x%x" % (self.__class__.__name__,
|
|
||||||
u' '.join(['%s=%r' % (p, self.__getattribute__(p)) for p in self.__dict__]
|
|
||||||
),
|
|
||||||
id(self))
|
|
||||||
|
|
||||||
|
|
||||||
class Out(object):
|
class Out(object):
|
||||||
"""
|
"""A simple class which makes appended items available as a combined string"""
|
||||||
a simple class which makes appended items available as a combined string
|
|
||||||
"""
|
|
||||||
def __init__(self, ser):
|
def __init__(self, ser):
|
||||||
self.ser = ser
|
self.ser = ser
|
||||||
self.out = []
|
self.out = []
|
||||||
@ -178,11 +171,11 @@ class Out(object):
|
|||||||
- typ "Property", cssutils.css.CSSRule.UNKNOWN_RULE
|
- typ "Property", cssutils.css.CSSRule.UNKNOWN_RULE
|
||||||
uses cssText
|
uses cssText
|
||||||
- typ STRING
|
- typ STRING
|
||||||
escapes ser._string
|
escapes helper.string
|
||||||
- typ S
|
- typ S
|
||||||
ignored except ``keepS=True``
|
ignored except ``keepS=True``
|
||||||
- typ URI
|
- typ URI
|
||||||
calls ser_uri
|
calls helper.uri
|
||||||
- val ``{``
|
- val ``{``
|
||||||
adds LF after
|
adds LF after
|
||||||
- val ``;``
|
- val ``;``
|
||||||
@ -194,6 +187,8 @@ class Out(object):
|
|||||||
- some other vals
|
- some other vals
|
||||||
add ``*spacer`` except ``space=False``
|
add ``*spacer`` except ``space=False``
|
||||||
"""
|
"""
|
||||||
|
prefspace = self.ser.prefs.spacer
|
||||||
|
|
||||||
if val or typ in ('STRING', 'URI'):
|
if val or typ in ('STRING', 'URI'):
|
||||||
# PRE
|
# PRE
|
||||||
if 'COMMENT' == typ:
|
if 'COMMENT' == typ:
|
||||||
@ -207,6 +202,8 @@ class Out(object):
|
|||||||
# val = val.cssText
|
# val = val.cssText
|
||||||
elif 'S' == typ and not keepS:
|
elif 'S' == typ and not keepS:
|
||||||
return
|
return
|
||||||
|
elif 'S' == typ and keepS:
|
||||||
|
val = u' '
|
||||||
elif typ in ('NUMBER', 'DIMENSION', 'PERCENTAGE') and val == '0':
|
elif typ in ('NUMBER', 'DIMENSION', 'PERCENTAGE') and val == '0':
|
||||||
# remove sign + or - if value is zero
|
# remove sign + or - if value is zero
|
||||||
# TODO: only for lenghts!
|
# TODO: only for lenghts!
|
||||||
@ -216,9 +213,13 @@ class Out(object):
|
|||||||
# may be empty but MUST not be None
|
# may be empty but MUST not be None
|
||||||
if val is None:
|
if val is None:
|
||||||
return
|
return
|
||||||
val = self.ser._string(val)
|
val = helper.string(val)
|
||||||
|
if not prefspace:
|
||||||
|
self._remove_last_if_S()
|
||||||
elif 'URI' == typ:
|
elif 'URI' == typ:
|
||||||
val = self.ser._uri(val)
|
val = helper.uri(val)
|
||||||
|
elif 'HASH' == typ:
|
||||||
|
val = self.ser._hash(val)
|
||||||
elif val in u'+>~,:{;)]/':
|
elif val in u'+>~,:{;)]/':
|
||||||
self._remove_last_if_S()
|
self._remove_last_if_S()
|
||||||
|
|
||||||
@ -243,8 +244,11 @@ class Out(object):
|
|||||||
self.out.append(self.ser.prefs.lineSeparator)
|
self.out.append(self.ser.prefs.lineSeparator)
|
||||||
elif u';' == val: # end or prop or block
|
elif u';' == val: # end or prop or block
|
||||||
self.out.append(self.ser.prefs.lineSeparator)
|
self.out.append(self.ser.prefs.lineSeparator)
|
||||||
elif val not in u'}[]()/' and typ not in ('FUNCTION',) and space:
|
elif val not in u'}[]()/' and typ != 'FUNCTION' and space:
|
||||||
self.out.append(self.ser.prefs.spacer)
|
self.out.append(self.ser.prefs.spacer)
|
||||||
|
if typ != 'STRING' and not self.ser.prefs.spacer and \
|
||||||
|
self.out and not self.out[-1].endswith(u' '):
|
||||||
|
self.out.append(u' ')
|
||||||
|
|
||||||
def value(self, delim=u'', end=None, keepS=False):
|
def value(self, delim=u'', end=None, keepS=False):
|
||||||
"returns all items joined by delim"
|
"returns all items joined by delim"
|
||||||
@ -256,19 +260,14 @@ class Out(object):
|
|||||||
|
|
||||||
|
|
||||||
class CSSSerializer(object):
|
class CSSSerializer(object):
|
||||||
"""
|
"""Serialize a CSSStylesheet and its parts.
|
||||||
Methods to serialize a CSSStylesheet and its parts
|
|
||||||
|
|
||||||
To use your own serializing method the easiest is to subclass CSS
|
To use your own serializing method the easiest is to subclass CSS
|
||||||
Serializer and overwrite the methods you like to customize.
|
Serializer and overwrite the methods you like to customize.
|
||||||
"""
|
"""
|
||||||
# chars not in URI without quotes around as problematic with other stuff
|
|
||||||
# really ","?
|
|
||||||
__forbidden_in_uri_matcher = re.compile(ur'''.*?[\(\)\s\;,]''', re.U).match
|
|
||||||
|
|
||||||
def __init__(self, prefs=None):
|
def __init__(self, prefs=None):
|
||||||
"""
|
"""
|
||||||
prefs
|
:param prefs:
|
||||||
instance of Preferences
|
instance of Preferences
|
||||||
"""
|
"""
|
||||||
if not prefs:
|
if not prefs:
|
||||||
@ -319,23 +318,17 @@ class CSSSerializer(object):
|
|||||||
text = self.prefs.lineSeparator.join(out)
|
text = self.prefs.lineSeparator.join(out)
|
||||||
return text
|
return text
|
||||||
|
|
||||||
def _string(self, s):
|
def _hash(self, val, type_=None):
|
||||||
"""
|
"""
|
||||||
returns s encloded between "..." and escaped delim charater ",
|
Short form of hash, e.g. #123 instead of #112233
|
||||||
escape line breaks \\n \\r and \\f
|
|
||||||
"""
|
"""
|
||||||
# \n = 0xa, \r = 0xd, \f = 0xc
|
# TODO: add pref for this!
|
||||||
s = s.replace('\n', '\\a ').replace(
|
if len(val) == 7 and val[1] == val[2] and\
|
||||||
'\r', '\\d ').replace(
|
val[3] == val[4] and\
|
||||||
'\f', '\\c ')
|
val[5] == val[6]:
|
||||||
return u'"%s"' % s.replace('"', u'\\"')
|
return u'#%s%s%s' % (val[1], val[3], val[5])
|
||||||
|
|
||||||
def _uri(self, uri):
|
|
||||||
"""returns uri enclosed in url() and "..." if necessary"""
|
|
||||||
if CSSSerializer.__forbidden_in_uri_matcher(uri):
|
|
||||||
return 'url(%s)' % self._string(uri)
|
|
||||||
else:
|
else:
|
||||||
return 'url(%s)' % uri
|
return val
|
||||||
|
|
||||||
def _valid(self, x):
|
def _valid(self, x):
|
||||||
"checks items valid property and prefs.validOnly"
|
"checks items valid property and prefs.validOnly"
|
||||||
@ -384,7 +377,7 @@ class CSSSerializer(object):
|
|||||||
no comments or other things allowed!
|
no comments or other things allowed!
|
||||||
"""
|
"""
|
||||||
if rule.wellformed:
|
if rule.wellformed:
|
||||||
return u'@charset %s;' % self._string(rule.encoding)
|
return u'@charset %s;' % helper.string(rule.encoding)
|
||||||
else:
|
else:
|
||||||
return u''
|
return u''
|
||||||
|
|
||||||
@ -438,8 +431,6 @@ class CSSSerializer(object):
|
|||||||
rule.hreftype == 'string'):
|
rule.hreftype == 'string'):
|
||||||
out.append(val, 'STRING')
|
out.append(val, 'STRING')
|
||||||
else:
|
else:
|
||||||
if not len(self.prefs.spacer):
|
|
||||||
out.append(u' ')
|
|
||||||
out.append(val, 'URI')
|
out.append(val, 'URI')
|
||||||
elif 'media' == typ:
|
elif 'media' == typ:
|
||||||
# media
|
# media
|
||||||
@ -469,9 +460,6 @@ class CSSSerializer(object):
|
|||||||
if rule.wellformed:
|
if rule.wellformed:
|
||||||
out = Out(self)
|
out = Out(self)
|
||||||
out.append(self._atkeyword(rule, u'@namespace'))
|
out.append(self._atkeyword(rule, u'@namespace'))
|
||||||
if not len(self.prefs.spacer):
|
|
||||||
out.append(u' ')
|
|
||||||
|
|
||||||
for item in rule.seq:
|
for item in rule.seq:
|
||||||
typ, val = item.type, item.value
|
typ, val = item.type, item.value
|
||||||
if 'namespaceURI' == typ:
|
if 'namespaceURI' == typ:
|
||||||
@ -509,7 +497,7 @@ class CSSSerializer(object):
|
|||||||
if rule.name:
|
if rule.name:
|
||||||
out.append(self.prefs.spacer)
|
out.append(self.prefs.spacer)
|
||||||
nameout = Out(self)
|
nameout = Out(self)
|
||||||
nameout.append(self._string(rule.name))
|
nameout.append(helper.string(rule.name))
|
||||||
for item in rule.seq:
|
for item in rule.seq:
|
||||||
nameout.append(item.value, item.type)
|
nameout.append(item.value, item.type)
|
||||||
out.append(nameout.value())
|
out.append(nameout.value())
|
||||||
@ -548,16 +536,10 @@ class CSSSerializer(object):
|
|||||||
+ CSSComments
|
+ CSSComments
|
||||||
"""
|
"""
|
||||||
styleText = self.do_css_CSSStyleDeclaration(rule.style)
|
styleText = self.do_css_CSSStyleDeclaration(rule.style)
|
||||||
|
|
||||||
if styleText and rule.wellformed:
|
if styleText and rule.wellformed:
|
||||||
out = Out(self)
|
out = Out(self)
|
||||||
out.append(self._atkeyword(rule, u'@page'))
|
out.append(self._atkeyword(rule, u'@page'))
|
||||||
if not len(self.prefs.spacer):
|
out.append(rule.selectorText)
|
||||||
out.append(u' ')
|
|
||||||
|
|
||||||
for item in rule.seq:
|
|
||||||
out.append(item.value, item.type)
|
|
||||||
|
|
||||||
out.append(u'{')
|
out.append(u'{')
|
||||||
out.append(u'%s%s}' % (styleText, self.prefs.lineSeparator),
|
out.append(u'%s%s}' % (styleText, self.prefs.lineSeparator),
|
||||||
indent=1)
|
indent=1)
|
||||||
@ -565,6 +547,16 @@ class CSSSerializer(object):
|
|||||||
else:
|
else:
|
||||||
return u''
|
return u''
|
||||||
|
|
||||||
|
def do_CSSPageRuleSelector(self, seq):
|
||||||
|
"Serialize selector of a CSSPageRule"
|
||||||
|
out = Out(self)
|
||||||
|
for item in seq:
|
||||||
|
if item.type == 'IDENT':
|
||||||
|
out.append(item.value, item.type, space=False)
|
||||||
|
else:
|
||||||
|
out.append(item.value, item.type)
|
||||||
|
return out.value()
|
||||||
|
|
||||||
def do_CSSUnknownRule(self, rule):
|
def do_CSSUnknownRule(self, rule):
|
||||||
"""
|
"""
|
||||||
serializes CSSUnknownRule
|
serializes CSSUnknownRule
|
||||||
@ -574,8 +566,6 @@ class CSSSerializer(object):
|
|||||||
if rule.wellformed:
|
if rule.wellformed:
|
||||||
out = Out(self)
|
out = Out(self)
|
||||||
out.append(rule.atkeyword)
|
out.append(rule.atkeyword)
|
||||||
if not len(self.prefs.spacer):
|
|
||||||
out.append(u' ')
|
|
||||||
|
|
||||||
stacks = []
|
stacks = []
|
||||||
for item in rule.seq:
|
for item in rule.seq:
|
||||||
@ -751,7 +741,7 @@ class CSSSerializer(object):
|
|||||||
out.append(separator)
|
out.append(separator)
|
||||||
elif isinstance(val, cssutils.css.Property):
|
elif isinstance(val, cssutils.css.Property):
|
||||||
# PropertySimilarNameList
|
# PropertySimilarNameList
|
||||||
out.append(self.do_Property(val))
|
out.append(val.cssText)
|
||||||
if not (self.prefs.omitLastSemicolon and i==len(seq)-1):
|
if not (self.prefs.omitLastSemicolon and i==len(seq)-1):
|
||||||
out.append(u';')
|
out.append(u';')
|
||||||
out.append(separator)
|
out.append(separator)
|
||||||
@ -823,7 +813,6 @@ class CSSSerializer(object):
|
|||||||
a Properties priority "!" S* "important"
|
a Properties priority "!" S* "important"
|
||||||
"""
|
"""
|
||||||
# TODO: use Out()
|
# TODO: use Out()
|
||||||
|
|
||||||
out = []
|
out = []
|
||||||
for part in priorityseq:
|
for part in priorityseq:
|
||||||
if hasattr(part, 'cssText'): # comments
|
if hasattr(part, 'cssText'): # comments
|
||||||
@ -836,72 +825,47 @@ class CSSSerializer(object):
|
|||||||
|
|
||||||
def do_css_CSSValue(self, cssvalue):
|
def do_css_CSSValue(self, cssvalue):
|
||||||
"""Serializes a CSSValue"""
|
"""Serializes a CSSValue"""
|
||||||
# TODO: use self._valid(cssvalue)?
|
|
||||||
if not cssvalue:
|
if not cssvalue:
|
||||||
return u''
|
return u''
|
||||||
else:
|
else:
|
||||||
out = Out(self)
|
out = Out(self)
|
||||||
for item in cssvalue.seq:
|
for item in cssvalue.seq:
|
||||||
type_, val = item.type, item.value
|
type_, val = item.type, item.value
|
||||||
if type_ in (cssutils.css.CSSColor,
|
if hasattr(val, 'cssText'):
|
||||||
cssutils.css.CSSValue):
|
# RGBColor or CSSValue if a CSSValueList
|
||||||
# CSSColor or CSSValue if a CSSValueList
|
out.append(val.cssText, type_)
|
||||||
out.append(val.cssText, type_, space=False, keepS=True)
|
|
||||||
else:
|
else:
|
||||||
if val and val[0] == val[-1] and val[0] in '\'"':
|
if val and val[0] == val[-1] and val[0] in '\'"':
|
||||||
val = self._string(val[1:-1])
|
val = helper.string(val[1:-1])
|
||||||
# S must be kept! in between values but no extra space
|
# S must be kept! in between values but no extra space
|
||||||
out.append(val, type_, space=False, keepS=True)
|
out.append(val, type_)
|
||||||
|
|
||||||
return out.value()
|
return out.value()
|
||||||
|
|
||||||
def do_css_CSSPrimitiveValue(self, cssvalue):
|
def do_css_CSSPrimitiveValue(self, cssvalue):
|
||||||
"""Serialize a CSSPrimitiveValue"""
|
"""Serialize a CSSPrimitiveValue"""
|
||||||
# TODO: use self._valid(cssvalue)?
|
|
||||||
if not cssvalue:
|
if not cssvalue:
|
||||||
return u''
|
return u''
|
||||||
else:
|
else:
|
||||||
out = Out(self)
|
out = Out(self)
|
||||||
|
|
||||||
unary = None
|
|
||||||
for item in cssvalue.seq:
|
for item in cssvalue.seq:
|
||||||
type_, val = item.type, item.value
|
type_, val = item.type, item.value
|
||||||
if 'CHAR' == type_ and val in u'+-':
|
if type_ in ('DIMENSION', 'NUMBER', 'PERCENTAGE'):
|
||||||
# save for next round
|
n, d = cssvalue._getNumDim(val)
|
||||||
unary = val
|
if 0 == n:
|
||||||
continue
|
if cssvalue.primitiveType in cssvalue._lengthtypes:
|
||||||
if cssutils.css.CSSColor == type_:
|
# 0 if zero value
|
||||||
# Comment or CSSColor
|
|
||||||
val = val.cssText
|
|
||||||
elif type_ in ('DIMENSION', 'NUMBER', 'PERCENTAGE'):
|
|
||||||
# handle saved unary and add to number
|
|
||||||
try:
|
|
||||||
# NUMBER or DIMENSION and is it 0?
|
|
||||||
if 0 == cssvalue.getFloatValue():
|
|
||||||
val = u'0'
|
val = u'0'
|
||||||
else:
|
else:
|
||||||
# add unary to val if not 0
|
val = u'0' + d
|
||||||
# TODO: only for lengths!
|
else:
|
||||||
if u'-' == unary:
|
val = unicode(n) + d
|
||||||
val = unary + val
|
|
||||||
except xml.dom.InvalidAccessErr, e:
|
|
||||||
pass
|
|
||||||
unary = None
|
|
||||||
elif unary:
|
|
||||||
# or simple add
|
|
||||||
out.append(unary, 'CHAR', space=False, keepS=True)
|
|
||||||
unary = None
|
|
||||||
|
|
||||||
out.append(val, type_)
|
out.append(val, type_)
|
||||||
# if hasattr(val, 'cssText'):
|
|
||||||
# # comments or CSSValue if a CSSValueList
|
|
||||||
# out.append(val.cssText, type_)
|
|
||||||
# else:
|
|
||||||
# out.append(val, type_) #?
|
|
||||||
|
|
||||||
return out.value()
|
return out.value()
|
||||||
|
|
||||||
def do_css_CSSColor(self, cssvalue):
|
def do_css_RGBColor(self, cssvalue):
|
||||||
"""Serialize a CSSColor value"""
|
"""Serialize a RGBColor value"""
|
||||||
if not cssvalue:
|
if not cssvalue:
|
||||||
return u''
|
return u''
|
||||||
else:
|
else:
|
||||||
@ -910,21 +874,16 @@ class CSSSerializer(object):
|
|||||||
for item in cssvalue.seq:
|
for item in cssvalue.seq:
|
||||||
type_, val = item.type, item.value
|
type_, val = item.type, item.value
|
||||||
|
|
||||||
# prepare
|
# # prepare
|
||||||
if 'HASH' == type_:
|
# if 'CHAR' == type_ and val in u'+-':
|
||||||
# TODO: add pref for this!
|
# # save - for next round
|
||||||
if len(val) == 7 and val[1] == val[2] and \
|
# if u'-' == val:
|
||||||
val[3] == val[4] and val[5] == val[6]:
|
# # omit +
|
||||||
val = u'#%s%s%s' % (val[1], val[3], val[5])
|
# unary = val
|
||||||
elif 'CHAR' == type_ and val in u'+-':
|
# continue
|
||||||
# save - for next round
|
# elif unary:
|
||||||
if u'-' == val:
|
# val = unary + val.cssText
|
||||||
# omit +
|
# unary = None
|
||||||
unary = val
|
|
||||||
continue
|
|
||||||
elif unary:
|
|
||||||
val = unary + val.cssText
|
|
||||||
unary = None
|
|
||||||
|
|
||||||
out.append(val, type_)
|
out.append(val, type_)
|
||||||
|
|
||||||
@ -960,3 +919,29 @@ class CSSSerializer(object):
|
|||||||
return u' '.join(out)
|
return u' '.join(out)
|
||||||
else:
|
else:
|
||||||
return u''
|
return u''
|
||||||
|
|
||||||
|
|
||||||
|
def do_css_ExpressionValue(self, cssvalue):
|
||||||
|
"""Serialize an ExpressionValue (IE only),
|
||||||
|
should at least keep the original syntax"""
|
||||||
|
if not cssvalue:
|
||||||
|
return u''
|
||||||
|
else:
|
||||||
|
out = Out(self)
|
||||||
|
for item in cssvalue.seq:
|
||||||
|
type_, val = item.type, item.value
|
||||||
|
if type_ in ('DIMENSION', 'NUMBER', 'PERCENTAGE'):
|
||||||
|
n, d = cssvalue._getNumDim(val)
|
||||||
|
if 0 == n:
|
||||||
|
if cssvalue.primitiveType in cssvalue._lengthtypes:
|
||||||
|
# 0 if zero value
|
||||||
|
val = u'0'
|
||||||
|
else:
|
||||||
|
val = u'0' + d
|
||||||
|
else:
|
||||||
|
val = unicode(n) + d
|
||||||
|
# do no send type_ so no special cases!
|
||||||
|
out.append(val, None, space=False)
|
||||||
|
|
||||||
|
return out.value()
|
||||||
|
|
@ -1,16 +1,9 @@
|
|||||||
"""
|
"""Implements Document Object Model Level 2 Style Sheets
|
||||||
Document Object Model Level 2 Style Sheets
|
|
||||||
http://www.w3.org/TR/2000/PR-DOM-Level-2-Style-20000927/stylesheets.html
|
http://www.w3.org/TR/2000/PR-DOM-Level-2-Style-20000927/stylesheets.html
|
||||||
|
|
||||||
currently implemented:
|
|
||||||
- MediaList
|
|
||||||
- MediaQuery (http://www.w3.org/TR/css3-mediaqueries/)
|
|
||||||
- StyleSheet
|
|
||||||
- StyleSheetList
|
|
||||||
"""
|
"""
|
||||||
__all__ = ['MediaList', 'MediaQuery', 'StyleSheet', 'StyleSheetList']
|
__all__ = ['MediaList', 'MediaQuery', 'StyleSheet', 'StyleSheetList']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: __init__.py 1116 2008-03-05 13:52:23Z cthedot $'
|
__version__ = '$Id: __init__.py 1588 2009-01-01 20:16:13Z cthedot $'
|
||||||
|
|
||||||
from medialist import *
|
from medialist import *
|
||||||
from mediaquery import *
|
from mediaquery import *
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
"""
|
"""MediaList implements DOM Level 2 Style Sheets MediaList.
|
||||||
MediaList implements DOM Level 2 Style Sheets MediaList.
|
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
- delete: maybe if deleting from all, replace *all* with all others?
|
- delete: maybe if deleting from all, replace *all* with all others?
|
||||||
@ -7,49 +6,36 @@ TODO:
|
|||||||
"""
|
"""
|
||||||
__all__ = ['MediaList']
|
__all__ = ['MediaList']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: medialist.py 1423 2008-08-11 12:43:22Z cthedot $'
|
__version__ = '$Id: medialist.py 1605 2009-01-03 18:27:32Z cthedot $'
|
||||||
|
|
||||||
import xml.dom
|
|
||||||
import cssutils
|
|
||||||
from cssutils.css import csscomment
|
from cssutils.css import csscomment
|
||||||
from mediaquery import MediaQuery
|
from mediaquery import MediaQuery
|
||||||
|
import cssutils
|
||||||
|
import xml.dom
|
||||||
|
|
||||||
class MediaList(cssutils.util.Base, cssutils.util.ListSeq):
|
class MediaList(cssutils.util.Base, cssutils.util.ListSeq):
|
||||||
"""
|
"""Provides the abstraction of an ordered collection of media,
|
||||||
Provides the abstraction of an ordered collection of media,
|
|
||||||
without defining or constraining how this collection is
|
without defining or constraining how this collection is
|
||||||
implemented.
|
implemented.
|
||||||
|
|
||||||
A media is always an instance of MediaQuery.
|
A single media in the list is an instance of :class:`MediaQuery`.
|
||||||
|
|
||||||
An empty list is the same as a list that contains the medium "all".
|
An empty list is the same as a list that contains the medium "all".
|
||||||
|
|
||||||
Properties
|
Format from CSS2.1::
|
||||||
==========
|
|
||||||
length:
|
|
||||||
The number of MediaQuery objects in the list.
|
|
||||||
mediaText: of type DOMString
|
|
||||||
The parsable textual representation of this MediaList
|
|
||||||
self: a list (cssutils)
|
|
||||||
All MediaQueries in this MediaList
|
|
||||||
wellformed:
|
|
||||||
if this list is wellformed
|
|
||||||
|
|
||||||
Format
|
|
||||||
======
|
|
||||||
::
|
|
||||||
|
|
||||||
medium [ COMMA S* medium ]*
|
medium [ COMMA S* medium ]*
|
||||||
|
|
||||||
New::
|
New format with :class:`MediaQuery`::
|
||||||
|
|
||||||
<media_query> [, <media_query> ]*
|
<media_query> [, <media_query> ]*
|
||||||
"""
|
"""
|
||||||
def __init__(self, mediaText=None, readonly=False):
|
def __init__(self, mediaText=None, readonly=False):
|
||||||
"""
|
"""
|
||||||
mediaText
|
:param mediaText:
|
||||||
unicodestring of parsable comma separared media
|
Unicodestring of parsable comma separared media
|
||||||
or a list of media
|
or a (Python) list of media.
|
||||||
|
:param readonly:
|
||||||
|
Not used yet.
|
||||||
"""
|
"""
|
||||||
super(MediaList, self).__init__()
|
super(MediaList, self).__init__()
|
||||||
self._wellformed = False
|
self._wellformed = False
|
||||||
@ -62,27 +48,31 @@ class MediaList(cssutils.util.Base, cssutils.util.ListSeq):
|
|||||||
|
|
||||||
self._readonly = readonly
|
self._readonly = readonly
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "cssutils.stylesheets.%s(mediaText=%r)" % (
|
||||||
|
self.__class__.__name__, self.mediaText)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "<cssutils.stylesheets.%s object mediaText=%r at 0x%x>" % (
|
||||||
|
self.__class__.__name__, self.mediaText, id(self))
|
||||||
|
|
||||||
length = property(lambda self: len(self),
|
length = property(lambda self: len(self),
|
||||||
doc="(DOM readonly) The number of media in the list.")
|
doc="The number of media in the list (DOM readonly).")
|
||||||
|
|
||||||
def _getMediaText(self):
|
def _getMediaText(self):
|
||||||
"""
|
|
||||||
returns serialized property mediaText
|
|
||||||
"""
|
|
||||||
return cssutils.ser.do_stylesheets_medialist(self)
|
return cssutils.ser.do_stylesheets_medialist(self)
|
||||||
|
|
||||||
def _setMediaText(self, mediaText):
|
def _setMediaText(self, mediaText):
|
||||||
"""
|
"""
|
||||||
mediaText
|
:param mediaText:
|
||||||
simple value or comma-separated list of media
|
simple value or comma-separated list of media
|
||||||
|
|
||||||
DOMException
|
:exceptions:
|
||||||
|
- - :exc:`~xml.dom.SyntaxErr`:
|
||||||
- SYNTAX_ERR: (MediaQuery)
|
Raised if the specified string value has a syntax error and is
|
||||||
Raised if the specified string value has a syntax error and is
|
unparsable.
|
||||||
unparsable.
|
- - :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
Raised if this media list is readonly.
|
||||||
Raised if this media list is readonly.
|
|
||||||
"""
|
"""
|
||||||
self._checkReadonly()
|
self._checkReadonly()
|
||||||
wellformed = True
|
wellformed = True
|
||||||
@ -121,10 +111,7 @@ class MediaList(cssutils.util.Base, cssutils.util.ListSeq):
|
|||||||
self._wellformed = True
|
self._wellformed = True
|
||||||
|
|
||||||
mediaText = property(_getMediaText, _setMediaText,
|
mediaText = property(_getMediaText, _setMediaText,
|
||||||
doc="""(DOM) The parsable textual representation of the media list.
|
doc="The parsable textual representation of the media list.")
|
||||||
This is a comma-separated list of media.""")
|
|
||||||
|
|
||||||
wellformed = property(lambda self: self._wellformed)
|
|
||||||
|
|
||||||
def __prepareset(self, newMedium):
|
def __prepareset(self, newMedium):
|
||||||
# used by appendSelector and __setitem__
|
# used by appendSelector and __setitem__
|
||||||
@ -137,10 +124,9 @@ class MediaList(cssutils.util.Base, cssutils.util.ListSeq):
|
|||||||
return newMedium
|
return newMedium
|
||||||
|
|
||||||
def __setitem__(self, index, newMedium):
|
def __setitem__(self, index, newMedium):
|
||||||
"""
|
"""Overwriting ListSeq.__setitem__
|
||||||
overwrites ListSeq.__setitem__
|
|
||||||
|
|
||||||
Any duplicate items are **not** removed.
|
Any duplicate items are **not yet** removed.
|
||||||
"""
|
"""
|
||||||
newMedium = self.__prepareset(newMedium)
|
newMedium = self.__prepareset(newMedium)
|
||||||
if newMedium:
|
if newMedium:
|
||||||
@ -148,28 +134,23 @@ class MediaList(cssutils.util.Base, cssutils.util.ListSeq):
|
|||||||
# TODO: remove duplicates?
|
# TODO: remove duplicates?
|
||||||
|
|
||||||
def appendMedium(self, newMedium):
|
def appendMedium(self, newMedium):
|
||||||
"""
|
"""Add the `newMedium` to the end of the list.
|
||||||
(DOM)
|
If the `newMedium` is already used, it is first removed.
|
||||||
Adds the medium newMedium to the end of the list. If the newMedium
|
|
||||||
is already used, it is first removed.
|
|
||||||
|
|
||||||
newMedium
|
:param newMedium:
|
||||||
a string or a MediaQuery object
|
a string or a :class:`~cssutils.stylesheets.MediaQuery`
|
||||||
|
:returns: Wellformedness of `newMedium`.
|
||||||
returns if newMedium is wellformed
|
:exceptions:
|
||||||
|
- :exc:`~xml.dom.InvalidCharacterErr`:
|
||||||
DOMException
|
If the medium contains characters that are invalid in the
|
||||||
|
underlying style language.
|
||||||
- INVALID_CHARACTER_ERR: (self)
|
- :exc:`~xml.dom.InvalidModificationErr`:
|
||||||
If the medium contains characters that are invalid in the
|
If mediaText is "all" and a new medium is tried to be added.
|
||||||
underlying style language.
|
Exception is "handheld" which is set in any case (Opera does handle
|
||||||
- INVALID_MODIFICATION_ERR (self)
|
"all, handheld" special, this special case might be removed in the
|
||||||
If mediaText is "all" and a new medium is tried to be added.
|
future).
|
||||||
Exception is "handheld" which is set in any case (Opera does handle
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
"all, handheld" special, this special case might be removed in the
|
Raised if this list is readonly.
|
||||||
future).
|
|
||||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
|
||||||
Raised if this list is readonly.
|
|
||||||
"""
|
"""
|
||||||
newMedium = self.__prepareset(newMedium)
|
newMedium = self.__prepareset(newMedium)
|
||||||
|
|
||||||
@ -207,20 +188,19 @@ class MediaList(cssutils.util.Base, cssutils.util.ListSeq):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def append(self, newMedium):
|
def append(self, newMedium):
|
||||||
"overwrites ListSeq.append"
|
"Same as :meth:`appendMedium`."
|
||||||
self.appendMedium(newMedium)
|
self.appendMedium(newMedium)
|
||||||
|
|
||||||
def deleteMedium(self, oldMedium):
|
def deleteMedium(self, oldMedium):
|
||||||
"""
|
"""Delete a medium from the list.
|
||||||
(DOM)
|
|
||||||
Deletes the medium indicated by oldMedium from the list.
|
|
||||||
|
|
||||||
DOMException
|
:param oldMedium:
|
||||||
|
delete this medium from the list.
|
||||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
:exceptions:
|
||||||
Raised if this list is readonly.
|
- :exc:`~xml.dom.NotFoundErr`:
|
||||||
- NOT_FOUND_ERR: (self)
|
Raised if `oldMedium` is not in the list.
|
||||||
Raised if oldMedium is not in the list.
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
|
Raised if this list is readonly.
|
||||||
"""
|
"""
|
||||||
self._checkReadonly()
|
self._checkReadonly()
|
||||||
oldMedium = self._normalize(oldMedium)
|
oldMedium = self._normalize(oldMedium)
|
||||||
@ -232,25 +212,15 @@ class MediaList(cssutils.util.Base, cssutils.util.ListSeq):
|
|||||||
else:
|
else:
|
||||||
self._log.error(u'"%s" not in this MediaList' % oldMedium,
|
self._log.error(u'"%s" not in this MediaList' % oldMedium,
|
||||||
error=xml.dom.NotFoundErr)
|
error=xml.dom.NotFoundErr)
|
||||||
# raise xml.dom.NotFoundErr(
|
|
||||||
# u'"%s" not in this MediaList' % oldMedium)
|
|
||||||
|
|
||||||
def item(self, index):
|
def item(self, index):
|
||||||
"""
|
"""Return the mediaType of the `index`'th element in the list.
|
||||||
(DOM)
|
If `index` is greater than or equal to the number of media in the
|
||||||
Returns the mediaType of the index'th element in the list.
|
list, returns ``None``.
|
||||||
If index is greater than or equal to the number of media in the
|
|
||||||
list, returns None.
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return self[index].mediaType
|
return self[index].mediaType
|
||||||
except IndexError:
|
except IndexError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def __repr__(self):
|
wellformed = property(lambda self: self._wellformed)
|
||||||
return "cssutils.stylesheets.%s(mediaText=%r)" % (
|
|
||||||
self.__class__.__name__, self.mediaText)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "<cssutils.stylesheets.%s object mediaText=%r at 0x%x>" % (
|
|
||||||
self.__class__.__name__, self.mediaText, id(self))
|
|
||||||
|
@ -1,41 +1,22 @@
|
|||||||
"""
|
"""Implements a DOM for MediaQuery, see
|
||||||
MediaQuery, see http://www.w3.org/TR/css3-mediaqueries/
|
http://www.w3.org/TR/css3-mediaqueries/.
|
||||||
|
|
||||||
A cssutils own implementation, not defined in official DOM
|
A cssutils implementation, not defined in official DOM.
|
||||||
|
|
||||||
TODO:
|
|
||||||
add possibility to
|
|
||||||
|
|
||||||
part of a media_query_list: <media_query> [, <media_query> ]*
|
|
||||||
see stylesheets.MediaList
|
|
||||||
"""
|
"""
|
||||||
__all__ = ['MediaQuery']
|
__all__ = ['MediaQuery']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: mediaquery.py 1363 2008-07-13 18:14:26Z cthedot $'
|
__version__ = '$Id: mediaquery.py 1638 2009-01-13 20:39:33Z cthedot $'
|
||||||
|
|
||||||
|
import cssutils
|
||||||
import re
|
import re
|
||||||
import xml.dom
|
import xml.dom
|
||||||
import cssutils
|
|
||||||
|
|
||||||
class MediaQuery(cssutils.util.Base):
|
class MediaQuery(cssutils.util.Base):
|
||||||
"""
|
"""
|
||||||
A Media Query consists of a media type and one or more
|
A Media Query consists of one of :const:`MediaQuery.MEDIA_TYPES`
|
||||||
expressions involving media features.
|
and one or more expressions involving media features.
|
||||||
|
|
||||||
Properties
|
Format::
|
||||||
==========
|
|
||||||
mediaText: of type DOMString
|
|
||||||
The parsable textual representation of this MediaQuery
|
|
||||||
mediaType: of type DOMString
|
|
||||||
one of MEDIA_TYPES like e.g. 'print'
|
|
||||||
seq: a list (cssutils)
|
|
||||||
All parts of this MediaQuery including CSSComments
|
|
||||||
wellformed:
|
|
||||||
if this query is wellformed
|
|
||||||
|
|
||||||
Format
|
|
||||||
======
|
|
||||||
::
|
|
||||||
|
|
||||||
media_query: [[only | not]? <media_type> [ and <expression> ]*]
|
media_query: [[only | not]? <media_type> [ and <expression> ]*]
|
||||||
| <expression> [ and <expression> ]*
|
| <expression> [ and <expression> ]*
|
||||||
@ -65,7 +46,7 @@ class MediaQuery(cssutils.util.Base):
|
|||||||
|
|
||||||
def __init__(self, mediaText=None, readonly=False):
|
def __init__(self, mediaText=None, readonly=False):
|
||||||
"""
|
"""
|
||||||
mediaText
|
:param mediaText:
|
||||||
unicodestring of parsable media
|
unicodestring of parsable media
|
||||||
"""
|
"""
|
||||||
super(MediaQuery, self).__init__()
|
super(MediaQuery, self).__init__()
|
||||||
@ -77,26 +58,30 @@ class MediaQuery(cssutils.util.Base):
|
|||||||
|
|
||||||
self._readonly = readonly
|
self._readonly = readonly
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "cssutils.stylesheets.%s(mediaText=%r)" % (
|
||||||
|
self.__class__.__name__, self.mediaText)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "<cssutils.stylesheets.%s object mediaText=%r at 0x%x>" % (
|
||||||
|
self.__class__.__name__, self.mediaText, id(self))
|
||||||
|
|
||||||
def _getMediaText(self):
|
def _getMediaText(self):
|
||||||
"""
|
|
||||||
returns serialized property mediaText
|
|
||||||
"""
|
|
||||||
return cssutils.ser.do_stylesheets_mediaquery(self)
|
return cssutils.ser.do_stylesheets_mediaquery(self)
|
||||||
|
|
||||||
def _setMediaText(self, mediaText):
|
def _setMediaText(self, mediaText):
|
||||||
"""
|
"""
|
||||||
mediaText
|
:param mediaText:
|
||||||
a single media query string, e.g. "print and (min-width: 25cm)"
|
a single media query string, e.g. ``print and (min-width: 25cm)``
|
||||||
|
|
||||||
DOMException
|
:exceptions:
|
||||||
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
- SYNTAX_ERR: (self)
|
Raised if the specified string value has a syntax error and is
|
||||||
Raised if the specified string value has a syntax error and is
|
unparsable.
|
||||||
unparsable.
|
- :exc:`~xml.dom.InvalidCharacterErr`:
|
||||||
- INVALID_CHARACTER_ERR: (self)
|
Raised if the given mediaType is unknown.
|
||||||
Raised if the given mediaType is unknown.
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
Raised if this media query is readonly.
|
||||||
Raised if this media query is readonly.
|
|
||||||
"""
|
"""
|
||||||
self._checkReadonly()
|
self._checkReadonly()
|
||||||
tokenizer = self._tokenize2(mediaText)
|
tokenizer = self._tokenize2(mediaText)
|
||||||
@ -171,29 +156,21 @@ class MediaQuery(cssutils.util.Base):
|
|||||||
self.seq = newseq
|
self.seq = newseq
|
||||||
|
|
||||||
mediaText = property(_getMediaText, _setMediaText,
|
mediaText = property(_getMediaText, _setMediaText,
|
||||||
doc="""(DOM) The parsable textual representation of the media list.
|
doc="The parsable textual representation of the media list.")
|
||||||
This is a comma-separated list of media.""")
|
|
||||||
|
|
||||||
def _getMediaType(self):
|
|
||||||
"""
|
|
||||||
returns serialized property mediaText
|
|
||||||
"""
|
|
||||||
return self._mediaType
|
|
||||||
|
|
||||||
def _setMediaType(self, mediaType):
|
def _setMediaType(self, mediaType):
|
||||||
"""
|
"""
|
||||||
mediaType
|
:param mediaType:
|
||||||
one of MEDIA_TYPES
|
one of :attr:`MEDIA_TYPES`
|
||||||
|
|
||||||
DOMException
|
:exceptions:
|
||||||
|
- :exc:`~xml.dom.SyntaxErr`:
|
||||||
- SYNTAX_ERR: (self)
|
Raised if the specified string value has a syntax error and is
|
||||||
Raised if the specified string value has a syntax error and is
|
unparsable.
|
||||||
unparsable.
|
- :exc:`~xml.dom.InvalidCharacterErr`:
|
||||||
- INVALID_CHARACTER_ERR: (self)
|
Raised if the given mediaType is unknown.
|
||||||
Raised if the given mediaType is unknown.
|
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
Raised if this media query is readonly.
|
||||||
Raised if this media query is readonly.
|
|
||||||
"""
|
"""
|
||||||
self._checkReadonly()
|
self._checkReadonly()
|
||||||
nmediaType = self._normalize(mediaType)
|
nmediaType = self._normalize(mediaType)
|
||||||
@ -223,15 +200,8 @@ class MediaQuery(cssutils.util.Base):
|
|||||||
else:
|
else:
|
||||||
self.seq.insert(0, mediaType)
|
self.seq.insert(0, mediaType)
|
||||||
|
|
||||||
mediaType = property(_getMediaType, _setMediaType,
|
mediaType = property(lambda self: self._mediaType, _setMediaType,
|
||||||
doc="""(DOM) media type (one of MediaQuery.MEDIA_TYPES) of this MediaQuery.""")
|
doc="The media type of this MediaQuery (one of "
|
||||||
|
":attr:`MEDIA_TYPES`).")
|
||||||
|
|
||||||
wellformed = property(lambda self: bool(len(self.seq)))
|
wellformed = property(lambda self: bool(len(self.seq)))
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "cssutils.stylesheets.%s(mediaText=%r)" % (
|
|
||||||
self.__class__.__name__, self.mediaText)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "<cssutils.stylesheets.%s object mediaText=%r at 0x%x>" % (
|
|
||||||
self.__class__.__name__, self.mediaText, id(self))
|
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
"""
|
"""StyleSheet implements DOM Level 2 Style Sheets StyleSheet."""
|
||||||
StyleSheet implements DOM Level 2 Style Sheets StyleSheet.
|
|
||||||
"""
|
|
||||||
__all__ = ['StyleSheet']
|
__all__ = ['StyleSheet']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: stylesheet.py 1284 2008-06-05 16:29:17Z cthedot $'
|
__version__ = '$Id: stylesheet.py 1629 2009-01-04 18:58:47Z cthedot $'
|
||||||
|
|
||||||
import urlparse
|
|
||||||
import cssutils
|
import cssutils
|
||||||
|
import urlparse
|
||||||
|
|
||||||
class StyleSheet(cssutils.util.Base2):
|
class StyleSheet(cssutils.util.Base2):
|
||||||
"""
|
"""
|
||||||
@ -16,7 +14,7 @@ class StyleSheet(cssutils.util.Base2):
|
|||||||
|
|
||||||
In HTML, the StyleSheet interface represents either an
|
In HTML, the StyleSheet interface represents either an
|
||||||
external style sheet, included via the HTML LINK element,
|
external style sheet, included via the HTML LINK element,
|
||||||
or an inline STYLE element (-ch: also an @import stylesheet?).
|
or an inline STYLE element (also an @import stylesheet?).
|
||||||
|
|
||||||
In XML, this interface represents
|
In XML, this interface represents
|
||||||
an external style sheet, included via a style sheet
|
an external style sheet, included via a style sheet
|
||||||
@ -30,14 +28,8 @@ class StyleSheet(cssutils.util.Base2):
|
|||||||
ownerNode=None,
|
ownerNode=None,
|
||||||
parentStyleSheet=None):
|
parentStyleSheet=None):
|
||||||
"""
|
"""
|
||||||
type: readonly
|
type
|
||||||
This specifies the style sheet language for this
|
readonly
|
||||||
style sheet. The style sheet language is specified
|
|
||||||
as a content type (e.g. "text/css"). The content
|
|
||||||
type is often specified in the ownerNode. Also see
|
|
||||||
the type attribute definition for the LINK element
|
|
||||||
in HTML 4.0, and the type pseudo-attribute for the
|
|
||||||
XML style sheet processing instruction.
|
|
||||||
href: readonly
|
href: readonly
|
||||||
If the style sheet is a linked style sheet, the value
|
If the style sheet is a linked style sheet, the value
|
||||||
of this attribute is its location. For inline style
|
of this attribute is its location. For inline style
|
||||||
@ -74,12 +66,6 @@ class StyleSheet(cssutils.util.Base2):
|
|||||||
included by other style sheets, the value of this
|
included by other style sheets, the value of this
|
||||||
attribute is None.
|
attribute is None.
|
||||||
parentStyleSheet: of type StyleSheet, readonly
|
parentStyleSheet: of type StyleSheet, readonly
|
||||||
For style sheet languages that support the concept
|
|
||||||
of style sheet inclusion, this attribute represents
|
|
||||||
the including style sheet, if one exists. If the style
|
|
||||||
sheet is a top-level style sheet, or the style sheet
|
|
||||||
language does not support inclusion, the value of this
|
|
||||||
attribute is None.
|
|
||||||
"""
|
"""
|
||||||
super(StyleSheet, self).__init__()
|
super(StyleSheet, self).__init__()
|
||||||
|
|
||||||
@ -92,10 +78,31 @@ class StyleSheet(cssutils.util.Base2):
|
|||||||
self.media = media
|
self.media = media
|
||||||
self.title = title
|
self.title = title
|
||||||
|
|
||||||
href = property(lambda self: self._href)
|
href = property(lambda self: self._href,
|
||||||
|
doc="If the style sheet is a linked style sheet, the value "
|
||||||
|
"of this attribute is its location. For inline style "
|
||||||
|
"sheets, the value of this attribute is None. See the "
|
||||||
|
"href attribute definition for the LINK element in HTML "
|
||||||
|
"4.0, and the href pseudo-attribute for the XML style "
|
||||||
|
"sheet processing instruction.")
|
||||||
|
|
||||||
ownerNode = property(lambda self: self._ownerNode)
|
ownerNode = property(lambda self: self._ownerNode,
|
||||||
|
doc="Not used in cssutils yet.")
|
||||||
|
|
||||||
parentStyleSheet = property(lambda self: self._parentStyleSheet)
|
parentStyleSheet = property(lambda self: self._parentStyleSheet,
|
||||||
|
doc="For style sheet languages that support the concept "
|
||||||
|
"of style sheet inclusion, this attribute represents "
|
||||||
|
"the including style sheet, if one exists. If the style "
|
||||||
|
"sheet is a top-level style sheet, or the style sheet "
|
||||||
|
"language does not support inclusion, the value of this "
|
||||||
|
"attribute is None.")
|
||||||
|
|
||||||
type = property(lambda self: self._type, doc=u'Default: "ext/css"')
|
type = property(lambda self: self._type,
|
||||||
|
doc="This specifies the style sheet language for this "
|
||||||
|
"style sheet. The style sheet language is specified "
|
||||||
|
"as a content type (e.g. ``text/css``). The content "
|
||||||
|
"type is often specified in the ownerNode. Also see "
|
||||||
|
"the type attribute definition for the LINK element "
|
||||||
|
"in HTML 4.0, and the type pseudo-attribute for the "
|
||||||
|
"XML style sheet processing instruction. "
|
||||||
|
"For CSS this is always ``text/css``.")
|
||||||
|
@ -1,18 +1,15 @@
|
|||||||
"""
|
"""StyleSheetList implements DOM Level 2 Style Sheets StyleSheetList."""
|
||||||
StyleSheetList implements DOM Level 2 Style Sheets StyleSheetList.
|
|
||||||
"""
|
|
||||||
__all__ = ['StyleSheetList']
|
__all__ = ['StyleSheetList']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: stylesheetlist.py 1116 2008-03-05 13:52:23Z cthedot $'
|
__version__ = '$Id: stylesheetlist.py 1629 2009-01-04 18:58:47Z cthedot $'
|
||||||
|
|
||||||
class StyleSheetList(list):
|
class StyleSheetList(list):
|
||||||
"""
|
"""Interface `StyleSheetList` (introduced in DOM Level 2)
|
||||||
Interface StyleSheetList (introduced in DOM Level 2)
|
|
||||||
|
|
||||||
The StyleSheetList interface provides the abstraction of an ordered
|
The `StyleSheetList` interface provides the abstraction of an ordered
|
||||||
collection of style sheets.
|
collection of :class:`~cssutils.stylesheets.StyleSheet` objects.
|
||||||
|
|
||||||
The items in the StyleSheetList are accessible via an integral index,
|
The items in the `StyleSheetList` are accessible via an integral index,
|
||||||
starting from 0.
|
starting from 0.
|
||||||
|
|
||||||
This Python implementation is based on a standard Python list so e.g.
|
This Python implementation is based on a standard Python list so e.g.
|
||||||
@ -20,9 +17,9 @@ class StyleSheetList(list):
|
|||||||
"""
|
"""
|
||||||
def item(self, index):
|
def item(self, index):
|
||||||
"""
|
"""
|
||||||
Used to retrieve a style sheet by ordinal index. If index is
|
Used to retrieve a style sheet by ordinal `index`. If `index` is
|
||||||
greater than or equal to the number of style sheets in the list,
|
greater than or equal to the number of style sheets in the list,
|
||||||
this returns None.
|
this returns ``None``.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return self[index]
|
return self[index]
|
||||||
@ -30,6 +27,6 @@ class StyleSheetList(list):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
length = property(lambda self: len(self),
|
length = property(lambda self: len(self),
|
||||||
doc="""The number of StyleSheets in the list. The range of valid
|
doc="The number of :class:`StyleSheet` objects in the list. The range"
|
||||||
child stylesheet indices is 0 to length-1 inclusive.""")
|
" of valid child stylesheet indices is 0 to length-1 inclusive.")
|
||||||
|
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
"""
|
"""
|
||||||
__all__ = ['Tokenizer', 'CSSProductions']
|
__all__ = ['Tokenizer', 'CSSProductions']
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: tokenize2.py 1420 2008-08-09 19:28:34Z cthedot $'
|
__version__ = '$Id: tokenize2.py 1547 2008-12-10 20:42:26Z cthedot $'
|
||||||
|
|
||||||
import re
|
|
||||||
from helper import normalize
|
|
||||||
from cssproductions import *
|
from cssproductions import *
|
||||||
|
from helper import normalize
|
||||||
|
import re
|
||||||
|
|
||||||
class Tokenizer(object):
|
class Tokenizer(object):
|
||||||
"""
|
"""
|
||||||
@ -23,6 +23,8 @@ class Tokenizer(object):
|
|||||||
u'@page': CSSProductions.PAGE_SYM
|
u'@page': CSSProductions.PAGE_SYM
|
||||||
}
|
}
|
||||||
_linesep = u'\n'
|
_linesep = u'\n'
|
||||||
|
unicodesub = re.compile(r'\\[0-9a-fA-F]{1,6}(?:\r\n|[\t|\r|\n|\f|\x20])?').sub
|
||||||
|
cleanstring = re.compile(r'\\((\r\n)|[\n|\r|\f])').sub
|
||||||
|
|
||||||
def __init__(self, macros=None, productions=None):
|
def __init__(self, macros=None, productions=None):
|
||||||
"""
|
"""
|
||||||
@ -38,7 +40,6 @@ class Tokenizer(object):
|
|||||||
productions))
|
productions))
|
||||||
self.commentmatcher = [x[1] for x in self.tokenmatches if x[0] == 'COMMENT'][0]
|
self.commentmatcher = [x[1] for x in self.tokenmatches if x[0] == 'COMMENT'][0]
|
||||||
self.urimatcher = [x[1] for x in self.tokenmatches if x[0] == 'URI'][0]
|
self.urimatcher = [x[1] for x in self.tokenmatches if x[0] == 'URI'][0]
|
||||||
self.unicodesub = re.compile(r'\\[0-9a-fA-F]{1,6}(?:\r\n|[\t|\r|\n|\f|\x20])?').sub
|
|
||||||
|
|
||||||
def _expand_macros(self, macros, productions):
|
def _expand_macros(self, macros, productions):
|
||||||
"""returns macro expanded productions, order of productions is kept"""
|
"""returns macro expanded productions, order of productions is kept"""
|
||||||
@ -150,6 +151,9 @@ class Tokenizer(object):
|
|||||||
# may contain unicode escape, replace with normal char
|
# may contain unicode escape, replace with normal char
|
||||||
# but do not _normalize (?)
|
# but do not _normalize (?)
|
||||||
value = self.unicodesub(_repl, found)
|
value = self.unicodesub(_repl, found)
|
||||||
|
if name in ('STRING', 'INVALID'): #'URI'?
|
||||||
|
# remove \ followed by nl (so escaped) from string
|
||||||
|
value = self.cleanstring('', found)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if 'ATKEYWORD' == name:
|
if 'ATKEYWORD' == name:
|
||||||
|
@ -2,25 +2,85 @@
|
|||||||
"""
|
"""
|
||||||
__all__ = []
|
__all__ = []
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
__version__ = '$Id: util.py 1453 2008-09-08 20:57:19Z cthedot $'
|
__version__ = '$Id: util.py 1654 2009-02-03 20:16:20Z cthedot $'
|
||||||
|
|
||||||
import codecs
|
|
||||||
from itertools import ifilter
|
|
||||||
import types
|
|
||||||
import urllib2
|
|
||||||
import xml.dom
|
|
||||||
|
|
||||||
from helper import normalize
|
from helper import normalize
|
||||||
|
from itertools import ifilter
|
||||||
|
import css
|
||||||
|
import codec
|
||||||
|
import codecs
|
||||||
|
import errorhandler
|
||||||
import tokenize2
|
import tokenize2
|
||||||
import cssutils
|
import types
|
||||||
import encutils
|
import xml.dom
|
||||||
|
|
||||||
class Base(object):
|
try:
|
||||||
|
from _fetchgae import _defaultFetcher
|
||||||
|
except ImportError, e:
|
||||||
|
from _fetch import _defaultFetcher
|
||||||
|
|
||||||
|
log = errorhandler.ErrorHandler()
|
||||||
|
|
||||||
|
class _BaseClass(object):
|
||||||
"""
|
"""
|
||||||
Base class for most CSS and StyleSheets classes
|
Base class for Base, Base2 and _NewBase.
|
||||||
|
|
||||||
|
**Base and Base2 will be removed in the future!**
|
||||||
|
"""
|
||||||
|
_log = errorhandler.ErrorHandler()
|
||||||
|
_prods = tokenize2.CSSProductions
|
||||||
|
|
||||||
|
def _checkReadonly(self):
|
||||||
|
"Raise xml.dom.NoModificationAllowedErr if rule/... is readonly"
|
||||||
|
if hasattr(self, '_readonly') and self._readonly:
|
||||||
|
raise xml.dom.NoModificationAllowedErr(
|
||||||
|
u'%s is readonly.' % self.__class__)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _valuestr(self, t):
|
||||||
|
"""
|
||||||
|
Return string value of t (t may be a string, a list of token tuples
|
||||||
|
or a single tuple in format (type, value, line, col).
|
||||||
|
Mainly used to get a string value of t for error messages.
|
||||||
|
"""
|
||||||
|
if not t:
|
||||||
|
return u''
|
||||||
|
elif isinstance(t, basestring):
|
||||||
|
return t
|
||||||
|
else:
|
||||||
|
return u''.join([x[1] for x in t])
|
||||||
|
|
||||||
|
|
||||||
|
class _NewBase(_BaseClass):
|
||||||
|
"""
|
||||||
|
New base class for classes using ProdParser.
|
||||||
|
|
||||||
|
**Currently CSSValue and related ones only.**
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
self._seq = Seq()
|
||||||
|
|
||||||
|
def _setSeq(self, newseq):
|
||||||
|
"""Set value of ``seq`` which is readonly."""
|
||||||
|
newseq._readonly = True
|
||||||
|
self._seq = newseq
|
||||||
|
|
||||||
|
def _tempSeq(self, readonly=False):
|
||||||
|
"Get a writeable Seq() which is used to set ``seq`` later"
|
||||||
|
return Seq(readonly=readonly)
|
||||||
|
|
||||||
|
seq = property(lambda self: self._seq,
|
||||||
|
doc="Internal readonly attribute, **DO NOT USE**!")
|
||||||
|
|
||||||
|
|
||||||
|
class Base(_BaseClass):
|
||||||
|
"""
|
||||||
|
**Superceded by _NewBase**
|
||||||
|
|
||||||
**Superceded by Base2 which is used for new seq handling class.**
|
**Superceded by Base2 which is used for new seq handling class.**
|
||||||
See cssutils.util.Base2
|
|
||||||
|
Base class for most CSS and StyleSheets classes
|
||||||
|
|
||||||
Contains helper methods for inheriting classes helping parsing
|
Contains helper methods for inheriting classes helping parsing
|
||||||
|
|
||||||
@ -28,9 +88,6 @@ class Base(object):
|
|||||||
"""
|
"""
|
||||||
__tokenizer2 = tokenize2.Tokenizer()
|
__tokenizer2 = tokenize2.Tokenizer()
|
||||||
|
|
||||||
_log = cssutils.log
|
|
||||||
_prods = tokenize2.CSSProductions
|
|
||||||
|
|
||||||
# for more on shorthand properties see
|
# for more on shorthand properties see
|
||||||
# http://www.dustindiaz.com/css-shorthand/
|
# http://www.dustindiaz.com/css-shorthand/
|
||||||
# format: shorthand: [(propname, mandatorycheck?)*]
|
# format: shorthand: [(propname, mandatorycheck?)*]
|
||||||
@ -66,14 +123,6 @@ class Base(object):
|
|||||||
"""
|
"""
|
||||||
return normalize(x)
|
return normalize(x)
|
||||||
|
|
||||||
def _checkReadonly(self):
|
|
||||||
"raises xml.dom.NoModificationAllowedErr if rule/... is readonly"
|
|
||||||
if hasattr(self, '_readonly') and self._readonly:
|
|
||||||
raise xml.dom.NoModificationAllowedErr(
|
|
||||||
u'%s is readonly.' % self.__class__)
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _splitNamespacesOff(self, text_namespaces_tuple):
|
def _splitNamespacesOff(self, text_namespaces_tuple):
|
||||||
"""
|
"""
|
||||||
returns tuple (text, dict-of-namespaces) or if no namespaces are
|
returns tuple (text, dict-of-namespaces) or if no namespaces are
|
||||||
@ -141,7 +190,7 @@ class Base(object):
|
|||||||
"""
|
"""
|
||||||
if token:
|
if token:
|
||||||
value = token[1]
|
value = token[1]
|
||||||
return value.replace('\\'+value[0], value[0])[1:-1]
|
return value.replace('\\' + value[0], value[0])[1: - 1]
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -153,10 +202,10 @@ class Base(object):
|
|||||||
url("\"") => "
|
url("\"") => "
|
||||||
"""
|
"""
|
||||||
if token:
|
if token:
|
||||||
value = token[1][4:-1].strip()
|
value = token[1][4: - 1].strip()
|
||||||
if value and (value[0] in '\'"') and (value[0] == value[-1]):
|
if value and (value[0] in '\'"') and (value[0] == value[ - 1]):
|
||||||
# a string "..." or '...'
|
# a string "..." or '...'
|
||||||
value = value.replace('\\'+value[0], value[0])[1:-1]
|
value = value.replace('\\' + value[0], value[0])[1: - 1]
|
||||||
return value
|
return value
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
@ -190,7 +239,7 @@ class Base(object):
|
|||||||
|
|
||||||
if blockstartonly: # {
|
if blockstartonly: # {
|
||||||
ends = u'{'
|
ends = u'{'
|
||||||
brace = -1 # set to 0 with first {
|
brace = - 1 # set to 0 with first {
|
||||||
elif blockendonly: # }
|
elif blockendonly: # }
|
||||||
ends = u'}'
|
ends = u'}'
|
||||||
brace = 1
|
brace = 1
|
||||||
@ -205,7 +254,7 @@ class Base(object):
|
|||||||
# end of mediaquery which may be { or STRING
|
# end of mediaquery which may be { or STRING
|
||||||
# special case, see below
|
# special case, see below
|
||||||
ends = u'{'
|
ends = u'{'
|
||||||
brace = -1 # set to 0 with first {
|
brace = - 1 # set to 0 with first {
|
||||||
endtypes = ('STRING',)
|
endtypes = ('STRING',)
|
||||||
elif semicolon:
|
elif semicolon:
|
||||||
ends = u';'
|
ends = u';'
|
||||||
@ -254,7 +303,7 @@ class Base(object):
|
|||||||
if (brace == bracket == parant == 0) and (
|
if (brace == bracket == parant == 0) and (
|
||||||
val in ends or typ in endtypes):
|
val in ends or typ in endtypes):
|
||||||
break
|
break
|
||||||
elif mediaqueryendonly and brace == -1 and (
|
elif mediaqueryendonly and brace == - 1 and (
|
||||||
bracket == parant == 0) and typ in endtypes:
|
bracket == parant == 0) and typ in endtypes:
|
||||||
# mediaqueryendonly with STRING
|
# mediaqueryendonly with STRING
|
||||||
break
|
break
|
||||||
@ -262,25 +311,12 @@ class Base(object):
|
|||||||
if separateEnd:
|
if separateEnd:
|
||||||
# TODO: use this method as generator, then this makes sense
|
# TODO: use this method as generator, then this makes sense
|
||||||
if resulttokens:
|
if resulttokens:
|
||||||
return resulttokens[:-1], resulttokens[-1]
|
return resulttokens[: - 1], resulttokens[ - 1]
|
||||||
else:
|
else:
|
||||||
return resulttokens, None
|
return resulttokens, None
|
||||||
else:
|
else:
|
||||||
return resulttokens
|
return resulttokens
|
||||||
|
|
||||||
def _valuestr(self, t):
|
|
||||||
"""
|
|
||||||
returns string value of t (t may be a string, a list of token tuples
|
|
||||||
or a single tuple in format (type, value, line, col).
|
|
||||||
Mainly used to get a string value of t for error messages.
|
|
||||||
"""
|
|
||||||
if not t:
|
|
||||||
return u''
|
|
||||||
elif isinstance(t, basestring):
|
|
||||||
return t
|
|
||||||
else:
|
|
||||||
return u''.join([x[1] for x in t])
|
|
||||||
|
|
||||||
def _adddefaultproductions(self, productions, new=None):
|
def _adddefaultproductions(self, productions, new=None):
|
||||||
"""
|
"""
|
||||||
adds default productions if not already present, used by
|
adds default productions if not already present, used by
|
||||||
@ -295,7 +331,7 @@ class Base(object):
|
|||||||
"default impl for unexpected @rule"
|
"default impl for unexpected @rule"
|
||||||
if expected != 'EOF':
|
if expected != 'EOF':
|
||||||
# TODO: parentStyleSheet=self
|
# TODO: parentStyleSheet=self
|
||||||
rule = cssutils.css.CSSUnknownRule()
|
rule = css.CSSUnknownRule()
|
||||||
rule.cssText = self._tokensupto2(tokenizer, token)
|
rule.cssText = self._tokensupto2(tokenizer, token)
|
||||||
if rule.wellformed:
|
if rule.wellformed:
|
||||||
seq.append(rule)
|
seq.append(rule)
|
||||||
@ -307,7 +343,7 @@ class Base(object):
|
|||||||
|
|
||||||
def COMMENT(expected, seq, token, tokenizer=None):
|
def COMMENT(expected, seq, token, tokenizer=None):
|
||||||
"default implementation for COMMENT token adds CSSCommentRule"
|
"default implementation for COMMENT token adds CSSCommentRule"
|
||||||
seq.append(cssutils.css.CSSComment([token]))
|
seq.append(css.CSSComment([token]))
|
||||||
return expected
|
return expected
|
||||||
|
|
||||||
def S(expected, seq, token, tokenizer=None):
|
def S(expected, seq, token, tokenizer=None):
|
||||||
@ -375,26 +411,15 @@ class Base(object):
|
|||||||
return wellformed, expected
|
return wellformed, expected
|
||||||
|
|
||||||
|
|
||||||
class Base2(Base):
|
class Base2(Base, _NewBase):
|
||||||
"""
|
"""
|
||||||
Base class for new seq handling, used by Selector for now only
|
**Superceded by _NewBase.**
|
||||||
|
|
||||||
|
Base class for new seq handling.
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._seq = Seq()
|
self._seq = Seq()
|
||||||
|
|
||||||
def _setSeq(self, newseq):
|
|
||||||
"""
|
|
||||||
sets newseq and makes it readonly
|
|
||||||
"""
|
|
||||||
newseq._readonly = True
|
|
||||||
self._seq = newseq
|
|
||||||
|
|
||||||
seq = property(lambda self: self._seq, doc="seq for most classes")
|
|
||||||
|
|
||||||
def _tempSeq(self, readonly=False):
|
|
||||||
"get a writeable Seq() which is added later"
|
|
||||||
return Seq(readonly=readonly)
|
|
||||||
|
|
||||||
def _adddefaultproductions(self, productions, new=None):
|
def _adddefaultproductions(self, productions, new=None):
|
||||||
"""
|
"""
|
||||||
adds default productions if not already present, used by
|
adds default productions if not already present, used by
|
||||||
@ -409,10 +434,10 @@ class Base2(Base):
|
|||||||
"default impl for unexpected @rule"
|
"default impl for unexpected @rule"
|
||||||
if expected != 'EOF':
|
if expected != 'EOF':
|
||||||
# TODO: parentStyleSheet=self
|
# TODO: parentStyleSheet=self
|
||||||
rule = cssutils.css.CSSUnknownRule()
|
rule = css.CSSUnknownRule()
|
||||||
rule.cssText = self._tokensupto2(tokenizer, token)
|
rule.cssText = self._tokensupto2(tokenizer, token)
|
||||||
if rule.wellformed:
|
if rule.wellformed:
|
||||||
seq.append(rule, cssutils.css.CSSRule.UNKNOWN_RULE,
|
seq.append(rule, css.CSSRule.UNKNOWN_RULE,
|
||||||
line=token[2], col=token[3])
|
line=token[2], col=token[3])
|
||||||
return expected
|
return expected
|
||||||
else:
|
else:
|
||||||
@ -425,7 +450,7 @@ class Base2(Base):
|
|||||||
if expected == 'EOF':
|
if expected == 'EOF':
|
||||||
new['wellformed'] = False
|
new['wellformed'] = False
|
||||||
self._log.error(u'Expected EOF but found comment.', token=token)
|
self._log.error(u'Expected EOF but found comment.', token=token)
|
||||||
seq.append(cssutils.css.CSSComment([token]), 'COMMENT')
|
seq.append(css.CSSComment([token]), 'COMMENT')
|
||||||
return expected
|
return expected
|
||||||
|
|
||||||
def S(expected, seq, token, tokenizer=None):
|
def S(expected, seq, token, tokenizer=None):
|
||||||
@ -493,7 +518,7 @@ class Seq(object):
|
|||||||
else:
|
else:
|
||||||
self._seq.append(item)
|
self._seq.append(item)
|
||||||
|
|
||||||
def replace(self, index=-1, val=None, typ=None, line=None, col=None):
|
def replace(self, index= - 1, val=None, typ=None, line=None, col=None):
|
||||||
"""
|
"""
|
||||||
if not readonly replace Item at index with new Item or
|
if not readonly replace Item at index with new Item or
|
||||||
simply replace value or type
|
simply replace value or type
|
||||||
@ -503,7 +528,13 @@ class Seq(object):
|
|||||||
else:
|
else:
|
||||||
self._seq[index] = Item(val, typ, line, col)
|
self._seq[index] = Item(val, typ, line, col)
|
||||||
|
|
||||||
def appendToVal(self, val=None, index=-1):
|
def rstrip(self):
|
||||||
|
"trims S items from end of Seq"
|
||||||
|
while self._seq and self._seq[ - 1].type == tokenize2.CSSProductions.S:
|
||||||
|
# TODO: removed S before CSSComment /**/ /**/
|
||||||
|
del self._seq[ - 1]
|
||||||
|
|
||||||
|
def appendToVal(self, val=None, index= - 1):
|
||||||
"""
|
"""
|
||||||
if not readonly append to Item's value at index
|
if not readonly append to Item's value at index
|
||||||
"""
|
"""
|
||||||
@ -516,10 +547,11 @@ class Seq(object):
|
|||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
"returns a repr same as a list of tuples of (value, type)"
|
"returns a repr same as a list of tuples of (value, type)"
|
||||||
return u'cssutils.%s.%s([\n %s])' % (self.__module__,
|
return u'cssutils.%s.%s([\n %s], readonly=%r)' % (self.__module__,
|
||||||
self.__class__.__name__,
|
self.__class__.__name__,
|
||||||
u',\n '.join([u'%r' % item for item in self._seq]
|
u',\n '.join([u'%r' % item for item in self._seq]
|
||||||
))
|
), self._readonly)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
vals = []
|
vals = []
|
||||||
for v in self:
|
for v in self:
|
||||||
@ -530,9 +562,9 @@ class Seq(object):
|
|||||||
else:
|
else:
|
||||||
vals.append(str(v))
|
vals.append(str(v))
|
||||||
|
|
||||||
return "<cssutils.%s.%s object length=%r valuestring=%r at 0x%x>" % (
|
return "<cssutils.%s.%s object length=%r values=%r readonly=%r at 0x%x>" % (
|
||||||
self.__module__, self.__class__.__name__, len(self),
|
self.__module__, self.__class__.__name__, len(self),
|
||||||
u''.join(vals), id(self))
|
u''.join(vals), self._readonly, id(self))
|
||||||
|
|
||||||
class Item(object):
|
class Item(object):
|
||||||
"""
|
"""
|
||||||
@ -671,7 +703,7 @@ class _Namespaces(object):
|
|||||||
prefix = u'' # None or ''
|
prefix = u'' # None or ''
|
||||||
rule = self.__findrule(prefix)
|
rule = self.__findrule(prefix)
|
||||||
if not rule:
|
if not rule:
|
||||||
self.parentStyleSheet.insertRule(cssutils.css.CSSNamespaceRule(
|
self.parentStyleSheet.insertRule(css.CSSNamespaceRule(
|
||||||
prefix=prefix,
|
prefix=prefix,
|
||||||
namespaceURI=namespaceURI),
|
namespaceURI=namespaceURI),
|
||||||
inOrder=True)
|
inOrder=True)
|
||||||
@ -688,7 +720,12 @@ class _Namespaces(object):
|
|||||||
if rule.prefix == prefix:
|
if rule.prefix == prefix:
|
||||||
return rule
|
return rule
|
||||||
|
|
||||||
def __getNamespaces(self):
|
@property
|
||||||
|
def namespaces(self):
|
||||||
|
"""
|
||||||
|
A property holding only effective @namespace rules in
|
||||||
|
self.parentStyleSheets.
|
||||||
|
"""
|
||||||
namespaces = {}
|
namespaces = {}
|
||||||
for rule in ifilter(lambda r: r.type == r.NAMESPACE_RULE,
|
for rule in ifilter(lambda r: r.type == r.NAMESPACE_RULE,
|
||||||
reversed(self.parentStyleSheet.cssRules)):
|
reversed(self.parentStyleSheet.cssRules)):
|
||||||
@ -696,10 +733,6 @@ class _Namespaces(object):
|
|||||||
namespaces[rule.prefix] = rule.namespaceURI
|
namespaces[rule.prefix] = rule.namespaceURI
|
||||||
return namespaces
|
return namespaces
|
||||||
|
|
||||||
namespaces = property(__getNamespaces,
|
|
||||||
doc=u'Holds only effective @namespace rules in self.parentStyleSheets'
|
|
||||||
'@namespace rules.')
|
|
||||||
|
|
||||||
def get(self, prefix, default):
|
def get(self, prefix, default):
|
||||||
return self.namespaces.get(prefix, default)
|
return self.namespaces.get(prefix, default)
|
||||||
|
|
||||||
@ -751,35 +784,6 @@ class _SimpleNamespaces(_Namespaces):
|
|||||||
self.namespaces)
|
self.namespaces)
|
||||||
|
|
||||||
|
|
||||||
def _defaultFetcher(url):
|
|
||||||
"""Retrieve data from ``url``. cssutils default implementation of fetch
|
|
||||||
URL function.
|
|
||||||
|
|
||||||
Returns ``(encoding, string)`` or ``None``
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
res = urllib2.urlopen(url)
|
|
||||||
except OSError, e:
|
|
||||||
# e.g if file URL and not found
|
|
||||||
cssutils.log.warn(e, error=OSError)
|
|
||||||
except (OSError, ValueError), e:
|
|
||||||
# invalid url, e.g. "1"
|
|
||||||
cssutils.log.warn(u'ValueError, %s' % e.message, error=ValueError)
|
|
||||||
except urllib2.HTTPError, e:
|
|
||||||
# http error, e.g. 404, e can be raised
|
|
||||||
cssutils.log.warn(u'HTTPError opening url=%r: %s %s' %
|
|
||||||
(url, e.code, e.msg), error=e)
|
|
||||||
except urllib2.URLError, e:
|
|
||||||
# URLError like mailto: or other IO errors, e can be raised
|
|
||||||
cssutils.log.warn(u'URLError, %s' % e.reason, error=e)
|
|
||||||
else:
|
|
||||||
if res:
|
|
||||||
mimeType, encoding = encutils.getHTTPInfo(res)
|
|
||||||
if mimeType != u'text/css':
|
|
||||||
cssutils.log.error(u'Expected "text/css" mime type for url=%r but found: %r' %
|
|
||||||
(url, mimeType), error=ValueError)
|
|
||||||
return encoding, res.read()
|
|
||||||
|
|
||||||
def _readUrl(url, fetcher=None, overrideEncoding=None, parentEncoding=None):
|
def _readUrl(url, fetcher=None, overrideEncoding=None, parentEncoding=None):
|
||||||
"""
|
"""
|
||||||
Read cssText from url and decode it using all relevant methods (HTTP
|
Read cssText from url and decode it using all relevant methods (HTTP
|
||||||
@ -825,8 +829,13 @@ def _readUrl(url, fetcher=None, overrideEncoding=None, parentEncoding=None):
|
|||||||
enctype = 1 # 1. HTTP
|
enctype = 1 # 1. HTTP
|
||||||
encoding = httpEncoding
|
encoding = httpEncoding
|
||||||
else:
|
else:
|
||||||
# check content
|
if isinstance(content, unicode):
|
||||||
contentEncoding, explicit = cssutils.codec.detectencoding_str(content)
|
# no need to check content as unicode so no BOM
|
||||||
|
explicit = False
|
||||||
|
else:
|
||||||
|
# check content
|
||||||
|
contentEncoding, explicit = codec.detectencoding_str(content)
|
||||||
|
|
||||||
if explicit:
|
if explicit:
|
||||||
enctype = 2 # 2. BOM/@charset: explicitly
|
enctype = 2 # 2. BOM/@charset: explicitly
|
||||||
encoding = contentEncoding
|
encoding = contentEncoding
|
||||||
@ -838,18 +847,17 @@ def _readUrl(url, fetcher=None, overrideEncoding=None, parentEncoding=None):
|
|||||||
enctype = 5 # 5. assume UTF-8
|
enctype = 5 # 5. assume UTF-8
|
||||||
encoding = 'utf-8'
|
encoding = 'utf-8'
|
||||||
|
|
||||||
try:
|
if isinstance(content, unicode):
|
||||||
# encoding may still be wrong if encoding *is lying*!
|
decodedCssText = content
|
||||||
if isinstance(content, unicode):
|
else:
|
||||||
decodedCssText = content
|
try:
|
||||||
elif content is not None:
|
# encoding may still be wrong if encoding *is lying*!
|
||||||
decodedCssText = codecs.lookup("css")[1](content, encoding=encoding)[0]
|
decodedCssText = codecs.lookup("css")[1](content, encoding=encoding)[0]
|
||||||
else:
|
except UnicodeDecodeError, e:
|
||||||
|
log.warn(e, neverraise=True)
|
||||||
decodedCssText = None
|
decodedCssText = None
|
||||||
except UnicodeDecodeError, e:
|
|
||||||
cssutils.log.warn(e, neverraise=True)
|
|
||||||
decodedCssText = None
|
|
||||||
|
|
||||||
return encoding, enctype, decodedCssText
|
return encoding, enctype, decodedCssText
|
||||||
else:
|
else:
|
||||||
return None, None, None
|
return None, None, None
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user