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  __version__ = '$Id: cssproperties.py 1116 2008-03-05 13:52:23Z cthedot $' 
 65   
 66  import re 
 67   
 68  """ 
 69  Define some regular expression fragments that will be used as 
 70  macros within the CSS property value regular expressions. 
 71  """ 
 72  MACROS = { 
 73      'ident': r'[-]?{nmstart}{nmchar}*', 
 74      'name': r'{nmchar}+', 
 75      'nmstart': r'[_a-z]|{nonascii}|{escape}', 
 76      'nonascii': r'[^\0-\177]', 
 77      'unicode': r'\\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?', 
 78      'escape': r'{unicode}|\\[ -~\200-\777]', 
 79  #   'escape': r'{unicode}|\\[ -~\200-\4177777]', 
 80      'int': r'[-]?\d+', 
 81      'nmchar': r'[\w-]|{nonascii}|{escape}', 
 82      'num': r'[-]?\d+|[-]?\d*\.\d+', 
 83      'number': r'{num}', 
 84      'string': r'{string1}|{string2}', 
 85      'string1': r'"(\\\"|[^\"])*"', 
 86      'string2': r"'(\\\'|[^\'])*'", 
 87      'nl': r'\n|\r\n|\r|\f', 
 88      'w': r'\s*', 
 89   
 90      'integer': r'{int}', 
 91      'length': r'0|{num}(em|ex|px|in|cm|mm|pt|pc)', 
 92      'angle': r'0|{num}(deg|grad|rad)', 
 93      'time': r'0|{num}m?s', 
 94      'frequency': r'0|{num}k?Hz', 
 95      '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}\)', 
 96      'uri': r'url\({w}({string}|(\\\)|[^\)])+){w}\)', 
 97      'percentage': r'{num}%', 
 98      'border-style': 'none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset', 
 99      'border-color': '{color}', 
100      'border-width': '{length}|thin|medium|thick', 
101   
102      'background-color': r'{color}|transparent|inherit', 
103      'background-image': r'{uri}|none|inherit', 
104      'background-position': r'({percentage}|{length})(\s*({percentage}|{length}))?|((top|center|bottom)\s*(left|center|right))|((left|center|right)\s*(top|center|bottom))|inherit', 
105      'background-repeat': r'repeat|repeat-x|repeat-y|no-repeat|inherit', 
106      'background-attachment': r'scroll|fixed|inherit', 
107   
108      'shape': r'rect\(({w}({length}|auto}){w},){3}{w}({length}|auto){w}\)', 
109      'counter': r'counter\({w}{identifier}{w}(?:,{w}{list-style-type}{w})?\)', 
110      'identifier': r'{ident}', 
111      'family-name': r'{string}|{identifier}', 
112      'generic-family': r'serif|sans-serif|cursive|fantasy|monospace', 
113      'absolute-size': r'(x?x-)?(small|large)|medium', 
114      'relative-size': r'smaller|larger', 
115      'font-family': r'(({family-name}|{generic-family}){w},{w})*({family-name}|{generic-family})|inherit', 
116      'font-size': r'{absolute-size}|{relative-size}|{length}|{percentage}|inherit', 
117      'font-style': r'normal|italic|oblique|inherit', 
118      'font-variant': r'normal|small-caps|inherit', 
119      'font-weight': r'normal|bold|bolder|lighter|[1-9]00|inherit', 
120      'line-height': r'normal|{number}|{length}|{percentage}|inherit', 
121      'list-style-image': r'{uri}|none|inherit', 
122      'list-style-position': r'inside|outside|inherit', 
123      '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', 
124      'margin-width': r'{length}|{percentage}|auto', 
125      'outline-color': r'{color}|invert|inherit', 
126      'outline-style': r'{border-style}|inherit', 
127      'outline-width': r'{border-width}|inherit', 
128      'padding-width': r'{length}|{percentage}', 
129      'specific-voice': r'{identifier}', 
130      'generic-voice': r'male|female|child', 
131      'content': r'{string}|{uri}|{counter}|attr\({w}{identifier}{w}\)|open-quote|close-quote|no-open-quote|no-close-quote', 
132      'border-attrs': r'{border-width}|{border-style}|{border-color}', 
133      'background-attrs': r'{background-color}|{background-image}|{background-repeat}|{background-attachment}|{background-position}', 
134      'list-attrs': r'{list-style-type}|{list-style-position}|{list-style-image}', 
135      'font-attrs': r'{font-style}|{font-variant}|{font-weight}', 
136      'outline-attrs': r'{outline-color}|{outline-style}|{outline-width}', 
137      'text-attrs': r'underline|overline|line-through|blink', 
138  } 
139   
140  """ 
141  Define the regular expressions for validation all CSS values 
142  """ 
143  cssvalues = { 
144      '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', 
145      'background-attachment': r'{background-attachment}', 
146      'background-color': r'{background-color}', 
147      'background-image': r'{background-image}', 
148      'background-position': r'{background-position}', 
149      'background-repeat': r'{background-repeat}', 
150      # Each piece should only be allowed one time 
151      'background': r'{background-attrs}(\s+{background-attrs})*|inherit', 
152      'border-collapse': r'collapse|separate|inherit', 
153      'border-color': r'({border-color}|transparent)(\s+({border-color}|transparent)){0,3}|inherit', 
154      'border-spacing': r'{length}(\s+{length})?|inherit', 
155      'border-style': r'{border-style}(\s+{border-style}){0,3}|inherit', 
156      'border-top': r'{border-attrs}(\s+{border-attrs})*|inherit', 
157      'border-right': r'{border-attrs}(\s+{border-attrs})*|inherit', 
158      'border-bottom': r'{border-attrs}(\s+{border-attrs})*|inherit', 
159      'border-left': r'{border-attrs}(\s+{border-attrs})*|inherit', 
160      'border-top-color': r'{border-color}|transparent|inherit', 
161      'border-right-color': r'{border-color}|transparent|inherit', 
162      'border-bottom-color': r'{border-color}|transparent|inherit', 
163      'border-left-color': r'{border-color}|transparent|inherit', 
164      'border-top-style': r'{border-style}|inherit', 
165      'border-right-style': r'{border-style}|inherit', 
166      'border-bottom-style': r'{border-style}|inherit', 
167      'border-left-style': r'{border-style}|inherit', 
168      'border-top-width': r'{border-width}|inherit', 
169      'border-right-width': r'{border-width}|inherit', 
170      'border-bottom-width': r'{border-width}|inherit', 
171      'border-right-width': r'{border-width}|inherit', 
172      'border-width': r'{border-width}(\s+{border-width}){0,3}|inherit', 
173      'border': r'{border-attrs}(\s+{border-attrs})*|inherit', 
174      'bottom': r'{length}|{percentage}|auto|inherit', 
175      'caption-side': r'top|bottom|inherit', 
176      'clear': r'none|left|right|both|inherit', 
177      'clip': r'{shape}|auto|inherit', 
178      'color': r'{color}|inherit', 
179      'content': r'normal|{content}(\s+{content})*|inherit', 
180      'counter-increment': r'({identifier}(\s+{integer})?)(\s+({identifier}(\s+{integer})))*|none|inherit', 
181      'counter-reset': r'({identifier}(\s+{integer})?)(\s+({identifier}(\s+{integer})))*|none|inherit', 
182      'cue-after': r'{uri}|none|inherit', 
183      'cue-before': r'{uri}|none|inherit', 
184      'cue': r'({uri}|none|inherit){1,2}|inherit', 
185      'cursor': r'((({uri}{w},{w})*)?(auto|crosshair|default|pointer|move|(e|ne|nw|n|se|sw|s|w)-resize|text|wait|help|progress))|inherit', 
186      'direction': r'ltr|rtl|inherit', 
187      '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', 
188      'elevation': r'{angle}|below|level|above|higher|lower|inherit', 
189      'empty-cells': r'show|hide|inherit', 
190      'float': r'left|right|none|inherit', 
191      'font-family': r'{font-family}', 
192      'font-size': r'{font-size}', 
193      'font-style': r'{font-style}', 
194      'font-variant': r'{font-variant}', 
195      'font-weight': r'{font-weight}', 
196      'font': r'({font-attrs}\s+)*{font-size}({w}/{w}{line-height})?\s+{font-family}|caption|icon|menu|message-box|small-caption|status-bar|inherit', 
197      'height': r'{length}|{percentage}|auto|inherit', 
198      'left': r'{length}|{percentage}|auto|inherit', 
199      'letter-spacing': r'normal|{length}|inherit', 
200      'line-height': r'{line-height}', 
201      'list-style-image': r'{list-style-image}', 
202      'list-style-position': r'{list-style-position}', 
203      'list-style-type': r'{list-style-type}', 
204      'list-style': r'{list-attrs}(\s+{list-attrs})*|inherit', 
205      'margin-right': r'{margin-width}|inherit', 
206      'margin-left': r'{margin-width}|inherit', 
207      'margin-top': r'{margin-width}|inherit', 
208      'margin-bottom': r'{margin-width}|inherit', 
209      'margin': r'{margin-width}(\s+{margin-width}){0,3}|inherit', 
210      'max-height': r'{length}|{percentage}|none|inherit', 
211      'max-width': r'{length}|{percentage}|none|inherit', 
212      'min-height': r'{length}|{percentage}|none|inherit', 
213      'min-width': r'{length}|{percentage}|none|inherit', 
214      'orphans': r'{integer}|inherit', 
215      'outline-color': r'{outline-color}', 
216      'outline-style': r'{outline-style}', 
217      'outline-width': r'{outline-width}', 
218      'outline': r'{outline-attrs}(\s+{outline-attrs})*|inherit', 
219      'overflow': r'visible|hidden|scroll|auto|inherit', 
220      'padding-top': r'{padding-width}|inherit', 
221      'padding-right': r'{padding-width}|inherit', 
222      'padding-bottom': r'{padding-width}|inherit', 
223      'padding-left': r'{padding-width}|inherit', 
224      'padding': r'{padding-width}(\s+{padding-width}){0,3}|inherit', 
225      'page-break-after': r'auto|always|avoid|left|right|inherit', 
226      'page-break-before': r'auto|always|avoid|left|right|inherit', 
227      'page-break-inside': r'avoid|auto|inherit', 
228      'pause-after': r'{time}|{percentage}|inherit', 
229      'pause-before': r'{time}|{percentage}|inherit', 
230      'pause': r'({time}|{percentage}){1,2}|inherit', 
231      'pitch-range': r'{number}|inherit', 
232      'pitch': r'{frequency}|x-low|low|medium|high|x-high|inherit', 
233      'play-during': r'{uri}(\s+(mix|repeat))*|auto|none|inherit', 
234      'position': r'static|relative|absolute|fixed|inherit', 
235      'quotes': r'({string}\s+{string})(\s+{string}\s+{string})*|none|inherit', 
236      'richness': r'{number}|inherit', 
237      'right': r'{length}|{percentage}|auto|inherit', 
238      'speak-header': r'once|always|inherit', 
239      'speak-numeral': r'digits|continuous|inherit', 
240      'speak-punctuation': r'code|none|inherit', 
241      'speak': r'normal|none|spell-out|inherit', 
242      'speech-rate': r'{number}|x-slow|slow|medium|fast|x-fast|faster|slower|inherit', 
243      'stress': r'{number}|inherit', 
244      'table-layout': r'auto|fixed|inherit', 
245      'text-align': r'left|right|center|justify|inherit', 
246      'text-decoration': r'none|{text-attrs}(\s+{text-attrs})*|inherit', 
247      'text-indent': r'{length}|{percentage}|inherit', 
248      'text-transform': r'capitalize|uppercase|lowercase|none|inherit', 
249      'top': r'{length}|{percentage}|auto|inherit', 
250      'unicode-bidi': r'normal|embed|bidi-override|inherit', 
251      'vertical-align': r'baseline|sub|super|top|text-top|middle|bottom|text-bottom|{percentage}|{length}|inherit', 
252      'visibility': r'visible|hidden|collapse|inherit', 
253      'voice-family': r'({specific-voice}|{generic-voice}{w},{w})*({specific-voice}|{generic-voice})|inherit', 
254      'volume': r'{number}|{percentage}|silent|x-soft|soft|medium|loud|x-loud|inherit', 
255      'white-space': r'normal|pre|nowrap|pre-wrap|pre-line|inherit', 
256      'widows': r'{integer}|inherit', 
257      'width': r'{length}|{percentage}|auto|inherit', 
258      'word-spacing': r'normal|{length}|inherit', 
259      'z-index': r'auto|{integer}|inherit', 
260  } 
261   
262 -def _expand_macros(tokdict):
263 """ Expand macros in token dictionary """ 264 def macro_value(m): 265 return '(?:%s)' % MACROS[m.groupdict()['macro']]
266 for key, value in tokdict.items(): 267 while re.search(r'{[a-z][a-z0-9-]*}', value): 268 value = re.sub(r'{(?P<macro>[a-z][a-z0-9-]*)}', 269 macro_value, value) 270 tokdict[key] = value 271 return tokdict 272
273 -def _compile_regexes(tokdict):
274 """ Compile all regular expressions into callable objects """ 275 for key, value in tokdict.items(): 276 tokdict[key] = re.compile('^(?:%s)$' % value, re.I).match 277 return tokdict
278 279 _compile_regexes(_expand_macros(cssvalues)) 280 281 282 # functions to convert between CSS and DOM name 283 284 _reCSStoDOMname = re.compile('-[a-z]', re.I)
285 -def _toDOMname(CSSname):
286 """ 287 returns DOMname for given CSSname e.g. for CSSname 'font-style' returns 288 'fontStyle' 289 """ 290 def _doCSStoDOMname2(m): return m.group(0)[1].capitalize() 291 return _reCSStoDOMname.sub(_doCSStoDOMname2, CSSname)
292 293 _reDOMtoCSSname = re.compile('([A-Z])[a-z]+')
294 -def _toCSSname(DOMname):
295 """ 296 returns CSSname for given DOMname e.g. for DOMname 'fontStyle' returns 297 'font-style' 298 """ 299 def _doDOMtoCSSname2(m): return '-' + m.group(0).lower() 300 return _reDOMtoCSSname.sub(_doDOMtoCSSname2, DOMname)
301 302
303 -class CSS2Properties(object):
304 """ 305 The CSS2Properties interface represents a convenience mechanism 306 for retrieving and setting properties within a CSSStyleDeclaration. 307 The attributes of this interface correspond to all the properties 308 specified in CSS2. Getting an attribute of this interface is 309 equivalent to calling the getPropertyValue method of the 310 CSSStyleDeclaration interface. Setting an attribute of this 311 interface is equivalent to calling the setProperty method of the 312 CSSStyleDeclaration interface. 313 314 cssutils actually also allows usage of ``del`` to remove a CSS property 315 from a CSSStyleDeclaration. 316 317 This is an abstract class, the following functions need to be present 318 in inheriting class: 319 320 - ``_getP`` 321 - ``_setP`` 322 - ``_delP`` 323 """ 324 # actual properties are set after the class definition!
325 - def _getP(self, CSSname): pass
326 - def _setP(self, CSSname, value): pass
327 - def _delP(self, CSSname): pass
328 329 # add list of DOMname properties to CSS2Properties 330 # used for CSSStyleDeclaration to check if allowed properties 331 # but somehow doubled, any better way? 332 CSS2Properties._properties = [_toDOMname(p) for p in cssvalues.keys()] 333 334 # add CSS2Properties to CSSStyleDeclaration:
335 -def __named_property_def(DOMname):
336 """ 337 closure to keep name known in each properties accessor function 338 DOMname is converted to CSSname here, so actual calls use CSSname 339 """ 340 CSSname = _toCSSname(DOMname) 341 def _get(self): return self._getP(CSSname) 342 def _set(self, value): self._setP(CSSname, value) 343 def _del(self): self._delP(CSSname) 344 return _get, _set, _del
345 346 # add all CSS2Properties to CSSStyleDeclaration 347 for DOMname in CSS2Properties._properties: 348 setattr(CSS2Properties, DOMname, 349 property(*__named_property_def(DOMname))) 350