summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEevee (Alex Munroe) <eevee.git@veekun.com>2013-08-21 19:03:41 -0700
committerEevee (Alex Munroe) <eevee.git@veekun.com>2013-08-21 19:03:41 -0700
commite6e920ac90368f0044536505a408f8809860aece (patch)
tree7a36a133c9f2d7263391860776af89db2400c07b
parent5594328337f4078db708d6d14411f435deec6ad1 (diff)
downloadpyscss-e6e920ac90368f0044536505a408f8809860aece.tar.gz
Gradient cleanup, now with tests! Also unbreaks radial-gradient.
-rw-r--r--scss/functions/compass/gradients.py44
-rw-r--r--scss/tests/files/compass/gradients.css58
-rw-r--r--scss/tests/files/compass/gradients.scss83
-rw-r--r--scss/tests/files/kronuz/linear-gradient.css3
-rw-r--r--scss/tests/functions/compass/test_gradients.py57
5 files changed, 222 insertions, 23 deletions
diff --git a/scss/functions/compass/gradients.py b/scss/functions/compass/gradients.py
index 2a5cd32..37fd5fe 100644
--- a/scss/functions/compass/gradients.py
+++ b/scss/functions/compass/gradients.py
@@ -62,10 +62,11 @@ def __color_stops(percentages, *args):
if stops[-1] is None:
stops[-1] = Number(100, '%')
- if percentages:
- max_stops = max(s and (s.value if s.unit != '%' else None) or None for s in stops)
+ maxable_stops = [s for s in stops if s and s.unit != '%']
+ if maxable_stops:
+ max_stops = max(maxable_stops)
else:
- max_stops = max(s if s and s.unit != '%' else None for s in stops)
+ max_stops = None
stops = [_s / max_stops if _s and _s.unit != '%' else _s for _s in stops]
@@ -88,10 +89,23 @@ def __color_stops(percentages, *args):
if not max_stops or percentages:
pass
else:
- stops = [s * max_stops for s in stops]
+ stops = [s if s.unit == '%' else s * max_stops for s in stops]
+
return zip(stops, colors)
+def _render_standard_color_stops(color_stops):
+ pairs = []
+ for i, (stop, color) in enumerate(color_stops):
+ if ((i == 0 and stop == Number(0, '%')) or
+ (i == len(color_stops) - 1 and stop == Number(100, '%'))):
+ pairs.append(color)
+ else:
+ pairs.append(List([color, stop], use_comma=False))
+
+ return List(pairs, use_comma=True)
+
+
@register('grad-color-stops')
def grad_color_stops(*args):
args = List.from_maybe_starargs(args)
@@ -155,15 +169,9 @@ def color_stops_in_percentages(*args):
def _get_gradient_position_and_angle(args):
for arg in args:
- if isinstance(arg, (String, Number, six.string_types)):
- _arg = [arg]
- elif isinstance(arg, (list, tuple, List)):
- _arg = arg
- else:
- continue
ret = None
skip = False
- for a in _arg:
+ for a in arg:
if isinstance(a, Color):
skip = True
break
@@ -178,26 +186,20 @@ def _get_gradient_position_and_angle(args):
'top', 'bottom',
'left', 'right',
):
- if String(seek) in _arg:
+ if String(seek) in arg:
return arg
return None
def _get_gradient_shape_and_size(args):
for arg in args:
- if isinstance(arg, (String, Number, six.string_types)):
- _arg = [arg]
- elif isinstance(arg, (list, tuple, List)):
- _arg = arg
- else:
- continue
for seek in (
'circle', 'ellipse',
'closest-side', 'closest-corner',
'farthest-side', 'farthest-corner',
'contain', 'cover',
):
- if seek in _arg:
+ if String(seek) in arg:
return arg
return None
@@ -227,7 +229,7 @@ def radial_gradient(*args):
position(position_and_angle) if position_and_angle is not None else None,
shape_and_size if shape_and_size is not None else None,
]
- args.extend('%s %s' % (c, to_str(s)) for s, c in color_stops)
+ args.extend(_render_standard_color_stops(color_stops))
to__s = 'radial-gradient(' + ', '.join(to_str(a) for a in args or [] if a is not None) + ')'
ret = String.unquoted(to__s)
@@ -282,7 +284,7 @@ def linear_gradient(*args):
args = [
position(position_and_angle) if position_and_angle is not None else None,
]
- args.extend('%s %s' % (c.render(), s.render()) for s, c in color_stops)
+ args.extend(_render_standard_color_stops(color_stops))
to__s = 'linear-gradient(' + ', '.join(to_str(a) for a in args or [] if a is not None) + ')'
ret = String.unquoted(to__s)
diff --git a/scss/tests/files/compass/gradients.css b/scss/tests/files/compass/gradients.css
new file mode 100644
index 0000000..9a99ca1
--- /dev/null
+++ b/scss/tests/files/compass/gradients.css
@@ -0,0 +1,58 @@
+.bg-shortcut-linear-gradient {
+ background: #fff linear-gradient(top left, #ddd, #aaa);
+}
+.bg-shortcut-radial-gradient {
+ background: #fff radial-gradient(center center, #ddd, #aaa 100px);
+}
+.bg-linear-gradient-angle-svg {
+ background-image: linear-gradient(-45deg, blue, black);
+}
+.bg-linear-gradient-angle2-svg {
+ background-image: linear-gradient(top left, blue, black);
+}
+.bg-linear-gradient {
+ background-image: linear-gradient(top left, #ddd, #aaa);
+}
+.bg-linear-gradient-pixel-stop-from-top {
+ background-image: linear-gradient(top, #ddd 10px, #aaa 40px);
+}
+.bg-linear-gradient-pixel-stop-from-left {
+ background-image: linear-gradient(left, #ddd 10px, #aaa 40px);
+}
+.transparent-in-linear-gradient {
+ background-image: #fff linear-gradient(top left, transparent, #aaa);
+}
+.bg-radial-gradient {
+ background-image: radial-gradient(center center, #ddd, transparent 100px);
+}
+.bg-linear-gradient-with-angle {
+ background-image: linear-gradient(-45deg, #ddd, #aaa);
+}
+.bg-radial-gradient-with-angle-and-shape {
+ background-image: radial-gradient(ellipse cover, #ddd, #aaa 100px);
+}
+.bg-all-gradient-types {
+ background-image: linear-gradient(top left, #ddd, #aaa);
+ background-image: radial-gradient(center center, #ddd, #aaa 100px);
+}
+.border-image-gradient {
+ border-image: radial-gradient(#0f0, #f00 100px) 100 stretch;
+}
+.direct-list-image-with-gradient {
+ list-style-image: radial-gradient(lime, red 10px);
+}
+.shorthand-list-image-with-gradient {
+ list-style: outside radial-gradient(lime, red 10px);
+}
+.content-with-gradient {
+ content: radial-gradient(lime, red 10px);
+}
+.bg-linear-gradient-no-position {
+ background-image: linear-gradient(#ddd, #aaa);
+}
+.bg-radial-gradient-no-position {
+ background-image: radial-gradient(#ddd, #aaa 100px);
+}
+.cross-fade {
+ background-image: cross-fade(radial-gradient(#ddd, #aaa 100px), url("4x6.png"));
+}
diff --git a/scss/tests/files/compass/gradients.scss b/scss/tests/files/compass/gradients.scss
new file mode 100644
index 0000000..9f7d726
--- /dev/null
+++ b/scss/tests/files/compass/gradients.scss
@@ -0,0 +1,83 @@
+// Borrowed from Compass's actual test suite, but cut down to just the gradient
+// calls, and with some editing to e.g. preserve color formatting:
+// https://github.com/chriseppstein/compass/blob/stable/test/fixtures/stylesheets/compass/sass/gradients.sass
+// Similarly, the expected results have been trimmed to just the standard
+// syntax, since this file doesn't use any of Compass's background() calls etc.
+// TODO maybe it should, since we try to support all that
+
+.bg-shortcut-linear-gradient {
+ background: #fff linear-gradient(top left, #ddd, #aaa);
+}
+
+.bg-shortcut-radial-gradient {
+ background: #fff radial-gradient(center center, #ddd, #aaa 100px);
+}
+
+.bg-linear-gradient-angle-svg {
+ background-image: linear-gradient(-45deg, blue, black);
+}
+
+.bg-linear-gradient-angle2-svg {
+ background-image: linear-gradient(top left, blue, black);
+}
+
+.bg-linear-gradient {
+ background-image: linear-gradient(top left, #ddd, #aaa);
+}
+
+.bg-linear-gradient-pixel-stop-from-top {
+ background-image: linear-gradient(top, #ddd 10px, #aaa 40px);
+}
+
+.bg-linear-gradient-pixel-stop-from-left {
+ background-image: linear-gradient(left, #ddd 10px, #aaa 40px);
+}
+
+.transparent-in-linear-gradient {
+ background-image: #fff linear-gradient(top left, transparent, #aaa);
+}
+
+.bg-radial-gradient {
+ background-image: radial-gradient(center center, #ddd, transparent 100px);
+}
+
+.bg-linear-gradient-with-angle {
+ background-image: linear-gradient(-45deg, #ddd, #aaa);
+}
+
+.bg-radial-gradient-with-angle-and-shape {
+ background-image: radial-gradient(ellipse cover, #ddd, #aaa 100px);
+}
+
+.bg-all-gradient-types {
+ background-image: linear-gradient(top left, #ddd, #aaa);
+ background-image: radial-gradient(center center, #ddd, #aaa 100px);
+}
+
+.border-image-gradient {
+ border-image: radial-gradient(#0f0,#f00 100px) 100 stretch;
+}
+
+.direct-list-image-with-gradient {
+ list-style-image: radial-gradient(lime, red 10px);
+}
+
+.shorthand-list-image-with-gradient {
+ list-style: outside radial-gradient(lime, red 10px);
+}
+
+.content-with-gradient {
+ content: radial-gradient(lime, red 10px);
+}
+
+.bg-linear-gradient-no-position {
+ background-image: linear-gradient(#ddd, #aaa);
+}
+
+.bg-radial-gradient-no-position {
+ background-image: radial-gradient(#ddd, #aaa 100px);
+}
+
+.cross-fade {
+ background-image: cross-fade(radial-gradient(#ddd, #aaa 100px), url("4x6.png"));
+}
diff --git a/scss/tests/files/kronuz/linear-gradient.css b/scss/tests/files/kronuz/linear-gradient.css
index bfed43f..3af528b 100644
--- a/scss/tests/files/kronuz/linear-gradient.css
+++ b/scss/tests/files/kronuz/linear-gradient.css
@@ -1,4 +1,3 @@
div {
- background: linear-gradient(top, #4d4d4d 0%, #3f3f3f 50%, #333333 50%, #252525
- 100%);
+ background: linear-gradient(top, #4d4d4d, #3f3f3f 50%, #333333 50%, #252525);
}
diff --git a/scss/tests/functions/compass/test_gradients.py b/scss/tests/functions/compass/test_gradients.py
new file mode 100644
index 0000000..e555b4b
--- /dev/null
+++ b/scss/tests/functions/compass/test_gradients.py
@@ -0,0 +1,57 @@
+"""Tests for Compass gradient generation."""
+
+from scss.expression import Calculator
+from scss.functions.compass.gradients import COMPASS_GRADIENTS_LIBRARY, linear_gradient
+from scss.rule import Namespace
+from scss.types import String, List, Number, Color
+
+import pytest
+
+
+@pytest.fixture
+def calc():
+ ns = Namespace(functions=COMPASS_GRADIENTS_LIBRARY)
+ return Calculator(ns).evaluate_expression
+
+
+def test_linear_gradient():
+ # Set up some values
+ to = String.unquoted('to')
+ bottom = String.unquoted('bottom')
+ left = String.unquoted('left')
+ angle = Number(45, 'deg')
+
+ red = Color.from_name('red')
+ blue = Color.from_name('blue')
+
+ start = Number(0, "%")
+ middle = Number(50, "%")
+ end = Number(100, "%")
+
+ assert (
+ linear_gradient(left, List((red, start)), List((blue, middle)))
+ == String('linear-gradient(left, red, blue 50%)')
+ )
+
+ assert (
+ linear_gradient(List((to, bottom)), blue, List((red, end)))
+ == String('linear-gradient(to bottom, blue, red)')
+ )
+
+
+@pytest.mark.xfail("rainbow still has intermediate values added")
+def test_linear_gradient_idempotent(calc):
+ # linear-gradient should leave valid syntax alone.
+ # Examples graciously stolen from MDN:
+ # https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient
+ trials = [
+ 'linear-gradient(45deg, blue, red)',
+ 'linear-gradient(to left top, blue, red)',
+ 'linear-gradient(0deg, blue, green 40%, red)',
+ 'linear-gradient(to right, red, orange, yellow, green, blue, indigo, violet)',
+ 'linear-gradient(to bottom right, red, rgba(255,0,0,0))',
+ 'linear-gradient(to bottom, hsl(0, 80%, 70%), #bada55)',
+ ]
+
+ for trial in trials:
+ assert calc(trial) == String(trial)