compass-core 1.0.0.alpha.13

Sign up to get free protection for your applications and to get access to all the features.
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