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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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