gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / cssutils / css / cssstyledeclaration.py @ 475
History | View | Annotate | Download (26.5 KB)
1 |
"""CSSStyleDeclaration implements DOM Level 2 CSS CSSStyleDeclaration and
|
---|---|
2 |
extends CSS2Properties
|
3 |
|
4 |
see
|
5 |
http://www.w3.org/TR/1998/REC-CSS2-19980512/syndata.html#parsing-errors
|
6 |
|
7 |
Unknown properties
|
8 |
------------------
|
9 |
User agents must ignore a declaration with an unknown property.
|
10 |
For example, if the style sheet is::
|
11 |
|
12 |
H1 { color: red; rotation: 70minutes }
|
13 |
|
14 |
the user agent will treat this as if the style sheet had been::
|
15 |
|
16 |
H1 { color: red }
|
17 |
|
18 |
Cssutils gives a message about any unknown properties but
|
19 |
keeps any property (if syntactically correct).
|
20 |
|
21 |
Illegal values
|
22 |
--------------
|
23 |
User agents must ignore a declaration with an illegal value. For example::
|
24 |
|
25 |
IMG { float: left } /* correct CSS2 */
|
26 |
IMG { float: left here } /* "here" is not a value of 'float' */
|
27 |
IMG { background: "red" } /* keywords cannot be quoted in CSS2 */
|
28 |
IMG { border-width: 3 } /* a unit must be specified for length values */
|
29 |
|
30 |
A CSS2 parser would honor the first rule and ignore the rest, as if the
|
31 |
style sheet had been::
|
32 |
|
33 |
IMG { float: left }
|
34 |
IMG { }
|
35 |
IMG { }
|
36 |
IMG { }
|
37 |
|
38 |
Cssutils again will issue a message (WARNING in this case) about invalid
|
39 |
CSS2 property values.
|
40 |
|
41 |
TODO:
|
42 |
This interface is also used to provide a read-only access to the
|
43 |
computed values of an element. See also the ViewCSS interface.
|
44 |
|
45 |
- return computed values and not literal values
|
46 |
- simplify unit pairs/triples/quadruples
|
47 |
2px 2px 2px 2px -> 2px for border/padding...
|
48 |
- normalize compound properties like:
|
49 |
background: no-repeat left url() #fff
|
50 |
-> background: #fff url() no-repeat left
|
51 |
"""
|
52 |
__all__ = ['CSSStyleDeclaration', 'Property'] |
53 |
__docformat__ = 'restructuredtext'
|
54 |
__version__ = '$Id$'
|
55 |
|
56 |
from cssproperties import CSS2Properties |
57 |
from property import Property |
58 |
import cssutils |
59 |
import xml.dom |
60 |
|
61 |
class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2): |
62 |
"""The CSSStyleDeclaration class represents a single CSS declaration
|
63 |
block. This class may be used to determine the style properties
|
64 |
currently set in a block or to set style properties explicitly
|
65 |
within the block.
|
66 |
|
67 |
While an implementation may not recognize all CSS properties within
|
68 |
a CSS declaration block, it is expected to provide access to all
|
69 |
specified properties in the style sheet through the
|
70 |
CSSStyleDeclaration interface.
|
71 |
Furthermore, implementations that support a specific level of CSS
|
72 |
should correctly handle CSS shorthand properties for that level. For
|
73 |
a further discussion of shorthand properties, see the CSS2Properties
|
74 |
interface.
|
75 |
|
76 |
Additionally the CSS2Properties interface is implemented.
|
77 |
|
78 |
$css2propertyname
|
79 |
All properties defined in the CSS2Properties class are available
|
80 |
as direct properties of CSSStyleDeclaration with their respective
|
81 |
DOM name, so e.g. ``fontStyle`` for property 'font-style'.
|
82 |
|
83 |
These may be used as::
|
84 |
|
85 |
>>> style = CSSStyleDeclaration(cssText='color: red')
|
86 |
>>> style.color = 'green'
|
87 |
>>> print style.color
|
88 |
green
|
89 |
>>> del style.color
|
90 |
>>> print style.color
|
91 |
<BLANKLINE>
|
92 |
|
93 |
Format::
|
94 |
|
95 |
[Property: Value Priority?;]* [Property: Value Priority?]?
|
96 |
"""
|
97 |
def __init__(self, cssText=u'', parentRule=None, readonly=False, |
98 |
validating=None):
|
99 |
"""
|
100 |
:param cssText:
|
101 |
Shortcut, sets CSSStyleDeclaration.cssText
|
102 |
:param parentRule:
|
103 |
The CSS rule that contains this declaration block or
|
104 |
None if this CSSStyleDeclaration is not attached to a CSSRule.
|
105 |
:param readonly:
|
106 |
defaults to False
|
107 |
:param validating:
|
108 |
a flag defining if this sheet should be validated on change.
|
109 |
Defaults to None, which means defer to the parent stylesheet.
|
110 |
"""
|
111 |
super(CSSStyleDeclaration, self).__init__() |
112 |
self._parentRule = parentRule
|
113 |
self.validating = validating
|
114 |
self.cssText = cssText
|
115 |
self._readonly = readonly
|
116 |
|
117 |
def __contains__(self, nameOrProperty): |
118 |
"""Check if a property (or a property with given name) is in style.
|
119 |
|
120 |
:param name:
|
121 |
a string or Property, uses normalized name and not literalname
|
122 |
"""
|
123 |
if isinstance(nameOrProperty, Property): |
124 |
name = nameOrProperty.name |
125 |
else:
|
126 |
name = self._normalize(nameOrProperty)
|
127 |
return name in self.__nnames() |
128 |
|
129 |
def __iter__(self): |
130 |
"""Iterator of set Property objects with different normalized names."""
|
131 |
def properties(): |
132 |
for name in self.__nnames(): |
133 |
yield self.getProperty(name) |
134 |
return properties()
|
135 |
|
136 |
def keys(self): |
137 |
"""Analoguous to standard dict returns property names which are set in
|
138 |
this declaration."""
|
139 |
return list(self.__nnames()) |
140 |
|
141 |
def __getitem__(self, CSSName): |
142 |
"""Retrieve the value of property ``CSSName`` from this declaration.
|
143 |
|
144 |
``CSSName`` will be always normalized.
|
145 |
"""
|
146 |
return self.getPropertyValue(CSSName) |
147 |
|
148 |
def __setitem__(self, CSSName, value): |
149 |
"""Set value of property ``CSSName``. ``value`` may also be a tuple of
|
150 |
(value, priority), e.g. style['color'] = ('red', 'important')
|
151 |
|
152 |
``CSSName`` will be always normalized.
|
153 |
"""
|
154 |
priority = None
|
155 |
if isinstance(value, tuple): |
156 |
value, priority = value |
157 |
|
158 |
return self.setProperty(CSSName, value, priority) |
159 |
|
160 |
def __delitem__(self, CSSName): |
161 |
"""Delete property ``CSSName`` from this declaration.
|
162 |
If property is not in this declaration return u'' just like
|
163 |
removeProperty.
|
164 |
|
165 |
``CSSName`` will be always normalized.
|
166 |
"""
|
167 |
return self.removeProperty(CSSName) |
168 |
|
169 |
def __setattr__(self, n, v): |
170 |
"""Prevent setting of unknown properties on CSSStyleDeclaration
|
171 |
which would not work anyway. For these
|
172 |
``CSSStyleDeclaration.setProperty`` MUST be called explicitly!
|
173 |
|
174 |
TODO:
|
175 |
implementation of known is not really nice, any alternative?
|
176 |
"""
|
177 |
known = ['_tokenizer', '_log', '_ttypes', |
178 |
'_seq', 'seq', 'parentRule', '_parentRule', 'cssText', |
179 |
'valid', 'wellformed', 'validating', |
180 |
'_readonly', '_profiles', '_validating'] |
181 |
known.extend(CSS2Properties._properties) |
182 |
if n in known: |
183 |
super(CSSStyleDeclaration, self).__setattr__(n, v) |
184 |
else:
|
185 |
raise AttributeError(u'Unknown CSS Property, ' |
186 |
u'``CSSStyleDeclaration.setProperty("%s", '
|
187 |
u'...)`` MUST be used.' % n)
|
188 |
|
189 |
def __repr__(self): |
190 |
return u"cssutils.css.%s(cssText=%r)" % ( |
191 |
self.__class__.__name__,
|
192 |
self.getCssText(separator=u' ')) |
193 |
|
194 |
def __str__(self): |
195 |
return u"<cssutils.css.%s object length=%r (all: %r) at 0x%x>" % ( |
196 |
self.__class__.__name__,
|
197 |
self.length,
|
198 |
len(self.getProperties(all=True)), |
199 |
id(self)) |
200 |
|
201 |
def __nnames(self): |
202 |
"""Return iterator for all different names in order as set
|
203 |
if names are set twice the last one is used (double reverse!)
|
204 |
"""
|
205 |
names = [] |
206 |
for item in reversed(self.seq): |
207 |
val = item.value |
208 |
if isinstance(val, Property) and not val.name in names: |
209 |
names.append(val.name) |
210 |
return reversed(names) |
211 |
|
212 |
# overwritten accessor functions for CSS2Properties' properties
|
213 |
def _getP(self, CSSName): |
214 |
"""(DOM CSS2Properties) Overwritten here and effectively the same as
|
215 |
``self.getPropertyValue(CSSname)``.
|
216 |
|
217 |
Parameter is in CSSname format ('font-style'), see CSS2Properties.
|
218 |
|
219 |
Example::
|
220 |
|
221 |
>>> style = CSSStyleDeclaration(cssText='font-style:italic;')
|
222 |
>>> print style.fontStyle
|
223 |
italic
|
224 |
"""
|
225 |
return self.getPropertyValue(CSSName) |
226 |
|
227 |
def _setP(self, CSSName, value): |
228 |
"""(DOM CSS2Properties) Overwritten here and effectively the same as
|
229 |
``self.setProperty(CSSname, value)``.
|
230 |
|
231 |
Only known CSS2Properties may be set this way, otherwise an
|
232 |
AttributeError is raised.
|
233 |
For these unknown properties ``setPropertyValue(CSSname, value)``
|
234 |
has to be called explicitly.
|
235 |
Also setting the priority of properties needs to be done with a
|
236 |
call like ``setPropertyValue(CSSname, value, priority)``.
|
237 |
|
238 |
Example::
|
239 |
|
240 |
>>> style = CSSStyleDeclaration()
|
241 |
>>> style.fontStyle = 'italic'
|
242 |
>>> # or
|
243 |
>>> style.setProperty('font-style', 'italic', '!important')
|
244 |
|
245 |
"""
|
246 |
self.setProperty(CSSName, value)
|
247 |
# TODO: Shorthand ones
|
248 |
|
249 |
def _delP(self, CSSName): |
250 |
"""(cssutils only) Overwritten here and effectively the same as
|
251 |
``self.removeProperty(CSSname)``.
|
252 |
|
253 |
Example::
|
254 |
|
255 |
>>> style = CSSStyleDeclaration(cssText='font-style:italic;')
|
256 |
>>> del style.fontStyle
|
257 |
>>> print style.fontStyle
|
258 |
<BLANKLINE>
|
259 |
|
260 |
"""
|
261 |
self.removeProperty(CSSName)
|
262 |
|
263 |
def children(self): |
264 |
"""Generator yielding any known child in this declaration including
|
265 |
*all* properties, comments or CSSUnknownrules.
|
266 |
"""
|
267 |
for item in self._seq: |
268 |
yield item.value
|
269 |
|
270 |
def _getCssText(self): |
271 |
"""Return serialized property cssText."""
|
272 |
return cssutils.ser.do_css_CSSStyleDeclaration(self) |
273 |
|
274 |
def _setCssText(self, cssText): |
275 |
"""Setting this attribute will result in the parsing of the new value
|
276 |
and resetting of all the properties in the declaration block
|
277 |
including the removal or addition of properties.
|
278 |
|
279 |
:exceptions:
|
280 |
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
281 |
Raised if this declaration is readonly or a property is readonly.
|
282 |
- :exc:`~xml.dom.SyntaxErr`:
|
283 |
Raised if the specified CSS string value has a syntax error and
|
284 |
is unparsable.
|
285 |
"""
|
286 |
self._checkReadonly()
|
287 |
tokenizer = self._tokenize2(cssText)
|
288 |
|
289 |
# for closures: must be a mutable
|
290 |
new = {'wellformed': True} |
291 |
def ident(expected, seq, token, tokenizer=None): |
292 |
# a property
|
293 |
|
294 |
tokens = self._tokensupto2(tokenizer, starttoken=token,
|
295 |
semicolon=True)
|
296 |
if self._tokenvalue(tokens[-1]) == u';': |
297 |
tokens.pop() |
298 |
property = Property(parent=self)
|
299 |
property.cssText = tokens
|
300 |
if property.wellformed: |
301 |
seq.append(property, 'Property') |
302 |
else:
|
303 |
self._log.error(u'CSSStyleDeclaration: Syntax Error in ' |
304 |
u'Property: %s' % self._valuestr(tokens)) |
305 |
# does not matter in this case
|
306 |
return expected
|
307 |
|
308 |
def unexpected(expected, seq, token, tokenizer=None): |
309 |
# error, find next ; or } to omit upto next property
|
310 |
ignored = self._tokenvalue(token) + self._valuestr( |
311 |
self._tokensupto2(tokenizer,
|
312 |
propertyvalueendonly=True))
|
313 |
self._log.error(u'CSSStyleDeclaration: Unexpected token, ignoring ' |
314 |
'upto %r.' % ignored,token)
|
315 |
# does not matter in this case
|
316 |
return expected
|
317 |
|
318 |
def char(expected, seq, token, tokenizer=None): |
319 |
# a standalone ; or error...
|
320 |
if self._tokenvalue(token) == u';': |
321 |
self._log.info(u'CSSStyleDeclaration: Stripped standalone semicolon' |
322 |
u': %s' % self._valuestr([token]), neverraise=True) |
323 |
return expected
|
324 |
else:
|
325 |
return unexpected(expected, seq, token, tokenizer)
|
326 |
|
327 |
# [Property: Value;]* Property: Value?
|
328 |
newseq = self._tempSeq()
|
329 |
wellformed, expected = self._parse(expected=None, |
330 |
seq=newseq, tokenizer=tokenizer, |
331 |
productions={'IDENT': ident, 'CHAR': char}, |
332 |
default=unexpected) |
333 |
# wellformed set by parse
|
334 |
|
335 |
for item in newseq: |
336 |
item.value._parent = self
|
337 |
|
338 |
# do not check wellformed as invalid things are removed anyway
|
339 |
self._setSeq(newseq)
|
340 |
|
341 |
cssText = property(_getCssText, _setCssText,
|
342 |
doc=u"(DOM) A parsable textual representation of the "
|
343 |
u"declaration block excluding the surrounding curly "
|
344 |
u"braces.")
|
345 |
|
346 |
def getCssText(self, separator=None): |
347 |
"""
|
348 |
:returns:
|
349 |
serialized property cssText, each property separated by
|
350 |
given `separator` which may e.g. be ``u''`` to be able to use
|
351 |
cssText directly in an HTML style attribute. ``;`` is part of
|
352 |
each property (except the last one) and **cannot** be set with
|
353 |
separator!
|
354 |
"""
|
355 |
return cssutils.ser.do_css_CSSStyleDeclaration(self, separator) |
356 |
|
357 |
def _setParentRule(self, parentRule): |
358 |
self._parentRule = parentRule
|
359 |
# for x in self.children():
|
360 |
# x.parent = self
|
361 |
|
362 |
parentRule = property(lambda self: self._parentRule, _setParentRule, |
363 |
doc="(DOM) The CSS rule that contains this declaration block or "
|
364 |
"None if this CSSStyleDeclaration is not attached to a CSSRule.")
|
365 |
|
366 |
def getProperties(self, name=None, all=False): |
367 |
"""
|
368 |
:param name:
|
369 |
optional `name` of properties which are requested.
|
370 |
Only properties with this **always normalized** `name` are returned.
|
371 |
If `name` is ``None`` all properties are returned (at least one for
|
372 |
each set name depending on parameter `all`).
|
373 |
:param all:
|
374 |
if ``False`` (DEFAULT) only the effective properties are returned.
|
375 |
If name is given a list with only one property is returned.
|
376 |
|
377 |
if ``True`` all properties including properties set multiple times
|
378 |
with different values or priorities for different UAs are returned.
|
379 |
The order of the properties is fully kept as in the original
|
380 |
stylesheet.
|
381 |
:returns:
|
382 |
a list of :class:`~cssutils.css.Property` objects set in
|
383 |
this declaration.
|
384 |
"""
|
385 |
if name and not all: |
386 |
# single prop but list
|
387 |
p = self.getProperty(name)
|
388 |
if p:
|
389 |
return [p]
|
390 |
else:
|
391 |
return []
|
392 |
elif not all: |
393 |
# effective Properties in name order
|
394 |
return [self.getProperty(name) for name in self.__nnames()] |
395 |
else:
|
396 |
# all properties or all with this name
|
397 |
nname = self._normalize(name)
|
398 |
properties = [] |
399 |
for item in self.seq: |
400 |
val = item.value |
401 |
if isinstance(val, Property) and ( |
402 |
(bool(nname) == False) or (val.name == nname)): |
403 |
properties.append(val) |
404 |
return properties
|
405 |
|
406 |
def getProperty(self, name, normalize=True): |
407 |
"""
|
408 |
:param name:
|
409 |
of the CSS property, always lowercase (even if not normalized)
|
410 |
:param normalize:
|
411 |
if ``True`` (DEFAULT) name will be normalized (lowercase, no simple
|
412 |
escapes) so "color", "COLOR" or "C\olor" will all be equivalent
|
413 |
|
414 |
If ``False`` may return **NOT** the effective value but the
|
415 |
effective for the unnormalized name.
|
416 |
:returns:
|
417 |
the effective :class:`~cssutils.css.Property` object.
|
418 |
"""
|
419 |
nname = self._normalize(name)
|
420 |
found = None
|
421 |
for item in reversed(self.seq): |
422 |
val = item.value |
423 |
if isinstance(val, Property): |
424 |
if (normalize and nname == val.name) or name == val.literalname: |
425 |
if val.priority:
|
426 |
return val
|
427 |
elif not found: |
428 |
found = val |
429 |
return found
|
430 |
|
431 |
def getPropertyCSSValue(self, name, normalize=True): |
432 |
"""
|
433 |
:param name:
|
434 |
of the CSS property, always lowercase (even if not normalized)
|
435 |
:param normalize:
|
436 |
if ``True`` (DEFAULT) name will be normalized (lowercase, no simple
|
437 |
escapes) so "color", "COLOR" or "C\olor" will all be equivalent
|
438 |
|
439 |
If ``False`` may return **NOT** the effective value but the
|
440 |
effective for the unnormalized name.
|
441 |
:returns:
|
442 |
:class:`~cssutils.css.CSSValue`, the value of the effective
|
443 |
property if it has been explicitly set for this declaration block.
|
444 |
|
445 |
(DOM)
|
446 |
Used to retrieve the object representation of the value of a CSS
|
447 |
property if it has been explicitly set within this declaration
|
448 |
block. Returns None if the property has not been set.
|
449 |
|
450 |
(This method returns None if the property is a shorthand
|
451 |
property. Shorthand property values can only be accessed and
|
452 |
modified as strings, using the getPropertyValue and setProperty
|
453 |
methods.)
|
454 |
|
455 |
**cssutils currently always returns a CSSValue if the property is
|
456 |
set.**
|
457 |
|
458 |
for more on shorthand properties see
|
459 |
http://www.dustindiaz.com/css-shorthand/
|
460 |
"""
|
461 |
nname = self._normalize(name)
|
462 |
if nname in self._SHORTHANDPROPERTIES: |
463 |
self._log.info(u'CSSValue for shorthand property "%s" should be ' |
464 |
u'None, this may be implemented later.' %
|
465 |
nname, neverraise=True)
|
466 |
|
467 |
p = self.getProperty(name, normalize)
|
468 |
if p:
|
469 |
return p.propertyValue
|
470 |
else:
|
471 |
return None |
472 |
|
473 |
def getPropertyValue(self, name, normalize=True): |
474 |
"""
|
475 |
:param name:
|
476 |
of the CSS property, always lowercase (even if not normalized)
|
477 |
:param normalize:
|
478 |
if ``True`` (DEFAULT) name will be normalized (lowercase, no simple
|
479 |
escapes) so "color", "COLOR" or "C\olor" will all be equivalent
|
480 |
|
481 |
If ``False`` may return **NOT** the effective value but the
|
482 |
effective for the unnormalized name.
|
483 |
:returns:
|
484 |
the value of the effective property if it has been explicitly set
|
485 |
for this declaration block. Returns the empty string if the
|
486 |
property has not been set.
|
487 |
"""
|
488 |
p = self.getProperty(name, normalize)
|
489 |
if p:
|
490 |
return p.value
|
491 |
else:
|
492 |
return u'' |
493 |
|
494 |
def getPropertyPriority(self, name, normalize=True): |
495 |
"""
|
496 |
:param name:
|
497 |
of the CSS property, always lowercase (even if not normalized)
|
498 |
:param normalize:
|
499 |
if ``True`` (DEFAULT) name will be normalized (lowercase, no simple
|
500 |
escapes) so "color", "COLOR" or "C\olor" will all be equivalent
|
501 |
|
502 |
If ``False`` may return **NOT** the effective value but the
|
503 |
effective for the unnormalized name.
|
504 |
:returns:
|
505 |
the priority of the effective CSS property (e.g. the
|
506 |
"important" qualifier) if the property has been explicitly set in
|
507 |
this declaration block. The empty string if none exists.
|
508 |
"""
|
509 |
p = self.getProperty(name, normalize)
|
510 |
if p:
|
511 |
return p.priority
|
512 |
else:
|
513 |
return u'' |
514 |
|
515 |
def removeProperty(self, name, normalize=True): |
516 |
"""
|
517 |
(DOM)
|
518 |
Used to remove a CSS property if it has been explicitly set within
|
519 |
this declaration block.
|
520 |
|
521 |
:param name:
|
522 |
of the CSS property
|
523 |
:param normalize:
|
524 |
if ``True`` (DEFAULT) name will be normalized (lowercase, no simple
|
525 |
escapes) so "color", "COLOR" or "C\olor" will all be equivalent.
|
526 |
The effective Property value is returned and *all* Properties
|
527 |
with ``Property.name == name`` are removed.
|
528 |
|
529 |
If ``False`` may return **NOT** the effective value but the
|
530 |
effective for the unnormalized `name` only. Also only the
|
531 |
Properties with the literal name `name` are removed.
|
532 |
:returns:
|
533 |
the value of the property if it has been explicitly set for
|
534 |
this declaration block. Returns the empty string if the property
|
535 |
has not been set or the property name does not correspond to a
|
536 |
known CSS property
|
537 |
|
538 |
|
539 |
:exceptions:
|
540 |
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
541 |
Raised if this declaration is readonly or the property is
|
542 |
readonly.
|
543 |
"""
|
544 |
self._checkReadonly()
|
545 |
r = self.getPropertyValue(name, normalize=normalize)
|
546 |
newseq = self._tempSeq()
|
547 |
if normalize:
|
548 |
# remove all properties with name == nname
|
549 |
nname = self._normalize(name)
|
550 |
for item in self.seq: |
551 |
if not (isinstance(item.value, Property) |
552 |
and item.value.name == nname):
|
553 |
newseq.appendItem(item) |
554 |
else:
|
555 |
# remove all properties with literalname == name
|
556 |
for item in self.seq: |
557 |
if not (isinstance(item.value, Property) |
558 |
and item.value.literalname == name):
|
559 |
newseq.appendItem(item) |
560 |
self._setSeq(newseq)
|
561 |
return r
|
562 |
|
563 |
def setProperty(self, name, value=None, priority=u'', |
564 |
normalize=True, replace=True): |
565 |
"""(DOM) Set a property value and priority within this declaration
|
566 |
block.
|
567 |
|
568 |
:param name:
|
569 |
of the CSS property to set (in W3C DOM the parameter is called
|
570 |
"propertyName"), always lowercase (even if not normalized)
|
571 |
|
572 |
If a property with this `name` is present it will be reset.
|
573 |
|
574 |
cssutils also allowed `name` to be a
|
575 |
:class:`~cssutils.css.Property` object, all other
|
576 |
parameter are ignored in this case
|
577 |
|
578 |
:param value:
|
579 |
the new value of the property, ignored if `name` is a Property.
|
580 |
:param priority:
|
581 |
the optional priority of the property (e.g. "important"),
|
582 |
ignored if `name` is a Property.
|
583 |
:param normalize:
|
584 |
if True (DEFAULT) `name` will be normalized (lowercase, no simple
|
585 |
escapes) so "color", "COLOR" or "C\olor" will all be equivalent
|
586 |
:param replace:
|
587 |
if True (DEFAULT) the given property will replace a present
|
588 |
property. If False a new property will be added always.
|
589 |
The difference to `normalize` is that two or more properties with
|
590 |
the same name may be set, useful for e.g. stuff like::
|
591 |
|
592 |
background: red;
|
593 |
background: rgba(255, 0, 0, 0.5);
|
594 |
|
595 |
which defines the same property but only capable UAs use the last
|
596 |
property value, older ones use the first value.
|
597 |
|
598 |
:exceptions:
|
599 |
- :exc:`~xml.dom.SyntaxErr`:
|
600 |
Raised if the specified value has a syntax error and is
|
601 |
unparsable.
|
602 |
- :exc:`~xml.dom.NoModificationAllowedErr`:
|
603 |
Raised if this declaration is readonly or the property is
|
604 |
readonly.
|
605 |
"""
|
606 |
self._checkReadonly()
|
607 |
|
608 |
if isinstance(name, Property): |
609 |
newp = name |
610 |
name = newp.literalname |
611 |
elif not value: |
612 |
# empty string or None effectively removed property
|
613 |
return self.removeProperty(name) |
614 |
else:
|
615 |
newp = Property(name, value, priority) |
616 |
|
617 |
if newp.wellformed:
|
618 |
if replace:
|
619 |
# check if update
|
620 |
nname = self._normalize(name)
|
621 |
properties = self.getProperties(name, all=(not normalize)) |
622 |
for property in reversed(properties): |
623 |
if normalize and property.name == nname: |
624 |
property.propertyValue = newp.propertyValue.cssText
|
625 |
property.priority = newp.priority
|
626 |
return
|
627 |
elif property.literalname == name: |
628 |
property.propertyValue = newp.propertyValue.cssText
|
629 |
property.priority = newp.priority
|
630 |
return
|
631 |
|
632 |
# not yet set or forced omit replace
|
633 |
newp.parent = self
|
634 |
self.seq._readonly = False |
635 |
self.seq.append(newp, 'Property') |
636 |
self.seq._readonly = True |
637 |
|
638 |
else:
|
639 |
self._log.warn(u'Invalid Property: %s: %s %s' |
640 |
% (name, value, priority)) |
641 |
|
642 |
def item(self, index): |
643 |
"""(DOM) Retrieve the properties that have been explicitly set in
|
644 |
this declaration block. The order of the properties retrieved using
|
645 |
this method does not have to be the order in which they were set.
|
646 |
This method can be used to iterate over all properties in this
|
647 |
declaration block.
|
648 |
|
649 |
:param index:
|
650 |
of the property to retrieve, negative values behave like
|
651 |
negative indexes on Python lists, so -1 is the last element
|
652 |
|
653 |
:returns:
|
654 |
the name of the property at this ordinal position. The
|
655 |
empty string if no property exists at this position.
|
656 |
|
657 |
**ATTENTION:**
|
658 |
Only properties with different names are counted. If two
|
659 |
properties with the same name are present in this declaration
|
660 |
only the effective one is included.
|
661 |
|
662 |
:meth:`item` and :attr:`length` work on the same set here.
|
663 |
"""
|
664 |
names = list(self.__nnames()) |
665 |
try:
|
666 |
return names[index]
|
667 |
except IndexError: |
668 |
return u'' |
669 |
|
670 |
length = property(lambda self: len(list(self.__nnames())), |
671 |
doc=u"(DOM) The number of distinct properties that have "
|
672 |
u"been explicitly in this declaration block. The "
|
673 |
u"range of valid indices is 0 to length-1 inclusive. "
|
674 |
u"These are properties with a different ``name`` "
|
675 |
u"only. :meth:`item` and :attr:`length` work on the "
|
676 |
u"same set here.")
|
677 |
|
678 |
def _getValidating(self): |
679 |
try:
|
680 |
# CSSParser.parseX() sets validating of stylesheet
|
681 |
return self.parentRule.parentStyleSheet.validating |
682 |
except AttributeError: |
683 |
# CSSParser.parseStyle() sets validating of declaration
|
684 |
if self._validating is not None: |
685 |
return self._validating |
686 |
# default
|
687 |
return True |
688 |
|
689 |
def _setValidating(self, validating): |
690 |
self._validating = validating
|
691 |
|
692 |
validating = property(_getValidating, _setValidating,
|
693 |
doc=u"If ``True`` this declaration validates "
|
694 |
u"contained properties. The parent StyleSheet "
|
695 |
u"validation setting does *always* win though so "
|
696 |
u"even if validating is True it may not validate "
|
697 |
u"if the StyleSheet defines else!")
|