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-09-25 21:47:06 +0200 (Di, 25 Sep 2007) $'
     66  __version__ = '$LastChangedRevision: 455 $'
     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