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