Merge branch 'master' of github.com:chriseppstein/compass into stable

This commit is contained in:
Scott Davis 2011-05-12 14:27:51 -04:00
commit 9992a18a72
19 changed files with 145 additions and 26 deletions

View File

@ -14,6 +14,13 @@ The Documentation for the [latest stable release](http://compass-style.org/docs/
The Documentation for the [latest preview release](http://beta.compass-style.org/) The Documentation for the [latest preview release](http://beta.compass-style.org/)
0.11.3 (PENDING)
-------------------
* Sprites will now by default remove any old versions of the sprite a new variable has been created to override this.
* Nested sprites are now supported using globs `@import 'nested/**/*.png';`.
* Fixed a bug that was causing sprite variable options to not get passed to the image classes.
* Sass Colors will no longer cause an error if you use them as sprite names.
0.11.2 (05/01/2011) 0.11.2 (05/01/2011)
------------------- -------------------

View File

@ -182,6 +182,7 @@ the sprites were contained within a folder called `icon`.
included in each sprite's CSS output. Can be `true` or `false`. Defaults to `false`. included in each sprite's CSS output. Can be `true` or `false`. Defaults to `false`.
* `$<map>-sprite-base-class` -- The base class for these sprites. Defaults to `.<map>-sprite`. * `$<map>-sprite-base-class` -- The base class for these sprites. Defaults to `.<map>-sprite`.
E.g. `$icon-sprite-base-class: ".action-icon"` E.g. `$icon-sprite-base-class: ".action-icon"`
* `$<map>-clean-up` -- Whether or not to removed the old sprite file when a new one is created. Defaults to true
### Options per Sprite ### Options per Sprite

View File

@ -15,14 +15,15 @@ $sprite-selectors: hover, target, active !default;
background-position: sprite-position($map, $sprite, $offset-x, $offset-y); background-position: sprite-position($map, $sprite, $offset-x, $offset-y);
} }
// Determines if you want to include magic selectors in your sprites
$disable-magic-sprite-selectors:false !default;
// Include the position and (optionally) dimensions of this `$sprite` // Include the position and (optionally) dimensions of this `$sprite`
// in the given sprite `$map`. The sprite url should come from either a base // in the given sprite `$map`. The sprite url should come from either a base
// class or you can specify the `sprite-url` explicitly like this: // class or you can specify the `sprite-url` explicitly like this:
// //
// background: $map no-repeat; // background: $map no-repeat;
$disable-magic-sprite-selectors:false !default;
@mixin sprite($map, $sprite, $dimensions: false, $offset-x: 0, $offset-y: 0) { @mixin sprite($map, $sprite, $dimensions: false, $offset-x: 0, $offset-y: 0) {
@include sprite-background-position($map, $sprite, $offset-x, $offset-y); @include sprite-background-position($map, $sprite, $offset-x, $offset-y);
@if $dimensions { @if $dimensions {

View File

@ -34,6 +34,7 @@ module Compass::SassExtensions::Functions::Sprites
# #
# background: url('/images/icons.png?12345678') 0 -24px no-repeat; # background: url('/images/icons.png?12345678') 0 -24px no-repeat;
def sprite(map, sprite, offset_x = ZERO, offset_y = ZERO) def sprite(map, sprite, offset_x = ZERO, offset_y = ZERO)
sprite = convert_sprite_name(sprite)
verify_map(map) verify_map(map)
unless sprite.is_a?(Sass::Script::String) unless sprite.is_a?(Sass::Script::String)
raise Sass::SyntaxError, %Q(The second argument to sprite() must be a sprite name. See http://beta.compass-style.org/help/tutorials/spriting/ for more information.) raise Sass::SyntaxError, %Q(The second argument to sprite() must be a sprite name. See http://beta.compass-style.org/help/tutorials/spriting/ for more information.)
@ -56,6 +57,7 @@ module Compass::SassExtensions::Functions::Sprites
# Returns the path to the original image file for the sprite with the given name # Returns the path to the original image file for the sprite with the given name
def sprite_file(map, sprite) def sprite_file(map, sprite)
sprite = convert_sprite_name(sprite)
verify_map(map, "sprite") verify_map(map, "sprite")
verify_sprite(sprite) verify_sprite(sprite)
if image = map.image_for(sprite.value) if image = map.image_for(sprite.value)
@ -68,6 +70,7 @@ module Compass::SassExtensions::Functions::Sprites
# Returns voolean if sprite has a parent # Returns voolean if sprite has a parent
def sprite_does_not_have_parent(map, sprite) def sprite_does_not_have_parent(map, sprite)
sprite = convert_sprite_name(sprite)
verify_map map verify_map map
verify_sprite sprite verify_sprite sprite
Sass::Script::Bool.new map.image_for(sprite.value).parent.nil? Sass::Script::Bool.new map.image_for(sprite.value).parent.nil?
@ -77,6 +80,7 @@ module Compass::SassExtensions::Functions::Sprites
# Returns boolean if sprite has the selector # Returns boolean if sprite has the selector
def sprite_has_selector(map, sprite, selector) def sprite_has_selector(map, sprite, selector)
sprite = convert_sprite_name(sprite)
verify_map map verify_map map
verify_sprite sprite verify_sprite sprite
unless VALID_SELECTORS.include?(selector.value) unless VALID_SELECTORS.include?(selector.value)
@ -118,6 +122,7 @@ module Compass::SassExtensions::Functions::Sprites
# #
# background-position: 3px -36px; # background-position: 3px -36px;
def sprite_position(map, sprite = nil, offset_x = ZERO, offset_y = ZERO) def sprite_position(map, sprite = nil, offset_x = ZERO, offset_y = ZERO)
sprite = convert_sprite_name(sprite)
verify_map(map, "sprite-position") verify_map(map, "sprite-position")
unless sprite && sprite.is_a?(Sass::Script::String) unless sprite && sprite.is_a?(Sass::Script::String)
raise Sass::SyntaxError, %Q(The second argument to sprite-position must be a sprite name. See http://beta.compass-style.org/help/tutorials/spriting/ for more information.) raise Sass::SyntaxError, %Q(The second argument to sprite-position must be a sprite name. See http://beta.compass-style.org/help/tutorials/spriting/ for more information.)
@ -147,6 +152,13 @@ module Compass::SassExtensions::Functions::Sprites
protected protected
def convert_sprite_name(sprite)
if sprite.is_a?(Sass::Script::Color)
return Sass::Script::String.new(Sass::Script::Color::HTML4_COLORS_REVERSE[sprite.rgb])
end
sprite
end
def verify_map(map, error = "sprite") def verify_map(map, error = "sprite")
unless map.is_a?(Compass::SassExtensions::Sprites::Base) unless map.is_a?(Compass::SassExtensions::Sprites::Base)
missing_sprite!(error) missing_sprite!(error)

View File

@ -8,7 +8,6 @@ module Compass
# the path is relative to the <tt>images_path</tt> confguration option # the path is relative to the <tt>images_path</tt> confguration option
def self.from_uri(uri, context, kwargs) def self.from_uri(uri, context, kwargs)
sprite_map = ::Compass::SpriteMap.new(uri.value, {}) sprite_map = ::Compass::SpriteMap.new(uri.value, {})
sprites = sprite_map.files.map do |sprite| sprites = sprite_map.files.map do |sprite|
sprite.gsub(Compass.configuration.images_path+"/", "") sprite.gsub(Compass.configuration.images_path+"/", "")
end end
@ -24,18 +23,22 @@ module Compass
# We should do so only when the packing algorithm changes # We should do so only when the packing algorithm changes
SPRITE_VERSION = "1" SPRITE_VERSION = "1"
attr_accessor :image_names, :path, :name, :options, :map attr_accessor :image_names, :path, :name, :map, :kwargs
attr_accessor :images, :width, :height attr_accessor :images, :width, :height
def initialize(image_names, map, context, options) def initialize(sprites, sprite_map, context, kwargs)
require_engine! require_engine!
@image_names, @path, @name, @options = image_names, map.path, map.name, options @image_names = sprites
@path = sprite_map.path
@name = sprite_map.name
@kwargs = kwargs
@kwargs['cleanup'] ||= Sass::Script::Bool.new(true)
@images = nil @images = nil
@width = nil @width = nil
@height = nil @height = nil
@evaluation_context = context @evaluation_context = context
@map = map @map = sprite_map
validate! validate!
compute_image_metadata! compute_image_metadata!
end end
@ -58,7 +61,7 @@ module Compass
# Creates the Sprite::Image objects for each image and calculates the width # Creates the Sprite::Image objects for each image and calculates the width
def init_images def init_images
@images = image_names.collect do |relative_file| @images = image_names.collect do |relative_file|
image = Compass::SassExtensions::Sprites::Image.new(self, relative_file, options) image = Compass::SassExtensions::Sprites::Image.new(self, relative_file, kwargs)
@width = [ @width, image.width + image.offset ].max @width = [ @width, image.width + image.offset ].max
image image
end end
@ -118,12 +121,21 @@ module Compass
# Generate a sprite image if necessary # Generate a sprite image if necessary
def generate def generate
if generation_required? if generation_required?
if kwargs.get_var('cleanup').value
cleanup_old_sprites
end
sprite_data = construct_sprite sprite_data = construct_sprite
save!(sprite_data) save!(sprite_data)
Compass.configuration.run_callback(:sprite_generated, sprite_data) Compass.configuration.run_callback(:sprite_generated, sprite_data)
end end
end end
def cleanup_old_sprites
Dir[File.join(Compass.configuration.images_path, "#{path}-*.png")].each do |file|
FileUtils.rm file
end
end
# Does this sprite need to be generated # Does this sprite need to be generated
def generation_required? def generation_required?
!File.exists?(filename) || outdated? !File.exists?(filename) || outdated?
@ -174,7 +186,7 @@ module Compass
to_s to_s
end end
def to_s(options = self.options) def to_s(kwargs = self.kwargs)
sprite_url(self).value sprite_url(self).value
end end

View File

@ -50,7 +50,18 @@ module Compass
end end
def ensure_path_and_name! def ensure_path_and_name!
@path, @name = Compass::Sprites.path_and_name(uri) @path ||= get_path
@name ||= get_name
end
def get_name
_, name = Compass::Sprites.path_and_name(uri)
name
end
def get_path
path, _ = Compass::Sprites.path_and_name(uri)
path
end end
def key(uri, options) def key(uri, options)
@ -74,8 +85,9 @@ $#{name}-position: 0% !default;
$#{name}-spacing: 0 !default; $#{name}-spacing: 0 !default;
$#{name}-repeat: no-repeat !default; $#{name}-repeat: no-repeat !default;
$#{name}-prefix: '' !default; $#{name}-prefix: '' !default;
$#{name}-clean-up: true !default;
#{skip_overrides ? "$#{name}-sprites: sprite-map(\"#{uri}\");" : generate_overrides } #{skip_overrides ? "$#{name}-sprites: sprite-map(\"#{uri}\", $cleanup: $#{name}-clean-up);" : generate_overrides }
// All sprites should extend this class // All sprites should extend this class
// The #{name}-sprite mixin will do so for you. // The #{name}-sprite mixin will do so for you.
@ -129,7 +141,7 @@ $#{name}-#{sprite_name}-repeat: $#{name}-repeat !default;
SCSS SCSS
end.join end.join
content += "\n$#{name}-sprites: sprite-map(\"#{uri}\",\n" content += "\n$#{name}-sprites: sprite-map(\"#{uri}\", \n$cleanup: $#{name}-clean-up,\n"
content += sprite_names.map do |sprite_name| content += sprite_names.map do |sprite_name|
%Q{ $#{sprite_name}-position: $#{name}-#{sprite_name}-position, %Q{ $#{sprite_name}-position: $#{name}-#{sprite_name}-position,
$#{sprite_name}-spacing: $#{name}-#{sprite_name}-spacing, $#{sprite_name}-spacing: $#{name}-#{sprite_name}-spacing,

View File

@ -3,8 +3,8 @@ module Compass
attr_accessor :name, :path attr_accessor :name, :path
def self.path_and_name(uri) def self.path_and_name(uri)
if uri =~ %r{((.+/)?(.+))/(.+?)\.png} if uri =~ %r{((.+/)?([^\*.]+))/(.+?)\.png}
[$1, $3, $4] [$1, $3]
end end
end end

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -9,8 +9,8 @@ class SpritesTest < Test::Unit::TestCase
def setup def setup
Compass.reset_configuration! Compass.reset_configuration!
@images_src_path = File.join(File.dirname(__FILE__), 'fixtures', 'sprites', 'public', 'images') @images_src_path = File.join(File.dirname(__FILE__), '..', 'fixtures', 'sprites', 'public', 'images')
@images_tmp_path = File.join(File.dirname(__FILE__), 'fixtures', 'sprites', 'public', 'images-tmp') @images_tmp_path = File.join(File.dirname(__FILE__), '..', 'fixtures', 'sprites', 'public', 'images-tmp')
::FileUtils.cp_r @images_src_path, @images_tmp_path ::FileUtils.cp_r @images_src_path, @images_tmp_path
file = StringIO.new("images_path = #{@images_tmp_path.inspect}\n") file = StringIO.new("images_path = #{@images_tmp_path.inspect}\n")
Compass.add_configuration(file, "sprite_config") Compass.add_configuration(file, "sprite_config")
@ -24,7 +24,11 @@ class SpritesTest < Test::Unit::TestCase
def map_location(file) def map_location(file)
Dir.glob(File.join(@images_tmp_path, file)).first map_files(file).first
end
def map_files(glob)
Dir.glob(File.join(@images_tmp_path, glob))
end end
def image_size(file) def image_size(file)
@ -547,4 +551,57 @@ class SpritesTest < Test::Unit::TestCase
CSS CSS
end end
it "should generate a sprite and remove the old file" do
FileUtils.touch File.join(@images_tmp_path, "selectors-cc8834Fdd.png")
assert_equal 1, map_files('selectors-*.png').size
css = render <<-SCSS
@import "selectors/*.png";
a {
$disable-magic-sprite-selectors:true;
@include selectors-sprite(ten-by-ten)
}
SCSS
assert_equal 1, map_files('selectors-*.png').size, "File was not removed"
end
it "should generate a sprite and NOT remove the old file" do
FileUtils.touch File.join(@images_tmp_path, "selectors-cc8834Ftest.png")
assert_equal 1, map_files('selectors-*.png').size
css = render <<-SCSS
$selectors-clean-up: false;
@import "selectors/*.png";
a {
$disable-magic-sprite-selectors:true;
@include selectors-sprite(ten-by-ten)
}
SCSS
assert_equal 2, map_files('selectors-*.png').size, "File was removed"
end
it "should generate a sprite if the sprite is a colorname" do
css = render <<-SCSS
@import "colors/*.png";
a {
@include colors-sprite(blue);
}
SCSS
assert !css.empty?
end
it "should generate a sprite from nested folders" do
css = render <<-SCSS
@import "nested/**/*.png";
@include all-nested-sprites;
SCSS
assert_correct css, <<-CSS
.nested-sprite, .nested-ten-by-ten {
background: url('/nested-55a8935544.png') no-repeat;
}
.nested-ten-by-ten {
background-position: 0 0;
}
CSS
end
end end

View File

@ -1,7 +1,7 @@
require 'test_helper' require 'test_helper'
require 'fileutils' require 'fileutils'
class CommandLineTest < Test::Unit::TestCase class CompassPngTest < Test::Unit::TestCase
def test_class_crc_table def test_class_crc_table
assert_equal 256, Compass::PNG::CRC_TABLE.length assert_equal 256, Compass::PNG::CRC_TABLE.length

View File

@ -3,15 +3,20 @@ require 'test_helper'
class SpritesBaseTest < Test::Unit::TestCase class SpritesBaseTest < Test::Unit::TestCase
def setup def setup
@images_src_path = File.join(File.dirname(__FILE__), '..', 'fixtures', 'sprites', 'public', 'images') Hash.send(:include, Compass::SassExtensions::Functions::Sprites::VariableReader)
@images_tmp_path = File.join(File.dirname(__FILE__), '..', 'fixtures', 'sprites', 'public', 'images-tmp') @images_src_path = File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'sprites', 'public', 'images')
@images_tmp_path = File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'sprites', 'public', 'images-tmp')
FileUtils.cp_r @images_src_path, @images_tmp_path FileUtils.cp_r @images_src_path, @images_tmp_path
config = Compass::Configuration::Data.new('config') config = Compass::Configuration::Data.new('config')
config.images_path = @images_tmp_path config.images_path = @images_tmp_path
Compass.add_configuration(config) Compass.add_configuration(config)
Compass.configure_sass_plugin! Compass.configure_sass_plugin!
options = Compass.sass_engine_options.extend Compass::SassExtensions::Functions::Sprites::VariableReader @options = {'cleanup' => Sass::Script::Bool.new(true)}
@map = Compass::SpriteMap.new("selectors/*.png", options) setup_map
end
def setup_map
@map = Compass::SpriteMap.new("selectors/*.png", @options)
@base = Compass::SassExtensions::Sprites::Base.new(@map.sprite_names.map{|n| "selectors/#{n}.png"}, @map, @map.sass_engine, @map.options) @base = Compass::SassExtensions::Sprites::Base.new(@map.sprite_names.map{|n| "selectors/#{n}.png"}, @map, @map.sass_engine, @map.options)
end end
@ -70,4 +75,16 @@ class SpritesBaseTest < Test::Unit::TestCase
assert !@base.outdated? assert !@base.outdated?
end end
it "should remove old sprite when generating new" do
@base.generate
file = @base.filename
assert File.exists?(file), "Original file does not exist"
file_to_remove = File.join(@images_tmp_path, 'selectors', 'ten-by-ten.png')
FileUtils.rm file_to_remove
assert !File.exists?(file_to_remove), "Failed to remove sprite file"
setup_map
@base.generate
assert !File.exists?(file), "Sprite file did not get removed"
end
end end

View File

@ -5,7 +5,7 @@ class SpritesImageTest < Test::Unit::TestCase
def setup def setup
@images_src_path = File.join(File.dirname(__FILE__), '..', 'fixtures', 'sprites', 'public', 'images') @images_src_path = File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'sprites', 'public', 'images')
file = StringIO.new("images_path = #{@images_src_path.inspect}\n") file = StringIO.new("images_path = #{@images_src_path.inspect}\n")
Compass.add_configuration(file, "sprite_config") Compass.add_configuration(file, "sprite_config")
@repeat = 'no-repeat' @repeat = 'no-repeat'