compass-core 1.0.0.alpha.13

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 (141) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +22 -0
  3. data/VERSION +1 -0
  4. data/data/caniuse.json +1 -0
  5. data/data/caniuse_extras/css-placeholder.json +171 -0
  6. data/lib/compass-core.rb +1 -0
  7. data/lib/compass/browser_support.rb +62 -0
  8. data/lib/compass/configuration.rb +168 -0
  9. data/lib/compass/configuration/data.rb +178 -0
  10. data/lib/compass/configuration/defaults.rb +197 -0
  11. data/lib/compass/configuration/inheritance.rb +304 -0
  12. data/lib/compass/configuration/paths.rb +19 -0
  13. data/lib/compass/core.rb +64 -0
  14. data/lib/compass/core/caniuse.rb +282 -0
  15. data/lib/compass/core/sass_extensions.rb +10 -0
  16. data/lib/compass/core/sass_extensions/functions.rb +39 -0
  17. data/lib/compass/core/sass_extensions/functions/colors.rb +67 -0
  18. data/lib/compass/core/sass_extensions/functions/configuration.rb +162 -0
  19. data/lib/compass/core/sass_extensions/functions/constants.rb +74 -0
  20. data/lib/compass/core/sass_extensions/functions/cross_browser_support.rb +269 -0
  21. data/lib/compass/core/sass_extensions/functions/display.rb +32 -0
  22. data/lib/compass/core/sass_extensions/functions/enumerate.rb +7 -0
  23. data/lib/compass/core/sass_extensions/functions/env.rb +60 -0
  24. data/lib/compass/core/sass_extensions/functions/font_files.rb +41 -0
  25. data/lib/compass/core/sass_extensions/functions/gradient_support.rb +616 -0
  26. data/lib/compass/core/sass_extensions/functions/image_size.rb +117 -0
  27. data/lib/compass/core/sass_extensions/functions/inline_image.rb +64 -0
  28. data/lib/compass/core/sass_extensions/functions/lists.rb +101 -0
  29. data/lib/compass/core/sass_extensions/functions/math.rb +92 -0
  30. data/lib/compass/core/sass_extensions/functions/selectors.rb +64 -0
  31. data/lib/compass/core/sass_extensions/functions/urls.rb +297 -0
  32. data/lib/compass/core/sass_extensions/monkey_patches.rb +3 -0
  33. data/lib/compass/core/sass_extensions/monkey_patches/browser_support.rb +118 -0
  34. data/lib/compass/core/sass_extensions/monkey_patches/traversal.rb +23 -0
  35. data/lib/compass/core/version.rb +5 -0
  36. data/lib/compass/error.rb +5 -0
  37. data/stylesheets/_compass.scss +3 -0
  38. data/stylesheets/_lemonade.scss +38 -0
  39. data/stylesheets/compass/_configuration.scss +54 -0
  40. data/stylesheets/compass/_css3.scss +21 -0
  41. data/stylesheets/compass/_layout.scss +3 -0
  42. data/stylesheets/compass/_reset-legacy.scss +3 -0
  43. data/stylesheets/compass/_reset.scss +3 -0
  44. data/stylesheets/compass/_support.scss +441 -0
  45. data/stylesheets/compass/_typography.scss +4 -0
  46. data/stylesheets/compass/_utilities.scss +9 -0
  47. data/stylesheets/compass/css3/_animation.scss +122 -0
  48. data/stylesheets/compass/css3/_appearance.scss +17 -0
  49. data/stylesheets/compass/css3/_background-clip.scss +35 -0
  50. data/stylesheets/compass/css3/_background-origin.scss +37 -0
  51. data/stylesheets/compass/css3/_background-size.scss +19 -0
  52. data/stylesheets/compass/css3/_border-radius.scss +107 -0
  53. data/stylesheets/compass/css3/_box-shadow.scss +88 -0
  54. data/stylesheets/compass/css3/_box-sizing.scss +15 -0
  55. data/stylesheets/compass/css3/_box.scss +85 -0
  56. data/stylesheets/compass/css3/_columns.scss +210 -0
  57. data/stylesheets/compass/css3/_deprecated-support.scss +272 -0
  58. data/stylesheets/compass/css3/_filter.scss +50 -0
  59. data/stylesheets/compass/css3/_flexbox.scss +156 -0
  60. data/stylesheets/compass/css3/_font-face.scss +48 -0
  61. data/stylesheets/compass/css3/_hyphenation.scss +71 -0
  62. data/stylesheets/compass/css3/_images.scss +139 -0
  63. data/stylesheets/compass/css3/_inline-block.scss +31 -0
  64. data/stylesheets/compass/css3/_opacity.scss +23 -0
  65. data/stylesheets/compass/css3/_pie.scss +1 -0
  66. data/stylesheets/compass/css3/_regions.scss +27 -0
  67. data/stylesheets/compass/css3/_selection.scss +59 -0
  68. data/stylesheets/compass/css3/_shared.scss +5 -0
  69. data/stylesheets/compass/css3/_text-shadow.scss +82 -0
  70. data/stylesheets/compass/css3/_transform.scss +590 -0
  71. data/stylesheets/compass/css3/_transition.scss +171 -0
  72. data/stylesheets/compass/css3/_user-interface.scss +71 -0
  73. data/stylesheets/compass/layout/_grid-background.scss +178 -0
  74. data/stylesheets/compass/layout/_sticky-footer.scss +23 -0
  75. data/stylesheets/compass/layout/_stretching.scss +24 -0
  76. data/stylesheets/compass/reset/_utilities-legacy.scss +135 -0
  77. data/stylesheets/compass/reset/_utilities.scss +142 -0
  78. data/stylesheets/compass/typography/_links.scss +3 -0
  79. data/stylesheets/compass/typography/_lists.scss +4 -0
  80. data/stylesheets/compass/typography/_text.scss +4 -0
  81. data/stylesheets/compass/typography/_units.scss +152 -0
  82. data/stylesheets/compass/typography/_vertical_rhythm.scss +300 -0
  83. data/stylesheets/compass/typography/links/_hover-link.scss +5 -0
  84. data/stylesheets/compass/typography/links/_link-colors.scss +28 -0
  85. data/stylesheets/compass/typography/links/_unstyled-link.scss +7 -0
  86. data/stylesheets/compass/typography/lists/_bullets.scss +34 -0
  87. data/stylesheets/compass/typography/lists/_horizontal-list.scss +63 -0
  88. data/stylesheets/compass/typography/lists/_inline-block-list.scss +50 -0
  89. data/stylesheets/compass/typography/lists/_inline-list.scss +47 -0
  90. data/stylesheets/compass/typography/text/_ellipsis.scss +25 -0
  91. data/stylesheets/compass/typography/text/_force-wrap.scss +12 -0
  92. data/stylesheets/compass/typography/text/_nowrap.scss +2 -0
  93. data/stylesheets/compass/typography/text/_replacement.scss +68 -0
  94. data/stylesheets/compass/utilities/_color.scss +1 -0
  95. data/stylesheets/compass/utilities/_general.scss +6 -0
  96. data/stylesheets/compass/utilities/_links.scss +5 -0
  97. data/stylesheets/compass/utilities/_lists.scss +6 -0
  98. data/stylesheets/compass/utilities/_print.scss +17 -0
  99. data/stylesheets/compass/utilities/_sass.scss +2 -0
  100. data/stylesheets/compass/utilities/_sprites.scss +2 -0
  101. data/stylesheets/compass/utilities/_tables.scss +3 -0
  102. data/stylesheets/compass/utilities/_text.scss +5 -0
  103. data/stylesheets/compass/utilities/color/_brightness.scss +12 -0
  104. data/stylesheets/compass/utilities/color/_contrast.scss +52 -0
  105. data/stylesheets/compass/utilities/general/_clearfix.scss +44 -0
  106. data/stylesheets/compass/utilities/general/_float.scss +38 -0
  107. data/stylesheets/compass/utilities/general/_hacks.scss +65 -0
  108. data/stylesheets/compass/utilities/general/_min.scss +16 -0
  109. data/stylesheets/compass/utilities/general/_reset.scss +2 -0
  110. data/stylesheets/compass/utilities/general/_tabs.scss +1 -0
  111. data/stylesheets/compass/utilities/general/_tag-cloud.scss +18 -0
  112. data/stylesheets/compass/utilities/links/_hover-link.scss +3 -0
  113. data/stylesheets/compass/utilities/links/_link-colors.scss +3 -0
  114. data/stylesheets/compass/utilities/links/_unstyled-link.scss +3 -0
  115. data/stylesheets/compass/utilities/lists/_bullets.scss +3 -0
  116. data/stylesheets/compass/utilities/lists/_horizontal-list.scss +3 -0
  117. data/stylesheets/compass/utilities/lists/_inline-block-list.scss +3 -0
  118. data/stylesheets/compass/utilities/lists/_inline-list.scss +3 -0
  119. data/stylesheets/compass/utilities/sass/_lists.scss +16 -0
  120. data/stylesheets/compass/utilities/sass/_maps.scss +19 -0
  121. data/stylesheets/compass/utilities/sprites/_base.scss +92 -0
  122. data/stylesheets/compass/utilities/sprites/_sprite-img.scss +81 -0
  123. data/stylesheets/compass/utilities/tables/_alternating-rows-and-columns.scss +22 -0
  124. data/stylesheets/compass/utilities/tables/_borders.scss +38 -0
  125. data/stylesheets/compass/utilities/tables/_scaffolding.scss +9 -0
  126. data/stylesheets/compass/utilities/text/_ellipsis.scss +3 -0
  127. data/stylesheets/compass/utilities/text/_nowrap.scss +3 -0
  128. data/stylesheets/compass/utilities/text/_replacement.scss +3 -0
  129. data/templates/ellipsis/ellipsis.sass +9 -0
  130. data/templates/ellipsis/manifest.rb +27 -0
  131. data/templates/ellipsis/xml/ellipsis.xml +14 -0
  132. data/templates/extension/manifest.rb +26 -0
  133. data/templates/extension/stylesheets/main.sass +1 -0
  134. data/templates/extension/templates/project/manifest.rb +2 -0
  135. data/templates/extension/templates/project/screen.sass +2 -0
  136. data/templates/project/USAGE.markdown +32 -0
  137. data/templates/project/ie.sass +6 -0
  138. data/templates/project/manifest.rb +4 -0
  139. data/templates/project/print.sass +6 -0
  140. data/templates/project/screen.sass +7 -0
  141. metadata +241 -0
@@ -0,0 +1,162 @@
1
+ require 'pathname'
2
+ module Compass::Core::SassExtensions::Functions::Configuration
3
+ extend Compass::Core::SassExtensions::Functions::SassDeclarationHelper
4
+
5
+ # Users who need to support windows and unix paths in their configuration
6
+ # should construct them with this helper function.
7
+ def join_file_segments(*segments)
8
+ quoted_string(File.join(*segments.map{|s| assert_type s, :String; s.value}))
9
+ end
10
+ declare :absolute_path, [], :var_args => true
11
+
12
+ # Returns an absolute path for the path relative to the sass file it was called from.
13
+ def absolute_path(relative_path)
14
+ quoted_string(File.expand_path(File.join(File.dirname(options[:filename]), relative_path.value)))
15
+ end
16
+ declare :absolute_path, [:relative_path]
17
+
18
+ # split a file into directory, basename, and extension
19
+ def split_filename(path)
20
+ pathname = Pathname.new(path.value)
21
+ list(quoted_string(pathname.dirname.to_s),
22
+ quoted_string(pathname.basename(pathname.extname).to_s),
23
+ quoted_string(pathname.extname.to_s),
24
+ :space)
25
+ end
26
+ declare :split_filename, [:path]
27
+
28
+ # Returns true if the compass compiler is compiling this stylesheet.
29
+ def using_compass_compiler
30
+ bool(options[:compass] && options[:compass][:compiler_in_use])
31
+ end
32
+ declare :using_compass_compiler, []
33
+
34
+ def reset_configuration()
35
+ Compass.reset_configuration!
36
+ null()
37
+ end
38
+ declare :reset_configuration, []
39
+
40
+ def add_sass_configuration(project_path)
41
+ css_location = File.expand_path(options[:css_location]) if options[:css_location]
42
+ template_location = File.expand_path(options[:template_location]) if options[:template_location]
43
+ original_filename = File.expand_path(options[:original_filename]) if options[:original_filename]
44
+ project_path = if project_path.value.nil?
45
+ if css_location && template_location
46
+ common_parent_directory(css_location, template_location)
47
+ end
48
+ else
49
+ project_path.value
50
+ end
51
+ config = {
52
+ :project_path => project_path,
53
+ :cache => options[:cache],
54
+ :additional_import_paths => options[:load_paths],
55
+ :line_comments => options[:line_comments]
56
+ }
57
+ unless options[:quiet].nil?
58
+ config.update(:disable_warnings => options[:quiet])
59
+ end
60
+ if project_path && css_location && (css_dir = relative_path_from(css_location, project_path))
61
+ config.update(:css_dir => css_dir)
62
+ elsif css_location
63
+ config.update(:css_path => css_location)
64
+ end
65
+ if project_path && template_location && (sass_dir = relative_path_from(template_location, project_path))
66
+ config.update(:sass_dir => sass_dir)
67
+ elsif template_location
68
+ config.update(:css_path => template_location)
69
+ end
70
+ config_name = "Sass Defaults: #{project_path ? relative_path_from(original_filename, project_path) : original_filename}"
71
+ Compass.add_configuration(Compass::Configuration::Data.new(config_name, config))
72
+ update_sass_options!
73
+ null
74
+ rescue => e
75
+ puts e.backtrace.join("\n")
76
+ raise
77
+ end
78
+ declare :add_sass_configuration, [:project_path]
79
+
80
+ OPTION_TRANSFORMER = Hash.new() {|h, k| proc {|v, ctx| v.value } }
81
+ OPTION_TRANSFORMER[:asset_cache_buster] = proc do |v, ctx|
82
+ proc do |file|
83
+ if ctx.environment.function(v.value) || Sass::Script::Functions.callable?(v.value.tr('-', '_'))
84
+ result = ctx.call(v, ctx.quoted_string(file))
85
+ case result
86
+ when Sass::Script::Value::String, Sass::Script::Value::Null
87
+ result.value
88
+ else
89
+ ctx.assert_type(result, :Map)
90
+ result.value.keys.inject({}) do |r, k|
91
+ ctx.assert_type k, :String
92
+ ctx.assert_type(result.value[k], :String) unless result.value[k].value.nil?
93
+ if k.value == "path" || k.value == "query"
94
+ r[k.value.to_sym] = result.value[k].value
95
+ end
96
+ r
97
+ end
98
+ end
99
+ else
100
+ raise ArgumentError, "#{v.value} is not a function."
101
+ end
102
+ end
103
+ end
104
+ OPTION_TRANSFORMER[:asset_host] = proc do |v, ctx|
105
+ proc do |file|
106
+ if ctx.environment.function(v.value) || Sass::Script::Functions.callable?(v.value.tr('-', '_'))
107
+ result = ctx.call(v, ctx.quoted_string(file))
108
+ case result
109
+ when Sass::Script::Value::String, Sass::Script::Value::Null
110
+ result.value
111
+ else
112
+ ctx.assert_type(result, :String)
113
+ end
114
+ else
115
+ raise ArgumentError, "#{v.value} is not a function."
116
+ end
117
+ end
118
+ end
119
+
120
+ def add_configuration(options)
121
+ attributes = {}
122
+ options.value.keys.each do |key|
123
+ underscored = key.value.to_s.tr("-", "_")
124
+ unless runtime_writable_attributes.find{|a| a.to_s == underscored}
125
+ raise ArgumentError, "#{key} is not a valid configuration option."
126
+ end
127
+ underscored = underscored.to_sym
128
+ attributes[underscored] = OPTION_TRANSFORMER[underscored].call(options.value[key], self)
129
+ end
130
+ name = "#{options.source_range.file}:#{options.source_range.start_pos.line}"
131
+ Compass.add_configuration(Compass::Configuration::Data.new(name, attributes))
132
+ update_sass_options!
133
+ null
134
+ end
135
+ declare :add_configuration, [:options]
136
+
137
+ private
138
+
139
+ def runtime_writable_attributes
140
+ Compass::Configuration::ATTRIBUTES - Compass::Configuration::RUNTIME_READONLY_ATTRIBUTES
141
+ end
142
+
143
+ def common_parent_directory(directory1, directory2)
144
+ relative = Pathname.new(directory1).relative_path_from(Pathname.new(directory2))
145
+ File.expand_path(directory2, relative.to_s.scan("..#{File::SEPARATOR}").join)
146
+ end
147
+
148
+ def relative_path_from(directory1, directory2)
149
+ Pathname.new(directory1).relative_path_from(Pathname.new(directory2)).to_s
150
+ end
151
+
152
+ def update_sass_options!
153
+ Compass.configuration.additional_import_paths.each do |lp|
154
+ options[:load_paths] << lp unless options[:load_paths].include?(lp)
155
+ end
156
+ if Compass.configuration.disable_warnings
157
+ Sass.logger.log_level = :error
158
+ else
159
+ Sass.logger.log_level = :warn
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,74 @@
1
+ module Compass::Core::SassExtensions::Functions::Constants
2
+ POSITIONS = /top|bottom|left|right|center/
3
+ if defined?(Sass::Script::Value::List)
4
+ def is_position(position)
5
+ Sass::Script::Bool.new(position.is_a?(Sass::Script::String) && !!(position.value =~ POSITIONS))
6
+ end
7
+ def is_position_list(position_list)
8
+ Sass::Script::Bool.new(position_list.is_a?(Sass::Script::List) && position_list.value.all?{|p| is_position(p).to_bool})
9
+ end
10
+ # returns the opposite position of a side or corner.
11
+ def opposite_position(position)
12
+ position = unless position.is_a?(Sass::Script::List)
13
+ Sass::Script::List.new([position], :space)
14
+ else
15
+ Sass::Script::List.new(position.value.dup, position.separator)
16
+ end
17
+ position = Sass::Script::List.new(position.value.map do |pos|
18
+ if pos.is_a? Sass::Script::String
19
+ opposite = case pos.value
20
+ when "top" then "bottom"
21
+ when "bottom" then "top"
22
+ when "left" then "right"
23
+ when "right" then "left"
24
+ when "center" then "center"
25
+ else
26
+ Compass::Util.compass_warn("Cannot determine the opposite position of: #{pos}")
27
+ pos.value
28
+ end
29
+ Sass::Script::String.new(opposite)
30
+ elsif pos.is_a? Sass::Script::Number
31
+ if pos.numerator_units == ["%"] && pos.denominator_units == []
32
+ Sass::Script::Number.new(100-pos.value, ["%"])
33
+ else
34
+ Compass::Util.compass_warn("Cannot determine the opposite position of: #{pos}")
35
+ pos
36
+ end
37
+ else
38
+ Compass::Util.compass_warn("Cannot determine the opposite position of: #{pos}")
39
+ pos
40
+ end
41
+ end, position.separator)
42
+ if position.value.size == 1
43
+ position.value.first
44
+ else
45
+ position
46
+ end
47
+ end
48
+
49
+ def is_url(string)
50
+ if string.is_a?(Sass::Script::String)
51
+ is_url = !!(string.value =~ /^url\(.*\)$/)
52
+ Sass::Script::Bool.new(is_url)
53
+ else
54
+ Sass::Script::Bool.new(false)
55
+ end
56
+ end
57
+ else
58
+ # returns the opposite position of a side or corner.
59
+ def opposite_position(position)
60
+ opposite = position.value.split(/ +/).map do |pos|
61
+ case pos
62
+ when "top" then "bottom"
63
+ when "bottom" then "top"
64
+ when "left" then "right"
65
+ when "right" then "left"
66
+ when "center" then "center"
67
+ else
68
+ pos
69
+ end
70
+ end
71
+ Sass::Script::String.new(opposite.join(" "), position.type)
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,269 @@
1
+ module Compass::Core::SassExtensions::Functions::CrossBrowserSupport
2
+
3
+ class CSS2FallbackValue < Sass::Script::Literal
4
+ attr_accessor :value, :css2_value
5
+ def children
6
+ [value, css2_value]
7
+ end
8
+ def initialize(value, css2_value)
9
+ self.value = value
10
+ self.css2_value = css2_value
11
+ end
12
+ def inspect
13
+ to_s
14
+ end
15
+ def to_s(options = self.options)
16
+ value.to_s(options)
17
+ end
18
+ def supports?(aspect)
19
+ aspect == "css2"
20
+ end
21
+ def has_aspect?
22
+ true
23
+ end
24
+ def to_css2(options = self.options)
25
+ css2_value
26
+ end
27
+ end
28
+
29
+ # Check if any of the arguments passed require a vendor prefix.
30
+ def prefixed(prefix, *args)
31
+ assert_type prefix, :String
32
+ aspect = prefix.value.sub(/^-/,"")
33
+ needed = args.any?{|a| a.respond_to?(:supports?) && a.supports?(aspect)}
34
+ Sass::Script::Bool.new(needed)
35
+ end
36
+
37
+ %w(webkit moz o ms svg css2).each do |prefix|
38
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
39
+ # Syntactic sugar to apply the given prefix
40
+ # -moz($arg) is the same as calling prefix(-moz, $arg)
41
+ def _#{prefix}(*args)
42
+ prefix("#{prefix}", *args)
43
+ end
44
+ RUBY
45
+ end
46
+
47
+ def prefix(prefix, *objects)
48
+ assert_type prefix, :String if prefix.is_a?(Sass::Script::Value::Base)
49
+ prefix = prefix.value if prefix.is_a?(Sass::Script::String)
50
+ prefix = prefix[1..-1] if prefix[0] == ?-
51
+ if objects.size > 1
52
+ self.prefix(prefix, Sass::Script::List.new(objects, :comma))
53
+ else
54
+ object = objects.first
55
+ if object.is_a?(Sass::Script::List)
56
+ Sass::Script::List.new(object.value.map{|e|
57
+ self.prefix(prefix, e)
58
+ }, object.separator)
59
+ elsif object.respond_to?(:supports?) && object.supports?(prefix) && object.respond_to?(:"to_#{prefix}")
60
+ object.options = options
61
+ object.send(:"to_#{prefix}")
62
+ else
63
+ object
64
+ end
65
+ end
66
+ end
67
+
68
+ def css2_fallback(value, css2_value)
69
+ CSS2FallbackValue.new(value, css2_value)
70
+ end
71
+
72
+ # The known browsers.
73
+ #
74
+ # If prefix is given, limits the returned browsers to those using the specified prefix.
75
+ def browsers(prefix = nil)
76
+ browsers = if prefix
77
+ assert_type prefix, :String
78
+ Compass::Core::CanIUse.instance.browsers_with_prefix(prefix.value)
79
+ else
80
+ Compass::Core::CanIUse.instance.browsers
81
+ end
82
+ list(browsers.map{|b| identifier(b)}, :comma)
83
+ end
84
+ Sass::Script::Functions.declare(:browsers, [])
85
+ Sass::Script::Functions.declare(:browsers, [:prefix])
86
+
87
+ # The known capabilities of browsers.
88
+ def browser_capabilities
89
+ list(Compass::Core::CanIUse.instance.capabilities.map{|c| identifier(c)}, :comma)
90
+ end
91
+ Sass::Script::Functions.declare(:browser_capabilities, [])
92
+
93
+ # The versions for the given browser.
94
+ def browser_versions(browser)
95
+ assert_type browser, :String
96
+ list(Compass::Core::CanIUse.instance.versions(browser.value).map{|v| quoted_string(v)}, :comma)
97
+ rescue ArgumentError => e
98
+ raise Sass::SyntaxError.new(e.message)
99
+ end
100
+ Sass::Script::Functions.declare(:browser_versions, [:browser])
101
+
102
+ # whether the browser uses a prefix for the given capability at the version
103
+ # specified or a later version. Returns the prefix it requires, or null.
104
+ def browser_requires_prefix(browser, version, capability, capability_options)
105
+ assert_type browser, :String
106
+ assert_type version, :String
107
+ assert_type capability, :String
108
+ p = Compass::Core::CanIUse.instance.requires_prefix(browser.value,
109
+ version.value,
110
+ capability.value,
111
+ unbox_capability_options_list(capability_options))
112
+ p ? identifier(p) : null()
113
+ rescue ArgumentError => e
114
+ raise Sass::SyntaxError.new(e.message)
115
+ end
116
+ Sass::Script::Functions.declare(:browser_requires_prefix, [:browser, :version, :capability])
117
+
118
+ # the prefix for the given browser.
119
+ def browser_prefix(browser, version = nil)
120
+ assert_type browser, :String
121
+ identifier(Compass::Core::CanIUse.instance.prefix(browser.value))
122
+ rescue ArgumentError => e
123
+ raise Sass::SyntaxError.new(e.message)
124
+ end
125
+ Sass::Script::Functions.declare(:browser_prefix, [:browser])
126
+ Sass::Script::Functions.declare(:browser_prefix, [:browser, :version])
127
+
128
+ # The prefixes used by the given browsers.
129
+ def browser_prefixes(browsers)
130
+ browsers = list(browsers, :comma) if browsers.is_a?(Sass::Script::Value::String)
131
+ assert_type browsers, :List
132
+ browser_strings = browsers.value.map {|b| assert_type(b, :String); b.value }
133
+ prefix_strings = Compass::Core::CanIUse.instance.prefixes(browser_strings)
134
+ list(prefix_strings.map {|p| identifier(p)}, :comma)
135
+ rescue ArgumentError => e
136
+ raise Sass::SyntaxError.new(e.message)
137
+ end
138
+ Sass::Script::Functions.declare(:browser_prefixes, [:browsers])
139
+
140
+ # The percent of users that are omitted by setting the min_version of browser
141
+ # as specified.
142
+ def omitted_usage(browser, min_version, max_version = nil)
143
+ assert_type browser, :String
144
+ assert_type min_version, :String, :min_version
145
+ assert_type(max_version, :String, :max_version) if max_version
146
+ versions = [min_version.value]
147
+ versions << max_version.value if max_version
148
+ number(Compass::Core::CanIUse.instance.omitted_usage(browser.value, *versions))
149
+ end
150
+ Sass::Script::Functions.declare(:omitted_usage, [:browser, :min_version])
151
+ Sass::Script::Functions.declare(:omitted_usage, [:browser, :min_version, :max_version])
152
+
153
+ # The version before the version for the browser specified
154
+ def previous_version(browser, version)
155
+ assert_type browser, :String
156
+ assert_type version, :String
157
+ previous = Compass::Core::CanIUse.instance.previous_version(browser.value, version.value)
158
+ previous.nil? ? null() : quoted_string(previous)
159
+ end
160
+ Sass::Script::Functions.declare(:previous_version, [:browser, :version])
161
+
162
+ # The version before the version for the browser specified
163
+ def next_version(browser, version)
164
+ assert_type browser, :String
165
+ assert_type version, :String
166
+ next_version = Compass::Core::CanIUse.instance.next_version(browser.value, version.value)
167
+ next_version.nil? ? null() : quoted_string(next_version)
168
+ end
169
+ Sass::Script::Functions.declare(:next_version, [:browser, :version])
170
+
171
+ # The percent of users relying on a particular prefix
172
+ def prefix_usage(prefix, capability, capability_options)
173
+ assert_type prefix, :String
174
+ assert_type capability, :String
175
+ number(Compass::Core::CanIUse.instance.prefixed_usage(prefix.value,
176
+ capability.value,
177
+ unbox_capability_options_list(capability_options)))
178
+ rescue ArgumentError => e
179
+ raise Sass::SyntaxError.new(e.message)
180
+ end
181
+ Sass::Script::Functions.declare(:prefix_usage, [:prefix, :capability])
182
+
183
+ # Compares two browser versions. Returning:
184
+ #
185
+ # * 0 if they are the same
186
+ # * <0 if the first version is less than the second
187
+ # * >0 if the first version is more than the second
188
+ def compare_browser_versions(browser, version1, version2)
189
+ assert_type browser, :String, :browser
190
+ assert_type version1, :String, :version1
191
+ assert_type version2, :String, :version2
192
+ index1 = index2 = nil
193
+ Compass::Core::CanIUse.instance.versions(browser.value).each_with_index do |v, i|
194
+ index1 = i if v == version1.value
195
+ index2 = i if v == version2.value
196
+ break if index1 && index2
197
+ end
198
+ unless index1
199
+ raise Sass::SyntaxError.new("#{version1} is not a version for #{browser}")
200
+ end
201
+ unless index2
202
+ raise Sass::SyntaxError.new("#{version2} is not a version for #{browser}")
203
+ end
204
+ number(index1 <=> index2)
205
+ end
206
+ Sass::Script::Functions.declare(:compare_browser_versions, [:browser, :version1, :version2])
207
+
208
+ # Returns a map of browsers to the first version the capability became available
209
+ # without a prefix.
210
+ #
211
+ # If a prefix is provided, only those browsers using that prefix will be returned
212
+ # and the minimum version will be when it first became available as a prefix or
213
+ # without a prefix.
214
+ #
215
+ # If a browser does not have the capability, it will not included in the map.
216
+ def browser_ranges(capability, prefix = null(), include_unprefixed_versions = bool(true))
217
+ assert_type capability, :String
218
+ assert_type(prefix, :String) unless prefix == null()
219
+ mins = Compass::Core::CanIUse.instance.browser_ranges(capability.value,
220
+ prefix.value,
221
+ include_unprefixed_versions.to_bool)
222
+ Sass::Script::Value::Map.new(mins.inject({}) do |m, (h, range)|
223
+ m[identifier(h)] = list(range.map{|version| quoted_string(version)}, :space)
224
+ m
225
+ end)
226
+ end
227
+ Sass::Script::Functions.declare(:browser_minimums, [:capability])
228
+ Sass::Script::Functions.declare(:browser_minimums, [:capability, :prefix])
229
+
230
+ private
231
+
232
+ def unbox_capability_options_list(capability_options_list)
233
+ if capability_options_list.is_a?(Sass::Script::Value::Map)
234
+ [unbox_capability_options(capability_options_list)]
235
+ elsif capability_options_list.is_a?(Sass::Script::Value::List)
236
+ capability_options_list.to_a.map{|opts| unbox_capability_options(opts) }
237
+ else
238
+ assert_type capability_options_list, :List
239
+ end
240
+ end
241
+
242
+ CAPABILITY_OPTION_KEYS = {
243
+ "full-support" => :full_support,
244
+ "partial-support" => :partial_support,
245
+ "prefixed" => :prefixed,
246
+ "spec-versions" => :spec_versions,
247
+ }
248
+
249
+ CAPABILITY_OPTION_UNBOXER = {
250
+ :full_support => lambda {|v| v.to_bool },
251
+ :partial_support => lambda {|v| v.to_bool },
252
+ :prefixed => lambda {|v| v.to_bool },
253
+ :spec_versions => lambda {|versions| versions.to_a.map {|v| v.value } }
254
+ }
255
+
256
+ def unbox_capability_options(capability_options)
257
+ assert_type capability_options, :Map
258
+ result = {}
259
+ capability_options.value.each do |k, v|
260
+ assert_type k, :String
261
+ key = CAPABILITY_OPTION_KEYS[k.value]
262
+ unless key
263
+ raise Sass::SyntaxError, "#{k} is not valid capability option"
264
+ end
265
+ result[key] = CAPABILITY_OPTION_UNBOXER[key].call(v)
266
+ end
267
+ result
268
+ end
269
+ end