Infrastructure for cross browser support of simple, experimental functions
This commit is contained in:
parent
4c289c9db0
commit
15f760e002
doc-src/content
lib/compass/sass_extensions
test/fixtures/stylesheets/compass
@ -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
|
||||
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.
|
||||
* 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)
|
||||
|
@ -133,29 +133,29 @@ module Compass::SassExtensions::Functions::GradientSupport
|
||||
|
||||
# Check if any of the arguments passed have a tendency towards vendor prefixing.
|
||||
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!
|
||||
Sass::Script::Bool.new(args.any?{|a| a.respond_to?(method)})
|
||||
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(:to_#{prefix}, a)})
|
||||
List.new(*args.map! {|a| add_prefix("#{prefix}", a)})
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def add_prefix(prefix_method, object)
|
||||
def add_prefix(prefix, object)
|
||||
if object.is_a?(List)
|
||||
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.send(prefix_method)
|
||||
object.send(:"to_#{prefix_method}")
|
||||
else
|
||||
object
|
||||
end
|
||||
@ -269,33 +269,31 @@ module Compass::SassExtensions::Functions::GradientSupport
|
||||
Sass::Script::List.new list.values[start_index..end_index], list.separator
|
||||
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)
|
||||
method = prefix.value.sub(/^-/,"to_").to_sym
|
||||
2.times do
|
||||
args.map!{|a| a.is_a?(Sass::Script::List) ? a.value : a}.flatten!
|
||||
end
|
||||
Sass::Script::Bool.new(args.any?{|a| a.respond_to?(method)})
|
||||
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(:to_#{prefix}, a)}, :comma)
|
||||
Sass::Script::List.new(args.map! {|a| add_prefix("#{prefix}", a)}, :comma)
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def add_prefix(prefix_method, object)
|
||||
def add_prefix(prefix, object)
|
||||
if object.is_a?(Sass::Script::List)
|
||||
Sass::Script::List.new(object.value.map{|e|
|
||||
add_prefix(prefix_method, e)
|
||||
add_prefix(prefix, e)
|
||||
}, object.separator)
|
||||
elsif object.respond_to?(prefix_method)
|
||||
elsif object.respond_to?(:supports?) && object.supports?(prefix)
|
||||
object.options = options
|
||||
object.send(prefix_method)
|
||||
object.send(:"to_#{prefix}")
|
||||
else
|
||||
object
|
||||
end
|
||||
@ -317,7 +315,6 @@ module Compass::SassExtensions::Functions::GradientSupport
|
||||
|
||||
end
|
||||
|
||||
|
||||
class ColorStop < Sass::Script::Literal
|
||||
attr_accessor :color, :stop
|
||||
def children
|
||||
@ -349,6 +346,8 @@ module Compass::SassExtensions::Functions::GradientSupport
|
||||
end
|
||||
end
|
||||
|
||||
GRADIENT_ASPECTS = %w(webkit moz svg pie css2).freeze
|
||||
|
||||
class RadialGradient < Sass::Script::Literal
|
||||
attr_accessor :position_and_angle, :shape_and_size, :color_stops
|
||||
def children
|
||||
@ -372,6 +371,12 @@ module Compass::SassExtensions::Functions::GradientSupport
|
||||
s << color_stops.to_s(options)
|
||||
s << ")"
|
||||
end
|
||||
def supports?(aspect)
|
||||
GRADIENT_ASPECTS.include?(aspect)
|
||||
end
|
||||
def has_aspect?
|
||||
true
|
||||
end
|
||||
def to_webkit(options = self.options)
|
||||
args = [
|
||||
grad_point(position_and_angle || _center_position),
|
||||
@ -421,6 +426,12 @@ module Compass::SassExtensions::Functions::GradientSupport
|
||||
s << color_stops.to_s(options)
|
||||
s << ")"
|
||||
end
|
||||
def supports?(aspect)
|
||||
GRADIENT_ASPECTS.include?(aspect)
|
||||
end
|
||||
def has_aspect?
|
||||
true
|
||||
end
|
||||
def to_webkit(options = self.options)
|
||||
args = []
|
||||
args << grad_point(position_and_angle || Sass::Script::String.new("top"))
|
||||
@ -726,6 +737,7 @@ EOS
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class LinearGradient < Sass::Script::Literal
|
||||
include Functions
|
||||
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}"
|
||||
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: 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 {
|
||||
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);
|
||||
|
@ -1,4 +1,3 @@
|
||||
@charset "UTF-8";
|
||||
.pie-element, .bordered, .gradient {
|
||||
behavior: url('/tmp/PIE.htc');
|
||||
position: relative; }
|
||||
|
@ -58,6 +58,15 @@ $experimental-support-for-svg: false
|
||||
.bg-radial-gradient-no-position
|
||||
+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-gradient(color-stops(#dddddd, #aaaaaa))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user