diff --git a/Gemfile.lock b/Gemfile.lock index f5264999..6042394b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,7 +7,7 @@ GIT PATH remote: . specs: - compass (0.11.beta.3.eba8611) + compass (0.11.beta.3.f8197c5) chunky_png (~> 1.1.0) sass (>= 3.1.0.alpha.249) diff --git a/lib/compass.rb b/lib/compass.rb index 5ce7268d..952c0627 100644 --- a/lib/compass.rb +++ b/lib/compass.rb @@ -18,6 +18,6 @@ module Compass extend QuickCache end -%w(configuration frameworks app_integration actions compiler sprites).each do |lib| +%w(configuration frameworks app_integration actions compiler).each do |lib| require "compass/#{lib}" end diff --git a/lib/compass/sass_extensions/sprites.rb b/lib/compass/sass_extensions/sprites.rb index 0bf1f30d..85765179 100644 --- a/lib/compass/sass_extensions/sprites.rb +++ b/lib/compass/sass_extensions/sprites.rb @@ -1,4 +1,6 @@ require 'digest/md5' +require 'compass/sass_extensions/sprites/sprites' +require 'compass/sass_extensions/sprites/sprite_map' require 'compass/sass_extensions/sprites/image' require 'compass/sass_extensions/sprites/base' require 'compass/sass_extensions/sprites/engines' diff --git a/lib/compass/sass_extensions/sprites/base.rb b/lib/compass/sass_extensions/sprites/base.rb index 8a35b040..e2f7251e 100644 --- a/lib/compass/sass_extensions/sprites/base.rb +++ b/lib/compass/sass_extensions/sprites/base.rb @@ -1,5 +1,3 @@ -require 'compass/sprite_map' - module Compass module SassExtensions module Sprites diff --git a/lib/compass/sass_extensions/sprites/sprite_map.rb b/lib/compass/sass_extensions/sprites/sprite_map.rb new file mode 100644 index 00000000..ece478a7 --- /dev/null +++ b/lib/compass/sass_extensions/sprites/sprite_map.rb @@ -0,0 +1,121 @@ +module Compass + class SpriteMap + attr_reader :uri, :options + + def initialize(uri, options) + @uri, @options = uri, options + end + + def name + ensure_path_and_name! + @name + end + + def path + ensure_path_and_name! + @path + end + + def files + @files ||= Dir[File.join(Compass.configuration.images_path, uri)].sort + end + + def sprite_names + @sprite_names ||= files.collect { |file| File.basename(file, '.png') } + end + + def sass_options + @sass_options ||= options.merge(:filename => name, :syntax => :scss, :importer => self) + end + + def mtime + Compass.quick_cache("mtime:#{uri}") do + files.collect { |file| File.mtime(file) }.max + end + end + + def sass_engine + Sass::Engine.new(content_for_images, options) + end + + private + def ensure_path_and_name! + return if @path && @name + uri =~ %r{((.+/)?(.+))/(.+?)\.png} + @path, @name = $1, $3 + end + + def content_for_images(skip_overrides = false) + <<-SCSS +@import "compass/utilities/sprites/base"; + +// General Sprite Defaults +// You can override them before you import this file. +$#{name}-sprite-base-class: ".#{name}-sprite" !default; +$#{name}-sprite-dimensions: false !default; +$#{name}-position: 0% !default; +$#{name}-spacing: 0 !default; +$#{name}-repeat: no-repeat !default; +$#{name}-prefix: '' !default; + +#{skip_overrides ? "$#{name}-sprites: sprite-map(\"#{uri}\");" : generate_overrides } + +// All sprites should extend this class +// The #{name}-sprite mixin will do so for you. +\#{$#{name}-sprite-base-class} { + background: $#{name}-sprites no-repeat; +} + +// Use this to set the dimensions of an element +// based on the size of the original image. +@mixin #{name}-sprite-dimensions($name) { + @include sprite-dimensions($#{name}-sprites, $name) +} + +// Move the background position to display the sprite. +@mixin #{name}-sprite-position($name, $offset-x: 0, $offset-y: 0) { + @include sprite-background-position($#{name}-sprites, $name, $offset-x, $offset-y) +} + +// Extends the sprite base class and set the background position for the desired sprite. +// It will also apply the image dimensions if $dimensions is true. +@mixin #{name}-sprite($name, $dimensions: $#{name}-sprite-dimensions, $offset-x: 0, $offset-y: 0) { + @extend \#{$#{name}-sprite-base-class}; + @include sprite($#{name}-sprites, $name, $dimensions, $offset-x, $offset-y) +} + +@mixin #{name}-sprites($sprite-names, $dimensions: $#{name}-sprite-dimensions, $prefix: sprite-map-name($#{name}-sprites)) { + @include sprites($#{name}-sprites, $sprite-names, $#{name}-sprite-base-class, $dimensions, $prefix) +} + +// Generates a class for each sprited image. +@mixin all-#{name}-sprites($dimensions: $#{name}-sprite-dimensions, $prefix: sprite-map-name($#{name}-sprites)) { + @include #{name}-sprites(#{sprite_names.join(" ")}, $dimensions, $prefix); +} +SCSS + end + + def generate_overrides + content = <<-TXT +// These variables control the generated sprite output +// You can override them selectively before you import this file. + TXT + sprite_names.map do |sprite_name| + content += <<-SCSS +$#{name}-#{sprite_name}-position: $#{name}-position !default; +$#{name}-#{sprite_name}-spacing: $#{name}-spacing !default; +$#{name}-#{sprite_name}-repeat: $#{name}-repeat !default; + SCSS + end.join + + content += "\n$#{name}-sprites: sprite-map(\"#{uri}\",\n" + content += sprite_names.map do |sprite_name| +%Q{ $#{sprite_name}-position: $#{name}-#{sprite_name}-position, + $#{sprite_name}-spacing: $#{name}-#{sprite_name}-spacing, + $#{sprite_name}-repeat: $#{name}-#{sprite_name}-repeat} + end.join(",\n") + content += ");" + end + end +end + diff --git a/lib/compass/sass_extensions/sprites/sprites.rb b/lib/compass/sass_extensions/sprites/sprites.rb new file mode 100644 index 00000000..5dea8570 --- /dev/null +++ b/lib/compass/sass_extensions/sprites/sprites.rb @@ -0,0 +1,26 @@ +module Compass + class Sprites < Sass::Importers::Base + def find_relative(*args) + nil + end + + def find(uri, options) + if uri =~ /\.png$/ + SpriteMap.new(uri, options).sass_engine + end + end + + def key(uri, options) + [self.class.name + ":" + File.dirname(File.expand_path(uri)), + File.basename(uri)] + end + + def mtime(uri, options) + SpriteMap.new(uri, options).mtime + end + + def to_s + "" + end + end +end diff --git a/spec/compass/sass_extensions/sprites/sprite_map_spec.rb b/spec/compass/sass_extensions/sprites/sprite_map_spec.rb new file mode 100644 index 00000000..1136e9a4 --- /dev/null +++ b/spec/compass/sass_extensions/sprites/sprite_map_spec.rb @@ -0,0 +1,51 @@ +require 'spec_helper' +require 'fakefs/spec_helpers' +require 'timecop' + +describe Compass::SpriteMap do + include FakeFS::SpecHelpers + + let(:sprite_map) { self.class.describes.new(uri, options) } + let(:options) { { :test => :test2 } } + + subject { sprite_map } + + let(:path) { 'path' } + let(:dir) { "dir/#{name}" } + let(:name) { 'subdir' } + + let(:sprite_path) { File.join(path, dir) } + let(:files) { (1..3).collect { |i| File.join(sprite_path, "#{i}.png") } } + let(:expanded_files) { files.collect { |file| File.expand_path(file) } } + + let(:configuration) { stub(:images_path => path) } + let(:mtime) { Time.now - 30 } + + before { + Compass.stubs(:configuration).returns(configuration) + + FileUtils.mkdir_p(sprite_path) + Timecop.freeze(mtime) do + files.each { |file| File.open(file, 'w') } + end + Timecop.return + } + + describe '#initialize' do + let(:uri) { 'dir/subdir/*.png' } + + its(:uri) { should == uri } + its(:path) { should == dir } + its(:name) { should == name } + + its(:files) { should == expanded_files } + + its(:sass_options) { should == options.merge(:filename => name, :syntax => :scss, :importer => sprite_map) } + + its(:mtime) { should == mtime } + + it "should have a test for the sass engine" do + pending 'sass' + end + end +end diff --git a/spec/compass/sass_extensions/sprites/sprites_spec.rb b/spec/compass/sass_extensions/sprites/sprites_spec.rb new file mode 100644 index 00000000..9246d8d3 --- /dev/null +++ b/spec/compass/sass_extensions/sprites/sprites_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' +require 'fakefs/spec_helpers' + +describe Compass::Sprites do +end diff --git a/spec/sprites_spec.rb b/spec/sprites_spec.rb index 0c8fd94c..ec6555ea 100644 --- a/spec/sprites_spec.rb +++ b/spec/sprites_spec.rb @@ -1,5 +1,4 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper') -require "compass/sprites" require 'digest/md5' describe Compass::Sprites do