Package cssutils :: Package css :: Module cssproperties
[hide private]
[frames] | no frames]

Source Code for Module cssutils.css.cssproperties

  1  """CSS2Properties (partly!) implements DOM Level 2 CSS CSS2Properties used 
  2  by CSSStyleDeclaration 
  3   
  4  TODO: CSS2Properties 
  5      If an implementation does implement this interface, it is expected to 
  6      understand the specific syntax of the shorthand properties, and apply 
  7      their semantics; when the margin property is set, for example, the 
  8      marginTop, marginRight, marginBottom and marginLeft properties are 
  9      actually being set by the underlying implementation. 
 10   
 11      When dealing with CSS "shorthand" properties, the shorthand properties 
 12      should be decomposed into their component longhand properties as 
 13      appropriate, and when querying for their value, the form returned 
 14      should be the shortest form exactly equivalent to the declarations made 
 15      in the ruleset. However, if there is no shorthand declaration that 
 16      could be added to the ruleset without changing in any way the rules 
 17      already declared in the ruleset (i.e., by adding longhand rules that 
 18      were previously not declared in the ruleset), then the empty string 
 19      should be returned for the shorthand property. 
 20   
 21      For example, querying for the font property should not return 
 22      "normal normal normal 14pt/normal Arial, sans-serif", when 
 23      "14pt Arial, sans-serif" suffices. (The normals are initial values, and 
 24      are implied by use of the longhand property.) 
 25   
 26      If the values for all the longhand properties that compose a particular 
 27      string are the initial values, then a string consisting of all the 
 28      initial values should be returned (e.g. a border-width value of 
 29      "medium" should be returned as such, not as ""). 
 30   
 31      For some shorthand properties that take missing values from other 
 32      sides, such as the margin, padding, and border-[width|style|color] 
 33      properties, the minimum number of sides possible should be used; i.e., 
 34      "0px 10px" will be returned instead of "0px 10px 0px 10px". 
 35   
 36      If the value of a shorthand property can not be decomposed into its 
 37      component longhand properties, as is the case for the font property 
 38      with a value of "menu", querying for the values of the component 
 39      longhand properties should return the empty string. 
 40   
 41  TODO: CSS2Properties DOMImplementation 
 42      The interface found within this section are not mandatory. A DOM 
 43      application can use the hasFeature method of the DOMImplementation 
 44      interface to determine whether it is supported or not. The feature 
 45      string for this extended interface listed in this section is "CSS2" 
 46      and the version is "2.0". 
 47   
 48   
 49  cssvalues 
 50  ========= 
 51  contributed by Kevin D. Smith, thanks! 
 52   
 53  "cssvalues" is used as a property validator. 
 54  it is an importable object that contains a dictionary of compiled regular 
 55  expressions.  The keys of this dictionary are all of the valid CSS property 
 56  names.  The values are compiled regular expressions that can be used to 
 57  validate the values for that property. (Actually, the values are references 
 58  to the 'match' method of a compiled regular expression, so that they are 
 59  simply called like functions.) 
 60   
 61  """ 
 62  __all__ = ['CSS2Properties', 'cssvalues'] 
 63  __docformat__ = 'restructuredtext' 
 64  __author__ = '$LastChangedBy: doerwalter $' 
 65  __date__ = '$LastChangedDate: 2007-08-02 22:58:23 +0200 (Do, 02 Aug 2007) $' 
 66  __version__ = '0.9.2b3, $LastChangedRevision: 160 $' 
 67   
 68  import re 
 69   
 70   
 71  """ 
 72  Define some regular expression fragments that will be used as 
 73  macros within the CSS property value regular expressions. 
 74  """ 
 75  MACROS = { 
 76      'ident': r'[-]?{nmstart}{nmchar}*', 
 77      'name': r'{nmchar}+', 
 78      'nmstart': r'[_a-z]|{nonascii}|{escape}', 
 79      'nonascii': r'[^\0-\177]', 
 80      'unicode': r'\\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?', 
 81      'escape': r'{unicode}|\\[ -~\200-\777]', 
 82  #   'escape': r'{unicode}|\\[ -~\200-\4177777]', 
 83      'int': r'[-]?\d+', 
 84      'nmchar': r'[\w-]|{nonascii}|{escape}', 
 85      'num': r'[-]?\d+|[-]?\d*\.\d+', 
 86      'number': r'{num}', 
 87      'string': r'{string1}|{string2}', 
 88      'string1': r'"(\\\"|[^\"])*"', 
 89      'string2': r"'(\\\'|[^\'])*'", 
 90      'nl': r'\n|\r\n|\r|\f', 
 91      'w': r'\s*', 
 92   
 93      'integer': r'{int}', 
 94      'length': r'0|{num}(em|ex|px|in|cm|mm|pt|pc)', 
 95      'angle': r'0|{num}(deg|grad|rad)', 
 96      'time': r'0|{num}m?s', 
 97      'frequency': r'0|{num}k?Hz', 
 98      'color': r'(maroon|red|orange|yellow|olive|purple|fuchsia|white|lime|green|navy|blue|aqua|teal|black|silver|gray|ActiveBorder|ActiveCaption|AppWorkspace|Background|ButtonFace|ButtonHighlight|ButtonShadow|ButtonText|CaptionText|GrayText|Highlight|HighlightText|InactiveBorder|InactiveCaption|InactiveCaptionText|InfoBackground|InfoText|Menu|MenuText|Scrollbar|ThreeDDarkShadow|ThreeDFace|ThreeDHighlight|ThreeDLightShadow|ThreeDShadow|Window|WindowFrame|WindowText)|#[0-9a-f]{3}|#[0-9a-f]{6}|rgb\({w}{int}{w},{w}{int}{w},{w}{int}{w}\)|rgb\({w}{num}%{w},{w}{num}%{w},{w}{num}%{w}\)', 
 99      'uri': r'url\({w}({string}|(\\\)|[^\)])+){w}\)', 
100      'percentage': r'{num}%', 
101      'border-style': 'none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset', 
102      'border-color': '{color}', 
103      'border-width': '{length}|thin|medium|thick', 
104   
105      'background-color': r'{color}|transparent|inherit', 
106      'background-image': r'{uri}|none|inherit', 
107   
108      'background-position': r'(({percentage}|{length}|left|center|right)(\s*{percentage}|{length}|top|center|bottom)?)|(left|center|right|top|center|bottom)(\s*(left|center|right|top|center|bottom))?|inherit', 
109      'background-repeat': r'repeat|repeat-x|repeat-y|no-repeat|inherit', 
110      'background-attachment': r'scroll|fixed|inherit', 
111   
112      'shape': r'rect\(({w}({length}|auto}){w},){3}{w}({length}|auto){w}\)', 
113      'counter': r'counter\({w}{identifier}{w}(?:,{w}{list-style-type}{w})?\)', 
114      'identifier': r'{ident}', 
115      'family-name': r'{string}|{identifier}', 
116      'generic-family': r'serif|sans-serif|cursive|fantasy|monospace', 
117      'absolute-size': r'(x?x-)?(small|large)|medium', 
118      'relative-size': r'smaller|larger', 
119      'font-family': r'(({family-name}|{generic-family}){w},{w})*({family-name}|{generic-family})|inherit', 
120      'font-size': r'{absolute-size}|{relative-size}|{length}|{percentage}|inherit', 
121      'font-style': r'normal|italic|oblique|inherit', 
122      'font-variant': r'normal|small-caps|inherit', 
123      'font-weight': r'normal|bold|bolder|lighter|[1-9]00|inherit', 
124      'line-height': r'normal|{number}|{length}|{percentage}|inherit', 
125      'list-style-image': r'{uri}|none|inherit', 
126      'list-style-position': r'inside|outside|inherit', 
127      'list-style-type': r'disc|circle|square|decimal|decimal-leading-zero|lower-roman|upper-roman|lower-greek|lower-(latin|alpha)|upper-(latin|alpha)|armenian|georgian|none|inherit', 
128      'margin-width': r'{length}|{percentage}|auto', 
129      'outline-color': r'{color}|invert|inherit', 
130      'outline-style': r'{border-style}|inherit', 
131      'outline-width': r'{border-width}|inherit', 
132      'padding-width': r'{length}|{percentage}', 
133      'specific-voice': r'{identifier}', 
134      'generic-voice': r'male|female|child', 
135      'content': r'{string}|{uri}|{counter}|attr\({w}{identifier}{w}\)|open-quote|close-quote|no-open-quote|no-close-quote', 
136      'border-attrs': r'{border-width}|{border-style}|{border-color}', 
137      'background-attrs': r'{background-color}|{background-image}|{background-repeat}|{background-attachment}|{background-position}', 
138      'list-attrs': r'{list-style-type}|{list-style-position}|{list-style-image}', 
139      'font-attrs': r'{font-style}|{font-variant}|{font-weight}', 
140      'outline-attrs': r'{outline-color}|{outline-style}|{outline-width}', 
141      'text-attrs': r'underline|overline|line-through|blink', 
142  } 
143   
144  """ 
145  Define the regular expressions for validation all CSS values 
146  """ 
147  cssvalues = { 
148      'azimuth': r'{angle}|(behind\s+)?(left-side|far-left|left|center-left|center|center-right|right|far-right|right-side)(\s+behind)?|behind|leftwards|rightwards|inherit', 
149      'background-attachment': r'{background-attachment}', 
150      'background-color': r'{background-color}', 
151      'background-image': r'{background-image}', 
152      'background-position': r'{background-position}', 
153      'background-repeat': r'{background-repeat}', 
154      # Each piece should only be allowed one time 
155      'background': r'{background-attrs}(\s+{background-attrs})*|inherit', 
156      'border-collapse': r'collapse|separate|inherit', 
157      'border-color': r'({border-color}|transparent)(\s+({border-color}|transparent)){0,3}|inherit', 
158      'border-spacing': r'{length}(\s+{length})?|inherit', 
159      'border-style': r'{border-style}(\s+{border-style}){0,3}|inherit', 
160      'border-top': r'{border-attrs}(\s+{border-attrs})*|inherit', 
161      'border-right': r'{border-attrs}(\s+{border-attrs})*|inherit', 
162      'border-bottom': r'{border-attrs}(\s+{border-attrs})*|inherit', 
163      'border-left': r'{border-attrs}(\s+{border-attrs})*|inherit', 
164      'border-top-color': r'{border-color}|transparent|inherit', 
165      'border-right-color': r'{border-color}|transparent|inherit', 
166      'border-bottom-color': r'{border-color}|transparent|inherit', 
167      'border-left-color': r'{border-color}|transparent|inherit', 
168      'border-top-style': r'{border-style}|inherit', 
169      'border-right-style': r'{border-style}|inherit', 
170      'border-bottom-style': r'{border-style}|inherit', 
171      'border-left-style': r'{border-style}|inherit', 
172      'border-top-width': r'{border-width}|inherit', 
173      'border-right-width': r'{border-width}|inherit', 
174      'border-bottom-width': r'{border-width}|inherit', 
175      'border-right-width': r'{border-width}|inherit', 
176      'border-width': r'{border-width}(\s+{border-width}){0,3}|inherit', 
177      'border': r'{border-attrs}(\s+{border-attrs})*|inherit', 
178      'bottom': r'{length}|{percentage}|auto|inherit', 
179      'caption-side': r'top|bottom|inherit', 
180      'clear': r'none|left|right|both|inherit', 
181      'clip': r'{shape}|auto|inherit', 
182      'color': r'{color}|inherit', 
183      'content': r'normal|{content}(\s+{content})*|inherit', 
184      'counter-increment': r'({identifier}(\s+{integer})?)(\s+({identifier}(\s+{integer})))*|none|inherit', 
185      'counter-reset': r'({identifier}(\s+{integer})?)(\s+({identifier}(\s+{integer})))*|none|inherit', 
186      'cue-after': r'{uri}|none|inherit', 
187      'cue-before': r'{uri}|none|inherit', 
188      'cue': r'({uri}|none|inherit){1,2}|inherit', 
189      'cursor': r'((({uri}{w},{w})*)?(auto|crosshair|default|pointer|move|(e|ne|nw|n|se|sw|s|w)-resize|text|wait|help|progress))|inherit', 
190      'direction': r'ltr|rtl|inherit', 
191      'display': r'inline|block|list-item|run-in|inline-block|table|inline-table|table-row-group|table-header-group|table-footer-group|table-row|table-column-group|table-column|table-cell|table-caption|none|inherit', 
192      'elevation': r'{angle}|below|level|above|higher|lower|inherit', 
193      'empty-cells': r'show|hide|inherit', 
194      'float': r'left|right|none|inherit', 
195      'font-family': r'{font-family}', 
196      'font-size': r'{font-size}', 
197      'font-style': r'{font-style}', 
198      'font-variant': r'{font-variant}', 
199      'font-weight': r'{font-weight}', 
200      'font': r'({font-attrs}\s+)*{font-size}({w}/{w}{line-height})?\s+{font-family}|caption|icon|menu|message-box|small-caption|status-bar|inherit', 
201      'height': r'{length}|{percentage}|auto|inherit', 
202      'left': r'{length}|{percentage}|auto|inherit', 
203      'letter-spacing': r'normal|{length}|inherit', 
204      'line-height': r'{line-height}', 
205      'list-style-image': r'{list-style-image}', 
206      'list-style-position': r'{list-style-position}', 
207      'list-style-type': r'{list-style-type}', 
208      'list-style': r'{list-attrs}(\s+{list-attrs})*|inherit', 
209      'margin-right': r'{margin-width}|inherit', 
210      'margin-left': r'{margin-width}|inherit', 
211      'margin-top': r'{margin-width}|inherit', 
212      'margin-bottom': r'{margin-width}|inherit', 
213      'margin': r'{margin-width}(\s+{margin-width}){0,3}|inherit', 
214      'max-height': r'{length}|{percentage}|none|inherit', 
215      'max-width': r'{length}|{percentage}|none|inherit', 
216      'min-height': r'{length}|{percentage}|none|inherit', 
217      'min-width': r'{length}|{percentage}|none|inherit', 
218      'orphans': r'{integer}|inherit', 
219      'outline-color': r'{outline-color}', 
220      'outline-style': r'{outline-style}', 
221      'outline-width': r'{outline-width}', 
222      'outline': r'{outline-attrs}(\s+{outline-attrs})*|inherit', 
223      'overflow': r'visible|hidden|scroll|auto|inherit', 
224      'padding-top': r'{padding-width}|inherit', 
225      'padding-right': r'{padding-width}|inherit', 
226      'padding-bottom': r'{padding-width}|inherit', 
227      'padding-left': r'{padding-width}|inherit', 
228      'padding': r'{padding-width}(\s+{padding-width}){0,3}|inherit', 
229      'page-break-after': r'auto|always|avoid|left|right|inherit', 
230      'page-break-before': r'auto|always|avoid|left|right|inherit', 
231      'page-break-inside': r'avoid|auto|inherit', 
232      'pause-after': r'{time}|{percentage}|inherit', 
233      'pause-before': r'{time}|{percentage}|inherit', 
234      'pause': r'({time}|{percentage}){1,2}|inherit', 
235      'pitch-range': r'{number}|inherit', 
236      'pitch': r'{frequency}|x-low|low|medium|high|x-high|inherit', 
237      'play-during': r'{uri}(\s+(mix|repeat))*|auto|none|inherit', 
238      'position': r'static|relative|absolute|fixed|inherit', 
239      'quotes': r'({string}\s+{string})(\s+{string}\s+{string})*|none|inherit', 
240      'richness': r'{number}|inherit', 
241      'right': r'{length}|{percentage}|auto|inherit', 
242      'speak-header': r'once|always|inherit', 
243      'speak-numeral': r'digits|continuous|inherit', 
244      'speak-punctuation': r'code|none|inherit', 
245      'speak': r'normal|none|spell-out|inherit', 
246      'speech-rate': r'{number}|x-slow|slow|medium|fast|x-fast|faster|slower|inherit', 
247      'stress': r'{number}|inherit', 
248      'table-layout': r'auto|fixed|inherit', 
249      'text-align': r'left|right|center|justify|inherit', 
250      'text-decoration': r'none|{text-attrs}(\s+{text-attrs})*|inherit', 
251      'text-indent': r'{length}|{percentage}|inherit', 
252      'text-transform': r'capitalize|uppercase|lowercase|none|inherit', 
253      'top': r'{length}|{percentage}|auto|inherit', 
254      'unicode-bidi': r'normal|embed|bidi-override|inherit', 
255      'vertical-align': r'baseline|sub|super|top|text-top|middle|bottom|text-bottom|{percentage}|{length}|inherit', 
256      'visibility': r'visible|hidden|collapse|inherit', 
257      'voice-family': r'({specific-voice}|{generic-voice}{w},{w})*({specific-voice}|{generic-voice})|inherit', 
258      'volume': r'{number}|{percentage}|silent|x-soft|soft|medium|loud|x-loud|inherit', 
259      'white-space': r'normal|pre|nowrap|pre-wrap|pre-line|inherit', 
260      'widows': r'{integer}|inherit', 
261      'width': r'{length}|{percentage}|auto|inherit', 
262      'word-spacing': r'normal|{length}|inherit', 
263      'z-index': r'auto|{integer}|inherit', 
264  } 
265   
266 -def _expand_macros(tokdict):
267 """ Expand macros in token dictionary """ 268 def macro_value(m): 269 return '(?:%s)' % MACROS[m.groupdict()['macro']]
270 for key, value in tokdict.items(): 271 while re.search(r'{[a-z][a-z0-9-]*}', value): 272 value = re.sub(r'{(?P<macro>[a-z][a-z0-9-]*)}', 273 macro_value, value) 274 tokdict[key] = value 275 return tokdict 276
277 -def _compile_regexes(tokdict):
278 """ Compile all regular expressions into callable objects """ 279 for key, value in tokdict.items(): 280 tokdict[key] = re.compile('^(?:%s)$' % value, re.I).match 281 return tokdict
282 283 _compile_regexes(_expand_macros(cssvalues)) 284 285 286 # functions to convert between CSS and DOM name 287 288 _reCSStoDOMname = re.compile('-[a-z]', re.I)
289 -def _toDOMname(CSSname):
290 """ 291 returns DOMname for given CSSname e.g. for CSSname 'font-style' returns 292 'fontStyle' 293 """ 294 def _doCSStoDOMname2(m): return m.group(0)[1].capitalize() 295 return _reCSStoDOMname.sub(_doCSStoDOMname2, CSSname)
296 297 _reDOMtoCSSname = re.compile('([A-Z])[a-z]+')
298 -def _toCSSname(DOMname):
299 """ 300 returns CSSname for given DOMname e.g. for DOMname 'fontStyle' returns 301 'font-style' 302 """ 303 def _doDOMtoCSSname2(m): return '-' + m.group(0).lower() 304 return _reDOMtoCSSname.sub(_doDOMtoCSSname2, DOMname)
305 306
307 -class CSS2Properties(object):
308 """ 309 The CSS2Properties interface represents a convenience mechanism 310 for retrieving and setting properties within a CSSStyleDeclaration. 311 The attributes of this interface correspond to all the properties 312 specified in CSS2. Getting an attribute of this interface is 313 equivalent to calling the getPropertyValue method of the 314 CSSStyleDeclaration interface. Setting an attribute of this 315 interface is equivalent to calling the setProperty method of the 316 CSSStyleDeclaration interface. 317 318 cssutils actually also allows usage of ``del`` to remove a CSS property 319 from a CSSStyleDeclaration. 320 321 This is an abstract class, the following functions need to be present 322 in inheriting class: 323 324 - ``_getP`` 325 - ``_setP`` 326 - ``_delP`` 327 """ 328 # actual properties are set after the class definition!
329 - def _getP(self, CSSname): pass
330 - def _setP(self, CSSname, value): pass
331 - def _delP(self, CSSname): pass
332 333 334 # add list of DOMname properties to CSS2Properties 335 # used for CSSStyleDeclaration to check if allowed properties 336 # but somehow doubled, any better way? 337 CSS2Properties._properties = [_toDOMname(p) for p in cssvalues.keys()] 338 339 # add CSS2Properties to CSSStyleDeclaration:
340 -def __named_property_def(DOMname):
341 """ 342 closure to keep name known in each properties accessor function 343 DOMname is converted to CSSname here, so actual calls use CSSname 344 """ 345 CSSname = _toCSSname(DOMname) 346 def _get(self): return self._getP(CSSname) 347 def _set(self, value): self._setP(CSSname, value) 348 def _del(self): self._delP(CSSname) 349 return _get, _set, _del
350 351 # add all CSS2Properties to CSSStyleDeclaration 352 for DOMname in CSS2Properties._properties: 353 setattr(CSS2Properties, DOMname, 354 property(*__named_property_def(DOMname))) 355 356 357 358 if __name__=='__main__': 359 c = CSS2Properties() 360 print CSS2Properties.color 361 ## #print type(CSS2Properties.color) 362 ## c.color = 'green' 363 ## #print type(CSS2Properties.color), c.color 364 ## print c.color 365 ## del c.color 366 ## #print type(CSS2Properties.color), c.color 367