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