1 """Property is a single CSS property in a CSSStyleDeclaration
2
3 Internal use only, may be removed in the future!
4 """
5 __all__ = ['Property']
6 __docformat__ = 'restructuredtext'
7 __author__ = '$LastChangedBy: cthedot $'
8 __date__ = '$LastChangedDate: 2007-12-28 13:07:34 +0100 (Fr, 28 Dez 2007) $'
9 __version__ = '$LastChangedRevision: 753 $'
10
11 import xml.dom
12 import cssutils
13 import cssproperties
14 from cssvalue import CSSValue
15
17 """
18 (cssutils) a CSS property in a StyleDeclaration of a CSSStyleRule
19
20 Properties
21 ==========
22 cssText
23 a parsable textual representation of this property
24 name
25 of the property
26 normalname
27 normalized name of the property, e.g. "color" when name is "c\olor"
28 cssValue
29 the relevant CSSValue instance for this property
30 value
31 the string value of the property, same as cssValue.cssText
32 priority
33 of the property (currently only "!important" or None)
34 seqs
35 combination of a list for seq of name, a CSSValue object, and
36 a list for seq of priority (empty or [!important] currently)
37 valid
38 if this Property is valid
39 wellformed
40 if this Property is syntactically ok
41
42 Format
43 ======
44 ::
45
46 property = name
47 : IDENT S*
48 ;
49
50 expr = value
51 : term [ operator term ]*
52 ;
53 term
54 : unary_operator?
55 [ NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* | ANGLE S* |
56 TIME S* | FREQ S* | function ]
57 | STRING S* | IDENT S* | URI S* | hexcolor
58 ;
59 function
60 : FUNCTION S* expr ')' S*
61 ;
62 /*
63 * There is a constraint on the color that it must
64 * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F])
65 * after the "#"; e.g., "#000" is OK, but "#abcd" is not.
66 */
67 hexcolor
68 : HASH S*
69 ;
70
71 prio
72 : IMPORTANT_SYM S*
73 ;
74
75 """
76 - def __init__(self, name=None, value=None, priority=None, _mediaQuery=False):
77 """
78 inits property
79
80 name
81 a property name string
82 value
83 a property value string
84 priority
85 an optional priority string
86 _mediaQuery boolean
87 if True value is optional as used by MediaQuery objects
88 """
89 super(Property, self).__init__()
90
91 self.seqs = [[], None, []]
92 self.valid = False
93 self.wellformed = False
94 self._mediaQuery = _mediaQuery
95
96 if name:
97 self.name = name
98 else:
99 self._name = u''
100 self.normalname = u''
101
102 if value:
103 self.cssValue = value
104 else:
105 self.seqs[1] = CSSValue()
106
107 self.priority = priority
108
109 - def _getCssText(self):
110 """
111 returns serialized property cssText
112 """
113 return cssutils.ser.do_Property(self)
114
115 - def _setCssText(self, cssText):
116 """
117 DOMException on setting
118
119 - NO_MODIFICATION_ALLOWED_ERR: (CSSRule)
120 Raised if the rule is readonly.
121 - SYNTAX_ERR: (self)
122 Raised if the specified CSS string value has a syntax error and
123 is unparsable.
124 """
125
126 tokenizer = self._tokenize2(cssText)
127 nametokens = self._tokensupto2(tokenizer, propertynameendonly=True)
128 valuetokens = self._tokensupto2(tokenizer, propertyvalueendonly=True)
129 prioritytokens = self._tokensupto2(tokenizer, propertypriorityendonly=True)
130
131 wellformed = True
132 if nametokens:
133
134 if self._mediaQuery and not valuetokens:
135
136 self.name = nametokens
137 self.cssValue = None
138 self.priority = None
139 return
140
141
142 colontoken = nametokens.pop()
143 if self._tokenvalue(colontoken) != u':':
144 wellformed = False
145 self._log.error(u'Property: No ":" after name found: %r' %
146 self._valuestr(cssText), colontoken)
147 elif not nametokens:
148 wellformed = False
149 self._log.error(u'Property: No property name found: %r.' %
150 self._valuestr(cssText), colontoken)
151
152 if valuetokens:
153 if self._tokenvalue(valuetokens[-1]) == u'!':
154
155 prioritytokens.insert(0, valuetokens.pop(-1))
156 else:
157 wellformed = False
158 self._log.error(u'Property: No property value found: %r.' %
159 self._valuestr(cssText), colontoken)
160
161 if wellformed:
162 self.wellformed = True
163 self.name = nametokens
164 self.cssValue = valuetokens
165 self.priority = prioritytokens
166
167 else:
168 self._log.error(u'Property: No property name found: %r.' %
169 self._valuestr(cssText))
170
171 cssText = property(fget=_getCssText, fset=_setCssText,
172 doc="A parsable textual representation.")
173
176
178 """
179 DOMException on setting
180
181 - SYNTAX_ERR: (self)
182 Raised if the specified name has a syntax error and is
183 unparsable.
184 """
185
186 new = {'name': None,
187 'wellformed': True}
188
189 def _ident(expected, seq, token, tokenizer=None):
190
191 if 'name' == expected:
192 new['name'] = self._tokenvalue(token).lower()
193 seq.append(new['name'])
194 return 'EOF'
195 else:
196 new['wellformed'] = False
197 self._log.error(u'Property: Unexpected ident.', token)
198 return expected
199
200 newseq = []
201 wellformed, expected = self._parse(expected='name',
202 seq=newseq,
203 tokenizer=self._tokenize2(name),
204 productions={'IDENT': _ident})
205 wellformed = wellformed and new['wellformed']
206
207
208
209 if isinstance(name, list):
210 token = name[0]
211 else:
212 token = None
213
214 if not new['name']:
215 wellformed = False
216 self._log.error(u'Property: No name found: %r' %
217 self._valuestr(name), token=token)
218
219 if wellformed:
220 self.wellformed = True
221 self._name = new['name']
222 self.normalname = self._normalize(self._name)
223 self.seqs[0] = newseq
224
225
226 if self.normalname not in cssproperties.cssvalues:
227 self.valid = False
228 tokenizer=self._tokenize2(name)
229 self._log.info(u'Property: No CSS2 Property: %r.' %
230 new['name'], token=token, neverraise=True)
231 else:
232 self.valid = True
233 if self.cssValue:
234 self.cssValue._propertyName = self.normalname
235 self.valid = self.cssValue.valid
236
237
238 else:
239 self.wellformed = False
240
241 name = property(_getName, _setName,
242 doc="(cssutils) Name of this property")
243
246
248 """
249 see css.CSSValue
250
251 DOMException on setting?
252
253 - SYNTAX_ERR: (self)
254 Raised if the specified CSS string value has a syntax error
255 (according to the attached property) or is unparsable.
256 - TODO: INVALID_MODIFICATION_ERR:
257 Raised if the specified CSS string value represents a different
258 type of values than the values allowed by the CSS property.
259 """
260 if self._mediaQuery and not cssText:
261 self.seqs[1] = CSSValue()
262 else:
263 if not self.seqs[1]:
264 self.seqs[1] = CSSValue()
265
266 cssvalue = self.seqs[1]
267 cssvalue._propertyName = self.name
268 cssvalue.cssText = cssText
269 if cssvalue._value and cssvalue.wellformed:
270 self.seqs[1] = cssvalue
271 self.valid = self.valid and cssvalue.valid
272 self.wellformed = self.wellformed and cssvalue.wellformed
273
274 cssValue = property(_getCSSValue, _setCSSValue,
275 doc="(cssutils) CSSValue object of this property")
276
280
285
286 value = property(_getValue, _setValue,
287 doc="The textual value of this Properties cssValue.")
288
291
293 """
294 priority
295 a string
296
297 Format
298 ======
299 ::
300
301 prio
302 : IMPORTANT_SYM S*
303 ;
304
305 "!"{w}"important" {return IMPORTANT_SYM;}
306
307 DOMException on setting
308
309 - SYNTAX_ERR: (self)
310 Raised if the specified priority has a syntax error and is
311 unparsable.
312 In this case a priority not equal to None, "" or "!{w}important".
313 """
314 if self._mediaQuery:
315 self._priority = u''
316 if priority:
317 self._log.error(u'Property: No priority in a MediaQuery - ignored.')
318 return
319
320
321 new = {'priority': u'',
322 'wellformed': True}
323
324 def _char(expected, seq, token, tokenizer=None):
325
326 val = self._tokenvalue(token)
327 if u'!' == expected == val:
328 seq.append(val)
329 return 'important'
330 else:
331 new['wellformed'] = False
332 self._log.error(u'Property: Unexpected char.', token)
333 return expected
334
335 def _ident(expected, seq, token, tokenizer=None):
336
337 val = self._tokenvalue(token)
338 normalval = self._tokenvalue(token, normalize=True)
339 if 'important' == expected == normalval:
340 new['priority'] = val.lower()
341 seq.append(val.lower())
342 return 'EOF'
343 else:
344 new['wellformed'] = False
345 self._log.error(u'Property: Unexpected ident.', token)
346 return expected
347
348 newseq = []
349 wellformed, expected = self._parse(expected='!',
350 seq=newseq,
351 tokenizer=self._tokenize2(priority),
352 productions={'CHAR': _char,
353 'IDENT': _ident})
354 wellformed = wellformed and new['wellformed']
355
356
357 if priority and not new['priority']:
358 wellformed = False
359 self._log.info(u'Property: Invalid priority: %r.' %
360 self._valuestr(priority))
361
362 if wellformed:
363 self.wellformed = self.wellformed and wellformed
364 self._priority = new['priority']
365 self._normalpriority = self._normalize(self._priority)
366 self.seqs[2] = newseq
367
368
369 if self._normalpriority not in (u'', u'important'):
370 self.valid = False
371 self._log.info(u'Property: No CSS2 priority value: %r.' %
372 self._normalpriority, neverraise=True)
373
374 priority = property(_getPriority, _setPriority,
375 doc="(cssutils) Priority of this property")
376
378 return "cssutils.css.%s(name=%r, value=%r, priority=%r)" % (
379 self.__class__.__name__,
380 self.name, self.cssValue.cssText, self.priority)
381
383 return "<%s.%s object name=%r value=%r priority=%r at 0x%x>" % (
384 self.__class__.__module__, self.__class__.__name__,
385 self.name, self.cssValue.cssText, self.priority, id(self))
386