diff --git a/frameworks/compass/stylesheets/compass/css3/_gradient.sass b/frameworks/compass/stylesheets/compass/css3/_gradient.sass index d67d863a..526f2bc0 100644 --- a/frameworks/compass/stylesheets/compass/css3/_gradient.sass +++ b/frameworks/compass/stylesheets/compass/css3/_gradient.sass @@ -6,35 +6,39 @@ background: -moz-#{!type}-gradient(#{!gradient}) //* - // This will yeild a radial gradient with an apparent specular highlight + // This will yield a radial gradient with an apparent specular highlight +radial-gradient("45 45, 10, 52 50, 30", Cyan, DodgerBlue) =radial-gradient(!coords, !color1, !color2, !color_stop = false) +gradient("radial", !coords, !color1, !color2, !color_stop) //* - // This yields a linear gradient spanning from !start to !end coordinates - +linear-gradient("left top", "left bottom", #fff, #ddd) - -=linear-gradient(!start, !end, !color1, !color2, !color_stop = false) - !coords = !start + ", " + !end - +gradient("linear", !coords, !color1, !color2, !color_stop) - -//* - // This yields a gradient starting at the top with #fff, ending in #aaa - +v-gradient(#fff, #aaa) - // Same as above but with a #ccc at the halfway point - +v-gradient(#fff, #aaa, color_stop(50%, #ccc)) - // Same as the first example but with #ccc at the 30% from the top, and #bbb at 70% from the top - +v-gradient(#fff, #aaa, color_stop(30%, #ccc, 70%, #bbb)) - -=v-gradient(!color1, !color2, !color_stop = false) - +linear-gradient("left top", "left bottom", !color1, !color2, !color_stop) - -//* - // This yields a horizontal linear gradient spanning from left to right - // It can be used just like v-gradient above - h-gradient(#fff, #ddd) + // This yields a linear gradient spanning from top to bottom + +linear-gradient(color_stops(white, black)) -=h-gradient(!color1, !color2, !color_stop = false) - +linear-gradient("left top", "right top", !color1, !color2, !color_stop) \ No newline at end of file + // This yields a linear gradient spanning from bottom to top + +linear-gradient(color_stops(white, black), "bottom") + + // This yields a linear gradient spanning from left to right + +linear-gradient(color_stops(white, black), "left") + + // This yields a linear gradient starting at white passing + // thru blue at 33% down and then to black + +linear-gradient(color_stops(white, blue 33%, black)) + + // This yields a linear gradient starting at white passing + // thru blue at 33% down and then to black at 67% until the end + +linear-gradient(color_stops(white, blue 33%, black 67%)) + +=linear-gradient(!color_stops, !start = "top") + // Firefox's gradient api is nice. + // Webkit's gradient api sucks -- hence these backflips: + !end = grad_opposite_position(!start) + !start_color = grad_start_color(!color_stops) + !end_color = grad_end_color(!color_stops) + !webkit_stops = grad_color_stops(!color_stops) + !gradient= "#{grad_point(!start)}, #{grad_point(!end)}, from(#{!start_color}), to(#{!end_color})" + @if !webkit_stops + !gradient= !gradient + ", " + !webkit_stops + background-image: -webkit-gradient(linear, #{!gradient}) + background-image: -moz-linear-gradient(#{!start}, #{!color_stops}) diff --git a/lib/compass/sass_extensions/functions.rb b/lib/compass/sass_extensions/functions.rb index c33a3012..0c9fa2e8 100644 --- a/lib/compass/sass_extensions/functions.rb +++ b/lib/compass/sass_extensions/functions.rb @@ -1,7 +1,7 @@ module Compass::SassExtensions::Functions end -%w(selectors enumerate urls display inline_image color_stop font_files).each do |func| +%w(selectors enumerate urls display inline_image gradient_support font_files).each do |func| require "compass/sass_extensions/functions/#{func}" end @@ -11,7 +11,7 @@ module Sass::Script::Functions include Compass::SassExtensions::Functions::Urls include Compass::SassExtensions::Functions::Display include Compass::SassExtensions::Functions::InlineImage - include Compass::SassExtensions::Functions::ColorStop + include Compass::SassExtensions::Functions::GradientSupport::Functions include Compass::SassExtensions::Functions::FontFiles end diff --git a/lib/compass/sass_extensions/functions/color_stop.rb b/lib/compass/sass_extensions/functions/color_stop.rb deleted file mode 100644 index a0902dfe..00000000 --- a/lib/compass/sass_extensions/functions/color_stop.rb +++ /dev/null @@ -1,10 +0,0 @@ -module Compass::SassExtensions::Functions::ColorStop - def color_stop(*args) - raise Sass::SyntaxError, "An even number of arguments must be passed to color-stop()" unless args.size % 2 == 0 - stops = [] - while args.size > 0 - stops << "color-stop(#{args.shift}, #{args.shift})" - end - Sass::Script::String.new(stops.join(", ")) - end -end diff --git a/lib/compass/sass_extensions/functions/gradient_support.rb b/lib/compass/sass_extensions/functions/gradient_support.rb new file mode 100644 index 00000000..71287d82 --- /dev/null +++ b/lib/compass/sass_extensions/functions/gradient_support.rb @@ -0,0 +1,123 @@ +module Compass::SassExtensions::Functions::GradientSupport + + class List < Sass::Script::Literal + attr_accessor :values + def initialize(*values) + self.values = values + end + def inspect + to_s + end + def to_s + values.map{|v| v.to_s}.join(", ") + end + end + + class ColorStop < Sass::Script::Literal + attr_accessor :color, :stop + def initialize(color, stop = nil) + self.color, self.stop = color, stop + end + def inspect + to_s + end + def to_s + s = "#{color}" + if stop + s << " " + s << stop.times(Sass::Script::Number.new(100)).to_s + s << "%" + end + s + end + end + + module Functions + def grad_opposite_position(position) + opposite = position.value.split(/ +/).map do |pos| + case pos + when "top" then "bottom" + when "bottom" then "top" + when "left" then "right" + when "right" then "left" + else + raise Sass::SyntaxError, "Cannot determine the opposite of #{pos}" + end + end + Sass::Script::String.new(opposite.join(" ")) + end + def grad_color_stops(color_list) + positions = color_list.values.map{|c| [c.stop && c.stop.value, c.color]} + # fill in the blank positions + positions[0][0] = 0 unless positions.first.first + positions[positions.size - 1][0] = 1 unless positions.last.first + for i in 0...positions.size + if positions[i].first.nil? + num = 2.0 + for j in (i+1)...positions.size + if positions[j].first + positions[i][0] = positions[i-1].first + (positions[j].first - positions[i-1].first) / num + break + else + num += 1 + end + end + end + end + positions = positions[1..-1] if positions.first.first == 0.0 + positions = positions[0..-2] if positions.last.first == 1.0 + if positions.empty? + # We return false here since sass has no nil. + Sass::Script::Bool.new(false) + else + color_stops = positions.map {|pos| "color-stop(#{Sass::Script::Number.new((pos.first*10000).round/100.0).to_s}%, #{pos.last})"} + Sass::Script::String.new(color_stops.join(", ")) + end + end + def grad_start_color(color_list) + color_list.values.first.color + end + def grad_end_color(color_list) + color_list.values.last.color + end + def grad_point(position) + position = position.value + position = if position[" "] + position + else + case position + when /top|bottom/ + "#{position} left" + when /left|right/ + "top #{position}" + end + end + Sass::Script::String.new position.gsub(/top/, "0%").gsub(/bottom/, "100%").gsub(/left/,"0%").gsub(/right/,"100%") + end + def color_stops(*args) + List.new(*args.map do |arg| + case arg + when Sass::Script::Color + ColorStop.new(arg) + when Sass::Script::String + color, stop = arg.value.split(/ +/, 2) + color = Sass::Script::Parser.parse(color, 0, 0) + if stop =~ /^(\d+)?(?:\.(\d+))?(%)?$/ + integral, decimal, percent = $1, $2, $3 + number = "#{integral || 0}.#{decimal || 0}".to_f + number = number / 100 if percent + if number > 1 + raise Sass::SyntaxError, "A color stop location must be between 0#{"%" if percent} and 1#{"00%" if percent}. Got: #{stop}" + end + stop = Sass::Script::Number.new(number) + elsif !stop.nil? + raise Sass::SyntaxError, "A color stop location must be between 0 and 1 or 0% and 100%. Got: #{stop}" + end + ColorStop.new(color, stop) + else + raise Sass::SyntaxError, "Not a valid color stop: #{arg}" + end + end) + end + end +end diff --git a/test/compass_test.rb b/test/compass_test.rb index aff2388a..d0e43f23 100644 --- a/test/compass_test.rb +++ b/test/compass_test.rb @@ -42,7 +42,7 @@ class CompassTest < Test::Unit::TestCase each_css_file(proj.css_path) do |css_file| assert_no_errors css_file, 'compass' end - assert_renders_correctly :reset, :layout, :utilities + assert_renders_correctly :reset, :layout, :utilities, :gradients end end diff --git a/test/fixtures/stylesheets/compass/css/gradients.css b/test/fixtures/stylesheets/compass/css/gradients.css new file mode 100644 index 00000000..93f0acf6 --- /dev/null +++ b/test/fixtures/stylesheets/compass/css/gradients.css @@ -0,0 +1,43 @@ +.linear-1 { + background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, from(#dddddd), to(#aaaaaa)); + background-image: -moz-linear-gradient(top, #dddddd, #aaaaaa); } + +.linear-2 { + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#dddddd), to(#aaaaaa)); + background-image: -moz-linear-gradient(left, #dddddd, #aaaaaa); } + +.linear-3 { + background-image: -webkit-gradient(linear, 0% 0%, 100% 100%, from(#dddddd), to(#aaaaaa)); + background-image: -moz-linear-gradient(top left, #dddddd, #aaaaaa); } + +.linear-4 { + background-image: -webkit-gradient(linear, 0% 100%, 100% 0%, from(#dddddd), to(#aaaaaa)); + background-image: -moz-linear-gradient(top right, #dddddd, #aaaaaa); } + +.linear-5 { + background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, from(#dddddd), to(#aaaaaa), color-stop(50%, #cccccc)); + background-image: -moz-linear-gradient(top, #dddddd, #cccccc, #aaaaaa); } + +.linear-6 { + background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, from(#dddddd), to(#aaaaaa), color-stop(20%, #cccccc)); + background-image: -moz-linear-gradient(top, #dddddd, #cccccc 20%, #aaaaaa); } + +.linear-7 { + background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, from(#dddddd), to(#aaaaaa), color-stop(20%, #cccccc), color-stop(60%, #eeeeee)); + background-image: -moz-linear-gradient(top, #dddddd, #cccccc 20%, #eeeeee, #aaaaaa); } + +.linear-8 { + background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, from(#dddddd), to(#aaaaaa), color-stop(80%, #dddddd)); + background-image: -moz-linear-gradient(top, #dddddd 80%, #aaaaaa); } + +.linear-9 { + background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, from(#dddddd), to(#aaaaaa), color-stop(20%, #aaaaaa)); + background-image: -moz-linear-gradient(top, #dddddd, #aaaaaa 20%); } + +.linear-10 { + background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, from(#dddddd), to(#aaaaaa), color-stop(40%, #dddddd), color-stop(50%, #aaaaaa)); + background-image: -moz-linear-gradient(top, #dddddd 40%, #aaaaaa 50%); } + +.linear-11 { + background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, from(#dddddd), to(#aaaaaa), color-stop(40%, #dddddd), color-stop(45%, black), color-stop(50%, #aaaaaa)); + background-image: -moz-linear-gradient(top, #dddddd 40%, black, #aaaaaa 50%); } diff --git a/test/fixtures/stylesheets/compass/sass/gradients.sass b/test/fixtures/stylesheets/compass/sass/gradients.sass new file mode 100644 index 00000000..1f729437 --- /dev/null +++ b/test/fixtures/stylesheets/compass/sass/gradients.sass @@ -0,0 +1,24 @@ +@import compass/css3.sass + +.linear-1 + +linear-gradient(color_stops(#ddd, #aaa)) +.linear-2 + +linear-gradient(color_stops(#ddd, #aaa), "left") +.linear-3 + +linear-gradient(color_stops(#ddd, #aaa), "top left") +.linear-4 + +linear-gradient(color_stops(#ddd, #aaa), "top right") +.linear-5 + +linear-gradient(color_stops(#ddd, #ccc, #aaa)) +.linear-6 + +linear-gradient(color_stops(#ddd, #ccc 20%, #aaa)) +.linear-7 + +linear-gradient(color_stops(#ddd, #ccc 20%, #eee, #aaa)) +.linear-8 + +linear-gradient(color_stops(#ddd 80%, #aaa)) +.linear-9 + +linear-gradient(color_stops(#ddd, #aaa 20%)) +.linear-10 + +linear-gradient(color_stops(#ddd 40%, #aaa 50%)) +.linear-11 + +linear-gradient(color_stops(#ddd 40%, #000, #aaa 50%)) \ No newline at end of file