compass 0.11.alpha.0 → 0.11.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/VERSION.yml +1 -1
  2. data/examples/compass/headers.txt +7 -0
  3. data/examples/compass/images/border2.png +0 -0
  4. data/examples/compass/images/icon-chrome.png +0 -0
  5. data/examples/compass/images/icon-firefox.png +0 -0
  6. data/examples/compass/images/icon-ie.png +0 -0
  7. data/examples/compass/images/icon-opera.png +0 -0
  8. data/examples/compass/images/icon-safari.png +0 -0
  9. data/examples/compass/pie.html.haml +73 -0
  10. data/examples/compass/src/pie.scss +110 -0
  11. data/features/command_line.feature +11 -33
  12. data/features/step_definitions/command_line_steps.rb +5 -5
  13. data/frameworks/blueprint/templates/project/screen.sass +5 -4
  14. data/frameworks/blueprint/templates/semantic/partials/_page.sass +3 -4
  15. data/frameworks/compass/stylesheets/compass/_css3.scss +16 -1
  16. data/frameworks/compass/stylesheets/compass/_support.scss +2 -0
  17. data/frameworks/compass/stylesheets/compass/css3/_background-clip.scss +1 -1
  18. data/frameworks/compass/stylesheets/compass/css3/_box-shadow.scss +85 -12
  19. data/frameworks/compass/stylesheets/compass/css3/_gradient.scss +6 -13
  20. data/frameworks/compass/stylesheets/compass/css3/_images.scss +42 -2
  21. data/frameworks/compass/stylesheets/compass/css3/_pie.scss +73 -0
  22. data/frameworks/compass/stylesheets/compass/css3/_text-shadow.scss +39 -4
  23. data/frameworks/compass/stylesheets/compass/css3/_transform-legacy.scss +87 -0
  24. data/frameworks/compass/stylesheets/compass/css3/_transform.scss +553 -54
  25. data/frameworks/compass/templates/ellipsis/manifest.rb +3 -3
  26. data/frameworks/compass/templates/extension/manifest.rb +1 -1
  27. data/frameworks/compass/templates/pie/LICENSE +12 -0
  28. data/frameworks/compass/templates/pie/LICENSE-APACHE2.txt +13 -0
  29. data/frameworks/compass/templates/pie/LICENSE-GPL2.txt +278 -0
  30. data/frameworks/compass/templates/pie/PIE.htc +77 -0
  31. data/frameworks/compass/templates/pie/manifest.rb +39 -0
  32. data/frameworks/compass/templates/pie/pie.scss +74 -0
  33. data/lib/compass.rb +1 -1
  34. data/lib/compass/exec/helpers.rb +1 -1
  35. data/lib/compass/installers/base.rb +15 -1
  36. data/lib/compass/rails.rb +2 -0
  37. data/lib/compass/sass_extensions/functions/colors.rb +1 -5
  38. data/lib/compass/sass_extensions/functions/constants.rb +52 -11
  39. data/lib/compass/sass_extensions/functions/gradient_support.rb +382 -190
  40. data/lib/compass/sass_extensions/functions/if.rb +2 -2
  41. data/lib/compass/sass_extensions/functions/lists.rb +2 -0
  42. data/lib/compass/sass_extensions/functions/urls.rb +1 -1
  43. data/lib/compass/util.rb +18 -0
  44. data/test/fixtures/stylesheets/compass/css/gradients.css +110 -85
  45. data/test/fixtures/stylesheets/compass/css/pie.css +25 -0
  46. data/test/fixtures/stylesheets/compass/css/text_shadow.css +14 -0
  47. data/test/fixtures/stylesheets/compass/sass/box.sass +1 -1
  48. data/test/fixtures/stylesheets/compass/sass/box_shadow.scss +2 -2
  49. data/test/fixtures/stylesheets/compass/sass/gradients.sass +1 -1
  50. data/test/fixtures/stylesheets/compass/sass/pie.scss +47 -0
  51. data/test/fixtures/stylesheets/compass/sass/text_shadow.scss +7 -0
  52. data/test/fixtures/stylesheets/compass/sass/transform.scss +1 -1
  53. metadata +30 -9
  54. data/frameworks/compass/stylesheets/compass/css3/_box-shadow-v2.scss +0 -98
  55. data/frameworks/compass/stylesheets/compass/css3/_text-shadow-v2.scss +0 -72
  56. data/frameworks/compass/stylesheets/compass/css3/_transform-v2.scss +0 -584
  57. data/frameworks/compass/stylesheets/compass/css3/_version-1.scss +0 -16
  58. data/frameworks/compass/stylesheets/compass/css3/_version-2.scss +0 -16
  59. data/lib/rails/init.rb +0 -2
@@ -0,0 +1,74 @@
1
+ // this file demonstrates how to use the CSS PIE extension for
2
+ // legacy versions of Internet Explorer. In many cases, PIE will allow
3
+ // you to style in CSS things that you'd have to do using image chops otherwise.
4
+ //
5
+ // Note: Each element that has PIE enabled on it will add about 10ms to your page load.
6
+ @import "compass/css3/pie";
7
+ @import "compass/css3";
8
+
9
+ // Set this to wherever you end up putting your behavior file.
10
+ //
11
+ // **Note:** this file must be served as a root-relative resource or
12
+ // else IE will interpret it as relative to the current webpage
13
+ // instead of the stylesheet.
14
+ //
15
+ // **Also Note:** this file must be delivered with a mime-type of:
16
+ //
17
+ // text/x-component
18
+ $pie-behavior: url("<%= config.http_stylesheets_path %>/PIE.htc");
19
+
20
+ // It is suggested that you use Sass's @extend directive to apply the PIE
21
+ // behavior to your elements. Setting this variable will tell the `pie` mixin
22
+ // to extend it. Or you can just extend the base class yourself.
23
+ $pie-base-class: pie-element;
24
+
25
+ // There are two approaches to creating PIE elements
26
+ // The default approach is to make the element position: relative.
27
+ .pie-element {
28
+ // relative is the default, so passing relative
29
+ // is redundant, but we do it here for clarity.
30
+ @include pie-element(relative);
31
+ }
32
+
33
+ .bordered {
34
+ @include pie; // Because $pie-base-class is set, this results in an extend of .pie-element.
35
+ @include border-radius(5px);
36
+ }
37
+
38
+ .gradient {
39
+ @include pie; // Because $pie-base-class is set, this results in an extend of .pie-element.
40
+ @include background(linear-gradient(#f00, #00f));
41
+ }
42
+
43
+
44
+ // But sometimes this messes up your positioning
45
+ // So you can also use z-indexing. In this case
46
+ // an ancestor element before or having the first
47
+ // opaque background should be marked as a pie-container
48
+ // which gives it a z-index of 0 (actually any z-index
49
+ // can be provided to the pie-container mixin).
50
+ // And then the pie element itself should be given
51
+ // a z-index of -1.
52
+ .pie-container {
53
+ @include pie-container;
54
+ }
55
+
56
+ .z-pie-element {
57
+ // this will get a z-index of 0, you can pass a z-index value if you want
58
+ @include pie-element(z-index);
59
+ }
60
+
61
+ // This is just a simple example of how to use the z-index approach.
62
+ .widget {
63
+ @extend .pie-container;
64
+ h3 {
65
+ @include pie(z-pie-element); // This will extend .z-pie-element instead of .pie-element
66
+ }
67
+ }
68
+
69
+
70
+ // Lastly, you can just include the pie-element mixin directly if you need to do a one-off:
71
+ .has-gradient {
72
+ @include pie-element(relative);
73
+ @include background(linear-gradient(#f00, #00f));
74
+ }
@@ -1,7 +1,7 @@
1
1
  module Compass
2
2
  end
3
3
 
4
- %w(dependencies sass_extensions core_ext version errors).each do |lib|
4
+ %w(dependencies util sass_extensions core_ext version errors).each do |lib|
5
5
  require "compass/#{lib}"
6
6
  end
7
7
 
@@ -7,7 +7,7 @@ module Compass::Exec
7
7
  else
8
8
  unless arguments.include?("-h") || arguments.include?("--help")
9
9
  Compass::Logger.new.red do
10
- Haml::Util.haml_warn "WARNING: This interface is deprecated. Please use the new subcommand interface.\nSee `compass help` for more information.\n"
10
+ Compass::Util.compass_warn "WARNING: This interface is deprecated. Please use the new subcommand interface.\nSee `compass help` for more information.\n"
11
11
  end
12
12
  end
13
13
  SwitchUI
@@ -71,7 +71,17 @@ module Compass
71
71
  define_method "install_#{type}" do |from, to, options|
72
72
  from = templatize(from)
73
73
  to = targetize(send(loc_method, to, options))
74
- copy from, to, nil, (installer_opts[:binary] || options[:binary])
74
+ is_binary = installer_opts[:binary] || options[:binary]
75
+ if is_binary
76
+ copy from, to, nil, is_binary
77
+ else
78
+ contents = File.new(from).read
79
+ if options.delete(:erb)
80
+ ctx = TemplateContext.ctx(:to => to, :options => options)
81
+ contents = process_erb(contents, ctx)
82
+ end
83
+ write_file to, contents
84
+ end
75
85
  end
76
86
  end
77
87
 
@@ -83,6 +93,10 @@ module Compass
83
93
  from = templatize(from)
84
94
  to = targetize(install_location_for_stylesheet(to, options))
85
95
  contents = File.new(from).read
96
+ if options.delete(:erb)
97
+ ctx = TemplateContext.ctx(:to => to, :options => options)
98
+ contents = process_erb(contents, ctx)
99
+ end
86
100
  if preferred_syntax.to_s != from[-4..-1]
87
101
  # logger.record :convert, basename(from)
88
102
  tree = Sass::Engine.new(contents, Compass.sass_engine_options.merge(:syntax => from[-4..-1].intern)).to_tree
@@ -0,0 +1,2 @@
1
+ # Rails requires compass by requiring this file.
2
+ require 'compass'
@@ -1,9 +1,5 @@
1
1
  module Compass::SassExtensions::Functions::Colors
2
- if defined?(Sass::Util)
3
- include Sass::Util
4
- else
5
- include Haml::Util
6
- end
2
+ include Compass::Util
7
3
 
8
4
  # a genericized version of lighten/darken so that negative values can be used.
9
5
  def adjust_lightness(color, amount)
@@ -1,17 +1,58 @@
1
1
  module Compass::SassExtensions::Functions::Constants
2
- # returns the opposite position of a side or corner.
3
- def opposite_position(position)
4
- opposite = position.value.split(/ +/).map do |pos|
5
- case pos
6
- when "top" then "bottom"
7
- when "bottom" then "top"
8
- when "left" then "right"
9
- when "right" then "left"
10
- when "center" then "center"
2
+ if defined?(Sass::Script::List)
3
+ # returns the opposite position of a side or corner.
4
+ def opposite_position(position)
5
+ position = unless position.is_a?(Sass::Script::List)
6
+ Sass::Script::List.new([position], :space)
11
7
  else
12
- pos
8
+ Sass::Script::List.new(position.value.dup, position.separator)
13
9
  end
10
+ position.value.map! do |pos|
11
+ if pos.is_a? Sass::Script::String
12
+ opposite = case pos.value
13
+ when "top" then "bottom"
14
+ when "bottom" then "top"
15
+ when "left" then "right"
16
+ when "right" then "left"
17
+ when "center" then "center"
18
+ else
19
+ Compass::Util.compass_warn("Cannot determine the opposite position of: #{pos}")
20
+ pos.value
21
+ end
22
+ Sass::Script::String.new(opposite)
23
+ elsif pos.is_a? Sass::Script::Number
24
+ if pos.numerator_units == ["%"] && pos.denominator_units == []
25
+ Sass::Script::Number.new(100-pos.value, ["%"])
26
+ else
27
+ Compass::Util.compass_warn("Cannot determine the opposite position of: #{pos}")
28
+ pos
29
+ end
30
+ else
31
+ Compass::Util.compass_warn("Cannot determine the opposite position of: #{pos}")
32
+ pos
33
+ end
34
+ end
35
+ if position.value.size == 1
36
+ position.value.first
37
+ else
38
+ position
39
+ end
40
+ end
41
+ else
42
+ # returns the opposite position of a side or corner.
43
+ def opposite_position(position)
44
+ opposite = position.value.split(/ +/).map do |pos|
45
+ case pos
46
+ when "top" then "bottom"
47
+ when "bottom" then "top"
48
+ when "left" then "right"
49
+ when "right" then "left"
50
+ when "center" then "center"
51
+ else
52
+ pos
53
+ end
54
+ end
55
+ Sass::Script::String.new(opposite.join(" "), position.type)
14
56
  end
15
- Sass::Script::String.new(opposite.join(" "), position.type)
16
57
  end
17
58
  end
@@ -1,42 +1,321 @@
1
1
  module Compass::SassExtensions::Functions::GradientSupport
2
2
 
3
- class List < Sass::Script::Literal
4
- attr_accessor :values
5
- def initialize(*values)
6
- self.values = values
3
+ module ListFreeSassSupport
4
+ class List < Sass::Script::Literal
5
+ attr_accessor :values
6
+ def children
7
+ values
8
+ end
9
+ def value
10
+ # duck type to a Sass List
11
+ values
12
+ end
13
+ def initialize(*values)
14
+ self.values = values
15
+ end
16
+ def join_with
17
+ ", "
18
+ end
19
+ def inspect
20
+ to_s
21
+ end
22
+ def to_s(options = self.options)
23
+ values.map {|v| v.to_s }.join(join_with)
24
+ end
25
+ def size
26
+ values.size
27
+ end
7
28
  end
8
- def join_with
9
- ", "
29
+
30
+ class SpaceList < List
31
+ def join_with
32
+ " "
33
+ end
10
34
  end
11
- def inspect
12
- to_s
35
+
36
+ # given a position list, return a corresponding position in percents
37
+ def grad_point(position)
38
+ position = position.is_a?(Sass::Script::String) ? position.value : position.to_s
39
+ position = if position[" "]
40
+ if position =~ /(top|bottom|center) (left|right|center)/
41
+ "#{$2} #{$1}"
42
+ else
43
+ position
44
+ end
45
+ else
46
+ case position
47
+ when /top|bottom/
48
+ "center #{position}"
49
+ when /left|right/
50
+ "#{position} center"
51
+ when /center/
52
+ "center center"
53
+ else
54
+ "#{position} center"
55
+ end
56
+ end
57
+ position = position.
58
+ gsub(/top/, "0%").
59
+ gsub(/bottom/, "100%").
60
+ gsub(/left/,"0%").
61
+ gsub(/right/,"100%").
62
+ gsub(/center/, "50%")
63
+ SpaceList.new(*position.split(/ /).map{|s| Sass::Script::String.new(s)})
13
64
  end
14
- def to_s
15
- values.map {|v| v.to_s }.join(join_with)
65
+
66
+ def color_stops(*args)
67
+ List.new(*args.map do |arg|
68
+ case arg
69
+ when ColorStop
70
+ arg
71
+ when Sass::Script::Color
72
+ ColorStop.new(arg)
73
+ when Sass::Script::String
74
+ # We get a string as the result of concatenation
75
+ # So we have to reparse the expression
76
+ parse_color_stop(arg)
77
+ else
78
+ raise Sass::SyntaxError, "Not a valid color stop: #{arg.class.name}: #{arg}"
79
+ end
80
+ end)
81
+ end
82
+
83
+ # Returns a comma-delimited list after removing any non-true values
84
+ def compact(*args)
85
+ List.new(*args.reject{|a| !a.to_bool})
16
86
  end
17
- def size
18
- values.size
87
+
88
+ # Returns a list object from a value that was passed.
89
+ # This can be used to unpack a space separated list that got turned
90
+ # into a string by sass before it was passed to a mixin.
91
+ def _compass_list(arg)
92
+ return arg if arg.is_a?(List)
93
+ values = case arg
94
+ when Sass::Script::String
95
+ expr = Sass::Script::Parser.parse(arg.value, 0, 0)
96
+ if expr.is_a?(Sass::Script::Operation)
97
+ extract_list_values(expr)
98
+ elsif expr.is_a?(Sass::Script::Funcall)
99
+ expr.perform(Sass::Environment.new) #we already evaluated the args in context so no harm in using a fake env
100
+ else
101
+ [arg]
102
+ end
103
+ else
104
+ [arg]
105
+ end
106
+
107
+ SpaceList.new(*values)
108
+ end
109
+
110
+ def _compass_space_list(list)
111
+ if list.is_a?(List) && !list.is_a?(SpaceList)
112
+ SpaceList.new(*list.values)
113
+ elsif list.is_a?(SpaceList)
114
+ list
115
+ else
116
+ SpaceList.new(list)
117
+ end
19
118
  end
119
+
120
+ def _compass_list_size(list)
121
+ Sass::Script::Number.new(list.size)
122
+ end
123
+
124
+ # slice a sublist from a list
125
+ def _compass_slice(list, start_index, end_index = nil)
126
+ end_index ||= Sass::Script::Number.new(-1)
127
+ start_index = start_index.value
128
+ end_index = end_index.value
129
+ start_index -= 1 unless start_index < 0
130
+ end_index -= 1 unless end_index < 0
131
+ list.class.new *list.values[start_index..end_index]
132
+ end
133
+
134
+ # Check if any of the arguments passed have a tendency towards vendor prefixing.
135
+ def prefixed(prefix, *args)
136
+ method = prefix.value.sub(/^-/,"to_").to_sym
137
+ args.map!{|a| a.is_a?(List) ? a.values : a}.flatten!
138
+ Sass::Script::Bool.new(args.any?{|a| a.respond_to?(method)})
139
+ end
140
+
141
+ %w(webkit moz o ms svg pie).each do |prefix|
142
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
143
+ def _#{prefix}(*args)
144
+ List.new(*args.map! do |a|
145
+ if a.is_a?(List)
146
+ a.class.new(*a.values.map{|v| v.respond_to?(:to_#{prefix}) ? v.to_#{prefix} : v})
147
+ else
148
+ a.respond_to?(:to_#{prefix}) ? a.to_#{prefix} : a
149
+ end
150
+ end)
151
+ end
152
+ RUBY
153
+ end
154
+
155
+ protected
156
+ def color_stop?(arg)
157
+ parse_color_stop(arg)
158
+ rescue
159
+ nil
160
+ end
161
+
162
+ def assert_list(value)
163
+ unless value.is_a?(List)
164
+ raise ArgumentError.new("#{value.inspect} is not a list")
165
+ end
166
+ end
167
+
20
168
  end
21
169
 
22
- class SpaceList < List
23
- def join_with
24
- " "
170
+ module ListBasedSassSupport
171
+ # given a position list, return a corresponding position in percents
172
+ def grad_point(position)
173
+ position = unless position.is_a?(Sass::Script::List)
174
+ Sass::Script::List.new([position], :space)
175
+ else
176
+ Sass::Script::List.new(position.value.dup, position.separator)
177
+ end
178
+ position.value.reject!{|p| p.is_a?(Sass::Script::Number) && p.numerator_units.include?("deg")}
179
+ if (position.value.first.value =~ /top|bottom/) or (position.value.last.value =~ /left|right/)
180
+ # browsers are pretty forgiving of reversed positions so we are too.
181
+ position.value.reverse!
182
+ end
183
+ if position.value.size == 1
184
+ if position.value.first.value =~ /top|bottom/
185
+ position.value.unshift Sass::Script::String.new("center")
186
+ elsif position.value.first.value =~ /left|right/
187
+ position.value.push Sass::Script::String.new("center")
188
+ end
189
+ end
190
+ position.value.map! do |p|
191
+ case p.value
192
+ when /top|left/
193
+ Sass::Script::Number.new(0, ["%"])
194
+ when /bottom|right/
195
+ Sass::Script::Number.new(100, ["%"])
196
+ when /center/
197
+ Sass::Script::Number.new(50, ["%"])
198
+ else
199
+ p
200
+ end
201
+ end
202
+ position
203
+ end
204
+
205
+ def color_stops(*args)
206
+ Sass::Script::List.new(args.map do |arg|
207
+ case arg
208
+ when ColorStop
209
+ arg
210
+ when Sass::Script::Color
211
+ ColorStop.new(arg)
212
+ when Sass::Script::List
213
+ ColorStop.new(*arg.value)
214
+ else
215
+ raise Sass::SyntaxError, "Not a valid color stop: #{arg.class.name}: #{arg}"
216
+ end
217
+ end, :comma)
218
+ end
219
+
220
+ # Returns a comma-delimited list after removing any non-true values
221
+ def compact(*args)
222
+ Sass::Script::List.new(args.reject{|a| !a.to_bool}, :comma)
223
+ end
224
+
225
+ # Returns a list object from a value that was passed.
226
+ # This can be used to unpack a space separated list that got turned
227
+ # into a string by sass before it was passed to a mixin.
228
+ def _compass_list(arg)
229
+ if arg.is_a?(Sass::Script::List)
230
+ Sass::Script::List.new(arg.value.dup, arg.separator)
231
+ else
232
+ Sass::Script::List.new([arg], :space)
233
+ end
234
+ end
235
+
236
+ def _compass_space_list(list)
237
+ if list.is_a?(Sass::Script::List)
238
+ Sass::Script::List.new(list.value.dup, :space)
239
+ else
240
+ Sass::Script::List.new([list], :space)
241
+ end
242
+ end
243
+
244
+ def _compass_list_size(list)
245
+ assert_list list
246
+ Sass::Script::Number.new(list.value.size)
247
+ end
248
+
249
+ # slice a sublist from a list
250
+ def _compass_slice(list, start_index, end_index = nil)
251
+ end_index ||= Sass::Script::Number.new(-1)
252
+ start_index = start_index.value
253
+ end_index = end_index.value
254
+ start_index -= 1 unless start_index < 0
255
+ end_index -= 1 unless end_index < 0
256
+ Sass::Script::List.new list.values[start_index..end_index], list.separator
257
+ end
258
+
259
+ # Check if any of the arguments passed have a tendency towards vendor prefixing.
260
+ def prefixed(prefix, *args)
261
+ method = prefix.value.sub(/^-/,"to_").to_sym
262
+ args.map!{|a| a.is_a?(Sass::Script::List) ? a.value : a}.flatten!
263
+ Sass::Script::Bool.new(args.any?{|a| a.respond_to?(method)})
264
+ end
265
+
266
+ %w(webkit moz o ms svg pie).each do |prefix|
267
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
268
+ def _#{prefix}(*args)
269
+ Sass::Script::List.new(args.map! do |a|
270
+ a.options = options
271
+ if a.is_a?(Sass::Script::List)
272
+ Sass::Script::List.new(a.value.map do |v|
273
+ v.respond_to?(:to_#{prefix}) ? v.to_#{prefix} : v
274
+ end, a.separator)
275
+ else
276
+ a.respond_to?(:to_#{prefix}) ? a.to_#{prefix} : a
277
+ end
278
+ end, :comma)
279
+ end
280
+ RUBY
281
+ end
282
+
283
+ protected
284
+ def color_stop?(arg)
285
+ arg.is_a?(ColorStop) ||
286
+ (arg.is_a?(Sass::Script::List) && ColorStop.new(*arg.value)) ||
287
+ ColorStop.new(arg)
288
+ rescue
289
+ nil
25
290
  end
291
+
292
+ def assert_list(value)
293
+ unless value.is_a?(Sass::Script::List)
294
+ raise ArgumentError.new("#{value.inspect} is not a list")
295
+ end
296
+ end
297
+
26
298
  end
27
299
 
300
+
28
301
  class ColorStop < Sass::Script::Literal
29
302
  attr_accessor :color, :stop
303
+ def children
304
+ [color, stop].compact
305
+ end
30
306
  def initialize(color, stop = nil)
31
307
  unless Sass::Script::Color === color || Sass::Script::Funcall === color
32
308
  raise Sass::SyntaxError, "Expected a color. Got: #{color}"
33
309
  end
310
+ if stop && !stop.is_a?(Sass::Script::Number)
311
+ raise Sass::SyntaxError, "Expected a number. Got: #{stop}"
312
+ end
34
313
  self.color, self.stop = color, stop
35
314
  end
36
315
  def inspect
37
316
  to_s
38
317
  end
39
- def to_s
318
+ def to_s(options = self.options)
40
319
  s = color.inspect.dup
41
320
  if stop
42
321
  s << " "
@@ -52,8 +331,11 @@ module Compass::SassExtensions::Functions::GradientSupport
52
331
 
53
332
  class RadialGradient < Sass::Script::Literal
54
333
  attr_accessor :position_and_angle, :shape_and_size, :color_stops
334
+ def children
335
+ [color_stops, position_and_angle, shape_and_size].compact
336
+ end
55
337
  def initialize(position_and_angle, shape_and_size, color_stops)
56
- unless color_stops.values.size >= 2
338
+ unless color_stops.value.size >= 2
57
339
  raise Sass::SyntaxError, "At least two color stops are required for a radial-gradient"
58
340
  end
59
341
  self.position_and_angle = position_and_angle
@@ -63,37 +345,45 @@ module Compass::SassExtensions::Functions::GradientSupport
63
345
  def inspect
64
346
  to_s
65
347
  end
66
- def to_s
348
+ def to_s(options = self.options)
67
349
  s = "radial-gradient("
68
- s << position_and_angle.to_s << ", " if position_and_angle
69
- s << shape_and_size.to_s << ", " if shape_and_size
70
- s << color_stops.to_s
350
+ s << position_and_angle.to_s(options) << ", " if position_and_angle
351
+ s << shape_and_size.to_s(options) << ", " if shape_and_size
352
+ s << color_stops.to_s(options)
71
353
  s << ")"
72
354
  end
73
- def to_webkit
355
+ def to_webkit(options = self.options)
74
356
  args = [
75
- grad_point(position_and_angle || Sass::Script::String.new("center center")),
76
- "0",
77
- grad_point(position_and_angle || Sass::Script::String.new("center center")),
357
+ grad_point(position_and_angle || _center_position),
358
+ Sass::Script::String.new("0"),
359
+ grad_point(position_and_angle || _center_position),
78
360
  grad_end_position(color_stops, Sass::Script::Bool.new(true)),
79
361
  grad_color_stops(color_stops)
80
362
  ]
363
+ args.each {|a| a.options = options}
81
364
  Sass::Script::String.new("-webkit-gradient(radial, #{args.join(', ')})")
82
365
 
83
366
  end
84
- def to_moz
85
- Sass::Script::String.new("-moz-#{to_s}")
367
+ def to_moz(options = self.options)
368
+ Sass::Script::String.new("-moz-#{to_s(options)}")
86
369
  end
87
- def to_svg
370
+ def to_svg(options = self.options)
88
371
  # XXX Add shape support if possible
89
- radial_svg_gradient(color_stops, position_and_angle || Sass::Script::String.new("center center"))
372
+ radial_svg_gradient(color_stops, position_and_angle || _center_position)
373
+ end
374
+ def to_pie(options = self.options)
375
+ Compass::Logger.new.record(:warning, "PIE does not support radial-gradient.")
376
+ Sass::Script::String.new("-pie-radial-gradient(unsupported)")
90
377
  end
91
378
  end
92
379
 
93
380
  class LinearGradient < Sass::Script::Literal
94
381
  attr_accessor :color_stops, :position_and_angle
382
+ def children
383
+ [color_stops, position_and_angle].compact
384
+ end
95
385
  def initialize(position_and_angle, color_stops)
96
- unless color_stops.values.size >= 2
386
+ unless color_stops.value.size >= 2
97
387
  raise Sass::SyntaxError, "At least two color stops are required for a linear-gradient"
98
388
  end
99
389
  self.position_and_angle = position_and_angle
@@ -102,29 +392,42 @@ module Compass::SassExtensions::Functions::GradientSupport
102
392
  def inspect
103
393
  to_s
104
394
  end
105
- def to_s
395
+ def to_s(options = self.options)
106
396
  s = "linear-gradient("
107
- s << position_and_angle.to_s << ", " if position_and_angle
108
- s << color_stops.to_s
397
+ s << position_and_angle.to_s(options) << ", " if position_and_angle
398
+ s << color_stops.to_s(options)
109
399
  s << ")"
110
400
  end
111
- def to_webkit
401
+ def to_webkit(options = self.options)
112
402
  args = []
113
403
  args << grad_point(position_and_angle || Sass::Script::String.new("top"))
114
404
  args << grad_point(opposite_position(position_and_angle || Sass::Script::String.new("top")))
115
405
  args << grad_color_stops(color_stops)
406
+ args.each{|a| a.options = options}
116
407
  Sass::Script::String.new("-webkit-gradient(linear, #{args.join(', ')})")
117
408
  end
118
- def to_moz
119
- Sass::Script::String.new("-moz-#{to_s}")
409
+ def to_moz(options = self.options)
410
+ Sass::Script::String.new("-moz-#{to_s(options)}")
120
411
  end
121
- def to_svg
412
+ def to_svg(options = self.options)
122
413
  linear_svg_gradient(color_stops, position_and_angle || Sass::Script::String.new("top"))
123
414
  end
415
+ def to_pie(options = self.options)
416
+ # PIE just uses the standard rep, but the property is prefixed so
417
+ # the presence of this attribute helps flag when to render a special rule.
418
+ Sass::Script::String.new to_s(options)
419
+ end
124
420
  end
125
421
 
126
422
  module Functions
127
423
 
424
+ # While supporting sass 3.1 and older versions, we need two different implementations.
425
+ if defined?(Sass::Script::List)
426
+ include ListBasedSassSupport
427
+ else
428
+ include ListFreeSassSupport
429
+ end
430
+
128
431
  def radial_gradient(position_and_angle, shape_and_size, *color_stops)
129
432
  # Have to deal with variable length/meaning arguments.
130
433
  if color_stop?(shape_and_size)
@@ -132,7 +435,7 @@ module Compass::SassExtensions::Functions::GradientSupport
132
435
  shape_and_size = nil
133
436
  elsif list_of_color_stops?(shape_and_size)
134
437
  # Support legacy use of the color-stops() function
135
- color_stops = shape_and_size.values + color_stops
438
+ color_stops = shape_and_size.value + color_stops
136
439
  shape_and_size = nil
137
440
  end
138
441
  shape_and_size = nil if shape_and_size && !shape_and_size.to_bool # nil out explictly passed falses
@@ -141,14 +444,14 @@ module Compass::SassExtensions::Functions::GradientSupport
141
444
  color_stops.unshift(position_and_angle)
142
445
  position_and_angle = nil
143
446
  elsif list_of_color_stops?(position_and_angle)
144
- color_stops = position_and_angle.values + color_stops
447
+ color_stops = position_and_angle.value + color_stops
145
448
  position_and_angle = nil
146
449
  end
147
450
  position_and_angle = nil if position_and_angle && !position_and_angle.to_bool
148
451
 
149
452
  # Support legacy use of the color-stops() function
150
453
  if color_stops.size == 1 && list_of_color_stops?(color_stops.first)
151
- color_stops = color_stops.first.values
454
+ color_stops = color_stops.first.value
152
455
  end
153
456
  RadialGradient.new(position_and_angle, shape_and_size, send(:color_stops, *color_stops))
154
457
  end
@@ -158,14 +461,14 @@ module Compass::SassExtensions::Functions::GradientSupport
158
461
  color_stops.unshift(position_and_angle)
159
462
  position_and_angle = nil
160
463
  elsif list_of_color_stops?(position_and_angle)
161
- color_stops = position_and_angle.values + color_stops
464
+ color_stops = position_and_angle.value + color_stops
162
465
  position_and_angle = nil
163
466
  end
164
467
  position_and_angle = nil if position_and_angle && !position_and_angle.to_bool
165
468
 
166
469
  # Support legacy use of the color-stops() function
167
470
  if color_stops.size == 1 && list_of_color_stops?(color_stops.first)
168
- color_stops = color_stops.first.values
471
+ color_stops = color_stops.first.value
169
472
  end
170
473
  LinearGradient.new(position_and_angle, send(:color_stops, *color_stops))
171
474
  end
@@ -180,10 +483,10 @@ module Compass::SassExtensions::Functions::GradientSupport
180
483
 
181
484
  def color_stops_in_percentages(color_list)
182
485
  assert_list(color_list)
183
- normalize_stops!(color_list)
184
- max = color_list.values.last.stop
486
+ color_list = normalize_stops(color_list)
487
+ max = color_list.value.last.stop
185
488
  last_value = nil
186
- color_stops = color_list.values.map do |pos|
489
+ color_stops = color_list.value.map do |pos|
187
490
  # have to convert absolute units to percentages for use in color stop functions.
188
491
  stop = pos.stop
189
492
  stop = stop.div(max).times(Sass::Script::Number.new(100,["%"])) if stop.numerator_units == max.numerator_units && max.numerator_units != ["%"]
@@ -200,12 +503,12 @@ module Compass::SassExtensions::Functions::GradientSupport
200
503
  def grad_end_position(color_list, radial = Sass::Script::Bool.new(false))
201
504
  assert_list(color_list)
202
505
  default = Sass::Script::Number.new(100)
203
- grad_position(color_list, Sass::Script::Number.new(color_list.values.size), default, radial)
506
+ grad_position(color_list, Sass::Script::Number.new(color_list.value.size), default, radial)
204
507
  end
205
508
 
206
509
  def grad_position(color_list, index, default, radial = Sass::Script::Bool.new(false))
207
510
  assert_list(color_list)
208
- stop = color_list.values[index.value - 1].stop
511
+ stop = color_list.value[index.value - 1].stop
209
512
  if stop && radial.to_bool
210
513
  orig_stop = stop
211
514
  if stop.unitless?
@@ -217,8 +520,8 @@ module Compass::SassExtensions::Functions::GradientSupport
217
520
  stop = stop.times(Sass::Script::Number.new(1, ["px"]))
218
521
  end
219
522
  end
220
- if stop.numerator_units == ["%"] && color_list.values.last.stop && color_list.values.last.stop.numerator_units == ["px"]
221
- stop = stop.times(color_list.values.last.stop).div(Sass::Script::Number.new(100, ["%"]))
523
+ if stop.numerator_units == ["%"] && color_list.value.last.stop && color_list.value.last.stop.numerator_units == ["px"]
524
+ stop = stop.times(color_list.value.last.stop).div(Sass::Script::Number.new(100, ["%"]))
222
525
  end
223
526
  Compass::Logger.new.record(:warning, "Webkit only supports pixels for the start and end stops for radial gradients. Got: #{orig_stop}") if stop.numerator_units != ["px"]
224
527
  stop.div(Sass::Script::Number.new(1, stop.numerator_units, stop.denominator_units))
@@ -229,55 +532,9 @@ module Compass::SassExtensions::Functions::GradientSupport
229
532
  end
230
533
  end
231
534
 
232
- # the given a position, return a point in percents
233
- def grad_point(position)
234
- position = position.value
235
- position = if position[" "]
236
- if position =~ /(top|bottom|center) (left|right|center)/
237
- "#{$2} #{$1}"
238
- else
239
- position
240
- end
241
- else
242
- case position
243
- when /top|bottom/
244
- "center #{position}"
245
- when /left|right/
246
- "#{position} center"
247
- when /center/
248
- "center center"
249
- else
250
- position
251
- end
252
- end
253
- Sass::Script::String.new(position.
254
- gsub(/top/, "0%").
255
- gsub(/bottom/, "100%").
256
- gsub(/left/,"0%").
257
- gsub(/right/,"100%").
258
- gsub(/center/, "50%"))
259
- end
260
-
261
- def color_stops(*args)
262
- List.new(*args.map do |arg|
263
- case arg
264
- when ColorStop
265
- arg
266
- when Sass::Script::Color
267
- ColorStop.new(arg)
268
- when Sass::Script::String
269
- # We get a string as the result of concatenation
270
- # So we have to reparse the expression
271
- parse_color_stop(arg)
272
- else
273
- raise Sass::SyntaxError, "Not a valid color stop: #{arg.class.name}: #{arg}"
274
- end
275
- end)
276
- end
277
-
278
535
  def linear_svg_gradient(color_stops, start)
279
- x1, y1 = grad_point(start).to_s.split
280
- x2, y2 = grad_point(opposite_position(start)).to_s.split
536
+ x1, y1 = *grad_point(start).value
537
+ x2, y2 = *grad_point(opposite_position(start)).value
281
538
  stops = color_stops_in_percentages(color_stops)
282
539
 
283
540
  svg = linear_svg(stops, x1, y1, x2, y2)
@@ -285,7 +542,7 @@ module Compass::SassExtensions::Functions::GradientSupport
285
542
  end
286
543
 
287
544
  def radial_svg_gradient(color_stops, center)
288
- cx, cy = grad_point(center).to_s.split
545
+ cx, cy = *grad_point(center).value
289
546
  r = grad_end_position(color_stops, Sass::Script::Bool.new(true))
290
547
  stops = color_stops_in_percentages(color_stops)
291
548
 
@@ -293,90 +550,20 @@ module Compass::SassExtensions::Functions::GradientSupport
293
550
  inline_image_string(svg.gsub(/\s+/, ' '), 'image/svg+xml')
294
551
  end
295
552
 
296
- # Returns a comma-delimited list after removing any non-true values
297
- def compact(*args)
298
- List.new(*args.reject{|a| !a.to_bool})
299
- end
300
-
301
- # Returns a list object from a value that was passed.
302
- # This can be used to unpack a space separated list that got turned
303
- # into a string by sass before it was passed to a mixin.
304
- def _compass_list(arg)
305
- return arg if arg.is_a?(List)
306
- values = case arg
307
- when Sass::Script::String
308
- expr = Sass::Script::Parser.parse(arg.value, 0, 0)
309
- if expr.is_a?(Sass::Script::Operation)
310
- extract_list_values(expr)
311
- elsif expr.is_a?(Sass::Script::Funcall)
312
- expr.perform(Sass::Environment.new) #we already evaluated the args in context so no harm in using a fake env
313
- else
314
- [arg]
315
- end
316
- else
317
- [arg]
318
- end
319
-
320
- SpaceList.new(*values)
321
- end
322
-
323
- def _compass_list_size(list)
324
- Sass::Script::Number.new(list.size)
325
- end
326
-
327
553
  # Get the nth value from a list
328
554
  def _compass_nth(list, place)
329
- if place.value == "last"
330
- list.values.last
331
- elsif place.value == "first"
332
- list.values.first
555
+ assert_list list
556
+ if place.value == "first"
557
+ list.value.first
558
+ elsif place.value == "last"
559
+ list.value.last
333
560
  else
334
- list.values[place.value - 1]
561
+ list.value[place.value - 1]
335
562
  end
336
563
  end
337
564
 
338
- def _compass_space_list(list)
339
- if list.is_a?(List) && !list.is_a?(SpaceList)
340
- SpaceList.new(*list.values)
341
- elsif list.is_a?(SpaceList)
342
- list
343
- else
344
- SpaceList.new(list)
345
- end
346
- end
347
-
348
- # slice a sublist from a list
349
- def _compass_slice(list, start_index, end_index = nil)
350
- end_index ||= Sass::Script::Number.new(-1)
351
- start_index = start_index.value
352
- end_index = end_index.value
353
- start_index -= 1 unless start_index < 0
354
- end_index -= 1 unless end_index < 0
355
- list.class.new *list.values[start_index..end_index]
356
- end
357
-
358
- %w(webkit moz o ms svg).each do |prefix|
359
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
360
- def _#{prefix}(*args)
361
- List.new(*args.map! do |a|
362
- if a.is_a?(List)
363
- a.class.new(*a.values.map{|v| v.respond_to?(:to_#{prefix}) ? v.to_#{prefix} : v})
364
- else
365
- a.respond_to?(:to_#{prefix}) ? a.to_#{prefix} : a
366
- end
367
- end)
368
- end
369
- RUBY
370
- end
371
-
372
- # Check if any of the arguments passed have a tendency towards vendor prefixing.
373
- def prefixed(prefix, *args)
374
- method = prefix.value.sub(/^-/,"to_").to_sym
375
- args.map!{|a| a.is_a?(List) ? a.values : a}.flatten!
376
- Sass::Script::Bool.new(args.any?{|a| a.respond_to?(method)})
377
- end
378
-
379
565
  private
566
+
380
567
  # After using the sass script parser to parse a string, this reconstructs
381
568
  # a list from operands to the space/concat operation
382
569
  def extract_list_values(operation)
@@ -399,8 +586,8 @@ module Compass::SassExtensions::Functions::GradientSupport
399
586
  Sass::Script::String.new(node.to_s)
400
587
  end
401
588
  end
402
- def normalize_stops!(color_list)
403
- positions = color_list.values
589
+ def normalize_stops(color_list)
590
+ positions = color_list.value.map{|obj| obj.dup}
404
591
  # fill in the start and end positions, if unspecified
405
592
  positions.first.stop = Sass::Script::Number.new(0) unless positions.first.stop
406
593
  positions.last.stop = Sass::Script::Number.new(100, ["%"]) unless positions.last.stop
@@ -430,12 +617,11 @@ module Compass::SassExtensions::Functions::GradientSupport
430
617
  positions.last.stop.eq(Sass::Script::Number.new(0, ["%"])).to_bool)
431
618
  raise Sass::SyntaxError.new("Color stops must be specified in increasing order")
432
619
  end
433
- nil
434
- end
435
-
436
- def assert_list(value)
437
- return if value.is_a?(List)
438
- raise ArgumentError.new("#{value.inspect} is not a list of color stops. Expected: color_stops(<color> <number>?, ...)")
620
+ if defined?(Sass::Script::List)
621
+ Sass::Script::List.new(positions, color_list.separator)
622
+ else
623
+ color_list.class.new(*positions)
624
+ end
439
625
  end
440
626
 
441
627
  def parse_color_stop(arg)
@@ -461,14 +647,8 @@ module Compass::SassExtensions::Functions::GradientSupport
461
647
  ColorStop.new(color, stop)
462
648
  end
463
649
 
464
- def color_stop?(arg)
465
- parse_color_stop(arg)
466
- rescue
467
- nil
468
- end
469
-
470
650
  def list_of_color_stops?(arg)
471
- arg.is_a?(List) && arg.values.first.is_a?(ColorStop)
651
+ arg.value.is_a?(Array) && arg.value.all?{|a| a.is_a?(ColorStop)}
472
652
  end
473
653
 
474
654
  def linear_svg(color_stops, x1, y1, x2, y2)
@@ -494,6 +674,18 @@ module Compass::SassExtensions::Functions::GradientSupport
494
674
  <svg version="1.1" xmlns="http://www.w3.org/2000/svg"><defs>#{gradient}</defs><rect x="0" y="0" width="100%" height="100%" fill="url(#grad)" /></svg>
495
675
  EOS
496
676
  end
677
+
678
+ def _center_position
679
+ if defined?(Sass::Script::List)
680
+ Sass::Script::List.new([
681
+ Sass::Script::String.new("center"),
682
+ Sass::Script::String.new("center")
683
+ ],:space)
684
+ else
685
+ Sass::Script::String.new("center center")
686
+ end
687
+ end
688
+
497
689
  end
498
690
  class LinearGradient < Sass::Script::Literal
499
691
  include Functions