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