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