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