File: //usr/local/bin/python37_/lib/python3.7/site-packages/cssutils/css/marginrule.py
"""MarginRule implements DOM Level 2 CSS MarginRule."""
__all__ = ['MarginRule']
from cssutils.prodparser import Choice, PreDef, Prod, ProdParser, Sequence
from .cssstyledeclaration import CSSStyleDeclaration
from . import cssrule
import cssutils
import xml.dom
class MarginRule(cssrule.CSSRule):
"""
A margin at-rule consists of an ATKEYWORD that identifies the margin box
(e.g. '@top-left') and a block of declarations (said to be in the margin
context).
Format::
margin :
margin_sym S* '{' declaration [ ';' S* declaration? ]* '}' S*
;
margin_sym :
TOPLEFTCORNER_SYM |
TOPLEFT_SYM |
TOPCENTER_SYM |
TOPRIGHT_SYM |
TOPRIGHTCORNER_SYM |
BOTTOMLEFTCORNER_SYM |
BOTTOMLEFT_SYM |
BOTTOMCENTER_SYM |
BOTTOMRIGHT_SYM |
BOTTOMRIGHTCORNER_SYM |
LEFTTOP_SYM |
LEFTMIDDLE_SYM |
LEFTBOTTOM_SYM |
RIGHTTOP_SYM |
RIGHTMIDDLE_SYM |
RIGHTBOTTOM_SYM
;
e.g.::
@top-left {
content: "123";
}
"""
margins = [
'@top-left-corner',
'@top-left',
'@top-center',
'@top-right',
'@top-right-corner',
'@bottom-left-corner',
'@bottom-left',
'@bottom-center',
'@bottom-right',
'@bottom-right-corner',
'@left-top',
'@left-middle',
'@left-bottom',
'@right-top',
'@right-middle',
'@right-bottom',
]
def __init__(
self,
margin=None,
style=None,
parentRule=None,
parentStyleSheet=None,
readonly=False,
):
"""
:param atkeyword:
The margin area, e.g. '@top-left' for this rule
:param style:
CSSStyleDeclaration for this MarginRule
"""
super().__init__(parentRule=parentRule, parentStyleSheet=parentStyleSheet)
self._atkeyword = self._keyword = None
if margin:
self.margin = margin
if style:
self.style = style
else:
self.style = CSSStyleDeclaration(parentRule=self)
self._readonly = readonly
def _setMargin(self, margin):
"""Check if new keyword fits the rule it is used for."""
n = self._normalize(margin)
if n not in MarginRule.margins:
self._log.error(
'Invalid margin @keyword for this {} rule: {!r}'.format(
self.margin, margin
),
error=xml.dom.InvalidModificationErr,
)
else:
self._atkeyword = n
self._keyword = margin
margin = property(
lambda self: self._atkeyword,
_setMargin,
doc="Margin area of parent CSSPageRule. "
"`margin` and `atkeyword` are both normalized "
"@keyword of the @rule.",
)
atkeyword = margin
def __repr__(self):
return "cssutils.css.{}(margin={!r}, style={!r})".format(
self.__class__.__name__,
self.margin,
self.style.cssText,
)
def __str__(self):
return "<cssutils.css.%s object margin=%r style=%r " "at 0x%x>" % (
self.__class__.__name__,
self.margin,
self.style.cssText,
id(self),
)
def _getCssText(self):
"""Return serialized property cssText."""
return cssutils.ser.do_MarginRule(self)
def _setCssText(self, cssText):
"""
: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()._setCssText(cssText)
# TEMP: all style tokens are saved in store to fill styledeclaration
# TODO: resolve when all generators
styletokens = Prod(
name='styletokens',
match=lambda t, v: v != '}',
# toSeq=False,
toStore='styletokens',
storeToken=True,
)
prods = Sequence(
Prod(
name='@ margin',
match=lambda t, v: t == 'ATKEYWORD'
and self._normalize(v) in MarginRule.margins,
toStore='margin'
# TODO?
# , exception=xml.dom.InvalidModificationErr
),
PreDef.char('OPEN', '{'),
Sequence(
Choice(PreDef.unknownrule(toStore='@'), styletokens),
minmax=lambda: (0, None),
),
PreDef.char('CLOSE', '}', stopAndKeep=True),
)
# parse
ok, seq, store, unused = ProdParser().parse(cssText, 'MarginRule', prods)
if ok:
# TODO: use seq for serializing instead of fixed stuff?
self._setSeq(seq)
if 'margin' in store:
# may raise:
self.margin = store['margin'].value
else:
self._log.error(
'No margin @keyword for this %s rule' % self.margin,
error=xml.dom.InvalidModificationErr,
)
# new empty style
self.style = CSSStyleDeclaration(parentRule=self)
if 'styletokens' in store:
# may raise:
self.style.cssText = store['styletokens']
cssText = property(
fget=_getCssText,
fset=_setCssText,
doc="(DOM) The parsable textual representation.",
)
def _setStyle(self, style):
"""
:param style: A string or CSSStyleDeclaration which replaces the
current style object.
"""
self._checkReadonly()
if isinstance(style, str):
self._style = CSSStyleDeclaration(cssText=style, parentRule=self)
else:
style._parentRule = self
self._style = style
style = property(
lambda self: self._style,
_setStyle,
doc="(DOM) The declaration-block of this rule set.",
)
type = property(
lambda self: self.MARGIN_RULE,
doc="The type of this rule, as defined by a CSSRule " "type constant.",
)
wellformed = property(lambda self: bool(self.atkeyword))