1 """CSSPageRule implements DOM Level 2 CSS CSSPageRule.
2 """
3 __all__ = ['CSSPageRule']
4 __docformat__ = 'restructuredtext'
5 __author__ = '$LastChangedBy: cthedot $'
6 __date__ = '$LastChangedDate: 2007-10-18 22:44:54 +0200 (Do, 18 Okt 2007) $'
7 __version__ = '$LastChangedRevision: 507 $'
8
9 import xml.dom
10 import cssrule
11 import cssutils
12 from selectorlist import SelectorList
13 from cssstyledeclaration import CSSStyleDeclaration
14
15
17 """
18 The CSSPageRule interface represents a @page rule within a CSS style
19 sheet. The @page rule is used to specify the dimensions, orientation,
20 margins, etc. of a page box for paged media.
21
22 Properties
23 ==========
24 cssText: of type DOMString
25 The parsable textual representation of this rule
26 selectorText: of type DOMString
27 The parsable textual representation of the page selector for the rule.
28 style: of type CSSStyleDeclaration
29 The declaration-block of this rule.
30
31 cssutils only
32 -------------
33 atkeyword:
34 the literal keyword used
35
36 Inherits properties from CSSRule
37
38 Format
39 ======
40 ::
41
42 page
43 : PAGE_SYM S* pseudo_page? S*
44 LBRACE S* declaration [ ';' S* declaration ]* '}' S*
45 ;
46 pseudo_page
47 : ':' IDENT # :first, :left, :right in CSS 2.1
48 ;
49
50 """
51 type = cssrule.CSSRule.PAGE_RULE
52
54 """
55 if readonly allows setting of properties in constructor only
56
57 selectorText
58 type string
59 style
60 CSSStyleDeclaration for this CSSStyleRule
61 """
62 super(CSSPageRule, self).__init__()
63
64 self.atkeyword = u'@page'
65
66 if selectorText:
67 self.selectorText = selectorText
68 self.seq.append(self.selectorText)
69 else:
70 self._selectorText = u''
71 if style:
72 self.style = style
73 self.seq.append(self.style)
74 else:
75 self._style = CSSStyleDeclaration(parentRule=self)
76
77 self._readonly = readonly
78
80 """
81 parses selectorText which may also be a list of tokens
82 and returns (selectorText, seq)
83
84 see _setSelectorText for details
85 """
86
87 new = {'selector': None, 'valid': True}
88
89 def _char(expected, seq, token, tokenizer=None):
90
91 val = self._tokenvalue(token)
92 if ':' == expected and u':' == val:
93 try:
94 identtoken = tokenizer.next()
95 except StopIteration:
96 self._log.error(
97 u'CSSPageRule selectorText: No IDENT found.', token)
98 else:
99 ival, ityp = self._tokenvalue(identtoken), self._type(identtoken)
100 if 'IDENT' != ityp:
101 self._log.error(
102 u'CSSPageRule selectorText: Expected IDENT but found: %r' %
103 ival, token)
104 else:
105 new['selector'] = val + ival
106 seq.append(new['selector'])
107 return 'EOF'
108 return expected
109 else:
110 new['valid'] = False
111 self._log.error(
112 u'CSSPageRule selectorText: Unexpected CHAR: %r' % val, token)
113 return expected
114
115 newseq = []
116 valid, expected = self._parse(expected=':',
117 seq=newseq, tokenizer=self._tokenize2(selectorText),
118 productions={'CHAR': _char})
119 valid = valid and new['valid']
120 newselector = new['selector']
121
122
123 if expected == 'ident':
124 self._log.error(
125 u'CSSPageRule selectorText: No valid selector: %r' %
126 self._valuestr(selectorText))
127
128 if not newselector in (None, u':first', u':left', u':right'):
129 self._log.warn(u'CSSPageRule: Unknown CSS 2.1 @page selector: %r' %
130 newselector, neverraise=True)
131
132 return newselector, newseq
133
135 """
136 returns serialized property cssText
137 """
138 return cssutils.ser.do_CSSPageRule(self)
139
141 """
142 DOMException on setting
143
144 - SYNTAX_ERR: (self, StyleDeclaration)
145 Raised if the specified CSS string value has a syntax error and
146 is unparsable.
147 - INVALID_MODIFICATION_ERR: (self)
148 Raised if the specified CSS string value represents a different
149 type of rule than the current one.
150 - HIERARCHY_REQUEST_ERR: (CSSStylesheet)
151 Raised if the rule cannot be inserted at this point in the
152 style sheet.
153 - NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
154 Raised if the rule is readonly.
155 """
156 super(CSSPageRule, self)._setCssText(cssText)
157
158 tokenizer = self._tokenize2(cssText)
159 attoken = self._nexttoken(tokenizer, None)
160 if not attoken or u'@page' != self._tokenvalue(
161 attoken, normalize=True):
162 self._log.error(u'CSSPageRule: No CSSPageRule found: %s' %
163 self._valuestr(cssText),
164 error=xml.dom.InvalidModificationErr)
165 else:
166 valid = True
167 selectortokens = self._tokensupto2(tokenizer, blockstartonly=True)
168 styletokens = self._tokensupto2(tokenizer, blockendonly=True)
169
170 try:
171 bracetoken = selectortokens.pop()
172 except IndexError:
173 bracetoken = None
174 if self._tokenvalue(bracetoken) != u'{':
175 valid = False
176 self._log.error(
177 u'CSSPageRule: No start { of style declaration found: %r' %
178 self._valuestr(cssText), bracetoken)
179
180 newselector, newselectorseq = self.__parseSelectorText(selectortokens)
181
182 newstyle = CSSStyleDeclaration()
183 if not styletokens:
184 valid = False
185 self._log.error(
186 u'CSSPageRule: No style declaration or "}" found: %r' %
187 self._valuestr(cssText))
188
189 braceorEOFtoken = styletokens.pop()
190 val, typ = self._tokenvalue(braceorEOFtoken), self._type(braceorEOFtoken)
191 if val != u'}' and typ != 'EOF':
192 valid = False
193 self._log.error(
194 u'CSSPageRule: No "}" after style declaration found: %r' %
195 self._valuestr(cssText))
196 else:
197 if 'EOF' == typ:
198
199 styletokens.append(braceorEOFtoken)
200 newstyle.cssText = styletokens
201
202 if valid:
203 self.valid = True
204 self._selectorText = newselector
205 self.style = newstyle
206 self.seq = newselectorseq
207
208 cssText = property(_getCssText, _setCssText,
209 doc="(DOM) The parsable textual representation of the rule.")
210
212 """
213 wrapper for cssutils Selector object
214 """
215 return self._selectorText
216
218 """
219 wrapper for cssutils Selector object
220
221 selector: DOM String
222 in CSS 2.1 one of
223 - :first
224 - :left
225 - :right
226 - empty
227
228 If WS or Comments are included they are ignored here! Only
229 way to add a comment is via setting ``cssText``
230
231 DOMException on setting
232
233 - SYNTAX_ERR:
234 Raised if the specified CSS string value has a syntax error
235 and is unparsable.
236 - NO_MODIFICATION_ALLOWED_ERR: (self)
237 Raised if this rule is readonly.
238 """
239 self._checkReadonly()
240
241
242 newselectortext, newseq = self.__parseSelectorText(selectorText)
243
244 if newselectortext:
245 for i, x in enumerate(self.seq):
246 if x == self._selectorText:
247 self.seq[i] = newselectortext
248 self._selectorText = newselectortext
249
250 selectorText = property(_getSelectorText, _setSelectorText,
251 doc="""(DOM) The parsable textual representation of the page selector for the rule.""")
252
255
257 """
258 style
259 StyleDeclaration or string
260 """
261 self._checkReadonly()
262 if isinstance(style, basestring):
263 self._style = CSSStyleDeclaration(parentRule=self, cssText=style)
264 else:
265 self._style = style
266 style.parentRule = self
267
268 style = property(_getStyle, _setStyle,
269 doc="(DOM) The declaration-block of this rule set.")
270
272 return "cssutils.css.%s(selectorText=%r, style=%r)" % (
273 self.__class__.__name__, self.selectorText, self.style.cssText)
274
276 return "<cssutils.css.%s object selectorText=%r style=%r at 0x%x>" % (
277 self.__class__.__name__, self.selectorText, self.style.cssText,
278 id(self))
279