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-02-19 22:56:27 +0100 (Di, 19 Feb 2008) $'
9 __version__ = '$LastChangedRevision: 1068 $'
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 if nametokens:
144 wellformed = True
145
146 valuetokens = self._tokensupto2(tokenizer,
147 propertyvalueendonly=True)
148 prioritytokens = self._tokensupto2(tokenizer,
149 propertypriorityendonly=True)
150
151 if self._mediaQuery and not valuetokens:
152
153 self.name = nametokens
154 self.cssValue = None
155 self.priority = None
156 return
157
158
159 colontoken = nametokens.pop()
160 if self._tokenvalue(colontoken) != u':':
161 wellformed = False
162 self._log.error(u'Property: No ":" after name found: %r' %
163 self._valuestr(cssText), colontoken)
164 elif not nametokens:
165 wellformed = False
166 self._log.error(u'Property: No property name found: %r.' %
167 self._valuestr(cssText), colontoken)
168
169 if valuetokens:
170 if self._tokenvalue(valuetokens[-1]) == u'!':
171
172 prioritytokens.insert(0, valuetokens.pop(-1))
173 else:
174 wellformed = False
175 self._log.error(u'Property: No property value found: %r.' %
176 self._valuestr(cssText), colontoken)
177
178 if wellformed:
179 self.wellformed = True
180 self.name = nametokens
181 self.cssValue = valuetokens
182 self.priority = prioritytokens
183
184 else:
185 self._log.error(u'Property: No property name found: %r.' %
186 self._valuestr(cssText))
187
188 cssText = property(fget=_getCssText, fset=_setCssText,
189 doc="A parsable textual representation.")
190
192 """
193 DOMException on setting
194
195 - SYNTAX_ERR: (self)
196 Raised if the specified name has a syntax error and is
197 unparsable.
198 """
199
200 new = {'literalname': None,
201 'wellformed': True}
202
203 def _ident(expected, seq, token, tokenizer=None):
204
205 if 'name' == expected:
206 new['literalname'] = self._tokenvalue(token).lower()
207 seq.append(new['literalname'])
208 return 'EOF'
209 else:
210 new['wellformed'] = False
211 self._log.error(u'Property: Unexpected ident.', token)
212 return expected
213
214 newseq = []
215 wellformed, expected = self._parse(expected='name',
216 seq=newseq,
217 tokenizer=self._tokenize2(name),
218 productions={'IDENT': _ident})
219 wellformed = wellformed and new['wellformed']
220
221
222
223 if isinstance(name, list):
224 token = name[0]
225 else:
226 token = None
227
228 if not new['literalname']:
229 wellformed = False
230 self._log.error(u'Property: No name found: %r' %
231 self._valuestr(name), token=token)
232
233 if wellformed:
234 self.wellformed = True
235 self._literalname = new['literalname']
236 self._name = self._normalize(self._literalname)
237 self.__normalname = self._name
238 self.seqs[0] = newseq
239
240
241 if self._name not in cssproperties.cssvalues:
242 self.valid = False
243 tokenizer=self._tokenize2(name)
244 self._log.info(u'Property: No CSS2 Property: %r.' %
245 new['literalname'], token=token, neverraise=True)
246 else:
247 self.valid = True
248 if self.cssValue:
249 self.cssValue._propertyName = self._name
250 self.valid = self.cssValue.valid
251 else:
252 self.wellformed = False
253
254 name = property(lambda self: self._name, _setName,
255 doc="Name of this property")
256
257 literalname = property(lambda self: self._literalname,
258 doc="Readonly literal (not normalized) name of this property")
259
262
289
290 cssValue = property(_getCSSValue, _setCSSValue,
291 doc="(cssutils) CSSValue object of this property")
292
298
303
304 value = property(_getValue, _setValue,
305 doc="The textual value of this Properties cssValue.")
306
308 """
309 priority
310 a string, currently either u'', u'!important' or u'important'
311
312 Format
313 ======
314 ::
315
316 prio
317 : IMPORTANT_SYM S*
318 ;
319
320 "!"{w}"important" {return IMPORTANT_SYM;}
321
322 DOMException on setting
323
324 - SYNTAX_ERR: (self)
325 Raised if the specified priority has a syntax error and is
326 unparsable.
327 In this case a priority not equal to None, "" or "!{w}important".
328 As CSSOM defines CSSStyleDeclaration.getPropertyPriority resulting in
329 u'important' this value is also allowed to set a Properties priority
330 """
331 if self._mediaQuery:
332 self._priority = u''
333 self._literalpriority = u''
334 if priority:
335 self._log.error(u'Property: No priority in a MediaQuery - ignored.')
336 return
337
338 if isinstance(priority, basestring) and\
339 u'important' == self._normalize(priority):
340 priority = u'!%s' % priority
341
342
343 new = {'literalpriority': u'',
344 'wellformed': True}
345
346 def _char(expected, seq, token, tokenizer=None):
347
348 val = self._tokenvalue(token)
349 if u'!' == expected == val:
350 seq.append(val)
351 return 'important'
352 else:
353 new['wellformed'] = False
354 self._log.error(u'Property: Unexpected char.', token)
355 return expected
356
357 def _ident(expected, seq, token, tokenizer=None):
358
359 val = self._tokenvalue(token)
360 normalval = self._tokenvalue(token, normalize=True)
361 if 'important' == expected == normalval:
362 new['literalpriority'] = val
363 seq.append(val)
364 return 'EOF'
365 else:
366 new['wellformed'] = False
367 self._log.error(u'Property: Unexpected ident.', token)
368 return expected
369
370 newseq = []
371 wellformed, expected = self._parse(expected='!',
372 seq=newseq,
373 tokenizer=self._tokenize2(priority),
374 productions={'CHAR': _char,
375 'IDENT': _ident})
376 wellformed = wellformed and new['wellformed']
377
378
379 if priority and not new['literalpriority']:
380 wellformed = False
381 self._log.info(u'Property: Invalid priority: %r.' %
382 self._valuestr(priority))
383
384 if wellformed:
385 self.wellformed = self.wellformed and wellformed
386 self._literalpriority = new['literalpriority']
387 self._priority = self._normalize(self.literalpriority)
388 self.seqs[2] = newseq
389
390
391 if self._priority not in (u'', u'important'):
392 self.valid = False
393 self._log.info(u'Property: No CSS2 priority value: %r.' %
394 self._priority, neverraise=True)
395
396 priority = property(lambda self: self._priority, _setPriority,
397 doc="(cssutils) Priority of this property")
398
399 literalpriority = property(lambda self: self._literalpriority,
400 doc="Readonly literal (not normalized) priority of this property")
401
406
408 return "<%s.%s object name=%r value=%r priority=%r at 0x%x>" % (
409 self.__class__.__module__, self.__class__.__name__,
410 self.name, self.cssValue.cssText, self.priority, id(self))
411
412 @Deprecated(u'Use property ``name`` instead (since cssutils 0.9.5).')
414 return self.__normalname
415 normalname = property(_getNormalname,
416 doc="DEPRECATED since 0.9.5, use name instead")
417