Minify on backend

This commit is contained in:
Ruud
2013-04-30 13:17:03 +02:00
parent 12c3fc6ce3
commit 30ec8216e1
62 changed files with 17953 additions and 737 deletions
+11
View File
@@ -0,0 +1,11 @@
"""Implements Document Object Model Level 2 Style Sheets
http://www.w3.org/TR/2000/PR-DOM-Level-2-Style-20000927/stylesheets.html
"""
__all__ = ['MediaList', 'MediaQuery', 'StyleSheet', 'StyleSheetList']
__docformat__ = 'restructuredtext'
__version__ = '$Id$'
from medialist import *
from mediaquery import *
from stylesheet import *
from stylesheetlist import *
+235
View File
@@ -0,0 +1,235 @@
"""MediaList implements DOM Level 2 Style Sheets MediaList.
TODO:
- delete: maybe if deleting from all, replace *all* with all others?
- is unknown media an exception?
"""
__all__ = ['MediaList']
__docformat__ = 'restructuredtext'
__version__ = '$Id$'
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,
without defining or constraining how this collection is
implemented.
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".
Format from CSS2.1::
medium [ COMMA S* medium ]*
New format with :class:`MediaQuery`::
<media_query> [, <media_query> ]*
"""
def __init__(self, mediaText=None, parentRule=None, readonly=False):
"""
:param mediaText:
Unicodestring of parsable comma separared media
or a (Python) list of media.
:param parentRule:
CSSRule this medialist is used in, e.g. an @import or @media.
:param readonly:
Not used yet.
"""
super(MediaList, self).__init__()
self._wellformed = False
if isinstance(mediaText, list):
mediaText = u','.join(mediaText)
self._parentRule = parentRule
if mediaText:
self.mediaText = mediaText
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="The number of media in the list (DOM readonly).")
def _getMediaText(self):
return cssutils.ser.do_stylesheets_medialist(self)
def _setMediaText(self, mediaText):
"""
:param mediaText:
simple value or comma-separated list of media
: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
tokenizer = self._tokenize2(mediaText)
newseq = []
expected = None
while True:
# find all upto and including next ",", EOF or nothing
mqtokens = self._tokensupto2(tokenizer, listseponly=True)
if mqtokens:
if self._tokenvalue(mqtokens[-1]) == ',':
expected = mqtokens.pop()
else:
expected = None
mq = MediaQuery(mqtokens)
if mq.wellformed:
newseq.append(mq)
else:
wellformed = False
self._log.error(u'MediaList: Invalid MediaQuery: %s' %
self._valuestr(mqtokens))
else:
break
# post condition
if expected:
wellformed = False
self._log.error(u'MediaList: Cannot end with ",".')
if wellformed:
del self[:]
for mq in newseq:
self.appendMedium(mq)
self._wellformed = True
mediaText = property(_getMediaText, _setMediaText,
doc="The parsable textual representation of the media list.")
def __prepareset(self, newMedium):
# used by appendSelector and __setitem__
self._checkReadonly()
if not isinstance(newMedium, MediaQuery):
newMedium = MediaQuery(newMedium)
if newMedium.wellformed:
return newMedium
def __setitem__(self, index, newMedium):
"""Overwriting ListSeq.__setitem__
Any duplicate items are **not yet** removed.
"""
newMedium = self.__prepareset(newMedium)
if newMedium:
self.seq[index] = newMedium
# TODO: remove duplicates?
def appendMedium(self, newMedium):
"""Add the `newMedium` to the end of the list.
If the `newMedium` is already used, it is first removed.
: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)
if newMedium:
mts = [self._normalize(mq.mediaType) for mq in self]
newmt = self._normalize(newMedium.mediaType)
if newmt in mts:
self.deleteMedium(newmt)
self.seq.append(newMedium)
elif u'all' == newmt:
# remove all except handheld (Opera)
h = None
for mq in self:
if mq.mediaType == u'handheld':
h = mq
del self[:]
self.seq.append(newMedium)
if h:
self.append(h)
elif u'all' in mts:
if u'handheld' == newmt:
self.seq.append(newMedium)
self._log.info(u'MediaList: Already specified "all" but still setting new medium: %r' %
newMedium, error=xml.dom.InvalidModificationErr, neverraise=True)
else:
self._log.info(u'MediaList: Ignoring new medium %r as already specified "all" (set ``mediaText`` instead).' %
newMedium, error=xml.dom.InvalidModificationErr)
else:
self.seq.append(newMedium)
return True
else:
return False
def append(self, newMedium):
"Same as :meth:`appendMedium`."
self.appendMedium(newMedium)
def deleteMedium(self, oldMedium):
"""Delete a medium from 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)
for i, mq in enumerate(self):
if self._normalize(mq.mediaType) == oldMedium:
del self[i]
break
else:
self._log.error(u'"%s" not in this MediaList' % oldMedium,
error=xml.dom.NotFoundErr)
def item(self, index):
"""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
parentRule = property(lambda self: self._parentRule,
doc=u"The CSSRule (e.g. an @media or @import rule "
u"this list is part of or None")
wellformed = property(lambda self: self._wellformed)
+207
View File
@@ -0,0 +1,207 @@
"""Implements a DOM for MediaQuery, see
http://www.w3.org/TR/css3-mediaqueries/.
A cssutils implementation, not defined in official DOM.
"""
__all__ = ['MediaQuery']
__docformat__ = 'restructuredtext'
__version__ = '$Id$'
import cssutils
import re
import xml.dom
class MediaQuery(cssutils.util.Base):
"""
A Media Query consists of one of :const:`MediaQuery.MEDIA_TYPES`
and one or more expressions involving media features.
Format::
media_query: [[only | not]? <media_type> [ and <expression> ]*]
| <expression> [ and <expression> ]*
expression: ( <media_feature> [: <value>]? )
media_type: all | braille | handheld | print |
projection | speech | screen | tty | tv | embossed
media_feature: width | min-width | max-width
| height | min-height | max-height
| device-width | min-device-width | max-device-width
| device-height | min-device-height | max-device-height
| device-aspect-ratio | min-device-aspect-ratio | max-device-aspect-ratio
| color | min-color | max-color
| color-index | min-color-index | max-color-index
| monochrome | min-monochrome | max-monochrome
| resolution | min-resolution | max-resolution
| scan | grid
"""
MEDIA_TYPES = [u'all', u'braille', u'embossed', u'handheld',
u'print', u'projection', u'screen', u'speech', u'tty', u'tv']
# From the HTML spec (see MediaQuery):
# "[...] character that isn't a US ASCII letter [a-zA-Z] (Unicode
# decimal 65-90, 97-122), digit [0-9] (Unicode hex 30-39), or hyphen (45)."
# so the following is a valid mediaType
__mediaTypeMatch = re.compile(ur'^[-a-zA-Z0-9]+$', re.U).match
def __init__(self, mediaText=None, readonly=False):
"""
:param mediaText:
unicodestring of parsable media
"""
super(MediaQuery, self).__init__()
self.seq = []
self._mediaType = u''
if mediaText:
self.mediaText = mediaText # sets self._mediaType too
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):
return cssutils.ser.do_stylesheets_mediaquery(self)
def _setMediaText(self, mediaText):
"""
:param mediaText:
a single media query string, e.g. ``print and (min-width: 25cm)``
: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)
if not tokenizer:
self._log.error(u'MediaQuery: No MediaText given.')
else:
# for closures: must be a mutable
new = {'mediatype': None,
'wellformed': True }
def _ident_or_dim(expected, seq, token, tokenizer=None):
# only|not or mediatype or and
val = self._tokenvalue(token)
nval = self._normalize(val)
if expected.endswith('mediatype'):
if nval in (u'only', u'not'):
# only or not
seq.append(val)
return 'mediatype'
else:
# mediatype
new['mediatype'] = val
seq.append(val)
return 'and'
elif 'and' == nval and expected.startswith('and'):
seq.append(u'and')
return 'feature'
else:
new['wellformed'] = False
self._log.error(
u'MediaQuery: Unexpected syntax.', token=token)
return expected
def _char(expected, seq, token, tokenizer=None):
# starting a feature which basically is a CSS Property
# but may simply be a property name too
val = self._tokenvalue(token)
if val == u'(' and expected == 'feature':
proptokens = self._tokensupto2(
tokenizer, funcendonly=True)
if proptokens and u')' == self._tokenvalue(proptokens[-1]):
proptokens.pop()
property = cssutils.css.Property(_mediaQuery=True)
property.cssText = proptokens
seq.append(property)
return 'and or EOF'
else:
new['wellformed'] = False
self._log.error(
u'MediaQuery: Unexpected syntax, expected "and" but found "%s".' %
val, token)
return expected
# expected: only|not or mediatype, mediatype, feature, and
newseq = []
wellformed, expected = self._parse(expected='only|not or mediatype',
seq=newseq, tokenizer=tokenizer,
productions={'IDENT': _ident_or_dim, # e.g. "print"
'DIMENSION': _ident_or_dim, # e.g. "3d"
'CHAR': _char})
wellformed = wellformed and new['wellformed']
# post conditions
if not new['mediatype']:
wellformed = False
self._log.error(u'MediaQuery: No mediatype found: %s' %
self._valuestr(mediaText))
if wellformed:
# set
self.mediaType = new['mediatype']
self.seq = newseq
mediaText = property(_getMediaText, _setMediaText,
doc="The parsable textual representation of the media list.")
def _setMediaType(self, mediaType):
"""
:param mediaType:
one of :attr:`MEDIA_TYPES`
: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)
if not MediaQuery.__mediaTypeMatch(nmediaType):
self._log.error(
u'MediaQuery: Syntax Error in media type "%s".' % mediaType,
error=xml.dom.SyntaxErr)
else:
if nmediaType not in MediaQuery.MEDIA_TYPES:
self._log.warn(
u'MediaQuery: Unknown media type "%s".' % mediaType,
error=xml.dom.InvalidCharacterErr)
return
# set
self._mediaType = mediaType
# update seq
for i, x in enumerate(self.seq):
if isinstance(x, basestring):
if self._normalize(x) in (u'only', u'not'):
continue
else:
self.seq[i] = mediaType
break
else:
self.seq.insert(0, mediaType)
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)))
+123
View File
@@ -0,0 +1,123 @@
"""StyleSheet implements DOM Level 2 Style Sheets StyleSheet."""
__all__ = ['StyleSheet']
__docformat__ = 'restructuredtext'
__version__ = '$Id$'
import cssutils
import urlparse
class StyleSheet(cssutils.util.Base2):
"""
The StyleSheet interface is the abstract base interface
for any type of style sheet. It represents a single style
sheet associated with a structured document.
In HTML, the StyleSheet interface represents either an
external style sheet, included via the HTML LINK element,
or an inline STYLE element (also an @import stylesheet?).
In XML, this interface represents
an external style sheet, included via a style sheet
processing instruction.
"""
def __init__(self, type='text/css',
href=None,
media=None,
title=u'',
ownerNode=None,
parentStyleSheet=None,
alternate=False,
disabled=None,
validating=True):
"""
type
readonly
href: readonly
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.
media: of type MediaList, readonly
The intended destination media for style information.
The media is often specified in the ownerNode. If no
media has been specified, the MediaList will be empty.
See the media attribute definition for the LINK element
in HTML 4.0, and the media pseudo-attribute for the XML
style sheet processing instruction. Modifying the media
list may cause a change to the attribute disabled.
title: readonly
The advisory title. The title is often specified in
the ownerNode. See the title attribute definition for
the LINK element in HTML 4.0, and the title
pseudo-attribute for the XML style sheet processing
instruction.
disabled: False if the style sheet is applied to the
document. True if it is not. Modifying this attribute
may cause a new resolution of style for the document.
A stylesheet only applies if both an appropriate medium
definition is present and the disabled attribute is False.
So, if the media doesn't apply to the current user agent,
the disabled attribute is ignored.
ownerNode: of type Node, readonly
The node that associates this style sheet with the
document. For HTML, this may be the corresponding LINK
or STYLE element. For XML, it may be the linking
processing instruction. For style sheets that are
included by other style sheets, the value of this
attribute is None.
parentStyleSheet: of type StyleSheet, readonly
a StyleSheet or None
alternate = False
a flag stating if a style sheet is an alternate one or not.
Currently not used in cssutils
validating = True
a flag defining if this sheet should be validate on change.
"""
super(StyleSheet, self).__init__()
self.validating = validating
self._alternate = alternate
self._href = href
self._ownerNode = ownerNode
self._parentStyleSheet = parentStyleSheet
self._type = type
self.disabled = bool(disabled)
self.media = media
self.title = title
alternate = property(lambda self: self._alternate,
doc="Not used in cssutils yet.")
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,
doc="Not used in cssutils yet.")
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="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``.")
+32
View File
@@ -0,0 +1,32 @@
"""StyleSheetList implements DOM Level 2 Style Sheets StyleSheetList."""
__all__ = ['StyleSheetList']
__docformat__ = 'restructuredtext'
__version__ = '$Id$'
class StyleSheetList(list):
"""Interface `StyleSheetList` (introduced in DOM Level 2)
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,
starting from 0.
This Python implementation is based on a standard Python list so e.g.
allows ``examplelist[index]`` usage.
"""
def item(self, index):
"""
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``.
"""
try:
return self[index]
except IndexError:
return None
length = property(lambda self: len(self),
doc="The number of :class:`StyleSheet` objects in the list. The range"
" of valid child stylesheet indices is 0 to length-1 inclusive.")