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-11-24 23:32:52 +0100 (Sa, 24 Nov 2007) $'
9 __version__ = '$LastChangedRevision: 679 $'
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 if not new['name']:
209 wellformed = False
210 self._log.error(u'Property: No name found: %r' %
211 self._valuestr(name))
212
213 if wellformed:
214 self.wellformed = True
215 self._name = new['name']
216 self.normalname = self._normalize(self._name)
217 self.seqs[0] = newseq
218
219
220 if self.normalname not in cssproperties.cssvalues:
221 self.valid = False
222 self._log.info(u'Property: No CSS2 Property: %r.' %
223 new['name'], neverraise=True)
224 else:
225 self.valid = True
226 if self.cssValue:
227 self.cssValue._propertyName = self.normalname
228 self.valid = self.cssValue.valid
229
230
231 else:
232 self.wellformed = False
233
234 name = property(_getName, _setName,
235 doc="(cssutils) Name of this property")
236
239
241 """
242 see css.CSSValue
243
244 DOMException on setting?
245
246 - SYNTAX_ERR: (self)
247 Raised if the specified CSS string value has a syntax error
248 (according to the attached property) or is unparsable.
249 - TODO: INVALID_MODIFICATION_ERR:
250 Raised if the specified CSS string value represents a different
251 type of values than the values allowed by the CSS property.
252 """
253 if self._mediaQuery and not cssText:
254 self.seqs[1] = CSSValue()
255 else:
256 if not self.seqs[1]:
257 self.seqs[1] = CSSValue()
258
259 cssvalue = self.seqs[1]
260 cssvalue._propertyName = self.name
261 cssvalue.cssText = cssText
262 if cssvalue._value and cssvalue.wellformed:
263 self.seqs[1] = cssvalue
264 self.valid = self.valid and cssvalue.valid
265 self.wellformed = self.wellformed and cssvalue.wellformed
266
267 cssValue = property(_getCSSValue, _setCSSValue,
268 doc="(cssutils) CSSValue object of this property")
269
273
278
279 value = property(_getValue, _setValue,
280 doc="The textual value of this Properties cssValue.")
281
284
286 """
287 priority
288 a string
289
290 Format
291 ======
292 ::
293
294 prio
295 : IMPORTANT_SYM S*
296 ;
297
298 "!"{w}"important" {return IMPORTANT_SYM;}
299
300 DOMException on setting
301
302 - SYNTAX_ERR: (self)
303 Raised if the specified priority has a syntax error and is
304 unparsable.
305 In this case a priority not equal to None, "" or "!{w}important".
306 """
307 if self._mediaQuery:
308 self._priority = u''
309 if priority:
310 self._log.error(u'Property: No priority in a MediaQuery - ignored.')
311 return
312
313
314 new = {'priority': u'',
315 'wellformed': True}
316
317 def _char(expected, seq, token, tokenizer=None):
318
319 val = self._tokenvalue(token)
320 if u'!' == expected == val:
321 seq.append(val)
322 return 'important'
323 else:
324 new['wellformed'] = False
325 self._log.error(u'Property: Unexpected char.', token)
326 return expected
327
328 def _ident(expected, seq, token, tokenizer=None):
329
330 val = self._tokenvalue(token)
331 normalval = self._tokenvalue(token, normalize=True)
332 if 'important' == expected == normalval:
333 new['priority'] = val.lower()
334 seq.append(val.lower())
335 return 'EOF'
336 else:
337 new['wellformed'] = False
338 self._log.error(u'Property: Unexpected ident.', token)
339 return expected
340
341 newseq = []
342 wellformed, expected = self._parse(expected='!',
343 seq=newseq,
344 tokenizer=self._tokenize2(priority),
345 productions={'CHAR': _char,
346 'IDENT': _ident})
347 wellformed = wellformed and new['wellformed']
348
349
350 if priority and not new['priority']:
351 wellformed = False
352 self._log.info(u'Property: Invalid priority: %r.' %
353 self._valuestr(priority))
354
355 if wellformed:
356 self.wellformed = self.wellformed and wellformed
357 self._priority = new['priority']
358 self._normalpriority = self._normalize(self._priority)
359 self.seqs[2] = newseq
360
361
362 if self._normalpriority not in (u'', u'important'):
363 self.valid = False
364 self._log.info(u'Property: No CSS2 priority value: %r.' %
365 self._normalpriority, neverraise=True)
366
367 priority = property(_getPriority, _setPriority,
368 doc="(cssutils) Priority of this property")
369
371 return "cssutils.css.%s(name=%r, value=%r, priority=%r)" % (
372 self.__class__.__name__,
373 self.name, self.cssValue.cssText, self.priority)
374
376 return "<%s.%s object name=%r value=%r priority=%r at 0x%x>" % (
377 self.__class__.__module__, self.__class__.__name__,
378 self.name, self.cssValue.cssText, self.priority, id(self))
379