Infrastructure for cross browser support of simple, experimental functions
This commit is contained in:
parent
4c289c9db0
commit
15f760e002
@ -26,6 +26,21 @@ The Documentation for the [latest preview release](http://beta.compass-style.org
|
|||||||
The CLI options will still override the values set within the config file, but they might
|
The CLI options will still override the values set within the config file, but they might
|
||||||
inform other values. For instance `compass compile -e production` will have the environment
|
inform other values. For instance `compass compile -e production` will have the environment
|
||||||
parameter preset to `:production` so that you can set other values in the project accordingly.
|
parameter preset to `:production` so that you can set other values in the project accordingly.
|
||||||
|
* New infrastructure for supporting experimental css3 functions that have the same syntax
|
||||||
|
across all browsers. It is now possible to configure which browsers support which experimental
|
||||||
|
functions outside of the compass release cycle by calling
|
||||||
|
`Compass::BrowserSupport.add_support('function', 'prefix')` and
|
||||||
|
`Compass::BrowserSupport.remove_support('function', 'prefix')`.
|
||||||
|
Once properly configured, the browser specific aspect can be inspected
|
||||||
|
via the `prefixed()` helper function and accessed via the various support
|
||||||
|
aspect helpers like `-moz()` and `-webkit()`. For example, if you call:
|
||||||
|
`Compass::BrowserSupport.add_support('image', 'webkit')` in your config
|
||||||
|
then in your stylesheet, `prefixed(-webkit, image("foo.png", "foo.gif"))` would
|
||||||
|
return true and `prefixed(-moz, image("foo.png", "foo.gif"))` would return false.
|
||||||
|
Additionally `-webkit(image("foo.png", "foo.gif"))` will return
|
||||||
|
`-webkit-image("foo.png", "foo.gif")`. This is very useful for creating mixins
|
||||||
|
that can support a range of inputs and vary the outputs according to the
|
||||||
|
support needs.
|
||||||
|
|
||||||
|
|
||||||
0.11.alpha.4 (12/08/2010)
|
0.11.alpha.4 (12/08/2010)
|
||||||
|
@ -133,29 +133,29 @@ module Compass::SassExtensions::Functions::GradientSupport
|
|||||||
|
|
||||||
# Check if any of the arguments passed have a tendency towards vendor prefixing.
|
# Check if any of the arguments passed have a tendency towards vendor prefixing.
|
||||||
def prefixed(prefix, *args)
|
def prefixed(prefix, *args)
|
||||||
method = prefix.value.sub(/^-/,"to_").to_sym
|
method = prefix.value.sub(/^-/,"")
|
||||||
args.map!{|a| a.is_a?(List) ? a.values : a}.flatten!
|
args.map!{|a| a.is_a?(List) ? a.values : a}.flatten!
|
||||||
Sass::Script::Bool.new(args.any?{|a| a.respond_to?(method)})
|
Sass::Script::Bool.new(args.any?{|a| a.supports?(method)})
|
||||||
end
|
end
|
||||||
|
|
||||||
%w(webkit moz o ms svg pie css2).each do |prefix|
|
%w(webkit moz o ms svg pie css2).each do |prefix|
|
||||||
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
||||||
def _#{prefix}(*args)
|
def _#{prefix}(*args)
|
||||||
List.new(*args.map! {|a| add_prefix(:to_#{prefix}, a)})
|
List.new(*args.map! {|a| add_prefix("#{prefix}", a)})
|
||||||
end
|
end
|
||||||
RUBY
|
RUBY
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def add_prefix(prefix_method, object)
|
def add_prefix(prefix, object)
|
||||||
if object.is_a?(List)
|
if object.is_a?(List)
|
||||||
object.class.new(object.value.map{|e|
|
object.class.new(object.value.map{|e|
|
||||||
add_prefix(prefix_method, e)
|
add_prefix(prefix, e)
|
||||||
})
|
})
|
||||||
elsif object.respond_to?(prefix_method)
|
elsif object.respond_to?(:supports?) && object.supports?(prefix)
|
||||||
object.options = options
|
object.options = options
|
||||||
object.send(prefix_method)
|
object.send(:"to_#{prefix_method}")
|
||||||
else
|
else
|
||||||
object
|
object
|
||||||
end
|
end
|
||||||
@ -269,33 +269,31 @@ module Compass::SassExtensions::Functions::GradientSupport
|
|||||||
Sass::Script::List.new list.values[start_index..end_index], list.separator
|
Sass::Script::List.new list.values[start_index..end_index], list.separator
|
||||||
end
|
end
|
||||||
|
|
||||||
# Check if any of the arguments passed have a tendency towards vendor prefixing.
|
# Check if any of the arguments passed have require the vendor prefix.
|
||||||
def prefixed(prefix, *args)
|
def prefixed(prefix, *args)
|
||||||
method = prefix.value.sub(/^-/,"to_").to_sym
|
aspect = prefix.value.sub(/^-/,"")
|
||||||
2.times do
|
needed = args.any?{|a| a.respond_to?(:supports?) && a.supports?(aspect)}
|
||||||
args.map!{|a| a.is_a?(Sass::Script::List) ? a.value : a}.flatten!
|
Sass::Script::Bool.new(needed)
|
||||||
end
|
|
||||||
Sass::Script::Bool.new(args.any?{|a| a.respond_to?(method)})
|
|
||||||
end
|
end
|
||||||
|
|
||||||
%w(webkit moz o ms svg pie css2).each do |prefix|
|
%w(webkit moz o ms svg pie css2).each do |prefix|
|
||||||
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
||||||
def _#{prefix}(*args)
|
def _#{prefix}(*args)
|
||||||
Sass::Script::List.new(args.map! {|a| add_prefix(:to_#{prefix}, a)}, :comma)
|
Sass::Script::List.new(args.map! {|a| add_prefix("#{prefix}", a)}, :comma)
|
||||||
end
|
end
|
||||||
RUBY
|
RUBY
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def add_prefix(prefix_method, object)
|
def add_prefix(prefix, object)
|
||||||
if object.is_a?(Sass::Script::List)
|
if object.is_a?(Sass::Script::List)
|
||||||
Sass::Script::List.new(object.value.map{|e|
|
Sass::Script::List.new(object.value.map{|e|
|
||||||
add_prefix(prefix_method, e)
|
add_prefix(prefix, e)
|
||||||
}, object.separator)
|
}, object.separator)
|
||||||
elsif object.respond_to?(prefix_method)
|
elsif object.respond_to?(:supports?) && object.supports?(prefix)
|
||||||
object.options = options
|
object.options = options
|
||||||
object.send(prefix_method)
|
object.send(:"to_#{prefix}")
|
||||||
else
|
else
|
||||||
object
|
object
|
||||||
end
|
end
|
||||||
@ -317,7 +315,6 @@ module Compass::SassExtensions::Functions::GradientSupport
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
class ColorStop < Sass::Script::Literal
|
class ColorStop < Sass::Script::Literal
|
||||||
attr_accessor :color, :stop
|
attr_accessor :color, :stop
|
||||||
def children
|
def children
|
||||||
@ -349,6 +346,8 @@ 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
|
||||||
@ -372,6 +371,12 @@ module Compass::SassExtensions::Functions::GradientSupport
|
|||||||
s << color_stops.to_s(options)
|
s << color_stops.to_s(options)
|
||||||
s << ")"
|
s << ")"
|
||||||
end
|
end
|
||||||
|
def supports?(aspect)
|
||||||
|
GRADIENT_ASPECTS.include?(aspect)
|
||||||
|
end
|
||||||
|
def has_aspect?
|
||||||
|
true
|
||||||
|
end
|
||||||
def to_webkit(options = self.options)
|
def to_webkit(options = self.options)
|
||||||
args = [
|
args = [
|
||||||
grad_point(position_and_angle || _center_position),
|
grad_point(position_and_angle || _center_position),
|
||||||
@ -421,6 +426,12 @@ module Compass::SassExtensions::Functions::GradientSupport
|
|||||||
s << color_stops.to_s(options)
|
s << color_stops.to_s(options)
|
||||||
s << ")"
|
s << ")"
|
||||||
end
|
end
|
||||||
|
def supports?(aspect)
|
||||||
|
GRADIENT_ASPECTS.include?(aspect)
|
||||||
|
end
|
||||||
|
def has_aspect?
|
||||||
|
true
|
||||||
|
end
|
||||||
def to_webkit(options = self.options)
|
def to_webkit(options = self.options)
|
||||||
args = []
|
args = []
|
||||||
args << grad_point(position_and_angle || Sass::Script::String.new("top"))
|
args << grad_point(position_and_angle || Sass::Script::String.new("top"))
|
||||||
@ -726,6 +737,7 @@ EOS
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class LinearGradient < Sass::Script::Literal
|
class LinearGradient < Sass::Script::Literal
|
||||||
include Functions
|
include Functions
|
||||||
include Compass::SassExtensions::Functions::Constants
|
include Compass::SassExtensions::Functions::Constants
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
%w(traversal).each do |patch|
|
%w(traversal browser_support).each do |patch|
|
||||||
require "compass/sass_extensions/monkey_patches/#{patch}"
|
require "compass/sass_extensions/monkey_patches/#{patch}"
|
||||||
end
|
end
|
||||||
|
152
lib/compass/sass_extensions/monkey_patches/browser_support.rb
Normal file
152
lib/compass/sass_extensions/monkey_patches/browser_support.rb
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
require 'sass/script/node'
|
||||||
|
require 'sass/script/literal'
|
||||||
|
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 HasSimpleCrossBrowserFunctionSupport
|
||||||
|
def supports?(aspect)
|
||||||
|
return true if Compass::BrowserSupport.supports?(name, aspect)
|
||||||
|
children.any? {|child| child.respond_to?(:supports?) && child.supports?(aspect) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_aspect?(children = nil)
|
||||||
|
children ||= self.children
|
||||||
|
return true if Compass::BrowserSupport.has_aspect?(name)
|
||||||
|
children.any? {|child| child.respond_to?(:has_aspect?) && child.has_aspect? }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class CrossBrowserFunctionCall < Literal
|
||||||
|
|
||||||
|
attr_accessor :name, :args
|
||||||
|
|
||||||
|
include HasSimpleCrossBrowserFunctionSupport
|
||||||
|
|
||||||
|
def initialize(name, args)
|
||||||
|
self.name = name
|
||||||
|
self.args = args
|
||||||
|
end
|
||||||
|
|
||||||
|
def children
|
||||||
|
args
|
||||||
|
end
|
||||||
|
|
||||||
|
def inspect
|
||||||
|
to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s(options = self.options)
|
||||||
|
s = "#{name}(#{args.join(", ")})"
|
||||||
|
end
|
||||||
|
|
||||||
|
%w(webkit moz o ms svg pie css2).each do |prefix|
|
||||||
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
||||||
|
def to_#{prefix}(options = self.options)
|
||||||
|
prefixed_args = args.map do |arg|
|
||||||
|
arg.respond_to?(:to_#{prefix}) ? arg.to_#{prefix}(options) : arg
|
||||||
|
end
|
||||||
|
prefixed_name = if Compass::BrowserSupport.supports?(name, "#{prefix}")
|
||||||
|
"-#{prefix}-\#{name}"
|
||||||
|
else
|
||||||
|
name
|
||||||
|
end
|
||||||
|
contents = prefixed_args.join(', ')
|
||||||
|
if contents.size > 0
|
||||||
|
opts(Sass::Script::String.new("\#{prefixed_name}(\#{contents})"))
|
||||||
|
else
|
||||||
|
opts(Sass::Script::String.new(""))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
class Funcall < Node
|
||||||
|
include HasSimpleCrossBrowserFunctionSupport
|
||||||
|
|
||||||
|
alias sass_to_literal to_literal
|
||||||
|
|
||||||
|
def to_literal(args)
|
||||||
|
if has_aspect?(args)
|
||||||
|
CrossBrowserFunctionCall.new(name, args)
|
||||||
|
else
|
||||||
|
sass_to_literal(args)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class List < Literal
|
||||||
|
def supports?(aspect)
|
||||||
|
children.any? {|child| child.respond_to?(:supports?) && child.supports?(aspect) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_aspect?
|
||||||
|
children.any? {|child| child.respond_to?(:has_aspect?) && child.has_aspect? }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
@ -96,6 +96,21 @@
|
|||||||
background-image: -moz-radial-gradient(#dddddd, #aaaaaa 100px);
|
background-image: -moz-radial-gradient(#dddddd, #aaaaaa 100px);
|
||||||
background-image: radial-gradient(#dddddd, #aaaaaa 100px); }
|
background-image: radial-gradient(#dddddd, #aaaaaa 100px); }
|
||||||
|
|
||||||
|
.image-fallback {
|
||||||
|
background-image: image(-webkit-gradient(radial, 50% 50%, 0, 50% 50%, 100, color-stop(0%, #dddddd), color-stop(100%, #aaaaaa)), url('/images/4x6.png?busted=true'), #cc0000);
|
||||||
|
background-image: image(-moz-radial-gradient(#dddddd, #aaaaaa 100px), url('/images/4x6.png?busted=true'), #cc0000);
|
||||||
|
background-image: image(radial-gradient(#dddddd, #aaaaaa 100px), url('/images/4x6.png?busted=true'), #cc0000); }
|
||||||
|
|
||||||
|
.cross-fade {
|
||||||
|
background-image: cross-fade(-webkit-gradient(radial, 50% 50%, 0, 50% 50%, 100, color-stop(0%, #dddddd), color-stop(100%, #aaaaaa)), url('/images/4x6.png?busted=true'));
|
||||||
|
background-image: cross-fade(-moz-radial-gradient(#dddddd, #aaaaaa 100px), url('/images/4x6.png?busted=true'));
|
||||||
|
background-image: cross-fade(radial-gradient(#dddddd, #aaaaaa 100px), url('/images/4x6.png?busted=true')); }
|
||||||
|
|
||||||
|
.unknown-function-wrapper {
|
||||||
|
background: foo(-webkit-gradient(radial, 50% 50%, 0, 50% 50%, 100, color-stop(0%, #dddddd), color-stop(100%, #aaaaaa)));
|
||||||
|
background: foo(-moz-radial-gradient(#dddddd, #aaaaaa 100px));
|
||||||
|
background: foo(radial-gradient(#dddddd, #aaaaaa 100px)); }
|
||||||
|
|
||||||
.linear-1 {
|
.linear-1 {
|
||||||
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #dddddd), color-stop(100%, #aaaaaa));
|
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #dddddd), color-stop(100%, #aaaaaa));
|
||||||
background-image: -moz-linear-gradient(top, #dddddd, #aaaaaa);
|
background-image: -moz-linear-gradient(top, #dddddd, #aaaaaa);
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
@charset "UTF-8";
|
|
||||||
.pie-element, .bordered, .gradient {
|
.pie-element, .bordered, .gradient {
|
||||||
behavior: url('/tmp/PIE.htc');
|
behavior: url('/tmp/PIE.htc');
|
||||||
position: relative; }
|
position: relative; }
|
||||||
|
@ -58,6 +58,15 @@ $experimental-support-for-svg: false
|
|||||||
.bg-radial-gradient-no-position
|
.bg-radial-gradient-no-position
|
||||||
+background-image(radial-gradient(#ddd, #aaa 100px))
|
+background-image(radial-gradient(#ddd, #aaa 100px))
|
||||||
|
|
||||||
|
.image-fallback
|
||||||
|
+background-image(image(radial-gradient(#ddd, #aaa 100px), image-url("4x6.png"), #c00))
|
||||||
|
|
||||||
|
.cross-fade
|
||||||
|
+background-image(cross-fade(radial-gradient(#ddd, #aaa 100px), image-url("4x6.png")))
|
||||||
|
|
||||||
|
.unknown-function-wrapper
|
||||||
|
+background(foo(radial-gradient(#ddd, #aaa 100px)))
|
||||||
|
|
||||||
.linear-1
|
.linear-1
|
||||||
+linear-gradient(color-stops(#dddddd, #aaaaaa))
|
+linear-gradient(color-stops(#dddddd, #aaaaaa))
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user