Refactor the cross browser support and list functions from gradient module.
This commit is contained in:
parent
15f760e002
commit
e11f1035bf
@ -1,7 +1,7 @@
|
|||||||
module Compass
|
module Compass
|
||||||
end
|
end
|
||||||
|
|
||||||
%w(dependencies util sass_extensions core_ext version errors quick_cache).each do |lib|
|
%w(dependencies util browser_support sass_extensions core_ext version errors quick_cache).each do |lib|
|
||||||
require "compass/#{lib}"
|
require "compass/#{lib}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
62
lib/compass/browser_support.rb
Normal file
62
lib/compass/browser_support.rb
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
module Compass
|
||||||
|
module BrowserSupport
|
||||||
|
extend self
|
||||||
|
|
||||||
|
ASPECTS = %w(webkit moz o ms svg pie css2)
|
||||||
|
|
||||||
|
SIMPLE_FUNCTIONS = {
|
||||||
|
"image" => %w(), # No browsers implement this yet.
|
||||||
|
"cross-fade" => %w() # No browsers implement this yet.
|
||||||
|
}
|
||||||
|
|
||||||
|
# Adds support for one or more aspects for the given simple function
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# Compass::BrowserSupport.add_support("image", "moz", "webkit")
|
||||||
|
# # => Adds support for moz and webkit to the image() function.
|
||||||
|
#
|
||||||
|
# This function can be called one or more times in a compass configuration
|
||||||
|
# file in order to add support for new, simple browser functions without
|
||||||
|
# waiting for a new compass release.
|
||||||
|
def add_support(function, *aspects)
|
||||||
|
aspects.each do |aspect|
|
||||||
|
unless ASPECTS.include?(aspect)
|
||||||
|
Compass::Util.compass_warn "Unknown support aspect: #{aspect}"
|
||||||
|
next
|
||||||
|
end
|
||||||
|
unless supports?(function, aspect)
|
||||||
|
SIMPLE_FUNCTIONS[function.to_s] ||= []
|
||||||
|
SIMPLE_FUNCTIONS[function.to_s] << aspect.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Removes support for one or more aspects for the given simple function
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# Compass::BrowserSupport.remove_support("image", "o", "ms")
|
||||||
|
# # => Adds support for moz and webkit to the image() function.
|
||||||
|
#
|
||||||
|
# This function can be called one or more times in a compass configuration
|
||||||
|
# file in order to remove support for simple functions that no longer need to
|
||||||
|
# a prefix without waiting for a new compass release.
|
||||||
|
def remove_support(function, *aspects)
|
||||||
|
aspects.each do |aspect|
|
||||||
|
unless ASPECTS.include?(aspect)
|
||||||
|
Compass::Util.compass_warn "Unknown support aspect: #{aspect}"
|
||||||
|
next
|
||||||
|
end
|
||||||
|
SIMPLE_FUNCTIONS[function.to_s].reject!{|a| a == aspect.to_s}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def supports?(function, aspect)
|
||||||
|
SIMPLE_FUNCTIONS.has_key?(function.to_s) && SIMPLE_FUNCTIONS[function.to_s].include?(aspect.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_aspect?(function)
|
||||||
|
SIMPLE_FUNCTIONS.has_key?(function.to_s) && SIMPLE_FUNCTIONS[function.to_s].size > 0
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
@ -4,7 +4,7 @@ end
|
|||||||
%w(
|
%w(
|
||||||
selectors enumerate urls display
|
selectors enumerate urls display
|
||||||
inline_image image_size constants gradient_support
|
inline_image image_size constants gradient_support
|
||||||
font_files lists colors trig sprites
|
font_files lists colors trig sprites cross_browser_support
|
||||||
).each do |func|
|
).each do |func|
|
||||||
require "compass/sass_extensions/functions/#{func}"
|
require "compass/sass_extensions/functions/#{func}"
|
||||||
end
|
end
|
||||||
@ -23,6 +23,7 @@ module Sass::Script::Functions
|
|||||||
include Compass::SassExtensions::Functions::Colors
|
include Compass::SassExtensions::Functions::Colors
|
||||||
include Compass::SassExtensions::Functions::Trig
|
include Compass::SassExtensions::Functions::Trig
|
||||||
include Compass::SassExtensions::Functions::Sprites
|
include Compass::SassExtensions::Functions::Sprites
|
||||||
|
include Compass::SassExtensions::Functions::CrossBrowserSupport
|
||||||
end
|
end
|
||||||
|
|
||||||
# Wierd that this has to be re-included to pick up sub-modules. Ruby bug?
|
# Wierd that this has to be re-included to pick up sub-modules. Ruby bug?
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
module Compass::SassExtensions::Functions::CrossBrowserSupport
|
||||||
|
# Check if any of the arguments passed require a vendor prefix.
|
||||||
|
def prefixed(prefix, *args)
|
||||||
|
aspect = prefix.value.sub(/^-/,"")
|
||||||
|
needed = args.any?{|a| a.respond_to?(:supports?) && a.supports?(aspect)}
|
||||||
|
Sass::Script::Bool.new(needed)
|
||||||
|
end
|
||||||
|
|
||||||
|
%w(webkit moz o ms svg pie css2).each do |prefix|
|
||||||
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
||||||
|
# Syntactic sugar to apply the given prefix
|
||||||
|
# -moz($arg) is the same as calling prefix(-moz, $arg)
|
||||||
|
def _#{prefix}(*args)
|
||||||
|
prefix("#{prefix}", *args)
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
def prefix(prefix, *objects)
|
||||||
|
prefix = prefix.value if prefix.is_a?(Sass::Script::String)
|
||||||
|
prefix = prefix[1..-1] if prefix[0] == ?-
|
||||||
|
if objects.size > 1
|
||||||
|
self.prefix(prefix, Sass::Script::List.new(objects, :comma))
|
||||||
|
else
|
||||||
|
object = objects.first
|
||||||
|
if object.is_a?(Sass::Script::List)
|
||||||
|
Sass::Script::List.new(object.value.map{|e|
|
||||||
|
self.prefix(prefix, e)
|
||||||
|
}, object.separator)
|
||||||
|
elsif object.respond_to?(:supports?) && object.supports?(prefix) && object.respond_to?(:"to_#{prefix}")
|
||||||
|
object.options = options
|
||||||
|
object.send(:"to_#{prefix}")
|
||||||
|
else
|
||||||
|
object
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
@ -1,319 +1,6 @@
|
|||||||
module Compass::SassExtensions::Functions::GradientSupport
|
module Compass::SassExtensions::Functions::GradientSupport
|
||||||
|
|
||||||
module ListFreeSassSupport
|
GRADIENT_ASPECTS = %w(webkit moz svg pie css2).freeze
|
||||||
class List < Sass::Script::Literal
|
|
||||||
attr_accessor :values
|
|
||||||
def children
|
|
||||||
values
|
|
||||||
end
|
|
||||||
def value
|
|
||||||
# duck type to a Sass List
|
|
||||||
values
|
|
||||||
end
|
|
||||||
def initialize(*values)
|
|
||||||
self.values = values
|
|
||||||
end
|
|
||||||
def join_with
|
|
||||||
", "
|
|
||||||
end
|
|
||||||
def inspect
|
|
||||||
to_s
|
|
||||||
end
|
|
||||||
def to_s(options = self.options)
|
|
||||||
values.map {|v| v.to_s }.join(join_with)
|
|
||||||
end
|
|
||||||
def size
|
|
||||||
values.size
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class SpaceList < List
|
|
||||||
def join_with
|
|
||||||
" "
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# given a position list, return a corresponding position in percents
|
|
||||||
def grad_point(position)
|
|
||||||
position = position.is_a?(Sass::Script::String) ? position.value : position.to_s
|
|
||||||
position = if position[" "]
|
|
||||||
if position =~ /(top|bottom|center) (left|right|center)/
|
|
||||||
"#{$2} #{$1}"
|
|
||||||
else
|
|
||||||
position
|
|
||||||
end
|
|
||||||
else
|
|
||||||
case position
|
|
||||||
when /top|bottom/
|
|
||||||
"center #{position}"
|
|
||||||
when /left|right/
|
|
||||||
"#{position} center"
|
|
||||||
when /center/
|
|
||||||
"center center"
|
|
||||||
else
|
|
||||||
"#{position} center"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
position = position.
|
|
||||||
gsub(/top/, "0%").
|
|
||||||
gsub(/bottom/, "100%").
|
|
||||||
gsub(/left/,"0%").
|
|
||||||
gsub(/right/,"100%").
|
|
||||||
gsub(/center/, "50%")
|
|
||||||
SpaceList.new(*position.split(/ /).map{|s| Sass::Script::String.new(s)})
|
|
||||||
end
|
|
||||||
|
|
||||||
def color_stops(*args)
|
|
||||||
List.new(*args.map do |arg|
|
|
||||||
case arg
|
|
||||||
when ColorStop
|
|
||||||
arg
|
|
||||||
when Sass::Script::Color
|
|
||||||
ColorStop.new(arg)
|
|
||||||
when Sass::Script::String
|
|
||||||
# We get a string as the result of concatenation
|
|
||||||
# So we have to reparse the expression
|
|
||||||
parse_color_stop(arg)
|
|
||||||
else
|
|
||||||
raise Sass::SyntaxError, "Not a valid color stop: #{arg.class.name}: #{arg}"
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns a comma-delimited list after removing any non-true values
|
|
||||||
def compact(*args)
|
|
||||||
List.new(*args.reject{|a| !a.to_bool})
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns a list object from a value that was passed.
|
|
||||||
# This can be used to unpack a space separated list that got turned
|
|
||||||
# into a string by sass before it was passed to a mixin.
|
|
||||||
def _compass_list(arg)
|
|
||||||
return arg if arg.is_a?(List)
|
|
||||||
values = case arg
|
|
||||||
when Sass::Script::String
|
|
||||||
expr = Sass::Script::Parser.parse(arg.value, 0, 0)
|
|
||||||
if expr.is_a?(Sass::Script::Operation)
|
|
||||||
extract_list_values(expr)
|
|
||||||
elsif expr.is_a?(Sass::Script::Funcall)
|
|
||||||
expr.perform(Sass::Environment.new) #we already evaluated the args in context so no harm in using a fake env
|
|
||||||
else
|
|
||||||
[arg]
|
|
||||||
end
|
|
||||||
else
|
|
||||||
[arg]
|
|
||||||
end
|
|
||||||
|
|
||||||
SpaceList.new(*values)
|
|
||||||
end
|
|
||||||
|
|
||||||
def _compass_space_list(list)
|
|
||||||
if list.is_a?(List) && !list.is_a?(SpaceList)
|
|
||||||
SpaceList.new(*list.values)
|
|
||||||
elsif list.is_a?(SpaceList)
|
|
||||||
list
|
|
||||||
else
|
|
||||||
SpaceList.new(list)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def _compass_list_size(list)
|
|
||||||
Sass::Script::Number.new(list.size)
|
|
||||||
end
|
|
||||||
|
|
||||||
# slice a sublist from a list
|
|
||||||
def _compass_slice(list, start_index, end_index = nil)
|
|
||||||
end_index ||= Sass::Script::Number.new(-1)
|
|
||||||
start_index = start_index.value
|
|
||||||
end_index = end_index.value
|
|
||||||
start_index -= 1 unless start_index < 0
|
|
||||||
end_index -= 1 unless end_index < 0
|
|
||||||
list.class.new *list.values[start_index..end_index]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Check if any of the arguments passed have a tendency towards vendor prefixing.
|
|
||||||
def prefixed(prefix, *args)
|
|
||||||
method = prefix.value.sub(/^-/,"")
|
|
||||||
args.map!{|a| a.is_a?(List) ? a.values : a}.flatten!
|
|
||||||
Sass::Script::Bool.new(args.any?{|a| a.supports?(method)})
|
|
||||||
end
|
|
||||||
|
|
||||||
%w(webkit moz o ms svg pie css2).each do |prefix|
|
|
||||||
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
||||||
def _#{prefix}(*args)
|
|
||||||
List.new(*args.map! {|a| add_prefix("#{prefix}", a)})
|
|
||||||
end
|
|
||||||
RUBY
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def add_prefix(prefix, object)
|
|
||||||
if object.is_a?(List)
|
|
||||||
object.class.new(object.value.map{|e|
|
|
||||||
add_prefix(prefix, e)
|
|
||||||
})
|
|
||||||
elsif object.respond_to?(:supports?) && object.supports?(prefix)
|
|
||||||
object.options = options
|
|
||||||
object.send(:"to_#{prefix_method}")
|
|
||||||
else
|
|
||||||
object
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def color_stop?(arg)
|
|
||||||
parse_color_stop(arg)
|
|
||||||
rescue
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def assert_list(value)
|
|
||||||
unless value.is_a?(List)
|
|
||||||
raise ArgumentError.new("#{value.inspect} is not a list")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
module ListBasedSassSupport
|
|
||||||
# given a position list, return a corresponding position in percents
|
|
||||||
def grad_point(position)
|
|
||||||
position = unless position.is_a?(Sass::Script::List)
|
|
||||||
Sass::Script::List.new([position], :space)
|
|
||||||
else
|
|
||||||
Sass::Script::List.new(position.value.dup, position.separator)
|
|
||||||
end
|
|
||||||
position.value.reject!{|p| p.is_a?(Sass::Script::Number) && p.numerator_units.include?("deg")}
|
|
||||||
if (position.value.first.value =~ /top|bottom/) or (position.value.last.value =~ /left|right/)
|
|
||||||
# browsers are pretty forgiving of reversed positions so we are too.
|
|
||||||
position.value.reverse!
|
|
||||||
end
|
|
||||||
if position.value.size == 1
|
|
||||||
if position.value.first.value =~ /top|bottom/
|
|
||||||
position.value.unshift Sass::Script::String.new("center")
|
|
||||||
elsif position.value.first.value =~ /left|right/
|
|
||||||
position.value.push Sass::Script::String.new("center")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
position.value.map! do |p|
|
|
||||||
case p.value
|
|
||||||
when /top|left/
|
|
||||||
Sass::Script::Number.new(0, ["%"])
|
|
||||||
when /bottom|right/
|
|
||||||
Sass::Script::Number.new(100, ["%"])
|
|
||||||
when /center/
|
|
||||||
Sass::Script::Number.new(50, ["%"])
|
|
||||||
else
|
|
||||||
p
|
|
||||||
end
|
|
||||||
end
|
|
||||||
position
|
|
||||||
end
|
|
||||||
|
|
||||||
def color_stops(*args)
|
|
||||||
Sass::Script::List.new(args.map do |arg|
|
|
||||||
case arg
|
|
||||||
when ColorStop
|
|
||||||
arg
|
|
||||||
when Sass::Script::Color
|
|
||||||
ColorStop.new(arg)
|
|
||||||
when Sass::Script::List
|
|
||||||
ColorStop.new(*arg.value)
|
|
||||||
else
|
|
||||||
raise Sass::SyntaxError, "Not a valid color stop: #{arg.class.name}: #{arg}"
|
|
||||||
end
|
|
||||||
end, :comma)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns a comma-delimited list after removing any non-true values
|
|
||||||
def compact(*args)
|
|
||||||
sep = :comma
|
|
||||||
if args.size == 1 && args.first.is_a?(Sass::Script::List)
|
|
||||||
args = args.first.value
|
|
||||||
sep = args.first.separator
|
|
||||||
end
|
|
||||||
Sass::Script::List.new(args.reject{|a| !a.to_bool}, sep)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns a list object from a value that was passed.
|
|
||||||
# This can be used to unpack a space separated list that got turned
|
|
||||||
# into a string by sass before it was passed to a mixin.
|
|
||||||
def _compass_list(arg)
|
|
||||||
if arg.is_a?(Sass::Script::List)
|
|
||||||
Sass::Script::List.new(arg.value.dup, arg.separator)
|
|
||||||
else
|
|
||||||
Sass::Script::List.new([arg], :space)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def _compass_space_list(list)
|
|
||||||
if list.is_a?(Sass::Script::List)
|
|
||||||
Sass::Script::List.new(list.value.dup, :space)
|
|
||||||
else
|
|
||||||
Sass::Script::List.new([list], :space)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def _compass_list_size(list)
|
|
||||||
assert_list list
|
|
||||||
Sass::Script::Number.new(list.value.size)
|
|
||||||
end
|
|
||||||
|
|
||||||
# slice a sublist from a list
|
|
||||||
def _compass_slice(list, start_index, end_index = nil)
|
|
||||||
end_index ||= Sass::Script::Number.new(-1)
|
|
||||||
start_index = start_index.value
|
|
||||||
end_index = end_index.value
|
|
||||||
start_index -= 1 unless start_index < 0
|
|
||||||
end_index -= 1 unless end_index < 0
|
|
||||||
Sass::Script::List.new list.values[start_index..end_index], list.separator
|
|
||||||
end
|
|
||||||
|
|
||||||
# Check if any of the arguments passed have require the vendor prefix.
|
|
||||||
def prefixed(prefix, *args)
|
|
||||||
aspect = prefix.value.sub(/^-/,"")
|
|
||||||
needed = args.any?{|a| a.respond_to?(:supports?) && a.supports?(aspect)}
|
|
||||||
Sass::Script::Bool.new(needed)
|
|
||||||
end
|
|
||||||
|
|
||||||
%w(webkit moz o ms svg pie css2).each do |prefix|
|
|
||||||
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
||||||
def _#{prefix}(*args)
|
|
||||||
Sass::Script::List.new(args.map! {|a| add_prefix("#{prefix}", a)}, :comma)
|
|
||||||
end
|
|
||||||
RUBY
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def add_prefix(prefix, object)
|
|
||||||
if object.is_a?(Sass::Script::List)
|
|
||||||
Sass::Script::List.new(object.value.map{|e|
|
|
||||||
add_prefix(prefix, e)
|
|
||||||
}, object.separator)
|
|
||||||
elsif object.respond_to?(:supports?) && object.supports?(prefix)
|
|
||||||
object.options = options
|
|
||||||
object.send(:"to_#{prefix}")
|
|
||||||
else
|
|
||||||
object
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def color_stop?(arg)
|
|
||||||
arg.is_a?(ColorStop) ||
|
|
||||||
(arg.is_a?(Sass::Script::List) && ColorStop.new(*arg.value)) ||
|
|
||||||
ColorStop.new(arg)
|
|
||||||
rescue
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def assert_list(value)
|
|
||||||
unless value.is_a?(Sass::Script::List)
|
|
||||||
raise ArgumentError.new("#{value.inspect} is not a list")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
class ColorStop < Sass::Script::Literal
|
class ColorStop < Sass::Script::Literal
|
||||||
attr_accessor :color, :stop
|
attr_accessor :color, :stop
|
||||||
@ -346,8 +33,6 @@ module Compass::SassExtensions::Functions::GradientSupport
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
GRADIENT_ASPECTS = %w(webkit moz svg pie css2).freeze
|
|
||||||
|
|
||||||
class RadialGradient < Sass::Script::Literal
|
class RadialGradient < Sass::Script::Literal
|
||||||
attr_accessor :position_and_angle, :shape_and_size, :color_stops
|
attr_accessor :position_and_angle, :shape_and_size, :color_stops
|
||||||
def children
|
def children
|
||||||
@ -458,11 +143,53 @@ module Compass::SassExtensions::Functions::GradientSupport
|
|||||||
|
|
||||||
module Functions
|
module Functions
|
||||||
|
|
||||||
# While supporting sass 3.1 and older versions, we need two different implementations.
|
# given a position list, return a corresponding position in percents
|
||||||
if defined?(Sass::Script::List)
|
def grad_point(position)
|
||||||
include ListBasedSassSupport
|
position = unless position.is_a?(Sass::Script::List)
|
||||||
|
Sass::Script::List.new([position], :space)
|
||||||
else
|
else
|
||||||
include ListFreeSassSupport
|
Sass::Script::List.new(position.value.dup, position.separator)
|
||||||
|
end
|
||||||
|
position.value.reject!{|p| p.is_a?(Sass::Script::Number) && p.numerator_units.include?("deg")}
|
||||||
|
if (position.value.first.value =~ /top|bottom/) or (position.value.last.value =~ /left|right/)
|
||||||
|
# browsers are pretty forgiving of reversed positions so we are too.
|
||||||
|
position.value.reverse!
|
||||||
|
end
|
||||||
|
if position.value.size == 1
|
||||||
|
if position.value.first.value =~ /top|bottom/
|
||||||
|
position.value.unshift Sass::Script::String.new("center")
|
||||||
|
elsif position.value.first.value =~ /left|right/
|
||||||
|
position.value.push Sass::Script::String.new("center")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
position.value.map! do |p|
|
||||||
|
case p.value
|
||||||
|
when /top|left/
|
||||||
|
Sass::Script::Number.new(0, ["%"])
|
||||||
|
when /bottom|right/
|
||||||
|
Sass::Script::Number.new(100, ["%"])
|
||||||
|
when /center/
|
||||||
|
Sass::Script::Number.new(50, ["%"])
|
||||||
|
else
|
||||||
|
p
|
||||||
|
end
|
||||||
|
end
|
||||||
|
position
|
||||||
|
end
|
||||||
|
|
||||||
|
def color_stops(*args)
|
||||||
|
Sass::Script::List.new(args.map do |arg|
|
||||||
|
case arg
|
||||||
|
when ColorStop
|
||||||
|
arg
|
||||||
|
when Sass::Script::Color
|
||||||
|
ColorStop.new(arg)
|
||||||
|
when Sass::Script::List
|
||||||
|
ColorStop.new(*arg.value)
|
||||||
|
else
|
||||||
|
raise Sass::SyntaxError, "Not a valid color stop: #{arg.class.name}: #{arg}"
|
||||||
|
end
|
||||||
|
end, :comma)
|
||||||
end
|
end
|
||||||
|
|
||||||
def radial_gradient(position_and_angle, shape_and_size, *color_stops)
|
def radial_gradient(position_and_angle, shape_and_size, *color_stops)
|
||||||
@ -519,7 +246,7 @@ module Compass::SassExtensions::Functions::GradientSupport
|
|||||||
end
|
end
|
||||||
|
|
||||||
def color_stops_in_percentages(color_list)
|
def color_stops_in_percentages(color_list)
|
||||||
assert_list(color_list)
|
assert_type color_list, :List
|
||||||
color_list = normalize_stops(color_list)
|
color_list = normalize_stops(color_list)
|
||||||
max = color_list.value.last.stop
|
max = color_list.value.last.stop
|
||||||
last_value = nil
|
last_value = nil
|
||||||
@ -538,13 +265,13 @@ module Compass::SassExtensions::Functions::GradientSupport
|
|||||||
|
|
||||||
# returns the end position of the gradient from the color stop
|
# returns the end position of the gradient from the color stop
|
||||||
def grad_end_position(color_list, radial = Sass::Script::Bool.new(false))
|
def grad_end_position(color_list, radial = Sass::Script::Bool.new(false))
|
||||||
assert_list(color_list)
|
assert_type color_list, :List
|
||||||
default = Sass::Script::Number.new(100)
|
default = Sass::Script::Number.new(100)
|
||||||
grad_position(color_list, Sass::Script::Number.new(color_list.value.size), default, radial)
|
grad_position(color_list, Sass::Script::Number.new(color_list.value.size), default, radial)
|
||||||
end
|
end
|
||||||
|
|
||||||
def grad_position(color_list, index, default, radial = Sass::Script::Bool.new(false))
|
def grad_position(color_list, index, default, radial = Sass::Script::Bool.new(false))
|
||||||
assert_list(color_list)
|
assert_type color_list, :List
|
||||||
stop = color_list.value[index.value - 1].stop
|
stop = color_list.value[index.value - 1].stop
|
||||||
if stop && radial.to_bool
|
if stop && radial.to_bool
|
||||||
orig_stop = stop
|
orig_stop = stop
|
||||||
@ -587,55 +314,16 @@ module Compass::SassExtensions::Functions::GradientSupport
|
|||||||
inline_image_string(svg.gsub(/\s+/, ' '), 'image/svg+xml')
|
inline_image_string(svg.gsub(/\s+/, ' '), 'image/svg+xml')
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get the nth value from a list
|
|
||||||
def _compass_nth(list, place)
|
|
||||||
assert_list list
|
|
||||||
if place.value == "first"
|
|
||||||
list.value.first
|
|
||||||
elsif place.value == "last"
|
|
||||||
list.value.last
|
|
||||||
else
|
|
||||||
list.value[place.value - 1]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def blank(obj)
|
|
||||||
case obj
|
|
||||||
when Sass::Script::Bool
|
|
||||||
Sass::Script::Bool.new !obj.to_bool
|
|
||||||
when Sass::Script::String
|
|
||||||
Sass::Script::Bool.new obj.value.strip.size == 0
|
|
||||||
when Sass::Script::List
|
|
||||||
Sass::Script::Bool.new obj.value.size == 0 || obj.value.all?{|el| blank(el).to_bool}
|
|
||||||
else
|
|
||||||
Sass::Script::Bool.new false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# After using the sass script parser to parse a string, this reconstructs
|
def color_stop?(arg)
|
||||||
# a list from operands to the space/concat operation
|
arg.is_a?(ColorStop) ||
|
||||||
def extract_list_values(operation)
|
(arg.is_a?(Sass::Script::List) && ColorStop.new(*arg.value)) ||
|
||||||
left = operation.instance_variable_get("@operand1")
|
ColorStop.new(arg)
|
||||||
right = operation.instance_variable_get("@operand2")
|
rescue
|
||||||
left = extract_list_values(left) if left.is_a?(Sass::Script::Operation)
|
nil
|
||||||
right = extract_list_values(right) if right.is_a?(Sass::Script::Operation)
|
|
||||||
left = literalize(left) unless left.is_a?(Array)
|
|
||||||
right = literalize(right) unless right.is_a?(Array)
|
|
||||||
Array(left) + Array(right)
|
|
||||||
end
|
|
||||||
# Makes a literal from other various script nodes.
|
|
||||||
def literalize(node)
|
|
||||||
case node
|
|
||||||
when Sass::Script::Literal
|
|
||||||
node
|
|
||||||
when Sass::Script::Funcall
|
|
||||||
node.perform(Sass::Environment.new)
|
|
||||||
else
|
|
||||||
Sass::Script::String.new(node.to_s)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def normalize_stops(color_list)
|
def normalize_stops(color_list)
|
||||||
positions = color_list.value.map{|obj| obj.dup}
|
positions = color_list.value.map{|obj| obj.dup}
|
||||||
# fill in the start and end positions, if unspecified
|
# fill in the start and end positions, if unspecified
|
||||||
@ -726,24 +414,32 @@ EOS
|
|||||||
end
|
end
|
||||||
|
|
||||||
def _center_position
|
def _center_position
|
||||||
if defined?(Sass::Script::List)
|
|
||||||
Sass::Script::List.new([
|
Sass::Script::List.new([
|
||||||
Sass::Script::String.new("center"),
|
Sass::Script::String.new("center"),
|
||||||
Sass::Script::String.new("center")
|
Sass::Script::String.new("center")
|
||||||
],:space)
|
],:space)
|
||||||
else
|
|
||||||
Sass::Script::String.new("center center")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module Assertions
|
||||||
|
def assert_type(value, type, name = nil)
|
||||||
|
return if value.is_a?(Sass::Script.const_get(type))
|
||||||
|
err = "#{value.inspect} is not a #{type.to_s.downcase}"
|
||||||
|
err = "$#{name}: " + err if name
|
||||||
|
raise ArgumentError.new(err)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class LinearGradient < Sass::Script::Literal
|
class LinearGradient < Sass::Script::Literal
|
||||||
|
include Assertions
|
||||||
include Functions
|
include Functions
|
||||||
include Compass::SassExtensions::Functions::Constants
|
include Compass::SassExtensions::Functions::Constants
|
||||||
include Compass::SassExtensions::Functions::InlineImage
|
include Compass::SassExtensions::Functions::InlineImage
|
||||||
end
|
end
|
||||||
|
|
||||||
class RadialGradient < Sass::Script::Literal
|
class RadialGradient < Sass::Script::Literal
|
||||||
|
include Assertions
|
||||||
include Functions
|
include Functions
|
||||||
include Compass::SassExtensions::Functions::Constants
|
include Compass::SassExtensions::Functions::Constants
|
||||||
include Compass::SassExtensions::Functions::InlineImage
|
include Compass::SassExtensions::Functions::InlineImage
|
||||||
|
@ -1,4 +1,79 @@
|
|||||||
module Compass::SassExtensions::Functions::Lists
|
module Compass::SassExtensions::Functions::Lists
|
||||||
|
|
||||||
|
# Returns true when the object is false, an empty string, or an empty list
|
||||||
|
def blank(obj)
|
||||||
|
case obj
|
||||||
|
when Sass::Script::Bool
|
||||||
|
Sass::Script::Bool.new !obj.to_bool
|
||||||
|
when Sass::Script::String
|
||||||
|
Sass::Script::Bool.new obj.value.strip.size == 0
|
||||||
|
when Sass::Script::List
|
||||||
|
Sass::Script::Bool.new obj.value.size == 0 || obj.value.all?{|el| blank(el).to_bool}
|
||||||
|
else
|
||||||
|
Sass::Script::Bool.new false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns a new list after removing any non-true values
|
||||||
|
def compact(*args)
|
||||||
|
sep = :comma
|
||||||
|
if args.size == 1 && args.first.is_a?(Sass::Script::List)
|
||||||
|
args = args.first.value
|
||||||
|
sep = args.first.separator
|
||||||
|
end
|
||||||
|
Sass::Script::List.new(args.reject{|a| !a.to_bool}, sep)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get the nth value from a list
|
||||||
|
def _compass_nth(list, place)
|
||||||
|
assert_type list, :List
|
||||||
|
if place.value == "first"
|
||||||
|
list.value.first
|
||||||
|
elsif place.value == "last"
|
||||||
|
list.value.last
|
||||||
|
else
|
||||||
|
list.value[place.value - 1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns a list object from a value that was passed.
|
||||||
|
# This can be used to unpack a space separated list that got turned
|
||||||
|
# into a string by sass before it was passed to a mixin.
|
||||||
|
def _compass_list(arg)
|
||||||
|
if arg.is_a?(Sass::Script::List)
|
||||||
|
Sass::Script::List.new(arg.value.dup, arg.separator)
|
||||||
|
else
|
||||||
|
Sass::Script::List.new([arg], :space)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# If the argument is a list, it will return a new list that is space delimited
|
||||||
|
# Otherwise it returns a new, single element, space-delimited list.
|
||||||
|
def _compass_space_list(list)
|
||||||
|
if list.is_a?(Sass::Script::List)
|
||||||
|
Sass::Script::List.new(list.value.dup, :space)
|
||||||
|
else
|
||||||
|
Sass::Script::List.new([list], :space)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns the size of the list.
|
||||||
|
def _compass_list_size(list)
|
||||||
|
assert_list list
|
||||||
|
Sass::Script::Number.new(list.value.size)
|
||||||
|
end
|
||||||
|
|
||||||
|
# slice a sublist from a list
|
||||||
|
def _compass_slice(list, start_index, end_index = nil)
|
||||||
|
end_index ||= Sass::Script::Number.new(-1)
|
||||||
|
start_index = start_index.value
|
||||||
|
end_index = end_index.value
|
||||||
|
start_index -= 1 unless start_index < 0
|
||||||
|
end_index -= 1 unless end_index < 0
|
||||||
|
Sass::Script::List.new list.values[start_index..end_index], list.separator
|
||||||
|
end
|
||||||
|
|
||||||
|
# returns the first value of a space delimited list.
|
||||||
def first_value_of(list)
|
def first_value_of(list)
|
||||||
if list.is_a?(Sass::Script::String)
|
if list.is_a?(Sass::Script::String)
|
||||||
Sass::Script::String.new(list.value.split(/\s+/).first)
|
Sass::Script::String.new(list.value.split(/\s+/).first)
|
||||||
@ -8,4 +83,13 @@ module Compass::SassExtensions::Functions::Lists
|
|||||||
list
|
list
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def assert_list(value)
|
||||||
|
unless value.is_a?(Sass::Script::List)
|
||||||
|
raise ArgumentError.new("#{value.inspect} is not a list")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -2,69 +2,6 @@ require 'sass/script/node'
|
|||||||
require 'sass/script/literal'
|
require 'sass/script/literal'
|
||||||
require 'sass/script/funcall'
|
require 'sass/script/funcall'
|
||||||
|
|
||||||
module Compass
|
|
||||||
module BrowserSupport
|
|
||||||
extend self
|
|
||||||
|
|
||||||
ASPECTS = %w(webkit moz o ms svg pie css2)
|
|
||||||
|
|
||||||
SIMPLE_FUNCTIONS = {
|
|
||||||
"image" => %w(), # No browsers implement this yet.
|
|
||||||
"cross-fade" => %w() # No browsers implement this yet.
|
|
||||||
}
|
|
||||||
|
|
||||||
# Adds support for one or more aspects for the given simple function
|
|
||||||
# Example:
|
|
||||||
#
|
|
||||||
# Compass::BrowserSupport.add_support("image", "moz", "webkit")
|
|
||||||
# # => Adds support for moz and webkit to the image() function.
|
|
||||||
#
|
|
||||||
# This function can be called one or more times in a compass configuration
|
|
||||||
# file in order to add support for new, simple browser functions without
|
|
||||||
# waiting for a new compass release.
|
|
||||||
def add_support(function, *aspects)
|
|
||||||
aspects.each do |aspect|
|
|
||||||
unless ASPECTS.include?(aspect)
|
|
||||||
Compass::Util.compass_warn "Unknown support aspect: #{aspect}"
|
|
||||||
next
|
|
||||||
end
|
|
||||||
unless supports?(function, aspect)
|
|
||||||
SIMPLE_FUNCTIONS[function.to_s] ||= []
|
|
||||||
SIMPLE_FUNCTIONS[function.to_s] << aspect.to_s
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Removes support for one or more aspects for the given simple function
|
|
||||||
# Example:
|
|
||||||
#
|
|
||||||
# Compass::BrowserSupport.remove_support("image", "o", "ms")
|
|
||||||
# # => Adds support for moz and webkit to the image() function.
|
|
||||||
#
|
|
||||||
# This function can be called one or more times in a compass configuration
|
|
||||||
# file in order to remove support for simple functions that no longer need to
|
|
||||||
# a prefix without waiting for a new compass release.
|
|
||||||
def remove_support(function, *aspects)
|
|
||||||
aspects.each do |aspect|
|
|
||||||
unless ASPECTS.include?(aspect)
|
|
||||||
Compass::Util.compass_warn "Unknown support aspect: #{aspect}"
|
|
||||||
next
|
|
||||||
end
|
|
||||||
SIMPLE_FUNCTIONS[function.to_s].reject!{|a| a == aspect.to_s}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def supports?(function, aspect)
|
|
||||||
SIMPLE_FUNCTIONS.has_key?(function.to_s) && SIMPLE_FUNCTIONS[function.to_s].include?(aspect.to_s)
|
|
||||||
end
|
|
||||||
|
|
||||||
def has_aspect?(function)
|
|
||||||
SIMPLE_FUNCTIONS.has_key?(function.to_s) && SIMPLE_FUNCTIONS[function.to_s].size > 0
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
module Sass::Script
|
module Sass::Script
|
||||||
module HasSimpleCrossBrowserFunctionSupport
|
module HasSimpleCrossBrowserFunctionSupport
|
||||||
def supports?(aspect)
|
def supports?(aspect)
|
||||||
|
Loading…
Reference in New Issue
Block a user