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