Skip to content

Commit

Permalink
Add list properties
Browse files Browse the repository at this point in the history
  • Loading branch information
goanpeca committed Apr 27, 2020
1 parent 61880b7 commit 1ac4b6f
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 58 deletions.
54 changes: 53 additions & 1 deletion colosseum/constants.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from .validators import (ValidationError, is_border_spacing, is_color,
is_cursor, is_integer, is_length, is_number,
is_percentage, is_quote, is_rect)
is_percentage, is_quote, is_rect, is_uri)


class Choices:
Expand Down Expand Up @@ -305,8 +305,60 @@ def value(self, context):
# 12.5 Lists
######################################################################
# list_style_type
DISC = 'disc'
CIRCLE = 'circle'
SQUARE = 'square'
DECIMAL = 'decimal'
DECIMAL_LEADING_ZERO = 'decimal-leading-zero'
LOWER_ROMAN = 'lower-roman'
UPPER_ROMAN = 'upper-roman'
LOWER_GREEK = 'lower-greek'
LOWER_LATIN = 'lower-latin'
UPPER_LATIN = 'upper-latin'
ARMENIAN = 'armenian'
GEORGIAN = 'georgian'
LOWER_ALPHA = 'lower-alpha'
UPPER_ALPHA = 'upper-alpha'


LIST_TYPE_CHOICES = Choices(
DISC,
CIRCLE,
SQUARE,
DECIMAL,
DECIMAL_LEADING_ZERO,
LOWER_ROMAN,
UPPER_ROMAN,
LOWER_GREEK,
LOWER_LATIN,
UPPER_LATIN,
ARMENIAN,
GEORGIAN,
LOWER_ALPHA,
UPPER_ALPHA,
None,
explicit_defaulting_constants=[INHERIT],
)

# list_style_image
LIST_IMAGE_CHOICES = Choices(
None,
validators=[is_uri],
explicit_defaulting_constants=[INHERIT],
)


# list_style_position
INSIDE = 'inside'
OUTSIDE = 'outside'

LIST_POSITION_CHOICES = Choices(
INSIDE,
OUTSIDE,
explicit_defaulting_constants=[INHERIT],
)


# list_style

# 13. Paged media ####################################################
Expand Down
35 changes: 19 additions & 16 deletions colosseum/declaration.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,33 @@
from . import engine as css_engine
from . import parser
from . import engine as css_engine, parser
from .constants import ( # noqa
ALIGN_CONTENT_CHOICES, ALIGN_ITEMS_CHOICES, ALIGN_SELF_CHOICES, AUTO,
BACKGROUND_COLOR_CHOICES, BORDER_COLLAPSE_CHOICES, BORDER_COLOR_CHOICES,
BORDER_SPACING_CHOICES, BORDER_STYLE_CHOICES, BORDER_WIDTH_CHOICES,
BOX_OFFSET_CHOICES, CAPTION_SIDE_CHOICES, CLEAR_CHOICES, CLIP_CHOICES,
COLOR_CHOICES, DIRECTION_CHOICES, DISPLAY_CHOICES, EMPTY_CELLS_CHOICES,
FLEX_BASIS_CHOICES, FLEX_DIRECTION_CHOICES, FLEX_GROW_CHOICES,
FLEX_SHRINK_CHOICES, FLEX_START, FLEX_WRAP_CHOICES, FLOAT_CHOICES,
GRID_AUTO_CHOICES, GRID_AUTO_FLOW_CHOICES, GRID_GAP_CHOICES,
COLOR_CHOICES, DIRECTION_CHOICES, DISC, DISPLAY_CHOICES,
EMPTY_CELLS_CHOICES, FLEX_BASIS_CHOICES, FLEX_DIRECTION_CHOICES,
FLEX_GROW_CHOICES, FLEX_SHRINK_CHOICES, FLEX_START, FLEX_WRAP_CHOICES,
FLOAT_CHOICES, GRID_AUTO_CHOICES, GRID_AUTO_FLOW_CHOICES, GRID_GAP_CHOICES,
GRID_PLACEMENT_CHOICES, GRID_TEMPLATE_AREA_CHOICES, GRID_TEMPLATE_CHOICES,
INITIAL, INLINE, INVERT, JUSTIFY_CONTENT_CHOICES, LETTER_SPACING_CHOICES,
LTR, MARGIN_CHOICES, MAX_SIZE_CHOICES, MEDIUM, MIN_SIZE_CHOICES, NORMAL,
NOWRAP, ORDER_CHOICES, ORPHANS_CHOICES, OUTLINE_COLOR_CHOICES,
OUTLINE_STYLE_CHOICES, OUTLINE_WIDTH_CHOICES, OVERFLOW_CHOICES,
LIST_IMAGE_CHOICES, LIST_POSITION_CHOICES, LIST_TYPE_CHOICES, LTR,
MARGIN_CHOICES, MAX_SIZE_CHOICES, MEDIUM, MIN_SIZE_CHOICES, NORMAL, NOWRAP,
ORDER_CHOICES, ORPHANS_CHOICES, OUTLINE_COLOR_CHOICES,
OUTLINE_STYLE_CHOICES, OUTLINE_WIDTH_CHOICES, OUTSIDE, OVERFLOW_CHOICES,
PADDING_CHOICES, PAGE_BREAK_AFTER_CHOICES, PAGE_BREAK_BEFORE_CHOICES,
PAGE_BREAK_INSIDE_CHOICES, POSITION_CHOICES, QUOTES_CHOICES, ROW,
SEPARATE, SHOW, SIZE_CHOICES, STATIC, STRETCH, TABLE_LAYOUT_CHOICES,
PAGE_BREAK_INSIDE_CHOICES, POSITION_CHOICES, QUOTES_CHOICES, ROW, SEPARATE,
SHOW, SIZE_CHOICES, STATIC, STRETCH, TABLE_LAYOUT_CHOICES,
TEXT_ALIGN_CHOICES, TEXT_DECORATION_CHOICES, TEXT_INDENT_CHOICES,
TEXT_TRANSFORM_CHOICES, TOP, TRANSPARENT, UNICODE_BIDI_CHOICES,
VISIBILITY_CHOICES, VISIBLE, WHITE_SPACE_CHOICES, WIDOWS_CHOICES,
WORD_SPACING_CHOICES, Z_INDEX_CHOICES, OtherProperty,
TextAlignInitialValue, default, CURSOR_CHOICES,
)
from .exceptions import ValidationError
from .wrappers import Border, BorderBottom, BorderLeft, BorderRight, BorderTop, Outline
from .wrappers import (
Border, BorderBottom, BorderLeft, BorderRight, BorderTop, ListStyle,
Outline,
)

_CSS_PROPERTIES = set()

Expand Down Expand Up @@ -329,10 +332,10 @@ def __init__(self, **style):
# counter-increment

# 12.5 Lists
# list_style_type
# list_style_image
# list_style_position
# list_style
list_style_type = validated_property('list_style_type', choices=LIST_TYPE_CHOICES, initial=DISC)
list_style_image = validated_property('list_style_type', choices=LIST_IMAGE_CHOICES, initial=None)
list_style_position = validated_property('list_style_position', choices=LIST_POSITION_CHOICES, initial=OUTSIDE)
list_style = validated_shorthand_property('list_style', parser=parser.list_style, wrapper=ListStyle)

# 13. Paged media ####################################################
# 13.3.1 Page break properties
Expand Down
61 changes: 61 additions & 0 deletions colosseum/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,3 +445,64 @@ def cursor(values):
raise ValueError('Value {value} is not a valid cursor value'.format(value=value))

return Cursor(validated_values)


##############################################################################
# List shorthands
##############################################################################
def _parse_list_style_property_part(value, list_style_dict):
"""Parse list style shorthand property part for known properties."""
from .constants import ( # noqa
LIST_TYPE_CHOICES, LIST_IMAGE_CHOICES, LIST_POSITION_CHOICES
)

for property_name, choices in {'list_style_type': LIST_TYPE_CHOICES,
'list_style_image': LIST_IMAGE_CHOICES,
'list_style_position': LIST_POSITION_CHOICES}.items():
try:
value = choices.validate(value)
except (ValueError, ValidationError):
continue

if property_name in list_style_dict:
raise ValueError('Invalid duplicated property!')

list_style_dict[property_name] = value
return list_style_dict

raise ValueError('List style value "{value}" not valid!'.format(value=value))


def list_style(value):
"""
Parse list style string into a dictionary of list style properties.
The font CSS property is a shorthand for list-style-type, list-style-image, and list-style-position.
Reference:
- https://www.w3.org/TR/2011/REC-CSS2-20110607/generate.html#lists
"""
if value:
if isinstance(value, str):
values = [val.strip() for val in value.split()]
elif isinstance(value, Sequence):
values = value
else:
raise ValueError('Unknown list style %s ' % value)
else:
raise ValueError('Unknown list style %s ' % value)

# We iteratively split by the first left hand space found and try to validate if that part
# is a valid <list-style-type> or <list-style-image> or <list-style-position> (which can come in any order)

# We use this dictionary to store parsed values and check that values properties are not
# duplicated
list_style_dict = {}
for idx, part in enumerate(values):
if idx > 2:
# Outline can have a maximum of 3 parts
raise ValueError('List style property shorthand contains too many parts!')

list_style_dict = _parse_list_style_property_part(part, list_style_dict)

return list_style_dict
86 changes: 45 additions & 41 deletions colosseum/wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,47 +129,6 @@ def to_dict(self):
return properties


class Outline(Shorthand):
VALID_KEYS = ['outline_color', 'outline_style', 'outline_width']


class BorderTop(Shorthand):
VALID_KEYS = ['border_top_width', 'border_top_style', 'border_top_color']


class BorderRight(Shorthand):
VALID_KEYS = ['border_right_width', 'border_right_style', 'border_right_color']


class BorderBottom(Shorthand):
VALID_KEYS = ['border_bottom_width', 'border_bottom_style', 'border_bottom_color']


class BorderLeft(Shorthand):
VALID_KEYS = ['border_left_width', 'border_left_style', 'border_left_color']


class Border(Shorthand):
VALID_KEYS = ['border_width', 'border_style', 'border_color']


class Uri:
"""Wrapper for a url."""

def __init__(self, url):
self._url = url

def __repr__(self):
return 'url("%s")' % self._url

def __str__(self):
return repr(self)

@property
def url(self):
return self._url


class ImmutableList(list):
"""Immutable list to store list properties."""

Expand Down Expand Up @@ -233,5 +192,50 @@ def sort(self, cmp=None, key=None, reverse=False):
raise TypeError("{} values cannot be changed!".format(self.__class__.__name__))


class Outline(Shorthand):
VALID_KEYS = ['outline_color', 'outline_style', 'outline_width']


class BorderTop(Shorthand):
VALID_KEYS = ['border_top_width', 'border_top_style', 'border_top_color']


class BorderRight(Shorthand):
VALID_KEYS = ['border_right_width', 'border_right_style', 'border_right_color']


class BorderBottom(Shorthand):
VALID_KEYS = ['border_bottom_width', 'border_bottom_style', 'border_bottom_color']


class BorderLeft(Shorthand):
VALID_KEYS = ['border_left_width', 'border_left_style', 'border_left_color']


class Border(Shorthand):
VALID_KEYS = ['border_width', 'border_style', 'border_color']


class Uri:
"""Wrapper for a url."""

def __init__(self, url):
self._url = url

def __repr__(self):
return 'url("%s")' % self._url

def __str__(self):
return repr(self)

@property
def url(self):
return self._url


class Cursor(ImmutableList):
"""Immutable list to store cursor property."""


class ListStyle(Shorthand):
VALID_KEYS = ['list_style_type', 'list_style_image', 'list_style_position']

0 comments on commit 1ac4b6f

Please sign in to comment.