mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -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
|
||||
"""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
|
||||
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}')
|
||||
>>> print sheet.cssText
|
||||
a {
|
||||
color: red
|
||||
}
|
||||
color: red
|
||||
}
|
||||
|
||||
"""
|
||||
__all__ = ['css', 'stylesheets', 'CSSParser', 'CSSSerializer']
|
||||
__docformat__ = 'restructuredtext'
|
||||
__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 xml.dom
|
||||
@ -84,9 +84,9 @@ from helper import Deprecated
|
||||
import errorhandler
|
||||
log = errorhandler.ErrorHandler()
|
||||
|
||||
import util
|
||||
import css
|
||||
import stylesheets
|
||||
import util
|
||||
from parse import CSSParser
|
||||
|
||||
from serialize import CSSSerializer
|
||||
@ -96,8 +96,7 @@ ser = CSSSerializer()
|
||||
_ANYNS = -1
|
||||
|
||||
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
|
||||
the new CSSStyleSheet with a document in DOM Level 2.
|
||||
|
||||
@ -166,21 +165,21 @@ parse.__doc__ = CSSParser.parse.__doc__
|
||||
|
||||
# set "ser", default serializer
|
||||
def setSerializer(serializer):
|
||||
"""
|
||||
sets the global serializer used by all class in cssutils
|
||||
"""
|
||||
"""Set the global serializer used by all class in cssutils."""
|
||||
global ser
|
||||
ser = serializer
|
||||
|
||||
|
||||
def getUrls(sheet):
|
||||
"""
|
||||
Utility function to get all ``url(urlstring)`` values in
|
||||
``CSSImportRules`` and ``CSSStyleDeclaration`` objects (properties)
|
||||
of given CSSStyleSheet ``sheet``.
|
||||
"""Retrieve all ``url(urlstring)`` values (in e.g.
|
||||
:class:`cssutils.css.CSSImportRule` or :class:`cssutils.css.CSSValue`
|
||||
objects of given `sheet`.
|
||||
|
||||
This function is a generator. The url values exclude ``url(`` and ``)``
|
||||
and surrounding single or double quotes.
|
||||
:param sheet:
|
||||
: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):
|
||||
yield importrule.href
|
||||
@ -213,14 +212,15 @@ def getUrls(sheet):
|
||||
yield u
|
||||
|
||||
def replaceUrls(sheet, replacer):
|
||||
"""
|
||||
Utility function to replace all ``url(urlstring)`` values in
|
||||
``CSSImportRules`` and ``CSSStyleDeclaration`` objects (properties)
|
||||
of given CSSStyleSheet ``sheet``.
|
||||
"""Replace all URLs in :class:`cssutils.css.CSSImportRule` or
|
||||
:class:`cssutils.css.CSSValue` objects of given `sheet`.
|
||||
|
||||
``replacer`` must be a function which is called with a single
|
||||
argument ``urlstring`` which is the current value of url()
|
||||
excluding ``url(`` and ``)`` and surrounding single or double quotes.
|
||||
:param sheet:
|
||||
:class:`cssutils.css.CSSStyleSheet` which is changed
|
||||
: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):
|
||||
importrule.href = replacer(importrule.href)
|
||||
@ -249,6 +249,37 @@ def replaceUrls(sheet, replacer):
|
||||
elif v.CSS_PRIMITIVE_VALUE == v.cssValueType:
|
||||
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__':
|
||||
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'
|
||||
__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 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):
|
||||
"""
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
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.
|
||||
If ``final`` is true, ``detectencoding_str()`` will never return ``None``
|
||||
as the encoding.
|
||||
``final`` specifies whether more data will be available in later calls or
|
||||
not. If ``final`` is true, ``detectencoding_str()`` will never return
|
||||
``None`` as the encoding.
|
||||
"""
|
||||
|
||||
# A bit for every candidate
|
||||
|
@ -1,5 +1,4 @@
|
||||
"""
|
||||
Document Object Model Level 2 CSS
|
||||
"""Implements Document Object Model Level 2 CSS
|
||||
http://www.w3.org/TR/2000/PR-DOM-Level-2-Style-20000927/css.html
|
||||
|
||||
currently implemented
|
||||
@ -43,7 +42,7 @@ __all__ = [
|
||||
'CSSValue', 'CSSPrimitiveValue', 'CSSValueList'
|
||||
]
|
||||
__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 cssrulelist import *
|
||||
@ -60,4 +59,5 @@ from cssunknownrule import *
|
||||
from selector import *
|
||||
from selectorlist import *
|
||||
from cssstyledeclaration import *
|
||||
from property import *
|
||||
from cssvalue import *
|
||||
|
@ -1,16 +1,12 @@
|
||||
"""CSSCharsetRule implements DOM Level 2 CSS CSSCharsetRule.
|
||||
|
||||
TODO:
|
||||
- check encoding syntax and not codecs.lookup?
|
||||
"""
|
||||
"""CSSCharsetRule implements DOM Level 2 CSS CSSCharsetRule."""
|
||||
__all__ = ['CSSCharsetRule']
|
||||
__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 xml.dom
|
||||
import cssrule
|
||||
import cssutils
|
||||
import xml.dom
|
||||
|
||||
class CSSCharsetRule(cssrule.CSSRule):
|
||||
"""
|
||||
@ -29,34 +25,25 @@ class CSSCharsetRule(cssrule.CSSRule):
|
||||
(see CSS document representation) but this is not reflected in the
|
||||
CSSCharsetRule.
|
||||
|
||||
Properties
|
||||
==========
|
||||
cssText: of type DOMString
|
||||
The parsable textual representation of this rule
|
||||
encoding: of type DOMString
|
||||
The encoding information used in this @charset rule.
|
||||
This rule is not really needed anymore as setting
|
||||
:attr:`CSSStyleSheet.encoding` is much easier.
|
||||
|
||||
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";
|
||||
"""
|
||||
type = property(lambda self: cssrule.CSSRule.CHARSET_RULE)
|
||||
|
||||
def __init__(self, encoding=None, parentRule=None,
|
||||
parentStyleSheet=None, readonly=False):
|
||||
"""
|
||||
encoding:
|
||||
:param encoding:
|
||||
a valid character encoding
|
||||
readonly:
|
||||
:param readonly:
|
||||
defaults to False, not used yet
|
||||
|
||||
if readonly allows setting of properties in constructor only
|
||||
"""
|
||||
super(CSSCharsetRule, self).__init__(parentRule=parentRule,
|
||||
parentStyleSheet=parentStyleSheet)
|
||||
@ -67,25 +54,34 @@ class CSSCharsetRule(cssrule.CSSRule):
|
||||
|
||||
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):
|
||||
"""returns serialized property cssText"""
|
||||
"""The parsable textual representation."""
|
||||
return cssutils.ser.do_CSSCharsetRule(self)
|
||||
|
||||
def _setCssText(self, cssText):
|
||||
"""
|
||||
DOMException on setting
|
||||
|
||||
- SYNTAX_ERR: (self)
|
||||
Raised if the specified CSS string value has a syntax error and
|
||||
is unparsable.
|
||||
- INVALID_MODIFICATION_ERR: (self)
|
||||
Raised if the specified CSS string value represents a different
|
||||
type of rule than the current one.
|
||||
- HIERARCHY_REQUEST_ERR: (CSSStylesheet)
|
||||
Raised if the rule cannot be inserted at this point in the
|
||||
style sheet.
|
||||
- NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
|
||||
Raised if the rule is readonly.
|
||||
: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.
|
||||
"""
|
||||
super(CSSCharsetRule, self)._setCssText(cssText)
|
||||
|
||||
@ -120,14 +116,15 @@ class CSSCharsetRule(cssrule.CSSRule):
|
||||
|
||||
def _setEncoding(self, encoding):
|
||||
"""
|
||||
DOMException on setting
|
||||
|
||||
- NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
|
||||
Raised if this encoding rule is readonly.
|
||||
- SYNTAX_ERR: (self)
|
||||
Raised if the specified encoding value has a syntax error and
|
||||
is unparsable.
|
||||
Currently only valid Python encodings are allowed.
|
||||
:param encoding:
|
||||
a valid encoding to be used. Currently only valid Python encodings
|
||||
are allowed.
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
Raised if this encoding rule is readonly.
|
||||
- :exc:`~xml.dom.SyntaxErr`:
|
||||
Raised if the specified encoding value has a syntax error and
|
||||
is unparsable.
|
||||
"""
|
||||
self._checkReadonly()
|
||||
tokenizer = self._tokenize2(encoding)
|
||||
@ -154,12 +151,8 @@ class CSSCharsetRule(cssrule.CSSRule):
|
||||
encoding = property(lambda self: self._encoding, _setEncoding,
|
||||
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))
|
||||
|
||||
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
|
||||
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']
|
||||
__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 cssutils
|
||||
import xml.dom
|
||||
|
||||
class CSSComment(cssrule.CSSRule):
|
||||
"""
|
||||
(cssutils) a CSS comment
|
||||
Represents a CSS comment (cssutils only).
|
||||
|
||||
Properties
|
||||
==========
|
||||
cssText: of type DOMString
|
||||
The comment text including comment delimiters
|
||||
|
||||
Inherits properties from CSSRule
|
||||
|
||||
Format
|
||||
======
|
||||
::
|
||||
Format::
|
||||
|
||||
/*...*/
|
||||
"""
|
||||
type = property(lambda self: cssrule.CSSRule.COMMENT) # value = -1
|
||||
# constant but needed:
|
||||
wellformed = True
|
||||
|
||||
def __init__(self, cssText=None, parentRule=None,
|
||||
parentStyleSheet=None, readonly=False):
|
||||
super(CSSComment, self).__init__(parentRule=parentRule,
|
||||
@ -42,28 +30,33 @@ class CSSComment(cssrule.CSSRule):
|
||||
|
||||
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):
|
||||
"""returns serialized property cssText"""
|
||||
"""Return serialized property cssText."""
|
||||
return cssutils.ser.do_CSSComment(self)
|
||||
|
||||
def _setCssText(self, cssText):
|
||||
"""
|
||||
cssText
|
||||
:param cssText:
|
||||
textual text to set or tokenlist which is not tokenized
|
||||
anymore. May also be a single token for this rule
|
||||
parser
|
||||
if called from cssparser directly this is Parser instance
|
||||
|
||||
DOMException on setting
|
||||
|
||||
- SYNTAX_ERR: (self)
|
||||
Raised if the specified CSS string value has a syntax error and
|
||||
is unparsable.
|
||||
- INVALID_MODIFICATION_ERR: (self)
|
||||
Raised if the specified CSS string value represents a different
|
||||
type of rule than the current one.
|
||||
- NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
|
||||
Raised if the rule is readonly.
|
||||
: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.NoModificationAllowedErr`:
|
||||
Raised if the rule is readonly.
|
||||
"""
|
||||
super(CSSComment, self)._setCssText(cssText)
|
||||
tokenizer = self._tokenize2(cssText)
|
||||
@ -81,12 +74,11 @@ class CSSComment(cssrule.CSSRule):
|
||||
self._cssText = self._tokenvalue(commenttoken)
|
||||
|
||||
cssText = property(_getCssText, _setCssText,
|
||||
doc=u"(cssutils) Textual representation of this comment")
|
||||
doc=u"The parsable textual representation of this rule.")
|
||||
|
||||
def __repr__(self):
|
||||
return "cssutils.css.%s(cssText=%r)" % (
|
||||
self.__class__.__name__, self.cssText)
|
||||
type = property(lambda self: self.COMMENT,
|
||||
doc="The type of this rule, as defined by a CSSRule "
|
||||
"type constant.")
|
||||
|
||||
def __str__(self):
|
||||
return "<cssutils.css.%s object cssText=%r at 0x%x>" % (
|
||||
self.__class__.__name__, self.cssText, id(self))
|
||||
# constant but needed:
|
||||
wellformed = property(lambda self: True)
|
||||
|
@ -2,12 +2,12 @@
|
||||
"""
|
||||
__all__ = ['CSSFontFaceRule']
|
||||
__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 cssutils
|
||||
from cssstyledeclaration import CSSStyleDeclaration
|
||||
import xml.dom
|
||||
|
||||
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
|
||||
descriptions.
|
||||
|
||||
Properties
|
||||
==========
|
||||
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
|
||||
======
|
||||
::
|
||||
Format::
|
||||
|
||||
font_face
|
||||
: FONT_FACE_SYM 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,
|
||||
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
|
||||
"""
|
||||
super(CSSFontFaceRule, self).__init__(parentRule=parentRule,
|
||||
@ -57,27 +40,32 @@ class CSSFontFaceRule(cssrule.CSSRule):
|
||||
|
||||
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):
|
||||
"""
|
||||
returns serialized property cssText
|
||||
"""
|
||||
"""Return serialized property cssText."""
|
||||
return cssutils.ser.do_CSSFontFaceRule(self)
|
||||
|
||||
def _setCssText(self, cssText):
|
||||
"""
|
||||
DOMException on setting
|
||||
|
||||
- SYNTAX_ERR: (self, StyleDeclaration)
|
||||
Raised if the specified CSS string value has a syntax error and
|
||||
is unparsable.
|
||||
- INVALID_MODIFICATION_ERR: (self)
|
||||
Raised if the specified CSS string value represents a different
|
||||
type of rule than the current one.
|
||||
- HIERARCHY_REQUEST_ERR: (CSSStylesheet)
|
||||
Raised if the rule cannot be inserted at this point in the
|
||||
style sheet.
|
||||
- NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
|
||||
Raised if the rule is readonly.
|
||||
: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.
|
||||
"""
|
||||
super(CSSFontFaceRule, self)._setCssText(cssText)
|
||||
|
||||
@ -135,15 +123,12 @@ class CSSFontFaceRule(cssrule.CSSRule):
|
||||
self._setSeq(newseq) # contains (probably comments) upto { only
|
||||
|
||||
cssText = property(_getCssText, _setCssText,
|
||||
doc="(DOM) The parsable textual representation of the rule.")
|
||||
|
||||
def _getStyle(self):
|
||||
return self._style
|
||||
doc="(DOM) The parsable textual representation of this rule.")
|
||||
|
||||
def _setStyle(self, style):
|
||||
"""
|
||||
style
|
||||
StyleDeclaration or string
|
||||
:param style:
|
||||
a CSSStyleDeclaration or string
|
||||
"""
|
||||
self._checkReadonly()
|
||||
if isinstance(style, basestring):
|
||||
@ -151,13 +136,13 @@ class CSSFontFaceRule(cssrule.CSSRule):
|
||||
else:
|
||||
self._style._seq = style.seq
|
||||
|
||||
style = property(_getStyle, _setStyle,
|
||||
doc="(DOM) The declaration-block of this rule set.")
|
||||
style = property(lambda self: self._style, _setStyle,
|
||||
doc="(DOM) The declaration-block of this rule set, "
|
||||
"a :class:`~cssutils.css.CSSStyleDeclaration`.")
|
||||
|
||||
def __repr__(self):
|
||||
return "cssutils.css.%s(style=%r)" % (
|
||||
self.__class__.__name__, self.style.cssText)
|
||||
type = property(lambda self: self.FONT_FACE_RULE,
|
||||
doc="The type of this rule, as defined by a CSSRule "
|
||||
"type constant.")
|
||||
|
||||
def __str__(self):
|
||||
return "<cssutils.css.%s object style=%r at 0x%x>" % (
|
||||
self.__class__.__name__, self.style.cssText, id(self))
|
||||
# constant but needed:
|
||||
wellformed = property(lambda self: True)
|
||||
|
@ -1,60 +1,30 @@
|
||||
"""CSSImportRule implements DOM Level 2 CSS CSSImportRule.
|
||||
|
||||
plus:
|
||||
|
||||
``name`` property
|
||||
http://www.w3.org/TR/css3-cascade/#cascading
|
||||
"""CSSImportRule implements DOM Level 2 CSS CSSImportRule plus the
|
||||
``name`` property from http://www.w3.org/TR/css3-cascade/#cascading.
|
||||
|
||||
"""
|
||||
__all__ = ['CSSImportRule']
|
||||
__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 urllib
|
||||
import urlparse
|
||||
import xml.dom
|
||||
import cssrule
|
||||
import cssutils
|
||||
|
||||
class CSSImportRule(cssrule.CSSRule):
|
||||
"""
|
||||
Represents an @import rule within a CSS style sheet. The @import rule
|
||||
is used to import style rules from other style sheets.
|
||||
|
||||
Properties
|
||||
==========
|
||||
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).
|
||||
Format::
|
||||
|
||||
Inherits properties from CSSRule
|
||||
|
||||
Format
|
||||
======
|
||||
import
|
||||
: IMPORT_SYM S*
|
||||
[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,
|
||||
parentRule=None, parentStyleSheet=None, readonly=False):
|
||||
"""
|
||||
@ -90,30 +60,44 @@ class CSSImportRule(cssrule.CSSRule):
|
||||
self._setSeq(seq)
|
||||
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'),
|
||||
doc="if self._media is used (or simply empty)")
|
||||
|
||||
def _getCssText(self):
|
||||
"""
|
||||
returns serialized property cssText
|
||||
"""
|
||||
"""Return serialized property cssText."""
|
||||
return cssutils.ser.do_CSSImportRule(self)
|
||||
|
||||
def _setCssText(self, cssText):
|
||||
"""
|
||||
DOMException on setting
|
||||
|
||||
- HIERARCHY_REQUEST_ERR: (CSSStylesheet)
|
||||
Raised if the rule cannot be inserted at this point in the
|
||||
style sheet.
|
||||
- INVALID_MODIFICATION_ERR: (self)
|
||||
Raised if the specified CSS string value represents a different
|
||||
type of rule than the current one.
|
||||
- NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
|
||||
Raised if the rule is readonly.
|
||||
- SYNTAX_ERR: (self)
|
||||
Raised if the specified CSS string value has a syntax error and
|
||||
is unparsable.
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.HierarchyRequestErr`:
|
||||
Raised if the rule cannot be inserted at this point in the
|
||||
style sheet.
|
||||
- :exc:`~xml.dom.InvalidModificationErr`:
|
||||
Raised if the specified CSS string value represents a different
|
||||
type of rule than the current one.
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
Raised if the rule is readonly.
|
||||
- :exc:`~xml.dom.SyntaxErr`:
|
||||
Raised if the specified CSS string value has a syntax error and
|
||||
is unparsable.
|
||||
"""
|
||||
super(CSSImportRule, self)._setCssText(cssText)
|
||||
tokenizer = self._tokenize2(cssText)
|
||||
@ -268,7 +252,7 @@ class CSSImportRule(cssrule.CSSRule):
|
||||
self.styleSheet._parentStyleSheet = self.parentStyleSheet
|
||||
|
||||
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):
|
||||
# update seq
|
||||
@ -291,11 +275,11 @@ class CSSImportRule(cssrule.CSSRule):
|
||||
doc="Location of the style sheet to be imported.")
|
||||
|
||||
media = property(lambda self: self._media,
|
||||
doc=u"(DOM readonly) A list of media types for this rule"
|
||||
" of type MediaList")
|
||||
doc="(DOM readonly) A list of media types for this rule "
|
||||
"of type :class:`~cssutils.stylesheets.MediaList`.")
|
||||
|
||||
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:
|
||||
# "" or ''
|
||||
if not name:
|
||||
@ -322,7 +306,7 @@ class CSSImportRule(cssrule.CSSRule):
|
||||
self._log.error(u'CSSImportRule: Not a valid name: %s' % name)
|
||||
|
||||
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):
|
||||
"""Read new CSSStyleSheet cssText from href using parentStyleSheet.href
|
||||
@ -372,28 +356,15 @@ class CSSImportRule(cssrule.CSSRule):
|
||||
styleSheet = property(lambda self: self._styleSheet,
|
||||
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):
|
||||
"depending if media is used at all"
|
||||
"Depending if media is used at all."
|
||||
if self._usemedia:
|
||||
return bool(self.href and self.media.wellformed)
|
||||
else:
|
||||
return bool(self.href)
|
||||
|
||||
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']
|
||||
__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 cssutils
|
||||
import xml.dom
|
||||
|
||||
class CSSMediaRule(cssrule.CSSRule):
|
||||
"""
|
||||
@ -14,31 +13,17 @@ class CSSMediaRule(cssrule.CSSRule):
|
||||
MEDIA_RULE constant. On these objects the type attribute must return the
|
||||
value of that constant.
|
||||
|
||||
Properties
|
||||
==========
|
||||
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::
|
||||
|
||||
Format
|
||||
======
|
||||
media
|
||||
: MEDIA_SYM S* medium [ COMMA S* medium ]*
|
||||
|
||||
STRING? # the name
|
||||
|
||||
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,
|
||||
parentRule=None, parentStyleSheet=None, readonly=False):
|
||||
"""constructor"""
|
||||
@ -56,12 +41,20 @@ class CSSMediaRule(cssrule.CSSRule):
|
||||
self._readonly = readonly
|
||||
|
||||
def __iter__(self):
|
||||
"""generator which iterates over cssRules."""
|
||||
"""Generator iterating over these rule's cssRules."""
|
||||
for rule in self.cssRules:
|
||||
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):
|
||||
"""return serialized property cssText"""
|
||||
"""Return serialized property cssText."""
|
||||
return cssutils.ser.do_CSSMediaRule(self)
|
||||
|
||||
def _setCssText(self, cssText):
|
||||
@ -69,19 +62,19 @@ class CSSMediaRule(cssrule.CSSRule):
|
||||
:param cssText:
|
||||
a parseable string or a tuple of (cssText, dict-of-namespaces)
|
||||
:Exceptions:
|
||||
- `NAMESPACE_ERR`: (Selector)
|
||||
- :exc:`~xml.dom.NamespaceErr`:
|
||||
Raised if a specified selector uses an unknown namespace
|
||||
prefix.
|
||||
- `SYNTAX_ERR`: (self, StyleDeclaration, etc)
|
||||
- :exc:`~xml.dom.SyntaxErr`:
|
||||
Raised if the specified CSS string value has a syntax error and
|
||||
is unparsable.
|
||||
- `INVALID_MODIFICATION_ERR`: (self)
|
||||
- :exc:`~xml.dom.InvalidModificationErr`:
|
||||
Raised if the specified CSS string value represents a different
|
||||
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
|
||||
style sheet.
|
||||
- `NO_MODIFICATION_ALLOWED_ERR`: (CSSRule)
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
Raised if the rule is readonly.
|
||||
"""
|
||||
super(CSSMediaRule, self)._setCssText(cssText)
|
||||
@ -209,7 +202,7 @@ class CSSMediaRule(cssrule.CSSRule):
|
||||
self.cssRules.append(r)
|
||||
|
||||
cssText = property(_getCssText, _setCssText,
|
||||
doc="(DOM attribute) The parsable textual representation.")
|
||||
doc="(DOM) The parsable textual representation of this rule.")
|
||||
|
||||
def _setName(self, name):
|
||||
if isinstance(name, basestring) or name is None:
|
||||
@ -221,30 +214,26 @@ class CSSMediaRule(cssrule.CSSRule):
|
||||
else:
|
||||
self._log.error(u'CSSImportRule: Not a valid name: %s' % name)
|
||||
|
||||
|
||||
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,
|
||||
doc=u"(DOM readonly) A list of media types for this rule of type\
|
||||
MediaList")
|
||||
|
||||
wellformed = property(lambda self: self.media.wellformed)
|
||||
doc=u"(DOM readonly) A list of media types for this rule of type "
|
||||
u":class:`~cssutils.stylesheets.MediaList`.")
|
||||
|
||||
def deleteRule(self, index):
|
||||
"""
|
||||
index
|
||||
within the media block's rule collection of the rule to remove.
|
||||
Delete the rule at `index` from the media block.
|
||||
|
||||
Used to delete a rule from the media block.
|
||||
:param index:
|
||||
of the rule to remove within the media block's rule collection
|
||||
|
||||
DOMExceptions
|
||||
|
||||
- INDEX_SIZE_ERR: (self)
|
||||
Raised if the specified index does not correspond to a rule in
|
||||
the media rule list.
|
||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
||||
Raised if this media rule is readonly.
|
||||
:Exceptions:
|
||||
- :exc:`~xml.dom.IndexSizeErr`:
|
||||
Raised if the specified index does not correspond to a rule in
|
||||
the media rule list.
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
Raised if this media rule is readonly.
|
||||
"""
|
||||
self._checkReadonly()
|
||||
|
||||
@ -257,46 +246,47 @@ class CSSMediaRule(cssrule.CSSRule):
|
||||
index, self.cssRules.length))
|
||||
|
||||
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)
|
||||
|
||||
def insertRule(self, rule, index=None):
|
||||
"""
|
||||
rule
|
||||
The parsable text representing the rule. For rule sets this
|
||||
contains both the selector and the style declaration. For
|
||||
at-rules, this specifies both the at-identifier and the rule
|
||||
Insert `rule` into the media block.
|
||||
|
||||
:param 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.
|
||||
|
||||
cssutils also allows rule to be a valid **CSSRule** object
|
||||
cssutils also allows rule to be a valid :class:`~cssutils.css.CSSRule`
|
||||
object.
|
||||
|
||||
index
|
||||
within the media block's rule collection of the rule before
|
||||
which to insert the specified rule. If the specified index is
|
||||
:param index:
|
||||
before the specified `rule` will be inserted.
|
||||
If the specified `index` is
|
||||
equal to the length of the media blocks's rule collection, the
|
||||
rule will be added to the end of the media block.
|
||||
If index is not given or None rule will be appended to rule
|
||||
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
|
||||
|
||||
- HIERARCHY_REQUEST_ERR:
|
||||
(no use case yet as no @charset or @import allowed))
|
||||
Raised if the rule cannot be inserted at the specified index,
|
||||
e.g., if an @import rule is inserted after a standard rule set
|
||||
or other at-rule.
|
||||
- INDEX_SIZE_ERR: (self)
|
||||
Raised if the specified index is not a valid insertion point.
|
||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
||||
Raised if this media rule is readonly.
|
||||
- SYNTAX_ERR: (CSSStyleRule)
|
||||
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.
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.HierarchyRequestErr`:
|
||||
Raised if the `rule` cannot be inserted at the specified `index`,
|
||||
e.g., if an @import rule is inserted after a standard rule set
|
||||
or other at-rule.
|
||||
- :exc:`~xml.dom.IndexSizeErr`:
|
||||
Raised if the specified `index` is not a valid insertion point.
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
Raised if this media rule is readonly.
|
||||
- :exc:`~xml.dom.SyntaxErr`:
|
||||
Raised if the specified `rule` has a syntax error and is
|
||||
unparsable.
|
||||
|
||||
"""
|
||||
self._checkReadonly()
|
||||
@ -340,10 +330,8 @@ class CSSMediaRule(cssrule.CSSRule):
|
||||
rule._parentStyleSheet = self.parentStyleSheet
|
||||
return index
|
||||
|
||||
def __repr__(self):
|
||||
return "cssutils.css.%s(mediaText=%r)" % (
|
||||
self.__class__.__name__, self.media.mediaText)
|
||||
type = property(lambda self: self.MEDIA_RULE,
|
||||
doc="The type of this rule, as defined by a CSSRule "
|
||||
"type constant.")
|
||||
|
||||
def __str__(self):
|
||||
return "<cssutils.css.%s object mediaText=%r at 0x%x>" % (
|
||||
self.__class__.__name__, self.media.mediaText, id(self))
|
||||
wellformed = property(lambda self: self.media.wellformed)
|
||||
|
@ -1,16 +1,12 @@
|
||||
"""CSSNamespaceRule currently implements
|
||||
http://dev.w3.org/csswg/css3-namespace/
|
||||
|
||||
(until 0.9.5a2: http://www.w3.org/TR/2006/WD-css3-namespace-20060828/)
|
||||
"""
|
||||
"""CSSNamespaceRule currently implements http://dev.w3.org/csswg/css3-namespace/"""
|
||||
__all__ = ['CSSNamespaceRule']
|
||||
__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 cssutils
|
||||
from cssutils.helper import Deprecated
|
||||
import xml.dom
|
||||
|
||||
class CSSNamespaceRule(cssrule.CSSRule):
|
||||
"""
|
||||
@ -21,35 +17,18 @@ class CSSNamespaceRule(cssrule.CSSRule):
|
||||
used in namespace-qualified names such as those described in the
|
||||
Selectors Module [SELECT] or the Values and Units module [CSS3VAL].
|
||||
|
||||
Properties
|
||||
==========
|
||||
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.
|
||||
Dealing with these rules directly is not needed anymore, easier is
|
||||
the use of :attr:`cssutils.css.CSSStyleSheet.namespaces`.
|
||||
|
||||
Inherits properties from CSSRule
|
||||
Format::
|
||||
|
||||
Format
|
||||
======
|
||||
namespace
|
||||
: NAMESPACE_SYM S* [namespace_prefix S*]? [STRING|URI] S* ';' S*
|
||||
;
|
||||
namespace_prefix
|
||||
: IDENT
|
||||
;
|
||||
namespace
|
||||
: NAMESPACE_SYM S* [namespace_prefix S*]? [STRING|URI] S* ';' S*
|
||||
;
|
||||
namespace_prefix
|
||||
: IDENT
|
||||
;
|
||||
"""
|
||||
type = property(lambda self: cssrule.CSSRule.NAMESPACE_RULE)
|
||||
|
||||
def __init__(self, namespaceURI=None, prefix=None, cssText=None,
|
||||
parentRule=None, parentStyleSheet=None, readonly=False):
|
||||
"""
|
||||
@ -102,27 +81,31 @@ class CSSNamespaceRule(cssrule.CSSRule):
|
||||
|
||||
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):
|
||||
"""
|
||||
returns serialized property cssText
|
||||
"""
|
||||
"""Return serialized property cssText"""
|
||||
return cssutils.ser.do_CSSNamespaceRule(self)
|
||||
|
||||
def _setCssText(self, cssText):
|
||||
"""
|
||||
DOMException on setting
|
||||
|
||||
:param cssText: initial value for this rules cssText which is parsed
|
||||
:Exceptions:
|
||||
- `HIERARCHY_REQUEST_ERR`: (CSSStylesheet)
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.HierarchyRequestErr`:
|
||||
Raised if the rule cannot be inserted at this point in the
|
||||
style sheet.
|
||||
- `INVALID_MODIFICATION_ERR`: (self)
|
||||
- :exc:`~xml.dom.InvalidModificationErr`:
|
||||
Raised if the specified CSS string value represents a different
|
||||
type of rule than the current one.
|
||||
- `NO_MODIFICATION_ALLOWED_ERR`: (CSSRule)
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
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
|
||||
is unparsable.
|
||||
"""
|
||||
@ -222,15 +205,13 @@ class CSSNamespaceRule(cssrule.CSSRule):
|
||||
self._setSeq(newseq)
|
||||
|
||||
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):
|
||||
"""
|
||||
DOMException on setting
|
||||
|
||||
:param namespaceURI: the initial value for this rules namespaceURI
|
||||
:Exceptions:
|
||||
- `NO_MODIFICATION_ALLOWED_ERR`:
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
(CSSRule) Raised if this rule is readonly or a namespaceURI is
|
||||
already set in this rule.
|
||||
"""
|
||||
@ -246,18 +227,16 @@ class CSSNamespaceRule(cssrule.CSSRule):
|
||||
error=xml.dom.NoModificationAllowedErr)
|
||||
|
||||
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):
|
||||
"""
|
||||
DOMException on setting
|
||||
|
||||
:param prefix: the new prefix
|
||||
:Exceptions:
|
||||
- `SYNTAX_ERR`: (TODO)
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.SyntaxErr`:
|
||||
Raised if the specified CSS string value has a syntax error and
|
||||
is unparsable.
|
||||
- `NO_MODIFICATION_ALLOWED_ERR`: CSSRule)
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
Raised if this rule is readonly.
|
||||
"""
|
||||
self._checkReadonly()
|
||||
@ -295,12 +274,9 @@ class CSSNamespaceRule(cssrule.CSSRule):
|
||||
# _setParentStyleSheet,
|
||||
# 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)
|
||||
|
||||
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']
|
||||
__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 cssutils
|
||||
from selectorlist import SelectorList
|
||||
from cssstyledeclaration import CSSStyleDeclaration
|
||||
import xml.dom
|
||||
|
||||
class CSSPageRule(cssrule.CSSRule):
|
||||
"""
|
||||
@ -16,22 +16,7 @@ class CSSPageRule(cssrule.CSSRule):
|
||||
sheet. The @page rule is used to specify the dimensions, orientation,
|
||||
margins, etc. of a page box for paged media.
|
||||
|
||||
Properties
|
||||
==========
|
||||
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
|
||||
======
|
||||
::
|
||||
Format::
|
||||
|
||||
page
|
||||
: PAGE_SYM S* pseudo_page? S*
|
||||
@ -40,20 +25,15 @@ class CSSPageRule(cssrule.CSSRule):
|
||||
pseudo_page
|
||||
: ':' 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,
|
||||
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
|
||||
style
|
||||
:param style:
|
||||
CSSStyleDeclaration for this CSSStyleRule
|
||||
"""
|
||||
super(CSSPageRule, self).__init__(parentRule=parentRule,
|
||||
@ -64,7 +44,7 @@ class CSSPageRule(cssrule.CSSRule):
|
||||
self.selectorText = selectorText
|
||||
tempseq.append(self.selectorText, 'selectorText')
|
||||
else:
|
||||
self._selectorText = u''
|
||||
self._selectorText = self._tempSeq()
|
||||
if style:
|
||||
self.style = style
|
||||
tempseq.append(self.style, 'style')
|
||||
@ -74,20 +54,29 @@ class CSSPageRule(cssrule.CSSRule):
|
||||
|
||||
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):
|
||||
"""
|
||||
parses selectorText which may also be a list of tokens
|
||||
and returns (selectorText, seq)
|
||||
Parse `selectorText` which may also be a list of tokens
|
||||
and returns (selectorText, seq).
|
||||
|
||||
see _setSelectorText for details
|
||||
"""
|
||||
# for closures: must be a mutable
|
||||
new = {'selector': None, 'wellformed': True}
|
||||
new = {'wellformed': True, 'last-S': False}
|
||||
|
||||
def _char(expected, seq, token, tokenizer=None):
|
||||
# pseudo_page, :left, :right or :first
|
||||
val = self._tokenvalue(token)
|
||||
if ':' == expected and u':' == val:
|
||||
if not new['last-S'] and expected in ['page', ': or EOF'] and u':' == val:
|
||||
try:
|
||||
identtoken = tokenizer.next()
|
||||
except StopIteration:
|
||||
@ -100,8 +89,7 @@ class CSSPageRule(cssrule.CSSRule):
|
||||
u'CSSPageRule selectorText: Expected IDENT but found: %r' %
|
||||
ival, token)
|
||||
else:
|
||||
new['selector'] = val + ival
|
||||
seq.append(new['selector'], 'selector')
|
||||
seq.append(val + ival, 'pseudo')
|
||||
return 'EOF'
|
||||
return expected
|
||||
else:
|
||||
@ -112,22 +100,37 @@ class CSSPageRule(cssrule.CSSRule):
|
||||
|
||||
def S(expected, seq, token, tokenizer=None):
|
||||
"Does not raise if EOF is found."
|
||||
if expected == ': or EOF':
|
||||
# pseudo must directly follow IDENT if given
|
||||
new['last-S'] = True
|
||||
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):
|
||||
"Does not raise if EOF is found."
|
||||
seq.append(cssutils.css.CSSComment([token]), 'COMMENT')
|
||||
return expected
|
||||
|
||||
newseq = self._tempSeq()
|
||||
wellformed, expected = self._parse(expected=':',
|
||||
wellformed, expected = self._parse(expected='page',
|
||||
seq=newseq, tokenizer=self._tokenize2(selectorText),
|
||||
productions={'CHAR': _char,
|
||||
'IDENT': IDENT,
|
||||
'COMMENT': COMMENT,
|
||||
'S': S},
|
||||
new=new)
|
||||
wellformed = wellformed and new['wellformed']
|
||||
newselector = new['selector']
|
||||
|
||||
# post conditions
|
||||
if expected == 'ident':
|
||||
@ -135,33 +138,30 @@ class CSSPageRule(cssrule.CSSRule):
|
||||
u'CSSPageRule selectorText: No valid selector: %r' %
|
||||
self._valuestr(selectorText))
|
||||
|
||||
if not newselector in (None, u':first', u':left', u':right'):
|
||||
self._log.warn(u'CSSPageRule: Unknown CSS 2.1 @page selector: %r' %
|
||||
newselector, neverraise=True)
|
||||
# if not newselector in (None, u':first', u':left', u':right'):
|
||||
# self._log.warn(u'CSSPageRule: Unknown CSS 2.1 @page selector: %r' %
|
||||
# newselector, neverraise=True)
|
||||
|
||||
return newselector, newseq
|
||||
return wellformed, newseq
|
||||
|
||||
def _getCssText(self):
|
||||
"""
|
||||
returns serialized property cssText
|
||||
"""
|
||||
"""Return serialized property cssText."""
|
||||
return cssutils.ser.do_CSSPageRule(self)
|
||||
|
||||
def _setCssText(self, cssText):
|
||||
"""
|
||||
DOMException on setting
|
||||
|
||||
- SYNTAX_ERR: (self, StyleDeclaration)
|
||||
Raised if the specified CSS string value has a syntax error and
|
||||
is unparsable.
|
||||
- INVALID_MODIFICATION_ERR: (self)
|
||||
Raised if the specified CSS string value represents a different
|
||||
type of rule than the current one.
|
||||
- HIERARCHY_REQUEST_ERR: (CSSStylesheet)
|
||||
Raised if the rule cannot be inserted at this point in the
|
||||
style sheet.
|
||||
- NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
|
||||
Raised if the rule is readonly.
|
||||
: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.
|
||||
"""
|
||||
super(CSSPageRule, self)._setCssText(cssText)
|
||||
|
||||
@ -190,7 +190,7 @@ class CSSPageRule(cssrule.CSSRule):
|
||||
u'CSSPageRule: Trailing content found.', token=nonetoken)
|
||||
|
||||
|
||||
newselector, newselectorseq = self.__parseSelectorText(selectortokens)
|
||||
wellformed, newselectorseq = self.__parseSelectorText(selectortokens)
|
||||
|
||||
newstyle = CSSStyleDeclaration()
|
||||
val, typ = self._tokenvalue(braceorEOFtoken), self._type(braceorEOFtoken)
|
||||
@ -206,63 +206,49 @@ class CSSPageRule(cssrule.CSSRule):
|
||||
newstyle.cssText = styletokens
|
||||
|
||||
if wellformed:
|
||||
self._selectorText = newselector # already parsed
|
||||
self._selectorText = newselectorseq # already parsed
|
||||
self.style = newstyle
|
||||
self._setSeq(newselectorseq) # contains upto style only
|
||||
|
||||
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):
|
||||
"""
|
||||
wrapper for cssutils Selector object
|
||||
"""
|
||||
return self._selectorText
|
||||
"""Wrapper for cssutils Selector object."""
|
||||
return cssutils.ser.do_CSSPageRuleSelector(self._selectorText)#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
|
||||
- :left
|
||||
- :right
|
||||
- empty
|
||||
|
||||
If WS or Comments are included they are ignored here! Only
|
||||
way to add a comment is via setting ``cssText``
|
||||
|
||||
DOMException on setting
|
||||
|
||||
- SYNTAX_ERR:
|
||||
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.
|
||||
:exceptions:
|
||||
- :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()
|
||||
|
||||
# may raise SYNTAX_ERR
|
||||
newselectortext, newseq = self.__parseSelectorText(selectorText)
|
||||
|
||||
if newselectortext:
|
||||
for i, x in enumerate(self.seq):
|
||||
if x == self._selectorText:
|
||||
self.seq[i] = newselectortext
|
||||
self._selectorText = newselectortext
|
||||
wellformed, newseq = self.__parseSelectorText(selectorText)
|
||||
if wellformed and newseq:
|
||||
self._selectorText = newseq
|
||||
|
||||
selectorText = property(_getSelectorText, _setSelectorText,
|
||||
doc="""(DOM) The parsable textual representation of the page selector for the rule.""")
|
||||
|
||||
def _getStyle(self):
|
||||
|
||||
return self._style
|
||||
|
||||
def _setStyle(self, style):
|
||||
"""
|
||||
style
|
||||
StyleDeclaration or string
|
||||
:param style:
|
||||
a CSSStyleDeclaration or string
|
||||
"""
|
||||
self._checkReadonly()
|
||||
|
||||
@ -273,14 +259,14 @@ class CSSPageRule(cssrule.CSSRule):
|
||||
# so use seq!
|
||||
self._style._seq = style.seq
|
||||
|
||||
style = property(_getStyle, _setStyle,
|
||||
doc="(DOM) The declaration-block of this rule set.")
|
||||
style = property(lambda self: self._style, _setStyle,
|
||||
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):
|
||||
return "<cssutils.css.%s object selectorText=%r style=%r at 0x%x>" % (
|
||||
self.__class__.__name__, self.selectorText, self.style.cssText,
|
||||
id(self))
|
||||
type = property(lambda self: self.PAGE_RULE,
|
||||
doc="The type of this rule, as defined by a CSSRule "
|
||||
"type constant.")
|
||||
|
||||
# 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"
|
||||
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'
|
||||
__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
|
||||
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
The CSS2Properties interface represents a convenience mechanism
|
||||
"""The CSS2Properties interface represents a convenience mechanism
|
||||
for retrieving and setting properties within a CSSStyleDeclaration.
|
||||
The attributes of this interface correspond to all the properties
|
||||
specified in CSS2. Getting an attribute of this interface is
|
||||
@ -326,16 +78,37 @@ class CSS2Properties(object):
|
||||
def _setP(self, CSSname, value): 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
|
||||
# used for CSSStyleDeclaration to check if allowed properties
|
||||
# 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:
|
||||
def __named_property_def(DOMname):
|
||||
"""
|
||||
closure to keep name known in each properties accessor function
|
||||
DOMname is converted to CSSname here, so actual calls use CSSname
|
||||
Closure to keep name known in each properties accessor function
|
||||
DOMname is converted to CSSname here, so actual calls use CSSname.
|
||||
"""
|
||||
CSSname = _toCSSname(DOMname)
|
||||
def _get(self): return self._getP(CSSname)
|
||||
|
@ -1,46 +1,17 @@
|
||||
"""CSSRule implements DOM Level 2 CSS CSSRule."""
|
||||
__all__ = ['CSSRule']
|
||||
__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 xml.dom
|
||||
|
||||
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
|
||||
all rules specified in a CSS style sheet, even if the rule is not
|
||||
recognized by the parser. Unrecognized rules are represented using the
|
||||
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
|
||||
:class:`CSSUnknownRule` interface.
|
||||
"""
|
||||
|
||||
"""
|
||||
@ -61,21 +32,8 @@ class CSSRule(cssutils.util.Base2):
|
||||
'MEDIA_RULE', 'FONT_FACE_RULE', 'PAGE_RULE', 'NAMESPACE_RULE',
|
||||
'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):
|
||||
"""
|
||||
set common attributes for all rules
|
||||
"""
|
||||
"""Set common attributes for all rules."""
|
||||
super(CSSRule, self).__init__()
|
||||
self._parentRule = parentRule
|
||||
self._parentStyleSheet = parentStyleSheet
|
||||
@ -83,33 +41,8 @@ class CSSRule(cssutils.util.Base2):
|
||||
# must be set after initialization of #inheriting rule is done
|
||||
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):
|
||||
"""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) ==
|
||||
self._normalize(self.atkeyword)):
|
||||
self._atkeyword = akw
|
||||
@ -119,16 +52,48 @@ class CSSRule(cssutils.util.Base2):
|
||||
error=xml.dom.InvalidModificationErr)
|
||||
|
||||
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,
|
||||
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,
|
||||
doc=u"READONLY")
|
||||
doc="The style sheet that contains this rule.")
|
||||
|
||||
wellformed = property(lambda self: False,
|
||||
doc=u"READONLY")
|
||||
type = property(lambda self: self.UNKNOWN_RULE,
|
||||
doc="The type of this rule, as defined by a CSSRule "
|
||||
"type constant.")
|
||||
|
||||
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.
|
||||
|
||||
Partly also
|
||||
* http://dev.w3.org/csswg/cssom/#the-cssrulelist
|
||||
"""CSSRuleList implements DOM Level 2 CSS CSSRuleList.
|
||||
Partly also http://dev.w3.org/csswg/cssom/#the-cssrulelist
|
||||
"""
|
||||
__all__ = ['CSSRuleList']
|
||||
__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):
|
||||
"""
|
||||
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,
|
||||
starting from 0.
|
||||
@ -21,28 +17,20 @@ class CSSRuleList(list):
|
||||
class if so desired.
|
||||
E.g. CSSStyleSheet adds ``append`` which is not available in a simple
|
||||
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):
|
||||
"nothing is set as this must also be defined later"
|
||||
"Nothing is set as this must also be defined later."
|
||||
pass
|
||||
|
||||
def __notimplemented(self, *ignored):
|
||||
"no direct setting possible"
|
||||
"Implemented in class using a CSSRuleList only."
|
||||
raise NotImplementedError(
|
||||
'Must be implemented by class using an instance of this class.')
|
||||
|
||||
append = extend = __setitem__ = __setslice__ = __notimplemented
|
||||
|
||||
def item(self, index):
|
||||
"""
|
||||
(DOM)
|
||||
Used to retrieve a CSS rule by ordinal index. The order in this
|
||||
"""(DOM) Retrieve a CSS rule by ordinal `index`. The order in this
|
||||
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
|
||||
the list, this returns None.
|
||||
|
@ -51,16 +51,15 @@ TODO:
|
||||
"""
|
||||
__all__ = ['CSSStyleDeclaration', 'Property']
|
||||
__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 property import Property
|
||||
import cssutils
|
||||
import xml.dom
|
||||
|
||||
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
|
||||
currently set in a block or to set style properties explicitly
|
||||
within the block.
|
||||
@ -76,24 +75,6 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
||||
|
||||
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
|
||||
All properties defined in the CSS2Properties class are available
|
||||
as direct properties of CSSStyleDeclaration with their respective
|
||||
@ -106,33 +87,32 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
||||
>>> print style.color
|
||||
green
|
||||
>>> del style.color
|
||||
>>> print style.color # print empty string
|
||||
>>> print style.color
|
||||
<BLANKLINE>
|
||||
|
||||
Format
|
||||
======
|
||||
[Property: Value Priority?;]* [Property: Value Priority?]?
|
||||
Format::
|
||||
|
||||
[Property: Value Priority?;]* [Property: Value Priority?]?
|
||||
"""
|
||||
def __init__(self, cssText=u'', parentRule=None, readonly=False):
|
||||
"""
|
||||
cssText
|
||||
:param cssText:
|
||||
Shortcut, sets CSSStyleDeclaration.cssText
|
||||
parentRule
|
||||
:param parentRule:
|
||||
The CSS rule that contains this declaration block or
|
||||
None if this CSSStyleDeclaration is not attached to a CSSRule.
|
||||
readonly
|
||||
:param readonly:
|
||||
defaults to False
|
||||
"""
|
||||
super(CSSStyleDeclaration, self).__init__()
|
||||
self._parentRule = parentRule
|
||||
#self._seq = self._tempSeq()
|
||||
self.cssText = cssText
|
||||
self._readonly = readonly
|
||||
|
||||
def __contains__(self, nameOrProperty):
|
||||
"""
|
||||
checks if a property (or a property with given name is in style
|
||||
"""Check 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
|
||||
"""
|
||||
if isinstance(nameOrProperty, Property):
|
||||
@ -142,47 +122,12 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
||||
return name in self.__nnames()
|
||||
|
||||
def __iter__(self):
|
||||
"""
|
||||
iterator of set Property objects with different normalized names.
|
||||
"""
|
||||
"""Iterator of set Property objects with different normalized names."""
|
||||
def properties():
|
||||
for name in self.__nnames():
|
||||
yield self.getProperty(name)
|
||||
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):
|
||||
"""Retrieve the value of property ``CSSName`` from this declaration.
|
||||
|
||||
@ -211,11 +156,49 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
||||
"""
|
||||
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
|
||||
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)``.
|
||||
|
||||
Parameter is in CSSname format ('font-style'), see CSS2Properties.
|
||||
@ -229,9 +212,7 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
||||
return self.getPropertyValue(CSSName)
|
||||
|
||||
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)``.
|
||||
|
||||
Only known CSS2Properties may be set this way, otherwise an
|
||||
@ -247,44 +228,40 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
||||
>>> style.fontStyle = 'italic'
|
||||
>>> # or
|
||||
>>> style.setProperty('font-style', 'italic', '!important')
|
||||
|
||||
"""
|
||||
self.setProperty(CSSName, value)
|
||||
# TODO: Shorthand ones
|
||||
|
||||
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)``.
|
||||
|
||||
Example::
|
||||
|
||||
>>> style = CSSStyleDeclaration(cssText='font-style:italic;')
|
||||
>>> del style.fontStyle
|
||||
>>> print style.fontStyle # prints u''
|
||||
>>> print style.fontStyle
|
||||
<BLANKLINE>
|
||||
|
||||
"""
|
||||
self.removeProperty(CSSName)
|
||||
|
||||
def _getCssText(self):
|
||||
"""
|
||||
returns serialized property cssText
|
||||
"""
|
||||
"""Return serialized property cssText."""
|
||||
return cssutils.ser.do_css_CSSStyleDeclaration(self)
|
||||
|
||||
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
|
||||
including the removal or addition of properties.
|
||||
|
||||
DOMException on setting
|
||||
|
||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
||||
Raised if this declaration is readonly or a property is readonly.
|
||||
- SYNTAX_ERR: (self)
|
||||
Raised if the specified CSS string value has a syntax error and
|
||||
is unparsable.
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
Raised if this declaration is readonly or a property is readonly.
|
||||
- :exc:`~xml.dom.SyntaxErr`:
|
||||
Raised if the specified CSS string value has a syntax error and
|
||||
is unparsable.
|
||||
"""
|
||||
self._checkReadonly()
|
||||
tokenizer = self._tokenize2(cssText)
|
||||
@ -336,11 +313,12 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
||||
|
||||
def getCssText(self, separator=None):
|
||||
"""
|
||||
returns serialized property cssText, each property separated by
|
||||
given ``separator`` which may e.g. be u'' to be able to use
|
||||
cssText directly in an HTML style attribute. ";" is always part of
|
||||
each property (except the last one) and can **not** be set with
|
||||
separator!
|
||||
:returns:
|
||||
serialized property cssText, each property separated by
|
||||
given `separator` which may e.g. be ``u''`` to be able to use
|
||||
cssText directly in an HTML style attribute. ``;`` is part of
|
||||
each property (except the last one) and **cannot** be set with
|
||||
separator!
|
||||
"""
|
||||
return cssutils.ser.do_css_CSSStyleDeclaration(self, separator)
|
||||
|
||||
@ -351,25 +329,27 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
||||
self._parentRule = parentRule
|
||||
|
||||
parentRule = property(_getParentRule, _setParentRule,
|
||||
doc="(DOM) The CSS rule that contains this declaration block or\
|
||||
None if this CSSStyleDeclaration is not attached to a CSSRule.")
|
||||
doc="(DOM) The CSS rule that contains this declaration block or "
|
||||
"None if this CSSStyleDeclaration is not attached to a CSSRule.")
|
||||
|
||||
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
|
||||
optional name of properties which are requested (a filter).
|
||||
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.
|
||||
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
|
||||
stylesheet.
|
||||
:returns:
|
||||
a list of :class:`~cssutils.css.Property` objects set in
|
||||
this declaration.
|
||||
"""
|
||||
if name and not all:
|
||||
# single prop but list
|
||||
@ -394,16 +374,16 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
||||
|
||||
def getProperty(self, name, normalize=True):
|
||||
"""
|
||||
Returns the effective Property object.
|
||||
|
||||
name
|
||||
:param name:
|
||||
of the CSS property, always lowercase (even if not normalized)
|
||||
normalize
|
||||
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
|
||||
|
||||
If False may return **NOT** the effective value but the effective
|
||||
for the unnormalized name.
|
||||
If ``False`` may return **NOT** the effective value but the
|
||||
effective for the unnormalized name.
|
||||
:returns:
|
||||
the effective :class:`~cssutils.css.Property` object.
|
||||
"""
|
||||
nname = self._normalize(name)
|
||||
found = None
|
||||
@ -419,17 +399,17 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
||||
|
||||
def getPropertyCSSValue(self, name, normalize=True):
|
||||
"""
|
||||
Returns CSSValue, the value of the effective property if it has been
|
||||
explicitly set for this declaration block.
|
||||
|
||||
name
|
||||
:param name:
|
||||
of the CSS property, always lowercase (even if not normalized)
|
||||
normalize
|
||||
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
|
||||
|
||||
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.
|
||||
:returns:
|
||||
:class:`~cssutils.css.CSSValue`, the value of the effective
|
||||
property if it has been explicitly set for this declaration block.
|
||||
|
||||
(DOM)
|
||||
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):
|
||||
"""
|
||||
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.
|
||||
|
||||
name
|
||||
:param name:
|
||||
of the CSS property, always lowercase (even if not normalized)
|
||||
normalize
|
||||
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
|
||||
|
||||
If False may return **NOT** the effective value but the effective
|
||||
for the unnormalized name.
|
||||
If ``False`` may return **NOT** the effective value but the
|
||||
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)
|
||||
if p:
|
||||
@ -482,18 +462,18 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
||||
|
||||
def getPropertyPriority(self, name, normalize=True):
|
||||
"""
|
||||
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.
|
||||
|
||||
name
|
||||
:param name:
|
||||
of the CSS property, always lowercase (even if not normalized)
|
||||
normalize
|
||||
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
|
||||
|
||||
If False may return **NOT** the effective value but the effective
|
||||
for the unnormalized name.
|
||||
If ``False`` may return **NOT** the effective value but the
|
||||
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)
|
||||
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
|
||||
this declaration block.
|
||||
|
||||
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
|
||||
|
||||
name
|
||||
:param name:
|
||||
of the CSS property
|
||||
normalize
|
||||
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.
|
||||
The effective Property value is returned and *all* Properties
|
||||
with ``Property.name == name`` are removed.
|
||||
|
||||
If False may return **NOT** the effective value but the effective
|
||||
for the unnormalized ``name`` only. Also only the Properties with
|
||||
the literal name ``name`` are removed.
|
||||
If ``False`` may return **NOT** the effective value but the
|
||||
effective for the unnormalized `name` only. Also only the
|
||||
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)
|
||||
Raised if this declaration is readonly or the property is
|
||||
readonly.
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
Raised if this declaration is readonly or the property is
|
||||
readonly.
|
||||
"""
|
||||
self._checkReadonly()
|
||||
r = self.getPropertyValue(name, normalize=normalize)
|
||||
@ -548,36 +528,35 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
||||
return r
|
||||
|
||||
def setProperty(self, name, value=None, priority=u'', normalize=True):
|
||||
"""
|
||||
(DOM)
|
||||
Used to set a property value and priority within this declaration
|
||||
"""(DOM) Set a property value and priority within this declaration
|
||||
block.
|
||||
|
||||
name
|
||||
:param name:
|
||||
of the CSS property to set (in W3C DOM the parameter is called
|
||||
"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
|
||||
|
||||
value
|
||||
the new value of the property, omit if name is already a Property
|
||||
priority
|
||||
the optional priority of the property (e.g. "important")
|
||||
normalize
|
||||
if True (DEFAULT) name will be normalized (lowercase, no simple
|
||||
:param value:
|
||||
the new value of the property, ignored if `name` is a Property.
|
||||
:param priority:
|
||||
the optional priority of the property (e.g. "important"),
|
||||
ignored if `name` is a Property.
|
||||
:param normalize:
|
||||
if True (DEFAULT) `name` will be normalized (lowercase, no simple
|
||||
escapes) so "color", "COLOR" or "C\olor" will all be equivalent
|
||||
|
||||
DOMException on setting
|
||||
|
||||
- SYNTAX_ERR: (self)
|
||||
Raised if the specified value has a syntax error and is
|
||||
unparsable.
|
||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
||||
Raised if this declaration is readonly or the property is
|
||||
readonly.
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.SyntaxErr`:
|
||||
Raised if the specified value has a syntax error and is
|
||||
unparsable.
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
Raised if this declaration is readonly or the property is
|
||||
readonly.
|
||||
"""
|
||||
self._checkReadonly()
|
||||
|
||||
@ -607,27 +586,26 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
||||
self.seq._readonly = True
|
||||
|
||||
def item(self, index):
|
||||
"""
|
||||
(DOM)
|
||||
Used to retrieve the properties that have been explicitly set in
|
||||
"""(DOM) Retrieve the properties that have been explicitly set in
|
||||
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 can be used to iterate over all properties in this
|
||||
declaration block.
|
||||
|
||||
index
|
||||
:param index:
|
||||
of the property to retrieve, negative values behave like
|
||||
negative indexes on Python lists, so -1 is the last element
|
||||
|
||||
returns the name of the property at this ordinal position. The
|
||||
empty string if no property exists at this position.
|
||||
:returns:
|
||||
the name of the property at this ordinal position. The
|
||||
empty string if no property exists at this position.
|
||||
|
||||
ATTENTION:
|
||||
Only properties with a different name are counted. If two
|
||||
**ATTENTION:**
|
||||
Only properties with different names are counted. If two
|
||||
properties with the same name are present in this declaration
|
||||
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())
|
||||
try:
|
||||
@ -636,16 +614,7 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
|
||||
return u''
|
||||
|
||||
length = property(lambda self: len(self.__nnames()),
|
||||
doc="(DOM) The number of distinct properties that have been explicitly\
|
||||
in this declaration block. The range of valid indices is 0 to\
|
||||
length-1 inclusive. These are properties with a different ``name``\
|
||||
only. ``item()`` and ``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))
|
||||
doc="(DOM) The number of distinct properties that have been explicitly "
|
||||
"in this declaration block. The range of valid indices is 0 to "
|
||||
"length-1 inclusive. These are properties with a different ``name`` "
|
||||
"only. :meth:`item` and :attr:`length` work on the same set here.")
|
||||
|
@ -1,49 +1,25 @@
|
||||
"""CSSStyleRule implements DOM Level 2 CSS CSSStyleRule.
|
||||
"""
|
||||
"""CSSStyleRule implements DOM Level 2 CSS CSSStyleRule."""
|
||||
__all__ = ['CSSStyleRule']
|
||||
__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 cssutils
|
||||
from selectorlist import SelectorList
|
||||
from cssstyledeclaration import CSSStyleDeclaration
|
||||
import xml.dom
|
||||
|
||||
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
|
||||
associated group of selectors.
|
||||
|
||||
Properties
|
||||
==========
|
||||
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::
|
||||
Format::
|
||||
|
||||
: selector [ COMMA S* selector ]*
|
||||
LBRACE S* declaration [ ';' S* declaration ]* '}' S*
|
||||
;
|
||||
"""
|
||||
type = property(lambda self: cssrule.CSSRule.STYLE_RULE)
|
||||
|
||||
def __init__(self, selectorText=None, style=None, parentRule=None,
|
||||
parentStyleSheet=None, readonly=False):
|
||||
"""
|
||||
@ -67,31 +43,41 @@ class CSSStyleRule(cssrule.CSSRule):
|
||||
|
||||
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):
|
||||
"""
|
||||
returns serialized property cssText
|
||||
"""
|
||||
"""Return serialized property cssText."""
|
||||
return cssutils.ser.do_CSSStyleRule(self)
|
||||
|
||||
def _setCssText(self, cssText):
|
||||
"""
|
||||
:param cssText:
|
||||
a parseable string or a tuple of (cssText, dict-of-namespaces)
|
||||
:Exceptions:
|
||||
- `NAMESPACE_ERR`: (Selector)
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.NamespaceErr`:
|
||||
Raised if the specified selector uses an unknown namespace
|
||||
prefix.
|
||||
- `SYNTAX_ERR`: (self, StyleDeclaration, etc)
|
||||
- :exc:`~xml.dom.SyntaxErr`:
|
||||
Raised if the specified CSS string value has a syntax error and
|
||||
is unparsable.
|
||||
- `INVALID_MODIFICATION_ERR`: (self)
|
||||
- :exc:`~xml.dom.InvalidModificationErr`:
|
||||
Raised if the specified CSS string value represents a different
|
||||
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
|
||||
style sheet.
|
||||
- `NO_MODIFICATION_ALLOWED_ERR`: (CSSRule)
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
Raised if the rule is readonly.
|
||||
"""
|
||||
super(CSSStyleRule, self)._setCssText(cssText)
|
||||
@ -160,20 +146,21 @@ class CSSStyleRule(cssrule.CSSRule):
|
||||
self.style = newstyle
|
||||
|
||||
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):
|
||||
"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:
|
||||
return self.parentStyleSheet.namespaces
|
||||
except AttributeError:
|
||||
return self.selectorList._namespaces
|
||||
|
||||
_namespaces = property(__getNamespaces, doc=u"""if this Rule is
|
||||
attached to a CSSStyleSheet the namespaces of that sheet are mirrored
|
||||
here. While the Rule is not attached the namespaces of selectorList
|
||||
are used.""")
|
||||
_namespaces = property(__getNamespaces,
|
||||
doc="If this Rule is attached to a CSSStyleSheet "
|
||||
"the namespaces of that sheet are mirrored "
|
||||
"here. While the Rule is not attached the "
|
||||
"namespaces of selectorList are used.""")
|
||||
|
||||
def _setSelectorList(self, selectorList):
|
||||
"""
|
||||
@ -190,16 +177,17 @@ class CSSStyleRule(cssrule.CSSRule):
|
||||
"""
|
||||
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
|
||||
:Exceptions:
|
||||
- `NAMESPACE_ERR`: (Selector)
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.NamespaceErr`:
|
||||
Raised if the specified selector uses an unknown namespace
|
||||
prefix.
|
||||
- `SYNTAX_ERR`: (SelectorList, Selector)
|
||||
- :exc:`~xml.dom.SyntaxErr`:
|
||||
Raised if the specified CSS string value has a syntax error
|
||||
and is unparsable.
|
||||
- `NO_MODIFICATION_ALLOWED_ERR`: (self)
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
Raised if this rule is readonly.
|
||||
"""
|
||||
self._checkReadonly()
|
||||
@ -207,8 +195,8 @@ class CSSStyleRule(cssrule.CSSRule):
|
||||
|
||||
selectorText = property(lambda self: self._selectorList.selectorText,
|
||||
_setSelectorText,
|
||||
doc="""(DOM) The textual representation of the selector for the
|
||||
rule set.""")
|
||||
doc="(DOM) The textual representation of the "
|
||||
"selector for the rule set.")
|
||||
|
||||
def _setStyle(self, style):
|
||||
"""
|
||||
@ -224,19 +212,10 @@ class CSSStyleRule(cssrule.CSSRule):
|
||||
self._style._seq = style._seq
|
||||
|
||||
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)
|
||||
|
||||
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:
|
||||
- http://dev.w3.org/csswg/cssom/#the-cssstylesheet
|
||||
@ -10,53 +9,32 @@ TODO:
|
||||
"""
|
||||
__all__ = ['CSSStyleSheet']
|
||||
__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.util import _Namespaces, _SimpleNamespaces, _readUrl
|
||||
import cssutils.stylesheets
|
||||
import xml.dom
|
||||
|
||||
class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
|
||||
"""
|
||||
The CSSStyleSheet interface represents a CSS style sheet.
|
||||
"""CSSStyleSheet represents a CSS style sheet.
|
||||
|
||||
Properties
|
||||
==========
|
||||
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.
|
||||
Format::
|
||||
|
||||
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
|
||||
--------
|
||||
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]* ]*
|
||||
``cssRules``
|
||||
All Rules in this style sheet, a :class:`~cssutils.css.CSSRuleList`.
|
||||
"""
|
||||
def __init__(self, href=None, media=None, title=u'', disabled=None,
|
||||
ownerNode=None, parentStyleSheet=None, readonly=False,
|
||||
ownerRule=None):
|
||||
"""
|
||||
init parameters are the same as for stylesheets.StyleSheet
|
||||
For parameters see :class:`~cssutils.stylesheets.StyleSheet`
|
||||
"""
|
||||
super(CSSStyleSheet, self).__init__(
|
||||
'text/css', href, media, title, disabled,
|
||||
@ -74,12 +52,32 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
|
||||
self._fetcher = None
|
||||
|
||||
def __iter__(self):
|
||||
"generator which iterates over cssRules."
|
||||
"Generator which iterates over cssRules."
|
||||
for rule in self.cssRules:
|
||||
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):
|
||||
"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
|
||||
namespaceitems = self.namespaces.items()
|
||||
i = 0
|
||||
@ -92,7 +90,7 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
|
||||
i += 1
|
||||
|
||||
def _getUsedURIs(self):
|
||||
"returns set of URIs used in the sheet"
|
||||
"Return set of URIs used in the sheet."
|
||||
useduris = set()
|
||||
for r1 in self:
|
||||
if r1.STYLE_RULE == r1.type:
|
||||
@ -104,21 +102,20 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
|
||||
return useduris
|
||||
|
||||
def _getCssText(self):
|
||||
"Textual representation of the stylesheet (a byte string)."
|
||||
return cssutils.ser.do_CSSStyleSheet(self)
|
||||
|
||||
def _setCssText(self, cssText):
|
||||
"""
|
||||
(cssutils)
|
||||
Parses ``cssText`` and overwrites the whole stylesheet.
|
||||
"""Parse `cssText` and overwrites the whole stylesheet.
|
||||
|
||||
:param cssText:
|
||||
a parseable string or a tuple of (cssText, dict-of-namespaces)
|
||||
:Exceptions:
|
||||
- `NAMESPACE_ERR`:
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.NamespaceErr`:
|
||||
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.
|
||||
- `SYNTAX_ERR`:
|
||||
- :exc:`~xml.dom.SyntaxErr`:
|
||||
Raised if the specified CSS string value has a syntax error and
|
||||
is unparsable.
|
||||
"""
|
||||
@ -269,10 +266,10 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
|
||||
self._cleanNamespaces()
|
||||
|
||||
cssText = property(_getCssText, _setCssText,
|
||||
"(cssutils) a textual representation of the stylesheet")
|
||||
"Textual representation of the stylesheet (a byte string)")
|
||||
|
||||
def _resolveImport(self, url):
|
||||
"""Read (encoding, enctype, decodedContent) from ``url`` for @import
|
||||
"""Read (encoding, enctype, decodedContent) from `url` for @import
|
||||
sheets."""
|
||||
try:
|
||||
# only available during parse of a complete sheet
|
||||
@ -291,10 +288,10 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
|
||||
|
||||
def _setCssTextWithEncodingOverride(self, cssText, encodingOverride=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.
|
||||
|
||||
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:
|
||||
# encoding during resolving of @import
|
||||
self.__encodingOverride = encodingOverride
|
||||
@ -312,14 +309,14 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
|
||||
self.encoding = encoding
|
||||
|
||||
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
|
||||
|
||||
def _setEncoding(self, encoding):
|
||||
"""
|
||||
sets encoding of charset rule if present or inserts new charsetrule
|
||||
with given encoding. If encoding if None removes charsetrule if
|
||||
present.
|
||||
"""Set `encoding` of charset rule if present in sheet or insert a new
|
||||
:class:`~cssutils.css.CSSCharsetRule` with given `encoding`.
|
||||
If `encoding` is None removes charsetrule if present resulting in
|
||||
default encoding of utf-8.
|
||||
"""
|
||||
try:
|
||||
rule = self.cssRules[0]
|
||||
@ -334,41 +331,41 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
|
||||
self.insertRule(cssutils.css.CSSCharsetRule(encoding=encoding), 0)
|
||||
|
||||
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:
|
||||
return self.cssRules[0].encoding
|
||||
except (IndexError, AttributeError):
|
||||
return 'utf-8'
|
||||
|
||||
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,
|
||||
doc="Namespaces used in this CSSStyleSheet.")
|
||||
doc="All Namespaces used in this CSSStyleSheet.")
|
||||
|
||||
def add(self, rule):
|
||||
"""
|
||||
Adds rule to stylesheet at appropriate position.
|
||||
Same as ``sheet.insertRule(rule, inOrder=True)``.
|
||||
"""Add `rule` to style sheet at appropriate position.
|
||||
Same as ``insertRule(rule, inOrder=True)``.
|
||||
"""
|
||||
return self.insertRule(rule, index=None, inOrder=True)
|
||||
|
||||
def deleteRule(self, index):
|
||||
"""
|
||||
Used to delete a rule from the style sheet.
|
||||
"""Delete rule at `index` from the style sheet.
|
||||
|
||||
:param index:
|
||||
of the rule to remove in the StyleSheet's rule list. For an
|
||||
index < 0 **no** INDEX_SIZE_ERR is raised but rules for
|
||||
normal Python lists are used. E.g. ``deleteRule(-1)`` removes
|
||||
the last rule in cssRules.
|
||||
:Exceptions:
|
||||
- `INDEX_SIZE_ERR`: (self)
|
||||
`index` < 0 **no** :exc:`~xml.dom.IndexSizeErr` is raised but
|
||||
rules for normal Python lists are used. E.g. ``deleteRule(-1)``
|
||||
removes the last rule in cssRules.
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.IndexSizeErr`:
|
||||
Raised if the specified index does not correspond to a rule in
|
||||
the style sheet's rule list.
|
||||
- `NAMESPACE_ERR`: (self)
|
||||
- :exc:`~xml.dom.NamespaceErr`:
|
||||
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.
|
||||
"""
|
||||
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
|
||||
becomes part of the cascade.
|
||||
|
||||
:Parameters:
|
||||
rule
|
||||
a parsable DOMString, in cssutils also a CSSRule or a
|
||||
CSSRuleList
|
||||
index
|
||||
of the rule before the new rule will be inserted.
|
||||
If the specified index is equal to the length of the
|
||||
StyleSheet's rule collection, the rule will be added to the end
|
||||
of the style sheet.
|
||||
If index is not given or None rule will be appended to rule
|
||||
list.
|
||||
inOrder
|
||||
if True the rule will be put to a proper location while
|
||||
ignoring index but without raising HIERARCHY_REQUEST_ERR.
|
||||
The resulting index is returned nevertheless
|
||||
:returns: the index within the stylesheet's rule collection
|
||||
:param rule:
|
||||
a parsable DOMString, in cssutils also a
|
||||
:class:`~cssutils.css.CSSRule` or :class:`~cssutils.css.CSSRuleList`
|
||||
:param index:
|
||||
of the rule before the new rule will be inserted.
|
||||
If the specified `index` is equal to the length of the
|
||||
StyleSheet's rule collection, the rule will be added to the end
|
||||
of the style sheet.
|
||||
If `index` is not given or ``None`` rule will be appended to rule
|
||||
list.
|
||||
:param inOrder:
|
||||
if ``True`` the rule will be put to a proper location while
|
||||
ignoring `index` and without raising :exc:`~xml.dom.HierarchyRequestErr`.
|
||||
The resulting index is returned nevertheless.
|
||||
:returns: The index within the style sheet's rule collection
|
||||
:Exceptions:
|
||||
- `HIERARCHY_REQUEST_ERR`: (self)
|
||||
Raised if the rule cannot be inserted at the specified index
|
||||
- :exc:`~xml.dom.HierarchyRequestErr`:
|
||||
Raised if the rule cannot be inserted at the specified `index`
|
||||
e.g. if an @import rule is inserted after a standard rule set
|
||||
or other at-rule.
|
||||
- `INDEX_SIZE_ERR`: (self)
|
||||
Raised if the specified index is not a valid insertion point.
|
||||
- `NO_MODIFICATION_ALLOWED_ERR`: (self)
|
||||
- :exc:`~xml.dom.IndexSizeErr`:
|
||||
Raised if the specified `index` is not a valid insertion point.
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
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
|
||||
unparsable.
|
||||
"""
|
||||
@ -618,57 +614,18 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet):
|
||||
return index
|
||||
|
||||
ownerRule = property(lambda self: self._ownerRule,
|
||||
doc="(DOM attribute) NOT IMPLEMENTED YET")
|
||||
|
||||
@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)
|
||||
doc="A ref to an @import rule if it is imported, else ``None``.")
|
||||
|
||||
def setSerializer(self, cssserializer):
|
||||
"""
|
||||
Sets the global Serializer used for output of all stylesheet
|
||||
output.
|
||||
"""
|
||||
"""Set the cssutils global Serializer used for all output."""
|
||||
if isinstance(cssserializer, cssutils.CSSSerializer):
|
||||
cssutils.ser = cssserializer
|
||||
else:
|
||||
raise ValueError(u'Serializer must be an instance of cssutils.CSSSerializer.')
|
||||
|
||||
def setSerializerPref(self, pref, value):
|
||||
"""
|
||||
Sets Preference of CSSSerializer used for output of this
|
||||
stylesheet. See cssutils.serialize.Preferences for possible
|
||||
"""Set a Preference of CSSSerializer used for output.
|
||||
See :class:`cssutils.serialize.Preferences` for possible
|
||||
preferences to be set.
|
||||
"""
|
||||
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']
|
||||
__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 cssutils
|
||||
import xml.dom
|
||||
|
||||
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
|
||||
==========
|
||||
inherited from CSSRule
|
||||
- cssText
|
||||
- type
|
||||
Format::
|
||||
|
||||
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 {...}
|
||||
"""
|
||||
type = property(lambda self: cssrule.CSSRule.UNKNOWN_RULE)
|
||||
|
||||
def __init__(self, cssText=u'', parentRule=None,
|
||||
parentStyleSheet=None, readonly=False):
|
||||
"""
|
||||
cssText
|
||||
:param cssText:
|
||||
of type string
|
||||
"""
|
||||
super(CSSUnknownRule, self).__init__(parentRule=parentRule,
|
||||
@ -49,25 +30,32 @@ class CSSUnknownRule(cssrule.CSSRule):
|
||||
|
||||
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):
|
||||
""" returns serialized property cssText """
|
||||
"""Return serialized property cssText."""
|
||||
return cssutils.ser.do_CSSUnknownRule(self)
|
||||
|
||||
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: (never raised)
|
||||
Raised if the rule cannot be inserted at this point in the
|
||||
style sheet.
|
||||
- NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
|
||||
Raised if the rule is readonly.
|
||||
: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.
|
||||
"""
|
||||
super(CSSUnknownRule, self)._setCssText(cssText)
|
||||
tokenizer = self._tokenize2(cssText)
|
||||
@ -197,12 +185,9 @@ class CSSUnknownRule(cssrule.CSSRule):
|
||||
cssText = property(fget=_getCssText, fset=_setCssText,
|
||||
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))
|
||||
|
||||
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
|
||||
|
||||
Internal use only, may be removed in the future!
|
||||
"""
|
||||
"""Property is a single CSS property in a CSSStyleDeclaration."""
|
||||
__all__ = ['Property']
|
||||
__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
|
||||
import cssutils
|
||||
#import cssproperties
|
||||
from cssutils.helper import Deprecated
|
||||
from cssutils.profiles import profiles
|
||||
from cssvalue import CSSValue
|
||||
from cssutils.helper import Deprecated
|
||||
import cssutils
|
||||
import xml.dom
|
||||
|
||||
class Property(cssutils.util.Base):
|
||||
"""
|
||||
(cssutils) a CSS property in a StyleDeclaration of a CSSStyleRule
|
||||
"""A CSS property in a StyleDeclaration of a CSSStyleRule (cssutils).
|
||||
|
||||
Properties
|
||||
==========
|
||||
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
|
||||
======
|
||||
::
|
||||
Format::
|
||||
|
||||
property = name
|
||||
: 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
|
||||
|
||||
name
|
||||
:param name:
|
||||
a property name string (will be normalized)
|
||||
value
|
||||
:param value:
|
||||
a property value string
|
||||
priority
|
||||
:param priority:
|
||||
an optional priority string which currently must be u'',
|
||||
u'!important' or u'important'
|
||||
_mediaQuery boolean
|
||||
if True value is optional as used by MediaQuery objects
|
||||
:param _mediaQuery:
|
||||
if ``True`` value is optional (used by MediaQuery)
|
||||
:param _parent:
|
||||
the parent object, normally a
|
||||
:class:`cssutils.css.CSSStyleDeclaration`
|
||||
"""
|
||||
super(Property, self).__init__()
|
||||
|
||||
self.seqs = [[], None, []]
|
||||
self.valid = False
|
||||
self.wellformed = False
|
||||
self._mediaQuery = _mediaQuery
|
||||
self._parent = _parent
|
||||
|
||||
self._name = u''
|
||||
self._literalname = u''
|
||||
if name:
|
||||
self.name = name
|
||||
else:
|
||||
self._name = u''
|
||||
self._literalname = u''
|
||||
self.__normalname = u'' # DEPRECATED
|
||||
|
||||
if value:
|
||||
self.cssValue = value
|
||||
else:
|
||||
self.seqs[1] = CSSValue()
|
||||
|
||||
self._priority = u''
|
||||
self._literalpriority = u''
|
||||
if priority:
|
||||
self.priority = priority
|
||||
else:
|
||||
self._priority = u''
|
||||
self._literalpriority = u''
|
||||
|
||||
def __repr__(self):
|
||||
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):
|
||||
"""
|
||||
returns serialized property cssText
|
||||
"""
|
||||
"""Return serialized property cssText."""
|
||||
return cssutils.ser.do_Property(self)
|
||||
|
||||
def _setCssText(self, cssText):
|
||||
"""
|
||||
DOMException on setting
|
||||
|
||||
- NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
|
||||
Raised if the rule is readonly.
|
||||
- SYNTAX_ERR: (self)
|
||||
Raised if the specified CSS string value has a syntax error and
|
||||
is unparsable.
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.SyntaxErr`:
|
||||
Raised if the specified CSS string value has a syntax error and
|
||||
is unparsable.
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
Raised if the rule is readonly.
|
||||
"""
|
||||
# check and prepare tokenlists for setting
|
||||
tokenizer = self._tokenize2(cssText)
|
||||
@ -180,6 +150,9 @@ class Property(cssutils.util.Base):
|
||||
self.cssValue = valuetokens
|
||||
self.priority = prioritytokens
|
||||
|
||||
# also invalid values are set!
|
||||
self.validate()
|
||||
|
||||
else:
|
||||
self._log.error(u'Property: No property name found: %r.' %
|
||||
self._valuestr(cssText))
|
||||
@ -189,11 +162,10 @@ class Property(cssutils.util.Base):
|
||||
|
||||
def _setName(self, name):
|
||||
"""
|
||||
DOMException on setting
|
||||
|
||||
- SYNTAX_ERR: (self)
|
||||
Raised if the specified name has a syntax error and is
|
||||
unparsable.
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.SyntaxErr`:
|
||||
Raised if the specified name has a syntax error and is
|
||||
unparsable.
|
||||
"""
|
||||
# for closures: must be a mutable
|
||||
new = {'literalname': None,
|
||||
@ -233,43 +205,42 @@ class Property(cssutils.util.Base):
|
||||
self.wellformed = True
|
||||
self._literalname = new['literalname']
|
||||
self._name = self._normalize(self._literalname)
|
||||
self.__normalname = self._name # DEPRECATED
|
||||
self.seqs[0] = newseq
|
||||
|
||||
# validate
|
||||
if self._name not in profiles.propertiesByProfile():
|
||||
self.valid = False
|
||||
tokenizer=self._tokenize2(name)
|
||||
self._log.warn(u'Property: Unknown Property: %r.' %
|
||||
new['literalname'], token=token, neverraise=True)
|
||||
# # validate
|
||||
if self._name not in profiles.knownnames:
|
||||
# self.valid = False
|
||||
self._log.warn(u'Property: Unknown Property.',
|
||||
token=token, neverraise=True)
|
||||
else:
|
||||
self.valid = True
|
||||
if self.cssValue:
|
||||
self.cssValue._propertyName = self._name
|
||||
self.valid = self.cssValue.valid
|
||||
pass
|
||||
# self.valid = True
|
||||
# if self.cssValue:
|
||||
# self.cssValue._propertyName = self._name
|
||||
# #self.valid = self.cssValue.valid
|
||||
else:
|
||||
self.wellformed = False
|
||||
|
||||
name = property(lambda self: self._name, _setName,
|
||||
doc="Name of this property")
|
||||
doc="Name of this property.")
|
||||
|
||||
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):
|
||||
return self.seqs[1]
|
||||
|
||||
def _setCSSValue(self, cssText):
|
||||
"""
|
||||
see css.CSSValue
|
||||
See css.CSSValue
|
||||
|
||||
DOMException on setting?
|
||||
|
||||
- SYNTAX_ERR: (self)
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.SyntaxErr`:
|
||||
Raised if the specified CSS string value has a syntax error
|
||||
(according to the attached property) or is unparsable.
|
||||
- TODO: INVALID_MODIFICATION_ERR:
|
||||
Raised if the specified CSS string value represents a different
|
||||
- :exc:`~xml.dom.InvalidModificationErr`:
|
||||
TODO: Raised if the specified CSS string value represents a different
|
||||
type of values than the values allowed by the CSS property.
|
||||
"""
|
||||
if self._mediaQuery and not cssText:
|
||||
@ -279,25 +250,24 @@ class Property(cssutils.util.Base):
|
||||
self.seqs[1] = CSSValue()
|
||||
|
||||
cssvalue = self.seqs[1]
|
||||
cssvalue._propertyName = self.name
|
||||
cssvalue.cssText = cssText
|
||||
if cssvalue._value and cssvalue.wellformed:
|
||||
if cssvalue.wellformed: #cssvalue._value and
|
||||
self.seqs[1] = cssvalue
|
||||
self.valid = self.valid and cssvalue.valid
|
||||
self.wellformed = self.wellformed and cssvalue.wellformed
|
||||
|
||||
cssValue = property(_getCSSValue, _setCSSValue,
|
||||
doc="(cssutils) CSSValue object of this property")
|
||||
|
||||
|
||||
def _getValue(self):
|
||||
if self.cssValue:
|
||||
return self.cssValue._value
|
||||
return self.cssValue.cssText # _value # [0]
|
||||
else:
|
||||
return u''
|
||||
|
||||
def _setValue(self, 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
|
||||
|
||||
value = property(_getValue, _setValue,
|
||||
@ -308,9 +278,7 @@ class Property(cssutils.util.Base):
|
||||
priority
|
||||
a string, currently either u'', u'!important' or u'important'
|
||||
|
||||
Format
|
||||
======
|
||||
::
|
||||
Format::
|
||||
|
||||
prio
|
||||
: IMPORTANT_SYM S*
|
||||
@ -318,14 +286,13 @@ class Property(cssutils.util.Base):
|
||||
|
||||
"!"{w}"important" {return IMPORTANT_SYM;}
|
||||
|
||||
DOMException on setting
|
||||
|
||||
- SYNTAX_ERR: (self)
|
||||
Raised if the specified priority has a syntax error and is
|
||||
unparsable.
|
||||
In this case a priority not equal to None, "" or "!{w}important".
|
||||
As CSSOM defines CSSStyleDeclaration.getPropertyPriority resulting in
|
||||
u'important' this value is also allowed to set a Properties priority
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.SyntaxErr`:
|
||||
Raised if the specified priority has a syntax error and is
|
||||
unparsable.
|
||||
In this case a priority not equal to None, "" or "!{w}important".
|
||||
As CSSOM defines CSSStyleDeclaration.getPropertyPriority resulting in
|
||||
u'important' this value is also allowed to set a Properties priority
|
||||
"""
|
||||
if self._mediaQuery:
|
||||
self._priority = u''
|
||||
@ -356,8 +323,7 @@ class Property(cssutils.util.Base):
|
||||
def _ident(expected, seq, token, tokenizer=None):
|
||||
# "important"
|
||||
val = self._tokenvalue(token)
|
||||
normalval = self._tokenvalue(token, normalize=True)
|
||||
if 'important' == expected == normalval:
|
||||
if 'important' == expected:
|
||||
new['literalpriority'] = val
|
||||
seq.append(val)
|
||||
return 'EOF'
|
||||
@ -378,38 +344,66 @@ class Property(cssutils.util.Base):
|
||||
if priority and not new['literalpriority']:
|
||||
wellformed = False
|
||||
self._log.info(u'Property: Invalid priority: %r.' %
|
||||
self._valuestr(priority))
|
||||
self._valuestr(priority))
|
||||
|
||||
if wellformed:
|
||||
self.wellformed = self.wellformed and wellformed
|
||||
self._literalpriority = new['literalpriority']
|
||||
self._priority = self._normalize(self.literalpriority)
|
||||
self.seqs[2] = newseq
|
||||
|
||||
# validate
|
||||
# validate priority
|
||||
if self._priority not in (u'', u'important'):
|
||||
self.valid = False
|
||||
self._log.info(u'Property: No CSS2 priority value: %r.' %
|
||||
self._priority, neverraise=True)
|
||||
self._log.error(u'Property: No CSS priority value: %r.' %
|
||||
self._priority)
|
||||
|
||||
priority = property(lambda self: self._priority, _setPriority,
|
||||
doc="(cssutils) Priority of this property")
|
||||
doc="Priority of this property.")
|
||||
|
||||
literalpriority = property(lambda self: self._literalpriority,
|
||||
doc="Readonly literal (not normalized) priority of this property")
|
||||
|
||||
def __repr__(self):
|
||||
return "cssutils.css.%s(name=%r, value=%r, priority=%r)" % (
|
||||
self.__class__.__name__,
|
||||
self.literalname, self.cssValue.cssText, self.priority)
|
||||
def validate(self, profile=None):
|
||||
"""Validate value against `profile`.
|
||||
|
||||
def __str__(self):
|
||||
return "<%s.%s object name=%r value=%r priority=%r at 0x%x>" % (
|
||||
self.__class__.__module__, self.__class__.__name__,
|
||||
self.name, self.cssValue.cssText, self.priority, id(self))
|
||||
:param profile:
|
||||
A profile name used for validating. If no `profile` is given
|
||||
``Property.profiles
|
||||
"""
|
||||
valid = False
|
||||
|
||||
@Deprecated(u'Use property ``name`` instead (since cssutils 0.9.5).')
|
||||
def _getNormalname(self):
|
||||
return self.__normalname
|
||||
normalname = property(_getNormalname,
|
||||
doc="DEPRECATED since 0.9.5, use name instead")
|
||||
if self.name and self.value:
|
||||
if profile is None:
|
||||
usedprofile = cssutils.profiles.defaultprofile
|
||||
else:
|
||||
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.
|
||||
|
||||
Partly implements
|
||||
http://www.w3.org/TR/css3-selectors/
|
||||
Partly implements http://www.w3.org/TR/css3-selectors/.
|
||||
|
||||
TODO
|
||||
- .contains(selector)
|
||||
@ -9,45 +7,18 @@ TODO
|
||||
"""
|
||||
__all__ = ['Selector']
|
||||
__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
|
||||
import cssutils
|
||||
import xml.dom
|
||||
|
||||
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
|
||||
==========
|
||||
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
|
||||
======
|
||||
::
|
||||
Format::
|
||||
|
||||
# implemented in SelectorList
|
||||
selectors_group
|
||||
@ -150,14 +121,46 @@ class Selector(cssutils.util.Base2):
|
||||
|
||||
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):
|
||||
"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:
|
||||
return self._parent.parentRule.parentStyleSheet.namespaces
|
||||
except AttributeError:
|
||||
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.
|
||||
While the Selector (or parent SelectorList or parentRule(s) of that are
|
||||
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.")
|
||||
|
||||
def _getSelectorText(self):
|
||||
"""
|
||||
returns serialized format
|
||||
"""
|
||||
"""Return serialized format."""
|
||||
return cssutils.ser.do_css_Selector(self)
|
||||
|
||||
def _setSelectorText(self, selectorText):
|
||||
@ -183,14 +184,14 @@ class Selector(cssutils.util.Base2):
|
||||
Given namespaces are ignored if this object is attached to a
|
||||
CSSStyleSheet!
|
||||
|
||||
:Exceptions:
|
||||
- `NAMESPACE_ERR`: (self)
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.NamespaceErr`:
|
||||
Raised if the specified selector uses an unknown namespace
|
||||
prefix.
|
||||
- `SYNTAX_ERR`: (self)
|
||||
- :exc:`~xml.dom.SyntaxErr`:
|
||||
Raised if the specified CSS string value has a syntax error
|
||||
and is unparsable.
|
||||
- `NO_MODIFICATION_ALLOWED_ERR`: (self)
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
Raised if this rule is readonly.
|
||||
"""
|
||||
self._checkReadonly()
|
||||
@ -763,38 +764,17 @@ class Selector(cssutils.util.Base2):
|
||||
|
||||
|
||||
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)))
|
||||
|
||||
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']
|
||||
__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
|
||||
import cssutils
|
||||
import xml.dom
|
||||
|
||||
class SelectorList(cssutils.util.Base, cssutils.util.ListSeq):
|
||||
"""
|
||||
(cssutils) a list of Selectors of a 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
|
||||
"""
|
||||
"""A list of :class:`~cssutils.css.Selector` objects
|
||||
of a :class:`~cssutils.css.CSSStyleRule`."""
|
||||
def __init__(self, selectorText=None, parentRule=None,
|
||||
readonly=False):
|
||||
"""
|
||||
initializes SelectorList with optional selectorText
|
||||
|
||||
:Parameters:
|
||||
selectorText
|
||||
parsable list of Selectors
|
||||
@ -63,8 +44,30 @@ class SelectorList(cssutils.util.Base, cssutils.util.ListSeq):
|
||||
|
||||
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):
|
||||
"used by appendSelector and __setitem__"
|
||||
"Used by appendSelector and __setitem__"
|
||||
if not namespaces:
|
||||
namespaces = {}
|
||||
self._checkReadonly()
|
||||
@ -75,26 +78,8 @@ class SelectorList(cssutils.util.Base, cssutils.util.ListSeq):
|
||||
newSelector._parent = self # maybe set twice but must be!
|
||||
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):
|
||||
"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:
|
||||
return self.parentRule.parentStyleSheet.namespaces
|
||||
except AttributeError:
|
||||
@ -103,17 +88,67 @@ class SelectorList(cssutils.util.Base, cssutils.util.ListSeq):
|
||||
namespaces.update(selector._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
|
||||
here. While the SelectorList (or parentRule(s) are
|
||||
not attached the namespaces of all children Selectors are used.""")
|
||||
|
||||
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.")
|
||||
def append(self, newSelector):
|
||||
"Same as :meth:`appendSelector`."
|
||||
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):
|
||||
"returns serialized format"
|
||||
"Return serialized format."
|
||||
return cssutils.ser.do_css_SelectorList(self)
|
||||
|
||||
def _setSelectorText(self, selectorText):
|
||||
@ -121,14 +156,14 @@ class SelectorList(cssutils.util.Base, cssutils.util.ListSeq):
|
||||
:param selectorText:
|
||||
comma-separated list of selectors or a tuple of
|
||||
(selectorText, dict-of-namespaces)
|
||||
:Exceptions:
|
||||
- `NAMESPACE_ERR`: (Selector)
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.NamespaceErr`:
|
||||
Raised if the specified selector uses an unknown namespace
|
||||
prefix.
|
||||
- `SYNTAX_ERR`: (self)
|
||||
- :exc:`~xml.dom.SyntaxErr`:
|
||||
Raised if the specified CSS string value has a syntax error
|
||||
and is unparsable.
|
||||
- `NO_MODIFICATION_ALLOWED_ERR`: (self)
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
Raised if this rule is readonly.
|
||||
"""
|
||||
self._checkReadonly()
|
||||
@ -184,66 +219,12 @@ class SelectorList(cssutils.util.Base, cssutils.util.ListSeq):
|
||||
doc="""(cssutils) The textual representation of the selector for
|
||||
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)))
|
||||
|
||||
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']
|
||||
__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
|
||||
MACROS = {
|
||||
'ident': r'[-]?{nmstart}{nmchar}*',
|
||||
'name': r'{nmchar}+',
|
||||
'nmstart': r'[_a-zA-Z]|{nonascii}|{escape}',
|
||||
'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-\4177777]',
|
||||
'nmstart': r'[_a-zA-Z]|{nonascii}|{escape}',
|
||||
'nmchar': r'[-_a-zA-Z0-9]|{nonascii}|{escape}',
|
||||
|
||||
'num': r'[0-9]*\.[0-9]+|[0-9]+', #r'[-]?\d+|[-]?\d*\.\d+',
|
||||
'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}',
|
||||
'string1': r'"([^\n\r\f\\"]|\\{nl}|{escape})*"',
|
||||
'string2': r"'([^\n\r\f\\']|\\{nl}|{escape})*'",
|
||||
'invalid1': 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'\/\*[^*]*\*+([^/][^*]*\*+)*\/',
|
||||
'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])?',
|
||||
'C': r'C|c|\\0{0,4}(?:43|63)(?:\r\n|[ \t\r\n\f])?',
|
||||
@ -77,8 +68,8 @@ MACROS = {
|
||||
PRODUCTIONS = [
|
||||
('BOM', r'\xFEFF'), # will only be checked at beginning of CSS
|
||||
|
||||
('S', r'{wc}+'), # 1st in list of general productions
|
||||
('URI', r'{U}{R}{L}\({w}({string}|{urlchar}*){w}\)'),
|
||||
('S', r'{s}+'), # 1st in list of general productions
|
||||
('URI', r'{U}{R}{L}\({w}({string}|{url}*){w}\)'),
|
||||
('FUNCTION', r'{ident}\('),
|
||||
('IDENT', r'{ident}'),
|
||||
('STRING', r'{string}'),
|
||||
|
@ -16,12 +16,12 @@ log
|
||||
"""
|
||||
__all__ = ['ErrorHandler']
|
||||
__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 urllib2
|
||||
import xml.dom
|
||||
from helper import Deprecated
|
||||
|
||||
class _ErrorHandler(object):
|
||||
"""
|
||||
@ -74,17 +74,22 @@ class _ErrorHandler(object):
|
||||
handles all calls
|
||||
logs or raises exception
|
||||
"""
|
||||
line, col = None, None
|
||||
if token:
|
||||
if isinstance(token, tuple):
|
||||
msg = u'%s [%s:%s: %s]' % (
|
||||
msg, token[2], token[3], token[1])
|
||||
value, line, col = token[1], token[2], token[3]
|
||||
else:
|
||||
msg = u'%s [%s:%s: %s]' % (
|
||||
msg, token.line, token.col, token.value)
|
||||
value, line, col = token.value, token.line, token.col
|
||||
msg = u'%s [%s:%s: %s]' % (
|
||||
msg, line, col, value)
|
||||
|
||||
if error and self.raiseExceptions and not neverraise:
|
||||
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:
|
||||
raise error(msg)
|
||||
else:
|
||||
|
@ -1,6 +1,5 @@
|
||||
"""cssutils helper
|
||||
"""
|
||||
__all__ = ['Deprecated', 'normalize']
|
||||
__docformat__ = 'restructuredtext'
|
||||
__version__ = '$Id: errorhandler.py 1234 2008-05-22 20:26:12Z cthedot $'
|
||||
|
||||
@ -32,7 +31,6 @@ class Deprecated(object):
|
||||
|
||||
# simple escapes, all non unicodes
|
||||
_simpleescapes = re.compile(ur'(\\[^0-9a-fA-F])').sub
|
||||
|
||||
def normalize(x):
|
||||
"""
|
||||
normalizes x, namely:
|
||||
@ -49,3 +47,81 @@ def normalize(x):
|
||||
return x.lower()
|
||||
else:
|
||||
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
|
||||
"""a validating CSSParser
|
||||
"""
|
||||
"""A validating CSSParser"""
|
||||
__all__ = ['CSSParser']
|
||||
__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
|
||||
import tokenize2
|
||||
import codecs
|
||||
import cssutils
|
||||
import os
|
||||
import tokenize2
|
||||
import urllib
|
||||
|
||||
class CSSParser(object):
|
||||
"""
|
||||
parses a CSS StyleSheet string or file and
|
||||
returns a DOM Level 2 CSS StyleSheet object
|
||||
"""Parse a CSS StyleSheet from URL, string or file and return a DOM Level 2
|
||||
CSS StyleSheet object.
|
||||
|
||||
Usage::
|
||||
|
||||
parser = CSSParser()
|
||||
|
||||
# optionally
|
||||
parser.setFetcher(fetcher)
|
||||
|
||||
sheet = parser.parseFile('test1.css', 'ascii')
|
||||
|
||||
print sheet.cssText
|
||||
"""
|
||||
def __init__(self, log=None, loglevel=None, raiseExceptions=None,
|
||||
@ -40,7 +35,7 @@ class CSSParser(object):
|
||||
parsing. Later while working with the resulting sheets
|
||||
the setting used in cssutils.log.raiseExeptions is used
|
||||
fetcher
|
||||
see ``setFetchUrl(fetcher)``
|
||||
see ``setFetcher(fetcher)``
|
||||
"""
|
||||
if log is not None:
|
||||
cssutils.log.setLog(log)
|
||||
@ -69,26 +64,28 @@ class CSSParser(object):
|
||||
|
||||
def parseString(self, cssText, encoding=None, href=None, media=None,
|
||||
title=None):
|
||||
"""Return parsed CSSStyleSheet from given string cssText.
|
||||
Raises errors during retrieving (e.g. UnicodeDecodeError).
|
||||
"""Parse `cssText` as :class:`~cssutils.css.CSSStyleSheet`.
|
||||
Errors may be raised (e.g. UnicodeDecodeError).
|
||||
|
||||
cssText
|
||||
:param cssText:
|
||||
CSS string to parse
|
||||
encoding
|
||||
:param encoding:
|
||||
If ``None`` the encoding will be read from BOM or an @charset
|
||||
rule or defaults to UTF-8.
|
||||
If given overrides any found encoding including the ones for
|
||||
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.
|
||||
href
|
||||
The href attribute to assign to the parsed style sheet.
|
||||
Used to resolve other urls in the parsed sheet like @import hrefs
|
||||
media
|
||||
The media attribute to assign to the parsed style sheet
|
||||
(may be a MediaList, list or a string)
|
||||
title
|
||||
The title attribute to assign to the parsed style sheet
|
||||
:param href:
|
||||
The ``href`` attribute to assign to the parsed style sheet.
|
||||
Used to resolve other urls in the parsed sheet like @import hrefs.
|
||||
:param media:
|
||||
The ``media`` attribute to assign to the parsed style sheet
|
||||
(may be a MediaList, list or a string).
|
||||
:param title:
|
||||
The ``title`` attribute to assign to the parsed style sheet.
|
||||
:returns:
|
||||
:class:`~cssutils.css.CSSStyleSheet`.
|
||||
"""
|
||||
self.__parseSetting(True)
|
||||
if isinstance(cssText, str):
|
||||
@ -107,23 +104,23 @@ class CSSParser(object):
|
||||
|
||||
def parseFile(self, filename, encoding=None,
|
||||
href=None, media=None, title=None):
|
||||
"""Retrieve and return a CSSStyleSheet from given filename.
|
||||
Raises errors during retrieving (e.g. IOError).
|
||||
"""Retrieve content from `filename` and parse it. Errors may be raised
|
||||
(e.g. IOError).
|
||||
|
||||
filename
|
||||
of the CSS file to parse, if no ``href`` is given filename is
|
||||
:param filename:
|
||||
of the CSS file to parse, if no `href` is given filename is
|
||||
converted to a (file:) URL and set as ``href`` of resulting
|
||||
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
|
||||
@import rules.
|
||||
encoding
|
||||
:param encoding:
|
||||
Value ``None`` defaults to encoding detection via BOM or an
|
||||
@charset rule.
|
||||
Other values override detected encoding for the sheet at
|
||||
``filename`` including any imported sheets.
|
||||
|
||||
for other parameters see ``parseString``
|
||||
`filename` including any imported sheets.
|
||||
:returns:
|
||||
:class:`~cssutils.css.CSSStyleSheet`.
|
||||
"""
|
||||
if not href:
|
||||
# prepend // for file URL, urllib does not do this?
|
||||
@ -134,19 +131,19 @@ class CSSParser(object):
|
||||
href=href, media=media, title=title)
|
||||
|
||||
def parseUrl(self, href, encoding=None, media=None, title=None):
|
||||
"""Retrieve and return a CSSStyleSheet from given href (an URL).
|
||||
In case of any errors while reading the URL returns None.
|
||||
"""Retrieve content from URL `href` and parse it. Errors may be raised
|
||||
(e.g. URLError).
|
||||
|
||||
href
|
||||
:param href:
|
||||
URL of the CSS file to parse, will also be set as ``href`` of
|
||||
resulting stylesheet
|
||||
encoding
|
||||
:param encoding:
|
||||
Value ``None`` defaults to encoding detection via HTTP, BOM or an
|
||||
@charset rule.
|
||||
A value overrides detected encoding for the sheet at ``href``
|
||||
including any imported sheets.
|
||||
|
||||
for other parameters see ``parseString``
|
||||
:returns:
|
||||
:class:`~cssutils.css.CSSStyleSheet`.
|
||||
"""
|
||||
encoding, enctype, text = cssutils.util._readUrl(href,
|
||||
overrideEncoding=encoding)
|
||||
@ -160,20 +157,24 @@ class CSSParser(object):
|
||||
|
||||
def setFetcher(self, fetcher=None):
|
||||
"""Replace the default URL fetch function with a custom one.
|
||||
The fetcher function gets a single parameter
|
||||
|
||||
``url``
|
||||
the URL to read
|
||||
:param fetcher:
|
||||
A function which gets a single parameter
|
||||
|
||||
and returns ``(encoding, content)`` where ``encoding`` is the HTTP
|
||||
charset normally given via the Content-Type header (which may simply
|
||||
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).
|
||||
``url``
|
||||
the URL to read
|
||||
|
||||
Calling ``setFetcher`` with ``fetcher=None`` resets cssutils
|
||||
to use its default function.
|
||||
and must return ``(encoding, content)`` where ``encoding`` is the
|
||||
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
|
||||
|
||||
|
@ -19,100 +19,152 @@ __docformat__ = 'restructuredtext'
|
||||
__version__ = '$Id: parse.py 1418 2008-08-09 19:27:50Z cthedot $'
|
||||
|
||||
import cssutils
|
||||
import sys
|
||||
|
||||
|
||||
class ParseError(Exception):
|
||||
"""Base Exception class for ProdParser (used internally)."""
|
||||
pass
|
||||
|
||||
class Done(ParseError):
|
||||
"""Raised if Sequence or Choice is finished and no more Prods left."""
|
||||
pass
|
||||
|
||||
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
|
||||
|
||||
class NoMatch(ParseError):
|
||||
"""Raised if Sequence or Choice do not match."""
|
||||
pass
|
||||
|
||||
class MissingToken(ParseError):
|
||||
"""Raised if Sequence or Choice are not exhausted."""
|
||||
"""Raised if nothing in Sequence or Choice does match."""
|
||||
pass
|
||||
|
||||
|
||||
class Choice(object):
|
||||
"""A Choice of productions (Sequence or single Prod)."""
|
||||
def __init__(self, prods):
|
||||
|
||||
def __init__(self, *prods, **options):
|
||||
"""
|
||||
prods
|
||||
*prods
|
||||
Prod or Sequence objects
|
||||
options:
|
||||
optional=False
|
||||
"""
|
||||
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
|
||||
|
||||
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):
|
||||
"""
|
||||
Return:
|
||||
|
||||
- next matching Prod or Sequence
|
||||
- raises ParseError if nothing matches
|
||||
- raises Exhausted if choice already done
|
||||
- ``None`` if any Prod or Sequence is optional and no token matched
|
||||
- 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."""
|
||||
if not self._exhausted:
|
||||
optional = False
|
||||
for x in self._prods:
|
||||
if isinstance(x, Prod):
|
||||
test = x
|
||||
else:
|
||||
# nested Sequence matches if 1st prod matches
|
||||
test = x.first()
|
||||
try:
|
||||
if test.matches(token):
|
||||
self._exhausted = True
|
||||
return x
|
||||
except ParseError, e:
|
||||
# do not raise if other my match
|
||||
continue
|
||||
if x.matches(token):
|
||||
self._exhausted = True
|
||||
x.reset()
|
||||
return x
|
||||
elif x.optional:
|
||||
optional = True
|
||||
else:
|
||||
# None matched
|
||||
raise ParseError(u'No match in choice')
|
||||
else:
|
||||
if not optional:
|
||||
# None matched but also None is optional
|
||||
raise ParseError(u'No match in %s' % self)
|
||||
elif 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):
|
||||
"""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
|
||||
minmax = lambda: (1, 1)
|
||||
callback returning number of times this sequence may run
|
||||
**options:
|
||||
minmax = lambda: (1, 1)
|
||||
callback returning number of times this sequence may run
|
||||
"""
|
||||
self._prods = prods
|
||||
if not minmax:
|
||||
try:
|
||||
minmax = options['minmax']
|
||||
except KeyError:
|
||||
minmax = lambda: (1, 1)
|
||||
|
||||
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._round = 1 # 1 based!
|
||||
self._pos = 0
|
||||
self._prodcount = len(self._prods)
|
||||
self.reset()
|
||||
|
||||
def first(self):
|
||||
"""Return 1st element of Sequence, used by Choice"""
|
||||
# TODO: current impl first only if 1st if an prod!
|
||||
def matches(self, token):
|
||||
"""Called by Choice to try to find if Sequence matches."""
|
||||
for prod in self._prods:
|
||||
if not prod.optional:
|
||||
return prod
|
||||
if prod.matches(token):
|
||||
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):
|
||||
"""Return current element of Sequence, used by name"""
|
||||
# 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:
|
||||
return prod.name
|
||||
return str(prod)
|
||||
else:
|
||||
return 'Unknown'
|
||||
return 'Sequence'
|
||||
|
||||
name = property(_currentName, doc='Used for Error reporting')
|
||||
optional = property(lambda self: self._min == 0)
|
||||
|
||||
def nextProd(self, token):
|
||||
"""Return
|
||||
@ -121,51 +173,53 @@ class Sequence(object):
|
||||
- raises ParseError if nothing matches
|
||||
- raises Exhausted if sequence already done
|
||||
"""
|
||||
while self._pos < self._number:
|
||||
x = self._prods[self._pos]
|
||||
thisround = self._round
|
||||
while self._round < self._max:
|
||||
# for this round
|
||||
i = self._i
|
||||
round = self._round
|
||||
p = self._prods[i]
|
||||
if i == 0:
|
||||
self._roundstarted = False
|
||||
|
||||
self._pos += 1
|
||||
if self._pos == self._number:
|
||||
if self._round < self._max:
|
||||
# new round?
|
||||
self._pos = 0
|
||||
self._round += 1
|
||||
# for next round
|
||||
self._i += 1
|
||||
if self._i == self._prodcount:
|
||||
self._round += 1
|
||||
self._i = 0
|
||||
|
||||
if isinstance(x, Prod):
|
||||
if not token and (x.optional or thisround > self._min):
|
||||
# token is None if nothing expected
|
||||
raise Exhausted()
|
||||
elif not token and not x.optional:
|
||||
raise MissingToken(u'Missing token for production %s'
|
||||
% x.name)
|
||||
elif x.matches(token):
|
||||
return x
|
||||
elif x.optional:
|
||||
# try next
|
||||
continue
|
||||
# elif thisround > self._min:
|
||||
# # minimum done
|
||||
# self._round = self._max
|
||||
# self._pos = self._number
|
||||
# return None
|
||||
if p.matches(token):
|
||||
self._roundstarted = True
|
||||
# reset nested Choice or Prod to use from start
|
||||
p.reset()
|
||||
return p
|
||||
|
||||
elif p.optional:
|
||||
continue
|
||||
|
||||
elif round < self._min:
|
||||
raise Missing(u'Missing token for production %s' % p)
|
||||
|
||||
elif not token:
|
||||
if self._roundstarted:
|
||||
raise Missing(u'Missing token for production %s' % p)
|
||||
else:
|
||||
# should have matched
|
||||
raise NoMatch(u'No matching production for token')
|
||||
raise Done()
|
||||
|
||||
else:
|
||||
# nested Sequence or Choice
|
||||
return x
|
||||
raise NoMatch(u'No matching production for token')
|
||||
|
||||
# Sequence is exhausted
|
||||
if self._round >= self._max:
|
||||
if 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):
|
||||
"""Single Prod in Sequence or Choice."""
|
||||
def __init__(self, name, match, toSeq=None, toStore=None,
|
||||
optional=False):
|
||||
def __init__(self, name, match, optional=False,
|
||||
toSeq=None, toStore=None,
|
||||
stop=False, nextSor=False, mayEnd=False):
|
||||
"""
|
||||
name
|
||||
name used for error reporting
|
||||
@ -173,16 +227,24 @@ class Prod(object):
|
||||
function called with parameters tokentype and tokenvalue
|
||||
returning True, False or raising ParseError
|
||||
toSeq callback (optional)
|
||||
if given calling toSeq(token) will be appended to seq
|
||||
else simply seq
|
||||
calling toSeq(token, tokens) returns (type_, val) == (token[0], token[1])
|
||||
to be appended to seq else simply unaltered (type_, val)
|
||||
toStore (optional)
|
||||
key to save util.Item to store or callback(store, util.Item)
|
||||
optional = False
|
||||
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.optional=optional
|
||||
self.optional = optional
|
||||
self.stop = stop
|
||||
self.nextSor = nextSor
|
||||
self.mayEnd = mayEnd
|
||||
|
||||
def makeToStore(key):
|
||||
"Return a function used by toStore."
|
||||
@ -198,9 +260,9 @@ class Prod(object):
|
||||
# called: seq.append(toSeq(value))
|
||||
self.toSeq = toSeq
|
||||
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
|
||||
elif toStore:
|
||||
self.toStore = makeToStore(toStore)
|
||||
@ -210,12 +272,20 @@ class Prod(object):
|
||||
|
||||
def matches(self, token):
|
||||
"""Return if token matches."""
|
||||
if not token:
|
||||
return False
|
||||
type_, val, line, col = token
|
||||
return self.match(type_, val)
|
||||
|
||||
def reset(self):
|
||||
pass
|
||||
|
||||
def __str__(self):
|
||||
return self._name
|
||||
|
||||
def __repr__(self):
|
||||
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):
|
||||
@ -225,6 +295,70 @@ class ProdParser(object):
|
||||
self._log = cssutils.log
|
||||
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):
|
||||
"""
|
||||
text (or token generator)
|
||||
@ -255,129 +389,140 @@ class ProdParser(object):
|
||||
:store: filled keys defined by Prod.toStore
|
||||
:unusedtokens: token generator containing tokens not used yet
|
||||
"""
|
||||
if isinstance(text, basestring):
|
||||
# to tokenize
|
||||
tokens = self._tokenizer.tokenize(text)
|
||||
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 = self._texttotokens(text)
|
||||
if not tokens:
|
||||
self._log.error(u'No content to parse.')
|
||||
# TODO: return???
|
||||
|
||||
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)
|
||||
|
||||
# store for specific values
|
||||
if not store:
|
||||
if not store: # store for specific values
|
||||
store = {}
|
||||
# store['_raw'] = []
|
||||
|
||||
# stack of productions
|
||||
prods = [productions]
|
||||
|
||||
prods = [productions] # stack of productions
|
||||
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
|
||||
# store['_raw'].append(val)
|
||||
|
||||
# default productions
|
||||
if type_ == self.types.S:
|
||||
# always append S?
|
||||
seq.append(val, type_, line, col)
|
||||
elif type_ == self.types.COMMENT:
|
||||
if type_ == self.types.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:
|
||||
# # @rule
|
||||
# r = cssutils.css.CSSUnknownRule(cssText=val)
|
||||
# seq.append(r, type(r), line, col)
|
||||
elif type_ == self.types.EOF:
|
||||
# do nothing
|
||||
elif type_ == self.types.INVALID:
|
||||
# invalidate parse
|
||||
wellformed = False
|
||||
self._log.error(u'Invalid token: %r' % (token,))
|
||||
break
|
||||
elif type_ == 'EOF':
|
||||
# do nothing? (self.types.EOF == True!)
|
||||
pass
|
||||
# next = 'EOF'
|
||||
else:
|
||||
# check prods
|
||||
started = True # check S now
|
||||
nextSor = False # reset
|
||||
|
||||
try:
|
||||
while True:
|
||||
# find next matching production
|
||||
try:
|
||||
prod = prods[-1].nextProd(token)
|
||||
except (NoMatch, Exhausted), e:
|
||||
except (Exhausted, NoMatch), e:
|
||||
# try next
|
||||
prod = None
|
||||
|
||||
if isinstance(prod, Prod):
|
||||
# found actual Prod, not a Choice or Sequence
|
||||
break
|
||||
elif not prod:
|
||||
if len(prods) > 1:
|
||||
# nested exhausted, next in parent
|
||||
prods.pop()
|
||||
else:
|
||||
raise Exhausted('Extra token')
|
||||
else:
|
||||
elif prod:
|
||||
# nested Sequence, Choice
|
||||
prods.append(prod)
|
||||
|
||||
else:
|
||||
# nested exhausted, try in parent
|
||||
if len(prods) > 1:
|
||||
prods.pop()
|
||||
else:
|
||||
raise ParseError('No match')
|
||||
except ParseError, e:
|
||||
wellformed = False
|
||||
self._log.error(u'%s: %s: %r' % (name, e, token))
|
||||
|
||||
break
|
||||
else:
|
||||
# process prod
|
||||
if prod.toSeq:
|
||||
seq.append(prod.toSeq(val), type_, line, col)
|
||||
else:
|
||||
type_, val = prod.toSeq(token, tokens)
|
||||
if val is not None:
|
||||
seq.append(val, type_, line, col)
|
||||
|
||||
if prod.toStore:
|
||||
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?
|
||||
# # stop here and ignore following tokens
|
||||
# break
|
||||
|
||||
lastprod = prod
|
||||
while True:
|
||||
# all productions exhausted?
|
||||
try:
|
||||
prod = prods[-1].nextProd(token=None)
|
||||
except Exhausted, e:
|
||||
prod = None # ok
|
||||
except (MissingToken, NoMatch), e:
|
||||
wellformed = False
|
||||
self._log.error(u'%s: %s'
|
||||
% (name, e))
|
||||
else:
|
||||
try:
|
||||
if prod.optional:
|
||||
# ignore optional ones
|
||||
continue
|
||||
except AttributeError:
|
||||
pass
|
||||
except Done, e:
|
||||
# ok
|
||||
prod = None
|
||||
|
||||
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
|
||||
self._log.error(u'%s: Missing token for production %r'
|
||||
% (name, prod.name))
|
||||
% (name, str(prod)))
|
||||
break
|
||||
elif len(prods) > 1:
|
||||
# nested exhausted, next in parent
|
||||
prods.pop()
|
||||
else:
|
||||
break
|
||||
|
||||
# bool, Seq, None or generator
|
||||
# trim S from end
|
||||
seq.rstrip()
|
||||
return wellformed, seq, store, tokens
|
||||
|
||||
|
||||
@ -385,18 +530,108 @@ class PreDef(object):
|
||||
"""Predefined Prod definition for use in productions definition
|
||||
for ProdParser instances.
|
||||
"""
|
||||
@staticmethod
|
||||
def comma():
|
||||
","
|
||||
return Prod(name=u'comma', match=lambda t, v: v == u',')
|
||||
types = cssutils.cssproductions.CSSProductions
|
||||
|
||||
@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
|
||||
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 -"
|
||||
return Prod(name=u'unary +-', match=lambda t, v: v in u'+-',
|
||||
optional=True)
|
||||
return Prod(name=u'unary +-', match=lambda t, v: v in (u'+', u'-'),
|
||||
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']
|
||||
@ -10,6 +19,7 @@ __version__ = '$Id: cssproperties.py 1116 2008-03-05 13:52:23Z cthedot $'
|
||||
import cssutils
|
||||
import re
|
||||
|
||||
properties = {}
|
||||
"""
|
||||
Define some regular expression fragments that will be used as
|
||||
macros within the CSS property value regular expressions.
|
||||
@ -56,12 +66,13 @@ css2macros = {
|
||||
'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',
|
||||
'overflow': r'visible|hidden|scroll|auto|inherit',
|
||||
}
|
||||
|
||||
"""
|
||||
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',
|
||||
'background-attachment': r'{background-attachment}',
|
||||
'background-color': r'{background-color}',
|
||||
@ -137,7 +148,7 @@ css2 = {
|
||||
'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',
|
||||
'overflow': r'{overflow}',
|
||||
'padding-top': r'{padding-width}|inherit',
|
||||
'padding-right': r'{padding-width}|inherit',
|
||||
'padding-bottom': r'{padding-width}|inherit',
|
||||
@ -187,14 +198,22 @@ css3colormacros = {
|
||||
# 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}\)',
|
||||
'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)',
|
||||
|
||||
}
|
||||
|
||||
|
||||
css3color = {
|
||||
properties['css3color'] = {
|
||||
'color': r'{namedcolor}|{hexcolor}|{rgbcolor}|{rgbacolor}|{hslcolor}|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):
|
||||
"""Raised if no profile with given name is found"""
|
||||
pass
|
||||
@ -202,17 +221,25 @@ class NoSuchProfileException(Exception):
|
||||
|
||||
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: {
|
||||
propname: propvalue_regex*
|
||||
}
|
||||
Predefined profiles are (use
|
||||
:meth:`~cssutils.profiles.Profiles.propertiesByProfile` to
|
||||
get a list of defined properties):
|
||||
|
||||
Predefined profiles are:
|
||||
|
||||
- 'CSS level 2': Properties defined by CSS2
|
||||
:attr:`~cssutils.profiles.Profiles.Profiles.CSS_LEVEL_2`
|
||||
Properties defined by CSS2.1
|
||||
: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 = {
|
||||
'ident': r'[-]?{nmstart}{nmchar}*',
|
||||
'name': r'{nmchar}+',
|
||||
@ -247,22 +274,24 @@ class Profiles(object):
|
||||
'percentage': r'{num}%',
|
||||
}
|
||||
|
||||
CSS_LEVEL_2 = 'CSS Level 2.1'
|
||||
CSS_COLOR_LEVEL_3 = 'CSS Color Module Level 3'
|
||||
|
||||
def __init__(self):
|
||||
"""A few known profiles are predefined."""
|
||||
self._log = cssutils.log
|
||||
self._profilenames = [] # to keep order, REFACTOR!
|
||||
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):
|
||||
"""Expand macros in token dictionary"""
|
||||
def macro_value(m):
|
||||
return '(?:%s)' % macros[m.groupdict()['macro']]
|
||||
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):
|
||||
value = re.sub(r'{(?P<macro>[a-z][a-z0-9-]*)}',
|
||||
macro_value, value)
|
||||
@ -272,23 +301,31 @@ class Profiles(object):
|
||||
def _compile_regexes(self, dictionary):
|
||||
"""Compile all regular expressions into callable objects"""
|
||||
for key, value in dictionary.items():
|
||||
if not callable(value):
|
||||
if not hasattr(value, '__call__'):
|
||||
value = re.compile('^(?:%s)$' % value, re.I).match
|
||||
dictionary[key] = value
|
||||
|
||||
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()),
|
||||
doc=u'Names of all profiles.')
|
||||
|
||||
def addProfile(self, profile, properties, macros=None):
|
||||
"""Add a new profile with name ``profile`` (e.g. 'CSS level 2')
|
||||
and the given ``properties``. ``macros`` are
|
||||
knownnames = property(lambda self: self._knownnames,
|
||||
doc="All known property names of all profiles.")
|
||||
|
||||
``profile``
|
||||
The new profile's name
|
||||
``properties``
|
||||
A dictionary of ``{ property-name: propery-value }`` items where
|
||||
def addProfile(self, profile, properties, macros=None):
|
||||
"""Add a new profile with name `profile` (e.g. 'CSS level 2')
|
||||
and the given `properties`.
|
||||
|
||||
: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
|
||||
``macros`` or the standard macros Profiles.tokens and
|
||||
Profiles.generalvalues.
|
||||
@ -300,6 +337,10 @@ class Profiles(object):
|
||||
are reported or raised as all other cssutils exceptions depending
|
||||
on cssutils.log.raiseExceptions which e.g during parsing normally
|
||||
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:
|
||||
macros = {}
|
||||
@ -310,14 +351,40 @@ class Profiles(object):
|
||||
self._profilenames.append(profile)
|
||||
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):
|
||||
"""Generator: Yield property names, if no profile(s) is given all
|
||||
profile's properties are used."""
|
||||
"""Generator: Yield property names, if no `profiles` is given all
|
||||
profile's properties are used.
|
||||
|
||||
:param profiles:
|
||||
a single profile name or a list of names.
|
||||
"""
|
||||
if not profiles:
|
||||
profiles = self.profiles
|
||||
elif isinstance(profiles, basestring):
|
||||
profiles = (profiles, )
|
||||
|
||||
try:
|
||||
for profile in sorted(profiles):
|
||||
for name in sorted(self._profiles[profile].keys()):
|
||||
@ -326,12 +393,22 @@ class Profiles(object):
|
||||
raise NoSuchProfileException(e)
|
||||
|
||||
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:
|
||||
if name in self._profiles[profile]:
|
||||
try:
|
||||
# custom validation errors are caught
|
||||
r = bool(self._profiles[profile][name](value))
|
||||
r = bool(self._profiles[profile][name](value))
|
||||
except Exception, e:
|
||||
self._log.error(e, error=Exception)
|
||||
return False
|
||||
@ -339,29 +416,63 @@ class Profiles(object):
|
||||
return r
|
||||
return False
|
||||
|
||||
def validateWithProfile(self, name, value):
|
||||
"""Check if value is valid for given property name returning
|
||||
(valid, valid_in_profile).
|
||||
def validateWithProfile(self, name, value, profiles=None):
|
||||
"""Check if `value` is valid for given property `name` returning
|
||||
``(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
|
||||
e.g. ``validateWithProfile('color', 'rgba(1,1,1,1)')`` returns
|
||||
(True, Profiles.CSS_COLOR_LEVEL_3)
|
||||
"""
|
||||
for profilename in self._profilenames:
|
||||
if name in self._profiles[profilename]:
|
||||
try:
|
||||
# custom validation errors are caught
|
||||
r = (bool(self._profiles[profilename][name](value)),
|
||||
profilename)
|
||||
except Exception, e:
|
||||
self._log.error(e, error=Exception)
|
||||
r = False, None
|
||||
if r[0]:
|
||||
return r
|
||||
return False, None
|
||||
if name not in self.knownnames:
|
||||
return False, []
|
||||
else:
|
||||
if not profiles:
|
||||
profiles = self._profilenames
|
||||
elif isinstance(profiles, basestring):
|
||||
profiles = (profiles, )
|
||||
|
||||
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()
|
||||
|
||||
# set for validation to e.g.``Profiles.CSS_LEVEL_2``
|
||||
defaultprofile = None
|
||||
|
||||
|
@ -4,16 +4,16 @@ __all__ = ['CSSCapture', 'csscombine']
|
||||
__docformat__ = 'restructuredtext'
|
||||
__version__ = '$Id: parse.py 1323 2008-07-06 18:13:57Z cthedot $'
|
||||
|
||||
import codecs
|
||||
import errno
|
||||
import HTMLParser
|
||||
import codecs
|
||||
import cssutils
|
||||
import errno
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import urllib2
|
||||
import urlparse
|
||||
|
||||
import cssutils
|
||||
try:
|
||||
import cssutils.encutils as encutils
|
||||
except ImportError:
|
||||
@ -307,65 +307,47 @@ class CSSCapture(object):
|
||||
sf.write(sheet.cssText)
|
||||
sf.close()
|
||||
|
||||
|
||||
def csscombine(proxypath, sourceencoding=None, targetencoding='utf-8',
|
||||
def csscombine(path=None, url=None,
|
||||
sourceencoding=None, targetencoding=None,
|
||||
minify=True):
|
||||
"""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
|
||||
:Parameters:
|
||||
`proxypath`
|
||||
url or path to a CSSStyleSheet which imports other sheets which
|
||||
`path` or `url`
|
||||
path or URL to a CSSStyleSheet which imports other sheets which
|
||||
are then combined into one sheet
|
||||
`sourceencoding`
|
||||
encoding of the source sheets including the proxy sheet
|
||||
`targetencoding`
|
||||
encoding of the combined stylesheet, default 'utf-8'
|
||||
`minify`
|
||||
defines if the combined sheet should be minified, default True
|
||||
"""
|
||||
log = cssutils.log
|
||||
|
||||
log.info('Combining files in proxy %r' % proxypath, neverraise=True)
|
||||
|
||||
cssutils.log.info(u'Combining files from %r' % url,
|
||||
neverraise=True)
|
||||
if sourceencoding is not None:
|
||||
log.info('Using source encoding %r' % sourceencoding,
|
||||
neverraise=True)
|
||||
cssutils.log.info(u'Using source encoding %r' % sourceencoding,
|
||||
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)
|
||||
srcpath = os.path.dirname(proxypath)
|
||||
combined = cssutils.css.CSSStyleSheet()
|
||||
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
|
||||
result = cssutils.resolveImports(src)
|
||||
result.encoding = targetencoding
|
||||
cssutils.log.info(u'Using target encoding: %r' % targetencoding, neverraise=True)
|
||||
|
||||
if minify:
|
||||
# save old setting and use own serializer
|
||||
oldser = cssutils.ser
|
||||
cssutils.setSerializer(cssutils.serialize.CSSSerializer())
|
||||
cssutils.ser.prefs.useMinified()
|
||||
cssText = combined.cssText
|
||||
cssText = result.cssText
|
||||
cssutils.setSerializer(oldser)
|
||||
else:
|
||||
cssText = combined.cssText
|
||||
cssText = result.cssText
|
||||
|
||||
return cssText
|
||||
|
||||
|
@ -1,15 +1,15 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""serializer classes for CSS classes
|
||||
|
||||
"""
|
||||
"""cssutils serializer"""
|
||||
__all__ = ['CSSSerializer', 'Preferences']
|
||||
__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 cssutils
|
||||
import helper
|
||||
import re
|
||||
import xml.dom
|
||||
import cssutils
|
||||
|
||||
def _escapecss(e):
|
||||
"""
|
||||
@ -26,8 +26,7 @@ codecs.register_error('escapecss', _escapecss)
|
||||
|
||||
|
||||
class Preferences(object):
|
||||
"""
|
||||
controls output of CSSSerializer
|
||||
"""Control output of CSSSerializer.
|
||||
|
||||
defaultAtKeyword = True
|
||||
Should the literal @keyword from src CSS be used or the default
|
||||
@ -39,11 +38,12 @@ class Preferences(object):
|
||||
Only used if ``keepAllProperties==False``.
|
||||
|
||||
defaultPropertyPriority = True
|
||||
Should the normalized or literal priority be used, e.g. '!important'
|
||||
or u'!Im\portant'
|
||||
Should the normalized or literal priority be used, e.g. ``!important``
|
||||
or ``!Im\portant``
|
||||
|
||||
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 * ' '
|
||||
Indentation of e.g Properties inside a CSSStyleDeclaration
|
||||
indentSpecificities = False
|
||||
@ -88,20 +88,27 @@ class Preferences(object):
|
||||
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
|
||||
valid.
|
||||
|
||||
"""
|
||||
def __init__(self, **initials):
|
||||
"""
|
||||
Always use named instead of positional parameters
|
||||
"""
|
||||
"""Always use named instead of positional parameters."""
|
||||
self.useDefaults()
|
||||
|
||||
for key, value in initials.items():
|
||||
if 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):
|
||||
"reset all preference options to the default value"
|
||||
"Reset all preference options to their default value."
|
||||
self.defaultAtKeyword = True
|
||||
self.defaultPropertyName = True
|
||||
self.defaultPropertyPriority = True
|
||||
@ -123,11 +130,10 @@ class Preferences(object):
|
||||
self.validOnly = False # should not be changed currently!!!
|
||||
|
||||
def useMinified(self):
|
||||
"""
|
||||
sets options to achive a minified stylesheet
|
||||
"""Set options resulting in a minified stylesheet.
|
||||
|
||||
you may want to set preferences with this convenience method
|
||||
and set settings you want adjusted afterwards
|
||||
You may want to set preferences with this convenience method
|
||||
and set settings you want adjusted afterwards.
|
||||
"""
|
||||
self.importHrefFormat = 'string'
|
||||
self.indent = u''
|
||||
@ -144,22 +150,9 @@ class Preferences(object):
|
||||
self.spacer = u''
|
||||
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):
|
||||
"""
|
||||
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):
|
||||
self.ser = ser
|
||||
self.out = []
|
||||
@ -178,11 +171,11 @@ class Out(object):
|
||||
- typ "Property", cssutils.css.CSSRule.UNKNOWN_RULE
|
||||
uses cssText
|
||||
- typ STRING
|
||||
escapes ser._string
|
||||
escapes helper.string
|
||||
- typ S
|
||||
ignored except ``keepS=True``
|
||||
- typ URI
|
||||
calls ser_uri
|
||||
calls helper.uri
|
||||
- val ``{``
|
||||
adds LF after
|
||||
- val ``;``
|
||||
@ -194,6 +187,8 @@ class Out(object):
|
||||
- some other vals
|
||||
add ``*spacer`` except ``space=False``
|
||||
"""
|
||||
prefspace = self.ser.prefs.spacer
|
||||
|
||||
if val or typ in ('STRING', 'URI'):
|
||||
# PRE
|
||||
if 'COMMENT' == typ:
|
||||
@ -207,6 +202,8 @@ class Out(object):
|
||||
# val = val.cssText
|
||||
elif 'S' == typ and not keepS:
|
||||
return
|
||||
elif 'S' == typ and keepS:
|
||||
val = u' '
|
||||
elif typ in ('NUMBER', 'DIMENSION', 'PERCENTAGE') and val == '0':
|
||||
# remove sign + or - if value is zero
|
||||
# TODO: only for lenghts!
|
||||
@ -216,9 +213,13 @@ class Out(object):
|
||||
# may be empty but MUST not be None
|
||||
if val is None:
|
||||
return
|
||||
val = self.ser._string(val)
|
||||
val = helper.string(val)
|
||||
if not prefspace:
|
||||
self._remove_last_if_S()
|
||||
elif 'URI' == typ:
|
||||
val = self.ser._uri(val)
|
||||
val = helper.uri(val)
|
||||
elif 'HASH' == typ:
|
||||
val = self.ser._hash(val)
|
||||
elif val in u'+>~,:{;)]/':
|
||||
self._remove_last_if_S()
|
||||
|
||||
@ -243,8 +244,11 @@ class Out(object):
|
||||
self.out.append(self.ser.prefs.lineSeparator)
|
||||
elif u';' == val: # end or prop or block
|
||||
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)
|
||||
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):
|
||||
"returns all items joined by delim"
|
||||
@ -256,19 +260,14 @@ class Out(object):
|
||||
|
||||
|
||||
class CSSSerializer(object):
|
||||
"""
|
||||
Methods to serialize a CSSStylesheet and its parts
|
||||
"""Serialize a CSSStylesheet and its parts.
|
||||
|
||||
To use your own serializing method the easiest is to subclass CSS
|
||||
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):
|
||||
"""
|
||||
prefs
|
||||
:param prefs:
|
||||
instance of Preferences
|
||||
"""
|
||||
if not prefs:
|
||||
@ -319,23 +318,17 @@ class CSSSerializer(object):
|
||||
text = self.prefs.lineSeparator.join(out)
|
||||
return text
|
||||
|
||||
def _string(self, s):
|
||||
def _hash(self, val, type_=None):
|
||||
"""
|
||||
returns s encloded between "..." and escaped delim charater ",
|
||||
escape line breaks \\n \\r and \\f
|
||||
Short form of hash, e.g. #123 instead of #112233
|
||||
"""
|
||||
# \n = 0xa, \r = 0xd, \f = 0xc
|
||||
s = s.replace('\n', '\\a ').replace(
|
||||
'\r', '\\d ').replace(
|
||||
'\f', '\\c ')
|
||||
return u'"%s"' % s.replace('"', u'\\"')
|
||||
|
||||
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)
|
||||
# TODO: add pref for this!
|
||||
if len(val) == 7 and val[1] == val[2] and\
|
||||
val[3] == val[4] and\
|
||||
val[5] == val[6]:
|
||||
return u'#%s%s%s' % (val[1], val[3], val[5])
|
||||
else:
|
||||
return 'url(%s)' % uri
|
||||
return val
|
||||
|
||||
def _valid(self, x):
|
||||
"checks items valid property and prefs.validOnly"
|
||||
@ -384,7 +377,7 @@ class CSSSerializer(object):
|
||||
no comments or other things allowed!
|
||||
"""
|
||||
if rule.wellformed:
|
||||
return u'@charset %s;' % self._string(rule.encoding)
|
||||
return u'@charset %s;' % helper.string(rule.encoding)
|
||||
else:
|
||||
return u''
|
||||
|
||||
@ -438,8 +431,6 @@ class CSSSerializer(object):
|
||||
rule.hreftype == 'string'):
|
||||
out.append(val, 'STRING')
|
||||
else:
|
||||
if not len(self.prefs.spacer):
|
||||
out.append(u' ')
|
||||
out.append(val, 'URI')
|
||||
elif 'media' == typ:
|
||||
# media
|
||||
@ -469,9 +460,6 @@ class CSSSerializer(object):
|
||||
if rule.wellformed:
|
||||
out = Out(self)
|
||||
out.append(self._atkeyword(rule, u'@namespace'))
|
||||
if not len(self.prefs.spacer):
|
||||
out.append(u' ')
|
||||
|
||||
for item in rule.seq:
|
||||
typ, val = item.type, item.value
|
||||
if 'namespaceURI' == typ:
|
||||
@ -509,7 +497,7 @@ class CSSSerializer(object):
|
||||
if rule.name:
|
||||
out.append(self.prefs.spacer)
|
||||
nameout = Out(self)
|
||||
nameout.append(self._string(rule.name))
|
||||
nameout.append(helper.string(rule.name))
|
||||
for item in rule.seq:
|
||||
nameout.append(item.value, item.type)
|
||||
out.append(nameout.value())
|
||||
@ -548,16 +536,10 @@ class CSSSerializer(object):
|
||||
+ CSSComments
|
||||
"""
|
||||
styleText = self.do_css_CSSStyleDeclaration(rule.style)
|
||||
|
||||
if styleText and rule.wellformed:
|
||||
out = Out(self)
|
||||
out.append(self._atkeyword(rule, u'@page'))
|
||||
if not len(self.prefs.spacer):
|
||||
out.append(u' ')
|
||||
|
||||
for item in rule.seq:
|
||||
out.append(item.value, item.type)
|
||||
|
||||
out.append(rule.selectorText)
|
||||
out.append(u'{')
|
||||
out.append(u'%s%s}' % (styleText, self.prefs.lineSeparator),
|
||||
indent=1)
|
||||
@ -565,6 +547,16 @@ class CSSSerializer(object):
|
||||
else:
|
||||
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):
|
||||
"""
|
||||
serializes CSSUnknownRule
|
||||
@ -574,8 +566,6 @@ class CSSSerializer(object):
|
||||
if rule.wellformed:
|
||||
out = Out(self)
|
||||
out.append(rule.atkeyword)
|
||||
if not len(self.prefs.spacer):
|
||||
out.append(u' ')
|
||||
|
||||
stacks = []
|
||||
for item in rule.seq:
|
||||
@ -751,7 +741,7 @@ class CSSSerializer(object):
|
||||
out.append(separator)
|
||||
elif isinstance(val, cssutils.css.Property):
|
||||
# PropertySimilarNameList
|
||||
out.append(self.do_Property(val))
|
||||
out.append(val.cssText)
|
||||
if not (self.prefs.omitLastSemicolon and i==len(seq)-1):
|
||||
out.append(u';')
|
||||
out.append(separator)
|
||||
@ -823,7 +813,6 @@ class CSSSerializer(object):
|
||||
a Properties priority "!" S* "important"
|
||||
"""
|
||||
# TODO: use Out()
|
||||
|
||||
out = []
|
||||
for part in priorityseq:
|
||||
if hasattr(part, 'cssText'): # comments
|
||||
@ -836,72 +825,47 @@ class CSSSerializer(object):
|
||||
|
||||
def do_css_CSSValue(self, cssvalue):
|
||||
"""Serializes a CSSValue"""
|
||||
# TODO: use self._valid(cssvalue)?
|
||||
if not cssvalue:
|
||||
return u''
|
||||
else:
|
||||
out = Out(self)
|
||||
for item in cssvalue.seq:
|
||||
type_, val = item.type, item.value
|
||||
if type_ in (cssutils.css.CSSColor,
|
||||
cssutils.css.CSSValue):
|
||||
# CSSColor or CSSValue if a CSSValueList
|
||||
out.append(val.cssText, type_, space=False, keepS=True)
|
||||
if hasattr(val, 'cssText'):
|
||||
# RGBColor or CSSValue if a CSSValueList
|
||||
out.append(val.cssText, type_)
|
||||
else:
|
||||
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
|
||||
out.append(val, type_, space=False, keepS=True)
|
||||
out.append(val, type_)
|
||||
|
||||
return out.value()
|
||||
|
||||
def do_css_CSSPrimitiveValue(self, cssvalue):
|
||||
"""Serialize a CSSPrimitiveValue"""
|
||||
# TODO: use self._valid(cssvalue)?
|
||||
if not cssvalue:
|
||||
return u''
|
||||
else:
|
||||
out = Out(self)
|
||||
|
||||
unary = None
|
||||
for item in cssvalue.seq:
|
||||
type_, val = item.type, item.value
|
||||
if 'CHAR' == type_ and val in u'+-':
|
||||
# save for next round
|
||||
unary = val
|
||||
continue
|
||||
if cssutils.css.CSSColor == type_:
|
||||
# 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():
|
||||
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:
|
||||
# add unary to val if not 0
|
||||
# TODO: only for lengths!
|
||||
if u'-' == unary:
|
||||
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
|
||||
|
||||
val = u'0' + d
|
||||
else:
|
||||
val = unicode(n) + d
|
||||
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()
|
||||
|
||||
def do_css_CSSColor(self, cssvalue):
|
||||
"""Serialize a CSSColor value"""
|
||||
def do_css_RGBColor(self, cssvalue):
|
||||
"""Serialize a RGBColor value"""
|
||||
if not cssvalue:
|
||||
return u''
|
||||
else:
|
||||
@ -910,21 +874,16 @@ class CSSSerializer(object):
|
||||
for item in cssvalue.seq:
|
||||
type_, val = item.type, item.value
|
||||
|
||||
# prepare
|
||||
if 'HASH' == type_:
|
||||
# TODO: add pref for this!
|
||||
if len(val) == 7 and val[1] == val[2] and \
|
||||
val[3] == val[4] and val[5] == val[6]:
|
||||
val = u'#%s%s%s' % (val[1], val[3], val[5])
|
||||
elif 'CHAR' == type_ and val in u'+-':
|
||||
# save - for next round
|
||||
if u'-' == val:
|
||||
# omit +
|
||||
unary = val
|
||||
continue
|
||||
elif unary:
|
||||
val = unary + val.cssText
|
||||
unary = None
|
||||
# # prepare
|
||||
# if 'CHAR' == type_ and val in u'+-':
|
||||
# # save - for next round
|
||||
# if u'-' == val:
|
||||
# # omit +
|
||||
# unary = val
|
||||
# continue
|
||||
# elif unary:
|
||||
# val = unary + val.cssText
|
||||
# unary = None
|
||||
|
||||
out.append(val, type_)
|
||||
|
||||
@ -960,3 +919,29 @@ class CSSSerializer(object):
|
||||
return u' '.join(out)
|
||||
else:
|
||||
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 @@
|
||||
"""
|
||||
Document Object Model Level 2 Style Sheets
|
||||
"""Implements Document Object Model Level 2 Style Sheets
|
||||
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']
|
||||
__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 mediaquery import *
|
||||
|
@ -1,5 +1,4 @@
|
||||
"""
|
||||
MediaList implements DOM Level 2 Style Sheets MediaList.
|
||||
"""MediaList implements DOM Level 2 Style Sheets MediaList.
|
||||
|
||||
TODO:
|
||||
- delete: maybe if deleting from all, replace *all* with all others?
|
||||
@ -7,49 +6,36 @@ TODO:
|
||||
"""
|
||||
__all__ = ['MediaList']
|
||||
__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 mediaquery import MediaQuery
|
||||
import cssutils
|
||||
import xml.dom
|
||||
|
||||
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
|
||||
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".
|
||||
|
||||
Properties
|
||||
==========
|
||||
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
|
||||
======
|
||||
::
|
||||
Format from CSS2.1::
|
||||
|
||||
medium [ COMMA S* medium ]*
|
||||
|
||||
New::
|
||||
New format with :class:`MediaQuery`::
|
||||
|
||||
<media_query> [, <media_query> ]*
|
||||
"""
|
||||
def __init__(self, mediaText=None, readonly=False):
|
||||
"""
|
||||
mediaText
|
||||
unicodestring of parsable comma separared media
|
||||
or a list of media
|
||||
:param mediaText:
|
||||
Unicodestring of parsable comma separared media
|
||||
or a (Python) list of media.
|
||||
:param readonly:
|
||||
Not used yet.
|
||||
"""
|
||||
super(MediaList, self).__init__()
|
||||
self._wellformed = False
|
||||
@ -62,27 +48,31 @@ class MediaList(cssutils.util.Base, cssutils.util.ListSeq):
|
||||
|
||||
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),
|
||||
doc="(DOM readonly) The number of media in the list.")
|
||||
doc="The number of media in the list (DOM readonly).")
|
||||
|
||||
def _getMediaText(self):
|
||||
"""
|
||||
returns serialized property mediaText
|
||||
"""
|
||||
return cssutils.ser.do_stylesheets_medialist(self)
|
||||
|
||||
def _setMediaText(self, mediaText):
|
||||
"""
|
||||
mediaText
|
||||
:param mediaText:
|
||||
simple value or comma-separated list of media
|
||||
|
||||
DOMException
|
||||
|
||||
- SYNTAX_ERR: (MediaQuery)
|
||||
Raised if the specified string value has a syntax error and is
|
||||
unparsable.
|
||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
||||
Raised if this media list is readonly.
|
||||
:exceptions:
|
||||
- - :exc:`~xml.dom.SyntaxErr`:
|
||||
Raised if the specified string value has a syntax error and is
|
||||
unparsable.
|
||||
- - :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
Raised if this media list is readonly.
|
||||
"""
|
||||
self._checkReadonly()
|
||||
wellformed = True
|
||||
@ -121,10 +111,7 @@ class MediaList(cssutils.util.Base, cssutils.util.ListSeq):
|
||||
self._wellformed = True
|
||||
|
||||
mediaText = property(_getMediaText, _setMediaText,
|
||||
doc="""(DOM) The parsable textual representation of the media list.
|
||||
This is a comma-separated list of media.""")
|
||||
|
||||
wellformed = property(lambda self: self._wellformed)
|
||||
doc="The parsable textual representation of the media list.")
|
||||
|
||||
def __prepareset(self, newMedium):
|
||||
# used by appendSelector and __setitem__
|
||||
@ -137,10 +124,9 @@ class MediaList(cssutils.util.Base, cssutils.util.ListSeq):
|
||||
return newMedium
|
||||
|
||||
def __setitem__(self, index, newMedium):
|
||||
"""
|
||||
overwrites ListSeq.__setitem__
|
||||
"""Overwriting ListSeq.__setitem__
|
||||
|
||||
Any duplicate items are **not** removed.
|
||||
Any duplicate items are **not yet** removed.
|
||||
"""
|
||||
newMedium = self.__prepareset(newMedium)
|
||||
if newMedium:
|
||||
@ -148,28 +134,23 @@ class MediaList(cssutils.util.Base, cssutils.util.ListSeq):
|
||||
# TODO: remove duplicates?
|
||||
|
||||
def appendMedium(self, newMedium):
|
||||
"""
|
||||
(DOM)
|
||||
Adds the medium newMedium to the end of the list. If the newMedium
|
||||
is already used, it is first removed.
|
||||
"""Add the `newMedium` to the end of the list.
|
||||
If the `newMedium` is already used, it is first removed.
|
||||
|
||||
newMedium
|
||||
a string or a MediaQuery object
|
||||
|
||||
returns if newMedium is wellformed
|
||||
|
||||
DOMException
|
||||
|
||||
- INVALID_CHARACTER_ERR: (self)
|
||||
If the medium contains characters that are invalid in the
|
||||
underlying style language.
|
||||
- INVALID_MODIFICATION_ERR (self)
|
||||
If mediaText is "all" and a new medium is tried to be added.
|
||||
Exception is "handheld" which is set in any case (Opera does handle
|
||||
"all, handheld" special, this special case might be removed in the
|
||||
future).
|
||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
||||
Raised if this list is readonly.
|
||||
:param newMedium:
|
||||
a string or a :class:`~cssutils.stylesheets.MediaQuery`
|
||||
:returns: Wellformedness of `newMedium`.
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.InvalidCharacterErr`:
|
||||
If the medium contains characters that are invalid in the
|
||||
underlying style language.
|
||||
- :exc:`~xml.dom.InvalidModificationErr`:
|
||||
If mediaText is "all" and a new medium is tried to be added.
|
||||
Exception is "handheld" which is set in any case (Opera does handle
|
||||
"all, handheld" special, this special case might be removed in the
|
||||
future).
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
Raised if this list is readonly.
|
||||
"""
|
||||
newMedium = self.__prepareset(newMedium)
|
||||
|
||||
@ -207,20 +188,19 @@ class MediaList(cssutils.util.Base, cssutils.util.ListSeq):
|
||||
return False
|
||||
|
||||
def append(self, newMedium):
|
||||
"overwrites ListSeq.append"
|
||||
"Same as :meth:`appendMedium`."
|
||||
self.appendMedium(newMedium)
|
||||
|
||||
def deleteMedium(self, oldMedium):
|
||||
"""
|
||||
(DOM)
|
||||
Deletes the medium indicated by oldMedium from the list.
|
||||
"""Delete a medium from the list.
|
||||
|
||||
DOMException
|
||||
|
||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
||||
Raised if this list is readonly.
|
||||
- NOT_FOUND_ERR: (self)
|
||||
Raised if oldMedium is not in the list.
|
||||
:param oldMedium:
|
||||
delete this medium from the list.
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.NotFoundErr`:
|
||||
Raised if `oldMedium` is not in the list.
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
Raised if this list is readonly.
|
||||
"""
|
||||
self._checkReadonly()
|
||||
oldMedium = self._normalize(oldMedium)
|
||||
@ -232,25 +212,15 @@ class MediaList(cssutils.util.Base, cssutils.util.ListSeq):
|
||||
else:
|
||||
self._log.error(u'"%s" not in this MediaList' % oldMedium,
|
||||
error=xml.dom.NotFoundErr)
|
||||
# raise xml.dom.NotFoundErr(
|
||||
# u'"%s" not in this MediaList' % oldMedium)
|
||||
|
||||
def item(self, index):
|
||||
"""
|
||||
(DOM)
|
||||
Returns the mediaType of the index'th element in the list.
|
||||
If index is greater than or equal to the number of media in the
|
||||
list, returns None.
|
||||
"""Return the mediaType of the `index`'th element in the list.
|
||||
If `index` is greater than or equal to the number of media in the
|
||||
list, returns ``None``.
|
||||
"""
|
||||
try:
|
||||
return self[index].mediaType
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
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))
|
||||
wellformed = property(lambda self: self._wellformed)
|
||||
|
@ -1,41 +1,22 @@
|
||||
"""
|
||||
MediaQuery, see http://www.w3.org/TR/css3-mediaqueries/
|
||||
"""Implements a DOM for MediaQuery, see
|
||||
http://www.w3.org/TR/css3-mediaqueries/.
|
||||
|
||||
A cssutils own implementation, not defined in official DOM
|
||||
|
||||
TODO:
|
||||
add possibility to
|
||||
|
||||
part of a media_query_list: <media_query> [, <media_query> ]*
|
||||
see stylesheets.MediaList
|
||||
A cssutils implementation, not defined in official DOM.
|
||||
"""
|
||||
__all__ = ['MediaQuery']
|
||||
__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 xml.dom
|
||||
import cssutils
|
||||
|
||||
class MediaQuery(cssutils.util.Base):
|
||||
"""
|
||||
A Media Query consists of a media type and one or more
|
||||
expressions involving media features.
|
||||
A Media Query consists of one of :const:`MediaQuery.MEDIA_TYPES`
|
||||
and one or more expressions involving media features.
|
||||
|
||||
Properties
|
||||
==========
|
||||
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
|
||||
======
|
||||
::
|
||||
Format::
|
||||
|
||||
media_query: [[only | not]? <media_type> [ and <expression> ]*]
|
||||
| <expression> [ and <expression> ]*
|
||||
@ -65,7 +46,7 @@ class MediaQuery(cssutils.util.Base):
|
||||
|
||||
def __init__(self, mediaText=None, readonly=False):
|
||||
"""
|
||||
mediaText
|
||||
:param mediaText:
|
||||
unicodestring of parsable media
|
||||
"""
|
||||
super(MediaQuery, self).__init__()
|
||||
@ -77,26 +58,30 @@ class MediaQuery(cssutils.util.Base):
|
||||
|
||||
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):
|
||||
"""
|
||||
returns serialized property mediaText
|
||||
"""
|
||||
return cssutils.ser.do_stylesheets_mediaquery(self)
|
||||
|
||||
def _setMediaText(self, mediaText):
|
||||
"""
|
||||
mediaText
|
||||
a single media query string, e.g. "print and (min-width: 25cm)"
|
||||
:param mediaText:
|
||||
a single media query string, e.g. ``print and (min-width: 25cm)``
|
||||
|
||||
DOMException
|
||||
|
||||
- SYNTAX_ERR: (self)
|
||||
Raised if the specified string value has a syntax error and is
|
||||
unparsable.
|
||||
- INVALID_CHARACTER_ERR: (self)
|
||||
Raised if the given mediaType is unknown.
|
||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
||||
Raised if this media query is readonly.
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.SyntaxErr`:
|
||||
Raised if the specified string value has a syntax error and is
|
||||
unparsable.
|
||||
- :exc:`~xml.dom.InvalidCharacterErr`:
|
||||
Raised if the given mediaType is unknown.
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
Raised if this media query is readonly.
|
||||
"""
|
||||
self._checkReadonly()
|
||||
tokenizer = self._tokenize2(mediaText)
|
||||
@ -171,29 +156,21 @@ class MediaQuery(cssutils.util.Base):
|
||||
self.seq = newseq
|
||||
|
||||
mediaText = property(_getMediaText, _setMediaText,
|
||||
doc="""(DOM) 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
|
||||
doc="The parsable textual representation of the media list.")
|
||||
|
||||
def _setMediaType(self, mediaType):
|
||||
"""
|
||||
mediaType
|
||||
one of MEDIA_TYPES
|
||||
:param mediaType:
|
||||
one of :attr:`MEDIA_TYPES`
|
||||
|
||||
DOMException
|
||||
|
||||
- SYNTAX_ERR: (self)
|
||||
Raised if the specified string value has a syntax error and is
|
||||
unparsable.
|
||||
- INVALID_CHARACTER_ERR: (self)
|
||||
Raised if the given mediaType is unknown.
|
||||
- NO_MODIFICATION_ALLOWED_ERR: (self)
|
||||
Raised if this media query is readonly.
|
||||
:exceptions:
|
||||
- :exc:`~xml.dom.SyntaxErr`:
|
||||
Raised if the specified string value has a syntax error and is
|
||||
unparsable.
|
||||
- :exc:`~xml.dom.InvalidCharacterErr`:
|
||||
Raised if the given mediaType is unknown.
|
||||
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
||||
Raised if this media query is readonly.
|
||||
"""
|
||||
self._checkReadonly()
|
||||
nmediaType = self._normalize(mediaType)
|
||||
@ -223,15 +200,8 @@ class MediaQuery(cssutils.util.Base):
|
||||
else:
|
||||
self.seq.insert(0, mediaType)
|
||||
|
||||
mediaType = property(_getMediaType, _setMediaType,
|
||||
doc="""(DOM) media type (one of MediaQuery.MEDIA_TYPES) of this MediaQuery.""")
|
||||
mediaType = property(lambda self: self._mediaType, _setMediaType,
|
||||
doc="The media type of this MediaQuery (one of "
|
||||
":attr:`MEDIA_TYPES`).")
|
||||
|
||||
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']
|
||||
__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 urlparse
|
||||
|
||||
class StyleSheet(cssutils.util.Base2):
|
||||
"""
|
||||
@ -16,7 +14,7 @@ class StyleSheet(cssutils.util.Base2):
|
||||
|
||||
In HTML, the StyleSheet interface represents either an
|
||||
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
|
||||
an external style sheet, included via a style sheet
|
||||
@ -30,14 +28,8 @@ class StyleSheet(cssutils.util.Base2):
|
||||
ownerNode=None,
|
||||
parentStyleSheet=None):
|
||||
"""
|
||||
type: readonly
|
||||
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.
|
||||
type
|
||||
readonly
|
||||
href: readonly
|
||||
If the style sheet is a linked style sheet, the value
|
||||
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
|
||||
attribute is None.
|
||||
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__()
|
||||
|
||||
@ -92,10 +78,31 @@ class StyleSheet(cssutils.util.Base2):
|
||||
self.media = media
|
||||
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']
|
||||
__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):
|
||||
"""
|
||||
Interface StyleSheetList (introduced in DOM Level 2)
|
||||
"""Interface `StyleSheetList` (introduced in DOM Level 2)
|
||||
|
||||
The StyleSheetList interface provides the abstraction of an ordered
|
||||
collection of style sheets.
|
||||
The `StyleSheetList` interface provides the abstraction of an ordered
|
||||
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.
|
||||
|
||||
This Python implementation is based on a standard Python list so e.g.
|
||||
@ -20,9 +17,9 @@ class StyleSheetList(list):
|
||||
"""
|
||||
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,
|
||||
this returns None.
|
||||
this returns ``None``.
|
||||
"""
|
||||
try:
|
||||
return self[index]
|
||||
@ -30,6 +27,6 @@ class StyleSheetList(list):
|
||||
return None
|
||||
|
||||
length = property(lambda self: len(self),
|
||||
doc="""The number of StyleSheets in the list. The range of valid
|
||||
child stylesheet indices is 0 to length-1 inclusive.""")
|
||||
doc="The number of :class:`StyleSheet` objects in the list. The range"
|
||||
" of valid child stylesheet indices is 0 to length-1 inclusive.")
|
||||
|
||||
|
@ -4,11 +4,11 @@
|
||||
"""
|
||||
__all__ = ['Tokenizer', 'CSSProductions']
|
||||
__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 helper import normalize
|
||||
import re
|
||||
|
||||
class Tokenizer(object):
|
||||
"""
|
||||
@ -23,6 +23,8 @@ class Tokenizer(object):
|
||||
u'@page': CSSProductions.PAGE_SYM
|
||||
}
|
||||
_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):
|
||||
"""
|
||||
@ -38,7 +40,6 @@ class Tokenizer(object):
|
||||
productions))
|
||||
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.unicodesub = re.compile(r'\\[0-9a-fA-F]{1,6}(?:\r\n|[\t|\r|\n|\f|\x20])?').sub
|
||||
|
||||
def _expand_macros(self, macros, productions):
|
||||
"""returns macro expanded productions, order of productions is kept"""
|
||||
@ -150,6 +151,9 @@ class Tokenizer(object):
|
||||
# may contain unicode escape, replace with normal char
|
||||
# but do not _normalize (?)
|
||||
value = self.unicodesub(_repl, found)
|
||||
if name in ('STRING', 'INVALID'): #'URI'?
|
||||
# remove \ followed by nl (so escaped) from string
|
||||
value = self.cleanstring('', found)
|
||||
|
||||
else:
|
||||
if 'ATKEYWORD' == name:
|
||||
|
@ -2,25 +2,85 @@
|
||||
"""
|
||||
__all__ = []
|
||||
__docformat__ = 'restructuredtext'
|
||||
__version__ = '$Id: util.py 1453 2008-09-08 20:57:19Z cthedot $'
|
||||
|
||||
import codecs
|
||||
from itertools import ifilter
|
||||
import types
|
||||
import urllib2
|
||||
import xml.dom
|
||||
__version__ = '$Id: util.py 1654 2009-02-03 20:16:20Z cthedot $'
|
||||
|
||||
from helper import normalize
|
||||
from itertools import ifilter
|
||||
import css
|
||||
import codec
|
||||
import codecs
|
||||
import errorhandler
|
||||
import tokenize2
|
||||
import cssutils
|
||||
import encutils
|
||||
import types
|
||||
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.**
|
||||
See cssutils.util.Base2
|
||||
|
||||
Base class for most CSS and StyleSheets classes
|
||||
|
||||
Contains helper methods for inheriting classes helping parsing
|
||||
|
||||
@ -28,9 +88,6 @@ class Base(object):
|
||||
"""
|
||||
__tokenizer2 = tokenize2.Tokenizer()
|
||||
|
||||
_log = cssutils.log
|
||||
_prods = tokenize2.CSSProductions
|
||||
|
||||
# for more on shorthand properties see
|
||||
# http://www.dustindiaz.com/css-shorthand/
|
||||
# format: shorthand: [(propname, mandatorycheck?)*]
|
||||
@ -66,14 +123,6 @@ class Base(object):
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
returns tuple (text, dict-of-namespaces) or if no namespaces are
|
||||
@ -141,7 +190,7 @@ class Base(object):
|
||||
"""
|
||||
if token:
|
||||
value = token[1]
|
||||
return value.replace('\\'+value[0], value[0])[1:-1]
|
||||
return value.replace('\\' + value[0], value[0])[1: - 1]
|
||||
else:
|
||||
return None
|
||||
|
||||
@ -153,10 +202,10 @@ class Base(object):
|
||||
url("\"") => "
|
||||
"""
|
||||
if token:
|
||||
value = token[1][4:-1].strip()
|
||||
if value and (value[0] in '\'"') and (value[0] == value[-1]):
|
||||
value = token[1][4: - 1].strip()
|
||||
if value and (value[0] in '\'"') and (value[0] == value[ - 1]):
|
||||
# a string "..." or '...'
|
||||
value = value.replace('\\'+value[0], value[0])[1:-1]
|
||||
value = value.replace('\\' + value[0], value[0])[1: - 1]
|
||||
return value
|
||||
else:
|
||||
return None
|
||||
@ -190,7 +239,7 @@ class Base(object):
|
||||
|
||||
if blockstartonly: # {
|
||||
ends = u'{'
|
||||
brace = -1 # set to 0 with first {
|
||||
brace = - 1 # set to 0 with first {
|
||||
elif blockendonly: # }
|
||||
ends = u'}'
|
||||
brace = 1
|
||||
@ -205,7 +254,7 @@ class Base(object):
|
||||
# end of mediaquery which may be { or STRING
|
||||
# special case, see below
|
||||
ends = u'{'
|
||||
brace = -1 # set to 0 with first {
|
||||
brace = - 1 # set to 0 with first {
|
||||
endtypes = ('STRING',)
|
||||
elif semicolon:
|
||||
ends = u';'
|
||||
@ -254,7 +303,7 @@ class Base(object):
|
||||
if (brace == bracket == parant == 0) and (
|
||||
val in ends or typ in endtypes):
|
||||
break
|
||||
elif mediaqueryendonly and brace == -1 and (
|
||||
elif mediaqueryendonly and brace == - 1 and (
|
||||
bracket == parant == 0) and typ in endtypes:
|
||||
# mediaqueryendonly with STRING
|
||||
break
|
||||
@ -262,25 +311,12 @@ class Base(object):
|
||||
if separateEnd:
|
||||
# TODO: use this method as generator, then this makes sense
|
||||
if resulttokens:
|
||||
return resulttokens[:-1], resulttokens[-1]
|
||||
return resulttokens[: - 1], resulttokens[ - 1]
|
||||
else:
|
||||
return resulttokens, None
|
||||
else:
|
||||
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):
|
||||
"""
|
||||
adds default productions if not already present, used by
|
||||
@ -295,7 +331,7 @@ class Base(object):
|
||||
"default impl for unexpected @rule"
|
||||
if expected != 'EOF':
|
||||
# TODO: parentStyleSheet=self
|
||||
rule = cssutils.css.CSSUnknownRule()
|
||||
rule = css.CSSUnknownRule()
|
||||
rule.cssText = self._tokensupto2(tokenizer, token)
|
||||
if rule.wellformed:
|
||||
seq.append(rule)
|
||||
@ -307,7 +343,7 @@ class Base(object):
|
||||
|
||||
def COMMENT(expected, seq, token, tokenizer=None):
|
||||
"default implementation for COMMENT token adds CSSCommentRule"
|
||||
seq.append(cssutils.css.CSSComment([token]))
|
||||
seq.append(css.CSSComment([token]))
|
||||
return expected
|
||||
|
||||
def S(expected, seq, token, tokenizer=None):
|
||||
@ -375,26 +411,15 @@ class Base(object):
|
||||
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):
|
||||
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):
|
||||
"""
|
||||
adds default productions if not already present, used by
|
||||
@ -409,10 +434,10 @@ class Base2(Base):
|
||||
"default impl for unexpected @rule"
|
||||
if expected != 'EOF':
|
||||
# TODO: parentStyleSheet=self
|
||||
rule = cssutils.css.CSSUnknownRule()
|
||||
rule = css.CSSUnknownRule()
|
||||
rule.cssText = self._tokensupto2(tokenizer, token)
|
||||
if rule.wellformed:
|
||||
seq.append(rule, cssutils.css.CSSRule.UNKNOWN_RULE,
|
||||
seq.append(rule, css.CSSRule.UNKNOWN_RULE,
|
||||
line=token[2], col=token[3])
|
||||
return expected
|
||||
else:
|
||||
@ -425,7 +450,7 @@ class Base2(Base):
|
||||
if expected == 'EOF':
|
||||
new['wellformed'] = False
|
||||
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
|
||||
|
||||
def S(expected, seq, token, tokenizer=None):
|
||||
@ -493,7 +518,7 @@ class Seq(object):
|
||||
else:
|
||||
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
|
||||
simply replace value or type
|
||||
@ -503,7 +528,13 @@ class Seq(object):
|
||||
else:
|
||||
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
|
||||
"""
|
||||
@ -516,10 +547,11 @@ class Seq(object):
|
||||
|
||||
def __repr__(self):
|
||||
"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__,
|
||||
u',\n '.join([u'%r' % item for item in self._seq]
|
||||
))
|
||||
), self._readonly)
|
||||
|
||||
def __str__(self):
|
||||
vals = []
|
||||
for v in self:
|
||||
@ -530,9 +562,9 @@ class Seq(object):
|
||||
else:
|
||||
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),
|
||||
u''.join(vals), id(self))
|
||||
u''.join(vals), self._readonly, id(self))
|
||||
|
||||
class Item(object):
|
||||
"""
|
||||
@ -671,7 +703,7 @@ class _Namespaces(object):
|
||||
prefix = u'' # None or ''
|
||||
rule = self.__findrule(prefix)
|
||||
if not rule:
|
||||
self.parentStyleSheet.insertRule(cssutils.css.CSSNamespaceRule(
|
||||
self.parentStyleSheet.insertRule(css.CSSNamespaceRule(
|
||||
prefix=prefix,
|
||||
namespaceURI=namespaceURI),
|
||||
inOrder=True)
|
||||
@ -688,7 +720,12 @@ class _Namespaces(object):
|
||||
if rule.prefix == prefix:
|
||||
return rule
|
||||
|
||||
def __getNamespaces(self):
|
||||
@property
|
||||
def namespaces(self):
|
||||
"""
|
||||
A property holding only effective @namespace rules in
|
||||
self.parentStyleSheets.
|
||||
"""
|
||||
namespaces = {}
|
||||
for rule in ifilter(lambda r: r.type == r.NAMESPACE_RULE,
|
||||
reversed(self.parentStyleSheet.cssRules)):
|
||||
@ -696,10 +733,6 @@ class _Namespaces(object):
|
||||
namespaces[rule.prefix] = rule.namespaceURI
|
||||
return namespaces
|
||||
|
||||
namespaces = property(__getNamespaces,
|
||||
doc=u'Holds only effective @namespace rules in self.parentStyleSheets'
|
||||
'@namespace rules.')
|
||||
|
||||
def get(self, prefix, default):
|
||||
return self.namespaces.get(prefix, default)
|
||||
|
||||
@ -751,35 +784,6 @@ class _SimpleNamespaces(_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):
|
||||
"""
|
||||
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
|
||||
encoding = httpEncoding
|
||||
else:
|
||||
# check content
|
||||
contentEncoding, explicit = cssutils.codec.detectencoding_str(content)
|
||||
if isinstance(content, unicode):
|
||||
# no need to check content as unicode so no BOM
|
||||
explicit = False
|
||||
else:
|
||||
# check content
|
||||
contentEncoding, explicit = codec.detectencoding_str(content)
|
||||
|
||||
if explicit:
|
||||
enctype = 2 # 2. BOM/@charset: explicitly
|
||||
encoding = contentEncoding
|
||||
@ -838,18 +847,17 @@ def _readUrl(url, fetcher=None, overrideEncoding=None, parentEncoding=None):
|
||||
enctype = 5 # 5. assume UTF-8
|
||||
encoding = 'utf-8'
|
||||
|
||||
try:
|
||||
# encoding may still be wrong if encoding *is lying*!
|
||||
if isinstance(content, unicode):
|
||||
decodedCssText = content
|
||||
elif content is not None:
|
||||
if isinstance(content, unicode):
|
||||
decodedCssText = content
|
||||
else:
|
||||
try:
|
||||
# encoding may still be wrong if encoding *is lying*!
|
||||
decodedCssText = codecs.lookup("css")[1](content, encoding=encoding)[0]
|
||||
else:
|
||||
except UnicodeDecodeError, e:
|
||||
log.warn(e, neverraise=True)
|
||||
decodedCssText = None
|
||||
except UnicodeDecodeError, e:
|
||||
cssutils.log.warn(e, neverraise=True)
|
||||
decodedCssText = None
|
||||
|
||||
return encoding, enctype, decodedCssText
|
||||
else:
|
||||
return None, None, None
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user